mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
Match substrate's fmt (#1148)
* Alter gitlab. * Use substrate's rustfmt.toml * cargo +nightly fmt --all * Fix spellcheck. * cargo +nightly fmt --all * format. * Fix spellcheck and fmt * fmt? * Fix spellcheck Co-authored-by: Tomasz Drwięga <tomasz@parity.io>
This commit is contained in:
@@ -16,8 +16,9 @@
|
||||
|
||||
use bp_millau::derive_account_from_rialto_id;
|
||||
use millau_runtime::{
|
||||
AccountId, AuraConfig, BalancesConfig, BridgeRialtoMessagesConfig, BridgeWestendGrandpaConfig, GenesisConfig,
|
||||
GrandpaConfig, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
|
||||
AccountId, AuraConfig, BalancesConfig, 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};
|
||||
@@ -190,12 +191,8 @@ fn testnet_genesis(
|
||||
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() },
|
||||
grandpa: GrandpaConfig { authorities: Vec::new() },
|
||||
sudo: SudoConfig { key: root_key },
|
||||
session: SessionConfig {
|
||||
keys: initial_authorities
|
||||
@@ -220,9 +217,7 @@ fn testnet_genesis(
|
||||
#[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());
|
||||
}
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
// 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_service::PartialComponents;
|
||||
@@ -75,7 +77,7 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
));
|
||||
|
||||
match &cli.subcommand {
|
||||
Some(Subcommand::Benchmark(cmd)) => {
|
||||
Some(Subcommand::Benchmark(cmd)) =>
|
||||
if cfg!(feature = "runtime-benchmarks") {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
|
||||
@@ -86,8 +88,7 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
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,69 +96,53 @@ 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::ExecutorDispatch>(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 {
|
||||
@@ -167,6 +152,6 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
}
|
||||
.map_err(sc_cli::Error::Service)
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
// =====================================================================================
|
||||
// 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;
|
||||
// 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 :)
|
||||
// =====================================================================================
|
||||
// =====================================================================================
|
||||
@@ -57,7 +57,8 @@ 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>;
|
||||
|
||||
@@ -72,7 +73,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>,
|
||||
),
|
||||
@@ -80,7 +86,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("Remote Keystores are not supported.".to_string()))
|
||||
}
|
||||
|
||||
let telemetry = config
|
||||
@@ -100,11 +106,12 @@ pub fn new_partial(
|
||||
config.max_runtime_instances,
|
||||
);
|
||||
|
||||
let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::<Block, RuntimeApi, Executor>(
|
||||
config,
|
||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||
executor,
|
||||
)?;
|
||||
let (client, backend, keystore_container, task_manager) =
|
||||
sc_service::new_full_parts::<Block, RuntimeApi, Executor>(
|
||||
config,
|
||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||
executor,
|
||||
)?;
|
||||
let client = Arc::new(client);
|
||||
|
||||
let telemetry = telemetry.map(|(worker, telemetry)| {
|
||||
@@ -131,26 +138,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,
|
||||
@@ -187,37 +198,39 @@ 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());
|
||||
let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new(
|
||||
backend.clone(),
|
||||
grandpa_link.shared_authority_set().clone(),
|
||||
));
|
||||
|
||||
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,
|
||||
warp_sync: Some(warp_sync),
|
||||
})?;
|
||||
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,
|
||||
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();
|
||||
@@ -244,8 +257,10 @@ 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| {
|
||||
let mut io = jsonrpc_core::IoHandler::default();
|
||||
@@ -292,37 +307,40 @@ 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,
|
||||
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(
|
||||
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.
|
||||
@@ -331,11 +349,8 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
|
||||
// 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 grandpa_config = sc_finality_grandpa::Config {
|
||||
// FIXME #1578 make this available through chainspec
|
||||
@@ -367,9 +382,10 @@ 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)?);
|
||||
task_manager.spawn_essential_handle().spawn_blocking(
|
||||
"grandpa-voter",
|
||||
sc_finality_grandpa::run_grandpa_voter(grandpa_config)?,
|
||||
);
|
||||
}
|
||||
|
||||
network_starter.start_network();
|
||||
@@ -407,10 +423,7 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
telemetry
|
||||
});
|
||||
|
||||
config
|
||||
.network
|
||||
.extra_sets
|
||||
.push(sc_finality_grandpa::grandpa_peers_set_config());
|
||||
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
|
||||
|
||||
let select_chain = sc_consensus::LongestChain::new(backend.clone());
|
||||
|
||||
@@ -431,45 +444,53 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
|
||||
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 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,
|
||||
);
|
||||
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()),
|
||||
})?;
|
||||
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 warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new(
|
||||
backend.clone(),
|
||||
grandpa_link.shared_authority_set().clone(),
|
||||
));
|
||||
|
||||
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,
|
||||
warp_sync: Some(warp_sync),
|
||||
})?;
|
||||
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,
|
||||
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 enable_grandpa = !config.disable_grandpa;
|
||||
|
||||
@@ -34,15 +34,19 @@ pub mod rialto_messages;
|
||||
|
||||
use crate::rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge};
|
||||
|
||||
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 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_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, NumberFor, OpaqueKeys},
|
||||
transaction_validity::{TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
|
||||
};
|
||||
@@ -61,8 +65,9 @@ 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 BridgeGrandpaRialtoCall, Call as BridgeGrandpaWestendCall,
|
||||
};
|
||||
pub use pallet_bridge_messages::Call as MessagesCall;
|
||||
pub use pallet_sudo::Call as SudoCall;
|
||||
pub use pallet_timestamp::Call as TimestampCall;
|
||||
@@ -138,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! {
|
||||
@@ -231,9 +233,12 @@ 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 = ();
|
||||
@@ -394,14 +399,16 @@ 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 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 OnDeliveryConfirmed =
|
||||
pallet_bridge_token_swap::Pallet<Runtime, WithRialtoTokenSwapInstance>;
|
||||
|
||||
type SourceHeaderChain = crate::rialto_messages::Rialto;
|
||||
type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch;
|
||||
@@ -488,8 +495,13 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signatu
|
||||
/// 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>;
|
||||
pub type Executive = frame_executive::Executive<
|
||||
Runtime,
|
||||
Block,
|
||||
frame_system::ChainContext<Runtime>,
|
||||
Runtime,
|
||||
AllPallets,
|
||||
>;
|
||||
|
||||
impl_runtime_apis! {
|
||||
impl sp_api::Core<Block> for Runtime {
|
||||
@@ -742,15 +754,18 @@ 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(),
|
||||
|
||||
@@ -35,7 +35,8 @@ 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);
|
||||
|
||||
@@ -47,13 +48,16 @@ parameter_types! {
|
||||
}
|
||||
|
||||
/// 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>;
|
||||
@@ -62,7 +66,8 @@ 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<
|
||||
@@ -86,8 +91,10 @@ impl MessageBridge for WithRialtoMessageBridge {
|
||||
type BridgedChain = Rialto;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +115,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 == crate::TokenSwapMessagesLane::get()
|
||||
*lane == [0, 0, 0, 0] ||
|
||||
*lane == [0, 0, 0, 1] ||
|
||||
*lane == crate::TokenSwapMessagesLane::get()
|
||||
}
|
||||
|
||||
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
|
||||
@@ -167,12 +176,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
|
||||
}
|
||||
@@ -232,9 +244,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +265,11 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,9 +283,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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ 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>;
|
||||
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 {
|
||||
@@ -157,9 +158,7 @@ fn testnet_genesis(
|
||||
},
|
||||
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: rialto_parachain_runtime::AuraConfig { authorities: initial_authorities },
|
||||
aura_ext: Default::default(),
|
||||
// parachain_system: Default::default(),
|
||||
}
|
||||
|
||||
@@ -131,14 +131,7 @@ impl RelayChainCli {
|
||||
) -> 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),
|
||||
}
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,15 +26,18 @@ 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,
|
||||
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> {
|
||||
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)),
|
||||
@@ -158,44 +161,51 @@ pub fn run() -> 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)) => {
|
||||
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)))
|
||||
}
|
||||
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)))
|
||||
}
|
||||
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()),
|
||||
[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))?;
|
||||
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)))
|
||||
}
|
||||
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, "");
|
||||
@@ -219,13 +229,14 @@ pub fn run() -> Result<()> {
|
||||
}
|
||||
|
||||
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(¶ms.chain.clone().unwrap_or_default())?)?;
|
||||
let raw_wasm_blob =
|
||||
extract_genesis_wasm(&*cli.load_spec(¶ms.chain.clone().unwrap_or_default())?)?;
|
||||
let output_buf = if params.raw {
|
||||
raw_wasm_blob
|
||||
} else {
|
||||
@@ -239,8 +250,8 @@ pub fn run() -> Result<()> {
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Some(Subcommand::Benchmark(cmd)) => {
|
||||
},
|
||||
Some(Subcommand::Benchmark(cmd)) =>
|
||||
if cfg!(feature = "runtime-benchmarks") {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
|
||||
@@ -249,46 +260,46 @@ pub fn run() -> Result<()> {
|
||||
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 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()),
|
||||
[RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()),
|
||||
);
|
||||
|
||||
let id = ParaId::from(cli.run.parachain_id.or(para_id).expect("Missing ParaId"));
|
||||
|
||||
let parachain_account = AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);
|
||||
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 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))?;
|
||||
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" }
|
||||
);
|
||||
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)
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,11 +368,7 @@ impl CliConfiguration<Self> for RelayChainCli {
|
||||
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
|
||||
})
|
||||
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> {
|
||||
@@ -408,7 +415,10 @@ impl CliConfiguration<Self> for RelayChainCli {
|
||||
self.base.base.announce_block()
|
||||
}
|
||||
|
||||
fn telemetry_endpoints(&self, chain_spec: &Box<dyn ChainSpec>) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
|
||||
fn telemetry_endpoints(
|
||||
&self,
|
||||
chain_spec: &Box<dyn ChainSpec>,
|
||||
) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
|
||||
self.base.base.telemetry_endpoints(chain_spec)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ use std::sync::Arc;
|
||||
use rialto_parachain_runtime::RuntimeApi;
|
||||
|
||||
// Cumulus Imports
|
||||
use cumulus_client_consensus_aura::{build_aura_consensus, BuildAuraConsensusParams, SlotProportion};
|
||||
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::{
|
||||
@@ -77,8 +79,14 @@ pub fn new_partial<RuntimeApi, Executor, BIQ>(
|
||||
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>>>,
|
||||
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,
|
||||
@@ -91,8 +99,10 @@ where
|
||||
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_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,
|
||||
@@ -102,7 +112,10 @@ where
|
||||
Option<TelemetryHandle>,
|
||||
&TaskManager,
|
||||
) -> Result<
|
||||
sc_consensus::DefaultImportQueue<Block, TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>,
|
||||
sc_consensus::DefaultImportQueue<
|
||||
Block,
|
||||
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
|
||||
>,
|
||||
sc_service::Error,
|
||||
>,
|
||||
{
|
||||
@@ -123,11 +136,12 @@ where
|
||||
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, 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());
|
||||
@@ -189,8 +203,10 @@ where
|
||||
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_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>,
|
||||
@@ -206,7 +222,10 @@ where
|
||||
Option<TelemetryHandle>,
|
||||
&TaskManager,
|
||||
) -> Result<
|
||||
sc_consensus::DefaultImportQueue<Block, TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>,
|
||||
sc_consensus::DefaultImportQueue<
|
||||
Block,
|
||||
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
|
||||
>,
|
||||
sc_service::Error,
|
||||
>,
|
||||
BIC: FnOnce(
|
||||
@@ -215,14 +234,19 @@ where
|
||||
Option<TelemetryHandle>,
|
||||
&TaskManager,
|
||||
&polkadot_service::NewFull<polkadot_service::Client>,
|
||||
Arc<sc_transaction_pool::FullPool<Block, TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>>,
|
||||
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());
|
||||
return Err("Light client not supported!".into())
|
||||
}
|
||||
|
||||
let parachain_config = prepare_node_config(parachain_config);
|
||||
@@ -231,12 +255,11 @@ where
|
||||
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 {
|
||||
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();
|
||||
@@ -253,16 +276,17 @@ where
|
||||
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: ¶chain_config,
|
||||
client: client.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
spawn_handle: task_manager.spawn_handle(),
|
||||
import_queue: import_queue.clone(),
|
||||
on_demand: None,
|
||||
block_announce_validator_builder: Some(Box::new(|_| block_announce_validator)),
|
||||
warp_sync: None,
|
||||
})?;
|
||||
let (network, system_rpc_tx, start_network) =
|
||||
sc_service::build_network(sc_service::BuildNetworkParams {
|
||||
config: ¶chain_config,
|
||||
client: client.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
spawn_handle: task_manager.spawn_handle(),
|
||||
import_queue: import_queue.clone(),
|
||||
on_demand: None,
|
||||
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())));
|
||||
@@ -348,26 +372,33 @@ pub fn parachain_build_import_queue(
|
||||
> {
|
||||
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();
|
||||
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(
|
||||
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,
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -438,7 +469,9 @@ pub async fn start_node(
|
||||
);
|
||||
|
||||
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
||||
Box::<dyn std::error::Error + Send + Sync>::from("Failed to create parachain inherent")
|
||||
Box::<dyn std::error::Error + Send + Sync>::from(
|
||||
"Failed to create parachain inherent",
|
||||
)
|
||||
})?;
|
||||
Ok((time, slot, parachain_inherent))
|
||||
}
|
||||
|
||||
@@ -63,10 +63,11 @@ 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,
|
||||
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
|
||||
EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset,
|
||||
ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative,
|
||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents,
|
||||
};
|
||||
use xcm_executor::{Config, XcmExecutor};
|
||||
|
||||
@@ -110,8 +111,13 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signatu
|
||||
/// 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>;
|
||||
pub type Executive = frame_executive::Executive<
|
||||
Runtime,
|
||||
Block,
|
||||
frame_system::ChainContext<Runtime>,
|
||||
Runtime,
|
||||
AllPallets,
|
||||
>;
|
||||
|
||||
impl_opaque_keys! {
|
||||
pub struct SessionKeys {
|
||||
@@ -159,14 +165,11 @@ 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(),
|
||||
}
|
||||
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
|
||||
}
|
||||
|
||||
/// We assume that approximately 10 percent of the block weight is consumed by `on_initalize` handlers.
|
||||
/// This is used to limit the maximal weight of a single extrinsic.
|
||||
/// We assume that approximately 10 percent of the block weight is consumed by `on_initalize`
|
||||
/// handlers. This is used to limit the maximal weight of a single extrinsic.
|
||||
const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
|
||||
/// We allow `Normal` extrinsics to fill up the block up to 75 percent, the rest can be used
|
||||
/// by Operational extrinsics.
|
||||
@@ -664,12 +667,13 @@ impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
|
||||
.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");
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
use bp_rialto::derive_account_from_millau_id;
|
||||
use polkadot_primitives::v1::{AssignmentId, ValidatorId};
|
||||
use rialto_runtime::{
|
||||
AccountId, BabeConfig, BalancesConfig, BridgeKovanConfig, BridgeMillauMessagesConfig, BridgeRialtoPoaConfig,
|
||||
ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig,
|
||||
WASM_BINARY,
|
||||
AccountId, BabeConfig, BalancesConfig, BridgeKovanConfig, BridgeMillauMessagesConfig,
|
||||
BridgeRialtoPoaConfig, ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig,
|
||||
SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
|
||||
};
|
||||
use serde_json::json;
|
||||
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||
@@ -62,14 +62,7 @@ where
|
||||
/// Helper function to generate authority keys.
|
||||
pub fn get_authority_keys_from_seed(
|
||||
s: &str,
|
||||
) -> (
|
||||
AccountId,
|
||||
BabeId,
|
||||
GrandpaId,
|
||||
ValidatorId,
|
||||
AssignmentId,
|
||||
AuthorityDiscoveryId,
|
||||
) {
|
||||
) -> (AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) {
|
||||
(
|
||||
get_account_id_from_seed::<sr25519::Public>(s),
|
||||
get_from_seed::<BabeId>(s),
|
||||
@@ -195,13 +188,7 @@ fn session_keys(
|
||||
para_assignment: AssignmentId,
|
||||
authority_discovery: AuthorityDiscoveryId,
|
||||
) -> SessionKeys {
|
||||
SessionKeys {
|
||||
babe,
|
||||
grandpa,
|
||||
para_validator,
|
||||
para_assignment,
|
||||
authority_discovery,
|
||||
}
|
||||
SessionKeys { babe, grandpa, para_validator, para_assignment, authority_discovery }
|
||||
}
|
||||
|
||||
fn testnet_genesis(
|
||||
@@ -231,9 +218,7 @@ fn testnet_genesis(
|
||||
},
|
||||
bridge_rialto_poa: load_rialto_poa_bridge_config(),
|
||||
bridge_kovan: load_kovan_bridge_config(),
|
||||
grandpa: GrandpaConfig {
|
||||
authorities: Vec::new(),
|
||||
},
|
||||
grandpa: GrandpaConfig { authorities: Vec::new() },
|
||||
sudo: SudoConfig { key: root_key },
|
||||
session: SessionConfig {
|
||||
keys: initial_authorities
|
||||
@@ -242,7 +227,13 @@ fn testnet_genesis(
|
||||
(
|
||||
x.0.clone(),
|
||||
x.0.clone(),
|
||||
session_keys(x.1.clone(), x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
|
||||
session_keys(
|
||||
x.1.clone(),
|
||||
x.2.clone(),
|
||||
x.3.clone(),
|
||||
x.4.clone(),
|
||||
x.5.clone(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
@@ -320,9 +311,7 @@ fn load_kovan_bridge_config() -> BridgeKovanConfig {
|
||||
#[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());
|
||||
}
|
||||
|
||||
@@ -14,8 +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::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;
|
||||
@@ -73,7 +75,7 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
));
|
||||
|
||||
match &cli.subcommand {
|
||||
Some(Subcommand::Benchmark(cmd)) => {
|
||||
Some(Subcommand::Benchmark(cmd)) =>
|
||||
if cfg!(feature = "runtime-benchmarks") {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
|
||||
@@ -84,8 +86,7 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
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(),
|
||||
@@ -93,69 +94,57 @@ 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(|mut config| {
|
||||
let PartialComponents {
|
||||
client,
|
||||
task_manager,
|
||||
import_queue,
|
||||
..
|
||||
} = new_partial(&mut config).map_err(service_error)?;
|
||||
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(|mut config| {
|
||||
let PartialComponents {
|
||||
client, task_manager, ..
|
||||
} = new_partial(&mut config).map_err(service_error)?;
|
||||
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(|mut config| {
|
||||
let PartialComponents {
|
||||
client, task_manager, ..
|
||||
} = new_partial(&mut config).map_err(service_error)?;
|
||||
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(|mut config| {
|
||||
let PartialComponents {
|
||||
client,
|
||||
task_manager,
|
||||
import_queue,
|
||||
..
|
||||
} = new_partial(&mut config).map_err(service_error)?;
|
||||
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(|mut config| {
|
||||
let PartialComponents {
|
||||
client,
|
||||
task_manager,
|
||||
backend,
|
||||
..
|
||||
} = new_partial(&mut config).map_err(service_error)?;
|
||||
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, crate::service::ExecutorDispatch>(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);
|
||||
@@ -163,7 +152,7 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
|
||||
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);
|
||||
@@ -171,7 +160,7 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
|
||||
polkadot_node_core_pvf::execute_worker_entrypoint(&cmd.socket_path);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let runner = cli.create_runner(&cli.run)?;
|
||||
|
||||
@@ -192,7 +181,7 @@ pub fn run() -> sc_cli::Result<()> {
|
||||
.map_err(service_error),
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,8 @@ where
|
||||
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 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.
|
||||
@@ -143,7 +144,10 @@ pub fn create_default_subsystems<Spawner, RuntimeClient>(
|
||||
ProvisionerSubsystem<Spawner>,
|
||||
RuntimeApiSubsystem<RuntimeClient>,
|
||||
AvailabilityStoreSubsystem,
|
||||
NetworkBridgeSubsystem<Arc<sc_network::NetworkService<Block, Hash>>, AuthorityDiscoveryService>,
|
||||
NetworkBridgeSubsystem<
|
||||
Arc<sc_network::NetworkService<Block, Hash>>,
|
||||
AuthorityDiscoveryService,
|
||||
>,
|
||||
ChainApiSubsystem<RuntimeClient>,
|
||||
CollationGenerationSubsystem,
|
||||
CollatorProtocolSubsystem,
|
||||
@@ -167,10 +171,7 @@ where
|
||||
let all_subsystems = AllSubsystems {
|
||||
availability_distribution: AvailabilityDistributionSubsystem::new(
|
||||
keystore.clone(),
|
||||
IncomingRequestReceivers {
|
||||
pov_req_receiver,
|
||||
chunk_req_receiver,
|
||||
},
|
||||
IncomingRequestReceivers { pov_req_receiver, chunk_req_receiver },
|
||||
Metrics::register(registry)?,
|
||||
),
|
||||
availability_recovery: AvailabilityRecoverySubsystem::with_chunks_only(
|
||||
@@ -212,7 +213,11 @@ where
|
||||
Metrics::register(registry)?,
|
||||
),
|
||||
provisioner: ProvisionerSubsystem::new(spawner.clone(), (), Metrics::register(registry)?),
|
||||
runtime_api: RuntimeApiSubsystem::new(runtime_client, Metrics::register(registry)?, spawner),
|
||||
runtime_api: RuntimeApiSubsystem::new(
|
||||
runtime_client,
|
||||
Metrics::register(registry)?,
|
||||
spawner,
|
||||
),
|
||||
statement_distribution: StatementDistributionSubsystem::new(
|
||||
keystore.clone(),
|
||||
statement_req_receiver,
|
||||
@@ -287,6 +292,7 @@ impl OverseerGen for RealOverseerGen {
|
||||
|
||||
let all_subsystems = create_default_subsystems::<Spawner, RuntimeClient>(args)?;
|
||||
|
||||
Overseer::new(leaves, all_subsystems, registry, runtime_client, spawner).map_err(|e| e.into())
|
||||
Overseer::new(leaves, all_subsystems, registry, runtime_client, spawner)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
//! 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, std::io, std::path::PathBuf, std::sync::Arc};
|
||||
use kvdb::KeyValueDB;
|
||||
use std::{io, path::PathBuf, sync::Arc};
|
||||
|
||||
mod columns {
|
||||
pub const NUM_COLUMNS: u32 = 5;
|
||||
@@ -66,11 +67,7 @@ pub struct CacheSizes {
|
||||
|
||||
impl Default for CacheSizes {
|
||||
fn default() -> Self {
|
||||
CacheSizes {
|
||||
availability_data: 25,
|
||||
availability_meta: 1,
|
||||
approval_data: 5,
|
||||
}
|
||||
CacheSizes { availability_data: 25, availability_meta: 1, approval_data: 5 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
//! The code is mostly copy of `service/src/lib.rs` file from Polkadot repository
|
||||
//! without optional functions.
|
||||
|
||||
// this warning comes from Error enum (sc_cli::Error in particular) && it isn't easy to use box there
|
||||
// this warning comes from Error enum (sc_cli::Error in particular) && it isn't easy to use box
|
||||
// there
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
// this warning comes from `sc_service::PartialComponents` type
|
||||
#![allow(clippy::type_complexity)]
|
||||
@@ -46,14 +47,12 @@ use sp_runtime::traits::{BlakeTwo256, Block as BlockT};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use substrate_prometheus_endpoint::Registry;
|
||||
|
||||
pub use {
|
||||
polkadot_overseer::{Handle, Overseer, OverseerHandle},
|
||||
polkadot_primitives::v1::ParachainHost,
|
||||
sc_client_api::AuxStore,
|
||||
sp_authority_discovery::AuthorityDiscoveryApi,
|
||||
sp_blockchain::HeaderBackend,
|
||||
sp_consensus_babe::BabeApi,
|
||||
};
|
||||
pub use polkadot_overseer::{Handle, Overseer, OverseerHandle};
|
||||
pub use polkadot_primitives::v1::ParachainHost;
|
||||
pub use sc_client_api::AuxStore;
|
||||
pub use sp_authority_discovery::AuthorityDiscoveryApi;
|
||||
pub use sp_blockchain::HeaderBackend;
|
||||
pub use sp_consensus_babe::BabeApi;
|
||||
|
||||
pub type Executor = NativeElseWasmExecutor<ExecutorDispatch>;
|
||||
|
||||
@@ -108,9 +107,11 @@ pub enum Error {
|
||||
type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
|
||||
type FullBackend = sc_service::TFullBackend<Block>;
|
||||
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
|
||||
type FullGrandpaBlockImport = sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>;
|
||||
type FullGrandpaBlockImport =
|
||||
sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>;
|
||||
type FullTransactionPool = sc_transaction_pool::FullPool<Block, FullClient>;
|
||||
type FullBabeBlockImport = sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>;
|
||||
type FullBabeBlockImport =
|
||||
sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>;
|
||||
type FullBabeLink = sc_consensus_babe::BabeLink<Block>;
|
||||
type FullGrandpaLink = sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>;
|
||||
|
||||
@@ -125,8 +126,11 @@ pub trait RequiredApiCollection:
|
||||
+ sp_finality_grandpa::GrandpaApi<Block>
|
||||
+ polkadot_primitives::v1::ParachainHost<Block>
|
||||
+ sp_block_builder::BlockBuilder<Block>
|
||||
+ frame_system_rpc_runtime_api::AccountNonceApi<Block, bp_rialto::AccountId, rialto_runtime::Index>
|
||||
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
|
||||
+ frame_system_rpc_runtime_api::AccountNonceApi<
|
||||
Block,
|
||||
bp_rialto::AccountId,
|
||||
rialto_runtime::Index,
|
||||
> + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
|
||||
+ sp_api::Metadata<Block>
|
||||
+ sp_offchain::OffchainWorkerApi<Block>
|
||||
+ sp_session::SessionKeys<Block>
|
||||
@@ -144,8 +148,11 @@ where
|
||||
+ sp_finality_grandpa::GrandpaApi<Block>
|
||||
+ polkadot_primitives::v1::ParachainHost<Block>
|
||||
+ sp_block_builder::BlockBuilder<Block>
|
||||
+ frame_system_rpc_runtime_api::AccountNonceApi<Block, bp_rialto::AccountId, rialto_runtime::Index>
|
||||
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
|
||||
+ frame_system_rpc_runtime_api::AccountNonceApi<
|
||||
Block,
|
||||
bp_rialto::AccountId,
|
||||
rialto_runtime::Index,
|
||||
> + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
|
||||
+ sp_api::Metadata<Block>
|
||||
+ sp_offchain::OffchainWorkerApi<Block>
|
||||
+ sp_session::SessionKeys<Block>
|
||||
@@ -210,11 +217,12 @@ where
|
||||
config.max_runtime_instances,
|
||||
);
|
||||
|
||||
let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::<Block, RuntimeApi, Executor>(
|
||||
config,
|
||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||
executor,
|
||||
)?;
|
||||
let (client, backend, keystore_container, task_manager) =
|
||||
sc_service::new_full_parts::<Block, RuntimeApi, Executor>(
|
||||
config,
|
||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||
executor,
|
||||
)?;
|
||||
let client = Arc::new(client);
|
||||
|
||||
let telemetry = telemetry.map(|(worker, telemetry)| {
|
||||
@@ -232,13 +240,14 @@ where
|
||||
client.clone(),
|
||||
);
|
||||
|
||||
let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import_with_authority_set_hard_forks(
|
||||
client.clone(),
|
||||
&(client.clone() as Arc<_>),
|
||||
select_chain.clone(),
|
||||
Vec::new(),
|
||||
telemetry.as_ref().map(|x| x.handle()),
|
||||
)?;
|
||||
let (grandpa_block_import, grandpa_link) =
|
||||
sc_finality_grandpa::block_import_with_authority_set_hard_forks(
|
||||
client.clone(),
|
||||
&(client.clone() as Arc<_>),
|
||||
select_chain.clone(),
|
||||
Vec::new(),
|
||||
telemetry.as_ref().map(|x| x.handle()),
|
||||
)?;
|
||||
let justification_import = grandpa_block_import.clone();
|
||||
|
||||
let babe_config = sc_consensus_babe::Config::get_or_compute(&*client)?;
|
||||
@@ -255,10 +264,11 @@ where
|
||||
move |_, ()| async move {
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let slot = sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
let slot =
|
||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
|
||||
Ok((timestamp, slot))
|
||||
},
|
||||
@@ -295,8 +305,10 @@ where
|
||||
|
||||
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()),
|
||||
);
|
||||
|
||||
let mut io = jsonrpc_core::IoHandler::default();
|
||||
io.extend_with(SystemApi::to_delegate(FullSystem::new(
|
||||
@@ -325,13 +337,7 @@ where
|
||||
select_chain,
|
||||
import_queue,
|
||||
transaction_pool,
|
||||
other: (
|
||||
rpc_extensions_builder,
|
||||
import_setup,
|
||||
rpc_setup,
|
||||
slot_duration,
|
||||
telemetry,
|
||||
),
|
||||
other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, telemetry),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -344,7 +350,7 @@ pub struct NewFull<C> {
|
||||
pub backend: Arc<FullBackend>,
|
||||
}
|
||||
|
||||
/// The maximum number of active leaves we forward to the [`Overseer`] on startup.
|
||||
/// The maximum number of active leaves we forward to the [`Overseer`] on start up.
|
||||
const MAX_ACTIVE_LEAVES: usize = 4;
|
||||
|
||||
/// Returns the active leaves the overseer should start with.
|
||||
@@ -370,16 +376,12 @@ where
|
||||
|
||||
// Only consider leaves that are in maximum an uncle of the best block.
|
||||
if number < best_block.number().saturating_sub(1) || hash == best_block.hash() {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
let parent_hash = client.header(&BlockId::Hash(hash)).ok()??.parent_hash;
|
||||
|
||||
Some(BlockInfo {
|
||||
hash,
|
||||
parent_hash,
|
||||
number,
|
||||
})
|
||||
Some(BlockInfo { hash, parent_hash, number })
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -411,7 +413,8 @@ where
|
||||
|
||||
let role = config.role.clone();
|
||||
let force_authoring = config.force_authoring;
|
||||
let backoff_authoring_blocks = Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default());
|
||||
let backoff_authoring_blocks =
|
||||
Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default());
|
||||
|
||||
let disable_grandpa = config.disable_grandpa;
|
||||
let name = config.network.node_name.clone();
|
||||
@@ -435,18 +438,11 @@ where
|
||||
// Note: GrandPa is pushed before the Polkadot-specific protocols. This doesn't change
|
||||
// anything in terms of behaviour, but makes the logs more consistent with the other
|
||||
// Substrate nodes.
|
||||
config
|
||||
.network
|
||||
.extra_sets
|
||||
.push(sc_finality_grandpa::grandpa_peers_set_config());
|
||||
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
|
||||
|
||||
{
|
||||
use polkadot_network_bridge::{peer_sets_info, IsAuthority};
|
||||
let is_authority = if role.is_authority() {
|
||||
IsAuthority::Yes
|
||||
} else {
|
||||
IsAuthority::No
|
||||
};
|
||||
let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No };
|
||||
config.network.extra_sets.extend(peer_sets_info(is_authority));
|
||||
}
|
||||
|
||||
@@ -468,20 +464,25 @@ where
|
||||
import_setup.1.shared_authority_set().clone(),
|
||||
));
|
||||
|
||||
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,
|
||||
warp_sync: Some(warp_sync),
|
||||
})?;
|
||||
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,
|
||||
warp_sync: Some(warp_sync),
|
||||
})?;
|
||||
|
||||
if config.offchain_worker.enabled {
|
||||
let _ =
|
||||
sc_service::build_offchain_workers(&config, task_manager.spawn_handle(), client.clone(), network.clone());
|
||||
let _ = sc_service::build_offchain_workers(
|
||||
&config,
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
network.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
let parachains_db = crate::parachains_db::open_creating(
|
||||
@@ -551,12 +552,13 @@ where
|
||||
// don't publish our addresses when we're only a collator
|
||||
sc_authority_discovery::Role::Discover
|
||||
};
|
||||
let dht_event_stream = network.event_stream("authority-discovery").filter_map(|e| async move {
|
||||
match e {
|
||||
Event::Dht(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
let dht_event_stream =
|
||||
network.event_stream("authority-discovery").filter_map(|e| async move {
|
||||
match e {
|
||||
Event::Dht(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config(
|
||||
sc_authority_discovery::WorkerConfig {
|
||||
publish_non_global_ips: auth_disc_publish_non_global_ips,
|
||||
@@ -569,22 +571,22 @@ where
|
||||
prometheus_registry.clone(),
|
||||
);
|
||||
|
||||
task_manager
|
||||
.spawn_handle()
|
||||
.spawn("authority-discovery-worker", worker.run());
|
||||
task_manager.spawn_handle().spawn("authority-discovery-worker", worker.run());
|
||||
Some(service)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// we'd say let overseer_handler = authority_discovery_service.map(|authority_discovery_service|, ...),
|
||||
// but in that case we couldn't use ? to propagate errors
|
||||
// we'd say let overseer_handler =
|
||||
// authority_discovery_service.map(|authority_discovery_service|, ...), but in that case we
|
||||
// couldn't use ? to propagate errors
|
||||
let local_keystore = keystore_container.local_keystore();
|
||||
let maybe_params = local_keystore.and_then(move |k| authority_discovery_service.map(|a| (a, k)));
|
||||
let maybe_params =
|
||||
local_keystore.and_then(move |k| authority_discovery_service.map(|a| (a, k)));
|
||||
|
||||
let overseer_handle = if let Some((authority_discovery_service, keystore)) = maybe_params {
|
||||
let (overseer, overseer_handle) =
|
||||
overseer_gen.generate::<sc_service::SpawnTaskHandle, FullClient>(OverseerGenArgs {
|
||||
let (overseer, overseer_handle) = overseer_gen
|
||||
.generate::<sc_service::SpawnTaskHandle, FullClient>(OverseerGenArgs {
|
||||
leaves: active_leaves,
|
||||
keystore,
|
||||
runtime_client: overseer_client.clone(),
|
||||
@@ -635,7 +637,8 @@ where
|
||||
};
|
||||
|
||||
if role.is_authority() {
|
||||
let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
|
||||
let can_author_with =
|
||||
sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
|
||||
|
||||
let proposer = sc_basic_authorship::ProposerFactory::new(
|
||||
task_manager.spawn_handle(),
|
||||
@@ -646,10 +649,8 @@ where
|
||||
);
|
||||
|
||||
let client_clone = client.clone();
|
||||
let overseer_handle = overseer_handle
|
||||
.as_ref()
|
||||
.ok_or(Error::AuthoritiesRequireRealOverseer)?
|
||||
.clone();
|
||||
let overseer_handle =
|
||||
overseer_handle.as_ref().ok_or(Error::AuthoritiesRequireRealOverseer)?.clone();
|
||||
let slot_duration = babe_link.config().slot_duration();
|
||||
let babe_config = sc_consensus_babe::BabeParams {
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
@@ -671,7 +672,10 @@ where
|
||||
.await
|
||||
.map_err(Box::new)?;
|
||||
|
||||
let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider(&*client_clone, parent)?;
|
||||
let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider(
|
||||
&*client_clone,
|
||||
parent,
|
||||
)?;
|
||||
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
@@ -698,11 +702,8 @@ where
|
||||
|
||||
// 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_opt = if role.is_authority() {
|
||||
Some(keystore_container.sync_keystore())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let keystore_opt =
|
||||
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
|
||||
|
||||
let config = sc_finality_grandpa::Config {
|
||||
// FIXME substrate#1578 make this available through chainspec
|
||||
@@ -740,23 +741,20 @@ where
|
||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||
};
|
||||
|
||||
task_manager
|
||||
.spawn_essential_handle()
|
||||
.spawn_blocking("grandpa-voter", sc_finality_grandpa::run_grandpa_voter(grandpa_config)?);
|
||||
task_manager.spawn_essential_handle().spawn_blocking(
|
||||
"grandpa-voter",
|
||||
sc_finality_grandpa::run_grandpa_voter(grandpa_config)?,
|
||||
);
|
||||
}
|
||||
|
||||
network_starter.start_network();
|
||||
|
||||
Ok(NewFull {
|
||||
task_manager,
|
||||
client,
|
||||
overseer_handle,
|
||||
network,
|
||||
rpc_handlers,
|
||||
backend,
|
||||
})
|
||||
Ok(NewFull { task_manager, client, overseer_handle, network, rpc_handlers, backend })
|
||||
}
|
||||
|
||||
pub fn build_full(config: Configuration, overseer_gen: impl OverseerGen) -> Result<NewFull<Arc<FullClient>>, Error> {
|
||||
pub fn build_full(
|
||||
config: Configuration,
|
||||
overseer_gen: impl OverseerGen,
|
||||
) -> Result<NewFull<Arc<FullClient>>, Error> {
|
||||
new_full(config, None, overseer_gen)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ use pallet_bridge_eth_poa::{ValidatorsConfiguration, ValidatorsSource};
|
||||
use sp_std::vec;
|
||||
|
||||
pub use crate::kovan::{
|
||||
genesis_header, genesis_validators, BridgeAuraConfiguration, FinalityVotesCachingInterval, PruningStrategy,
|
||||
genesis_header, genesis_validators, BridgeAuraConfiguration, FinalityVotesCachingInterval,
|
||||
PruningStrategy,
|
||||
};
|
||||
|
||||
frame_support::parameter_types! {
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
//! 5) receive tokens by providing proof-of-inclusion of PoA transaction.
|
||||
|
||||
use bp_currency_exchange::{
|
||||
Error as ExchangeError, LockFundsTransaction, MaybeLockFundsTransaction, Result as ExchangeResult,
|
||||
Error as ExchangeError, LockFundsTransaction, MaybeLockFundsTransaction,
|
||||
Result as ExchangeResult,
|
||||
};
|
||||
use bp_eth_poa::{transaction_decode_rlp, RawTransaction, RawTransactionReceipt};
|
||||
use codec::{Decode, Encode};
|
||||
@@ -87,7 +88,7 @@ impl MaybeLockFundsTransaction for EthTransaction {
|
||||
tx.unsigned.to,
|
||||
);
|
||||
|
||||
return Err(ExchangeError::InvalidTransaction);
|
||||
return Err(ExchangeError::InvalidTransaction)
|
||||
}
|
||||
|
||||
let mut recipient_raw = sp_core::H256::default();
|
||||
@@ -100,8 +101,8 @@ impl MaybeLockFundsTransaction for EthTransaction {
|
||||
len,
|
||||
);
|
||||
|
||||
return Err(ExchangeError::InvalidRecipient);
|
||||
}
|
||||
return Err(ExchangeError::InvalidRecipient)
|
||||
},
|
||||
}
|
||||
let amount = tx.unsigned.value.low_u128();
|
||||
|
||||
@@ -112,7 +113,7 @@ impl MaybeLockFundsTransaction for EthTransaction {
|
||||
tx.unsigned.value,
|
||||
);
|
||||
|
||||
return Err(ExchangeError::InvalidAmount);
|
||||
return Err(ExchangeError::InvalidAmount)
|
||||
}
|
||||
|
||||
Ok(LockFundsTransaction {
|
||||
@@ -213,10 +214,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn invalid_transaction_rejected() {
|
||||
assert_eq!(
|
||||
EthTransaction::parse(&Vec::new()),
|
||||
Err(ExchangeError::InvalidTransaction),
|
||||
);
|
||||
assert_eq!(EthTransaction::parse(&Vec::new()), Err(ExchangeError::InvalidTransaction),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -21,8 +21,8 @@ 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,
|
||||
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as BridgePruningStrategy,
|
||||
ValidatorsConfiguration, ValidatorsSource,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
@@ -102,11 +102,14 @@ pub fn genesis_header() -> AuraHeader {
|
||||
timestamp: 0,
|
||||
number: 0,
|
||||
author: Default::default(),
|
||||
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
|
||||
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(),
|
||||
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
.into(),
|
||||
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
|
||||
.into(),
|
||||
extra_data: vec![],
|
||||
state_root: hex!("2480155b48a1cea17d67dbfdfaafe821c1d19cdd478c5358e8ec56dec24502b2").into(),
|
||||
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
|
||||
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
.into(),
|
||||
log_bloom: Default::default(),
|
||||
gas_used: Default::default(),
|
||||
gas_limit: 6000000.into(),
|
||||
@@ -114,8 +117,9 @@ pub fn genesis_header() -> AuraHeader {
|
||||
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,
|
||||
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,
|
||||
],
|
||||
],
|
||||
}
|
||||
@@ -153,12 +157,17 @@ 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);
|
||||
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;
|
||||
return None
|
||||
}
|
||||
|
||||
proof.proof.get(proof.index as usize).map(|(tx, _)| tx.clone())
|
||||
|
||||
@@ -41,15 +41,19 @@ pub mod rialto_poa;
|
||||
|
||||
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
|
||||
|
||||
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 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_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo};
|
||||
use sp_api::impl_runtime_apis;
|
||||
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
||||
use sp_runtime::traits::{AccountIdLookup, Block as BlockT, NumberFor, OpaqueKeys};
|
||||
use sp_runtime::{
|
||||
create_runtime_str, generic, impl_opaque_keys,
|
||||
traits::{AccountIdLookup, Block as BlockT, NumberFor, OpaqueKeys},
|
||||
transaction_validity::{TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
|
||||
};
|
||||
@@ -149,10 +153,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! {
|
||||
@@ -238,10 +239,14 @@ impl pallet_babe::Config for Runtime {
|
||||
|
||||
// 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 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 = ();
|
||||
@@ -308,13 +313,18 @@ 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);
|
||||
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
|
||||
// I'm dropping deposited here explicitly to illustrate the fact that it'll update
|
||||
// `TotalIssuance` on drop
|
||||
let deposited_amount = deposited.peek();
|
||||
drop(deposited);
|
||||
|
||||
@@ -332,7 +342,7 @@ impl bp_currency_exchange::DepositInto for DepositInto {
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
_ if deposited_amount == 0 => {
|
||||
log::error!(
|
||||
target: "runtime",
|
||||
@@ -342,7 +352,7 @@ impl bp_currency_exchange::DepositInto for DepositInto {
|
||||
);
|
||||
|
||||
Err(bp_currency_exchange::Error::DepositFailed)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
log::error!(
|
||||
target: "runtime",
|
||||
@@ -354,7 +364,7 @@ impl bp_currency_exchange::DepositInto for DepositInto {
|
||||
|
||||
// we can't return DepositFailed error here, because storage changes were made
|
||||
Err(bp_currency_exchange::Error::DepositPartiallyFailed)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,9 +373,12 @@ 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 = ();
|
||||
@@ -529,12 +542,13 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
|
||||
|
||||
type TargetHeaderChain = crate::millau_messages::Millau;
|
||||
type LaneMessageVerifier = crate::millau_messages::ToMillauMessageVerifier;
|
||||
type MessageDeliveryAndDispatchPayment = pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
|
||||
Runtime,
|
||||
pallet_balances::Pallet<Runtime>,
|
||||
GetDeliveryConfirmationTransactionFee,
|
||||
RootAccountForPayments,
|
||||
>;
|
||||
type MessageDeliveryAndDispatchPayment =
|
||||
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
|
||||
Runtime,
|
||||
pallet_balances::Pallet<Runtime>,
|
||||
GetDeliveryConfirmationTransactionFee,
|
||||
RootAccountForPayments,
|
||||
>;
|
||||
type OnMessageAccepted = ();
|
||||
type OnDeliveryConfirmed = ();
|
||||
|
||||
@@ -625,8 +639,13 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signatu
|
||||
/// 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>;
|
||||
pub type Executive = frame_executive::Executive<
|
||||
Runtime,
|
||||
Block,
|
||||
frame_system::ChainContext<Runtime>,
|
||||
Runtime,
|
||||
AllPallets,
|
||||
>;
|
||||
|
||||
impl_runtime_apis! {
|
||||
impl sp_api::Core<Block> for Runtime {
|
||||
@@ -1277,8 +1296,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,
|
||||
@@ -1305,7 +1324,8 @@ mod tests {
|
||||
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();
|
||||
let mut ext: sp_io::TestExternalities =
|
||||
SystemConfig::default().build_storage::<Runtime>().unwrap().into();
|
||||
ext.execute_with(|| {
|
||||
// initially issuance is zero
|
||||
assert_eq!(
|
||||
@@ -1317,7 +1337,10 @@ mod tests {
|
||||
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);
|
||||
<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(),
|
||||
@@ -1358,15 +1381,18 @@ mod tests {
|
||||
bp_rialto::max_extrinsic_size(),
|
||||
bp_rialto::max_extrinsic_weight(),
|
||||
max_incoming_message_proof_size,
|
||||
messages::target::maximal_incoming_message_dispatch_weight(bp_rialto::max_extrinsic_weight()),
|
||||
messages::target::maximal_incoming_message_dispatch_weight(
|
||||
bp_rialto::max_extrinsic_weight(),
|
||||
),
|
||||
);
|
||||
|
||||
let max_incoming_inbound_lane_data_proof_size = bp_messages::InboundLaneData::<()>::encoded_size_hint(
|
||||
bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE,
|
||||
bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE as _,
|
||||
bp_millau::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_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE,
|
||||
bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE as _,
|
||||
bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE as _,
|
||||
)
|
||||
.unwrap_or(u32::MAX);
|
||||
pallet_bridge_messages::ensure_able_to_receive_confirmation::<Weights>(
|
||||
bp_rialto::max_extrinsic_size(),
|
||||
bp_rialto::max_extrinsic_weight(),
|
||||
@@ -1381,7 +1407,9 @@ mod tests {
|
||||
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);
|
||||
<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(),
|
||||
@@ -1389,7 +1417,9 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&existing_account),
|
||||
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
|
||||
&existing_account
|
||||
),
|
||||
initial_amount + additional_amount,
|
||||
);
|
||||
additional_amount
|
||||
@@ -1408,7 +1438,9 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&new_account),
|
||||
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
|
||||
&new_account
|
||||
),
|
||||
initial_amount + additional_amount,
|
||||
);
|
||||
additional_amount
|
||||
|
||||
@@ -35,7 +35,8 @@ 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);
|
||||
|
||||
@@ -47,13 +48,16 @@ parameter_types! {
|
||||
}
|
||||
|
||||
/// 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>;
|
||||
@@ -70,7 +74,8 @@ pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDi
|
||||
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)]
|
||||
@@ -86,8 +91,10 @@ impl MessageBridge for WithMillauMessageBridge {
|
||||
type BridgedChain = Millau;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,12 +174,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
|
||||
}
|
||||
@@ -232,9 +242,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +263,11 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,9 +281,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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,7 +297,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},
|
||||
@@ -297,12 +311,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 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
|
||||
@@ -314,12 +331,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,
|
||||
@@ -329,10 +347,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,
|
||||
@@ -348,11 +363,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,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -17,25 +17,21 @@
|
||||
//! Parachains support in Rialto runtime.
|
||||
|
||||
use crate::{
|
||||
AccountId, Balance, Balances, BlockNumber, Event, Origin, RandomnessCollectiveFlip, Registrar, Runtime, Slots,
|
||||
AccountId, Balance, Balances, BlockNumber, Event, Origin, RandomnessCollectiveFlip, 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;
|
||||
use polkadot_runtime_parachains::dmp as parachains_dmp;
|
||||
use polkadot_runtime_parachains::hrmp as parachains_hrmp;
|
||||
use polkadot_runtime_parachains::inclusion as parachains_inclusion;
|
||||
use polkadot_runtime_parachains::initializer as parachains_initializer;
|
||||
use polkadot_runtime_parachains::origin as parachains_origin;
|
||||
use polkadot_runtime_parachains::paras as parachains_paras;
|
||||
use polkadot_runtime_parachains::paras_inherent as parachains_paras_inherent;
|
||||
use polkadot_runtime_parachains::scheduler as parachains_scheduler;
|
||||
use polkadot_runtime_parachains::session_info as parachains_session_info;
|
||||
use polkadot_runtime_parachains::shared as parachains_shared;
|
||||
use polkadot_runtime_parachains::ump as parachains_ump;
|
||||
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;
|
||||
|
||||
@@ -23,8 +23,8 @@ 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,
|
||||
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as TPruningStrategy,
|
||||
ValidatorsConfiguration, ValidatorsSource,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
@@ -79,11 +79,14 @@ pub fn genesis_header() -> AuraHeader {
|
||||
timestamp: 0,
|
||||
number: 0,
|
||||
author: Default::default(),
|
||||
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
|
||||
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(),
|
||||
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
.into(),
|
||||
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
|
||||
.into(),
|
||||
extra_data: vec![],
|
||||
state_root: hex!("a992d04c791620ed7ed96555a80cf0568355bb4bee2656f46899a4372f25f248").into(),
|
||||
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
|
||||
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
.into(),
|
||||
log_bloom: Default::default(),
|
||||
gas_used: Default::default(),
|
||||
gas_limit: 0x222222.into(),
|
||||
@@ -128,12 +131,17 @@ 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);
|
||||
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;
|
||||
return None
|
||||
}
|
||||
|
||||
proof.proof.get(proof.index as usize).map(|(tx, _)| tx.clone())
|
||||
|
||||
@@ -41,7 +41,10 @@ use sp_runtime::{
|
||||
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.
|
||||
@@ -64,7 +67,9 @@ pub trait MessageBridge {
|
||||
type BridgedChain: BridgedChainWithMessages;
|
||||
|
||||
/// 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.
|
||||
@@ -83,7 +88,14 @@ pub trait ChainWithMessages {
|
||||
/// 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.
|
||||
@@ -138,7 +150,8 @@ 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>;
|
||||
}
|
||||
|
||||
@@ -158,10 +171,11 @@ 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,
|
||||
@@ -224,7 +238,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.
|
||||
///
|
||||
@@ -236,19 +251,27 @@ 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.";
|
||||
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.";
|
||||
|
||||
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,
|
||||
@@ -264,7 +287,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
|
||||
@@ -273,19 +296,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(())
|
||||
@@ -307,13 +331,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
|
||||
@@ -321,16 +345,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,
|
||||
@@ -339,25 +364,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.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
|
||||
@@ -378,14 +401,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),
|
||||
@@ -470,14 +493,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)
|
||||
}
|
||||
@@ -495,16 +517,22 @@ pub mod target {
|
||||
where
|
||||
BalanceOf<ThisChain<B>>: Saturating + FixedPointOperand,
|
||||
ThisDispatchInstance: 'static,
|
||||
ThisRuntime: pallet_bridge_dispatch::Config<ThisDispatchInstance, BridgeMessageId = (LaneId, MessageNonce)>
|
||||
+ pallet_transaction_payment::Config,
|
||||
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>>>,
|
||||
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,8 +554,10 @@ pub mod target {
|
||||
message.data.payload.map_err(drop),
|
||||
|dispatch_origin, dispatch_weight| {
|
||||
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);
|
||||
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,
|
||||
@@ -565,8 +595,11 @@ pub mod target {
|
||||
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<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,
|
||||
>,
|
||||
>,
|
||||
{
|
||||
verify_messages_proof_with_parser::<B, _, _>(
|
||||
proof,
|
||||
@@ -601,12 +634,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,
|
||||
}
|
||||
}
|
||||
@@ -629,10 +663,11 @@ 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::BRIDGED_MESSAGES_PALLET_NAME, 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>> {
|
||||
@@ -652,7 +687,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 {
|
||||
@@ -664,18 +700,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)?;
|
||||
|
||||
@@ -689,20 +726,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(
|
||||
@@ -713,7 +745,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
|
||||
@@ -739,7 +771,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;
|
||||
|
||||
@@ -752,12 +785,15 @@ mod tests {
|
||||
type ThisChain = ThisChain;
|
||||
type BridgedChain = BridgedChain;
|
||||
|
||||
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;
|
||||
|
||||
@@ -892,7 +928,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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -913,7 +951,9 @@ mod tests {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn transaction_payment(_transaction: MessageTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
|
||||
fn transaction_payment(
|
||||
_transaction: MessageTransaction<WeightOf<Self>>,
|
||||
) -> BalanceOf<Self> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
@@ -944,7 +984,9 @@ mod tests {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn transaction_payment(_transaction: MessageTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
|
||||
fn transaction_payment(
|
||||
_transaction: MessageTransaction<WeightOf<Self>>,
|
||||
) -> BalanceOf<Self> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
@@ -955,7 +997,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
|
||||
}
|
||||
|
||||
@@ -971,7 +1014,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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,19 +1027,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> {
|
||||
@@ -1013,7 +1061,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,
|
||||
@@ -1042,11 +1091,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 {}",
|
||||
@@ -1065,16 +1117,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]
|
||||
@@ -1109,16 +1159,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]
|
||||
@@ -1143,16 +1191,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]
|
||||
@@ -1189,64 +1235,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(()),
|
||||
);
|
||||
}
|
||||
@@ -1338,13 +1378,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),
|
||||
);
|
||||
}
|
||||
@@ -1352,13 +1394,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),
|
||||
);
|
||||
}
|
||||
@@ -1366,8 +1410,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 {
|
||||
@@ -1375,8 +1421,8 @@ mod tests {
|
||||
latest_received_nonce: 1,
|
||||
latest_generated_nonce: 1,
|
||||
}),
|
||||
}
|
||||
),),
|
||||
}),
|
||||
),
|
||||
Err(target::MessageProofError::FailedToDecodeOutboundLaneState),
|
||||
);
|
||||
}
|
||||
@@ -1384,13 +1430,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),
|
||||
);
|
||||
}
|
||||
@@ -1398,8 +1446,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 {
|
||||
@@ -1407,8 +1457,8 @@ mod tests {
|
||||
latest_received_nonce: 1,
|
||||
latest_generated_nonce: 1,
|
||||
}),
|
||||
}
|
||||
),),
|
||||
}),
|
||||
),
|
||||
Ok(vec![(
|
||||
Default::default(),
|
||||
ProvedLaneMessages {
|
||||
@@ -1428,8 +1478,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 {
|
||||
@@ -1437,8 +1489,8 @@ mod tests {
|
||||
latest_received_nonce: 1,
|
||||
latest_generated_nonce: 1,
|
||||
}),
|
||||
}
|
||||
),),
|
||||
}),
|
||||
),
|
||||
Ok(vec![(
|
||||
Default::default(),
|
||||
ProvedLaneMessages {
|
||||
@@ -1448,14 +1500,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) },
|
||||
}],
|
||||
},
|
||||
)]
|
||||
@@ -1494,10 +1540,7 @@ mod tests {
|
||||
10,
|
||||
FixedU128::zero(),
|
||||
|weight| weight,
|
||||
MessageTransaction {
|
||||
size: 50,
|
||||
dispatch_weight: 777
|
||||
},
|
||||
MessageTransaction { size: 50, dispatch_weight: 777 },
|
||||
),
|
||||
100 + 50 * 10,
|
||||
);
|
||||
@@ -1513,10 +1556,7 @@ mod tests {
|
||||
10,
|
||||
FixedU128::one(),
|
||||
|weight| weight,
|
||||
MessageTransaction {
|
||||
size: 50,
|
||||
dispatch_weight: 777
|
||||
},
|
||||
MessageTransaction { size: 50, dispatch_weight: 777 },
|
||||
),
|
||||
100 + 50 * 10 + 777,
|
||||
);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
//! So we are giving runtime opportunity to prepare environment and construct proof
|
||||
//! before invoking module calls.
|
||||
|
||||
use super::{Call, Config as CurrencyExchangeConfig, InclusionProofVerifier, Pallet as CurrencyExchangePallet};
|
||||
use super::{
|
||||
Call, Config as CurrencyExchangeConfig, InclusionProofVerifier,
|
||||
Pallet as CurrencyExchangePallet,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use frame_benchmarking::{account, benchmarks_instance_pallet};
|
||||
@@ -37,8 +40,8 @@ pub struct ProofParams<Recipient> {
|
||||
pub recipient: Recipient,
|
||||
/// When true, recipient must exists before import.
|
||||
pub recipient_exists: bool,
|
||||
/// When 0, transaction should have minimal possible size. When this value has non-zero value n,
|
||||
/// transaction size should be (if possible) near to MIN_SIZE + n * SIZE_FACTOR.
|
||||
/// When 0, transaction should have minimal possible size. When this value has non-zero value
|
||||
/// n, transaction size should be (if possible) near to MIN_SIZE + n * SIZE_FACTOR.
|
||||
pub transaction_size_factor: u32,
|
||||
/// When 0, proof should have minimal possible size. When this value has non-zero value n,
|
||||
/// proof size should be (if possible) near to MIN_SIZE + n * SIZE_FACTOR.
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use bp_currency_exchange::{
|
||||
CurrencyConverter, DepositInto, Error as ExchangeError, MaybeLockFundsTransaction, RecipientsMap,
|
||||
CurrencyConverter, DepositInto, Error as ExchangeError, MaybeLockFundsTransaction,
|
||||
RecipientsMap,
|
||||
};
|
||||
use bp_header_chain::InclusionProofVerifier;
|
||||
use frame_support::ensure;
|
||||
@@ -92,7 +93,8 @@ pub mod pallet {
|
||||
{
|
||||
// if any changes were made to the storage, we can't just return error here, because
|
||||
// otherwise the same proof may be imported again
|
||||
let deposit_result = T::DepositInto::deposit_into(deposit.recipient, deposit.amount);
|
||||
let deposit_result =
|
||||
T::DepositInto::deposit_into(deposit.recipient, deposit.amount);
|
||||
match deposit_result {
|
||||
Ok(_) => (),
|
||||
Err(ExchangeError::DepositPartiallyFailed) => (),
|
||||
@@ -160,7 +162,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
err,
|
||||
);
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
true
|
||||
@@ -205,23 +207,16 @@ fn prepare_deposit_details<T: Config<I>, I: 'static>(
|
||||
.ok_or(Error::<T, I>::UnfinalizedTransaction)?;
|
||||
|
||||
// parse transaction
|
||||
let transaction =
|
||||
<T as Config<I>>::PeerMaybeLockFundsTransaction::parse(&transaction).map_err(Error::<T, I>::from)?;
|
||||
let transaction = <T as Config<I>>::PeerMaybeLockFundsTransaction::parse(&transaction)
|
||||
.map_err(Error::<T, I>::from)?;
|
||||
let transfer_id = transaction.id;
|
||||
ensure!(
|
||||
!Transfers::<T, I>::contains_key(&transfer_id),
|
||||
Error::<T, I>::AlreadyClaimed
|
||||
);
|
||||
ensure!(!Transfers::<T, I>::contains_key(&transfer_id), Error::<T, I>::AlreadyClaimed);
|
||||
|
||||
// grant recipient
|
||||
let recipient = T::RecipientsMap::map(transaction.recipient).map_err(Error::<T, I>::from)?;
|
||||
let amount = T::CurrencyConverter::convert(transaction.amount).map_err(Error::<T, I>::from)?;
|
||||
|
||||
Ok(DepositDetails {
|
||||
transfer_id,
|
||||
recipient,
|
||||
amount,
|
||||
})
|
||||
Ok(DepositDetails { transfer_id, recipient, amount })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -231,7 +226,9 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use bp_currency_exchange::LockFundsTransaction;
|
||||
use frame_support::{assert_noop, assert_ok, construct_runtime, parameter_types, weights::Weight};
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, construct_runtime, parameter_types, weights::Weight,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
@@ -264,7 +261,9 @@ mod tests {
|
||||
type Transaction = RawTransaction;
|
||||
type TransactionInclusionProof = (bool, RawTransaction);
|
||||
|
||||
fn verify_transaction_inclusion_proof(proof: &Self::TransactionInclusionProof) -> Option<RawTransaction> {
|
||||
fn verify_transaction_inclusion_proof(
|
||||
proof: &Self::TransactionInclusionProof,
|
||||
) -> Option<RawTransaction> {
|
||||
if proof.0 {
|
||||
Some(proof.1.clone())
|
||||
} else {
|
||||
@@ -295,7 +294,9 @@ mod tests {
|
||||
type PeerRecipient = AccountId;
|
||||
type Recipient = AccountId;
|
||||
|
||||
fn map(peer_recipient: Self::PeerRecipient) -> bp_currency_exchange::Result<Self::Recipient> {
|
||||
fn map(
|
||||
peer_recipient: Self::PeerRecipient,
|
||||
) -> bp_currency_exchange::Result<Self::Recipient> {
|
||||
match peer_recipient {
|
||||
UNKNOWN_RECIPIENT_ID => Err(ExchangeError::FailedToMapRecipients),
|
||||
_ => Ok(peer_recipient * 10),
|
||||
@@ -323,10 +324,14 @@ mod tests {
|
||||
type Recipient = AccountId;
|
||||
type Amount = u64;
|
||||
|
||||
fn deposit_into(_recipient: Self::Recipient, amount: Self::Amount) -> bp_currency_exchange::Result<()> {
|
||||
fn deposit_into(
|
||||
_recipient: Self::Recipient,
|
||||
amount: Self::Amount,
|
||||
) -> bp_currency_exchange::Result<()> {
|
||||
match amount {
|
||||
amount if amount < MAX_DEPOSIT_AMOUNT * 10 => Ok(()),
|
||||
amount if amount == MAX_DEPOSIT_AMOUNT * 10 => Err(ExchangeError::DepositPartiallyFailed),
|
||||
amount if amount == MAX_DEPOSIT_AMOUNT * 10 =>
|
||||
Err(ExchangeError::DepositPartiallyFailed),
|
||||
_ => Err(ExchangeError::DepositFailed),
|
||||
}
|
||||
}
|
||||
@@ -391,25 +396,22 @@ mod tests {
|
||||
}
|
||||
|
||||
fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let t = frame_system::GenesisConfig::default()
|
||||
.build_storage::<TestRuntime>()
|
||||
.unwrap();
|
||||
let t = frame_system::GenesisConfig::default().build_storage::<TestRuntime>().unwrap();
|
||||
sp_io::TestExternalities::new(t)
|
||||
}
|
||||
|
||||
fn transaction(id: u64) -> RawTransaction {
|
||||
RawTransaction {
|
||||
id,
|
||||
recipient: 1,
|
||||
amount: 2,
|
||||
}
|
||||
RawTransaction { id, recipient: 1, amount: 2 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfinalized_transaction_rejected() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(
|
||||
Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (false, transaction(0))),
|
||||
Exchange::import_peer_transaction(
|
||||
Origin::signed(SUBMITTER),
|
||||
(false, transaction(0))
|
||||
),
|
||||
Error::<TestRuntime, ()>::UnfinalizedTransaction,
|
||||
);
|
||||
});
|
||||
|
||||
+221
-120
@@ -60,7 +60,13 @@ pub mod pallet {
|
||||
/// it comes from the messages module.
|
||||
type BridgeMessageId: Parameter;
|
||||
/// Type of account ID on source chain.
|
||||
type SourceChainAccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + Default;
|
||||
type SourceChainAccountId: Parameter
|
||||
+ Member
|
||||
+ MaybeSerializeDeserialize
|
||||
+ Debug
|
||||
+ MaybeDisplay
|
||||
+ Ord
|
||||
+ Default;
|
||||
/// Type of account public key on target chain.
|
||||
type TargetChainAccountPublic: Parameter + IdentifyAccount<AccountId = Self::AccountId>;
|
||||
/// Type of signature that may prove that the message has been signed by
|
||||
@@ -75,8 +81,8 @@ pub mod pallet {
|
||||
>;
|
||||
/// Pre-dispatch filter for incoming calls.
|
||||
///
|
||||
/// The pallet will filter all incoming calls right before they're dispatched. If this filter
|
||||
/// rejects the call, special event (`Event::MessageCallRejected`) is emitted.
|
||||
/// The pallet will filter all incoming calls right before they're dispatched. If this
|
||||
/// filter rejects the call, special event (`Event::MessageCallRejected`) is emitted.
|
||||
type CallFilter: Contains<<Self as Config<I>>::Call>;
|
||||
/// The type that is used to wrap the `Self::Call` when it is moved over bridge.
|
||||
///
|
||||
@@ -136,8 +142,12 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId> for Pallet<T, I> {
|
||||
type Message =
|
||||
MessagePayload<T::SourceChainAccountId, T::TargetChainAccountPublic, T::TargetChainSignature, T::EncodedCall>;
|
||||
type Message = MessagePayload<
|
||||
T::SourceChainAccountId,
|
||||
T::TargetChainAccountPublic,
|
||||
T::TargetChainSignature,
|
||||
T::EncodedCall,
|
||||
>;
|
||||
|
||||
fn dispatch_weight(message: &Self::Message) -> bp_message_dispatch::Weight {
|
||||
message.weight
|
||||
@@ -165,8 +175,8 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
dispatch_result: false,
|
||||
unspent_weight: 0,
|
||||
dispatch_fee_paid_during_dispatch: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// verify spec version
|
||||
@@ -191,7 +201,7 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
expected_version,
|
||||
message.spec_version,
|
||||
));
|
||||
return dispatch_result;
|
||||
return dispatch_result
|
||||
}
|
||||
|
||||
// now that we have spec version checked, let's decode the call
|
||||
@@ -205,18 +215,19 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
id,
|
||||
);
|
||||
Self::deposit_event(Event::MessageCallDecodeFailed(source_chain, id));
|
||||
return dispatch_result;
|
||||
}
|
||||
return dispatch_result
|
||||
},
|
||||
};
|
||||
|
||||
// prepare dispatch origin
|
||||
let origin_account = match message.origin {
|
||||
CallOrigin::SourceRoot => {
|
||||
let hex_id = derive_account_id::<T::SourceChainAccountId>(source_chain, SourceAccount::Root);
|
||||
let hex_id =
|
||||
derive_account_id::<T::SourceChainAccountId>(source_chain, SourceAccount::Root);
|
||||
let target_id = T::AccountIdConverter::convert(hex_id);
|
||||
log::trace!(target: "runtime::bridge-dispatch", "Root Account: {:?}", &target_id);
|
||||
target_id
|
||||
}
|
||||
},
|
||||
CallOrigin::TargetAccount(source_account_id, target_public, target_signature) => {
|
||||
let digest = account_ownership_digest(
|
||||
&call,
|
||||
@@ -237,18 +248,19 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
target_signature,
|
||||
);
|
||||
Self::deposit_event(Event::MessageSignatureMismatch(source_chain, id));
|
||||
return dispatch_result;
|
||||
return dispatch_result
|
||||
}
|
||||
|
||||
log::trace!(target: "runtime::bridge-dispatch", "Target Account: {:?}", &target_account);
|
||||
target_account
|
||||
}
|
||||
},
|
||||
CallOrigin::SourceAccount(source_account_id) => {
|
||||
let hex_id = derive_account_id(source_chain, SourceAccount::Account(source_account_id));
|
||||
let hex_id =
|
||||
derive_account_id(source_chain, SourceAccount::Account(source_account_id));
|
||||
let target_id = T::AccountIdConverter::convert(hex_id);
|
||||
log::trace!(target: "runtime::bridge-dispatch", "Source Account: {:?}", &target_id);
|
||||
target_id
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// filter the call
|
||||
@@ -261,7 +273,7 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
call,
|
||||
);
|
||||
Self::deposit_event(Event::MessageCallRejected(source_chain, id));
|
||||
return dispatch_result;
|
||||
return dispatch_result
|
||||
}
|
||||
|
||||
// verify weight
|
||||
@@ -284,12 +296,15 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
expected_weight,
|
||||
message.weight,
|
||||
));
|
||||
return dispatch_result;
|
||||
return dispatch_result
|
||||
}
|
||||
|
||||
// pay dispatch fee right before dispatch
|
||||
let pay_dispatch_fee_at_target_chain = message.dispatch_fee_payment == DispatchFeePayment::AtTargetChain;
|
||||
if pay_dispatch_fee_at_target_chain && pay_dispatch_fee(&origin_account, message.weight).is_err() {
|
||||
let pay_dispatch_fee_at_target_chain =
|
||||
message.dispatch_fee_payment == DispatchFeePayment::AtTargetChain;
|
||||
if pay_dispatch_fee_at_target_chain &&
|
||||
pay_dispatch_fee(&origin_account, message.weight).is_err()
|
||||
{
|
||||
log::trace!(
|
||||
target: "runtime::bridge-dispatch",
|
||||
"Failed to pay dispatch fee for dispatching message {:?}/{:?} with weight {}",
|
||||
@@ -303,7 +318,7 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
origin_account,
|
||||
message.weight,
|
||||
));
|
||||
return dispatch_result;
|
||||
return dispatch_result
|
||||
}
|
||||
dispatch_result.dispatch_fee_paid_during_dispatch = pay_dispatch_fee_at_target_chain;
|
||||
|
||||
@@ -343,9 +358,19 @@ impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId>
|
||||
/// For example, if a message is sent from a "regular" account on the source chain it will not be
|
||||
/// allowed to be dispatched as Root on the target chain. This is a useful check to do on the source
|
||||
/// chain _before_ sending a message whose dispatch will be rejected on the target chain.
|
||||
pub fn verify_message_origin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Call>(
|
||||
pub fn verify_message_origin<
|
||||
SourceChainAccountId,
|
||||
TargetChainAccountPublic,
|
||||
TargetChainSignature,
|
||||
Call,
|
||||
>(
|
||||
sender_origin: &RawOrigin<SourceChainAccountId>,
|
||||
message: &MessagePayload<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Call>,
|
||||
message: &MessagePayload<
|
||||
SourceChainAccountId,
|
||||
TargetChainAccountPublic,
|
||||
TargetChainSignature,
|
||||
Call,
|
||||
>,
|
||||
) -> Result<Option<SourceChainAccountId>, BadOrigin>
|
||||
where
|
||||
SourceChainAccountId: PartialEq + Clone,
|
||||
@@ -354,21 +379,19 @@ where
|
||||
CallOrigin::SourceRoot => {
|
||||
ensure!(sender_origin == &RawOrigin::Root, BadOrigin);
|
||||
Ok(None)
|
||||
}
|
||||
},
|
||||
CallOrigin::TargetAccount(ref source_account_id, _, _) => {
|
||||
ensure!(
|
||||
sender_origin == &RawOrigin::Signed(source_account_id.clone()),
|
||||
BadOrigin
|
||||
);
|
||||
ensure!(sender_origin == &RawOrigin::Signed(source_account_id.clone()), BadOrigin);
|
||||
Ok(Some(source_account_id.clone()))
|
||||
}
|
||||
},
|
||||
CallOrigin::SourceAccount(ref source_account_id) => {
|
||||
ensure!(
|
||||
sender_origin == &RawOrigin::Signed(source_account_id.clone()) || sender_origin == &RawOrigin::Root,
|
||||
sender_origin == &RawOrigin::Signed(source_account_id.clone()) ||
|
||||
sender_origin == &RawOrigin::Root,
|
||||
BadOrigin
|
||||
);
|
||||
Ok(Some(source_account_id.clone()))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,16 +556,17 @@ mod tests {
|
||||
const TEST_WEIGHT: Weight = 1_000_000_000;
|
||||
|
||||
fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let t = frame_system::GenesisConfig::default()
|
||||
.build_storage::<TestRuntime>()
|
||||
.unwrap();
|
||||
let t = frame_system::GenesisConfig::default().build_storage::<TestRuntime>().unwrap();
|
||||
sp_io::TestExternalities::new(t)
|
||||
}
|
||||
|
||||
fn prepare_message(
|
||||
origin: CallOrigin<AccountId, TestAccountPublic, TestSignature>,
|
||||
call: Call,
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<AccountId, <TestRuntime as Config>::BridgeMessageId>>::Message {
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<
|
||||
AccountId,
|
||||
<TestRuntime as Config>::BridgeMessageId,
|
||||
>>::Message {
|
||||
MessagePayload {
|
||||
spec_version: TEST_SPEC_VERSION,
|
||||
weight: TEST_WEIGHT,
|
||||
@@ -554,20 +578,29 @@ mod tests {
|
||||
|
||||
fn prepare_root_message(
|
||||
call: Call,
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<AccountId, <TestRuntime as Config>::BridgeMessageId>>::Message {
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<
|
||||
AccountId,
|
||||
<TestRuntime as Config>::BridgeMessageId,
|
||||
>>::Message {
|
||||
prepare_message(CallOrigin::SourceRoot, call)
|
||||
}
|
||||
|
||||
fn prepare_target_message(
|
||||
call: Call,
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<AccountId, <TestRuntime as Config>::BridgeMessageId>>::Message {
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<
|
||||
AccountId,
|
||||
<TestRuntime as Config>::BridgeMessageId,
|
||||
>>::Message {
|
||||
let origin = CallOrigin::TargetAccount(1, TestAccountPublic(1), TestSignature(1));
|
||||
prepare_message(origin, call)
|
||||
}
|
||||
|
||||
fn prepare_source_message(
|
||||
call: Call,
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<AccountId, <TestRuntime as Config>::BridgeMessageId>>::Message {
|
||||
) -> <Pallet<TestRuntime> as MessageDispatch<
|
||||
AccountId,
|
||||
<TestRuntime as Config>::BridgeMessageId,
|
||||
>>::Message {
|
||||
let origin = CallOrigin::SourceAccount(1);
|
||||
prepare_message(origin, call)
|
||||
}
|
||||
@@ -578,13 +611,20 @@ mod tests {
|
||||
let id = [0; 4];
|
||||
|
||||
const BAD_SPEC_VERSION: SpecVersion = 99;
|
||||
let mut message =
|
||||
prepare_root_message(Call::System(<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3])));
|
||||
let mut message = prepare_root_message(Call::System(
|
||||
<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3]),
|
||||
));
|
||||
let weight = message.weight;
|
||||
message.spec_version = BAD_SPEC_VERSION;
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert_eq!(result.unspent_weight, weight);
|
||||
assert!(!result.dispatch_result);
|
||||
|
||||
@@ -592,12 +632,14 @@ mod tests {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageVersionSpecMismatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
id,
|
||||
TEST_SPEC_VERSION,
|
||||
BAD_SPEC_VERSION
|
||||
)),
|
||||
event: Event::Dispatch(
|
||||
call_dispatch::Event::<TestRuntime>::MessageVersionSpecMismatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
id,
|
||||
TEST_SPEC_VERSION,
|
||||
BAD_SPEC_VERSION
|
||||
)
|
||||
),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
@@ -612,13 +654,16 @@ mod tests {
|
||||
let call_weight = call.get_dispatch_info().weight;
|
||||
let mut message = prepare_root_message(call);
|
||||
message.weight = 7;
|
||||
assert!(
|
||||
call_weight != 7,
|
||||
"needed for test to actually trigger a weight mismatch"
|
||||
);
|
||||
assert!(call_weight != 7, "needed for test to actually trigger a weight mismatch");
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert_eq!(result.unspent_weight, 7);
|
||||
assert!(!result.dispatch_result);
|
||||
|
||||
@@ -626,12 +671,14 @@ mod tests {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageWeightMismatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
id,
|
||||
call_weight,
|
||||
7,
|
||||
)),
|
||||
event: Event::Dispatch(
|
||||
call_dispatch::Event::<TestRuntime>::MessageWeightMismatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
id,
|
||||
call_weight,
|
||||
7,
|
||||
)
|
||||
),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
@@ -651,7 +698,13 @@ mod tests {
|
||||
let weight = message.weight;
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert_eq!(result.unspent_weight, weight);
|
||||
assert!(!result.dispatch_result);
|
||||
|
||||
@@ -659,10 +712,12 @@ mod tests {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageSignatureMismatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
id
|
||||
)),
|
||||
event: Event::Dispatch(
|
||||
call_dispatch::Event::<TestRuntime>::MessageSignatureMismatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
id
|
||||
)
|
||||
),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
@@ -675,7 +730,13 @@ mod tests {
|
||||
let id = [0; 4];
|
||||
|
||||
System::set_block_number(1);
|
||||
Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Err(()), |_, _| unreachable!());
|
||||
Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Err(()),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
System::events(),
|
||||
@@ -696,13 +757,20 @@ mod tests {
|
||||
new_test_ext().execute_with(|| {
|
||||
let id = [0; 4];
|
||||
|
||||
let mut message =
|
||||
prepare_root_message(Call::System(<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3])));
|
||||
let mut message = prepare_root_message(Call::System(
|
||||
<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3]),
|
||||
));
|
||||
let weight = message.weight;
|
||||
message.call.0 = vec![];
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert_eq!(result.unspent_weight, weight);
|
||||
assert!(!result.dispatch_result);
|
||||
|
||||
@@ -710,10 +778,12 @@ mod tests {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageCallDecodeFailed(
|
||||
SOURCE_CHAIN_ID,
|
||||
id
|
||||
)),
|
||||
event: Event::Dispatch(
|
||||
call_dispatch::Event::<TestRuntime>::MessageCallDecodeFailed(
|
||||
SOURCE_CHAIN_ID,
|
||||
id
|
||||
)
|
||||
),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
@@ -725,13 +795,21 @@ mod tests {
|
||||
new_test_ext().execute_with(|| {
|
||||
let id = [0; 4];
|
||||
|
||||
let call = Call::System(<frame_system::Call<TestRuntime>>::fill_block(Perbill::from_percent(75)));
|
||||
let call = Call::System(<frame_system::Call<TestRuntime>>::fill_block(
|
||||
Perbill::from_percent(75),
|
||||
));
|
||||
let weight = call.get_dispatch_info().weight;
|
||||
let mut message = prepare_root_message(call);
|
||||
message.weight = weight;
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert_eq!(result.unspent_weight, weight);
|
||||
assert!(!result.dispatch_result);
|
||||
|
||||
@@ -739,10 +817,12 @@ mod tests {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageCallRejected(
|
||||
SOURCE_CHAIN_ID,
|
||||
id
|
||||
)),
|
||||
event: Event::Dispatch(
|
||||
call_dispatch::Event::<TestRuntime>::MessageCallRejected(
|
||||
SOURCE_CHAIN_ID,
|
||||
id
|
||||
)
|
||||
),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
@@ -754,13 +834,17 @@ mod tests {
|
||||
new_test_ext().execute_with(|| {
|
||||
let id = [0; 4];
|
||||
|
||||
let mut message =
|
||||
prepare_root_message(Call::System(<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3])));
|
||||
let mut message = prepare_root_message(Call::System(
|
||||
<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3]),
|
||||
));
|
||||
let weight = message.weight;
|
||||
message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| Err(()));
|
||||
let result =
|
||||
Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| {
|
||||
Err(())
|
||||
});
|
||||
assert_eq!(result.unspent_weight, weight);
|
||||
assert!(!result.dispatch_result);
|
||||
|
||||
@@ -768,15 +852,17 @@ mod tests {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageDispatchPaymentFailed(
|
||||
SOURCE_CHAIN_ID,
|
||||
id,
|
||||
AccountIdConverter::convert(derive_account_id::<AccountId>(
|
||||
event: Event::Dispatch(
|
||||
call_dispatch::Event::<TestRuntime>::MessageDispatchPaymentFailed(
|
||||
SOURCE_CHAIN_ID,
|
||||
SourceAccount::Root
|
||||
)),
|
||||
TEST_WEIGHT,
|
||||
)),
|
||||
id,
|
||||
AccountIdConverter::convert(derive_account_id::<AccountId>(
|
||||
SOURCE_CHAIN_ID,
|
||||
SourceAccount::Root
|
||||
)),
|
||||
TEST_WEIGHT,
|
||||
)
|
||||
),
|
||||
topics: vec![],
|
||||
}],
|
||||
);
|
||||
@@ -788,12 +874,19 @@ mod tests {
|
||||
new_test_ext().execute_with(|| {
|
||||
let id = [0; 4];
|
||||
|
||||
let mut message =
|
||||
prepare_root_message(Call::System(<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3])));
|
||||
let mut message = prepare_root_message(Call::System(
|
||||
<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3]),
|
||||
));
|
||||
message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| Ok(()));
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| Ok(()),
|
||||
);
|
||||
assert!(result.dispatch_fee_paid_during_dispatch);
|
||||
assert!(result.dispatch_result);
|
||||
|
||||
@@ -821,7 +914,13 @@ mod tests {
|
||||
let message = prepare_target_message(call);
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert!(!result.dispatch_fee_paid_during_dispatch);
|
||||
assert!(!result.dispatch_result);
|
||||
|
||||
@@ -844,10 +943,18 @@ mod tests {
|
||||
fn should_dispatch_bridge_message_from_root_origin() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let id = [0; 4];
|
||||
let message = prepare_root_message(Call::System(<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3])));
|
||||
let message = prepare_root_message(Call::System(
|
||||
<frame_system::Call<TestRuntime>>::remark(vec![1, 2, 3]),
|
||||
));
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert!(!result.dispatch_fee_paid_during_dispatch);
|
||||
assert!(result.dispatch_result);
|
||||
|
||||
@@ -875,7 +982,13 @@ mod tests {
|
||||
let message = prepare_target_message(call);
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert!(!result.dispatch_fee_paid_during_dispatch);
|
||||
assert!(result.dispatch_result);
|
||||
|
||||
@@ -903,7 +1016,13 @@ mod tests {
|
||||
let message = prepare_source_message(call);
|
||||
|
||||
System::set_block_number(1);
|
||||
let result = Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| unreachable!());
|
||||
let result = Dispatch::dispatch(
|
||||
SOURCE_CHAIN_ID,
|
||||
TARGET_CHAIN_ID,
|
||||
id,
|
||||
Ok(message),
|
||||
|_, _| unreachable!(),
|
||||
);
|
||||
assert!(!result.dispatch_fee_paid_during_dispatch);
|
||||
assert!(result.dispatch_result);
|
||||
|
||||
@@ -931,10 +1050,7 @@ mod tests {
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Ok(None)));
|
||||
|
||||
// when message is sent by some real account, CallOrigin::SourceRoot is not allowed
|
||||
assert!(matches!(
|
||||
verify_message_origin(&RawOrigin::Signed(1), &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Err(BadOrigin)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -943,23 +1059,14 @@ mod tests {
|
||||
let message = prepare_target_message(call);
|
||||
|
||||
// When message is sent by Root, CallOrigin::TargetAccount is not allowed
|
||||
assert!(matches!(
|
||||
verify_message_origin(&RawOrigin::Root, &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Err(BadOrigin)));
|
||||
|
||||
// When message is sent by some other account, it is rejected
|
||||
assert!(matches!(
|
||||
verify_message_origin(&RawOrigin::Signed(2), &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Signed(2), &message), Err(BadOrigin)));
|
||||
|
||||
// When message is sent by a real account, it is allowed to have origin
|
||||
// CallOrigin::TargetAccount
|
||||
assert!(matches!(
|
||||
verify_message_origin(&RawOrigin::Signed(1), &message),
|
||||
Ok(Some(1))
|
||||
));
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Ok(Some(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -968,16 +1075,10 @@ mod tests {
|
||||
let message = prepare_source_message(call);
|
||||
|
||||
// Sending a message from the expected origin account works
|
||||
assert!(matches!(
|
||||
verify_message_origin(&RawOrigin::Signed(1), &message),
|
||||
Ok(Some(1))
|
||||
));
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Ok(Some(1))));
|
||||
|
||||
// If we send a message from a different account, it is rejected
|
||||
assert!(matches!(
|
||||
verify_message_origin(&RawOrigin::Signed(2), &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Signed(2), &message), Err(BadOrigin)));
|
||||
|
||||
// The Root account is allowed to assume any expected origin account
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Ok(Some(1))));
|
||||
|
||||
@@ -135,7 +135,9 @@ pub fn verify_substrate_finality_proof(
|
||||
) -> Result<(), Error> {
|
||||
let best_set = AuthorityList::decode(&mut &*raw_best_set)
|
||||
.map_err(Error::BestSetDecode)
|
||||
.and_then(|authorities| VoterSet::new(authorities.into_iter()).ok_or(Error::InvalidBestSet));
|
||||
.and_then(|authorities| {
|
||||
VoterSet::new(authorities.into_iter()).ok_or(Error::InvalidBestSet)
|
||||
});
|
||||
|
||||
log::debug!(
|
||||
target: "bridge-builtin",
|
||||
@@ -150,15 +152,16 @@ pub fn verify_substrate_finality_proof(
|
||||
|
||||
let best_set = best_set?;
|
||||
|
||||
let verify_result = sc_finality_grandpa::GrandpaJustification::<Block>::decode_and_verify_finalizes(
|
||||
raw_finality_proof,
|
||||
(finality_target_hash, finality_target_number),
|
||||
best_set_id,
|
||||
&best_set,
|
||||
)
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::JustificationVerify)
|
||||
.map(|_| ());
|
||||
let verify_result =
|
||||
sc_finality_grandpa::GrandpaJustification::<Block>::decode_and_verify_finalizes(
|
||||
raw_finality_proof,
|
||||
(finality_target_hash, finality_target_number),
|
||||
best_set_id,
|
||||
&best_set,
|
||||
)
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::JustificationVerify)
|
||||
.map(|_| ());
|
||||
|
||||
log::debug!(
|
||||
target: "bridge-builtin",
|
||||
@@ -202,10 +205,7 @@ mod tests {
|
||||
#[test]
|
||||
fn from_substrate_block_number_succeeds() {
|
||||
assert_eq!(from_substrate_block_number(0).unwrap(), U256::zero());
|
||||
assert_eq!(
|
||||
from_substrate_block_number(std::u32::MAX).unwrap(),
|
||||
U256::from(std::u32::MAX)
|
||||
);
|
||||
assert_eq!(from_substrate_block_number(std::u32::MAX).unwrap(), U256::from(std::u32::MAX));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -285,10 +285,7 @@ mod tests {
|
||||
.parse()
|
||||
.unwrap(),
|
||||
number: 8,
|
||||
signal: Some(ValidatorsSetSignal {
|
||||
delay: 8,
|
||||
validators: authorities.encode(),
|
||||
}),
|
||||
signal: Some(ValidatorsSetSignal { delay: 8, validators: authorities.encode() }),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -296,13 +293,14 @@ mod tests {
|
||||
/// Number of the example block with justification.
|
||||
const EXAMPLE_JUSTIFIED_BLOCK_NUMBER: u32 = 8;
|
||||
/// Hash of the example block with justification.
|
||||
const EXAMPLE_JUSTIFIED_BLOCK_HASH: &str = "a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f343775";
|
||||
/// Id of authorities set that have generated example justification. Could be computed by tracking
|
||||
/// every set change in canonized headers.
|
||||
const EXAMPLE_JUSTIFIED_BLOCK_HASH: &str =
|
||||
"a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f343775";
|
||||
/// Id of authorities set that have generated example justification. Could be computed by
|
||||
/// tracking every set change in canonized headers.
|
||||
const EXAMPLE_AUTHORITIES_SET_ID: u64 = 0;
|
||||
/// Encoded authorities set that has generated example justification. Could be fetched from `ScheduledChange`
|
||||
/// digest of the block that has scheduled this set OR by calling `GrandpaApi::grandpa_authorities()` at
|
||||
/// appropriate block.
|
||||
/// Encoded authorities set that has generated example justification. Could be fetched from
|
||||
/// `ScheduledChange` digest of the block that has scheduled this set OR by calling
|
||||
/// `GrandpaApi::grandpa_authorities()` at appropriate block.
|
||||
const EXAMPLE_AUTHORITIES_SET: &str = "1488dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee0100000000000000d17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae690100000000000000439660b36c6c03afafca027b910b4fecf99801834c62a5e6006f27d978de234f01000000000000005e639b43e0052c47447dac87d6fd2b6ec50bdd4d0f614e4299c665249bbd09d901000000000000001dfe3e22cc0d45c70779c1095f7489a8ef3cf52d62fbd8c2fa38c9f1723502b50100000000000000";
|
||||
/// Example justification. Could be fetched by calling 'chain_getBlock' RPC.
|
||||
const EXAMPLE_JUSTIFICATION: &str = "2600000000000000a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f3437750800000010a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f34377508000000d66b4ceb57ef8bcbc955071b597c8c5d2adcfdbb009c73f8438d342670fdeca9ac60686cbd58105b10f51d0a64a8e73b2e5829b2eab3248a008c472852130b00439660b36c6c03afafca027b910b4fecf99801834c62a5e6006f27d978de234fa2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f34377508000000f5730c14d3cd22b7661e2f5fcb3139dd5fef37f946314a441d01b40ce1200ef70d810525f23fd278b588cd67473c200bda83c338c407b479386aa83798e5970b5e639b43e0052c47447dac87d6fd2b6ec50bdd4d0f614e4299c665249bbd09d9a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f34377508000000c78d6ec463f476461a695b4791d30e7626d16fdf72d7c252c2cad387495a97e8c2827ed4d5af853d6e05d31cb6fb7438c9481a7e9c6990d60a9bfaf6a6e1930988dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0eea2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f3437750800000052b4fc52d430286b3e2d650aa6e01b6ff4fae8b968893a62be789209eb97ee6e23780d3f5af7042d85bb48f1b202890b22724dfebce138826f66a5e00324320fd17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae6900";
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
use super::*;
|
||||
|
||||
use crate::test_utils::{
|
||||
build_custom_header, build_genesis_header, insert_header, validator_utils::*, validators_change_receipt,
|
||||
HeaderBuilder,
|
||||
build_custom_header, build_genesis_header, insert_header, validator_utils::*,
|
||||
validators_change_receipt, HeaderBuilder,
|
||||
};
|
||||
|
||||
use bp_eth_poa::{compute_merkle_root, U256};
|
||||
|
||||
@@ -85,7 +85,8 @@ impl Error {
|
||||
Error::InsufficientProof => "Header has insufficient proof",
|
||||
Error::InvalidDifficulty => "Header has invalid difficulty",
|
||||
Error::NotValidator => "Header is sealed by unexpected validator",
|
||||
Error::MissingTransactionsReceipts => "The import operation requires transactions receipts",
|
||||
Error::MissingTransactionsReceipts =>
|
||||
"The import operation requires transactions receipts",
|
||||
Error::RedundantTransactionsReceipts => "Redundant transactions receipts are provided",
|
||||
Error::TransactionsReceiptsMismatch => "Invalid transactions receipts provided",
|
||||
Error::UnsignedTooFarInTheFuture => "The unsigned header is too far in future",
|
||||
|
||||
@@ -14,18 +14,19 @@
|
||||
// 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::error::Error;
|
||||
use crate::Storage;
|
||||
use crate::{error::Error, Storage};
|
||||
use bp_eth_poa::{public_to_address, Address, AuraHeader, HeaderId, SealedEmptyStep, H256};
|
||||
use codec::{Decode, Encode};
|
||||
use sp_io::crypto::secp256k1_ecdsa_recover;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::collections::{
|
||||
btree_map::{BTreeMap, Entry},
|
||||
btree_set::BTreeSet,
|
||||
vec_deque::VecDeque,
|
||||
use sp_std::{
|
||||
collections::{
|
||||
btree_map::{BTreeMap, Entry},
|
||||
btree_set::BTreeSet,
|
||||
vec_deque::VecDeque,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// Cached finality votes for given block.
|
||||
#[derive(RuntimeDebug)]
|
||||
@@ -116,17 +117,14 @@ pub fn finalize_blocks<S: Storage>(
|
||||
¤t_votes,
|
||||
ancestor.id.number >= two_thirds_majority_transition,
|
||||
) {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
remove_signers_votes(&ancestor.signers, &mut current_votes);
|
||||
finalized_headers.push((ancestor.id, ancestor.submitter.clone()));
|
||||
}
|
||||
|
||||
Ok(FinalityEffects {
|
||||
finalized_headers,
|
||||
votes,
|
||||
})
|
||||
Ok(FinalityEffects { finalized_headers, votes })
|
||||
}
|
||||
|
||||
/// Returns true if there are enough votes to treat this header as finalized.
|
||||
@@ -135,8 +133,8 @@ fn is_finalized(
|
||||
votes: &BTreeMap<Address, u64>,
|
||||
requires_two_thirds_majority: bool,
|
||||
) -> bool {
|
||||
(!requires_two_thirds_majority && votes.len() * 2 > validators.len())
|
||||
|| (requires_two_thirds_majority && votes.len() * 3 > validators.len() * 2)
|
||||
(!requires_two_thirds_majority && votes.len() * 2 > validators.len()) ||
|
||||
(requires_two_thirds_majority && votes.len() * 3 > validators.len() * 2)
|
||||
}
|
||||
|
||||
/// Prepare 'votes' of header and its ancestors' signers.
|
||||
@@ -151,12 +149,12 @@ pub(crate) fn prepare_votes<Submitter>(
|
||||
// if we have reached finalized block sibling, then we're trying
|
||||
// to switch finalized blocks
|
||||
if cached_votes.stopped_at_finalized_sibling {
|
||||
return Err(Error::TryingToFinalizeSibling);
|
||||
return Err(Error::TryingToFinalizeSibling)
|
||||
}
|
||||
|
||||
// this fn can only work with single validators set
|
||||
if !validators.contains(&header.author) {
|
||||
return Err(Error::NotValidator);
|
||||
return Err(Error::NotValidator)
|
||||
}
|
||||
|
||||
// now we have votes that were valid when some block B has been inserted
|
||||
@@ -171,7 +169,7 @@ pub(crate) fn prepare_votes<Submitter>(
|
||||
while let Some(old_ancestor) = votes.ancestry.pop_front() {
|
||||
if old_ancestor.id.number > best_finalized.number {
|
||||
votes.ancestry.push_front(old_ancestor);
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
remove_signers_votes(&old_ancestor.signers, &mut votes.votes);
|
||||
@@ -180,7 +178,9 @@ pub(crate) fn prepare_votes<Submitter>(
|
||||
// add votes from new blocks
|
||||
let mut parent_empty_step_signers = empty_steps_signers(header);
|
||||
let mut unaccounted_ancestry = VecDeque::new();
|
||||
while let Some((ancestor_id, ancestor_submitter, ancestor)) = cached_votes.unaccounted_ancestry.pop_front() {
|
||||
while let Some((ancestor_id, ancestor_submitter, ancestor)) =
|
||||
cached_votes.unaccounted_ancestry.pop_front()
|
||||
{
|
||||
let mut signers = empty_steps_signers(&ancestor);
|
||||
sp_std::mem::swap(&mut signers, &mut parent_empty_step_signers);
|
||||
signers.insert(ancestor.author);
|
||||
@@ -199,11 +199,9 @@ pub(crate) fn prepare_votes<Submitter>(
|
||||
let mut header_signers = BTreeSet::new();
|
||||
header_signers.insert(header.author);
|
||||
*votes.votes.entry(header.author).or_insert(0) += 1;
|
||||
votes.ancestry.push_back(FinalityAncestor {
|
||||
id,
|
||||
submitter,
|
||||
signers: header_signers,
|
||||
});
|
||||
votes
|
||||
.ancestry
|
||||
.push_back(FinalityAncestor { id, submitter, signers: header_signers });
|
||||
|
||||
Ok(votes)
|
||||
}
|
||||
@@ -217,7 +215,7 @@ fn add_signers_votes(
|
||||
) -> Result<(), Error> {
|
||||
for signer in signers_to_add {
|
||||
if !validators.contains(signer) {
|
||||
return Err(Error::NotValidator);
|
||||
return Err(Error::NotValidator)
|
||||
}
|
||||
|
||||
*votes.entry(*signer).or_insert(0) += 1;
|
||||
@@ -230,13 +228,12 @@ fn add_signers_votes(
|
||||
fn remove_signers_votes(signers_to_remove: &BTreeSet<Address>, votes: &mut BTreeMap<Address, u64>) {
|
||||
for signer in signers_to_remove {
|
||||
match votes.entry(*signer) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
Entry::Occupied(mut entry) =>
|
||||
if *entry.get() <= 1 {
|
||||
entry.remove();
|
||||
} else {
|
||||
*entry.get_mut() -= 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
Entry::Vacant(_) => unreachable!("we only remove signers that have been added; qed"),
|
||||
}
|
||||
}
|
||||
@@ -272,18 +269,19 @@ impl<Submitter> Default for CachedFinalityVotes<Submitter> {
|
||||
|
||||
impl<Submitter> Default for FinalityVotes<Submitter> {
|
||||
fn default() -> Self {
|
||||
FinalityVotes {
|
||||
votes: BTreeMap::new(),
|
||||
ancestry: VecDeque::new(),
|
||||
}
|
||||
FinalityVotes { votes: BTreeMap::new(), ancestry: VecDeque::new() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{insert_header, run_test, validator, validators_addresses, HeaderBuilder, TestRuntime};
|
||||
use crate::{BridgeStorage, FinalityCache, HeaderToImport};
|
||||
use crate::{
|
||||
mock::{
|
||||
insert_header, run_test, validator, validators_addresses, HeaderBuilder, TestRuntime,
|
||||
},
|
||||
BridgeStorage, FinalityCache, HeaderToImport,
|
||||
};
|
||||
|
||||
const TOTAL_VALIDATORS: usize = 5;
|
||||
|
||||
@@ -341,7 +339,8 @@ mod tests {
|
||||
storage.insert_header(header_to_import.clone());
|
||||
|
||||
// when header#2 is inserted, nothing is finalized (2 votes)
|
||||
header_to_import.header = HeaderBuilder::with_parent_hash(id1.hash).sign_by(&validator(1));
|
||||
header_to_import.header =
|
||||
HeaderBuilder::with_parent_hash(id1.hash).sign_by(&validator(1));
|
||||
header_to_import.id = header_to_import.header.compute_id();
|
||||
let id2 = header_to_import.header.compute_id();
|
||||
assert_eq!(
|
||||
@@ -360,7 +359,8 @@ mod tests {
|
||||
storage.insert_header(header_to_import.clone());
|
||||
|
||||
// when header#3 is inserted, header#1 is finalized (3 votes)
|
||||
header_to_import.header = HeaderBuilder::with_parent_hash(id2.hash).sign_by(&validator(2));
|
||||
header_to_import.header =
|
||||
HeaderBuilder::with_parent_hash(id2.hash).sign_by(&validator(2));
|
||||
header_to_import.id = header_to_import.header.compute_id();
|
||||
let id3 = header_to_import.header.compute_id();
|
||||
assert_eq!(
|
||||
@@ -390,7 +390,9 @@ mod tests {
|
||||
// 2) add votes from header#4 and header#5
|
||||
let validators = validators_addresses(5);
|
||||
let headers = (1..6)
|
||||
.map(|number| HeaderBuilder::with_number(number).sign_by(&validator(number as usize - 1)))
|
||||
.map(|number| {
|
||||
HeaderBuilder::with_number(number).sign_by(&validator(number as usize - 1))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let ancestry = headers
|
||||
.iter()
|
||||
@@ -405,9 +407,10 @@ mod tests {
|
||||
prepare_votes::<()>(
|
||||
CachedFinalityVotes {
|
||||
stopped_at_finalized_sibling: false,
|
||||
unaccounted_ancestry: vec![(headers[3].compute_id(), None, headers[3].clone()),]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
unaccounted_ancestry:
|
||||
vec![(headers[3].compute_id(), None, headers[3].clone()),]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
votes: Some(FinalityVotes {
|
||||
votes: vec![(validators[0], 1), (validators[1], 1), (validators[2], 1),]
|
||||
.into_iter()
|
||||
@@ -445,7 +448,8 @@ mod tests {
|
||||
let mut ancestry = Vec::new();
|
||||
let mut parent_hash = ctx.genesis.compute_hash();
|
||||
for i in 1..10 {
|
||||
let header = HeaderBuilder::with_parent_hash(parent_hash).sign_by(&validator((i - 1) / 3));
|
||||
let header =
|
||||
HeaderBuilder::with_parent_hash(parent_hash).sign_by(&validator((i - 1) / 3));
|
||||
let id = header.compute_id();
|
||||
insert_header(&mut storage, header.clone());
|
||||
hashes.push(id.hash);
|
||||
@@ -539,10 +543,7 @@ mod tests {
|
||||
fn prepare_votes_fails_when_finalized_sibling_is_in_ancestry() {
|
||||
assert_eq!(
|
||||
prepare_votes::<()>(
|
||||
CachedFinalityVotes {
|
||||
stopped_at_finalized_sibling: true,
|
||||
..Default::default()
|
||||
},
|
||||
CachedFinalityVotes { stopped_at_finalized_sibling: true, ..Default::default() },
|
||||
Default::default(),
|
||||
&validators_addresses(3).iter().collect(),
|
||||
Default::default(),
|
||||
|
||||
@@ -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::error::Error;
|
||||
use crate::finality::finalize_blocks;
|
||||
use crate::validators::{Validators, ValidatorsConfiguration};
|
||||
use crate::verification::{is_importable_header, verify_aura_header};
|
||||
use crate::{AuraConfiguration, ChainTime, ChangeToEnact, PruningStrategy, Storage};
|
||||
use crate::{
|
||||
error::Error,
|
||||
finality::finalize_blocks,
|
||||
validators::{Validators, ValidatorsConfiguration},
|
||||
verification::{is_importable_header, verify_aura_header},
|
||||
AuraConfiguration, ChainTime, ChangeToEnact, PruningStrategy, Storage,
|
||||
};
|
||||
use bp_eth_poa::{AuraHeader, HeaderId, Receipt};
|
||||
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||
|
||||
@@ -65,7 +67,7 @@ pub fn import_headers<S: Storage, PS: PruningStrategy, CT: ChainTime>(
|
||||
}
|
||||
}
|
||||
useful += 1;
|
||||
}
|
||||
},
|
||||
Err(Error::AncientHeader) | Err(Error::KnownHeader) => useless += 1,
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
@@ -103,7 +105,8 @@ pub fn import_header<S: Storage, PS: PruningStrategy, CT: ChainTime>(
|
||||
|
||||
// check if block schedules new validators
|
||||
let validators = Validators::new(validators_config);
|
||||
let (scheduled_change, enacted_change) = validators.extract_validators_change(&header, receipts)?;
|
||||
let (scheduled_change, enacted_change) =
|
||||
validators.extract_validators_change(&header, receipts)?;
|
||||
|
||||
// check if block finalizes some other blocks and corresponding scheduled validators
|
||||
let validators_set = import_context.validators_set();
|
||||
@@ -117,11 +120,10 @@ pub fn import_header<S: Storage, PS: PruningStrategy, CT: ChainTime>(
|
||||
aura_config.two_thirds_majority_transition,
|
||||
)?;
|
||||
let enacted_change = enacted_change
|
||||
.map(|validators| ChangeToEnact {
|
||||
signal_block: None,
|
||||
validators,
|
||||
})
|
||||
.or_else(|| validators.finalize_validators_change(storage, &finalized_blocks.finalized_headers));
|
||||
.map(|validators| ChangeToEnact { signal_block: None, validators })
|
||||
.or_else(|| {
|
||||
validators.finalize_validators_change(storage, &finalized_blocks.finalized_headers)
|
||||
});
|
||||
|
||||
// NOTE: we can't return Err() from anywhere below this line
|
||||
// (because otherwise we'll have inconsistent storage if transaction will fail)
|
||||
@@ -145,9 +147,7 @@ pub fn import_header<S: Storage, PS: PruningStrategy, CT: ChainTime>(
|
||||
let new_best_finalized_block_id = finalized_blocks.finalized_headers.last().map(|(id, _)| *id);
|
||||
let pruning_upper_bound = pruning_strategy.pruning_upper_bound(
|
||||
new_best_block_id.number,
|
||||
new_best_finalized_block_id
|
||||
.map(|id| id.number)
|
||||
.unwrap_or(finalized_id.number),
|
||||
new_best_finalized_block_id.map(|id| id.number).unwrap_or(finalized_id.number),
|
||||
);
|
||||
|
||||
// now mark finalized headers && prune old headers
|
||||
@@ -171,12 +171,15 @@ pub fn header_import_requires_receipts<S: Storage>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
run_test, secret_to_address, test_aura_config, test_validators_config, validator, validators_addresses,
|
||||
validators_change_receipt, HeaderBuilder, KeepSomeHeadersBehindBest, TestRuntime, GAS_LIMIT,
|
||||
use crate::{
|
||||
mock::{
|
||||
run_test, secret_to_address, test_aura_config, test_validators_config, validator,
|
||||
validators_addresses, validators_change_receipt, HeaderBuilder,
|
||||
KeepSomeHeadersBehindBest, TestRuntime, GAS_LIMIT,
|
||||
},
|
||||
validators::ValidatorsSource,
|
||||
BlocksToPrune, BridgeStorage, Headers, PruningRange,
|
||||
};
|
||||
use crate::validators::ValidatorsSource;
|
||||
use crate::{BlocksToPrune, BridgeStorage, Headers, PruningRange};
|
||||
use secp256k1::SecretKey;
|
||||
|
||||
const TOTAL_VALIDATORS: usize = 3;
|
||||
@@ -186,10 +189,7 @@ mod tests {
|
||||
run_test(TOTAL_VALIDATORS, |_| {
|
||||
let mut storage = BridgeStorage::<TestRuntime>::new();
|
||||
storage.finalize_and_prune_headers(
|
||||
Some(HeaderId {
|
||||
number: 100,
|
||||
..Default::default()
|
||||
}),
|
||||
Some(HeaderId { number: 100, ..Default::default() }),
|
||||
0,
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -281,8 +281,10 @@ mod tests {
|
||||
#[test]
|
||||
fn headers_are_pruned_during_import() {
|
||||
run_test(TOTAL_VALIDATORS, |ctx| {
|
||||
let validators_config =
|
||||
ValidatorsConfiguration::Single(ValidatorsSource::Contract([3; 20].into(), ctx.addresses.clone()));
|
||||
let validators_config = ValidatorsConfiguration::Single(ValidatorsSource::Contract(
|
||||
[3; 20].into(),
|
||||
ctx.addresses.clone(),
|
||||
));
|
||||
let validators = vec![validator(0), validator(1), validator(2)];
|
||||
let mut storage = BridgeStorage::<TestRuntime>::new();
|
||||
|
||||
@@ -305,7 +307,8 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
match i {
|
||||
2..=10 => assert_eq!(finalized_blocks, vec![(parent_id, Some(100))], "At {}", i,),
|
||||
2..=10 =>
|
||||
assert_eq!(finalized_blocks, vec![(parent_id, Some(100))], "At {}", i,),
|
||||
_ => assert_eq!(finalized_blocks, vec![], "At {}", i),
|
||||
}
|
||||
latest_block_id = rolling_last_block_id;
|
||||
@@ -339,8 +342,8 @@ mod tests {
|
||||
latest_block_id = rolling_last_block_id;
|
||||
|
||||
// and now let's say validators 1 && 2 went offline
|
||||
// => in the range 12-25 no blocks are finalized, but we still continue to prune old headers
|
||||
// until header#11 is met. we can't prune #11, because it schedules change
|
||||
// => in the range 12-25 no blocks are finalized, but we still continue to prune old
|
||||
// headers until header#11 is met. we can't prune #11, because it schedules change
|
||||
let mut step = 56u64;
|
||||
let mut expected_blocks = vec![(header11.compute_id(), Some(101))];
|
||||
for i in 12..25 {
|
||||
@@ -366,10 +369,7 @@ mod tests {
|
||||
}
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 11,
|
||||
oldest_block_to_keep: 14,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 11, oldest_block_to_keep: 14 },
|
||||
);
|
||||
|
||||
// now let's insert block signed by validator 1
|
||||
@@ -393,10 +393,7 @@ mod tests {
|
||||
assert_eq!(finalized_blocks, expected_blocks);
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 15,
|
||||
oldest_block_to_keep: 15,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 15, oldest_block_to_keep: 15 },
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -483,9 +480,7 @@ mod tests {
|
||||
let header1 = import_custom_block(
|
||||
&mut storage,
|
||||
&ctx.validators,
|
||||
HeaderBuilder::with_parent_number(0)
|
||||
.step(2)
|
||||
.sign_by_set(&ctx.validators),
|
||||
HeaderBuilder::with_parent_number(0).step(2).sign_by_set(&ctx.validators),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(storage.best_block().0, header1);
|
||||
@@ -495,9 +490,7 @@ mod tests {
|
||||
let header2 = import_custom_block(
|
||||
&mut storage,
|
||||
&ctx.validators,
|
||||
HeaderBuilder::with_parent_number(1)
|
||||
.step(3)
|
||||
.sign_by_set(&ctx.validators),
|
||||
HeaderBuilder::with_parent_number(1).step(3).sign_by_set(&ctx.validators),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(storage.best_block().0, header2);
|
||||
@@ -507,9 +500,7 @@ mod tests {
|
||||
let header3 = import_custom_block(
|
||||
&mut storage,
|
||||
&ctx.validators,
|
||||
HeaderBuilder::with_parent_number(2)
|
||||
.step(4)
|
||||
.sign_by_set(&ctx.validators),
|
||||
HeaderBuilder::with_parent_number(2).step(4).sign_by_set(&ctx.validators),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(storage.best_block().0, header3);
|
||||
@@ -552,19 +543,19 @@ mod tests {
|
||||
assert_eq!(storage.best_block().0, header5_1);
|
||||
assert_eq!(storage.finalized_block(), header1);
|
||||
|
||||
// when we import header4 { parent = header3 }, authored by validator[0], header2 is finalized
|
||||
// when we import header4 { parent = header3 }, authored by validator[0], header2 is
|
||||
// finalized
|
||||
let header4 = import_custom_block(
|
||||
&mut storage,
|
||||
&ctx.validators,
|
||||
HeaderBuilder::with_parent_number(3)
|
||||
.step(5)
|
||||
.sign_by_set(&ctx.validators),
|
||||
HeaderBuilder::with_parent_number(3).step(5).sign_by_set(&ctx.validators),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(storage.best_block().0, header5_1);
|
||||
assert_eq!(storage.finalized_block(), header2);
|
||||
|
||||
// when we import header5 { parent = header4 }, authored by validator[1], header3 is finalized
|
||||
// when we import header5 { parent = header4 }, authored by validator[1], header3 is
|
||||
// finalized
|
||||
let header5 = import_custom_block(
|
||||
&mut storage,
|
||||
&ctx.validators,
|
||||
@@ -576,7 +567,8 @@ mod tests {
|
||||
assert_eq!(storage.best_block().0, header5);
|
||||
assert_eq!(storage.finalized_block(), header3);
|
||||
|
||||
// import of header2'' { parent = header1 } fails, because it has number < best_finalized
|
||||
// import of header2'' { parent = header1 } fails, because it has number <
|
||||
// best_finalized
|
||||
assert_eq!(
|
||||
import_custom_block(
|
||||
&mut storage,
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
|
||||
use crate::finality::{CachedFinalityVotes, FinalityVotes};
|
||||
use bp_eth_poa::{Address, AuraHeader, HeaderId, RawTransaction, RawTransactionReceipt, Receipt, H256, U256};
|
||||
use bp_eth_poa::{
|
||||
Address, AuraHeader, HeaderId, RawTransaction, RawTransactionReceipt, Receipt, H256, U256,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::traits::Get;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
@@ -222,10 +224,7 @@ impl<Submitter> ImportContext<Submitter> {
|
||||
/// This may point to parent if parent has signaled change.
|
||||
pub fn last_signal_block(&self) -> Option<HeaderId> {
|
||||
match self.parent_scheduled_change {
|
||||
Some(_) => Some(HeaderId {
|
||||
number: self.parent_header.number,
|
||||
hash: self.parent_hash,
|
||||
}),
|
||||
Some(_) => Some(HeaderId { number: self.parent_header.number, hash: self.parent_hash }),
|
||||
None => self.last_signal_block,
|
||||
}
|
||||
}
|
||||
@@ -313,8 +312,8 @@ pub trait PruningStrategy: Default {
|
||||
/// number greater than or equal to N even if strategy allows that.
|
||||
///
|
||||
/// If your strategy allows pruning unfinalized blocks, this could lead to switch
|
||||
/// between finalized forks (only if authorities are misbehaving). But since 50 percent plus one (or 2/3)
|
||||
/// authorities are able to do whatever they want with the chain, this isn't considered
|
||||
/// between finalized forks (only if authorities are misbehaving). But since 50 percent plus one
|
||||
/// (or 2/3) authorities are able to do whatever they want with the chain, this isn't considered
|
||||
/// fatal. If your strategy only prunes finalized blocks, we'll never be able to finalize
|
||||
/// header that isn't descendant of current best finalized block.
|
||||
fn pruning_upper_bound(&mut self, best_number: u64, best_finalized_number: u64) -> u64;
|
||||
@@ -343,10 +342,10 @@ impl ChainTime for () {
|
||||
pub trait OnHeadersSubmitted<AccountId> {
|
||||
/// Called when valid headers have been submitted.
|
||||
///
|
||||
/// The submitter **must not** be rewarded for submitting valid headers, because greedy authority
|
||||
/// could produce and submit multiple valid headers (without relaying them to other peers) and
|
||||
/// get rewarded. Instead, the provider could track submitters and stop rewarding if too many
|
||||
/// headers have been submitted without finalization.
|
||||
/// The submitter **must not** be rewarded for submitting valid headers, because greedy
|
||||
/// authority could produce and submit multiple valid headers (without relaying them to other
|
||||
/// peers) and get rewarded. Instead, the provider could track submitters and stop rewarding if
|
||||
/// too many headers have been submitted without finalization.
|
||||
fn on_valid_headers_submitted(submitter: AccountId, useful: u64, useless: u64);
|
||||
/// Called when invalid headers have been submitted.
|
||||
fn on_invalid_headers_submitted(submitter: AccountId);
|
||||
@@ -459,13 +458,14 @@ pub mod pallet {
|
||||
|
||||
// now track/penalize current submitter for providing new headers
|
||||
match import_result {
|
||||
Ok((useful, useless)) => T::OnHeadersSubmitted::on_valid_headers_submitted(submitter, useful, useless),
|
||||
Ok((useful, useless)) =>
|
||||
T::OnHeadersSubmitted::on_valid_headers_submitted(submitter, useful, useless),
|
||||
Err(error) => {
|
||||
// even though we may have accept some headers, we do not want to reward someone
|
||||
// who provides invalid headers
|
||||
T::OnHeadersSubmitted::on_invalid_headers_submitted(submitter);
|
||||
return Err(error.msg().into());
|
||||
}
|
||||
return Err(error.msg().into())
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -500,12 +500,13 @@ pub mod pallet {
|
||||
// UnsignedTooFarInTheFuture is the special error code used to limit
|
||||
// number of transactions in the pool - we do not want to ban transaction
|
||||
// in this case (see verification.rs for details)
|
||||
Err(error::Error::UnsignedTooFarInTheFuture) => {
|
||||
UnknownTransaction::Custom(error::Error::UnsignedTooFarInTheFuture.code()).into()
|
||||
}
|
||||
Err(error::Error::UnsignedTooFarInTheFuture) => UnknownTransaction::Custom(
|
||||
error::Error::UnsignedTooFarInTheFuture.code(),
|
||||
)
|
||||
.into(),
|
||||
Err(error) => InvalidTransaction::Custom(error.code()).into(),
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => InvalidTransaction::Call.into(),
|
||||
}
|
||||
}
|
||||
@@ -513,23 +514,28 @@ pub mod pallet {
|
||||
|
||||
/// Best known block.
|
||||
#[pallet::storage]
|
||||
pub(super) type BestBlock<T: Config<I>, I: 'static = ()> = StorageValue<_, (HeaderId, U256), ValueQuery>;
|
||||
pub(super) type BestBlock<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, (HeaderId, U256), ValueQuery>;
|
||||
|
||||
/// Best finalized block.
|
||||
#[pallet::storage]
|
||||
pub(super) type FinalizedBlock<T: Config<I>, I: 'static = ()> = StorageValue<_, HeaderId, ValueQuery>;
|
||||
pub(super) type FinalizedBlock<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, HeaderId, ValueQuery>;
|
||||
|
||||
/// Range of blocks that we want to prune.
|
||||
#[pallet::storage]
|
||||
pub(super) type BlocksToPrune<T: Config<I>, I: 'static = ()> = StorageValue<_, PruningRange, ValueQuery>;
|
||||
pub(super) type BlocksToPrune<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, PruningRange, ValueQuery>;
|
||||
|
||||
/// Map of imported headers by hash.
|
||||
#[pallet::storage]
|
||||
pub(super) type Headers<T: Config<I>, I: 'static = ()> = StorageMap<_, Identity, H256, StoredHeader<T::AccountId>>;
|
||||
pub(super) type Headers<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Identity, H256, StoredHeader<T::AccountId>>;
|
||||
|
||||
/// Map of imported header hashes by number.
|
||||
#[pallet::storage]
|
||||
pub(super) type HeadersByNumber<T: Config<I>, I: 'static = ()> = StorageMap<_, Blake2_128Concat, u64, Vec<H256>>;
|
||||
pub(super) type HeadersByNumber<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Blake2_128Concat, u64, Vec<H256>>;
|
||||
|
||||
/// Map of cached finality data by header hash.
|
||||
#[pallet::storage]
|
||||
@@ -538,17 +544,20 @@ pub mod pallet {
|
||||
|
||||
/// The ID of next validator set.
|
||||
#[pallet::storage]
|
||||
pub(super) type NextValidatorsSetId<T: Config<I>, I: 'static = ()> = StorageValue<_, u64, ValueQuery>;
|
||||
pub(super) type NextValidatorsSetId<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, u64, ValueQuery>;
|
||||
|
||||
/// Map of validators sets by their id.
|
||||
#[pallet::storage]
|
||||
pub(super) type ValidatorsSets<T: Config<I>, I: 'static = ()> = StorageMap<_, Twox64Concat, u64, ValidatorsSet>;
|
||||
pub(super) type ValidatorsSets<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Twox64Concat, u64, ValidatorsSet>;
|
||||
|
||||
/// Validators sets reference count. Each header that is authored by this set increases
|
||||
/// the reference count. When we prune this header, we decrease the reference count.
|
||||
/// When it reaches zero, we are free to prune validator set as well.
|
||||
#[pallet::storage]
|
||||
pub(super) type ValidatorsSetsRc<T: Config<I>, I: 'static = ()> = StorageMap<_, Twox64Concat, u64, u64>;
|
||||
pub(super) type ValidatorsSetsRc<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Twox64Concat, u64, u64>;
|
||||
|
||||
/// Map of validators set changes scheduled by given header.
|
||||
#[pallet::storage]
|
||||
@@ -572,14 +581,16 @@ pub mod pallet {
|
||||
// the initial blocks should be selected so that:
|
||||
// 1) it doesn't signal validators changes;
|
||||
// 2) there are no scheduled validators changes from previous blocks;
|
||||
// 3) (implied) all direct children of initial block are authored by the same validators set.
|
||||
// 3) (implied) all direct children of initial block are authored by the same validators
|
||||
// set.
|
||||
|
||||
assert!(
|
||||
!self.initial_validators.is_empty(),
|
||||
"Initial validators set can't be empty",
|
||||
assert!(!self.initial_validators.is_empty(), "Initial validators set can't be empty",);
|
||||
|
||||
initialize_storage::<T, I>(
|
||||
&self.initial_header,
|
||||
self.initial_difficulty,
|
||||
&self.initial_validators,
|
||||
);
|
||||
|
||||
initialize_storage::<T, I>(&self.initial_header, self.initial_difficulty, &self.initial_validators);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -648,7 +659,7 @@ impl<T: Config<I>, I: 'static> BridgeStorage<T, I> {
|
||||
for number in begin..end {
|
||||
// if we can't prune anything => break
|
||||
if max_blocks_to_prune == 0 {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
// read hashes of blocks with given number and try to prune these blocks
|
||||
@@ -664,7 +675,7 @@ impl<T: Config<I>, I: 'static> BridgeStorage<T, I> {
|
||||
// if we haven't pruned all blocks, remember unpruned
|
||||
if !blocks_at_number.is_empty() {
|
||||
HeadersByNumber::<T, I>::insert(number, blocks_at_number);
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,8 +703,10 @@ impl<T: Config<I>, I: 'static> BridgeStorage<T, I> {
|
||||
blocks_at_number: &mut Vec<H256>,
|
||||
) {
|
||||
// ensure that unfinalized headers we want to prune do not have scheduled changes
|
||||
if number > finalized_number && blocks_at_number.iter().any(ScheduledChanges::<T, I>::contains_key) {
|
||||
return;
|
||||
if number > finalized_number &&
|
||||
blocks_at_number.iter().any(ScheduledChanges::<T, I>::contains_key)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
// physically remove headers and (probably) obsolete validators sets
|
||||
@@ -718,7 +731,7 @@ impl<T: Config<I>, I: 'static> BridgeStorage<T, I> {
|
||||
// check if we have already pruned too much headers in this call
|
||||
*max_blocks_to_prune -= 1;
|
||||
if *max_blocks_to_prune == 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -749,21 +762,22 @@ impl<T: Config<I>, I: 'static> Storage for BridgeStorage<T, I> {
|
||||
let mut current_id = *parent;
|
||||
loop {
|
||||
// if we have reached finalized block's sibling => stop with special signal
|
||||
if current_id.number == best_finalized.number && current_id.hash != best_finalized.hash {
|
||||
if current_id.number == best_finalized.number && current_id.hash != best_finalized.hash
|
||||
{
|
||||
votes.stopped_at_finalized_sibling = true;
|
||||
return votes;
|
||||
return votes
|
||||
}
|
||||
|
||||
// if we have reached target header => stop
|
||||
if stop_at(¤t_id.hash) {
|
||||
return votes;
|
||||
return votes
|
||||
}
|
||||
|
||||
// if we have found cached votes => stop
|
||||
let cached_votes = FinalityCache::<T, I>::get(¤t_id.hash);
|
||||
if let Some(cached_votes) = cached_votes {
|
||||
votes.votes = Some(cached_votes);
|
||||
return votes;
|
||||
return votes
|
||||
}
|
||||
|
||||
// read next parent header id
|
||||
@@ -792,7 +806,9 @@ impl<T: Config<I>, I: 'static> Storage for BridgeStorage<T, I> {
|
||||
) -> Option<ImportContext<Self::Submitter>> {
|
||||
Headers::<T, I>::get(parent_hash).map(|parent_header| {
|
||||
let validators_set = ValidatorsSets::<T, I>::get(parent_header.next_validators_set_id)
|
||||
.expect("validators set is only pruned when last ref is pruned; there is a ref; qed");
|
||||
.expect(
|
||||
"validators set is only pruned when last ref is pruned; there is a ref; qed",
|
||||
);
|
||||
let parent_scheduled_change = ScheduledChanges::<T, I>::get(parent_hash);
|
||||
ImportContext {
|
||||
submitter,
|
||||
@@ -841,19 +857,20 @@ impl<T: Config<I>, I: 'static> Storage for BridgeStorage<T, I> {
|
||||
);
|
||||
ValidatorsSetsRc::<T, I>::insert(next_validators_set_id, 1);
|
||||
next_validators_set_id
|
||||
}
|
||||
},
|
||||
None => {
|
||||
ValidatorsSetsRc::<T, I>::mutate(header.context.validators_set_id, |rc| {
|
||||
*rc = Some(rc.map(|rc| rc + 1).unwrap_or(1));
|
||||
*rc
|
||||
});
|
||||
header.context.validators_set_id
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let finality_votes_caching_interval = T::FinalityVotesCachingInterval::get();
|
||||
if let Some(finality_votes_caching_interval) = finality_votes_caching_interval {
|
||||
let cache_entry_required = header.id.number != 0 && header.id.number % finality_votes_caching_interval == 0;
|
||||
let cache_entry_required =
|
||||
header.id.number != 0 && header.id.number % finality_votes_caching_interval == 0;
|
||||
if cache_entry_required {
|
||||
FinalityCache::<T, I>::insert(header.id.hash, header.finality_votes);
|
||||
}
|
||||
@@ -917,10 +934,7 @@ pub(crate) fn initialize_storage<T: Config<I>, I: 'static>(
|
||||
initial_hash,
|
||||
);
|
||||
|
||||
let initial_id = HeaderId {
|
||||
number: initial_header.number,
|
||||
hash: initial_hash,
|
||||
};
|
||||
let initial_id = HeaderId { number: initial_header.number, hash: initial_hash };
|
||||
BestBlock::<T, I>::put((initial_id, initial_difficulty));
|
||||
FinalizedBlock::<T, I>::put(initial_id);
|
||||
BlocksToPrune::<T, I>::put(PruningRange {
|
||||
@@ -965,7 +979,7 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
proof.len(),
|
||||
);
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
let header = match storage.header(&block) {
|
||||
@@ -977,8 +991,8 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
block,
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false
|
||||
},
|
||||
};
|
||||
let finalized = storage.finalized_block();
|
||||
|
||||
@@ -992,7 +1006,7 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
finalized.number,
|
||||
);
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
// check if header is actually finalized
|
||||
@@ -1010,7 +1024,7 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
finalized.hash,
|
||||
);
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
// verify that transaction is included in the block
|
||||
@@ -1022,7 +1036,7 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
computed_root,
|
||||
);
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
// verify that transaction receipt is included in the block
|
||||
@@ -1034,7 +1048,7 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
computed_root,
|
||||
);
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
// check that transaction has completed successfully
|
||||
@@ -1048,7 +1062,7 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
);
|
||||
|
||||
false
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::trace!(
|
||||
target: "runtime",
|
||||
@@ -1057,23 +1071,24 @@ pub fn verify_transaction_finalized<S: Storage>(
|
||||
);
|
||||
|
||||
false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction pool configuration.
|
||||
fn pool_configuration() -> PoolConfiguration {
|
||||
PoolConfiguration {
|
||||
max_future_number_difference: 10,
|
||||
}
|
||||
PoolConfiguration { max_future_number_difference: 10 }
|
||||
}
|
||||
|
||||
/// Return iterator of given header ancestors.
|
||||
fn ancestry<S: Storage>(storage: &'_ S, mut parent_hash: H256) -> impl Iterator<Item = (H256, AuraHeader)> + '_ {
|
||||
fn ancestry<S: Storage>(
|
||||
storage: &'_ S,
|
||||
mut parent_hash: H256,
|
||||
) -> impl Iterator<Item = (H256, AuraHeader)> + '_ {
|
||||
sp_std::iter::from_fn(move || {
|
||||
let (header, _) = storage.header(&parent_hash)?;
|
||||
if header.number == 0 {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
let hash = parent_hash;
|
||||
@@ -1085,12 +1100,14 @@ fn ancestry<S: Storage>(storage: &'_ S, mut parent_hash: H256) -> impl Iterator<
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use crate::finality::FinalityAncestor;
|
||||
use crate::mock::{
|
||||
genesis, insert_header, run_test, run_test_with_genesis, validators_addresses, HeaderBuilder, TestRuntime,
|
||||
GAS_LIMIT,
|
||||
use crate::{
|
||||
finality::FinalityAncestor,
|
||||
mock::{
|
||||
genesis, insert_header, run_test, run_test_with_genesis, validators_addresses,
|
||||
HeaderBuilder, TestRuntime, GAS_LIMIT,
|
||||
},
|
||||
test_utils::validator_utils::*,
|
||||
};
|
||||
use crate::test_utils::validator_utils::*;
|
||||
use bp_eth_poa::compute_merkle_root;
|
||||
|
||||
const TOTAL_VALIDATORS: usize = 3;
|
||||
@@ -1182,10 +1199,7 @@ pub(crate) mod tests {
|
||||
assert_eq!(HeadersByNumber::<TestRuntime, ()>::get(&5).unwrap().len(), 5);
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 5,
|
||||
oldest_block_to_keep: 5,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 5, oldest_block_to_keep: 5 },
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1202,10 +1216,7 @@ pub(crate) mod tests {
|
||||
storage.prune_blocks(0xFFFF, 10, 3);
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 5,
|
||||
oldest_block_to_keep: 5,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 5, oldest_block_to_keep: 5 },
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1221,10 +1232,7 @@ pub(crate) mod tests {
|
||||
assert!(HeadersByNumber::<TestRuntime, ()>::get(&3).is_some());
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 0,
|
||||
oldest_block_to_keep: 10,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 0, oldest_block_to_keep: 10 },
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1242,10 +1250,7 @@ pub(crate) mod tests {
|
||||
assert_eq!(HeadersByNumber::<TestRuntime, ()>::get(&2).unwrap().len(), 4);
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 2,
|
||||
oldest_block_to_keep: 10,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 2, oldest_block_to_keep: 10 },
|
||||
);
|
||||
|
||||
// try to prune blocks [2; 10)
|
||||
@@ -1258,10 +1263,7 @@ pub(crate) mod tests {
|
||||
assert_eq!(HeadersByNumber::<TestRuntime, ()>::get(&4).unwrap().len(), 3);
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 4,
|
||||
oldest_block_to_keep: 10,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 4, oldest_block_to_keep: 10 },
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1284,10 +1286,7 @@ pub(crate) mod tests {
|
||||
assert_eq!(HeadersByNumber::<TestRuntime, ()>::get(&7).unwrap().len(), 5);
|
||||
assert_eq!(
|
||||
BlocksToPrune::<TestRuntime, ()>::get(),
|
||||
PruningRange {
|
||||
oldest_unpruned_block: 7,
|
||||
oldest_block_to_keep: 10,
|
||||
},
|
||||
PruningRange { oldest_unpruned_block: 7, oldest_block_to_keep: 10 },
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1307,7 +1306,8 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
// for header with number = interval, cache entry is created
|
||||
let header_with_entry = HeaderBuilder::with_parent_number(interval - 1).sign_by_set(&ctx.validators);
|
||||
let header_with_entry =
|
||||
HeaderBuilder::with_parent_number(interval - 1).sign_by_set(&ctx.validators);
|
||||
let header_with_entry_hash = header_with_entry.compute_hash();
|
||||
insert_header(&mut storage, header_with_entry);
|
||||
assert!(FinalityCache::<TestRuntime>::get(&header_with_entry_hash).is_some());
|
||||
@@ -1354,10 +1354,7 @@ pub(crate) mod tests {
|
||||
let votes_at_3 = FinalityVotes {
|
||||
votes: vec![([42; 20].into(), 21)].into_iter().collect(),
|
||||
ancestry: vec![FinalityAncestor {
|
||||
id: HeaderId {
|
||||
number: 100,
|
||||
hash: Default::default(),
|
||||
},
|
||||
id: HeaderId { number: 100, hash: Default::default() },
|
||||
..Default::default()
|
||||
}]
|
||||
.into_iter()
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
// From construct_runtime macro
|
||||
#![allow(clippy::from_over_into)]
|
||||
|
||||
pub use crate::test_utils::{insert_header, validator_utils::*, validators_change_receipt, HeaderBuilder, GAS_LIMIT};
|
||||
pub use crate::test_utils::{
|
||||
insert_header, validator_utils::*, validators_change_receipt, HeaderBuilder, GAS_LIMIT,
|
||||
};
|
||||
pub use bp_eth_poa::signatures::secret_to_address;
|
||||
|
||||
use crate::validators::{ValidatorsConfiguration, ValidatorsSource};
|
||||
use crate::{AuraConfiguration, ChainTime, Config, GenesisConfig as CrateGenesisConfig, PruningStrategy};
|
||||
use crate::{
|
||||
validators::{ValidatorsConfiguration, ValidatorsSource},
|
||||
AuraConfiguration, ChainTime, Config, GenesisConfig as CrateGenesisConfig, PruningStrategy,
|
||||
};
|
||||
use bp_eth_poa::{Address, AuraHeader, H256, U256};
|
||||
use frame_support::{parameter_types, traits::GenesisBuild, weights::Weight};
|
||||
use secp256k1::SecretKey;
|
||||
@@ -154,14 +158,7 @@ pub fn run_test_with_genesis<T>(
|
||||
})
|
||||
.unwrap(),
|
||||
)
|
||||
.execute_with(|| {
|
||||
test(TestContext {
|
||||
genesis,
|
||||
total_validators,
|
||||
validators,
|
||||
addresses,
|
||||
})
|
||||
})
|
||||
.execute_with(|| test(TestContext { genesis, total_validators, validators, addresses }))
|
||||
}
|
||||
|
||||
/// Pruning strategy that keeps 10 headers behind best block.
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
// Since this is test code it's fine that not everything is used
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::finality::FinalityVotes;
|
||||
use crate::validators::CHANGE_EVENT_HASH;
|
||||
use crate::verification::calculate_score;
|
||||
use crate::{Config, HeaderToImport, Storage};
|
||||
use crate::{
|
||||
finality::FinalityVotes, validators::CHANGE_EVENT_HASH, verification::calculate_score, Config,
|
||||
HeaderToImport, Storage,
|
||||
};
|
||||
|
||||
use bp_eth_poa::{
|
||||
rlp_encode,
|
||||
@@ -130,10 +130,7 @@ impl HeaderBuilder {
|
||||
let sealed_empty_steps = empty_steps
|
||||
.iter()
|
||||
.map(|(author, step)| {
|
||||
let mut empty_step = SealedEmptyStep {
|
||||
step: *step,
|
||||
signature: Default::default(),
|
||||
};
|
||||
let mut empty_step = SealedEmptyStep { step: *step, signature: Default::default() };
|
||||
let message = empty_step.message(&self.header.parent_hash);
|
||||
let signature: [u8; 65] = sign(author, message).into();
|
||||
empty_step.signature = signature.into();
|
||||
@@ -216,7 +213,11 @@ pub fn build_genesis_header(author: &SecretKey) -> AuraHeader {
|
||||
}
|
||||
|
||||
/// Helper function for building a custom child header which has been signed by an authority.
|
||||
pub fn build_custom_header<F>(author: &SecretKey, previous: &AuraHeader, customize_header: F) -> AuraHeader
|
||||
pub fn build_custom_header<F>(
|
||||
author: &SecretKey,
|
||||
previous: &AuraHeader,
|
||||
customize_header: F,
|
||||
) -> AuraHeader
|
||||
where
|
||||
F: FnOnce(AuraHeader) -> AuraHeader,
|
||||
{
|
||||
@@ -232,7 +233,8 @@ pub fn insert_header<S: Storage>(storage: &mut S, header: AuraHeader) {
|
||||
let id = header.compute_id();
|
||||
let best_finalized = storage.finalized_block();
|
||||
let import_context = storage.import_context(None, &header.parent_hash).unwrap();
|
||||
let parent_finality_votes = storage.cached_finality_votes(&header.parent_id().unwrap(), &best_finalized, |_| false);
|
||||
let parent_finality_votes =
|
||||
storage.cached_finality_votes(&header.parent_id().unwrap(), &best_finalized, |_| false);
|
||||
let finality_votes = crate::finality::prepare_votes(
|
||||
parent_finality_votes,
|
||||
best_finalized,
|
||||
@@ -284,9 +286,10 @@ pub fn validators_change_receipt(parent_hash: H256) -> Receipt {
|
||||
address: [3; 20].into(),
|
||||
topics: vec![CHANGE_EVENT_HASH.into(), parent_hash],
|
||||
data: vec![
|
||||
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, 1, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
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, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
],
|
||||
}],
|
||||
}
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
// 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::error::Error;
|
||||
use crate::{ChangeToEnact, Storage};
|
||||
use crate::{error::Error, ChangeToEnact, Storage};
|
||||
use bp_eth_poa::{Address, AuraHeader, HeaderId, LogEntry, Receipt, U256};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// The hash of InitiateChange event of the validators set contract.
|
||||
pub(crate) const CHANGE_EVENT_HASH: &[u8; 32] = &[
|
||||
0x55, 0x25, 0x2f, 0xa6, 0xee, 0xe4, 0x74, 0x1b, 0x4e, 0x24, 0xa7, 0x4a, 0x70, 0xe9, 0xc1, 0x1f, 0xd2, 0xc2, 0x28,
|
||||
0x1d, 0xf8, 0xd6, 0xea, 0x13, 0x12, 0x6f, 0xf8, 0x45, 0xf7, 0x82, 0x5c, 0x89,
|
||||
0x55, 0x25, 0x2f, 0xa6, 0xee, 0xe4, 0x74, 0x1b, 0x4e, 0x24, 0xa7, 0x4a, 0x70, 0xe9, 0xc1, 0x1f,
|
||||
0xd2, 0xc2, 0x28, 0x1d, 0xf8, 0xd6, 0xea, 0x13, 0x12, 0x6f, 0xf8, 0x45, 0xf7, 0x82, 0x5c, 0x89,
|
||||
];
|
||||
|
||||
/// Where source of validators addresses come from. This covers the chain lifetime.
|
||||
@@ -104,7 +103,8 @@ impl<'a> Validators<'a> {
|
||||
if next_starts_at == header.number {
|
||||
match *next_source {
|
||||
ValidatorsSource::List(ref new_list) => return Ok((None, Some(new_list.clone()))),
|
||||
ValidatorsSource::Contract(_, ref new_list) => return Ok((Some(new_list.clone()), None)),
|
||||
ValidatorsSource::Contract(_, ref new_list) =>
|
||||
return Ok((Some(new_list.clone()), None)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +128,12 @@ impl<'a> Validators<'a> {
|
||||
.bloom();
|
||||
|
||||
if !header.log_bloom.contains(&expected_bloom) {
|
||||
return Ok((None, None));
|
||||
return Ok((None, None))
|
||||
}
|
||||
|
||||
let receipts = receipts.ok_or(Error::MissingTransactionsReceipts)?;
|
||||
if header.check_receipts_root(&receipts).is_err() {
|
||||
return Err(Error::TransactionsReceiptsMismatch);
|
||||
return Err(Error::TransactionsReceiptsMismatch)
|
||||
}
|
||||
|
||||
// iterate in reverse because only the _last_ change in a given
|
||||
@@ -145,24 +145,24 @@ impl<'a> Validators<'a> {
|
||||
.filter(|r| r.log_bloom.contains(&expected_bloom))
|
||||
.flat_map(|r| r.logs.iter())
|
||||
.filter(|l| {
|
||||
l.address == *contract_address
|
||||
&& l.topics.len() == 2 && l.topics[0].as_fixed_bytes() == CHANGE_EVENT_HASH
|
||||
&& l.topics[1] == header.parent_hash
|
||||
l.address == *contract_address &&
|
||||
l.topics.len() == 2 && l.topics[0].as_fixed_bytes() == CHANGE_EVENT_HASH &&
|
||||
l.topics[1] == header.parent_hash
|
||||
})
|
||||
.filter_map(|l| {
|
||||
let data_len = l.data.len();
|
||||
if data_len < 64 {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
let new_validators_len_u256 = U256::from_big_endian(&l.data[32..64]);
|
||||
let new_validators_len = new_validators_len_u256.low_u64();
|
||||
if new_validators_len_u256 != new_validators_len.into() {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
if (data_len - 64) as u64 != new_validators_len.saturating_mul(32) {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
Some(
|
||||
@@ -216,12 +216,10 @@ impl<'a> Validators<'a> {
|
||||
}
|
||||
})
|
||||
.and_then(|signal_block| {
|
||||
storage
|
||||
.scheduled_change(&signal_block.hash)
|
||||
.map(|change| ChangeToEnact {
|
||||
signal_block: Some(signal_block),
|
||||
validators: change.validators,
|
||||
})
|
||||
storage.scheduled_change(&signal_block.hash).map(|change| ChangeToEnact {
|
||||
signal_block: Some(signal_block),
|
||||
validators: change.validators,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -243,7 +241,11 @@ impl<'a> Validators<'a> {
|
||||
}
|
||||
|
||||
/// Returns source of validators that should author the next header.
|
||||
fn source_at_next_header(&self, header_source_index: usize, header_number: u64) -> (u64, &ValidatorsSource) {
|
||||
fn source_at_next_header(
|
||||
&self,
|
||||
header_source_index: usize,
|
||||
header_number: u64,
|
||||
) -> (u64, &ValidatorsSource) {
|
||||
match self.config {
|
||||
ValidatorsConfiguration::Single(ref source) => (0, source),
|
||||
ValidatorsConfiguration::Multi(ref sources) => {
|
||||
@@ -251,13 +253,13 @@ impl<'a> Validators<'a> {
|
||||
if next_source_index < sources.len() {
|
||||
let next_source = &sources[next_source_index];
|
||||
if next_source.0 < header_number + 1 {
|
||||
return (next_source.0, &next_source.1);
|
||||
return (next_source.0, &next_source.1)
|
||||
}
|
||||
}
|
||||
|
||||
let source = &sources[header_source_index];
|
||||
(source.0, &source.1)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,8 +277,10 @@ impl ValidatorsSource {
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{run_test, validators_addresses, validators_change_receipt, TestRuntime};
|
||||
use crate::{AuraScheduledChange, BridgeStorage, Headers, ScheduledChanges, StoredHeader};
|
||||
use crate::{
|
||||
mock::{run_test, validators_addresses, validators_change_receipt, TestRuntime},
|
||||
AuraScheduledChange, BridgeStorage, Headers, ScheduledChanges, StoredHeader,
|
||||
};
|
||||
use bp_eth_poa::compute_merkle_root;
|
||||
|
||||
const TOTAL_VALIDATORS: usize = 3;
|
||||
@@ -290,10 +294,7 @@ pub(crate) mod tests {
|
||||
]);
|
||||
let validators = Validators::new(&config);
|
||||
|
||||
assert_eq!(
|
||||
validators.source_at(99),
|
||||
(0, 0, &ValidatorsSource::List(vec![[1; 20].into()])),
|
||||
);
|
||||
assert_eq!(validators.source_at(99), (0, 0, &ValidatorsSource::List(vec![[1; 20].into()])),);
|
||||
assert_eq!(
|
||||
validators.source_at_next_header(0, 99),
|
||||
(0, &ValidatorsSource::List(vec![[1; 20].into()])),
|
||||
@@ -321,12 +322,12 @@ pub(crate) mod tests {
|
||||
#[test]
|
||||
fn maybe_signals_validators_change_works() {
|
||||
// when contract is active, but bloom has no required bits set
|
||||
let config = ValidatorsConfiguration::Single(ValidatorsSource::Contract(Default::default(), Vec::new()));
|
||||
let config = ValidatorsConfiguration::Single(ValidatorsSource::Contract(
|
||||
Default::default(),
|
||||
Vec::new(),
|
||||
));
|
||||
let validators = Validators::new(&config);
|
||||
let mut header = AuraHeader {
|
||||
number: u64::max_value(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut header = AuraHeader { number: u64::max_value(), ..Default::default() };
|
||||
assert!(!validators.maybe_signals_validators_change(&header));
|
||||
|
||||
// when contract is active and bloom has required bits set
|
||||
@@ -347,10 +348,7 @@ pub(crate) mod tests {
|
||||
(200, ValidatorsSource::Contract([3; 20].into(), vec![[3; 20].into()])),
|
||||
]);
|
||||
let validators = Validators::new(&config);
|
||||
let mut header = AuraHeader {
|
||||
number: 100,
|
||||
..Default::default()
|
||||
};
|
||||
let mut header = AuraHeader { number: 100, ..Default::default() };
|
||||
|
||||
// when we're at the block that switches to list source
|
||||
assert_eq!(
|
||||
@@ -406,26 +404,20 @@ pub(crate) mod tests {
|
||||
|
||||
fn try_finalize_with_scheduled_change(scheduled_at: Option<HeaderId>) -> Option<ChangeToEnact> {
|
||||
run_test(TOTAL_VALIDATORS, |_| {
|
||||
let config = ValidatorsConfiguration::Single(ValidatorsSource::Contract(Default::default(), Vec::new()));
|
||||
let config = ValidatorsConfiguration::Single(ValidatorsSource::Contract(
|
||||
Default::default(),
|
||||
Vec::new(),
|
||||
));
|
||||
let validators = Validators::new(&config);
|
||||
let storage = BridgeStorage::<TestRuntime>::new();
|
||||
|
||||
// when we're finailizing blocks 10...100
|
||||
let id10 = HeaderId {
|
||||
number: 10,
|
||||
hash: [10; 32].into(),
|
||||
};
|
||||
let id100 = HeaderId {
|
||||
number: 100,
|
||||
hash: [100; 32].into(),
|
||||
};
|
||||
let id10 = HeaderId { number: 10, hash: [10; 32].into() };
|
||||
let id100 = HeaderId { number: 100, hash: [100; 32].into() };
|
||||
let finalized_blocks = vec![(id10, None), (id100, None)];
|
||||
let header100 = StoredHeader::<u64> {
|
||||
submitter: None,
|
||||
header: AuraHeader {
|
||||
number: 100,
|
||||
..Default::default()
|
||||
},
|
||||
header: AuraHeader { number: 100, ..Default::default() },
|
||||
total_difficulty: 0.into(),
|
||||
next_validators_set_id: 0,
|
||||
last_signal_block: scheduled_at,
|
||||
@@ -445,16 +437,10 @@ pub(crate) mod tests {
|
||||
|
||||
#[test]
|
||||
fn finalize_validators_change_finalizes_scheduled_change() {
|
||||
let id50 = HeaderId {
|
||||
number: 50,
|
||||
..Default::default()
|
||||
};
|
||||
let id50 = HeaderId { number: 50, ..Default::default() };
|
||||
assert_eq!(
|
||||
try_finalize_with_scheduled_change(Some(id50)),
|
||||
Some(ChangeToEnact {
|
||||
signal_block: Some(id50),
|
||||
validators: validators_addresses(1),
|
||||
}),
|
||||
Some(ChangeToEnact { signal_block: Some(id50), validators: validators_addresses(1) }),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -465,10 +451,7 @@ pub(crate) mod tests {
|
||||
|
||||
#[test]
|
||||
fn finalize_validators_change_does_not_finalize_changes_when_they_are_outside_of_range() {
|
||||
let id5 = HeaderId {
|
||||
number: 5,
|
||||
..Default::default()
|
||||
};
|
||||
let id5 = HeaderId { number: 5, ..Default::default() };
|
||||
assert_eq!(try_finalize_with_scheduled_change(Some(id5)), None,);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
// 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::error::Error;
|
||||
use crate::validators::{Validators, ValidatorsConfiguration};
|
||||
use crate::{AuraConfiguration, AuraScheduledChange, ChainTime, ImportContext, PoolConfiguration, Storage};
|
||||
use crate::{
|
||||
error::Error,
|
||||
validators::{Validators, ValidatorsConfiguration},
|
||||
AuraConfiguration, AuraScheduledChange, ChainTime, ImportContext, PoolConfiguration, Storage,
|
||||
};
|
||||
use bp_eth_poa::{
|
||||
public_to_address, step_validator, Address, AuraHeader, HeaderId, Receipt, SealedEmptyStep, H256, H520, U128, U256,
|
||||
public_to_address, step_validator, Address, AuraHeader, HeaderId, Receipt, SealedEmptyStep,
|
||||
H256, H520, U128, U256,
|
||||
};
|
||||
use codec::Encode;
|
||||
use sp_io::crypto::secp256k1_ecdsa_recover;
|
||||
@@ -28,16 +31,19 @@ use sp_std::{vec, vec::Vec};
|
||||
/// Pre-check to see if should try and import this header.
|
||||
/// Returns error if we should not try to import this block.
|
||||
/// Returns ID of passed header and best finalized header.
|
||||
pub fn is_importable_header<S: Storage>(storage: &S, header: &AuraHeader) -> Result<(HeaderId, HeaderId), Error> {
|
||||
pub fn is_importable_header<S: Storage>(
|
||||
storage: &S,
|
||||
header: &AuraHeader,
|
||||
) -> Result<(HeaderId, HeaderId), Error> {
|
||||
// we never import any header that competes with finalized header
|
||||
let finalized_id = storage.finalized_block();
|
||||
if header.number <= finalized_id.number {
|
||||
return Err(Error::AncientHeader);
|
||||
return Err(Error::AncientHeader)
|
||||
}
|
||||
// we never import any header with known hash
|
||||
let id = header.compute_id();
|
||||
if storage.header(&id.hash).is_some() {
|
||||
return Err(Error::KnownHeader);
|
||||
return Err(Error::KnownHeader)
|
||||
}
|
||||
|
||||
Ok((id, finalized_id))
|
||||
@@ -64,7 +70,8 @@ pub fn accept_aura_header_into_pool<S: Storage, CT: ChainTime>(
|
||||
// we want to avoid having same headers twice in the pool
|
||||
// => we're strict about receipts here - if we need them, we require receipts to be Some,
|
||||
// otherwise we require receipts to be None
|
||||
let receipts_required = Validators::new(validators_config).maybe_signals_validators_change(header);
|
||||
let receipts_required =
|
||||
Validators::new(validators_config).maybe_signals_validators_change(header);
|
||||
match (receipts_required, receipts.is_some()) {
|
||||
(true, false) => return Err(Error::MissingTransactionsReceipts),
|
||||
(false, true) => return Err(Error::RedundantTransactionsReceipts),
|
||||
@@ -78,7 +85,7 @@ pub fn accept_aura_header_into_pool<S: Storage, CT: ChainTime>(
|
||||
let (best_id, _) = storage.best_block();
|
||||
let difference = header.number.saturating_sub(best_id.number);
|
||||
if difference > pool_config.max_future_number_difference {
|
||||
return Err(Error::UnsignedTooFarInTheFuture);
|
||||
return Err(Error::UnsignedTooFarInTheFuture)
|
||||
}
|
||||
|
||||
// TODO: only accept new headers when we're at the tip of PoA chain
|
||||
@@ -104,11 +111,8 @@ pub fn accept_aura_header_into_pool<S: Storage, CT: ChainTime>(
|
||||
|
||||
// since our parent is already in the storage, we do not require it
|
||||
// to be in the transaction pool
|
||||
(
|
||||
vec![],
|
||||
vec![provides_number_and_authority_tag, provides_header_number_and_hash_tag],
|
||||
)
|
||||
}
|
||||
(vec![], vec![provides_number_and_authority_tag, provides_header_number_and_hash_tag])
|
||||
},
|
||||
None => {
|
||||
// we know nothing about parent header
|
||||
// => the best thing we can do is to believe that there are no forks in
|
||||
@@ -119,34 +123,37 @@ pub fn accept_aura_header_into_pool<S: Storage, CT: ChainTime>(
|
||||
"import context is None only when header is missing from the storage;\
|
||||
best header is always in the storage; qed",
|
||||
);
|
||||
let validators_check_result =
|
||||
validator_checks(config, &best_context.validators_set().validators, header, header_step);
|
||||
let validators_check_result = validator_checks(
|
||||
config,
|
||||
&best_context.validators_set().validators,
|
||||
header,
|
||||
header_step,
|
||||
);
|
||||
if let Err(error) = validators_check_result {
|
||||
find_next_validators_signal(storage, &best_context)
|
||||
.ok_or(error)
|
||||
.and_then(|next_validators| validator_checks(config, &next_validators, header, header_step))?;
|
||||
find_next_validators_signal(storage, &best_context).ok_or(error).and_then(
|
||||
|next_validators| {
|
||||
validator_checks(config, &next_validators, header, header_step)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
// since our parent is missing from the storage, we **DO** require it
|
||||
// to be in the transaction pool
|
||||
// (- 1 can't underflow because there's always best block in the header)
|
||||
let requires_header_number_and_hash_tag = HeaderId {
|
||||
number: header.number - 1,
|
||||
hash: header.parent_hash,
|
||||
}
|
||||
.encode();
|
||||
let requires_header_number_and_hash_tag =
|
||||
HeaderId { number: header.number - 1, hash: header.parent_hash }.encode();
|
||||
(
|
||||
vec![requires_header_number_and_hash_tag],
|
||||
vec![provides_number_and_authority_tag, provides_header_number_and_hash_tag],
|
||||
)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// the heaviest, but rare operation - we do not want invalid receipts in the pool
|
||||
if let Some(receipts) = receipts {
|
||||
log::trace!(target: "runtime", "Got receipts! {:?}", receipts);
|
||||
if header.check_receipts_root(receipts).is_err() {
|
||||
return Err(Error::TransactionsReceiptsMismatch);
|
||||
return Err(Error::TransactionsReceiptsMismatch)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,32 +196,32 @@ fn contextless_checks<CT: ChainTime>(
|
||||
) -> Result<(), Error> {
|
||||
let expected_seal_fields = expected_header_seal_fields(config, header);
|
||||
if header.seal.len() != expected_seal_fields {
|
||||
return Err(Error::InvalidSealArity);
|
||||
return Err(Error::InvalidSealArity)
|
||||
}
|
||||
if header.number >= u64::max_value() {
|
||||
return Err(Error::RidiculousNumber);
|
||||
return Err(Error::RidiculousNumber)
|
||||
}
|
||||
if header.gas_used > header.gas_limit {
|
||||
return Err(Error::TooMuchGasUsed);
|
||||
return Err(Error::TooMuchGasUsed)
|
||||
}
|
||||
if header.gas_limit < config.min_gas_limit {
|
||||
return Err(Error::InvalidGasLimit);
|
||||
return Err(Error::InvalidGasLimit)
|
||||
}
|
||||
if header.gas_limit > config.max_gas_limit {
|
||||
return Err(Error::InvalidGasLimit);
|
||||
return Err(Error::InvalidGasLimit)
|
||||
}
|
||||
if header.number != 0 && header.extra_data.len() as u64 > config.maximum_extra_data_size {
|
||||
return Err(Error::ExtraDataOutOfBounds);
|
||||
return Err(Error::ExtraDataOutOfBounds)
|
||||
}
|
||||
|
||||
// we can't detect if block is from future in runtime
|
||||
// => let's only do an overflow check
|
||||
if header.timestamp > i32::max_value() as u64 {
|
||||
return Err(Error::TimestampOverflow);
|
||||
return Err(Error::TimestampOverflow)
|
||||
}
|
||||
|
||||
if chain_time.is_timestamp_ahead(header.timestamp) {
|
||||
return Err(Error::HeaderTimestampIsAhead);
|
||||
return Err(Error::HeaderTimestampIsAhead)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -233,15 +240,16 @@ fn contextual_checks<Submitter>(
|
||||
|
||||
// Ensure header is from the step after context.
|
||||
if header_step == parent_step {
|
||||
return Err(Error::DoubleVote);
|
||||
return Err(Error::DoubleVote)
|
||||
}
|
||||
#[allow(clippy::suspicious_operation_groupings)]
|
||||
if header.number >= config.validate_step_transition && header_step < parent_step {
|
||||
return Err(Error::DoubleVote);
|
||||
return Err(Error::DoubleVote)
|
||||
}
|
||||
|
||||
// If empty step messages are enabled we will validate the messages in the seal, missing messages are not
|
||||
// reported as there's no way to tell whether the empty step message was never sent or simply not included.
|
||||
// If empty step messages are enabled we will validate the messages in the seal, missing
|
||||
// messages are not reported as there's no way to tell whether the empty step message was never
|
||||
// sent or simply not included.
|
||||
let empty_steps_len = match header.number >= config.empty_steps_transition {
|
||||
true => {
|
||||
let strict_empty_steps = header.number >= config.strict_empty_steps_transition;
|
||||
@@ -251,16 +259,16 @@ fn contextual_checks<Submitter>(
|
||||
|
||||
for empty_step in empty_steps {
|
||||
if empty_step.step <= parent_step || empty_step.step >= header_step {
|
||||
return Err(Error::InsufficientProof);
|
||||
return Err(Error::InsufficientProof)
|
||||
}
|
||||
|
||||
if !verify_empty_step(&header.parent_hash, &empty_step, validators) {
|
||||
return Err(Error::InsufficientProof);
|
||||
return Err(Error::InsufficientProof)
|
||||
}
|
||||
|
||||
if strict_empty_steps {
|
||||
if empty_step.step <= prev_empty_step {
|
||||
return Err(Error::InsufficientProof);
|
||||
return Err(Error::InsufficientProof)
|
||||
}
|
||||
|
||||
prev_empty_step = empty_step.step;
|
||||
@@ -268,7 +276,7 @@ fn contextual_checks<Submitter>(
|
||||
}
|
||||
|
||||
empty_steps_len
|
||||
}
|
||||
},
|
||||
false => 0,
|
||||
};
|
||||
|
||||
@@ -276,7 +284,7 @@ fn contextual_checks<Submitter>(
|
||||
if header.number >= config.validate_score_transition {
|
||||
let expected_difficulty = calculate_score(parent_step, header_step, empty_steps_len as _);
|
||||
if header.difficulty != expected_difficulty {
|
||||
return Err(Error::InvalidDifficulty);
|
||||
return Err(Error::InvalidDifficulty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,16 +300,17 @@ fn validator_checks(
|
||||
) -> Result<(), Error> {
|
||||
let expected_validator = *step_validator(validators, header_step);
|
||||
if header.author != expected_validator {
|
||||
return Err(Error::NotValidator);
|
||||
return Err(Error::NotValidator)
|
||||
}
|
||||
|
||||
let validator_signature = header.signature().ok_or(Error::MissingSignature)?;
|
||||
let header_seal_hash = header
|
||||
.seal_hash(header.number >= config.empty_steps_transition)
|
||||
.ok_or(Error::MissingEmptySteps)?;
|
||||
let is_invalid_proposer = !verify_signature(&expected_validator, &validator_signature, &header_seal_hash);
|
||||
let is_invalid_proposer =
|
||||
!verify_signature(&expected_validator, &validator_signature, &header_seal_hash);
|
||||
if is_invalid_proposer {
|
||||
return Err(Error::NotValidator);
|
||||
return Err(Error::NotValidator)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -324,8 +333,13 @@ fn verify_empty_step(parent_hash: &H256, step: &SealedEmptyStep, validators: &[A
|
||||
}
|
||||
|
||||
/// Chain scoring: total weight is sqrt(U256::max_value())*height - step
|
||||
pub(crate) fn calculate_score(parent_step: u64, current_step: u64, current_empty_steps: usize) -> U256 {
|
||||
U256::from(U128::max_value()) + U256::from(parent_step) - U256::from(current_step) + U256::from(current_empty_steps)
|
||||
pub(crate) fn calculate_score(
|
||||
parent_step: u64,
|
||||
current_step: u64,
|
||||
current_empty_steps: usize,
|
||||
) -> U256 {
|
||||
U256::from(U128::max_value()) + U256::from(parent_step) - U256::from(current_step) +
|
||||
U256::from(current_empty_steps)
|
||||
}
|
||||
|
||||
/// Verify that the signature over message has been produced by given validator.
|
||||
@@ -337,7 +351,10 @@ fn verify_signature(expected_validator: &Address, signature: &H520, message: &H2
|
||||
}
|
||||
|
||||
/// Find next unfinalized validators set change after finalized set.
|
||||
fn find_next_validators_signal<S: Storage>(storage: &S, context: &ImportContext<S::Submitter>) -> Option<Vec<Address>> {
|
||||
fn find_next_validators_signal<S: Storage>(
|
||||
storage: &S,
|
||||
context: &ImportContext<S::Submitter>,
|
||||
) -> Option<Vec<Address>> {
|
||||
// that's the earliest block number we may met in following loop
|
||||
// it may be None if that's the first set
|
||||
let best_set_signal_block = context.validators_set().signal_block;
|
||||
@@ -352,14 +369,15 @@ fn find_next_validators_signal<S: Storage>(storage: &S, context: &ImportContext<
|
||||
// next_current_block_hash points to the block that schedules next
|
||||
// change
|
||||
let current_scheduled_set = match current_set_signal_block {
|
||||
Some(current_set_signal_block) if Some(¤t_set_signal_block) == best_set_signal_block.as_ref() => {
|
||||
return next_scheduled_set.map(|scheduled_set| scheduled_set.validators)
|
||||
}
|
||||
Some(current_set_signal_block)
|
||||
if Some(¤t_set_signal_block) == best_set_signal_block.as_ref() =>
|
||||
return next_scheduled_set.map(|scheduled_set| scheduled_set.validators),
|
||||
None => return next_scheduled_set.map(|scheduled_set| scheduled_set.validators),
|
||||
Some(current_set_signal_block) => storage.scheduled_change(¤t_set_signal_block.hash).expect(
|
||||
"header that is associated with this change is not pruned;\
|
||||
Some(current_set_signal_block) =>
|
||||
storage.scheduled_change(¤t_set_signal_block.hash).expect(
|
||||
"header that is associated with this change is not pruned;\
|
||||
scheduled changes are only removed when header is pruned; qed",
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
current_set_signal_block = current_scheduled_set.prev_signal_block;
|
||||
@@ -370,13 +388,15 @@ fn find_next_validators_signal<S: Storage>(storage: &S, context: &ImportContext<
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
insert_header, run_test_with_genesis, test_aura_config, validator, validator_address, validators_addresses,
|
||||
validators_change_receipt, AccountId, ConstChainTime, HeaderBuilder, TestRuntime, GAS_LIMIT,
|
||||
};
|
||||
use crate::validators::ValidatorsSource;
|
||||
use crate::{
|
||||
pool_configuration, BridgeStorage, FinalizedBlock, Headers, HeadersByNumber, NextValidatorsSetId,
|
||||
mock::{
|
||||
insert_header, run_test_with_genesis, test_aura_config, validator, validator_address,
|
||||
validators_addresses, validators_change_receipt, AccountId, ConstChainTime,
|
||||
HeaderBuilder, TestRuntime, GAS_LIMIT,
|
||||
},
|
||||
pool_configuration,
|
||||
validators::ValidatorsSource,
|
||||
BridgeStorage, FinalizedBlock, Headers, HeadersByNumber, NextValidatorsSetId,
|
||||
ScheduledChanges, ValidatorsSet, ValidatorsSets,
|
||||
};
|
||||
use bp_eth_poa::{compute_merkle_root, rlp_encode, TransactionOutcome, H520, U256};
|
||||
@@ -391,7 +411,10 @@ mod tests {
|
||||
HeaderBuilder::genesis().step(GENESIS_STEP).sign_by(&validator(0))
|
||||
}
|
||||
|
||||
fn verify_with_config(config: &AuraConfiguration, header: &AuraHeader) -> Result<ImportContext<AccountId>, Error> {
|
||||
fn verify_with_config(
|
||||
config: &AuraConfiguration,
|
||||
header: &AuraHeader,
|
||||
) -> Result<ImportContext<AccountId>, Error> {
|
||||
run_test_with_genesis(genesis(), TOTAL_VALIDATORS, |_| {
|
||||
let storage = BridgeStorage::<TestRuntime>::new();
|
||||
verify_aura_header(&storage, config, None, header, &ConstChainTime::default())
|
||||
@@ -418,8 +441,10 @@ mod tests {
|
||||
|
||||
FinalizedBlock::<TestRuntime, ()>::put(block2_id);
|
||||
|
||||
let validators_config =
|
||||
ValidatorsConfiguration::Single(ValidatorsSource::Contract(Default::default(), Vec::new()));
|
||||
let validators_config = ValidatorsConfiguration::Single(ValidatorsSource::Contract(
|
||||
Default::default(),
|
||||
Vec::new(),
|
||||
));
|
||||
let (header, receipts) = make_header(&validators);
|
||||
accept_aura_header_into_pool(
|
||||
&storage,
|
||||
@@ -433,7 +458,11 @@ mod tests {
|
||||
})
|
||||
}
|
||||
|
||||
fn change_validators_set_at(number: u64, finalized_set: Vec<Address>, signalled_set: Option<Vec<Address>>) {
|
||||
fn change_validators_set_at(
|
||||
number: u64,
|
||||
finalized_set: Vec<Address>,
|
||||
signalled_set: Option<Vec<Address>>,
|
||||
) {
|
||||
let set_id = NextValidatorsSetId::<TestRuntime, ()>::get();
|
||||
NextValidatorsSetId::<TestRuntime, ()>::put(set_id + 1);
|
||||
ValidatorsSets::<TestRuntime, ()>::insert(
|
||||
@@ -458,10 +487,7 @@ mod tests {
|
||||
});
|
||||
ScheduledChanges::<TestRuntime, ()>::insert(
|
||||
header.header.parent_hash,
|
||||
AuraScheduledChange {
|
||||
validators: signalled_set,
|
||||
prev_signal_block: None,
|
||||
},
|
||||
AuraScheduledChange { validators: signalled_set, prev_signal_block: None },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -520,21 +546,15 @@ mod tests {
|
||||
config.max_gas_limit = 200.into();
|
||||
|
||||
// when limit is lower than expected
|
||||
let header = HeaderBuilder::with_number(1)
|
||||
.gas_limit(50.into())
|
||||
.sign_by(&validator(0));
|
||||
let header = HeaderBuilder::with_number(1).gas_limit(50.into()).sign_by(&validator(0));
|
||||
assert_eq!(verify_with_config(&config, &header), Err(Error::InvalidGasLimit));
|
||||
|
||||
// when limit is larger than expected
|
||||
let header = HeaderBuilder::with_number(1)
|
||||
.gas_limit(250.into())
|
||||
.sign_by(&validator(0));
|
||||
let header = HeaderBuilder::with_number(1).gas_limit(250.into()).sign_by(&validator(0));
|
||||
assert_eq!(verify_with_config(&config, &header), Err(Error::InvalidGasLimit));
|
||||
|
||||
// when limit is within expected range
|
||||
let header = HeaderBuilder::with_number(1)
|
||||
.gas_limit(150.into())
|
||||
.sign_by(&validator(0));
|
||||
let header = HeaderBuilder::with_number(1).gas_limit(150.into()).sign_by(&validator(0));
|
||||
assert_ne!(verify_with_config(&config, &header), Err(Error::InvalidGasLimit));
|
||||
}
|
||||
|
||||
@@ -573,7 +593,8 @@ mod tests {
|
||||
// expected import context after verification
|
||||
let expect = ImportContext::<AccountId> {
|
||||
submitter: None,
|
||||
parent_hash: hex!("6e41bff05578fc1db17f6816117969b07d2217f1f9039d8116a82764335991d3").into(),
|
||||
parent_hash: hex!("6e41bff05578fc1db17f6816117969b07d2217f1f9039d8116a82764335991d3")
|
||||
.into(),
|
||||
parent_header: genesis(),
|
||||
parent_total_difficulty: U256::zero(),
|
||||
parent_scheduled_change: None,
|
||||
@@ -587,7 +608,8 @@ mod tests {
|
||||
signal_block: None,
|
||||
enact_block: HeaderId {
|
||||
number: 0,
|
||||
hash: hex!("6e41bff05578fc1db17f6816117969b07d2217f1f9039d8116a82764335991d3").into(),
|
||||
hash: hex!("6e41bff05578fc1db17f6816117969b07d2217f1f9039d8116a82764335991d3")
|
||||
.into(),
|
||||
},
|
||||
},
|
||||
last_signal_block: None,
|
||||
@@ -729,7 +751,10 @@ mod tests {
|
||||
fn pool_verifies_known_blocks() {
|
||||
// when header is known
|
||||
assert_eq!(
|
||||
default_accept_into_pool(|validators| (HeaderBuilder::with_parent_number(2).sign_by_set(validators), None)),
|
||||
default_accept_into_pool(|validators| (
|
||||
HeaderBuilder::with_parent_number(2).sign_by_set(validators),
|
||||
None
|
||||
)),
|
||||
Err(Error::KnownHeader),
|
||||
);
|
||||
}
|
||||
@@ -785,7 +810,10 @@ mod tests {
|
||||
fn pool_verifies_future_block_number() {
|
||||
// when header is too far from the future
|
||||
assert_eq!(
|
||||
default_accept_into_pool(|validators| (HeaderBuilder::with_number(100).sign_by_set(validators), None),),
|
||||
default_accept_into_pool(|validators| (
|
||||
HeaderBuilder::with_number(100).sign_by_set(validators),
|
||||
None
|
||||
),),
|
||||
Err(Error::UnsignedTooFarInTheFuture),
|
||||
);
|
||||
}
|
||||
@@ -811,7 +839,10 @@ mod tests {
|
||||
// (even if header will be considered invalid/duplicate later, we can use this signature
|
||||
// as a proof of malicious action by this validator)
|
||||
assert_eq!(
|
||||
default_accept_into_pool(|_| (HeaderBuilder::with_number(8).step(8).sign_by(&validator(1)), None,)),
|
||||
default_accept_into_pool(|_| (
|
||||
HeaderBuilder::with_number(8).step(8).sign_by(&validator(1)),
|
||||
None,
|
||||
)),
|
||||
Err(Error::NotValidator),
|
||||
);
|
||||
}
|
||||
@@ -829,10 +860,7 @@ mod tests {
|
||||
// no tags are required
|
||||
vec![],
|
||||
// header provides two tags
|
||||
vec![
|
||||
(4u64, validators_addresses(3)[1]).encode(),
|
||||
(4u64, hash.unwrap()).encode(),
|
||||
],
|
||||
vec![(4u64, validators_addresses(3)[1]).encode(), (4u64, hash.unwrap()).encode(),],
|
||||
)),
|
||||
);
|
||||
}
|
||||
@@ -843,9 +871,8 @@ mod tests {
|
||||
let mut parent_id = None;
|
||||
assert_eq!(
|
||||
default_accept_into_pool(|validators| {
|
||||
let header = HeaderBuilder::with_number(5)
|
||||
.step(GENESIS_STEP + 5)
|
||||
.sign_by_set(validators);
|
||||
let header =
|
||||
HeaderBuilder::with_number(5).step(GENESIS_STEP + 5).sign_by_set(validators);
|
||||
id = Some(header.compute_id());
|
||||
parent_id = header.parent_id();
|
||||
(header, None)
|
||||
@@ -881,7 +908,11 @@ mod tests {
|
||||
assert_eq!(
|
||||
default_accept_into_pool(|actual_validators| {
|
||||
// change finalized set at parent header + signal valid set at parent block
|
||||
change_validators_set_at(3, validators_addresses(10), Some(validators_addresses(3)));
|
||||
change_validators_set_at(
|
||||
3,
|
||||
validators_addresses(10),
|
||||
Some(validators_addresses(3)),
|
||||
);
|
||||
|
||||
// header is signed using wrong set
|
||||
let header = HeaderBuilder::with_number(5)
|
||||
@@ -933,10 +964,7 @@ mod tests {
|
||||
// no tags are required
|
||||
vec![],
|
||||
// header provides two tags
|
||||
vec![
|
||||
(4u64, validators_addresses(3)[1]).encode(),
|
||||
(4u64, hash.unwrap()).encode(),
|
||||
],
|
||||
vec![(4u64, validators_addresses(3)[1]).encode(), (4u64, hash.unwrap()).encode(),],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
use crate::*;
|
||||
|
||||
use bp_test_utils::{
|
||||
accounts, make_justification_for_header, JustificationGeneratorParams, TEST_GRANDPA_ROUND, TEST_GRANDPA_SET_ID,
|
||||
accounts, make_justification_for_header, JustificationGeneratorParams, TEST_GRANDPA_ROUND,
|
||||
TEST_GRANDPA_SET_ID,
|
||||
};
|
||||
use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller};
|
||||
use frame_support::traits::Get;
|
||||
|
||||
@@ -38,8 +38,7 @@
|
||||
|
||||
use crate::weights::WeightInfo;
|
||||
|
||||
use bp_header_chain::justification::GrandpaJustification;
|
||||
use bp_header_chain::InitializationData;
|
||||
use bp_header_chain::{justification::GrandpaJustification, InitializationData};
|
||||
use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use frame_support::{ensure, fail};
|
||||
@@ -136,10 +135,7 @@ pub mod pallet {
|
||||
ensure_operational::<T, I>()?;
|
||||
let _ = ensure_signed(origin)?;
|
||||
|
||||
ensure!(
|
||||
Self::request_count() < T::MaxRequests::get(),
|
||||
<Error<T, I>>::TooManyRequests
|
||||
);
|
||||
ensure!(Self::request_count() < T::MaxRequests::get(), <Error<T, I>>::TooManyRequests);
|
||||
|
||||
let (hash, number) = (finality_target.hash(), finality_target.number());
|
||||
log::trace!(target: "runtime::bridge-grandpa", "Going to try and finalize header {:?}", finality_target);
|
||||
@@ -153,27 +149,29 @@ pub mod pallet {
|
||||
finality_target,
|
||||
);
|
||||
fail!(<Error<T, I>>::NotInitialized);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// We do a quick check here to ensure that our header chain is making progress and isn't
|
||||
// "travelling back in time" (which could be indicative of something bad, e.g a hard-fork).
|
||||
// "travelling back in time" (which could be indicative of something bad, e.g a
|
||||
// hard-fork).
|
||||
ensure!(best_finalized.number() < number, <Error<T, I>>::OldHeader);
|
||||
|
||||
let authority_set = <CurrentAuthoritySet<T, I>>::get();
|
||||
let set_id = authority_set.set_id;
|
||||
verify_justification::<T, I>(&justification, hash, *number, authority_set)?;
|
||||
|
||||
let is_authorities_change_enacted = try_enact_authority_change::<T, I>(&finality_target, set_id)?;
|
||||
let is_authorities_change_enacted =
|
||||
try_enact_authority_change::<T, I>(&finality_target, set_id)?;
|
||||
<RequestCount<T, I>>::mutate(|count| *count += 1);
|
||||
insert_header::<T, I>(*finality_target, hash);
|
||||
log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash);
|
||||
|
||||
// mandatory header is a header that changes authorities set. The pallet can't go further
|
||||
// without importing this header. So every bridge MUST import mandatory headers.
|
||||
// mandatory header is a header that changes authorities set. The pallet can't go
|
||||
// further without importing this header. So every bridge MUST import mandatory headers.
|
||||
//
|
||||
// We don't want to charge extra costs for mandatory operations. So relayer is not paying
|
||||
// fee for mandatory headers import transactions.
|
||||
// We don't want to charge extra costs for mandatory operations. So relayer is not
|
||||
// paying fee for mandatory headers import transactions.
|
||||
let is_mandatory_header = is_authorities_change_enacted;
|
||||
let pays_fee = if is_mandatory_header { Pays::No } else { Pays::Yes };
|
||||
|
||||
@@ -183,8 +181,8 @@ pub mod pallet {
|
||||
/// Bootstrap the bridge pallet with an initial header and authority set from which to sync.
|
||||
///
|
||||
/// The initial configuration provided does not need to be the genesis header of the bridged
|
||||
/// chain, it can be any arbitrary header. You can also provide the next scheduled set change
|
||||
/// if it is already know.
|
||||
/// chain, it can be any arbitrary header. You can also provide the next scheduled set
|
||||
/// change if it is already know.
|
||||
///
|
||||
/// This function is only allowed to be called from a trusted origin and writes to storage
|
||||
/// with practically no checks in terms of the validity of the data. It is important that
|
||||
@@ -213,17 +211,20 @@ pub mod pallet {
|
||||
///
|
||||
/// May only be called either by root, or by `PalletOwner`.
|
||||
#[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))]
|
||||
pub fn set_owner(origin: OriginFor<T>, new_owner: Option<T::AccountId>) -> DispatchResultWithPostInfo {
|
||||
pub fn set_owner(
|
||||
origin: OriginFor<T>,
|
||||
new_owner: Option<T::AccountId>,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
ensure_owner_or_root::<T, I>(origin)?;
|
||||
match new_owner {
|
||||
Some(new_owner) => {
|
||||
PalletOwner::<T, I>::put(&new_owner);
|
||||
log::info!(target: "runtime::bridge-grandpa", "Setting pallet Owner to: {:?}", new_owner);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
PalletOwner::<T, I>::kill();
|
||||
log::info!(target: "runtime::bridge-grandpa", "Removed Owner of pallet.");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Ok(().into())
|
||||
@@ -233,7 +234,10 @@ pub mod pallet {
|
||||
///
|
||||
/// May only be called either by root, or by `PalletOwner`.
|
||||
#[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))]
|
||||
pub fn set_operational(origin: OriginFor<T>, operational: bool) -> DispatchResultWithPostInfo {
|
||||
pub fn set_operational(
|
||||
origin: OriginFor<T>,
|
||||
operational: bool,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
ensure_owner_or_root::<T, I>(origin)?;
|
||||
<IsHalted<T, I>>::put(operational);
|
||||
|
||||
@@ -260,11 +264,13 @@ pub mod pallet {
|
||||
|
||||
/// Hash of the header used to bootstrap the pallet.
|
||||
#[pallet::storage]
|
||||
pub(super) type InitialHash<T: Config<I>, I: 'static = ()> = StorageValue<_, BridgedBlockHash<T, I>, ValueQuery>;
|
||||
pub(super) type InitialHash<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, BridgedBlockHash<T, I>, ValueQuery>;
|
||||
|
||||
/// Hash of the best finalized header.
|
||||
#[pallet::storage]
|
||||
pub(super) type BestFinalized<T: Config<I>, I: 'static = ()> = StorageValue<_, BridgedBlockHash<T, I>, ValueQuery>;
|
||||
pub(super) type BestFinalized<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, BridgedBlockHash<T, I>, ValueQuery>;
|
||||
|
||||
/// A ring buffer of imported hashes. Ordered by the insertion time.
|
||||
#[pallet::storage]
|
||||
@@ -273,7 +279,8 @@ pub mod pallet {
|
||||
|
||||
/// Current ring buffer position.
|
||||
#[pallet::storage]
|
||||
pub(super) type ImportedHashesPointer<T: Config<I>, I: 'static = ()> = StorageValue<_, u32, ValueQuery>;
|
||||
pub(super) type ImportedHashesPointer<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, u32, ValueQuery>;
|
||||
|
||||
/// Headers which have been imported into the pallet.
|
||||
#[pallet::storage]
|
||||
@@ -292,7 +299,8 @@ pub mod pallet {
|
||||
/// runtime methods may still be used to do that (i.e. democracy::referendum to update halt
|
||||
/// flag directly or call the `halt_operations`).
|
||||
#[pallet::storage]
|
||||
pub(super) type PalletOwner<T: Config<I>, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>;
|
||||
pub(super) type PalletOwner<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, T::AccountId, OptionQuery>;
|
||||
|
||||
/// If true, all pallet transactions are failed immediately.
|
||||
#[pallet::storage]
|
||||
@@ -309,10 +317,7 @@ pub mod pallet {
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
owner: None,
|
||||
init_data: None,
|
||||
}
|
||||
Self { owner: None, init_data: None }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,29 +424,35 @@ pub mod pallet {
|
||||
) -> Result<(), sp_runtime::DispatchError> {
|
||||
use bp_header_chain::justification::verify_justification;
|
||||
|
||||
let voter_set = VoterSet::new(authority_set.authorities).ok_or(<Error<T, I>>::InvalidAuthoritySet)?;
|
||||
let voter_set =
|
||||
VoterSet::new(authority_set.authorities).ok_or(<Error<T, I>>::InvalidAuthoritySet)?;
|
||||
let set_id = authority_set.set_id;
|
||||
|
||||
Ok(
|
||||
verify_justification::<BridgedHeader<T, I>>((hash, number), set_id, &voter_set, justification).map_err(
|
||||
|e| {
|
||||
log::error!(
|
||||
target: "runtime::bridge-grandpa",
|
||||
"Received invalid justification for {:?}: {:?}",
|
||||
hash,
|
||||
e,
|
||||
);
|
||||
<Error<T, I>>::InvalidJustification
|
||||
},
|
||||
)?,
|
||||
Ok(verify_justification::<BridgedHeader<T, I>>(
|
||||
(hash, number),
|
||||
set_id,
|
||||
&voter_set,
|
||||
justification,
|
||||
)
|
||||
.map_err(|e| {
|
||||
log::error!(
|
||||
target: "runtime::bridge-grandpa",
|
||||
"Received invalid justification for {:?}: {:?}",
|
||||
hash,
|
||||
e,
|
||||
);
|
||||
<Error<T, I>>::InvalidJustification
|
||||
})?)
|
||||
}
|
||||
|
||||
/// Import a previously verified header to the storage.
|
||||
///
|
||||
/// Note this function solely takes care of updating the storage and pruning old entries,
|
||||
/// but does not verify the validity of such import.
|
||||
pub(crate) fn insert_header<T: Config<I>, I: 'static>(header: BridgedHeader<T, I>, hash: BridgedBlockHash<T, I>) {
|
||||
pub(crate) fn insert_header<T: Config<I>, I: 'static>(
|
||||
header: BridgedHeader<T, I>,
|
||||
hash: BridgedBlockHash<T, I>,
|
||||
) {
|
||||
let index = <ImportedHashesPointer<T, I>>::get();
|
||||
let pruning = <ImportedHashes<T, I>>::try_get(index);
|
||||
<BestFinalized<T, I>>::put(hash);
|
||||
@@ -461,12 +472,7 @@ pub mod pallet {
|
||||
pub(crate) fn initialize_bridge<T: Config<I>, I: 'static>(
|
||||
init_params: super::InitializationData<BridgedHeader<T, I>>,
|
||||
) {
|
||||
let super::InitializationData {
|
||||
header,
|
||||
authority_list,
|
||||
set_id,
|
||||
is_halted,
|
||||
} = init_params;
|
||||
let super::InitializationData { header, authority_list, set_id, is_halted } = init_params;
|
||||
|
||||
let initial_hash = header.hash();
|
||||
<InitialHash<T, I>>::put(initial_hash);
|
||||
@@ -506,7 +512,9 @@ pub mod pallet {
|
||||
fn ensure_owner_or_root<T: Config<I>, I: 'static>(origin: T::Origin) -> Result<(), BadOrigin> {
|
||||
match origin.into() {
|
||||
Ok(RawOrigin::Root) => Ok(()),
|
||||
Ok(RawOrigin::Signed(ref signer)) if Some(signer) == <PalletOwner<T, I>>::get().as_ref() => Ok(()),
|
||||
Ok(RawOrigin::Signed(ref signer))
|
||||
if Some(signer) == <PalletOwner<T, I>>::get().as_ref() =>
|
||||
Ok(()),
|
||||
_ => Err(BadOrigin),
|
||||
}
|
||||
}
|
||||
@@ -553,14 +561,17 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
parse: impl FnOnce(bp_runtime::StorageProofChecker<BridgedBlockHasher<T, I>>) -> R,
|
||||
) -> Result<R, sp_runtime::DispatchError> {
|
||||
let header = <ImportedHeaders<T, I>>::get(hash).ok_or(Error::<T, I>::UnknownHeader)?;
|
||||
let storage_proof_checker = bp_runtime::StorageProofChecker::new(*header.state_root(), storage_proof)
|
||||
.map_err(|_| Error::<T, I>::StorageRootMismatch)?;
|
||||
let storage_proof_checker =
|
||||
bp_runtime::StorageProofChecker::new(*header.state_root(), storage_proof)
|
||||
.map_err(|_| Error::<T, I>::StorageRootMismatch)?;
|
||||
|
||||
Ok(parse(storage_proof_checker))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn find_scheduled_change<H: HeaderT>(header: &H) -> Option<sp_finality_grandpa::ScheduledChange<H::Number>> {
|
||||
pub(crate) fn find_scheduled_change<H: HeaderT>(
|
||||
header: &H,
|
||||
) -> Option<sp_finality_grandpa::ScheduledChange<H::Number>> {
|
||||
use sp_runtime::generic::OpaqueDigestItemId;
|
||||
|
||||
let id = OpaqueDigestItemId::Consensus(&GRANDPA_ENGINE_ID);
|
||||
@@ -599,7 +610,8 @@ pub(crate) fn find_forced_change<H: HeaderT>(
|
||||
pub fn initialize_for_benchmarks<T: Config<I>, I: 'static>(header: BridgedHeader<T, I>) {
|
||||
initialize_bridge::<T, I>(InitializationData {
|
||||
header: Box::new(header),
|
||||
authority_list: sp_std::vec::Vec::new(), // we don't verify any proofs in external benchmarks
|
||||
authority_list: sp_std::vec::Vec::new(), /* we don't verify any proofs in external
|
||||
* benchmarks */
|
||||
set_id: 0,
|
||||
is_halted: false,
|
||||
});
|
||||
@@ -608,14 +620,15 @@ pub fn initialize_for_benchmarks<T: Config<I>, I: 'static>(header: BridgedHeader
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{run_test, test_header, Origin, TestHash, TestHeader, TestNumber, TestRuntime};
|
||||
use crate::mock::{
|
||||
run_test, test_header, Origin, TestHash, TestHeader, TestNumber, TestRuntime,
|
||||
};
|
||||
use bp_test_utils::{
|
||||
authority_list, make_default_justification, make_justification_for_header, JustificationGeneratorParams, ALICE,
|
||||
BOB,
|
||||
authority_list, make_default_justification, make_justification_for_header,
|
||||
JustificationGeneratorParams, ALICE, BOB,
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_support::weights::PostDispatchInfo;
|
||||
use frame_support::{assert_err, assert_noop, assert_ok};
|
||||
use frame_support::{assert_err, assert_noop, assert_ok, weights::PostDispatchInfo};
|
||||
use sp_runtime::{Digest, DigestItem, DispatchError};
|
||||
|
||||
fn initialize_substrate_bridge() {
|
||||
@@ -624,7 +637,10 @@ mod tests {
|
||||
|
||||
fn init_with_origin(
|
||||
origin: Origin,
|
||||
) -> Result<InitializationData<TestHeader>, sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>> {
|
||||
) -> Result<
|
||||
InitializationData<TestHeader>,
|
||||
sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>,
|
||||
> {
|
||||
let genesis = test_header(0);
|
||||
|
||||
let init_data = InitializationData {
|
||||
@@ -641,7 +657,11 @@ mod tests {
|
||||
let header = test_header(header.into());
|
||||
let justification = make_default_justification(&header);
|
||||
|
||||
Pallet::<TestRuntime>::submit_finality_proof(Origin::signed(1), Box::new(header), justification)
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
Origin::signed(1),
|
||||
Box::new(header),
|
||||
justification,
|
||||
)
|
||||
}
|
||||
|
||||
fn next_block() {
|
||||
@@ -653,10 +673,11 @@ mod tests {
|
||||
}
|
||||
|
||||
fn change_log(delay: u64) -> Digest<TestHash> {
|
||||
let consensus_log = ConsensusLog::<TestNumber>::ScheduledChange(sp_finality_grandpa::ScheduledChange {
|
||||
next_authorities: vec![(ALICE.into(), 1), (BOB.into(), 1)],
|
||||
delay,
|
||||
});
|
||||
let consensus_log =
|
||||
ConsensusLog::<TestNumber>::ScheduledChange(sp_finality_grandpa::ScheduledChange {
|
||||
next_authorities: vec![(ALICE.into(), 1), (BOB.into(), 1)],
|
||||
delay,
|
||||
});
|
||||
|
||||
Digest::<TestHash> {
|
||||
logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())],
|
||||
@@ -821,14 +842,16 @@ mod tests {
|
||||
|
||||
let header = test_header(1);
|
||||
|
||||
let params = JustificationGeneratorParams::<TestHeader> {
|
||||
set_id: 2,
|
||||
..Default::default()
|
||||
};
|
||||
let params =
|
||||
JustificationGeneratorParams::<TestHeader> { set_id: 2, ..Default::default() };
|
||||
let justification = make_justification_for_header(params);
|
||||
|
||||
assert_err!(
|
||||
Pallet::<TestRuntime>::submit_finality_proof(Origin::signed(1), Box::new(header), justification,),
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
Origin::signed(1),
|
||||
Box::new(header),
|
||||
justification,
|
||||
),
|
||||
<Error<TestRuntime>>::InvalidJustification
|
||||
);
|
||||
})
|
||||
@@ -844,7 +867,11 @@ mod tests {
|
||||
justification.round = 42;
|
||||
|
||||
assert_err!(
|
||||
Pallet::<TestRuntime>::submit_finality_proof(Origin::signed(1), Box::new(header), justification,),
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
Origin::signed(1),
|
||||
Box::new(header),
|
||||
justification,
|
||||
),
|
||||
<Error<TestRuntime>>::InvalidJustification
|
||||
);
|
||||
})
|
||||
@@ -869,7 +896,11 @@ mod tests {
|
||||
let justification = make_default_justification(&header);
|
||||
|
||||
assert_err!(
|
||||
Pallet::<TestRuntime>::submit_finality_proof(Origin::signed(1), Box::new(header), justification,),
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
Origin::signed(1),
|
||||
Box::new(header),
|
||||
justification,
|
||||
),
|
||||
<Error<TestRuntime>>::InvalidAuthoritySet
|
||||
);
|
||||
})
|
||||
@@ -942,7 +973,11 @@ mod tests {
|
||||
|
||||
// Should not be allowed to import this header
|
||||
assert_err!(
|
||||
Pallet::<TestRuntime>::submit_finality_proof(Origin::signed(1), Box::new(header), justification),
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
Origin::signed(1),
|
||||
Box::new(header),
|
||||
justification
|
||||
),
|
||||
<Error<TestRuntime>>::UnsupportedScheduledChange
|
||||
);
|
||||
})
|
||||
@@ -963,7 +998,11 @@ mod tests {
|
||||
|
||||
// Should not be allowed to import this header
|
||||
assert_err!(
|
||||
Pallet::<TestRuntime>::submit_finality_proof(Origin::signed(1), Box::new(header), justification),
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
Origin::signed(1),
|
||||
Box::new(header),
|
||||
justification
|
||||
),
|
||||
<Error<TestRuntime>>::UnsupportedScheduledChange
|
||||
);
|
||||
})
|
||||
@@ -1021,7 +1060,11 @@ mod tests {
|
||||
let mut invalid_justification = make_default_justification(&header);
|
||||
invalid_justification.round = 42;
|
||||
|
||||
Pallet::<TestRuntime>::submit_finality_proof(Origin::signed(1), Box::new(header), invalid_justification)
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
Origin::signed(1),
|
||||
Box::new(header),
|
||||
invalid_justification,
|
||||
)
|
||||
};
|
||||
|
||||
initialize_substrate_bridge();
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
//! Messages pallet benchmarking.
|
||||
|
||||
use crate::weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH;
|
||||
use crate::{
|
||||
inbound_lane::InboundLaneStorage, inbound_lane_storage, outbound_lane, outbound_lane::ReceivalConfirmationResult,
|
||||
Call,
|
||||
inbound_lane::InboundLaneStorage, inbound_lane_storage, outbound_lane,
|
||||
outbound_lane::ReceivalConfirmationResult, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, Call,
|
||||
};
|
||||
|
||||
use bp_messages::{
|
||||
source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, DeliveredMessages, InboundLaneData, LaneId,
|
||||
MessageData, MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState,
|
||||
source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, DeliveredMessages,
|
||||
InboundLaneData, LaneId, MessageData, MessageNonce, OutboundLaneData, UnrewardedRelayer,
|
||||
UnrewardedRelayersState,
|
||||
};
|
||||
use bp_runtime::messages::DispatchFeePayment;
|
||||
use frame_benchmarking::{account, benchmarks_instance_pallet};
|
||||
@@ -50,11 +50,11 @@ pub enum ProofSize {
|
||||
/// The proof is expected to be minimal. If value size may be changed, then it is expected to
|
||||
/// have given size.
|
||||
Minimal(u32),
|
||||
/// The proof is expected to have at least given size and grow by increasing number of trie nodes
|
||||
/// included in the proof.
|
||||
/// The proof is expected to have at least given size and grow by increasing number of trie
|
||||
/// nodes included in the proof.
|
||||
HasExtraNodes(u32),
|
||||
/// The proof is expected to have at least given size and grow by increasing value that is stored
|
||||
/// in the trie.
|
||||
/// The proof is expected to have at least given size and grow by increasing value that is
|
||||
/// stored in the trie.
|
||||
HasLargeLeaf(u32),
|
||||
}
|
||||
|
||||
@@ -900,18 +900,12 @@ benchmarks_instance_pallet! {
|
||||
|
||||
fn send_regular_message<T: Config<I>, I: 'static>() {
|
||||
let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
|
||||
outbound_lane.send_message(MessageData {
|
||||
payload: vec![],
|
||||
fee: MESSAGE_FEE.into(),
|
||||
});
|
||||
outbound_lane.send_message(MessageData { payload: vec![], fee: MESSAGE_FEE.into() });
|
||||
}
|
||||
|
||||
fn send_regular_message_with_payload<T: Config<I>, I: 'static>(payload: Vec<u8>) {
|
||||
let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
|
||||
outbound_lane.send_message(MessageData {
|
||||
payload,
|
||||
fee: MESSAGE_FEE.into(),
|
||||
});
|
||||
outbound_lane.send_message(MessageData { payload, fee: MESSAGE_FEE.into() });
|
||||
}
|
||||
|
||||
fn confirm_message_delivery<T: Config<I>, I: 'static>(nonce: MessageNonce) {
|
||||
@@ -943,7 +937,10 @@ fn receive_messages<T: Config<I>, I: 'static>(nonce: MessageNonce) {
|
||||
});
|
||||
}
|
||||
|
||||
fn ensure_relayer_rewarded<T: Config<I>, I: 'static>(relayer_id: &T::AccountId, old_balance: &T::OutboundMessageFee) {
|
||||
fn ensure_relayer_rewarded<T: Config<I>, I: 'static>(
|
||||
relayer_id: &T::AccountId,
|
||||
old_balance: &T::OutboundMessageFee,
|
||||
) {
|
||||
let new_balance = T::account_balance(relayer_id);
|
||||
assert!(
|
||||
new_balance > *old_balance,
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
use bp_messages::{
|
||||
target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
|
||||
DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, OutboundLaneData, UnrewardedRelayer,
|
||||
DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, OutboundLaneData,
|
||||
UnrewardedRelayer,
|
||||
};
|
||||
use bp_runtime::messages::MessageDispatchResult;
|
||||
use frame_support::RuntimeDebug;
|
||||
@@ -71,16 +72,19 @@ impl<S: InboundLaneStorage> InboundLane<S> {
|
||||
}
|
||||
|
||||
/// Receive state of the corresponding outbound lane.
|
||||
pub fn receive_state_update(&mut self, outbound_lane_data: OutboundLaneData) -> Option<MessageNonce> {
|
||||
pub fn receive_state_update(
|
||||
&mut self,
|
||||
outbound_lane_data: OutboundLaneData,
|
||||
) -> Option<MessageNonce> {
|
||||
let mut data = self.storage.data();
|
||||
let last_delivered_nonce = data.last_delivered_nonce();
|
||||
|
||||
if outbound_lane_data.latest_received_nonce > last_delivered_nonce {
|
||||
// this is something that should never happen if proofs are correct
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
if outbound_lane_data.latest_received_nonce <= data.last_confirmed_nonce {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
let new_confirmed_nonce = outbound_lane_data.latest_received_nonce;
|
||||
@@ -95,7 +99,8 @@ impl<S: InboundLaneStorage> InboundLane<S> {
|
||||
data.relayers.pop_front();
|
||||
}
|
||||
// Secondly, update the next record with lower nonce equal to new confirmed nonce if needed.
|
||||
// Note: There will be max. 1 record to update as we don't allow messages from relayers to overlap.
|
||||
// Note: There will be max. 1 record to update as we don't allow messages from relayers to
|
||||
// overlap.
|
||||
match data.relayers.front_mut() {
|
||||
Some(entry) if entry.messages.begin < new_confirmed_nonce => {
|
||||
entry.messages.dispatch_results = entry
|
||||
@@ -103,8 +108,8 @@ impl<S: InboundLaneStorage> InboundLane<S> {
|
||||
.dispatch_results
|
||||
.split_off((new_confirmed_nonce + 1 - entry.messages.begin) as _);
|
||||
entry.messages.begin = new_confirmed_nonce + 1;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
self.storage.set_data(data);
|
||||
@@ -122,28 +127,25 @@ impl<S: InboundLaneStorage> InboundLane<S> {
|
||||
let mut data = self.storage.data();
|
||||
let is_correct_message = nonce == data.last_delivered_nonce() + 1;
|
||||
if !is_correct_message {
|
||||
return ReceivalResult::InvalidNonce;
|
||||
return ReceivalResult::InvalidNonce
|
||||
}
|
||||
|
||||
// if there are more unrewarded relayer entries than we may accept, reject this message
|
||||
if data.relayers.len() as MessageNonce >= self.storage.max_unrewarded_relayer_entries() {
|
||||
return ReceivalResult::TooManyUnrewardedRelayers;
|
||||
return ReceivalResult::TooManyUnrewardedRelayers
|
||||
}
|
||||
|
||||
// if there are more unconfirmed messages than we may accept, reject this message
|
||||
let unconfirmed_messages_count = nonce.saturating_sub(data.last_confirmed_nonce);
|
||||
if unconfirmed_messages_count > self.storage.max_unconfirmed_messages() {
|
||||
return ReceivalResult::TooManyUnconfirmedMessages;
|
||||
return ReceivalResult::TooManyUnconfirmedMessages
|
||||
}
|
||||
|
||||
// then, dispatch message
|
||||
let dispatch_result = P::dispatch(
|
||||
relayer_at_this_chain,
|
||||
DispatchMessage {
|
||||
key: MessageKey {
|
||||
lane_id: self.storage.id(),
|
||||
nonce,
|
||||
},
|
||||
key: MessageKey { lane_id: self.storage.id(), nonce },
|
||||
data: message_data,
|
||||
},
|
||||
);
|
||||
@@ -153,7 +155,7 @@ impl<S: InboundLaneStorage> InboundLane<S> {
|
||||
Some(entry) if entry.relayer == *relayer_at_bridged_chain => {
|
||||
entry.messages.note_dispatched_message(dispatch_result.dispatch_result);
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => true,
|
||||
};
|
||||
if push_new {
|
||||
@@ -174,8 +176,9 @@ mod tests {
|
||||
use crate::{
|
||||
inbound_lane,
|
||||
mock::{
|
||||
dispatch_result, message_data, run_test, unrewarded_relayer, TestMessageDispatch, TestRuntime,
|
||||
REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, TEST_RELAYER_C,
|
||||
dispatch_result, message_data, run_test, unrewarded_relayer, TestMessageDispatch,
|
||||
TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B,
|
||||
TEST_RELAYER_C,
|
||||
},
|
||||
RuntimeInboundLaneStorage,
|
||||
};
|
||||
@@ -284,16 +287,10 @@ mod tests {
|
||||
let mut seed_storage_data = lane.storage.data();
|
||||
// Prepare data
|
||||
seed_storage_data.last_confirmed_nonce = 0;
|
||||
seed_storage_data
|
||||
.relayers
|
||||
.push_back(unrewarded_relayer(1, 1, TEST_RELAYER_A));
|
||||
seed_storage_data.relayers.push_back(unrewarded_relayer(1, 1, TEST_RELAYER_A));
|
||||
// Simulate messages batch (2, 3, 4) from relayer #2
|
||||
seed_storage_data
|
||||
.relayers
|
||||
.push_back(unrewarded_relayer(2, 4, TEST_RELAYER_B));
|
||||
seed_storage_data
|
||||
.relayers
|
||||
.push_back(unrewarded_relayer(5, 5, TEST_RELAYER_C));
|
||||
seed_storage_data.relayers.push_back(unrewarded_relayer(2, 4, TEST_RELAYER_B));
|
||||
seed_storage_data.relayers.push_back(unrewarded_relayer(5, 5, TEST_RELAYER_C));
|
||||
lane.storage.set_data(seed_storage_data);
|
||||
// Check
|
||||
assert_eq!(
|
||||
@@ -335,7 +332,8 @@ mod tests {
|
||||
fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() {
|
||||
run_test(|| {
|
||||
let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID);
|
||||
let max_nonce = <TestRuntime as crate::Config>::MaxUnrewardedRelayerEntriesAtInboundLane::get();
|
||||
let max_nonce =
|
||||
<TestRuntime as crate::Config>::MaxUnrewardedRelayerEntriesAtInboundLane::get();
|
||||
for current_nonce in 1..max_nonce + 1 {
|
||||
assert_eq!(
|
||||
lane.receive_message::<TestMessageDispatch, _>(
|
||||
@@ -374,7 +372,8 @@ mod tests {
|
||||
fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() {
|
||||
run_test(|| {
|
||||
let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID);
|
||||
let max_nonce = <TestRuntime as crate::Config>::MaxUnconfirmedMessagesAtInboundLane::get();
|
||||
let max_nonce =
|
||||
<TestRuntime as crate::Config>::MaxUnconfirmedMessagesAtInboundLane::get();
|
||||
for current_nonce in 1..=max_nonce {
|
||||
assert_eq!(
|
||||
lane.receive_message::<TestMessageDispatch, _>(
|
||||
|
||||
@@ -46,7 +46,8 @@ pub struct InstantCurrencyPayments<T, Currency, GetConfirmationFee, RootAccount>
|
||||
_phantom: sp_std::marker::PhantomData<(T, Currency, GetConfirmationFee, RootAccount)>,
|
||||
}
|
||||
|
||||
impl<T, Currency, GetConfirmationFee, RootAccount> MessageDeliveryAndDispatchPayment<T::AccountId, Currency::Balance>
|
||||
impl<T, Currency, GetConfirmationFee, RootAccount>
|
||||
MessageDeliveryAndDispatchPayment<T::AccountId, Currency::Balance>
|
||||
for InstantCurrencyPayments<T, Currency, GetConfirmationFee, RootAccount>
|
||||
where
|
||||
T: frame_system::Config,
|
||||
@@ -118,26 +119,31 @@ fn pay_relayers_rewards<Currency, AccountId>(
|
||||
// If delivery confirmation is submitted by other relayer, let's deduct confirmation fee
|
||||
// from relayer reward.
|
||||
//
|
||||
// If confirmation fee has been increased (or if it was the only component of message fee),
|
||||
// then messages relayer may receive zero reward.
|
||||
// If confirmation fee has been increased (or if it was the only component of message
|
||||
// fee), then messages relayer may receive zero reward.
|
||||
let mut confirmation_reward = confirmation_fee.saturating_mul(reward.messages.into());
|
||||
if confirmation_reward > relayer_reward {
|
||||
confirmation_reward = relayer_reward;
|
||||
}
|
||||
relayer_reward = relayer_reward.saturating_sub(confirmation_reward);
|
||||
confirmation_relayer_reward = confirmation_relayer_reward.saturating_add(confirmation_reward);
|
||||
confirmation_relayer_reward =
|
||||
confirmation_relayer_reward.saturating_add(confirmation_reward);
|
||||
} else {
|
||||
// If delivery confirmation is submitted by this relayer, let's add confirmation fee
|
||||
// from other relayers to this relayer reward.
|
||||
confirmation_relayer_reward = confirmation_relayer_reward.saturating_add(reward.reward);
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
pay_relayer_reward::<Currency, _>(relayer_fund_account, &relayer, relayer_reward);
|
||||
}
|
||||
|
||||
// finally - pay reward to confirmation relayer
|
||||
pay_relayer_reward::<Currency, _>(relayer_fund_account, confirmation_relayer, confirmation_relayer_reward);
|
||||
pay_relayer_reward::<Currency, _>(
|
||||
relayer_fund_account,
|
||||
confirmation_relayer,
|
||||
confirmation_relayer_reward,
|
||||
);
|
||||
}
|
||||
|
||||
/// Transfer funds from relayers fund account to given relayer.
|
||||
@@ -150,7 +156,7 @@ fn pay_relayer_reward<Currency, AccountId>(
|
||||
Currency: CurrencyT<AccountId>,
|
||||
{
|
||||
if reward.is_zero() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let pay_result = Currency::transfer(
|
||||
@@ -193,20 +199,8 @@ mod tests {
|
||||
|
||||
fn relayers_rewards() -> RelayersRewards<TestAccountId, TestBalance> {
|
||||
vec![
|
||||
(
|
||||
RELAYER_1,
|
||||
RelayerRewards {
|
||||
reward: 100,
|
||||
messages: 2,
|
||||
},
|
||||
),
|
||||
(
|
||||
RELAYER_2,
|
||||
RelayerRewards {
|
||||
reward: 100,
|
||||
messages: 3,
|
||||
},
|
||||
),
|
||||
(RELAYER_1, RelayerRewards { reward: 100, messages: 2 }),
|
||||
(RELAYER_2, RelayerRewards { reward: 100, messages: 3 }),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
@@ -215,7 +209,12 @@ mod tests {
|
||||
#[test]
|
||||
fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() {
|
||||
run_test(|| {
|
||||
pay_relayers_rewards::<Balances, _>(&RELAYER_2, relayers_rewards(), &RELAYERS_FUND_ACCOUNT, 10);
|
||||
pay_relayers_rewards::<Balances, _>(
|
||||
&RELAYER_2,
|
||||
relayers_rewards(),
|
||||
&RELAYERS_FUND_ACCOUNT,
|
||||
10,
|
||||
);
|
||||
|
||||
assert_eq!(Balances::free_balance(&RELAYER_1), 80);
|
||||
assert_eq!(Balances::free_balance(&RELAYER_2), 120);
|
||||
@@ -225,7 +224,12 @@ mod tests {
|
||||
#[test]
|
||||
fn confirmation_relayer_is_rewarded_if_it_has_not_delivered_any_delivered_messages() {
|
||||
run_test(|| {
|
||||
pay_relayers_rewards::<Balances, _>(&RELAYER_3, relayers_rewards(), &RELAYERS_FUND_ACCOUNT, 10);
|
||||
pay_relayers_rewards::<Balances, _>(
|
||||
&RELAYER_3,
|
||||
relayers_rewards(),
|
||||
&RELAYERS_FUND_ACCOUNT,
|
||||
10,
|
||||
);
|
||||
|
||||
assert_eq!(Balances::free_balance(&RELAYER_1), 80);
|
||||
assert_eq!(Balances::free_balance(&RELAYER_2), 70);
|
||||
@@ -236,7 +240,12 @@ mod tests {
|
||||
#[test]
|
||||
fn only_confirmation_relayer_is_rewarded_if_confirmation_fee_has_significantly_increased() {
|
||||
run_test(|| {
|
||||
pay_relayers_rewards::<Balances, _>(&RELAYER_3, relayers_rewards(), &RELAYERS_FUND_ACCOUNT, 1000);
|
||||
pay_relayers_rewards::<Balances, _>(
|
||||
&RELAYER_3,
|
||||
relayers_rewards(),
|
||||
&RELAYERS_FUND_ACCOUNT,
|
||||
1000,
|
||||
);
|
||||
|
||||
assert_eq!(Balances::free_balance(&RELAYER_1), 0);
|
||||
assert_eq!(Balances::free_balance(&RELAYER_2), 0);
|
||||
|
||||
+337
-258
File diff suppressed because it is too large
Load Diff
@@ -22,12 +22,14 @@ use crate::Config;
|
||||
use bitvec::prelude::*;
|
||||
use bp_messages::{
|
||||
source_chain::{
|
||||
LaneMessageVerifier, MessageDeliveryAndDispatchPayment, OnDeliveryConfirmed, OnMessageAccepted,
|
||||
RelayersRewards, Sender, TargetHeaderChain,
|
||||
LaneMessageVerifier, MessageDeliveryAndDispatchPayment, OnDeliveryConfirmed,
|
||||
OnMessageAccepted, RelayersRewards, Sender, TargetHeaderChain,
|
||||
},
|
||||
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain},
|
||||
DeliveredMessages, InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
||||
Parameter as MessagesParameter, UnrewardedRelayer,
|
||||
target_chain::{
|
||||
DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
|
||||
},
|
||||
DeliveredMessages, InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce,
|
||||
OutboundLaneData, Parameter as MessagesParameter, UnrewardedRelayer,
|
||||
};
|
||||
use bp_runtime::{messages::MessageDispatchResult, Size};
|
||||
use codec::{Decode, Encode};
|
||||
@@ -53,8 +55,8 @@ pub struct TestPayload {
|
||||
pub declared_weight: Weight,
|
||||
/// Message dispatch result.
|
||||
///
|
||||
/// Note: in correct code `dispatch_result.unspent_weight` will always be <= `declared_weight`, but for test
|
||||
/// purposes we'll be making it larger than `declared_weight` sometimes.
|
||||
/// Note: in correct code `dispatch_result.unspent_weight` will always be <= `declared_weight`,
|
||||
/// but for test purposes we'll be making it larger than `declared_weight` sometimes.
|
||||
pub dispatch_result: MessageDispatchResult,
|
||||
/// Extra bytes that affect payload size.
|
||||
pub extra: Vec<u8>,
|
||||
@@ -153,7 +155,8 @@ pub enum TestMessagesParameter {
|
||||
impl MessagesParameter for TestMessagesParameter {
|
||||
fn save(&self) {
|
||||
match *self {
|
||||
TestMessagesParameter::TokenConversionRate(conversion_rate) => TokenConversionRate::set(&conversion_rate),
|
||||
TestMessagesParameter::TokenConversionRate(conversion_rate) =>
|
||||
TokenConversionRate::set(&conversion_rate),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,14 +238,12 @@ impl From<Result<Vec<Message<TestMessageFee>>, ()>> for TestMessagesProof {
|
||||
fn from(result: Result<Vec<Message<TestMessageFee>>, ()>) -> Self {
|
||||
Self {
|
||||
result: result.map(|messages| {
|
||||
let mut messages_by_lane: BTreeMap<LaneId, ProvedLaneMessages<Message<TestMessageFee>>> =
|
||||
BTreeMap::new();
|
||||
let mut messages_by_lane: BTreeMap<
|
||||
LaneId,
|
||||
ProvedLaneMessages<Message<TestMessageFee>>,
|
||||
> = BTreeMap::new();
|
||||
for message in messages {
|
||||
messages_by_lane
|
||||
.entry(message.key.lane_id)
|
||||
.or_default()
|
||||
.messages
|
||||
.push(message);
|
||||
messages_by_lane.entry(message.key.lane_id).or_default().messages.push(message);
|
||||
}
|
||||
messages_by_lane.into_iter().collect()
|
||||
}),
|
||||
@@ -318,7 +319,8 @@ impl TestMessageDeliveryAndDispatchPayment {
|
||||
|
||||
/// Returns true if given fee has been paid by given submitter.
|
||||
pub fn is_fee_paid(submitter: AccountId, fee: TestMessageFee) -> bool {
|
||||
frame_support::storage::unhashed::get(b":message-fee:") == Some((Sender::Signed(submitter), fee))
|
||||
frame_support::storage::unhashed::get(b":message-fee:") ==
|
||||
Some((Sender::Signed(submitter), fee))
|
||||
}
|
||||
|
||||
/// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is
|
||||
@@ -329,7 +331,9 @@ impl TestMessageDeliveryAndDispatchPayment {
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee> for TestMessageDeliveryAndDispatchPayment {
|
||||
impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee>
|
||||
for TestMessageDeliveryAndDispatchPayment
|
||||
{
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
@@ -338,7 +342,7 @@ impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee> for TestMessag
|
||||
_relayer_fund_account: &AccountId,
|
||||
) -> Result<(), Self::Error> {
|
||||
if frame_support::storage::unhashed::get(b":reject-message-fee:") == Some(true) {
|
||||
return Err(TEST_ERROR);
|
||||
return Err(TEST_ERROR)
|
||||
}
|
||||
|
||||
frame_support::storage::unhashed::put(b":message-fee:", &(submitter, fee));
|
||||
@@ -382,7 +386,8 @@ impl OnMessageAccepted for TestOnMessageAccepted {
|
||||
fn on_messages_accepted(lane: &LaneId, message: &MessageNonce) -> Weight {
|
||||
let key = (b"TestOnMessageAccepted", lane, message).encode();
|
||||
frame_support::storage::unhashed::put(&key, &true);
|
||||
Self::get_consumed_weight_per_message().unwrap_or_else(|| DbWeight::get().reads_writes(1, 1))
|
||||
Self::get_consumed_weight_per_message()
|
||||
.unwrap_or_else(|| DbWeight::get().reads_writes(1, 1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,10 +456,7 @@ impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
|
||||
proof: Self::MessagesProof,
|
||||
_messages_count: u32,
|
||||
) -> Result<ProvedMessages<Message<TestMessageFee>>, Self::Error> {
|
||||
proof
|
||||
.result
|
||||
.map(|proof| proof.into_iter().collect())
|
||||
.map_err(|_| TEST_ERROR)
|
||||
proof.result.map(|proof| proof.into_iter().collect()).map_err(|_| TEST_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,31 +487,17 @@ impl MessageDispatch<AccountId, TestMessageFee> for TestMessageDispatch {
|
||||
|
||||
/// Return test lane message with given nonce and payload.
|
||||
pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message<TestMessageFee> {
|
||||
Message {
|
||||
key: MessageKey {
|
||||
lane_id: TEST_LANE_ID,
|
||||
nonce,
|
||||
},
|
||||
data: message_data(payload),
|
||||
}
|
||||
Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, data: message_data(payload) }
|
||||
}
|
||||
|
||||
/// Constructs message payload using given arguments and zero unspent weight.
|
||||
pub const fn message_payload(id: u64, declared_weight: Weight) -> TestPayload {
|
||||
TestPayload {
|
||||
id,
|
||||
declared_weight,
|
||||
dispatch_result: dispatch_result(0),
|
||||
extra: Vec::new(),
|
||||
}
|
||||
TestPayload { id, declared_weight, dispatch_result: dispatch_result(0), extra: Vec::new() }
|
||||
}
|
||||
|
||||
/// Return message data with valid fee for given payload.
|
||||
pub fn message_data(payload: TestPayload) -> MessageData<TestMessageFee> {
|
||||
MessageData {
|
||||
payload: payload.encode(),
|
||||
fee: 1,
|
||||
}
|
||||
MessageData { payload: payload.encode(), fee: 1 }
|
||||
}
|
||||
|
||||
/// Returns message dispatch result with given unspent weight.
|
||||
@@ -543,14 +531,10 @@ pub fn unrewarded_relayer(
|
||||
|
||||
/// Run pallet test.
|
||||
pub fn run_test<T>(test: impl FnOnce() -> T) -> T {
|
||||
let mut t = frame_system::GenesisConfig::default()
|
||||
.build_storage::<TestRuntime>()
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<TestRuntime>().unwrap();
|
||||
pallet_balances::GenesisConfig::<TestRuntime> { balances: vec![(ENDOWED_ACCOUNT, 1_000_000)] }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
pallet_balances::GenesisConfig::<TestRuntime> {
|
||||
balances: vec![(ENDOWED_ACCOUNT, 1_000_000)],
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
let mut ext = sp_io::TestExternalities::new(t);
|
||||
ext.execute_with(test)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
use bitvec::prelude::*;
|
||||
use bp_messages::{
|
||||
DeliveredMessages, DispatchResultsBitVec, LaneId, MessageData, MessageNonce, OutboundLaneData, UnrewardedRelayer,
|
||||
DeliveredMessages, DispatchResultsBitVec, LaneId, MessageData, MessageNonce, OutboundLaneData,
|
||||
UnrewardedRelayer,
|
||||
};
|
||||
use frame_support::RuntimeDebug;
|
||||
use sp_std::collections::vec_deque::VecDeque;
|
||||
@@ -57,11 +58,11 @@ pub enum ReceivalConfirmationResult {
|
||||
/// The unrewarded relayers vec contains an empty entry. May be a result of invalid bridged
|
||||
/// chain storage.
|
||||
EmptyUnrewardedRelayerEntry,
|
||||
/// The unrewarded relayers vec contains non-consecutive entries. May be a result of invalid bridged
|
||||
/// chain storage.
|
||||
/// The unrewarded relayers vec contains non-consecutive entries. May be a result of invalid
|
||||
/// bridged chain storage.
|
||||
NonConsecutiveUnrewardedRelayerEntries,
|
||||
/// The unrewarded relayers vec contains entry with mismatched number of dispatch results. May be
|
||||
/// a result of invalid bridged chain storage.
|
||||
/// The unrewarded relayers vec contains entry with mismatched number of dispatch results. May
|
||||
/// be a result of invalid bridged chain storage.
|
||||
InvalidNumberOfDispatchResults,
|
||||
/// The chain has more messages that need to be confirmed than there is in the proof.
|
||||
TryingToConfirmMoreMessagesThanExpected(MessageNonce),
|
||||
@@ -106,27 +107,30 @@ impl<S: OutboundLaneStorage> OutboundLane<S> {
|
||||
) -> ReceivalConfirmationResult {
|
||||
let mut data = self.storage.data();
|
||||
if latest_delivered_nonce <= data.latest_received_nonce {
|
||||
return ReceivalConfirmationResult::NoNewConfirmations;
|
||||
return ReceivalConfirmationResult::NoNewConfirmations
|
||||
}
|
||||
if latest_delivered_nonce > data.latest_generated_nonce {
|
||||
return ReceivalConfirmationResult::FailedToConfirmFutureMessages;
|
||||
return ReceivalConfirmationResult::FailedToConfirmFutureMessages
|
||||
}
|
||||
if latest_delivered_nonce - data.latest_received_nonce > max_allowed_messages {
|
||||
// that the relayer has declared correct number of messages that the proof contains (it is
|
||||
// checked outside of the function). But it may happen (but only if this/bridged chain storage is
|
||||
// corrupted, though) that the actual number of confirmed messages if larger than declared.
|
||||
// This would mean that 'reward loop' will take more time than the weight formula accounts,
|
||||
// so we can't allow that.
|
||||
// that the relayer has declared correct number of messages that the proof contains (it
|
||||
// is checked outside of the function). But it may happen (but only if this/bridged
|
||||
// chain storage is corrupted, though) that the actual number of confirmed messages if
|
||||
// larger than declared. This would mean that 'reward loop' will take more time than the
|
||||
// weight formula accounts, so we can't allow that.
|
||||
return ReceivalConfirmationResult::TryingToConfirmMoreMessagesThanExpected(
|
||||
latest_delivered_nonce - data.latest_received_nonce,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
let dispatch_results =
|
||||
match extract_dispatch_results(data.latest_received_nonce, latest_delivered_nonce, relayers) {
|
||||
Ok(dispatch_results) => dispatch_results,
|
||||
Err(extract_error) => return extract_error,
|
||||
};
|
||||
let dispatch_results = match extract_dispatch_results(
|
||||
data.latest_received_nonce,
|
||||
latest_delivered_nonce,
|
||||
relayers,
|
||||
) {
|
||||
Ok(dispatch_results) => dispatch_results,
|
||||
Err(extract_error) => return extract_error,
|
||||
};
|
||||
|
||||
let prev_latest_received_nonce = data.latest_received_nonce;
|
||||
data.latest_received_nonce = latest_delivered_nonce;
|
||||
@@ -146,7 +150,9 @@ impl<S: OutboundLaneStorage> OutboundLane<S> {
|
||||
let mut pruned_messages = 0;
|
||||
let mut anything_changed = false;
|
||||
let mut data = self.storage.data();
|
||||
while pruned_messages < max_messages_to_prune && data.oldest_unpruned_nonce <= data.latest_received_nonce {
|
||||
while pruned_messages < max_messages_to_prune &&
|
||||
data.oldest_unpruned_nonce <= data.latest_received_nonce
|
||||
{
|
||||
self.storage.remove_message(&data.oldest_unpruned_nonce);
|
||||
|
||||
anything_changed = true;
|
||||
@@ -171,9 +177,10 @@ fn extract_dispatch_results<RelayerId>(
|
||||
latest_received_nonce: MessageNonce,
|
||||
relayers: &VecDeque<UnrewardedRelayer<RelayerId>>,
|
||||
) -> Result<DispatchResultsBitVec, ReceivalConfirmationResult> {
|
||||
// the only caller of this functions checks that the prev_latest_received_nonce..=latest_received_nonce
|
||||
// is valid, so we're ready to accept messages in this range
|
||||
// => with_capacity call must succeed here or we'll be unable to receive confirmations at all
|
||||
// the only caller of this functions checks that the
|
||||
// prev_latest_received_nonce..=latest_received_nonce is valid, so we're ready to accept
|
||||
// messages in this range => with_capacity call must succeed here or we'll be unable to receive
|
||||
// confirmations at all
|
||||
let mut received_dispatch_result =
|
||||
BitVec::with_capacity((latest_received_nonce - prev_latest_received_nonce + 1) as _);
|
||||
let mut last_entry_end: Option<MessageNonce> = None;
|
||||
@@ -181,43 +188,48 @@ fn extract_dispatch_results<RelayerId>(
|
||||
// unrewarded relayer entry must have at least 1 unconfirmed message
|
||||
// (guaranteed by the `InboundLane::receive_message()`)
|
||||
if entry.messages.end < entry.messages.begin {
|
||||
return Err(ReceivalConfirmationResult::EmptyUnrewardedRelayerEntry);
|
||||
return Err(ReceivalConfirmationResult::EmptyUnrewardedRelayerEntry)
|
||||
}
|
||||
// every entry must confirm range of messages that follows previous entry range
|
||||
// (guaranteed by the `InboundLane::receive_message()`)
|
||||
if let Some(last_entry_end) = last_entry_end {
|
||||
let expected_entry_begin = last_entry_end.checked_add(1);
|
||||
if expected_entry_begin != Some(entry.messages.begin) {
|
||||
return Err(ReceivalConfirmationResult::NonConsecutiveUnrewardedRelayerEntries);
|
||||
return Err(ReceivalConfirmationResult::NonConsecutiveUnrewardedRelayerEntries)
|
||||
}
|
||||
}
|
||||
last_entry_end = Some(entry.messages.end);
|
||||
// entry can't confirm messages larger than `inbound_lane_data.latest_received_nonce()`
|
||||
// (guaranteed by the `InboundLane::receive_message()`)
|
||||
if entry.messages.end > latest_received_nonce {
|
||||
// technically this will be detected in the next loop iteration as `InvalidNumberOfDispatchResults`
|
||||
// but to guarantee safety of loop operations below this is detected now
|
||||
return Err(ReceivalConfirmationResult::FailedToConfirmFutureMessages);
|
||||
// technically this will be detected in the next loop iteration as
|
||||
// `InvalidNumberOfDispatchResults` but to guarantee safety of loop operations below
|
||||
// this is detected now
|
||||
return Err(ReceivalConfirmationResult::FailedToConfirmFutureMessages)
|
||||
}
|
||||
// entry must have single dispatch result for every message
|
||||
// (guaranteed by the `InboundLane::receive_message()`)
|
||||
if entry.messages.dispatch_results.len() as MessageNonce != entry.messages.end - entry.messages.begin + 1 {
|
||||
return Err(ReceivalConfirmationResult::InvalidNumberOfDispatchResults);
|
||||
if entry.messages.dispatch_results.len() as MessageNonce !=
|
||||
entry.messages.end - entry.messages.begin + 1
|
||||
{
|
||||
return Err(ReceivalConfirmationResult::InvalidNumberOfDispatchResults)
|
||||
}
|
||||
|
||||
// now we know that the entry is valid
|
||||
// => let's check if it brings new confirmations
|
||||
let new_messages_begin = sp_std::cmp::max(entry.messages.begin, prev_latest_received_nonce + 1);
|
||||
let new_messages_begin =
|
||||
sp_std::cmp::max(entry.messages.begin, prev_latest_received_nonce + 1);
|
||||
let new_messages_end = sp_std::cmp::min(entry.messages.end, latest_received_nonce);
|
||||
let new_messages_range = new_messages_begin..=new_messages_end;
|
||||
if new_messages_range.is_empty() {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
// now we know that entry brings new confirmations
|
||||
// => let's extract dispatch results
|
||||
received_dispatch_result.extend_from_bitslice(
|
||||
&entry.messages.dispatch_results[(new_messages_begin - entry.messages.begin) as usize..],
|
||||
&entry.messages.dispatch_results
|
||||
[(new_messages_begin - entry.messages.begin) as usize..],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,12 +240,17 @@ fn extract_dispatch_results<RelayerId>(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
mock::{message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID},
|
||||
mock::{
|
||||
message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, REGULAR_PAYLOAD,
|
||||
TEST_LANE_ID,
|
||||
},
|
||||
outbound_lane,
|
||||
};
|
||||
use sp_std::ops::RangeInclusive;
|
||||
|
||||
fn unrewarded_relayers(nonces: RangeInclusive<MessageNonce>) -> VecDeque<UnrewardedRelayer<TestRelayer>> {
|
||||
fn unrewarded_relayers(
|
||||
nonces: RangeInclusive<MessageNonce>,
|
||||
) -> VecDeque<UnrewardedRelayer<TestRelayer>> {
|
||||
vec![unrewarded_relayer(*nonces.start(), *nonces.end(), 0)]
|
||||
.into_iter()
|
||||
.collect()
|
||||
|
||||
@@ -25,8 +25,8 @@ use frame_support::weights::{RuntimeDbWeight, Weight};
|
||||
/// Size of the message being delivered in benchmarks.
|
||||
pub const EXPECTED_DEFAULT_MESSAGE_LENGTH: u32 = 128;
|
||||
|
||||
/// We assume that size of signed extensions on all our chains and size of all 'small' arguments of calls
|
||||
/// we're checking here would fit 1KB.
|
||||
/// We assume that size of signed extensions on all our chains and size of all 'small' arguments of
|
||||
/// calls we're checking here would fit 1KB.
|
||||
const SIGNED_EXTENSIONS_SIZE: u32 = 1024;
|
||||
|
||||
/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at
|
||||
@@ -54,12 +54,15 @@ pub fn ensure_weights_are_correct<W: WeightInfoExt>(
|
||||
|
||||
// verify that the hardcoded value covers `receive_messages_proof` weight
|
||||
let actual_single_regular_message_delivery_tx_weight = W::receive_messages_proof_weight(
|
||||
&PreComputedSize((EXPECTED_DEFAULT_MESSAGE_LENGTH + W::expected_extra_storage_proof_size()) as usize),
|
||||
&PreComputedSize(
|
||||
(EXPECTED_DEFAULT_MESSAGE_LENGTH + W::expected_extra_storage_proof_size()) as usize,
|
||||
),
|
||||
1,
|
||||
0,
|
||||
);
|
||||
assert!(
|
||||
actual_single_regular_message_delivery_tx_weight <= expected_default_message_delivery_tx_weight,
|
||||
actual_single_regular_message_delivery_tx_weight <=
|
||||
expected_default_message_delivery_tx_weight,
|
||||
"Default message delivery transaction weight {} is larger than expected weight {}",
|
||||
actual_single_regular_message_delivery_tx_weight,
|
||||
expected_default_message_delivery_tx_weight,
|
||||
@@ -91,7 +94,8 @@ pub fn ensure_weights_are_correct<W: WeightInfoExt>(
|
||||
db_weight,
|
||||
);
|
||||
assert!(
|
||||
actual_messages_delivery_confirmation_tx_weight <= expected_messages_delivery_confirmation_tx_weight,
|
||||
actual_messages_delivery_confirmation_tx_weight <=
|
||||
expected_messages_delivery_confirmation_tx_weight,
|
||||
"Messages delivery confirmation transaction weight {} is larger than expected weight {}",
|
||||
actual_messages_delivery_confirmation_tx_weight,
|
||||
expected_messages_delivery_confirmation_tx_weight,
|
||||
@@ -115,7 +119,8 @@ pub fn ensure_able_to_receive_message<W: WeightInfoExt>(
|
||||
max_incoming_message_dispatch_weight: Weight,
|
||||
) {
|
||||
// verify that we're able to receive proof of maximal-size message
|
||||
let max_delivery_transaction_size = max_incoming_message_proof_size.saturating_add(SIGNED_EXTENSIONS_SIZE);
|
||||
let max_delivery_transaction_size =
|
||||
max_incoming_message_proof_size.saturating_add(SIGNED_EXTENSIONS_SIZE);
|
||||
assert!(
|
||||
max_delivery_transaction_size <= max_extrinsic_size,
|
||||
"Size of maximal message delivery transaction {} + {} is larger than maximal possible transaction size {}",
|
||||
@@ -126,7 +131,9 @@ pub fn ensure_able_to_receive_message<W: WeightInfoExt>(
|
||||
|
||||
// verify that we're able to receive proof of maximal-size message with maximal dispatch weight
|
||||
let max_delivery_transaction_dispatch_weight = W::receive_messages_proof_weight(
|
||||
&PreComputedSize((max_incoming_message_proof_size + W::expected_extra_storage_proof_size()) as usize),
|
||||
&PreComputedSize(
|
||||
(max_incoming_message_proof_size + W::expected_extra_storage_proof_size()) as usize,
|
||||
),
|
||||
1,
|
||||
max_incoming_message_dispatch_weight,
|
||||
);
|
||||
@@ -158,7 +165,8 @@ pub fn ensure_able_to_receive_confirmation<W: WeightInfoExt>(
|
||||
max_extrinsic_size,
|
||||
);
|
||||
|
||||
// verify that we're able to reward maximal number of relayers that have delivered maximal number of messages
|
||||
// verify that we're able to reward maximal number of relayers that have delivered maximal
|
||||
// number of messages
|
||||
let max_confirmation_transaction_dispatch_weight = W::receive_messages_delivery_proof_weight(
|
||||
&PreComputedSize(max_inbound_lane_data_proof_size_from_peer_chain as usize),
|
||||
&UnrewardedRelayersState {
|
||||
@@ -200,10 +208,15 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
}
|
||||
|
||||
/// Weight of message delivery extrinsic.
|
||||
fn receive_messages_proof_weight(proof: &impl Size, messages_count: u32, dispatch_weight: Weight) -> Weight {
|
||||
fn receive_messages_proof_weight(
|
||||
proof: &impl Size,
|
||||
messages_count: u32,
|
||||
dispatch_weight: Weight,
|
||||
) -> Weight {
|
||||
// basic components of extrinsic weight
|
||||
let transaction_overhead = Self::receive_messages_proof_overhead();
|
||||
let outbound_state_delivery_weight = Self::receive_messages_proof_outbound_lane_state_overhead();
|
||||
let outbound_state_delivery_weight =
|
||||
Self::receive_messages_proof_outbound_lane_state_overhead();
|
||||
let messages_delivery_weight =
|
||||
Self::receive_messages_proof_messages_overhead(MessageNonce::from(messages_count));
|
||||
let messages_dispatch_weight = dispatch_weight;
|
||||
@@ -213,8 +226,9 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
.saturating_mul(messages_count.saturating_sub(1))
|
||||
.saturating_add(Self::expected_extra_storage_proof_size());
|
||||
let actual_proof_size = proof.size_hint();
|
||||
let proof_size_overhead =
|
||||
Self::storage_proof_size_overhead(actual_proof_size.saturating_sub(expected_proof_size));
|
||||
let proof_size_overhead = Self::storage_proof_size_overhead(
|
||||
actual_proof_size.saturating_sub(expected_proof_size),
|
||||
);
|
||||
|
||||
transaction_overhead
|
||||
.saturating_add(outbound_state_delivery_weight)
|
||||
@@ -231,17 +245,21 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
) -> Weight {
|
||||
// basic components of extrinsic weight
|
||||
let transaction_overhead = Self::receive_messages_delivery_proof_overhead();
|
||||
let messages_overhead = Self::receive_messages_delivery_proof_messages_overhead(relayers_state.total_messages);
|
||||
let relayers_overhead =
|
||||
Self::receive_messages_delivery_proof_relayers_overhead(relayers_state.unrewarded_relayer_entries);
|
||||
let messages_overhead =
|
||||
Self::receive_messages_delivery_proof_messages_overhead(relayers_state.total_messages);
|
||||
let relayers_overhead = Self::receive_messages_delivery_proof_relayers_overhead(
|
||||
relayers_state.unrewarded_relayer_entries,
|
||||
);
|
||||
|
||||
// proof size overhead weight
|
||||
let expected_proof_size = Self::expected_extra_storage_proof_size();
|
||||
let actual_proof_size = proof.size_hint();
|
||||
let proof_size_overhead =
|
||||
Self::storage_proof_size_overhead(actual_proof_size.saturating_sub(expected_proof_size));
|
||||
let proof_size_overhead = Self::storage_proof_size_overhead(
|
||||
actual_proof_size.saturating_sub(expected_proof_size),
|
||||
);
|
||||
|
||||
// and cost of calling `OnDeliveryConfirmed::on_messages_delivered()` for every confirmed message
|
||||
// and cost of calling `OnDeliveryConfirmed::on_messages_delivered()` for every confirmed
|
||||
// message
|
||||
let callback_overhead = relayers_state
|
||||
.total_messages
|
||||
.saturating_mul(Self::single_message_callback_overhead(db_weight));
|
||||
@@ -260,22 +278,26 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
Self::send_minimal_message_worst_case()
|
||||
}
|
||||
|
||||
/// Returns weight that needs to be accounted when message of given size is sent (`send_message`).
|
||||
/// Returns weight that needs to be accounted when message of given size is sent
|
||||
/// (`send_message`).
|
||||
fn send_message_size_overhead(message_size: u32) -> Weight {
|
||||
let message_size_in_kb = (1024u64 + message_size as u64) / 1024;
|
||||
let single_kb_weight = (Self::send_16_kb_message_worst_case() - Self::send_1_kb_message_worst_case()) / 15;
|
||||
let single_kb_weight =
|
||||
(Self::send_16_kb_message_worst_case() - Self::send_1_kb_message_worst_case()) / 15;
|
||||
message_size_in_kb * single_kb_weight
|
||||
}
|
||||
|
||||
/// Returns weight overhead of message delivery transaction (`receive_messages_proof`).
|
||||
fn receive_messages_proof_overhead() -> Weight {
|
||||
let weight_of_two_messages_and_two_tx_overheads = Self::receive_single_message_proof().saturating_mul(2);
|
||||
let weight_of_two_messages_and_two_tx_overheads =
|
||||
Self::receive_single_message_proof().saturating_mul(2);
|
||||
let weight_of_two_messages_and_single_tx_overhead = Self::receive_two_messages_proof();
|
||||
weight_of_two_messages_and_two_tx_overheads.saturating_sub(weight_of_two_messages_and_single_tx_overhead)
|
||||
weight_of_two_messages_and_two_tx_overheads
|
||||
.saturating_sub(weight_of_two_messages_and_single_tx_overhead)
|
||||
}
|
||||
|
||||
/// Returns weight that needs to be accounted when receiving given a number of messages with message
|
||||
/// delivery transaction (`receive_messages_proof`).
|
||||
/// Returns weight that needs to be accounted when receiving given a number of messages with
|
||||
/// message delivery transaction (`receive_messages_proof`).
|
||||
fn receive_messages_proof_messages_overhead(messages: MessageNonce) -> Weight {
|
||||
let weight_of_two_messages_and_single_tx_overhead = Self::receive_two_messages_proof();
|
||||
let weight_of_single_message_and_single_tx_overhead = Self::receive_single_message_proof();
|
||||
@@ -284,27 +306,31 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
.saturating_mul(messages as Weight)
|
||||
}
|
||||
|
||||
/// Returns weight that needs to be accounted when message delivery transaction (`receive_messages_proof`)
|
||||
/// is carrying outbound lane state proof.
|
||||
/// Returns weight that needs to be accounted when message delivery transaction
|
||||
/// (`receive_messages_proof`) is carrying outbound lane state proof.
|
||||
fn receive_messages_proof_outbound_lane_state_overhead() -> Weight {
|
||||
let weight_of_single_message_and_lane_state = Self::receive_single_message_proof_with_outbound_lane_state();
|
||||
let weight_of_single_message_and_lane_state =
|
||||
Self::receive_single_message_proof_with_outbound_lane_state();
|
||||
let weight_of_single_message = Self::receive_single_message_proof();
|
||||
weight_of_single_message_and_lane_state.saturating_sub(weight_of_single_message)
|
||||
}
|
||||
|
||||
/// Returns weight overhead of delivery confirmation transaction (`receive_messages_delivery_proof`).
|
||||
/// Returns weight overhead of delivery confirmation transaction
|
||||
/// (`receive_messages_delivery_proof`).
|
||||
fn receive_messages_delivery_proof_overhead() -> Weight {
|
||||
let weight_of_two_messages_and_two_tx_overheads =
|
||||
Self::receive_delivery_proof_for_single_message().saturating_mul(2);
|
||||
let weight_of_two_messages_and_single_tx_overhead =
|
||||
Self::receive_delivery_proof_for_two_messages_by_single_relayer();
|
||||
weight_of_two_messages_and_two_tx_overheads.saturating_sub(weight_of_two_messages_and_single_tx_overhead)
|
||||
weight_of_two_messages_and_two_tx_overheads
|
||||
.saturating_sub(weight_of_two_messages_and_single_tx_overhead)
|
||||
}
|
||||
|
||||
/// Returns weight that needs to be accounted when receiving confirmations for given a number of
|
||||
/// messages with delivery confirmation transaction (`receive_messages_delivery_proof`).
|
||||
fn receive_messages_delivery_proof_messages_overhead(messages: MessageNonce) -> Weight {
|
||||
let weight_of_two_messages = Self::receive_delivery_proof_for_two_messages_by_single_relayer();
|
||||
let weight_of_two_messages =
|
||||
Self::receive_delivery_proof_for_two_messages_by_single_relayer();
|
||||
let weight_of_single_message = Self::receive_delivery_proof_for_single_message();
|
||||
weight_of_two_messages
|
||||
.saturating_sub(weight_of_single_message)
|
||||
@@ -314,7 +340,8 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
/// Returns weight that needs to be accounted when receiving confirmations for given a number of
|
||||
/// relayers entries with delivery confirmation transaction (`receive_messages_delivery_proof`).
|
||||
fn receive_messages_delivery_proof_relayers_overhead(relayers: MessageNonce) -> Weight {
|
||||
let weight_of_two_messages_by_two_relayers = Self::receive_delivery_proof_for_two_messages_by_two_relayers();
|
||||
let weight_of_two_messages_by_two_relayers =
|
||||
Self::receive_delivery_proof_for_two_messages_by_two_relayers();
|
||||
let weight_of_two_messages_by_single_relayer =
|
||||
Self::receive_delivery_proof_for_two_messages_by_single_relayer();
|
||||
weight_of_two_messages_by_two_relayers
|
||||
@@ -322,8 +349,8 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
.saturating_mul(relayers as Weight)
|
||||
}
|
||||
|
||||
/// Returns weight that needs to be accounted when storage proof of given size is received (either in
|
||||
/// `receive_messages_proof` or `receive_messages_delivery_proof`).
|
||||
/// Returns weight that needs to be accounted when storage proof of given size is received
|
||||
/// (either in `receive_messages_proof` or `receive_messages_delivery_proof`).
|
||||
///
|
||||
/// **IMPORTANT**: this overhead is already included in the 'base' transaction cost - e.g. proof
|
||||
/// size depends on messages count or number of entries in the unrewarded relayers set. So this
|
||||
@@ -332,23 +359,26 @@ pub trait WeightInfoExt: WeightInfo {
|
||||
/// is less than that cost).
|
||||
fn storage_proof_size_overhead(proof_size: u32) -> Weight {
|
||||
let proof_size_in_bytes = proof_size as Weight;
|
||||
let byte_weight =
|
||||
(Self::receive_single_message_proof_16_kb() - Self::receive_single_message_proof_1_kb()) / (15 * 1024);
|
||||
let byte_weight = (Self::receive_single_message_proof_16_kb() -
|
||||
Self::receive_single_message_proof_1_kb()) /
|
||||
(15 * 1024);
|
||||
proof_size_in_bytes * byte_weight
|
||||
}
|
||||
|
||||
/// Returns weight of the pay-dispatch-fee operation for inbound messages.
|
||||
///
|
||||
/// This function may return zero if runtime doesn't support pay-dispatch-fee-at-target-chain option.
|
||||
/// This function may return zero if runtime doesn't support pay-dispatch-fee-at-target-chain
|
||||
/// option.
|
||||
fn pay_inbound_dispatch_fee_overhead() -> Weight {
|
||||
Self::receive_single_message_proof().saturating_sub(Self::receive_single_prepaid_message_proof())
|
||||
Self::receive_single_message_proof()
|
||||
.saturating_sub(Self::receive_single_prepaid_message_proof())
|
||||
}
|
||||
|
||||
/// Returns pre-dispatch weight of single callback call.
|
||||
///
|
||||
/// When benchmarking the weight please take into consideration both the `OnMessageAccepted` and
|
||||
/// `OnDeliveryConfirmed` callbacks. The method should return the greater of the two, because it's
|
||||
/// used to estimate the weight in both contexts.
|
||||
/// `OnDeliveryConfirmed` callbacks. The method should return the greater of the two, because
|
||||
/// it's used to estimate the weight in both contexts.
|
||||
fn single_message_callback_overhead(db_weight: RuntimeDbWeight) -> Weight {
|
||||
db_weight.reads_writes(1, 1)
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> {
|
||||
fn new_session(session_index: sp_staking::SessionIndex) -> Option<Vec<T::ValidatorId>> {
|
||||
// we don't want to add even more fields to genesis config => just return None
|
||||
if session_index == 0 || session_index == 1 {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
// the idea that on first call (i.e. when session 1 ends) we're reading current
|
||||
@@ -101,13 +101,17 @@ mod tests {
|
||||
#![allow(clippy::from_over_into)]
|
||||
|
||||
use super::*;
|
||||
use frame_support::sp_io::TestExternalities;
|
||||
use frame_support::sp_runtime::{
|
||||
testing::{Header, UintAuthorityId},
|
||||
traits::{BlakeTwo256, ConvertInto, IdentityLookup},
|
||||
Perbill, RuntimeAppPublic,
|
||||
use frame_support::{
|
||||
parameter_types,
|
||||
sp_io::TestExternalities,
|
||||
sp_runtime::{
|
||||
testing::{Header, UintAuthorityId},
|
||||
traits::{BlakeTwo256, ConvertInto, IdentityLookup},
|
||||
Perbill, RuntimeAppPublic,
|
||||
},
|
||||
weights::Weight,
|
||||
BasicExternalities,
|
||||
};
|
||||
use frame_support::{parameter_types, weights::Weight, BasicExternalities};
|
||||
use sp_core::H256;
|
||||
|
||||
type AccountId = u64;
|
||||
@@ -183,17 +187,21 @@ mod tests {
|
||||
impl pallet_session::SessionHandler<AccountId> for TestSessionHandler {
|
||||
const KEY_TYPE_IDS: &'static [sp_runtime::KeyTypeId] = &[UintAuthorityId::ID];
|
||||
|
||||
fn on_genesis_session<Ks: sp_runtime::traits::OpaqueKeys>(_validators: &[(AccountId, Ks)]) {}
|
||||
fn on_genesis_session<Ks: sp_runtime::traits::OpaqueKeys>(_validators: &[(AccountId, Ks)]) {
|
||||
}
|
||||
|
||||
fn on_new_session<Ks: sp_runtime::traits::OpaqueKeys>(_: bool, _: &[(AccountId, Ks)], _: &[(AccountId, Ks)]) {}
|
||||
fn on_new_session<Ks: sp_runtime::traits::OpaqueKeys>(
|
||||
_: bool,
|
||||
_: &[(AccountId, Ks)],
|
||||
_: &[(AccountId, Ks)],
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_disabled(_: usize) {}
|
||||
}
|
||||
|
||||
fn new_test_ext() -> TestExternalities {
|
||||
let mut t = frame_system::GenesisConfig::default()
|
||||
.build_storage::<TestRuntime>()
|
||||
.unwrap();
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<TestRuntime>().unwrap();
|
||||
|
||||
let keys = vec![
|
||||
(1, 1, UintAuthorityId(1)),
|
||||
|
||||
@@ -22,29 +22,30 @@
|
||||
//!
|
||||
//! There are four accounts participating in the swap:
|
||||
//!
|
||||
//! 1) account of This chain that has signed the `create_swap` transaction and has balance on This chain.
|
||||
//! We'll be referring to this account as `source_account_at_this_chain`;
|
||||
//! 2) account of the Bridged chain that is sending the `claim_swap` message from the Bridged to This chain.
|
||||
//! This account has balance on Bridged chain and is willing to swap these tokens to This chain tokens of
|
||||
//! the `source_account_at_this_chain`. We'll be referring to this account as `target_account_at_bridged_chain`;
|
||||
//! 3) account of the Bridged chain that is indirectly controlled by the `source_account_at_this_chain`. We'll be
|
||||
//! referring this account as `source_account_at_bridged_chain`;
|
||||
//! 4) account of This chain that is indirectly controlled by the `target_account_at_bridged_chain`. We'll be
|
||||
//! referring this account as `target_account_at_this_chain`.
|
||||
//! 1) account of This chain that has signed the `create_swap` transaction and has balance on This
|
||||
//! chain. We'll be referring to this account as `source_account_at_this_chain`;
|
||||
//! 2) account of the Bridged chain that is sending the `claim_swap` message from the Bridged to
|
||||
//! This chain. This account has balance on Bridged chain and is willing to swap these tokens to
|
||||
//! This chain tokens of the `source_account_at_this_chain`. We'll be referring to this account
|
||||
//! as `target_account_at_bridged_chain`; 3) account of the Bridged chain that is indirectly
|
||||
//! controlled by the `source_account_at_this_chain`. We'll be referring this account as
|
||||
//! `source_account_at_bridged_chain`; 4) account of This chain that is indirectly controlled by the
|
||||
//! `target_account_at_bridged_chain`. We'll be referring this account as
|
||||
//! `target_account_at_this_chain`.
|
||||
//!
|
||||
//! So the tokens swap is an intention of `source_account_at_this_chain` to swap his `source_balance_at_this_chain`
|
||||
//! tokens to the `target_balance_at_bridged_chain` tokens owned by `target_account_at_bridged_chain`. The swap
|
||||
//! process goes as follows:
|
||||
//! So the tokens swap is an intention of `source_account_at_this_chain` to swap his
|
||||
//! `source_balance_at_this_chain` tokens to the `target_balance_at_bridged_chain` tokens owned by
|
||||
//! `target_account_at_bridged_chain`. The swap process goes as follows:
|
||||
//!
|
||||
//! 1) the `source_account_at_this_chain` account submits the `create_swap` transaction on This chain;
|
||||
//! 2) the tokens transfer message that would transfer `target_balance_at_bridged_chain` tokens from the
|
||||
//! `target_account_at_bridged_chain` to the `source_account_at_bridged_chain`, is sent over the bridge;
|
||||
//! 3) when transfer message is delivered and dispatched, the pallet receives notification;
|
||||
//! 4) if message has been successfully dispatched, the `target_account_at_bridged_chain` sends the message
|
||||
//! that would transfer `source_balance_at_this_chain` tokens to his `target_account_at_this_chain`
|
||||
//! account;
|
||||
//! 5) if message dispatch has failed, the `source_account_at_this_chain` may submit the `cancel_swap`
|
||||
//! transaction and return his `source_balance_at_this_chain` back to his account.
|
||||
//! 1) the `source_account_at_this_chain` account submits the `create_swap` transaction on This
|
||||
//! chain; 2) the tokens transfer message that would transfer `target_balance_at_bridged_chain`
|
||||
//! tokens from the `target_account_at_bridged_chain` to the `source_account_at_bridged_chain`,
|
||||
//! is sent over the bridge; 3) when transfer message is delivered and dispatched, the pallet
|
||||
//! receives notification; 4) if message has been successfully dispatched, the
|
||||
//! `target_account_at_bridged_chain` sends the message that would transfer
|
||||
//! `source_balance_at_this_chain` tokens to his `target_account_at_this_chain` account;
|
||||
//! 5) if message dispatch has failed, the `source_account_at_this_chain` may submit the
|
||||
//! `cancel_swap` transaction and return his `source_balance_at_this_chain` back to his account.
|
||||
//!
|
||||
//! While swap is pending, the `source_balance_at_this_chain` tokens are owned by the special
|
||||
//! temporary `swap_account_at_this_chain` account. It is destroyed upon swap completion.
|
||||
@@ -118,8 +119,9 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
/// Tokens balance at This chain.
|
||||
pub type ThisChainBalance<T, I> =
|
||||
<<T as Config<I>>::ThisCurrency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
|
||||
pub type ThisChainBalance<T, I> = <<T as Config<I>>::ThisCurrency as Currency<
|
||||
<T as frame_system::Config>::AccountId,
|
||||
>>::Balance;
|
||||
|
||||
/// Type of the Bridged chain.
|
||||
pub type BridgedChainOf<T, I> = <T as Config<I>>::BridgedChain;
|
||||
@@ -164,33 +166,40 @@ pub mod pallet {
|
||||
{
|
||||
/// Start token swap procedure.
|
||||
///
|
||||
/// The dispatch origin for this call must be exactly the `swap.source_account_at_this_chain` account.
|
||||
/// The dispatch origin for this call must be exactly the
|
||||
/// `swap.source_account_at_this_chain` account.
|
||||
///
|
||||
/// Method arguments are:
|
||||
///
|
||||
/// - `swap` - token swap intention;
|
||||
/// - `target_public_at_bridged_chain` - the public key of the `swap.target_account_at_bridged_chain`
|
||||
/// account used to verify `bridged_currency_transfer_signature`;
|
||||
/// - `bridged_currency_transfer` - the SCALE-encoded tokens transfer call at the Bridged chain;
|
||||
/// - `bridged_currency_transfer_signature` - the signature of the `swap.target_account_at_bridged_chain`
|
||||
/// for the message returned by the `pallet_bridge_dispatch::account_ownership_digest()` function call.
|
||||
/// - `target_public_at_bridged_chain` - the public key of the
|
||||
/// `swap.target_account_at_bridged_chain` account used to verify
|
||||
/// `bridged_currency_transfer_signature`;
|
||||
/// - `bridged_currency_transfer` - the SCALE-encoded tokens transfer call at the Bridged
|
||||
/// chain;
|
||||
/// - `bridged_currency_transfer_signature` - the signature of the
|
||||
/// `swap.target_account_at_bridged_chain` for the message returned by the
|
||||
/// `pallet_bridge_dispatch::account_ownership_digest()` function call.
|
||||
///
|
||||
/// The `source_account_at_this_chain` MUST have enough balance to cover both token swap and message
|
||||
/// transfer. Message fee may be estimated using corresponding `OutboundLaneApi` of This runtime.
|
||||
/// The `source_account_at_this_chain` MUST have enough balance to cover both token swap and
|
||||
/// message transfer. Message fee may be estimated using corresponding `OutboundLaneApi` of
|
||||
/// This runtime.
|
||||
///
|
||||
/// **WARNING**: the submitter of this transaction is responsible for verifying:
|
||||
///
|
||||
/// 1) that the `bridged_currency_transfer` represents a valid token transfer call that transfers
|
||||
/// `swap.target_balance_at_bridged_chain` to his `source_account_at_bridged_chain` account;
|
||||
/// 2) that either the `source_account_at_bridged_chain` already exists, or the
|
||||
/// `swap.target_balance_at_bridged_chain` is above existential deposit of the Bridged chain;
|
||||
/// 3) the `target_public_at_bridged_chain` matches the `swap.target_account_at_bridged_chain`;
|
||||
/// 4) the `bridged_currency_transfer_signature` is valid and generated by the owner of the
|
||||
/// `target_public_at_bridged_chain` account (read more about [`CallOrigin::TargetAccount`]).
|
||||
/// 1) that the `bridged_currency_transfer` represents a valid token transfer call that
|
||||
/// transfers `swap.target_balance_at_bridged_chain` to his
|
||||
/// `source_account_at_bridged_chain` account; 2) that either the
|
||||
/// `source_account_at_bridged_chain` already exists, or the
|
||||
/// `swap.target_balance_at_bridged_chain` is above existential deposit of the Bridged
|
||||
/// chain; 3) the `target_public_at_bridged_chain` matches the
|
||||
/// `swap.target_account_at_bridged_chain`; 4) the `bridged_currency_transfer_signature` is
|
||||
/// valid and generated by the owner of the `target_public_at_bridged_chain` account
|
||||
/// (read more about [`CallOrigin::TargetAccount`]).
|
||||
///
|
||||
/// Violating rule#1 will lead to losing your `source_balance_at_this_chain` tokens. Violating other
|
||||
/// rules will lead to losing message fees for this and other transactions + losing fees for message
|
||||
/// transfer.
|
||||
/// Violating rule#1 will lead to losing your `source_balance_at_this_chain` tokens.
|
||||
/// Violating other rules will lead to losing message fees for this and other transactions +
|
||||
/// losing fees for message transfer.
|
||||
#[pallet::weight(0)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_swap(
|
||||
@@ -203,7 +212,8 @@ pub mod pallet {
|
||||
bridged_currency_transfer_weight: Weight,
|
||||
bridged_currency_transfer_signature: BridgedAccountSignatureOf<T, I>,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
// ensure that the `origin` is the same account that is mentioned in the `swap` intention
|
||||
// ensure that the `origin` is the same account that is mentioned in the `swap`
|
||||
// intention
|
||||
let origin_account = ensure_signed(origin)?;
|
||||
ensure!(
|
||||
origin_account == swap.source_account_at_this_chain,
|
||||
@@ -221,8 +231,8 @@ pub mod pallet {
|
||||
Error::<T, I>::TooLowBalanceOnThisChain,
|
||||
);
|
||||
|
||||
// if the swap is replay-protected, then we need to ensure that we have not yet passed the
|
||||
// specified block yet
|
||||
// if the swap is replay-protected, then we need to ensure that we have not yet passed
|
||||
// the specified block yet
|
||||
match swap.swap_type {
|
||||
TokenSwapType::TemporaryTargetAccountAtBridgedChain => (),
|
||||
TokenSwapType::LockClaimUntilBlock(block_number, _) => ensure!(
|
||||
@@ -237,7 +247,8 @@ pub mod pallet {
|
||||
let transfer_result = T::ThisCurrency::transfer(
|
||||
&swap.source_account_at_this_chain,
|
||||
&swap_account,
|
||||
// saturating_add is ok, or we have the chain where single holder owns all tokens
|
||||
// saturating_add is ok, or we have the chain where single holder owns all
|
||||
// tokens
|
||||
swap.source_balance_at_this_chain
|
||||
.saturating_add(swap_delivery_and_dispatch_fee),
|
||||
// if we'll allow account to die, then he'll be unable to `cancel_claim`
|
||||
@@ -254,8 +265,8 @@ pub mod pallet {
|
||||
);
|
||||
|
||||
return sp_runtime::TransactionOutcome::Rollback(Err(
|
||||
Error::<T, I>::FailedToTransferToSwapAccount.into()
|
||||
));
|
||||
Error::<T, I>::FailedToTransferToSwapAccount.into(),
|
||||
))
|
||||
}
|
||||
|
||||
// the transfer message is sent over the bridge. The message is supposed to be a
|
||||
@@ -289,20 +300,21 @@ pub mod pallet {
|
||||
|
||||
return sp_runtime::TransactionOutcome::Rollback(Err(
|
||||
Error::<T, I>::FailedToSendTransferMessage.into(),
|
||||
));
|
||||
}
|
||||
))
|
||||
},
|
||||
};
|
||||
|
||||
// remember that we have started the swap
|
||||
let swap_hash = swap.using_encoded(blake2_256).into();
|
||||
let insert_swap_result = PendingSwaps::<T, I>::try_mutate(swap_hash, |maybe_state| {
|
||||
if maybe_state.is_some() {
|
||||
return Err(());
|
||||
}
|
||||
let insert_swap_result =
|
||||
PendingSwaps::<T, I>::try_mutate(swap_hash, |maybe_state| {
|
||||
if maybe_state.is_some() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
*maybe_state = Some(TokenSwapState::Started);
|
||||
Ok(())
|
||||
});
|
||||
*maybe_state = Some(TokenSwapState::Started);
|
||||
Ok(())
|
||||
});
|
||||
if insert_swap_result.is_err() {
|
||||
log::error!(
|
||||
target: "runtime::bridge-token-swap",
|
||||
@@ -310,7 +322,9 @@ pub mod pallet {
|
||||
swap,
|
||||
);
|
||||
|
||||
return sp_runtime::TransactionOutcome::Rollback(Err(Error::<T, I>::SwapAlreadyStarted.into()));
|
||||
return sp_runtime::TransactionOutcome::Rollback(Err(
|
||||
Error::<T, I>::SwapAlreadyStarted.into(),
|
||||
))
|
||||
}
|
||||
|
||||
log::trace!(
|
||||
@@ -330,21 +344,23 @@ pub mod pallet {
|
||||
})
|
||||
}
|
||||
|
||||
/// Claim previously reserved `source_balance_at_this_chain` by `target_account_at_this_chain`.
|
||||
/// Claim previously reserved `source_balance_at_this_chain` by
|
||||
/// `target_account_at_this_chain`.
|
||||
///
|
||||
/// **WARNING**: the correct way to call this function is to call it over the messages bridge with
|
||||
/// dispatch origin set to `pallet_bridge_dispatch::CallOrigin::SourceAccount(target_account_at_bridged_chain)`.
|
||||
/// **WARNING**: the correct way to call this function is to call it over the messages
|
||||
/// bridge with dispatch origin set to
|
||||
/// `pallet_bridge_dispatch::CallOrigin::SourceAccount(target_account_at_bridged_chain)`.
|
||||
///
|
||||
/// This should be called only when successful transfer confirmation has been received.
|
||||
#[pallet::weight(0)]
|
||||
pub fn claim_swap(origin: OriginFor<T>, swap: TokenSwapOf<T, I>) -> DispatchResultWithPostInfo {
|
||||
pub fn claim_swap(
|
||||
origin: OriginFor<T>,
|
||||
swap: TokenSwapOf<T, I>,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
// ensure that the `origin` is controlled by the `swap.target_account_at_bridged_chain`
|
||||
let origin_account = ensure_signed(origin)?;
|
||||
let target_account_at_this_chain = target_account_at_this_chain::<T, I>(&swap);
|
||||
ensure!(
|
||||
origin_account == target_account_at_this_chain,
|
||||
Error::<T, I>::InvalidClaimant,
|
||||
);
|
||||
ensure!(origin_account == target_account_at_this_chain, Error::<T, I>::InvalidClaimant,);
|
||||
|
||||
// ensure that the swap is confirmed
|
||||
let swap_hash = swap.using_encoded(blake2_256).into();
|
||||
@@ -354,13 +370,12 @@ pub mod pallet {
|
||||
Some(TokenSwapState::Confirmed) => {
|
||||
let is_claim_allowed = match swap.swap_type {
|
||||
TokenSwapType::TemporaryTargetAccountAtBridgedChain => true,
|
||||
TokenSwapType::LockClaimUntilBlock(block_number, _) => {
|
||||
block_number < frame_system::Pallet::<T>::block_number()
|
||||
}
|
||||
TokenSwapType::LockClaimUntilBlock(block_number, _) =>
|
||||
block_number < frame_system::Pallet::<T>::block_number(),
|
||||
};
|
||||
|
||||
ensure!(is_claim_allowed, Error::<T, I>::SwapIsTemporaryLocked);
|
||||
}
|
||||
},
|
||||
Some(TokenSwapState::Failed) => fail!(Error::<T, I>::SwapIsFailed),
|
||||
None => fail!(Error::<T, I>::SwapIsInactive),
|
||||
}
|
||||
@@ -368,13 +383,18 @@ pub mod pallet {
|
||||
complete_claim::<T, I>(swap, swap_hash, origin_account, Event::SwapClaimed(swap_hash))
|
||||
}
|
||||
|
||||
/// Return previously reserved `source_balance_at_this_chain` back to the `source_account_at_this_chain`.
|
||||
/// Return previously reserved `source_balance_at_this_chain` back to the
|
||||
/// `source_account_at_this_chain`.
|
||||
///
|
||||
/// This should be called only when transfer has failed at Bridged chain and we have received
|
||||
/// notification about that.
|
||||
/// This should be called only when transfer has failed at Bridged chain and we have
|
||||
/// received notification about that.
|
||||
#[pallet::weight(0)]
|
||||
pub fn cancel_swap(origin: OriginFor<T>, swap: TokenSwapOf<T, I>) -> DispatchResultWithPostInfo {
|
||||
// ensure that the `origin` is the same account that is mentioned in the `swap` intention
|
||||
pub fn cancel_swap(
|
||||
origin: OriginFor<T>,
|
||||
swap: TokenSwapOf<T, I>,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
// ensure that the `origin` is the same account that is mentioned in the `swap`
|
||||
// intention
|
||||
let origin_account = ensure_signed(origin)?;
|
||||
ensure!(
|
||||
origin_account == swap.source_account_at_this_chain,
|
||||
@@ -388,9 +408,10 @@ pub mod pallet {
|
||||
Some(TokenSwapState::Started) => fail!(Error::<T, I>::SwapIsPending),
|
||||
Some(TokenSwapState::Confirmed) => fail!(Error::<T, I>::SwapIsConfirmed),
|
||||
Some(TokenSwapState::Failed) => {
|
||||
// we allow canceling swap even before lock period is over - the `source_account_at_this_chain`
|
||||
// has already paid for nothing and it is up to him to decide whether he want to try again
|
||||
}
|
||||
// we allow canceling swap even before lock period is over - the
|
||||
// `source_account_at_this_chain` has already paid for nothing and it is up to
|
||||
// him to decide whether he want to try again
|
||||
},
|
||||
None => fail!(Error::<T, I>::SwapIsInactive),
|
||||
}
|
||||
|
||||
@@ -413,13 +434,15 @@ pub mod pallet {
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T, I = ()> {
|
||||
/// The account that has submitted the `start_claim` doesn't match the `TokenSwap::source_account_at_this_chain`.
|
||||
/// The account that has submitted the `start_claim` doesn't match the
|
||||
/// `TokenSwap::source_account_at_this_chain`.
|
||||
MismatchedSwapSourceOrigin,
|
||||
/// The swap balance in This chain tokens is below existential deposit and can't be made.
|
||||
TooLowBalanceOnThisChain,
|
||||
/// Transfer from This chain account to temporary Swap account has failed.
|
||||
FailedToTransferToSwapAccount,
|
||||
/// Transfer from the temporary Swap account to the derived account of Bridged account has failed.
|
||||
/// Transfer from the temporary Swap account to the derived account of Bridged account has
|
||||
/// failed.
|
||||
FailedToTransferFromSwapAccount,
|
||||
/// The message to transfer tokens on Target chain can't be sent.
|
||||
FailedToSendTransferMessage,
|
||||
@@ -431,17 +454,18 @@ pub mod pallet {
|
||||
SwapIsFailed,
|
||||
/// Claiming swap is not allowed.
|
||||
///
|
||||
/// Now the only possible case when you may get this error, is when you're trying to claim swap with
|
||||
/// `TokenSwapType::LockClaimUntilBlock` before lock period is over.
|
||||
/// Now the only possible case when you may get this error, is when you're trying to claim
|
||||
/// swap with `TokenSwapType::LockClaimUntilBlock` before lock period is over.
|
||||
SwapIsTemporaryLocked,
|
||||
/// Swap period is finished and you can not restart it.
|
||||
///
|
||||
/// Now the only possible case when you may get this error, is when you're trying to start swap with
|
||||
/// `TokenSwapType::LockClaimUntilBlock` after lock period is over.
|
||||
/// Now the only possible case when you may get this error, is when you're trying to start
|
||||
/// swap with `TokenSwapType::LockClaimUntilBlock` after lock period is over.
|
||||
SwapPeriodIsFinished,
|
||||
/// Someone is trying to cancel swap that has been confirmed.
|
||||
SwapIsConfirmed,
|
||||
/// Someone is trying to claim/cancel swap that is either not started or already claimed/canceled.
|
||||
/// Someone is trying to claim/cancel swap that is either not started or already
|
||||
/// claimed/canceled.
|
||||
SwapIsInactive,
|
||||
/// The swap claimant is invalid.
|
||||
InvalidClaimant,
|
||||
@@ -449,17 +473,19 @@ pub mod pallet {
|
||||
|
||||
/// Pending token swaps states.
|
||||
#[pallet::storage]
|
||||
pub type PendingSwaps<T: Config<I>, I: 'static = ()> = StorageMap<_, Identity, H256, TokenSwapState>;
|
||||
pub type PendingSwaps<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Identity, H256, TokenSwapState>;
|
||||
|
||||
/// Pending transfer messages.
|
||||
#[pallet::storage]
|
||||
pub type PendingMessages<T: Config<I>, I: 'static = ()> = StorageMap<_, Identity, MessageNonce, H256>;
|
||||
pub type PendingMessages<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Identity, MessageNonce, H256>;
|
||||
|
||||
impl<T: Config<I>, I: 'static> OnDeliveryConfirmed for Pallet<T, I> {
|
||||
fn on_messages_delivered(lane: &LaneId, delivered_messages: &DeliveredMessages) -> Weight {
|
||||
// we're only interested in our lane messages
|
||||
if *lane != T::OutboundMessageLaneId::get() {
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
// so now we're dealing with our lane messages. Ideally we'll have dedicated lane
|
||||
@@ -472,11 +498,12 @@ pub mod pallet {
|
||||
if let Some(swap_hash) = PendingMessages::<T, I>::take(message_nonce) {
|
||||
writes += 1;
|
||||
|
||||
let token_swap_state = if delivered_messages.message_dispatch_result(message_nonce) {
|
||||
TokenSwapState::Confirmed
|
||||
} else {
|
||||
TokenSwapState::Failed
|
||||
};
|
||||
let token_swap_state =
|
||||
if delivered_messages.message_dispatch_result(message_nonce) {
|
||||
TokenSwapState::Confirmed
|
||||
} else {
|
||||
TokenSwapState::Failed
|
||||
};
|
||||
|
||||
log::trace!(
|
||||
target: "runtime::bridge-token-swap",
|
||||
@@ -494,12 +521,16 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
/// Returns temporary account id used to lock funds during swap on This chain.
|
||||
pub(crate) fn swap_account_id<T: Config<I>, I: 'static>(swap: &TokenSwapOf<T, I>) -> T::AccountId {
|
||||
pub(crate) fn swap_account_id<T: Config<I>, I: 'static>(
|
||||
swap: &TokenSwapOf<T, I>,
|
||||
) -> T::AccountId {
|
||||
T::FromSwapToThisAccountIdConverter::convert(swap.using_encoded(blake2_256).into())
|
||||
}
|
||||
|
||||
/// Expected target account representation on This chain (aka `target_account_at_this_chain`).
|
||||
pub(crate) fn target_account_at_this_chain<T: Config<I>, I: 'static>(swap: &TokenSwapOf<T, I>) -> T::AccountId {
|
||||
pub(crate) fn target_account_at_this_chain<T: Config<I>, I: 'static>(
|
||||
swap: &TokenSwapOf<T, I>,
|
||||
) -> T::AccountId {
|
||||
T::FromBridgedToThisAccountIdConverter::convert(bp_runtime::derive_account_id(
|
||||
T::BridgedChainId::get(),
|
||||
bp_runtime::SourceAccount::Account(swap.target_account_at_bridged_chain.clone()),
|
||||
@@ -533,8 +564,8 @@ pub mod pallet {
|
||||
);
|
||||
|
||||
return sp_runtime::TransactionOutcome::Rollback(Err(
|
||||
Error::<T, I>::FailedToTransferFromSwapAccount.into()
|
||||
));
|
||||
Error::<T, I>::FailedToTransferFromSwapAccount.into(),
|
||||
))
|
||||
}
|
||||
|
||||
log::trace!(
|
||||
@@ -786,20 +817,21 @@ mod tests {
|
||||
));
|
||||
|
||||
let swap_hash = test_swap_hash();
|
||||
assert_eq!(
|
||||
PendingSwaps::<TestRuntime>::get(swap_hash),
|
||||
Some(TokenSwapState::Started)
|
||||
);
|
||||
assert_eq!(PendingSwaps::<TestRuntime>::get(swap_hash), Some(TokenSwapState::Started));
|
||||
assert_eq!(PendingMessages::<TestRuntime>::get(MESSAGE_NONCE), Some(swap_hash));
|
||||
assert_eq!(
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<TestRuntime, ()>(&test_swap())),
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<
|
||||
TestRuntime,
|
||||
(),
|
||||
>(&test_swap())),
|
||||
test_swap().source_balance_at_this_chain + SWAP_DELIVERY_AND_DISPATCH_FEE,
|
||||
);
|
||||
assert!(
|
||||
frame_system::Pallet::<TestRuntime>::events()
|
||||
.iter()
|
||||
.any(|e| e.event
|
||||
== crate::mock::Event::TokenSwap(crate::Event::SwapStarted(swap_hash, MESSAGE_NONCE,))),
|
||||
frame_system::Pallet::<TestRuntime>::events().iter().any(|e| e.event ==
|
||||
crate::mock::Event::TokenSwap(crate::Event::SwapStarted(
|
||||
swap_hash,
|
||||
MESSAGE_NONCE,
|
||||
))),
|
||||
"Missing SwapStarted event: {:?}",
|
||||
frame_system::Pallet::<TestRuntime>::events(),
|
||||
);
|
||||
@@ -811,7 +843,9 @@ mod tests {
|
||||
run_test(|| {
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::claim_swap(
|
||||
Origin::signed(1 + target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
|
||||
Origin::signed(
|
||||
1 + target_account_at_this_chain::<TestRuntime, ()>(&test_swap())
|
||||
),
|
||||
test_swap(),
|
||||
),
|
||||
Error::<TestRuntime, ()>::InvalidClaimant
|
||||
@@ -913,19 +947,21 @@ mod tests {
|
||||
let swap_hash = test_swap_hash();
|
||||
assert_eq!(PendingSwaps::<TestRuntime>::get(swap_hash), None);
|
||||
assert_eq!(
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<TestRuntime, ()>(&test_swap())),
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<
|
||||
TestRuntime,
|
||||
(),
|
||||
>(&test_swap())),
|
||||
0,
|
||||
);
|
||||
assert_eq!(
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(&target_account_at_this_chain::<TestRuntime, ()>(
|
||||
&test_swap()
|
||||
),),
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(
|
||||
&target_account_at_this_chain::<TestRuntime, ()>(&test_swap()),
|
||||
),
|
||||
test_swap().source_balance_at_this_chain,
|
||||
);
|
||||
assert!(
|
||||
frame_system::Pallet::<TestRuntime>::events()
|
||||
.iter()
|
||||
.any(|e| e.event == crate::mock::Event::TokenSwap(crate::Event::SwapClaimed(swap_hash,))),
|
||||
frame_system::Pallet::<TestRuntime>::events().iter().any(|e| e.event ==
|
||||
crate::mock::Event::TokenSwap(crate::Event::SwapClaimed(swap_hash,))),
|
||||
"Missing SwapClaimed event: {:?}",
|
||||
frame_system::Pallet::<TestRuntime>::events(),
|
||||
);
|
||||
@@ -939,7 +975,10 @@ mod tests {
|
||||
receive_test_swap_confirmation(false);
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::cancel_swap(Origin::signed(THIS_CHAIN_ACCOUNT + 1), test_swap()),
|
||||
Pallet::<TestRuntime>::cancel_swap(
|
||||
Origin::signed(THIS_CHAIN_ACCOUNT + 1),
|
||||
test_swap()
|
||||
),
|
||||
Error::<TestRuntime, ()>::MismatchedSwapSourceOrigin
|
||||
);
|
||||
});
|
||||
@@ -1014,7 +1053,10 @@ mod tests {
|
||||
let swap_hash = test_swap_hash();
|
||||
assert_eq!(PendingSwaps::<TestRuntime>::get(swap_hash), None);
|
||||
assert_eq!(
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<TestRuntime, ()>(&test_swap())),
|
||||
pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<
|
||||
TestRuntime,
|
||||
(),
|
||||
>(&test_swap())),
|
||||
0,
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -1022,9 +1064,8 @@ mod tests {
|
||||
THIS_CHAIN_ACCOUNT_BALANCE - SWAP_DELIVERY_AND_DISPATCH_FEE,
|
||||
);
|
||||
assert!(
|
||||
frame_system::Pallet::<TestRuntime>::events()
|
||||
.iter()
|
||||
.any(|e| e.event == crate::mock::Event::TokenSwap(crate::Event::SwapCanceled(swap_hash,))),
|
||||
frame_system::Pallet::<TestRuntime>::events().iter().any(|e| e.event ==
|
||||
crate::mock::Event::TokenSwap(crate::Event::SwapCanceled(swap_hash,))),
|
||||
"Missing SwapCanceled event: {:?}",
|
||||
frame_system::Pallet::<TestRuntime>::events(),
|
||||
);
|
||||
@@ -1047,7 +1088,10 @@ mod tests {
|
||||
// when unrelated messages are delivered
|
||||
let mut messages = DeliveredMessages::new(MESSAGE_NONCE - 2, true);
|
||||
messages.note_dispatched_message(false);
|
||||
Pallet::<TestRuntime, ()>::on_messages_delivered(&OutboundMessageLaneId::get(), &messages);
|
||||
Pallet::<TestRuntime, ()>::on_messages_delivered(
|
||||
&OutboundMessageLaneId::get(),
|
||||
&messages,
|
||||
);
|
||||
assert_eq!(
|
||||
PendingMessages::<TestRuntime, ()>::get(MESSAGE_NONCE),
|
||||
Some(test_swap_hash())
|
||||
@@ -1061,7 +1105,10 @@ mod tests {
|
||||
let mut messages = DeliveredMessages::new(MESSAGE_NONCE - 1, false);
|
||||
messages.note_dispatched_message(true);
|
||||
messages.note_dispatched_message(false);
|
||||
Pallet::<TestRuntime, ()>::on_messages_delivered(&OutboundMessageLaneId::get(), &messages);
|
||||
Pallet::<TestRuntime, ()>::on_messages_delivered(
|
||||
&OutboundMessageLaneId::get(),
|
||||
&messages,
|
||||
);
|
||||
assert_eq!(PendingMessages::<TestRuntime, ()>::get(MESSAGE_NONCE), None);
|
||||
assert_eq!(
|
||||
PendingSwaps::<TestRuntime, ()>::get(test_swap_hash()),
|
||||
|
||||
@@ -172,9 +172,7 @@ impl sp_runtime::traits::Convert<H256, AccountId> for TestAccountConverter {
|
||||
|
||||
/// Run pallet test.
|
||||
pub fn run_test<T>(test: impl FnOnce() -> T) -> T {
|
||||
let mut t = frame_system::GenesisConfig::default()
|
||||
.build_storage::<TestRuntime>()
|
||||
.unwrap();
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<TestRuntime>().unwrap();
|
||||
pallet_balances::GenesisConfig::<TestRuntime> {
|
||||
balances: vec![(THIS_CHAIN_ACCOUNT, THIS_CHAIN_ACCOUNT_BALANCE)],
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#![allow(clippy::unnecessary_mut_passed)]
|
||||
|
||||
use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState};
|
||||
use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial};
|
||||
use frame_support::weights::{
|
||||
WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
@@ -83,29 +85,36 @@ pub const SESSION_LENGTH: BlockNumber = time_units::HOURS;
|
||||
pub const WITH_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotMessages";
|
||||
|
||||
/// Name of the DOT->KSM conversion rate stored in the Kusama runtime.
|
||||
pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str = "PolkadotToKusamaConversionRate";
|
||||
pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str =
|
||||
"PolkadotToKusamaConversionRate";
|
||||
|
||||
/// Name of the `KusamaFinalityApi::best_finalized` runtime method.
|
||||
pub const BEST_FINALIZED_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_best_finalized";
|
||||
/// Name of the `KusamaFinalityApi::is_known_header` runtime method.
|
||||
pub const IS_KNOWN_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_is_known_header";
|
||||
|
||||
/// Name of the `ToKusamaOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method.
|
||||
/// Name of the `ToKusamaOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
|
||||
/// method.
|
||||
pub const TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD: &str =
|
||||
"ToKusamaOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
|
||||
/// Name of the `ToKusamaOutboundLaneApi::message_details` runtime method.
|
||||
pub const TO_KUSAMA_MESSAGE_DETAILS_METHOD: &str = "ToKusamaOutboundLaneApi_message_details";
|
||||
/// Name of the `ToKusamaOutboundLaneApi::latest_generated_nonce` runtime method.
|
||||
pub const TO_KUSAMA_LATEST_GENERATED_NONCE_METHOD: &str = "ToKusamaOutboundLaneApi_latest_generated_nonce";
|
||||
pub const TO_KUSAMA_LATEST_GENERATED_NONCE_METHOD: &str =
|
||||
"ToKusamaOutboundLaneApi_latest_generated_nonce";
|
||||
/// Name of the `ToKusamaOutboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const TO_KUSAMA_LATEST_RECEIVED_NONCE_METHOD: &str = "ToKusamaOutboundLaneApi_latest_received_nonce";
|
||||
pub const TO_KUSAMA_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"ToKusamaOutboundLaneApi_latest_received_nonce";
|
||||
|
||||
/// Name of the `FromKusamaInboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const FROM_KUSAMA_LATEST_RECEIVED_NONCE_METHOD: &str = "FromKusamaInboundLaneApi_latest_received_nonce";
|
||||
pub const FROM_KUSAMA_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"FromKusamaInboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `FromKusamaInboundLaneApi::latest_onfirmed_nonce` runtime method.
|
||||
pub const FROM_KUSAMA_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromKusamaInboundLaneApi_latest_confirmed_nonce";
|
||||
pub const FROM_KUSAMA_LATEST_CONFIRMED_NONCE_METHOD: &str =
|
||||
"FromKusamaInboundLaneApi_latest_confirmed_nonce";
|
||||
/// Name of the `FromKusamaInboundLaneApi::unrewarded_relayers_state` runtime method.
|
||||
pub const FROM_KUSAMA_UNREWARDED_RELAYERS_STATE: &str = "FromKusamaInboundLaneApi_unrewarded_relayers_state";
|
||||
pub const FROM_KUSAMA_UNREWARDED_RELAYERS_STATE: &str =
|
||||
"FromKusamaInboundLaneApi_unrewarded_relayers_state";
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// API for querying information about the finalized Kusama headers.
|
||||
|
||||
@@ -30,9 +30,8 @@ use frame_support::{
|
||||
};
|
||||
use frame_system::limits;
|
||||
use sp_core::Hasher as HasherT;
|
||||
use sp_runtime::traits::Convert;
|
||||
use sp_runtime::{
|
||||
traits::{IdentifyAccount, Verify},
|
||||
traits::{Convert, IdentifyAccount, Verify},
|
||||
MultiSignature, MultiSigner, Perbill,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
@@ -77,29 +76,32 @@ pub const MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE: MessageNonce = 1024;
|
||||
/// Weight of single regular message delivery transaction on Millau chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH` bytes is delivered.
|
||||
/// The message must have dispatch weight set to zero. The result then must be rounded up to account
|
||||
/// possible future runtime upgrades.
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
|
||||
/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
|
||||
/// rounded up to account possible future runtime upgrades.
|
||||
pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = 1_500_000_000;
|
||||
|
||||
/// Increase of delivery transaction weight on Millau chain with every additional message byte.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The
|
||||
/// result then must be rounded up to account possible future runtime upgrades.
|
||||
/// This value is a result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
|
||||
/// must be rounded up to account possible future runtime upgrades.
|
||||
pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = 25_000;
|
||||
|
||||
/// Maximal weight of single message delivery confirmation transaction on Millau chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof` weight formula computation
|
||||
/// for the case when single message is confirmed. The result then must be rounded up to account possible future
|
||||
/// runtime upgrades.
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
|
||||
/// weight formula computation for the case when single message is confirmed. The result then must
|
||||
/// be rounded up to account possible future runtime upgrades.
|
||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000;
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Millau chain.
|
||||
///
|
||||
/// This value corresponds to the result of `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()`
|
||||
/// call for your chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery transactions cheaper.
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 600_000_000;
|
||||
|
||||
/// The target length of a session (how often authorities change) on Millau measured in of number of
|
||||
@@ -264,22 +266,28 @@ pub const WITH_RIALTO_TOKEN_SWAP_PALLET_NAME: &str = "BridgeRialtoTokenSwap";
|
||||
/// Name of the `MillauFinalityApi::best_finalized` runtime method.
|
||||
pub const BEST_FINALIZED_MILLAU_HEADER_METHOD: &str = "MillauFinalityApi_best_finalized";
|
||||
|
||||
/// Name of the `ToMillauOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method.
|
||||
/// Name of the `ToMillauOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
|
||||
/// method.
|
||||
pub const TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD: &str =
|
||||
"ToMillauOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
|
||||
/// Name of the `ToMillauOutboundLaneApi::message_details` runtime method.
|
||||
pub const TO_MILLAU_MESSAGE_DETAILS_METHOD: &str = "ToMillauOutboundLaneApi_message_details";
|
||||
/// Name of the `ToMillauOutboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const TO_MILLAU_LATEST_RECEIVED_NONCE_METHOD: &str = "ToMillauOutboundLaneApi_latest_received_nonce";
|
||||
pub const TO_MILLAU_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"ToMillauOutboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `ToMillauOutboundLaneApi::latest_generated_nonce` runtime method.
|
||||
pub const TO_MILLAU_LATEST_GENERATED_NONCE_METHOD: &str = "ToMillauOutboundLaneApi_latest_generated_nonce";
|
||||
pub const TO_MILLAU_LATEST_GENERATED_NONCE_METHOD: &str =
|
||||
"ToMillauOutboundLaneApi_latest_generated_nonce";
|
||||
|
||||
/// Name of the `FromMillauInboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const FROM_MILLAU_LATEST_RECEIVED_NONCE_METHOD: &str = "FromMillauInboundLaneApi_latest_received_nonce";
|
||||
pub const FROM_MILLAU_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"FromMillauInboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `FromMillauInboundLaneApi::latest_onfirmed_nonce` runtime method.
|
||||
pub const FROM_MILLAU_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromMillauInboundLaneApi_latest_confirmed_nonce";
|
||||
pub const FROM_MILLAU_LATEST_CONFIRMED_NONCE_METHOD: &str =
|
||||
"FromMillauInboundLaneApi_latest_confirmed_nonce";
|
||||
/// Name of the `FromMillauInboundLaneApi::unrewarded_relayers_state` runtime method.
|
||||
pub const FROM_MILLAU_UNREWARDED_RELAYERS_STATE: &str = "FromMillauInboundLaneApi_unrewarded_relayers_state";
|
||||
pub const FROM_MILLAU_UNREWARDED_RELAYERS_STATE: &str =
|
||||
"FromMillauInboundLaneApi_unrewarded_relayers_state";
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// API for querying information about the finalized Millau headers.
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#![allow(clippy::unnecessary_mut_passed)]
|
||||
|
||||
use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState};
|
||||
use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial};
|
||||
use frame_support::weights::{
|
||||
WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
@@ -72,8 +74,8 @@ pub const TRANSACTION_BYTE_FEE: Balance = 10 * 10_000_000_000 / 100 / 1_000;
|
||||
/// Existential deposit on Polkadot.
|
||||
pub const EXISTENTIAL_DEPOSIT: Balance = 10_000_000_000;
|
||||
|
||||
/// The target length of a session (how often authorities change) on Polkadot measured in of number of
|
||||
/// blocks.
|
||||
/// The target length of a session (how often authorities change) on Polkadot measured in of number
|
||||
/// of blocks.
|
||||
///
|
||||
/// Note that since this is a target sessions may change before/after this time depending on network
|
||||
/// conditions.
|
||||
@@ -83,29 +85,36 @@ pub const SESSION_LENGTH: BlockNumber = 4 * time_units::HOURS;
|
||||
pub const WITH_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessages";
|
||||
|
||||
/// Name of the KSM->DOT conversion rate stored in the Polkadot runtime.
|
||||
pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str = "KusamaToPolkadotConversionRate";
|
||||
pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str =
|
||||
"KusamaToPolkadotConversionRate";
|
||||
|
||||
/// Name of the `PolkadotFinalityApi::best_finalized` runtime method.
|
||||
pub const BEST_FINALIZED_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_best_finalized";
|
||||
/// Name of the `PolkadotFinalityApi::is_known_header` runtime method.
|
||||
pub const IS_KNOWN_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_is_known_header";
|
||||
|
||||
/// Name of the `ToPolkadotOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method.
|
||||
/// Name of the `ToPolkadotOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
|
||||
/// method.
|
||||
pub const TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD: &str =
|
||||
"ToPolkadotOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
|
||||
/// Name of the `ToPolkadotOutboundLaneApi::message_details` runtime method.
|
||||
pub const TO_POLKADOT_MESSAGE_DETAILS_METHOD: &str = "ToPolkadotOutboundLaneApi_message_details";
|
||||
/// Name of the `ToPolkadotOutboundLaneApi::latest_generated_nonce` runtime method.
|
||||
pub const TO_POLKADOT_LATEST_GENERATED_NONCE_METHOD: &str = "ToPolkadotOutboundLaneApi_latest_generated_nonce";
|
||||
pub const TO_POLKADOT_LATEST_GENERATED_NONCE_METHOD: &str =
|
||||
"ToPolkadotOutboundLaneApi_latest_generated_nonce";
|
||||
/// Name of the `ToPolkadotOutboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const TO_POLKADOT_LATEST_RECEIVED_NONCE_METHOD: &str = "ToPolkadotOutboundLaneApi_latest_received_nonce";
|
||||
pub const TO_POLKADOT_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"ToPolkadotOutboundLaneApi_latest_received_nonce";
|
||||
|
||||
/// Name of the `FromPolkadotInboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const FROM_POLKADOT_LATEST_RECEIVED_NONCE_METHOD: &str = "FromPolkadotInboundLaneApi_latest_received_nonce";
|
||||
pub const FROM_POLKADOT_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"FromPolkadotInboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `FromPolkadotInboundLaneApi::latest_onfirmed_nonce` runtime method.
|
||||
pub const FROM_POLKADOT_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromPolkadotInboundLaneApi_latest_confirmed_nonce";
|
||||
pub const FROM_POLKADOT_LATEST_CONFIRMED_NONCE_METHOD: &str =
|
||||
"FromPolkadotInboundLaneApi_latest_confirmed_nonce";
|
||||
/// Name of the `FromPolkadotInboundLaneApi::unrewarded_relayers_state` runtime method.
|
||||
pub const FROM_POLKADOT_UNREWARDED_RELAYERS_STATE: &str = "FromPolkadotInboundLaneApi_unrewarded_relayers_state";
|
||||
pub const FROM_POLKADOT_UNREWARDED_RELAYERS_STATE: &str =
|
||||
"FromPolkadotInboundLaneApi_unrewarded_relayers_state";
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// API for querying information about the finalized Polkadot headers.
|
||||
|
||||
@@ -68,29 +68,32 @@ pub const MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE: MessageNonce = 128;
|
||||
/// Weight of single regular message delivery transaction on Rialto chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH` bytes is delivered.
|
||||
/// The message must have dispatch weight set to zero. The result then must be rounded up to account
|
||||
/// possible future runtime upgrades.
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
|
||||
/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
|
||||
/// rounded up to account possible future runtime upgrades.
|
||||
pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = 1_500_000_000;
|
||||
|
||||
/// Increase of delivery transaction weight on Rialto chain with every additional message byte.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The
|
||||
/// result then must be rounded up to account possible future runtime upgrades.
|
||||
/// This value is a result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
|
||||
/// must be rounded up to account possible future runtime upgrades.
|
||||
pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = 25_000;
|
||||
|
||||
/// Maximal weight of single message delivery confirmation transaction on Rialto chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof` weight formula computation
|
||||
/// for the case when single message is confirmed. The result then must be rounded up to account possible future
|
||||
/// runtime upgrades.
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
|
||||
/// weight formula computation for the case when single message is confirmed. The result then must
|
||||
/// be rounded up to account possible future runtime upgrades.
|
||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000;
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Rialto chain.
|
||||
///
|
||||
/// This value corresponds to the result of `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()`
|
||||
/// call for your chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery transactions cheaper.
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 600_000_000;
|
||||
|
||||
/// The target length of a session (how often authorities change) on Rialto measured in of number of
|
||||
@@ -231,22 +234,28 @@ pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages";
|
||||
/// Name of the `RialtoFinalityApi::best_finalized` runtime method.
|
||||
pub const BEST_FINALIZED_RIALTO_HEADER_METHOD: &str = "RialtoFinalityApi_best_finalized";
|
||||
|
||||
/// Name of the `ToRialtoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method.
|
||||
/// Name of the `ToRialtoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
|
||||
/// method.
|
||||
pub const TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD: &str =
|
||||
"ToRialtoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
|
||||
/// Name of the `ToRialtoOutboundLaneApi::message_details` runtime method.
|
||||
pub const TO_RIALTO_MESSAGE_DETAILS_METHOD: &str = "ToRialtoOutboundLaneApi_message_details";
|
||||
/// Name of the `ToRialtoOutboundLaneApi::latest_generated_nonce` runtime method.
|
||||
pub const TO_RIALTO_LATEST_GENERATED_NONCE_METHOD: &str = "ToRialtoOutboundLaneApi_latest_generated_nonce";
|
||||
pub const TO_RIALTO_LATEST_GENERATED_NONCE_METHOD: &str =
|
||||
"ToRialtoOutboundLaneApi_latest_generated_nonce";
|
||||
/// Name of the `ToRialtoOutboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const TO_RIALTO_LATEST_RECEIVED_NONCE_METHOD: &str = "ToRialtoOutboundLaneApi_latest_received_nonce";
|
||||
pub const TO_RIALTO_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"ToRialtoOutboundLaneApi_latest_received_nonce";
|
||||
|
||||
/// Name of the `FromRialtoInboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const FROM_RIALTO_LATEST_RECEIVED_NONCE_METHOD: &str = "FromRialtoInboundLaneApi_latest_received_nonce";
|
||||
pub const FROM_RIALTO_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"FromRialtoInboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `FromRialtoInboundLaneApi::latest_onfirmed_nonce` runtime method.
|
||||
pub const FROM_RIALTO_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromRialtoInboundLaneApi_latest_confirmed_nonce";
|
||||
pub const FROM_RIALTO_LATEST_CONFIRMED_NONCE_METHOD: &str =
|
||||
"FromRialtoInboundLaneApi_latest_confirmed_nonce";
|
||||
/// Name of the `FromRialtoInboundLaneApi::unrewarded_relayers_state` runtime method.
|
||||
pub const FROM_RIALTO_UNREWARDED_RELAYERS_STATE: &str = "FromRialtoInboundLaneApi_unrewarded_relayers_state";
|
||||
pub const FROM_RIALTO_UNREWARDED_RELAYERS_STATE: &str =
|
||||
"FromRialtoInboundLaneApi_unrewarded_relayers_state";
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// API for querying information about the finalized Rialto headers.
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#![allow(clippy::unnecessary_mut_passed)]
|
||||
|
||||
use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState};
|
||||
use frame_support::weights::{Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial};
|
||||
use frame_support::weights::{
|
||||
Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
@@ -30,8 +32,8 @@ pub use bp_polkadot_core::*;
|
||||
/// Rococo Chain
|
||||
pub type Rococo = PolkadotLike;
|
||||
|
||||
/// The target length of a session (how often authorities change) on Westend measured in of number of
|
||||
/// blocks.
|
||||
/// The target length of a session (how often authorities change) on Westend measured in of number
|
||||
/// of blocks.
|
||||
///
|
||||
/// Note that since this is a target sessions may change before/after this time depending on network
|
||||
/// conditions.
|
||||
@@ -80,28 +82,36 @@ pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_fi
|
||||
/// Name of the `RococoFinalityApi::is_known_header` runtime method.
|
||||
pub const IS_KNOWN_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_is_known_header";
|
||||
|
||||
/// Name of the `ToRococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method.
|
||||
/// Name of the `ToRococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
|
||||
/// method.
|
||||
pub const TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str =
|
||||
"ToRococoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
|
||||
/// Name of the `ToRococoOutboundLaneApi::message_details` runtime method.
|
||||
pub const TO_ROCOCO_MESSAGE_DETAILS_METHOD: &str = "ToRococoOutboundLaneApi_message_details";
|
||||
/// Name of the `ToRococoOutboundLaneApi::latest_generated_nonce` runtime method.
|
||||
pub const TO_ROCOCO_LATEST_GENERATED_NONCE_METHOD: &str = "ToRococoOutboundLaneApi_latest_generated_nonce";
|
||||
pub const TO_ROCOCO_LATEST_GENERATED_NONCE_METHOD: &str =
|
||||
"ToRococoOutboundLaneApi_latest_generated_nonce";
|
||||
/// Name of the `ToRococoOutboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const TO_ROCOCO_LATEST_RECEIVED_NONCE_METHOD: &str = "ToRococoOutboundLaneApi_latest_received_nonce";
|
||||
pub const TO_ROCOCO_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"ToRococoOutboundLaneApi_latest_received_nonce";
|
||||
|
||||
/// Name of the `FromRococoInboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const FROM_ROCOCO_LATEST_RECEIVED_NONCE_METHOD: &str = "FromRococoInboundLaneApi_latest_received_nonce";
|
||||
pub const FROM_ROCOCO_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"FromRococoInboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `FromRococoInboundLaneApi::latest_onfirmed_nonce` runtime method.
|
||||
pub const FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromRococoInboundLaneApi_latest_confirmed_nonce";
|
||||
pub const FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str =
|
||||
"FromRococoInboundLaneApi_latest_confirmed_nonce";
|
||||
/// Name of the `FromRococoInboundLaneApi::unrewarded_relayers_state` runtime method.
|
||||
pub const FROM_ROCOCO_UNREWARDED_RELAYERS_STATE: &str = "FromRococoInboundLaneApi_unrewarded_relayers_state";
|
||||
pub const FROM_ROCOCO_UNREWARDED_RELAYERS_STATE: &str =
|
||||
"FromRococoInboundLaneApi_unrewarded_relayers_state";
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Rococo chain.
|
||||
///
|
||||
/// This value corresponds to the result of `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()`
|
||||
/// call for your chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery transactions cheaper.
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 600_000_000;
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
|
||||
use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState};
|
||||
use bp_runtime::Chain;
|
||||
use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial};
|
||||
use frame_support::weights::{
|
||||
WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
@@ -114,25 +116,31 @@ pub const BEST_FINALIZED_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_best_
|
||||
/// Name of the `WestendFinalityApi::is_known_header` runtime method.
|
||||
pub const IS_KNOWN_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_is_known_header";
|
||||
|
||||
/// Name of the `ToWestendOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method.
|
||||
/// Name of the `ToWestendOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
|
||||
/// method.
|
||||
pub const TO_WESTEND_ESTIMATE_MESSAGE_FEE_METHOD: &str =
|
||||
"ToWestendOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
|
||||
/// Name of the `ToWestendOutboundLaneApi::message_details` runtime method.
|
||||
pub const TO_WESTEND_MESSAGE_DETAILS_METHOD: &str = "ToWestendOutboundLaneApi_message_details";
|
||||
/// Name of the `ToWestendOutboundLaneApi::latest_generated_nonce` runtime method.
|
||||
pub const TO_WESTEND_LATEST_GENERATED_NONCE_METHOD: &str = "ToWestendOutboundLaneApi_latest_generated_nonce";
|
||||
pub const TO_WESTEND_LATEST_GENERATED_NONCE_METHOD: &str =
|
||||
"ToWestendOutboundLaneApi_latest_generated_nonce";
|
||||
/// Name of the `ToWestendOutboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const TO_WESTEND_LATEST_RECEIVED_NONCE_METHOD: &str = "ToWestendOutboundLaneApi_latest_received_nonce";
|
||||
pub const TO_WESTEND_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"ToWestendOutboundLaneApi_latest_received_nonce";
|
||||
|
||||
/// Name of the `FromWestendInboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const FROM_WESTEND_LATEST_RECEIVED_NONCE_METHOD: &str = "FromWestendInboundLaneApi_latest_received_nonce";
|
||||
pub const FROM_WESTEND_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"FromWestendInboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `FromWestendInboundLaneApi::latest_onfirmed_nonce` runtime method.
|
||||
pub const FROM_WESTEND_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromWestendInboundLaneApi_latest_confirmed_nonce";
|
||||
pub const FROM_WESTEND_LATEST_CONFIRMED_NONCE_METHOD: &str =
|
||||
"FromWestendInboundLaneApi_latest_confirmed_nonce";
|
||||
/// Name of the `FromWestendInboundLaneApi::unrewarded_relayers_state` runtime method.
|
||||
pub const FROM_WESTEND_UNREWARDED_RELAYERS_STATE: &str = "FromWestendInboundLaneApi_unrewarded_relayers_state";
|
||||
pub const FROM_WESTEND_UNREWARDED_RELAYERS_STATE: &str =
|
||||
"FromWestendInboundLaneApi_unrewarded_relayers_state";
|
||||
|
||||
/// The target length of a session (how often authorities change) on Westend measured in of number of
|
||||
/// blocks.
|
||||
/// The target length of a session (how often authorities change) on Westend measured in of number
|
||||
/// of blocks.
|
||||
///
|
||||
/// Note that since this is a target sessions may change before/after this time depending on network
|
||||
/// conditions.
|
||||
|
||||
@@ -45,22 +45,28 @@ pub const BEST_FINALIZED_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_best_fi
|
||||
/// Name of the `WococoFinalityApi::is_known_header` runtime method.
|
||||
pub const IS_KNOWN_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_is_known_header";
|
||||
|
||||
/// Name of the `ToWococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method.
|
||||
/// Name of the `ToWococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
|
||||
/// method.
|
||||
pub const TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str =
|
||||
"ToWococoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
|
||||
/// Name of the `ToWococoOutboundLaneApi::message_details` runtime method.
|
||||
pub const TO_WOCOCO_MESSAGE_DETAILS_METHOD: &str = "ToWococoOutboundLaneApi_message_details";
|
||||
/// Name of the `ToWococoOutboundLaneApi::latest_generated_nonce` runtime method.
|
||||
pub const TO_WOCOCO_LATEST_GENERATED_NONCE_METHOD: &str = "ToWococoOutboundLaneApi_latest_generated_nonce";
|
||||
pub const TO_WOCOCO_LATEST_GENERATED_NONCE_METHOD: &str =
|
||||
"ToWococoOutboundLaneApi_latest_generated_nonce";
|
||||
/// Name of the `ToWococoOutboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const TO_WOCOCO_LATEST_RECEIVED_NONCE_METHOD: &str = "ToWococoOutboundLaneApi_latest_received_nonce";
|
||||
pub const TO_WOCOCO_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"ToWococoOutboundLaneApi_latest_received_nonce";
|
||||
|
||||
/// Name of the `FromWococoInboundLaneApi::latest_received_nonce` runtime method.
|
||||
pub const FROM_WOCOCO_LATEST_RECEIVED_NONCE_METHOD: &str = "FromWococoInboundLaneApi_latest_received_nonce";
|
||||
pub const FROM_WOCOCO_LATEST_RECEIVED_NONCE_METHOD: &str =
|
||||
"FromWococoInboundLaneApi_latest_received_nonce";
|
||||
/// Name of the `FromWococoInboundLaneApi::latest_onfirmed_nonce` runtime method.
|
||||
pub const FROM_WOCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromWococoInboundLaneApi_latest_confirmed_nonce";
|
||||
pub const FROM_WOCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str =
|
||||
"FromWococoInboundLaneApi_latest_confirmed_nonce";
|
||||
/// Name of the `FromWococoInboundLaneApi::unrewarded_relayers_state` runtime method.
|
||||
pub const FROM_WOCOCO_UNREWARDED_RELAYERS_STATE: &str = "FromWococoInboundLaneApi_unrewarded_relayers_state";
|
||||
pub const FROM_WOCOCO_UNREWARDED_RELAYERS_STATE: &str =
|
||||
"FromWococoInboundLaneApi_unrewarded_relayers_state";
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// API for querying information about the finalized Wococo headers.
|
||||
|
||||
@@ -71,7 +71,9 @@ pub trait MaybeLockFundsTransaction {
|
||||
|
||||
/// Parse lock funds transaction of the peer blockchain. Returns None if
|
||||
/// transaction format is unknown, or it isn't a lock funds transaction.
|
||||
fn parse(tx: &Self::Transaction) -> Result<LockFundsTransaction<Self::Id, Self::Recipient, Self::Amount>>;
|
||||
fn parse(
|
||||
tx: &Self::Transaction,
|
||||
) -> Result<LockFundsTransaction<Self::Id, Self::Recipient, Self::Amount>>;
|
||||
}
|
||||
|
||||
/// Map that maps recipients from peer blockchain to this blockchain recipients.
|
||||
|
||||
@@ -185,10 +185,7 @@ pub struct SealedEmptyStep {
|
||||
impl AuraHeader {
|
||||
/// Compute id of this header.
|
||||
pub fn compute_id(&self) -> HeaderId {
|
||||
HeaderId {
|
||||
number: self.number,
|
||||
hash: self.compute_hash(),
|
||||
}
|
||||
HeaderId { number: self.number, hash: self.compute_hash() }
|
||||
}
|
||||
|
||||
/// Compute hash of this header (keccak of the RLP with seal).
|
||||
@@ -198,10 +195,9 @@ impl AuraHeader {
|
||||
|
||||
/// Get id of this header' parent. Returns None if this is genesis header.
|
||||
pub fn parent_id(&self) -> Option<HeaderId> {
|
||||
self.number.checked_sub(1).map(|parent_number| HeaderId {
|
||||
number: parent_number,
|
||||
hash: self.parent_hash,
|
||||
})
|
||||
self.number
|
||||
.checked_sub(1)
|
||||
.map(|parent_number| HeaderId { number: parent_number, hash: self.parent_hash })
|
||||
}
|
||||
|
||||
/// Check if passed transactions receipts are matching receipts root in this header.
|
||||
@@ -238,7 +234,7 @@ impl AuraHeader {
|
||||
let mut message = self.compute_hash().as_bytes().to_vec();
|
||||
message.extend_from_slice(self.seal.get(2)?);
|
||||
keccak_256(&message).into()
|
||||
}
|
||||
},
|
||||
false => keccak_256(&self.rlp(false)).into(),
|
||||
})
|
||||
}
|
||||
@@ -255,9 +251,7 @@ impl AuraHeader {
|
||||
|
||||
/// Extracts the empty steps from the header seal.
|
||||
pub fn empty_steps(&self) -> Option<Vec<SealedEmptyStep>> {
|
||||
self.seal
|
||||
.get(2)
|
||||
.and_then(|x| Rlp::new(x).as_list::<SealedEmptyStep>().ok())
|
||||
self.seal.get(2).and_then(|x| Rlp::new(x).as_list::<SealedEmptyStep>().ok())
|
||||
}
|
||||
|
||||
/// Returns header RLP with or without seals.
|
||||
@@ -368,15 +362,15 @@ impl Receipt {
|
||||
match self.outcome {
|
||||
TransactionOutcome::Unknown => {
|
||||
s.begin_list(3);
|
||||
}
|
||||
},
|
||||
TransactionOutcome::StateRoot(ref root) => {
|
||||
s.begin_list(4);
|
||||
s.append(root);
|
||||
}
|
||||
},
|
||||
TransactionOutcome::StatusCode(ref status_code) => {
|
||||
s.begin_list(4);
|
||||
s.append(status_code);
|
||||
}
|
||||
},
|
||||
}
|
||||
s.append(&self.gas_used);
|
||||
s.append(&EthBloom::from(self.log_bloom.0));
|
||||
@@ -428,13 +422,13 @@ impl Decodable for SealedEmptyStep {
|
||||
impl LogEntry {
|
||||
/// Calculates the bloom of this log entry.
|
||||
pub fn bloom(&self) -> Bloom {
|
||||
let eth_bloom =
|
||||
self.topics
|
||||
.iter()
|
||||
.fold(EthBloom::from(BloomInput::Raw(self.address.as_bytes())), |mut b, t| {
|
||||
b.accrue(BloomInput::Raw(t.as_bytes()));
|
||||
b
|
||||
});
|
||||
let eth_bloom = self.topics.iter().fold(
|
||||
EthBloom::from(BloomInput::Raw(self.address.as_bytes())),
|
||||
|mut b, t| {
|
||||
b.accrue(BloomInput::Raw(t.as_bytes()));
|
||||
b
|
||||
},
|
||||
);
|
||||
Bloom(*eth_bloom.data())
|
||||
}
|
||||
}
|
||||
@@ -498,14 +492,12 @@ pub fn transaction_decode_rlp(raw_tx: &[u8]) -> Result<Transaction, DecoderError
|
||||
let message = unsigned.message(chain_id);
|
||||
|
||||
// recover tx sender
|
||||
let sender_public = sp_io::crypto::secp256k1_ecdsa_recover(&signature, message.as_fixed_bytes())
|
||||
.map_err(|_| rlp::DecoderError::Custom("Failed to recover transaction sender"))?;
|
||||
let sender_public =
|
||||
sp_io::crypto::secp256k1_ecdsa_recover(&signature, message.as_fixed_bytes())
|
||||
.map_err(|_| rlp::DecoderError::Custom("Failed to recover transaction sender"))?;
|
||||
let sender_address = public_to_address(&sender_public);
|
||||
|
||||
Ok(Transaction {
|
||||
sender: sender_address,
|
||||
unsigned,
|
||||
})
|
||||
Ok(Transaction { sender: sender_address, unsigned })
|
||||
}
|
||||
|
||||
/// Convert public key into corresponding ethereum address.
|
||||
@@ -519,7 +511,10 @@ pub fn public_to_address(public: &[u8; 64]) -> Address {
|
||||
/// Check ethereum merkle proof.
|
||||
/// Returns Ok(computed-root) if check succeeds.
|
||||
/// Returns Err(computed-root) if check fails.
|
||||
fn check_merkle_proof<T: AsRef<[u8]>>(expected_root: H256, items: impl Iterator<Item = T>) -> Result<H256, H256> {
|
||||
fn check_merkle_proof<T: AsRef<[u8]>>(
|
||||
expected_root: H256,
|
||||
items: impl Iterator<Item = T>,
|
||||
) -> Result<H256, H256> {
|
||||
let computed_root = compute_merkle_root(items);
|
||||
if computed_root == expected_root {
|
||||
Ok(computed_root)
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
pub use secp256k1::SecretKey;
|
||||
|
||||
use crate::{
|
||||
public_to_address, rlp_encode, step_validator, Address, AuraHeader, RawTransaction, UnsignedTransaction, H256,
|
||||
H520, U256,
|
||||
public_to_address, rlp_encode, step_validator, Address, AuraHeader, RawTransaction,
|
||||
UnsignedTransaction, H256, H520, U256,
|
||||
};
|
||||
|
||||
use secp256k1::{Message, PublicKey};
|
||||
@@ -80,7 +80,8 @@ impl SignTransaction for UnsignedTransaction {
|
||||
|
||||
/// Return author's signature over given message.
|
||||
pub fn sign(author: &SecretKey, message: H256) -> H520 {
|
||||
let (signature, recovery_id) = secp256k1::sign(&Message::parse(message.as_fixed_bytes()), author);
|
||||
let (signature, recovery_id) =
|
||||
secp256k1::sign(&Message::parse(message.as_fixed_bytes()), author);
|
||||
let mut raw_signature = [0u8; 65];
|
||||
raw_signature[..64].copy_from_slice(&signature.serialize());
|
||||
raw_signature[64] = recovery_id.serialize();
|
||||
@@ -116,10 +117,7 @@ mod tests {
|
||||
let raw_tx = unsigned.clone().sign_by(&signer, Some(42));
|
||||
assert_eq!(
|
||||
transaction_decode_rlp(&raw_tx),
|
||||
Ok(Transaction {
|
||||
sender: signer_address,
|
||||
unsigned,
|
||||
}),
|
||||
Ok(Transaction { sender: signer_address, unsigned }),
|
||||
);
|
||||
|
||||
// case2: without chain_id replay protection + contract creation
|
||||
@@ -134,10 +132,7 @@ mod tests {
|
||||
let raw_tx = unsigned.clone().sign_by(&signer, None);
|
||||
assert_eq!(
|
||||
transaction_decode_rlp(&raw_tx),
|
||||
Ok(Transaction {
|
||||
sender: signer_address,
|
||||
unsigned,
|
||||
}),
|
||||
Ok(Transaction { sender: signer_address, unsigned }),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ use finality_grandpa::voter_set::VoterSet;
|
||||
use frame_support::RuntimeDebug;
|
||||
use sp_finality_grandpa::{AuthorityId, AuthoritySignature, SetId};
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
|
||||
use sp_std::prelude::*;
|
||||
use sp_std::{
|
||||
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
/// A GRANDPA Justification is a proof that a given header was finalized
|
||||
/// at a certain height and with a certain set of authorities.
|
||||
@@ -37,7 +39,8 @@ pub struct GrandpaJustification<Header: HeaderT> {
|
||||
/// The round (voting period) this justification is valid for.
|
||||
pub round: u64,
|
||||
/// The set of votes for the chain which is to be finalized.
|
||||
pub commit: finality_grandpa::Commit<Header::Hash, Header::Number, AuthoritySignature, AuthorityId>,
|
||||
pub commit:
|
||||
finality_grandpa::Commit<Header::Hash, Header::Number, AuthoritySignature, AuthorityId>,
|
||||
/// A proof that the chain of blocks in the commit are related to each other.
|
||||
pub votes_ancestries: Vec<Header>,
|
||||
}
|
||||
@@ -57,7 +60,8 @@ pub enum Error {
|
||||
InvalidJustificationTarget,
|
||||
/// The authority has provided an invalid signature.
|
||||
InvalidAuthoritySignature,
|
||||
/// The justification contains precommit for header that is not a descendant of the commit header.
|
||||
/// The justification contains precommit for header that is not a descendant of the commit
|
||||
/// header.
|
||||
PrecommitIsNotCommitDescendant,
|
||||
/// The cumulative weight of all votes in the justification is not enough to justify commit
|
||||
/// header finalization.
|
||||
@@ -87,7 +91,7 @@ where
|
||||
{
|
||||
// ensure that it is justification for the expected header
|
||||
if (justification.commit.target_hash, justification.commit.target_number) != finalized_target {
|
||||
return Err(Error::InvalidJustificationTarget);
|
||||
return Err(Error::InvalidJustificationTarget)
|
||||
}
|
||||
|
||||
let mut chain = AncestryChain::new(&justification.votes_ancestries);
|
||||
@@ -99,30 +103,32 @@ where
|
||||
let authority_info = match authorities_set.get(&signed.id) {
|
||||
Some(authority_info) => authority_info,
|
||||
None => {
|
||||
// just ignore precommit from unknown authority as `finality_grandpa::import_precommit` does
|
||||
continue;
|
||||
}
|
||||
// just ignore precommit from unknown authority as
|
||||
// `finality_grandpa::import_precommit` does
|
||||
continue
|
||||
},
|
||||
};
|
||||
|
||||
// check if authority has already voted in the same round.
|
||||
//
|
||||
// there's a lot of code in `validate_commit` and `import_precommit` functions inside
|
||||
// `finality-grandpa` crate (mostly related to reporing equivocations). But the only thing that we
|
||||
// care about is that only first vote from the authority is accepted
|
||||
// `finality-grandpa` crate (mostly related to reporing equivocations). But the only thing
|
||||
// that we care about is that only first vote from the authority is accepted
|
||||
if !votes.insert(signed.id.clone()) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
// everything below this line can't just `continue`, because state is already altered
|
||||
|
||||
// all precommits must be for block higher than the target
|
||||
if signed.precommit.target_number < justification.commit.target_number {
|
||||
return Err(Error::PrecommitIsNotCommitDescendant);
|
||||
return Err(Error::PrecommitIsNotCommitDescendant)
|
||||
}
|
||||
// all precommits must be for target block descendents
|
||||
chain = chain.ensure_descendant(&justification.commit.target_hash, &signed.precommit.target_hash)?;
|
||||
// since we know now that the precommit target is the descendant of the justification target,
|
||||
// we may increase 'weight' of the justification target
|
||||
chain = chain
|
||||
.ensure_descendant(&justification.commit.target_hash, &signed.precommit.target_hash)?;
|
||||
// since we know now that the precommit target is the descendant of the justification
|
||||
// target, we may increase 'weight' of the justification target
|
||||
//
|
||||
// there's a lot of code in the `VoteGraph::insert` method inside `finality-grandpa` crate,
|
||||
// but in the end it is only used to find GHOST, which we don't care about. The only thing
|
||||
@@ -144,13 +150,13 @@ where
|
||||
authorities_set_id,
|
||||
&mut signature_buffer,
|
||||
) {
|
||||
return Err(Error::InvalidAuthoritySignature);
|
||||
return Err(Error::InvalidAuthoritySignature)
|
||||
}
|
||||
}
|
||||
|
||||
// check that there are no extra headers in the justification
|
||||
if !chain.unvisited.is_empty() {
|
||||
return Err(Error::ExtraHeadersInVotesAncestries);
|
||||
return Err(Error::ExtraHeadersInVotesAncestries)
|
||||
}
|
||||
|
||||
// check that the cumulative weight of validators voted for the justification target (or one
|
||||
@@ -186,7 +192,8 @@ impl<Header: HeaderT> AncestryChain<Header> {
|
||||
AncestryChain { parents, unvisited }
|
||||
}
|
||||
|
||||
/// Returns `Err(_)` if `precommit_target` is a descendant of the `commit_target` block and `Ok(_)` otherwise.
|
||||
/// Returns `Err(_)` if `precommit_target` is a descendant of the `commit_target` block and
|
||||
/// `Ok(_)` otherwise.
|
||||
pub fn ensure_descendant(
|
||||
mut self,
|
||||
commit_target: &Header::Hash,
|
||||
@@ -195,22 +202,22 @@ impl<Header: HeaderT> AncestryChain<Header> {
|
||||
let mut current_hash = *precommit_target;
|
||||
loop {
|
||||
if current_hash == *commit_target {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
let is_visited_before = !self.unvisited.remove(¤t_hash);
|
||||
current_hash = match self.parents.get(¤t_hash) {
|
||||
Some(parent_hash) => {
|
||||
if is_visited_before {
|
||||
// `Some(parent_hash)` means that the `current_hash` is in the `parents` container
|
||||
// `is_visited_before` means that it has been visited before in some of previous calls
|
||||
// => since we assume that previous call has finished with `true`, this also will
|
||||
// be finished with `true`
|
||||
return Ok(self);
|
||||
// `Some(parent_hash)` means that the `current_hash` is in the `parents`
|
||||
// container `is_visited_before` means that it has been visited before in
|
||||
// some of previous calls => since we assume that previous call has finished
|
||||
// with `true`, this also will be finished with `true`
|
||||
return Ok(self)
|
||||
}
|
||||
|
||||
*parent_hash
|
||||
}
|
||||
},
|
||||
None => return Err(Error::PrecommitIsNotCommitDescendant),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,15 +20,11 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use codec::{Codec, Decode, Encode, EncodeLike};
|
||||
use core::clone::Clone;
|
||||
use core::cmp::Eq;
|
||||
use core::default::Default;
|
||||
use core::fmt::Debug;
|
||||
use core::{clone::Clone, cmp::Eq, default::Default, fmt::Debug};
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sp_finality_grandpa::{AuthorityList, ConsensusLog, SetId, GRANDPA_ENGINE_ID};
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_runtime::{generic::OpaqueDigestItemId, traits::Header as HeaderT};
|
||||
use sp_runtime::{generic::OpaqueDigestItemId, traits::Header as HeaderT, RuntimeDebug};
|
||||
use sp_std::boxed::Box;
|
||||
|
||||
pub mod justification;
|
||||
@@ -82,7 +78,9 @@ pub trait InclusionProofVerifier {
|
||||
/// Verify that transaction is a part of given block.
|
||||
///
|
||||
/// Returns Some(transaction) if proof is valid and None otherwise.
|
||||
fn verify_transaction_inclusion_proof(proof: &Self::TransactionInclusionProof) -> Option<Self::Transaction>;
|
||||
fn verify_transaction_inclusion_proof(
|
||||
proof: &Self::TransactionInclusionProof,
|
||||
) -> Option<Self::Transaction>;
|
||||
}
|
||||
|
||||
/// A trait for pallets which want to keep track of finalized headers from a bridged chain.
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
use assert_matches::assert_matches;
|
||||
use bp_header_chain::justification::{verify_justification, Error, GrandpaJustification};
|
||||
use bp_test_utils::{
|
||||
header_id, make_justification_for_header, signed_precommit, test_header, Account, JustificationGeneratorParams,
|
||||
ALICE, BOB, CHARLIE, DAVE, EVE, TEST_GRANDPA_SET_ID,
|
||||
header_id, make_justification_for_header, signed_precommit, test_header, Account,
|
||||
JustificationGeneratorParams, ALICE, BOB, CHARLIE, DAVE, EVE, TEST_GRANDPA_SET_ID,
|
||||
};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use sp_finality_grandpa::{AuthorityId, AuthorityWeight};
|
||||
@@ -44,18 +44,22 @@ impl AncestryChain {
|
||||
}
|
||||
|
||||
impl finality_grandpa::Chain<TestHash, TestNumber> for AncestryChain {
|
||||
fn ancestry(&self, base: TestHash, block: TestHash) -> Result<Vec<TestHash>, finality_grandpa::Error> {
|
||||
fn ancestry(
|
||||
&self,
|
||||
base: TestHash,
|
||||
block: TestHash,
|
||||
) -> Result<Vec<TestHash>, finality_grandpa::Error> {
|
||||
let mut route = Vec::new();
|
||||
let mut current_hash = block;
|
||||
loop {
|
||||
if current_hash == base {
|
||||
break;
|
||||
break
|
||||
}
|
||||
match self.0.parents.get(¤t_hash).cloned() {
|
||||
Some(parent_hash) => {
|
||||
current_hash = parent_hash;
|
||||
route.push(current_hash);
|
||||
}
|
||||
},
|
||||
_ => return Err(finality_grandpa::Error::NotDescendent),
|
||||
}
|
||||
}
|
||||
@@ -81,14 +85,11 @@ fn minimal_accounts_set() -> Vec<(Account, AuthorityWeight)> {
|
||||
vec![(ALICE, 1), (BOB, 1), (CHARLIE, 1), (DAVE, 1)]
|
||||
}
|
||||
|
||||
/// Get a minimal subset of GRANDPA authorities that have enough cumulative vote weight to justify a header finality.
|
||||
/// Get a minimal subset of GRANDPA authorities that have enough cumulative vote weight to justify a
|
||||
/// header finality.
|
||||
pub fn minimal_voter_set() -> VoterSet<AuthorityId> {
|
||||
VoterSet::new(
|
||||
minimal_accounts_set()
|
||||
.iter()
|
||||
.map(|(id, w)| (AuthorityId::from(*id), *w)),
|
||||
)
|
||||
.unwrap()
|
||||
VoterSet::new(minimal_accounts_set().iter().map(|(id, w)| (AuthorityId::from(*id), *w)))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Make a valid GRANDPA justification with sensible defaults.
|
||||
@@ -174,14 +175,8 @@ fn same_result_when_justification_contains_duplicate_vote() {
|
||||
let mut justification = make_default_justification(&test_header(1));
|
||||
// the justification may contain exactly the same vote (i.e. same precommit and same signature)
|
||||
// multiple times && it isn't treated as an error by original implementation
|
||||
justification
|
||||
.commit
|
||||
.precommits
|
||||
.push(justification.commit.precommits[0].clone());
|
||||
justification
|
||||
.commit
|
||||
.precommits
|
||||
.push(justification.commit.precommits[0].clone());
|
||||
justification.commit.precommits.push(justification.commit.precommits[0].clone());
|
||||
justification.commit.precommits.push(justification.commit.precommits[0].clone());
|
||||
|
||||
// our implementation succeeds
|
||||
assert_eq!(
|
||||
|
||||
@@ -112,7 +112,12 @@ pub enum CallOrigin<SourceChainAccountId, TargetChainAccountPublic, TargetChainS
|
||||
|
||||
/// Message payload type used by dispatch module.
|
||||
#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)]
|
||||
pub struct MessagePayload<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Call> {
|
||||
pub struct MessagePayload<
|
||||
SourceChainAccountId,
|
||||
TargetChainAccountPublic,
|
||||
TargetChainSignature,
|
||||
Call,
|
||||
> {
|
||||
/// Runtime specification version. We only dispatch messages that have the same
|
||||
/// runtime version. Otherwise we risk to misinterpret encoded calls.
|
||||
pub spec_version: SpecVersion,
|
||||
|
||||
@@ -110,22 +110,23 @@ pub struct Message<Fee> {
|
||||
/// Inbound lane data.
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)]
|
||||
pub struct InboundLaneData<RelayerId> {
|
||||
/// Identifiers of relayers and messages that they have delivered to this lane (ordered by message nonce).
|
||||
/// Identifiers of relayers and messages that they have delivered to this lane (ordered by
|
||||
/// message nonce).
|
||||
///
|
||||
/// This serves as a helper storage item, to allow the source chain to easily pay rewards
|
||||
/// to the relayers who successfully delivered messages to the target chain (inbound lane).
|
||||
///
|
||||
/// It is guaranteed to have at most N entries, where N is configured at the module level.
|
||||
/// If there are N entries in this vec, then:
|
||||
/// 1) all incoming messages are rejected if they're missing corresponding `proof-of(outbound-lane.state)`;
|
||||
/// 2) all incoming messages are rejected if `proof-of(outbound-lane.state).last_delivered_nonce` is
|
||||
/// equal to `self.last_confirmed_nonce`.
|
||||
/// Given what is said above, all nonces in this queue are in range:
|
||||
/// `(self.last_confirmed_nonce; self.last_delivered_nonce()]`.
|
||||
/// 1) all incoming messages are rejected if they're missing corresponding
|
||||
/// `proof-of(outbound-lane.state)`; 2) all incoming messages are rejected if
|
||||
/// `proof-of(outbound-lane.state).last_delivered_nonce` is equal to
|
||||
/// `self.last_confirmed_nonce`. Given what is said above, all nonces in this queue are in
|
||||
/// range: `(self.last_confirmed_nonce; self.last_delivered_nonce()]`.
|
||||
///
|
||||
/// When a relayer sends a single message, both of MessageNonces are the same.
|
||||
/// When relayer sends messages in a batch, the first arg is the lowest nonce, second arg the highest nonce.
|
||||
/// Multiple dispatches from the same relayer are allowed.
|
||||
/// When relayer sends messages in a batch, the first arg is the lowest nonce, second arg the
|
||||
/// highest nonce. Multiple dispatches from the same relayer are allowed.
|
||||
pub relayers: VecDeque<UnrewardedRelayer<RelayerId>>,
|
||||
|
||||
/// Nonce of the last message that
|
||||
@@ -141,10 +142,7 @@ pub struct InboundLaneData<RelayerId> {
|
||||
|
||||
impl<RelayerId> Default for InboundLaneData<RelayerId> {
|
||||
fn default() -> Self {
|
||||
InboundLaneData {
|
||||
relayers: VecDeque::new(),
|
||||
last_confirmed_nonce: 0,
|
||||
}
|
||||
InboundLaneData { relayers: VecDeque::new(), last_confirmed_nonce: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,12 +151,17 @@ impl<RelayerId> InboundLaneData<RelayerId> {
|
||||
/// size of each entry.
|
||||
///
|
||||
/// Returns `None` if size overflows `u32` limits.
|
||||
pub fn encoded_size_hint(relayer_id_encoded_size: u32, relayers_entries: u32, messages_count: u32) -> Option<u32> {
|
||||
pub fn encoded_size_hint(
|
||||
relayer_id_encoded_size: u32,
|
||||
relayers_entries: u32,
|
||||
messages_count: u32,
|
||||
) -> Option<u32> {
|
||||
let message_nonce_size = 8;
|
||||
let relayers_entry_size = relayer_id_encoded_size.checked_add(2 * message_nonce_size)?;
|
||||
let relayers_size = relayers_entries.checked_mul(relayers_entry_size)?;
|
||||
let dispatch_results_per_byte = 8;
|
||||
let dispatch_result_size = sp_std::cmp::max(relayers_entries, messages_count / dispatch_results_per_byte);
|
||||
let dispatch_result_size =
|
||||
sp_std::cmp::max(relayers_entries, messages_count / dispatch_results_per_byte);
|
||||
relayers_size
|
||||
.checked_add(message_nonce_size)
|
||||
.and_then(|result| result.checked_add(dispatch_result_size))
|
||||
@@ -193,8 +196,8 @@ pub type DispatchResultsBitVec = BitVec<Msb0, u8>;
|
||||
|
||||
/// Unrewarded relayer entry stored in the inbound lane data.
|
||||
///
|
||||
/// This struct represents a continuous range of messages that have been delivered by the same relayer
|
||||
/// and whose confirmations are still pending.
|
||||
/// This struct represents a continuous range of messages that have been delivered by the same
|
||||
/// relayer and whose confirmations are still pending.
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)]
|
||||
pub struct UnrewardedRelayer<RelayerId> {
|
||||
/// Identifier of the relayer.
|
||||
@@ -217,7 +220,8 @@ pub struct DeliveredMessages {
|
||||
}
|
||||
|
||||
impl DeliveredMessages {
|
||||
/// Create new `DeliveredMessages` struct that confirms delivery of single nonce with given dispatch result.
|
||||
/// Create new `DeliveredMessages` struct that confirms delivery of single nonce with given
|
||||
/// dispatch result.
|
||||
pub fn new(nonce: MessageNonce, dispatch_result: bool) -> Self {
|
||||
DeliveredMessages {
|
||||
begin: nonce,
|
||||
@@ -277,8 +281,8 @@ pub struct UnrewardedRelayersState {
|
||||
/// Outbound lane data.
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)]
|
||||
pub struct OutboundLaneData {
|
||||
/// Nonce of the oldest message that we haven't yet pruned. May point to not-yet-generated message if
|
||||
/// all sent messages are already pruned.
|
||||
/// Nonce of the oldest message that we haven't yet pruned. May point to not-yet-generated
|
||||
/// message if all sent messages are already pruned.
|
||||
pub oldest_unpruned_nonce: MessageNonce,
|
||||
/// Nonce of the latest message, received by bridged chain.
|
||||
pub latest_received_nonce: MessageNonce,
|
||||
@@ -289,7 +293,8 @@ pub struct OutboundLaneData {
|
||||
impl Default for OutboundLaneData {
|
||||
fn default() -> Self {
|
||||
OutboundLaneData {
|
||||
// it is 1 because we're pruning everything in [oldest_unpruned_nonce; latest_received_nonce]
|
||||
// it is 1 because we're pruning everything in [oldest_unpruned_nonce;
|
||||
// latest_received_nonce]
|
||||
oldest_unpruned_nonce: 1,
|
||||
latest_received_nonce: 0,
|
||||
latest_generated_nonce: 0,
|
||||
@@ -300,7 +305,9 @@ impl Default for OutboundLaneData {
|
||||
/// Returns total number of messages in the `InboundLaneData::relayers` vector.
|
||||
///
|
||||
/// Returns `None` if there are more messages that `MessageNonce` may fit (i.e. `MessageNonce + 1`).
|
||||
pub fn total_unrewarded_messages<RelayerId>(relayers: &VecDeque<UnrewardedRelayer<RelayerId>>) -> Option<MessageNonce> {
|
||||
pub fn total_unrewarded_messages<RelayerId>(
|
||||
relayers: &VecDeque<UnrewardedRelayer<RelayerId>>,
|
||||
) -> Option<MessageNonce> {
|
||||
match (relayers.front(), relayers.back()) {
|
||||
(Some(front), Some(back)) => {
|
||||
if let Some(difference) = back.messages.end.checked_sub(front.messages.begin) {
|
||||
@@ -308,7 +315,7 @@ pub fn total_unrewarded_messages<RelayerId>(relayers: &VecDeque<UnrewardedRelaye
|
||||
} else {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => Some(0),
|
||||
}
|
||||
}
|
||||
@@ -322,10 +329,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
total_unrewarded_messages(
|
||||
&vec![
|
||||
UnrewardedRelayer {
|
||||
relayer: 1,
|
||||
messages: DeliveredMessages::new(0, true)
|
||||
},
|
||||
UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0, true) },
|
||||
UnrewardedRelayer {
|
||||
relayer: 2,
|
||||
messages: DeliveredMessages::new(MessageNonce::MAX, true)
|
||||
@@ -349,7 +353,11 @@ mod tests {
|
||||
(13u8, 128u8),
|
||||
];
|
||||
for (relayer_entries, messages_count) in test_cases {
|
||||
let expected_size = InboundLaneData::<u8>::encoded_size_hint(1, relayer_entries as _, messages_count as _);
|
||||
let expected_size = InboundLaneData::<u8>::encoded_size_hint(
|
||||
1,
|
||||
relayer_entries as _,
|
||||
messages_count as _,
|
||||
);
|
||||
let actual_size = InboundLaneData {
|
||||
relayers: (1u8..=relayer_entries)
|
||||
.map(|i| {
|
||||
@@ -383,11 +391,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn message_dispatch_result_works() {
|
||||
let delivered_messages = DeliveredMessages {
|
||||
begin: 100,
|
||||
end: 150,
|
||||
dispatch_results: bitvec![Msb0, u8; 1; 151],
|
||||
};
|
||||
let delivered_messages =
|
||||
DeliveredMessages { begin: 100, end: 150, dispatch_results: bitvec![Msb0, u8; 1; 151] };
|
||||
|
||||
assert!(!delivered_messages.contains_message(99));
|
||||
assert!(delivered_messages.contains_message(100));
|
||||
|
||||
@@ -81,7 +81,8 @@ pub trait LaneMessageVerifier<Submitter, Payload, Fee> {
|
||||
/// Error type.
|
||||
type Error: Debug + Into<&'static str>;
|
||||
|
||||
/// Verify message payload and return Ok(()) if message is valid and allowed to be sent over the lane.
|
||||
/// Verify message payload and return Ok(()) if message is valid and allowed to be sent over the
|
||||
/// lane.
|
||||
fn verify_message(
|
||||
submitter: &Sender<Submitter>,
|
||||
delivery_and_dispatch_fee: &Fee,
|
||||
@@ -190,7 +191,8 @@ impl OnMessageAccepted for () {
|
||||
pub struct ForbidOutboundMessages;
|
||||
|
||||
/// Error message that is used in `ForbidOutboundMessages` implementation.
|
||||
const ALL_OUTBOUND_MESSAGES_REJECTED: &str = "This chain is configured to reject all outbound messages";
|
||||
const ALL_OUTBOUND_MESSAGES_REJECTED: &str =
|
||||
"This chain is configured to reject all outbound messages";
|
||||
|
||||
impl<Payload, AccountId> TargetHeaderChain<Payload, AccountId> for ForbidOutboundMessages {
|
||||
type Error = &'static str;
|
||||
@@ -208,7 +210,9 @@ impl<Payload, AccountId> TargetHeaderChain<Payload, AccountId> for ForbidOutboun
|
||||
}
|
||||
}
|
||||
|
||||
impl<Submitter, Payload, Fee> LaneMessageVerifier<Submitter, Payload, Fee> for ForbidOutboundMessages {
|
||||
impl<Submitter, Payload, Fee> LaneMessageVerifier<Submitter, Payload, Fee>
|
||||
for ForbidOutboundMessages
|
||||
{
|
||||
type Error = &'static str;
|
||||
|
||||
fn verify_message(
|
||||
@@ -222,7 +226,9 @@ impl<Submitter, Payload, Fee> LaneMessageVerifier<Submitter, Payload, Fee> for F
|
||||
}
|
||||
}
|
||||
|
||||
impl<AccountId, Balance> MessageDeliveryAndDispatchPayment<AccountId, Balance> for ForbidOutboundMessages {
|
||||
impl<AccountId, Balance> MessageDeliveryAndDispatchPayment<AccountId, Balance>
|
||||
for ForbidOutboundMessages
|
||||
{
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
|
||||
@@ -111,23 +111,19 @@ pub trait MessageDispatch<AccountId, Fee> {
|
||||
|
||||
impl<Message> Default for ProvedLaneMessages<Message> {
|
||||
fn default() -> Self {
|
||||
ProvedLaneMessages {
|
||||
lane_state: None,
|
||||
messages: Vec::new(),
|
||||
}
|
||||
ProvedLaneMessages { lane_state: None, messages: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<DispatchPayload: Decode, Fee> From<Message<Fee>> for DispatchMessage<DispatchPayload, Fee> {
|
||||
fn from(message: Message<Fee>) -> Self {
|
||||
DispatchMessage {
|
||||
key: message.key,
|
||||
data: message.data.into(),
|
||||
}
|
||||
DispatchMessage { key: message.key, data: message.data.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<DispatchPayload: Decode, Fee> From<MessageData<Fee>> for DispatchMessageData<DispatchPayload, Fee> {
|
||||
impl<DispatchPayload: Decode, Fee> From<MessageData<Fee>>
|
||||
for DispatchMessageData<DispatchPayload, Fee>
|
||||
{
|
||||
fn from(data: MessageData<Fee>) -> Self {
|
||||
DispatchMessageData {
|
||||
payload: DispatchPayload::decode(&mut &data.payload[..]),
|
||||
@@ -141,7 +137,8 @@ impl<DispatchPayload: Decode, Fee> From<MessageData<Fee>> for DispatchMessageDat
|
||||
pub struct ForbidInboundMessages;
|
||||
|
||||
/// Error message that is used in `ForbidOutboundMessages` implementation.
|
||||
const ALL_INBOUND_MESSAGES_REJECTED: &str = "This chain is configured to reject all inbound messages";
|
||||
const ALL_INBOUND_MESSAGES_REJECTED: &str =
|
||||
"This chain is configured to reject all inbound messages";
|
||||
|
||||
impl<Fee> SourceHeaderChain<Fee> for ForbidInboundMessages {
|
||||
type Error = &'static str;
|
||||
@@ -162,7 +159,10 @@ impl<AccountId, Fee> MessageDispatch<AccountId, Fee> for ForbidInboundMessages {
|
||||
Weight::MAX
|
||||
}
|
||||
|
||||
fn dispatch(_: &AccountId, _: DispatchMessage<Self::DispatchPayload, Fee>) -> MessageDispatchResult {
|
||||
fn dispatch(
|
||||
_: &AccountId,
|
||||
_: DispatchMessage<Self::DispatchPayload, Fee>,
|
||||
) -> MessageDispatchResult {
|
||||
MessageDispatchResult {
|
||||
dispatch_result: false,
|
||||
unspent_weight: 0,
|
||||
|
||||
@@ -76,8 +76,9 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
|
||||
/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
|
||||
pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND;
|
||||
|
||||
/// All Polkadot-like chains assume that an on-initialize consumes 1 percent of the weight on average,
|
||||
/// hence a single extrinsic will not be allowed to consume more than `AvailableBlockRatio - 1 percent`.
|
||||
/// All Polkadot-like chains assume that an on-initialize consumes 1 percent of the weight on
|
||||
/// average, hence a single extrinsic will not be allowed to consume more than
|
||||
/// `AvailableBlockRatio - 1 percent`.
|
||||
///
|
||||
/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
|
||||
pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(1);
|
||||
@@ -113,7 +114,8 @@ parameter_types! {
|
||||
.build_or_panic();
|
||||
}
|
||||
|
||||
/// Get the maximum weight (compute time) that a Normal extrinsic on the Polkadot-like chain can use.
|
||||
/// Get the maximum weight (compute time) that a Normal extrinsic on the Polkadot-like chain can
|
||||
/// use.
|
||||
pub fn max_extrinsic_weight() -> Weight {
|
||||
BlockWeights::get()
|
||||
.get(DispatchClass::Normal)
|
||||
@@ -144,18 +146,21 @@ pub const MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE: MessageNonce = 8192;
|
||||
|
||||
/// Maximal weight of single message delivery confirmation transaction on Polkadot-like chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof` weight formula
|
||||
/// computation for the case when single message is confirmed. The result then must be rounded up to account possible
|
||||
/// future runtime upgrades.
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
|
||||
/// weight formula computation for the case when single message is confirmed. The result then must
|
||||
/// be rounded up to account possible future runtime upgrades.
|
||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000;
|
||||
|
||||
/// Increase of delivery transaction weight on Polkadot-like chain with every additional message byte.
|
||||
/// Increase of delivery transaction weight on Polkadot-like chain with every additional message
|
||||
/// byte.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The
|
||||
/// result then must be rounded up to account possible future runtime upgrades.
|
||||
/// This value is a result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
|
||||
/// must be rounded up to account possible future runtime upgrades.
|
||||
pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = 25_000;
|
||||
|
||||
/// Maximal number of bytes, included in the signed Polkadot-like transaction apart from the encoded call itself.
|
||||
/// Maximal number of bytes, included in the signed Polkadot-like transaction apart from the encoded
|
||||
/// call itself.
|
||||
///
|
||||
/// Can be computed by subtracting encoded call size from raw transaction size.
|
||||
pub const TX_EXTRA_BYTES: u32 = 256;
|
||||
@@ -163,16 +168,18 @@ pub const TX_EXTRA_BYTES: u32 = 256;
|
||||
/// Weight of single regular message delivery transaction on Polkadot-like chain.
|
||||
///
|
||||
/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH` bytes is delivered.
|
||||
/// The message must have dispatch weight set to zero. The result then must be rounded up to account
|
||||
/// possible future runtime upgrades.
|
||||
/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
|
||||
/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
|
||||
/// rounded up to account possible future runtime upgrades.
|
||||
pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = 1_500_000_000;
|
||||
|
||||
/// Weight of pay-dispatch-fee operation for inbound messages at Polkadot-like chain.
|
||||
///
|
||||
/// This value corresponds to the result of `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()`
|
||||
/// call for your chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery transactions cheaper.
|
||||
/// This value corresponds to the result of
|
||||
/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
|
||||
/// chain. Don't put too much reserve there, because it is used to **decrease**
|
||||
/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
|
||||
/// transactions cheaper.
|
||||
pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 600_000_000;
|
||||
|
||||
/// Re-export `time_units` to make usage easier.
|
||||
@@ -240,15 +247,7 @@ pub type UncheckedExtrinsic<Call> =
|
||||
pub type Address = MultiAddress<AccountId, ()>;
|
||||
|
||||
/// A type of the data encoded as part of the transaction.
|
||||
pub type SignedExtra = (
|
||||
(),
|
||||
(),
|
||||
(),
|
||||
sp_runtime::generic::Era,
|
||||
Compact<Nonce>,
|
||||
(),
|
||||
Compact<Balance>,
|
||||
);
|
||||
pub type SignedExtra = ((), (), (), sp_runtime::generic::Era, Compact<Nonce>, (), Compact<Balance>);
|
||||
|
||||
/// Parameters which are part of the payload used to produce transaction signature,
|
||||
/// but don't end up in the transaction itself (i.e. inherent part of the runtime).
|
||||
@@ -270,7 +269,9 @@ impl<Call> parity_scale_codec::Encode for SignedExtensions<Call> {
|
||||
}
|
||||
|
||||
impl<Call> parity_scale_codec::Decode for SignedExtensions<Call> {
|
||||
fn decode<I: parity_scale_codec::Input>(_input: &mut I) -> Result<Self, parity_scale_codec::Error> {
|
||||
fn decode<I: parity_scale_codec::Input>(
|
||||
_input: &mut I,
|
||||
) -> Result<Self, parity_scale_codec::Error> {
|
||||
unimplemented!("SignedExtensions are never meant to be decoded, they are only used to create transaction");
|
||||
}
|
||||
}
|
||||
@@ -331,7 +332,9 @@ where
|
||||
type AdditionalSigned = AdditionalSigned;
|
||||
type Pre = ();
|
||||
|
||||
fn additional_signed(&self) -> Result<Self::AdditionalSigned, frame_support::unsigned::TransactionValidityError> {
|
||||
fn additional_signed(
|
||||
&self,
|
||||
) -> Result<Self::AdditionalSigned, frame_support::unsigned::TransactionValidityError> {
|
||||
Ok(self.additional_signed)
|
||||
}
|
||||
}
|
||||
@@ -372,7 +375,9 @@ pub fn account_info_storage_key(id: &AccountId) -> Vec<u8> {
|
||||
let storage_prefix_hashed = Twox128::hash(b"Account");
|
||||
let key_hashed = parity_scale_codec::Encode::using_encoded(id, Blake2_128Concat::hash);
|
||||
|
||||
let mut final_key = Vec::with_capacity(module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len());
|
||||
let mut final_key = Vec::with_capacity(
|
||||
module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len(),
|
||||
);
|
||||
|
||||
final_key.extend_from_slice(&module_prefix_hashed[..]);
|
||||
final_key.extend_from_slice(&storage_prefix_hashed[..]);
|
||||
@@ -400,8 +405,8 @@ mod tests {
|
||||
#[test]
|
||||
fn should_generate_storage_key() {
|
||||
let acc = [
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32,
|
||||
]
|
||||
.into();
|
||||
let key = account_info_storage_key(&acc);
|
||||
|
||||
@@ -18,8 +18,8 @@ use frame_support::Parameter;
|
||||
use num_traits::{AsPrimitive, Bounded, CheckedSub, SaturatingAdd, Zero};
|
||||
use sp_runtime::{
|
||||
traits::{
|
||||
AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, MaybeMallocSizeOf,
|
||||
MaybeSerialize, MaybeSerializeDeserialize, Member, SimpleBitOps, Verify,
|
||||
AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay,
|
||||
MaybeMallocSizeOf, MaybeSerialize, MaybeSerializeDeserialize, Member, SimpleBitOps, Verify,
|
||||
},
|
||||
FixedPointOperand,
|
||||
};
|
||||
@@ -77,10 +77,18 @@ pub trait Chain: Send + Sync + 'static {
|
||||
/// A type that fulfills the abstract idea of what a Substrate header is.
|
||||
// See here for more info:
|
||||
// https://crates.parity.io/sp_runtime/traits/trait.Header.html
|
||||
type Header: Parameter + HeaderT<Number = Self::BlockNumber, Hash = Self::Hash> + MaybeSerializeDeserialize;
|
||||
type Header: Parameter
|
||||
+ HeaderT<Number = Self::BlockNumber, Hash = Self::Hash>
|
||||
+ MaybeSerializeDeserialize;
|
||||
|
||||
/// The user account identifier type for the runtime.
|
||||
type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + Default;
|
||||
type AccountId: Parameter
|
||||
+ Member
|
||||
+ MaybeSerializeDeserialize
|
||||
+ Debug
|
||||
+ MaybeDisplay
|
||||
+ Ord
|
||||
+ Default;
|
||||
/// Balance of an account in native tokens.
|
||||
///
|
||||
/// The chain may support multiple tokens, but this particular type is for token that is used
|
||||
|
||||
@@ -25,8 +25,8 @@ use sp_io::hashing::blake2_256;
|
||||
use sp_std::{convert::TryFrom, vec::Vec};
|
||||
|
||||
pub use chain::{
|
||||
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, IndexOf, SignatureOf,
|
||||
TransactionEraOf,
|
||||
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf,
|
||||
IndexOf, SignatureOf, TransactionEraOf,
|
||||
};
|
||||
pub use storage_proof::{Error as StorageProofError, StorageProofChecker};
|
||||
|
||||
@@ -72,8 +72,9 @@ pub const ROOT_ACCOUNT_DERIVATION_PREFIX: &[u8] = b"pallet-bridge/account-deriva
|
||||
///
|
||||
/// In addition to its main function (identifying the chain), this type may also be used to
|
||||
/// identify module instance. We have a bunch of pallets that may be used in different bridges. E.g.
|
||||
/// messages pallet may be deployed twice in the same runtime to bridge ThisChain with Chain1 and Chain2.
|
||||
/// Sometimes we need to be able to identify deployed instance dynamically. This type may be used for that.
|
||||
/// messages pallet may be deployed twice in the same runtime to bridge ThisChain with Chain1 and
|
||||
/// Chain2. Sometimes we need to be able to identify deployed instance dynamically. This type may be
|
||||
/// used for that.
|
||||
pub type ChainId = [u8; 4];
|
||||
|
||||
/// Type of accounts on the source chain.
|
||||
@@ -103,8 +104,10 @@ where
|
||||
AccountId: Encode,
|
||||
{
|
||||
match id {
|
||||
SourceAccount::Root => (ROOT_ACCOUNT_DERIVATION_PREFIX, bridge_id).using_encoded(blake2_256),
|
||||
SourceAccount::Account(id) => (ACCOUNT_DERIVATION_PREFIX, bridge_id, id).using_encoded(blake2_256),
|
||||
SourceAccount::Root =>
|
||||
(ROOT_ACCOUNT_DERIVATION_PREFIX, bridge_id).using_encoded(blake2_256),
|
||||
SourceAccount::Account(id) =>
|
||||
(ACCOUNT_DERIVATION_PREFIX, bridge_id, id).using_encoded(blake2_256),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
@@ -113,8 +116,8 @@ where
|
||||
///
|
||||
/// This account is used to collect fees for relayers that are passing messages across the bridge.
|
||||
///
|
||||
/// The account ID can be the same across different instances of `pallet-bridge-messages` if the same
|
||||
/// `bridge_id` is used.
|
||||
/// The account ID can be the same across different instances of `pallet-bridge-messages` if the
|
||||
/// same `bridge_id` is used.
|
||||
pub fn derive_relayer_fund_account_id(bridge_id: ChainId) -> H256 {
|
||||
("relayer-fund-account", bridge_id).using_encoded(blake2_256).into()
|
||||
}
|
||||
@@ -154,9 +157,15 @@ pub enum TransactionEra<BlockNumber, BlockHash> {
|
||||
|
||||
impl<BlockNumber: Copy + Into<u64>, BlockHash: Copy> TransactionEra<BlockNumber, BlockHash> {
|
||||
/// Prepare transaction era, based on mortality period and current best block number.
|
||||
pub fn new(best_block_number: BlockNumber, best_block_hash: BlockHash, mortality_period: Option<u32>) -> Self {
|
||||
pub fn new(
|
||||
best_block_number: BlockNumber,
|
||||
best_block_hash: BlockHash,
|
||||
mortality_period: Option<u32>,
|
||||
) -> Self {
|
||||
mortality_period
|
||||
.map(|mortality_period| TransactionEra::Mortal(best_block_number, best_block_hash, mortality_period))
|
||||
.map(|mortality_period| {
|
||||
TransactionEra::Mortal(best_block_number, best_block_hash, mortality_period)
|
||||
})
|
||||
.unwrap_or(TransactionEra::Immortal)
|
||||
}
|
||||
|
||||
@@ -169,9 +178,8 @@ impl<BlockNumber: Copy + Into<u64>, BlockHash: Copy> TransactionEra<BlockNumber,
|
||||
pub fn frame_era(&self) -> sp_runtime::generic::Era {
|
||||
match *self {
|
||||
TransactionEra::Immortal => sp_runtime::generic::Era::immortal(),
|
||||
TransactionEra::Mortal(header_number, _, period) => {
|
||||
sp_runtime::generic::Era::mortal(period as _, header_number.into())
|
||||
}
|
||||
TransactionEra::Mortal(header_number, _, period) =>
|
||||
sp_runtime::generic::Era::mortal(period as _, header_number.into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,25 +192,40 @@ impl<BlockNumber: Copy + Into<u64>, BlockHash: Copy> TransactionEra<BlockNumber,
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a copypaste of the `frame_support::storage::generator::StorageMap::storage_map_final_key`
|
||||
/// for `Blake2_128Concat` maps.
|
||||
/// This is a copypaste of the
|
||||
/// `frame_support::storage::generator::StorageMap::storage_map_final_key` for `Blake2_128Concat`
|
||||
/// maps.
|
||||
///
|
||||
/// We're using it because to call `storage_map_final_key` directly, we need access to the runtime
|
||||
/// and pallet instance, which (sometimes) is impossible.
|
||||
pub fn storage_map_final_key_blake2_128concat(pallet_prefix: &str, map_name: &str, key: &[u8]) -> StorageKey {
|
||||
storage_map_final_key_identity(pallet_prefix, map_name, &frame_support::Blake2_128Concat::hash(key))
|
||||
pub fn storage_map_final_key_blake2_128concat(
|
||||
pallet_prefix: &str,
|
||||
map_name: &str,
|
||||
key: &[u8],
|
||||
) -> StorageKey {
|
||||
storage_map_final_key_identity(
|
||||
pallet_prefix,
|
||||
map_name,
|
||||
&frame_support::Blake2_128Concat::hash(key),
|
||||
)
|
||||
}
|
||||
|
||||
/// This is a copypaste of the `frame_support::storage::generator::StorageMap::storage_map_final_key`
|
||||
/// for `Identity` maps.
|
||||
/// This is a copypaste of the
|
||||
/// `frame_support::storage::generator::StorageMap::storage_map_final_key` for `Identity` maps.
|
||||
///
|
||||
/// We're using it because to call `storage_map_final_key` directly, we need access to the runtime
|
||||
/// and pallet instance, which (sometimes) is impossible.
|
||||
pub fn storage_map_final_key_identity(pallet_prefix: &str, map_name: &str, key_hashed: &[u8]) -> StorageKey {
|
||||
pub fn storage_map_final_key_identity(
|
||||
pallet_prefix: &str,
|
||||
map_name: &str,
|
||||
key_hashed: &[u8],
|
||||
) -> StorageKey {
|
||||
let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes());
|
||||
let storage_prefix_hashed = frame_support::Twox128::hash(map_name.as_bytes());
|
||||
|
||||
let mut final_key = Vec::with_capacity(pallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len());
|
||||
let mut final_key = Vec::with_capacity(
|
||||
pallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len(),
|
||||
);
|
||||
|
||||
final_key.extend_from_slice(&pallet_prefix_hashed[..]);
|
||||
final_key.extend_from_slice(&storage_prefix_hashed[..]);
|
||||
@@ -211,7 +234,8 @@ pub fn storage_map_final_key_identity(pallet_prefix: &str, map_name: &str, key_h
|
||||
StorageKey(final_key)
|
||||
}
|
||||
|
||||
/// This is how a storage key of storage parameter (`parameter_types! { storage Param: bool = false; }`) is computed.
|
||||
/// This is how a storage key of storage parameter (`parameter_types! { storage Param: bool = false;
|
||||
/// }`) is computed.
|
||||
///
|
||||
/// Copypaste from `frame_support::parameter_types` macro
|
||||
pub fn storage_parameter_key(parameter_name: &str) -> StorageKey {
|
||||
|
||||
@@ -50,7 +50,7 @@ pub struct MessageDispatchResult {
|
||||
/// 2) if message has not been dispatched at all.
|
||||
pub unspent_weight: Weight,
|
||||
/// Whether the message dispatch fee has been paid during dispatch. This will be true if your
|
||||
/// configuration supports pay-dispatch-fee-at-target-chain option and message sender has enabled
|
||||
/// this option.
|
||||
/// configuration supports pay-dispatch-fee-at-target-chain option and message sender has
|
||||
/// enabled this option.
|
||||
pub dispatch_fee_paid_during_dispatch: bool,
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ where
|
||||
pub fn new(root: H::Out, proof: StorageProof) -> Result<Self, Error> {
|
||||
let db = proof.into_memory_db();
|
||||
if !db.contains(&root, EMPTY_PREFIX) {
|
||||
return Err(Error::StorageRootMismatch);
|
||||
return Err(Error::StorageRootMismatch)
|
||||
}
|
||||
|
||||
let checker = StorageProofChecker { root, db };
|
||||
@@ -52,7 +52,8 @@ where
|
||||
/// Reads a value from the available subset of storage. If the value cannot be read due to an
|
||||
/// incomplete or otherwise invalid proof, this returns an error.
|
||||
pub fn read_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
|
||||
read_trie_value::<Layout<H>, _>(&self.db, &self.root, key).map_err(|_| Error::StorageValueUnavailable)
|
||||
read_trie_value::<Layout<H>, _>(&self.db, &self.root, key)
|
||||
.map_err(|_| Error::StorageValueUnavailable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +98,8 @@ pub mod tests {
|
||||
let (root, proof) = craft_valid_storage_proof();
|
||||
|
||||
// check proof in runtime
|
||||
let checker = <StorageProofChecker<sp_core::Blake2Hasher>>::new(root, proof.clone()).unwrap();
|
||||
let checker =
|
||||
<StorageProofChecker<sp_core::Blake2Hasher>>::new(root, proof.clone()).unwrap();
|
||||
assert_eq!(checker.read_value(b"key1"), Ok(Some(b"value1".to_vec())));
|
||||
assert_eq!(checker.read_value(b"key2"), Ok(Some(b"value2".to_vec())));
|
||||
assert_eq!(checker.read_value(b"key11111"), Err(Error::StorageValueUnavailable));
|
||||
|
||||
@@ -45,7 +45,8 @@ impl Account {
|
||||
let data = self.0.encode();
|
||||
let mut bytes = [0_u8; 32];
|
||||
bytes[0..data.len()].copy_from_slice(&*data);
|
||||
SecretKey::from_bytes(&bytes).expect("A static array of the correct length is a known good.")
|
||||
SecretKey::from_bytes(&bytes)
|
||||
.expect("A static array of the correct length is a known good.")
|
||||
}
|
||||
|
||||
pub fn pair(&self) -> Keypair {
|
||||
@@ -57,7 +58,8 @@ impl Account {
|
||||
let public = self.public();
|
||||
pair[32..].copy_from_slice(&public.to_bytes());
|
||||
|
||||
Keypair::from_bytes(&pair).expect("We expect the SecretKey to be good, so this must also be good.")
|
||||
Keypair::from_bytes(&pair)
|
||||
.expect("We expect the SecretKey to be good, so this must also be good.")
|
||||
}
|
||||
|
||||
pub fn sign(&self, msg: &[u8]) -> Signature {
|
||||
@@ -79,10 +81,7 @@ pub fn voter_set() -> VoterSet<AuthorityId> {
|
||||
|
||||
/// Convenience function to get a list of Grandpa authorities.
|
||||
pub fn authority_list() -> AuthorityList {
|
||||
test_keyring()
|
||||
.iter()
|
||||
.map(|(id, w)| (AuthorityId::from(*id), *w))
|
||||
.collect()
|
||||
test_keyring().iter().map(|(id, w)| (AuthorityId::from(*id), *w)).collect()
|
||||
}
|
||||
|
||||
/// Get the corresponding identities from the keyring for the "standard" authority set.
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
use bp_header_chain::justification::GrandpaJustification;
|
||||
use codec::Encode;
|
||||
use sp_application_crypto::TryFrom;
|
||||
use sp_finality_grandpa::{AuthorityId, AuthorityWeight};
|
||||
use sp_finality_grandpa::{AuthoritySignature, SetId};
|
||||
use sp_finality_grandpa::{AuthorityId, AuthoritySignature, AuthorityWeight, SetId};
|
||||
use sp_runtime::traits::{Header as HeaderT, One, Zero};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
@@ -72,10 +71,7 @@ impl<H: HeaderT> Default for JustificationGeneratorParams<H> {
|
||||
|
||||
/// Make a valid GRANDPA justification with sensible defaults
|
||||
pub fn make_default_justification<H: HeaderT>(header: &H) -> GrandpaJustification<H> {
|
||||
let params = JustificationGeneratorParams::<H> {
|
||||
header: header.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
let params = JustificationGeneratorParams::<H> { header: header.clone(), ..Default::default() };
|
||||
|
||||
make_justification_for_header(params)
|
||||
}
|
||||
@@ -89,15 +85,11 @@ pub fn make_default_justification<H: HeaderT>(header: &H) -> GrandpaJustificatio
|
||||
///
|
||||
/// Note: This needs at least three authorities or else the verifier will complain about
|
||||
/// being given an invalid commit.
|
||||
pub fn make_justification_for_header<H: HeaderT>(params: JustificationGeneratorParams<H>) -> GrandpaJustification<H> {
|
||||
let JustificationGeneratorParams {
|
||||
header,
|
||||
round,
|
||||
set_id,
|
||||
authorities,
|
||||
mut ancestors,
|
||||
forks,
|
||||
} = params;
|
||||
pub fn make_justification_for_header<H: HeaderT>(
|
||||
params: JustificationGeneratorParams<H>,
|
||||
) -> GrandpaJustification<H> {
|
||||
let JustificationGeneratorParams { header, round, set_id, authorities, mut ancestors, forks } =
|
||||
params;
|
||||
let (target_hash, target_number) = (header.hash(), *header.number());
|
||||
let mut votes_ancestries = vec![];
|
||||
let mut precommits = vec![];
|
||||
@@ -144,11 +136,7 @@ pub fn make_justification_for_header<H: HeaderT>(params: JustificationGeneratorP
|
||||
|
||||
GrandpaJustification {
|
||||
round,
|
||||
commit: finality_grandpa::Commit {
|
||||
target_hash,
|
||||
target_number,
|
||||
precommits,
|
||||
},
|
||||
commit: finality_grandpa::Commit { target_hash, target_number, precommits },
|
||||
votes_ancestries,
|
||||
}
|
||||
}
|
||||
@@ -165,10 +153,7 @@ fn generate_chain<H: HeaderT>(fork_id: u32, depth: u32, ancestor: &H) -> Vec<H>
|
||||
|
||||
// Modifying the digest so headers at the same height but in different forks have different
|
||||
// hashes
|
||||
header
|
||||
.digest_mut()
|
||||
.logs
|
||||
.push(sp_runtime::DigestItem::Other(fork_id.encode()));
|
||||
header.digest_mut().logs.push(sp_runtime::DigestItem::Other(fork_id.encode()));
|
||||
|
||||
headers.push(header);
|
||||
}
|
||||
@@ -183,29 +168,26 @@ pub fn signed_precommit<H: HeaderT>(
|
||||
round: u64,
|
||||
set_id: SetId,
|
||||
) -> finality_grandpa::SignedPrecommit<H::Hash, H::Number, AuthoritySignature, AuthorityId> {
|
||||
let precommit = finality_grandpa::Precommit {
|
||||
target_hash: target.0,
|
||||
target_number: target.1,
|
||||
};
|
||||
let precommit = finality_grandpa::Precommit { target_hash: target.0, target_number: target.1 };
|
||||
|
||||
let encoded =
|
||||
sp_finality_grandpa::localized_payload(round, set_id, &finality_grandpa::Message::Precommit(precommit.clone()));
|
||||
let encoded = sp_finality_grandpa::localized_payload(
|
||||
round,
|
||||
set_id,
|
||||
&finality_grandpa::Message::Precommit(precommit.clone()),
|
||||
);
|
||||
|
||||
let signature = signer.sign(&encoded);
|
||||
let raw_signature: Vec<u8> = signature.to_bytes().into();
|
||||
|
||||
// Need to wrap our signature and id types that they match what our `SignedPrecommit` is expecting
|
||||
// Need to wrap our signature and id types that they match what our `SignedPrecommit` is
|
||||
// expecting
|
||||
let signature = AuthoritySignature::try_from(raw_signature).expect(
|
||||
"We know our Keypair is good,
|
||||
so our signature must also be good.",
|
||||
);
|
||||
let id = (*signer).into();
|
||||
|
||||
finality_grandpa::SignedPrecommit {
|
||||
precommit,
|
||||
signature,
|
||||
id,
|
||||
}
|
||||
finality_grandpa::SignedPrecommit { precommit, signature, id }
|
||||
}
|
||||
|
||||
/// Get a header for testing.
|
||||
@@ -213,13 +195,7 @@ pub fn signed_precommit<H: HeaderT>(
|
||||
/// The correct parent hash will be used if given a non-zero header.
|
||||
pub fn test_header<H: HeaderT>(number: H::Number) -> H {
|
||||
let default = |num| {
|
||||
H::new(
|
||||
num,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
)
|
||||
H::new(num, Default::default(), Default::default(), Default::default(), Default::default())
|
||||
};
|
||||
|
||||
let mut header = default(number);
|
||||
|
||||
@@ -26,8 +26,8 @@ pub enum TokenSwapState {
|
||||
/// The swap has been started using the `start_claim` call, but we have no proof that it has
|
||||
/// happened at the Bridged chain.
|
||||
Started,
|
||||
/// The swap has happened at the Bridged chain and may be claimed by the Bridged chain party using
|
||||
/// the `claim_swap` call.
|
||||
/// The swap has happened at the Bridged chain and may be claimed by the Bridged chain party
|
||||
/// using the `claim_swap` call.
|
||||
Confirmed,
|
||||
/// The swap has failed at the Bridged chain and This chain party may cancel it using the
|
||||
/// `cancel_swap` call.
|
||||
@@ -43,19 +43,20 @@ pub enum TokenSwapType<ThisBlockNumber> {
|
||||
/// The `target_account_at_bridged_chain` is temporary and only have funds for single swap.
|
||||
///
|
||||
/// ***WARNING**: if `target_account_at_bridged_chain` still exists after the swap has been
|
||||
/// completed (either by claiming or canceling), the `source_account_at_this_chain` will be able
|
||||
/// to restart the swap again and repeat the swap until `target_account_at_bridged_chain` depletes.
|
||||
/// completed (either by claiming or canceling), the `source_account_at_this_chain` will be
|
||||
/// able to restart the swap again and repeat the swap until `target_account_at_bridged_chain`
|
||||
/// depletes.
|
||||
TemporaryTargetAccountAtBridgedChain,
|
||||
/// This swap type prevents `source_account_at_this_chain` from restarting the swap after it has
|
||||
/// been completed. There are two consequences:
|
||||
/// This swap type prevents `source_account_at_this_chain` from restarting the swap after it
|
||||
/// has been completed. There are two consequences:
|
||||
///
|
||||
/// 1) the `source_account_at_this_chain` won't be able to call `start_swap` after given <ThisBlockNumber>;
|
||||
/// 2) the `target_account_at_bridged_chain` won't be able to call `claim_swap` (over the bridge) before
|
||||
/// block `<ThisBlockNumber + 1>`.
|
||||
/// 1) the `source_account_at_this_chain` won't be able to call `start_swap` after given
|
||||
/// <ThisBlockNumber>; 2) the `target_account_at_bridged_chain` won't be able to call
|
||||
/// `claim_swap` (over the bridge) before block `<ThisBlockNumber + 1>`.
|
||||
///
|
||||
/// The second element is the nonce of the swap. You must care about its uniqueness if you're
|
||||
/// planning to perform another swap with exactly the same parameters (i.e. same amount, same accounts,
|
||||
/// same `ThisBlockNumber`) to avoid collisions.
|
||||
/// planning to perform another swap with exactly the same parameters (i.e. same amount, same
|
||||
/// accounts, same `ThisBlockNumber`) to avoid collisions.
|
||||
LockClaimUntilBlock(ThisBlockNumber, U256),
|
||||
}
|
||||
|
||||
@@ -64,9 +65,11 @@ pub enum TokenSwapType<ThisBlockNumber> {
|
||||
///
|
||||
/// **IMPORTANT NOTE**: this structure is always the same during single token swap. So even
|
||||
/// when chain changes, the meaning of This and Bridged are still used to point to the same chains.
|
||||
/// This chain is always the chain where swap has been started. And the Bridged chain is the other chain.
|
||||
/// This chain is always the chain where swap has been started. And the Bridged chain is the other
|
||||
/// chain.
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)]
|
||||
pub struct TokenSwap<ThisBlockNumber, ThisBalance, ThisAccountId, BridgedBalance, BridgedAccountId> {
|
||||
pub struct TokenSwap<ThisBlockNumber, ThisBalance, ThisAccountId, BridgedBalance, BridgedAccountId>
|
||||
{
|
||||
/// The type of the swap.
|
||||
pub swap_type: TokenSwapType<ThisBlockNumber>,
|
||||
/// This chain balance to be swapped with `target_balance_at_bridged_chain`.
|
||||
@@ -75,6 +78,7 @@ pub struct TokenSwap<ThisBlockNumber, ThisBalance, ThisAccountId, BridgedBalance
|
||||
pub source_account_at_this_chain: ThisAccountId,
|
||||
/// Bridged chain balance to be swapped with `source_balance_at_this_chain`.
|
||||
pub target_balance_at_bridged_chain: BridgedBalance,
|
||||
/// Account id of the party acting at the Bridged chain and owning the `target_balance_at_bridged_chain`.
|
||||
/// Account id of the party acting at the Bridged chain and owning the
|
||||
/// `target_balance_at_bridged_chain`.
|
||||
pub target_account_at_bridged_chain: BridgedAccountId,
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
// 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::rpc_errors::RpcError;
|
||||
use crate::substrate_sync_loop::QueuedRialtoHeader;
|
||||
use crate::{rpc_errors::RpcError, substrate_sync_loop::QueuedRialtoHeader};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_eth_poa::signatures::secret_to_address;
|
||||
@@ -60,7 +59,10 @@ pub trait EthereumHighLevelRpc {
|
||||
) -> SubmittedHeaders<RialtoHeaderId, RpcError>;
|
||||
|
||||
/// Returns ids of incomplete Substrate headers.
|
||||
async fn incomplete_substrate_headers(&self, contract_address: Address) -> RpcResult<HashSet<RialtoHeaderId>>;
|
||||
async fn incomplete_substrate_headers(
|
||||
&self,
|
||||
contract_address: Address,
|
||||
) -> RpcResult<HashSet<RialtoHeaderId>>;
|
||||
|
||||
/// Complete Substrate header.
|
||||
async fn complete_substrate_header(
|
||||
@@ -104,7 +106,7 @@ impl EthereumHighLevelRpc for EthereumClient {
|
||||
let hash = rialto_runtime::Hash::decode(&mut &raw_hash[..])?;
|
||||
|
||||
if number != number.low_u32().into() {
|
||||
return Err(RpcError::Ethereum(EthereumNodeError::InvalidSubstrateBlockNumber));
|
||||
return Err(RpcError::Ethereum(EthereumNodeError::InvalidSubstrateBlockNumber))
|
||||
}
|
||||
|
||||
Ok(HeaderId(number.low_u32(), hash))
|
||||
@@ -138,31 +140,28 @@ impl EthereumHighLevelRpc for EthereumClient {
|
||||
let address: Address = secret_to_address(¶ms.signer);
|
||||
let nonce = match self.account_nonce(address).await {
|
||||
Ok(nonce) => nonce,
|
||||
Err(error) => {
|
||||
Err(error) =>
|
||||
return SubmittedHeaders {
|
||||
submitted: Vec::new(),
|
||||
incomplete: Vec::new(),
|
||||
rejected: headers.iter().rev().map(|header| header.id()).collect(),
|
||||
fatal_error: Some(error.into()),
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// submit headers. Note that we're cloning self here. It is ok, because
|
||||
// cloning `jsonrpsee::Client` only clones reference to background threads
|
||||
submit_substrate_headers(
|
||||
EthereumHeadersSubmitter {
|
||||
client: self.clone(),
|
||||
params,
|
||||
contract_address,
|
||||
nonce,
|
||||
},
|
||||
EthereumHeadersSubmitter { client: self.clone(), params, contract_address, nonce },
|
||||
headers,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn incomplete_substrate_headers(&self, contract_address: Address) -> RpcResult<HashSet<RialtoHeaderId>> {
|
||||
async fn incomplete_substrate_headers(
|
||||
&self,
|
||||
contract_address: Address,
|
||||
) -> RpcResult<HashSet<RialtoHeaderId>> {
|
||||
let (encoded_call, call_decoder) = bridge_contract::functions::incomplete_headers::call();
|
||||
let call_request = CallRequest {
|
||||
to: Some(contract_address),
|
||||
@@ -173,13 +172,14 @@ impl EthereumHighLevelRpc for EthereumClient {
|
||||
let call_result = self.eth_call(call_request).await?;
|
||||
|
||||
// Q: Is is correct to call these "incomplete_ids"?
|
||||
let (incomplete_headers_numbers, incomplete_headers_hashes) = call_decoder.decode(&call_result.0)?;
|
||||
let (incomplete_headers_numbers, incomplete_headers_hashes) =
|
||||
call_decoder.decode(&call_result.0)?;
|
||||
let incomplete_ids = incomplete_headers_numbers
|
||||
.into_iter()
|
||||
.zip(incomplete_headers_hashes)
|
||||
.filter_map(|(number, hash)| {
|
||||
if number != number.low_u32().into() {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
Some(HeaderId(number.low_u32(), hash))
|
||||
@@ -202,7 +202,11 @@ impl EthereumHighLevelRpc for EthereumClient {
|
||||
Some(contract_address),
|
||||
None,
|
||||
false,
|
||||
bridge_contract::functions::import_finality_proof::encode_input(id.0, id.1, justification),
|
||||
bridge_contract::functions::import_finality_proof::encode_input(
|
||||
id.0,
|
||||
id.1,
|
||||
justification,
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -263,7 +267,7 @@ impl HeadersBatch {
|
||||
) -> Result<(Self, Vec<RialtoHeaderId>), ()> {
|
||||
if headers.len() != ids.len() {
|
||||
log::error!(target: "bridge", "Collection size mismatch ({} vs {})", headers.len(), ids.len());
|
||||
return Err(());
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let header1 = headers.pop().ok_or(())?;
|
||||
@@ -276,27 +280,14 @@ impl HeadersBatch {
|
||||
submitting_ids.extend(ids.pop().iter());
|
||||
}
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
header1,
|
||||
header2,
|
||||
header3,
|
||||
header4,
|
||||
},
|
||||
submitting_ids,
|
||||
))
|
||||
Ok((Self { header1, header2, header3, header4 }, submitting_ids))
|
||||
}
|
||||
|
||||
/// Returns unified array of headers.
|
||||
///
|
||||
/// The first element is always `Some`.
|
||||
fn headers(&self) -> [Option<&QueuedRialtoHeader>; HEADERS_BATCH] {
|
||||
[
|
||||
Some(&self.header1),
|
||||
self.header2.as_ref(),
|
||||
self.header3.as_ref(),
|
||||
self.header4.as_ref(),
|
||||
]
|
||||
[Some(&self.header1), self.header2.as_ref(), self.header3.as_ref(), self.header4.as_ref()]
|
||||
}
|
||||
|
||||
/// Encodes all headers. If header is not present an empty vector will be returned.
|
||||
@@ -323,9 +314,10 @@ impl HeadersBatch {
|
||||
/// or when `idx > HEADERS_BATCH`.
|
||||
pub fn split_off(&mut self, idx: usize) -> Result<(), ()> {
|
||||
if idx == 0 || idx > HEADERS_BATCH {
|
||||
return Err(());
|
||||
return Err(())
|
||||
}
|
||||
let mut vals: [_; HEADERS_BATCH] = [&mut None, &mut self.header2, &mut self.header3, &mut self.header4];
|
||||
let mut vals: [_; HEADERS_BATCH] =
|
||||
[&mut None, &mut self.header2, &mut self.header3, &mut self.header4];
|
||||
for val in vals.iter_mut().skip(idx) {
|
||||
**val = None;
|
||||
}
|
||||
@@ -359,7 +351,8 @@ struct EthereumHeadersSubmitter {
|
||||
impl HeadersSubmitter for EthereumHeadersSubmitter {
|
||||
async fn is_headers_incomplete(&self, headers: &HeadersBatch) -> RpcResult<usize> {
|
||||
let [h1, h2, h3, h4] = headers.encode();
|
||||
let (encoded_call, call_decoder) = bridge_contract::functions::is_incomplete_headers::call(h1, h2, h3, h4);
|
||||
let (encoded_call, call_decoder) =
|
||||
bridge_contract::functions::is_incomplete_headers::call(h1, h2, h3, h4);
|
||||
let call_request = CallRequest {
|
||||
to: Some(self.contract_address),
|
||||
data: Some(encoded_call.into()),
|
||||
@@ -369,7 +362,7 @@ impl HeadersSubmitter for EthereumHeadersSubmitter {
|
||||
let call_result = self.client.eth_call(call_request).await?;
|
||||
let incomplete_index: U256 = call_decoder.decode(&call_result.0)?;
|
||||
if incomplete_index > HEADERS_BATCH.into() {
|
||||
return Err(RpcError::Ethereum(EthereumNodeError::InvalidIncompleteIndex));
|
||||
return Err(RpcError::Ethereum(EthereumNodeError::InvalidIncompleteIndex))
|
||||
}
|
||||
|
||||
Ok(incomplete_index.low_u32() as _)
|
||||
@@ -407,17 +400,21 @@ async fn submit_substrate_headers(
|
||||
headers.reverse();
|
||||
|
||||
while !headers.is_empty() {
|
||||
let (headers, submitting_ids) =
|
||||
HeadersBatch::pop_from(&mut headers, &mut ids).expect("Headers and ids are not empty; qed");
|
||||
let (headers, submitting_ids) = HeadersBatch::pop_from(&mut headers, &mut ids)
|
||||
.expect("Headers and ids are not empty; qed");
|
||||
|
||||
submitted_headers.fatal_error =
|
||||
submit_substrate_headers_batch(&mut header_submitter, &mut submitted_headers, submitting_ids, headers)
|
||||
.await;
|
||||
submitted_headers.fatal_error = submit_substrate_headers_batch(
|
||||
&mut header_submitter,
|
||||
&mut submitted_headers,
|
||||
submitting_ids,
|
||||
headers,
|
||||
)
|
||||
.await;
|
||||
|
||||
if submitted_headers.fatal_error.is_some() {
|
||||
ids.reverse();
|
||||
submitted_headers.rejected.extend(ids);
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,9 +433,11 @@ async fn submit_substrate_headers_batch(
|
||||
// if parent of first header is either incomplete, or rejected, we assume that contract
|
||||
// will reject this header as well
|
||||
let parent_id = headers.header1.parent_id();
|
||||
if submitted_headers.rejected.contains(&parent_id) || submitted_headers.incomplete.contains(&parent_id) {
|
||||
if submitted_headers.rejected.contains(&parent_id) ||
|
||||
submitted_headers.incomplete.contains(&parent_id)
|
||||
{
|
||||
submitted_headers.rejected.extend(ids);
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
// check if headers are incomplete
|
||||
@@ -450,11 +449,11 @@ async fn submit_substrate_headers_batch(
|
||||
// contract has rejected all headers => we do not want to submit it
|
||||
submitted_headers.rejected.extend(ids);
|
||||
if error.is_connection_error() {
|
||||
return Some(error);
|
||||
return Some(error)
|
||||
} else {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Modify `ids` and `headers` to only contain values that are going to be accepted.
|
||||
@@ -477,12 +476,12 @@ async fn submit_substrate_headers_batch(
|
||||
submitted_headers.submitted.extend(submitted);
|
||||
submitted_headers.rejected.extend(rejected);
|
||||
None
|
||||
}
|
||||
},
|
||||
Err(error) => {
|
||||
submitted_headers.rejected.extend(submitted);
|
||||
submitted_headers.rejected.extend(rejected);
|
||||
Some(error)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,11 +520,7 @@ mod tests {
|
||||
number,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
if number == 0 {
|
||||
Default::default()
|
||||
} else {
|
||||
header(number - 1).id().1
|
||||
},
|
||||
if number == 0 { Default::default() } else { header(number - 1).id().1 },
|
||||
Default::default(),
|
||||
)
|
||||
.into(),
|
||||
@@ -535,10 +530,7 @@ mod tests {
|
||||
#[test]
|
||||
fn descendants_of_incomplete_headers_are_not_submitted() {
|
||||
let submitted_headers = async_std::task::block_on(submit_substrate_headers(
|
||||
TestHeadersSubmitter {
|
||||
incomplete: vec![header(5).id()],
|
||||
failed: vec![],
|
||||
},
|
||||
TestHeadersSubmitter { incomplete: vec![header(5).id()], failed: vec![] },
|
||||
vec![header(5), header(6)],
|
||||
));
|
||||
assert_eq!(submitted_headers.submitted, vec![header(5).id()]);
|
||||
@@ -550,19 +542,8 @@ mod tests {
|
||||
#[test]
|
||||
fn headers_after_fatal_error_are_not_submitted() {
|
||||
let submitted_headers = async_std::task::block_on(submit_substrate_headers(
|
||||
TestHeadersSubmitter {
|
||||
incomplete: vec![],
|
||||
failed: vec![header(9).id()],
|
||||
},
|
||||
vec![
|
||||
header(5),
|
||||
header(6),
|
||||
header(7),
|
||||
header(8),
|
||||
header(9),
|
||||
header(10),
|
||||
header(11),
|
||||
],
|
||||
TestHeadersSubmitter { incomplete: vec![], failed: vec![header(9).id()] },
|
||||
vec![header(5), header(6), header(7), header(8), header(9), header(10), header(11)],
|
||||
));
|
||||
assert_eq!(
|
||||
submitted_headers.submitted,
|
||||
@@ -583,10 +564,7 @@ mod tests {
|
||||
let (headers, ids) = HeadersBatch::pop_from(&mut init_headers, &mut init_ids).unwrap();
|
||||
assert_eq!(init_headers, vec![header(5)]);
|
||||
assert_eq!(init_ids, vec![header(5).id()]);
|
||||
assert_eq!(
|
||||
ids,
|
||||
vec![header(1).id(), header(2).id(), header(3).id(), header(4).id()]
|
||||
);
|
||||
assert_eq!(ids, vec![header(1).id(), header(2).id(), header(3).id(), header(4).id()]);
|
||||
headers
|
||||
}
|
||||
|
||||
|
||||
@@ -14,17 +14,21 @@
|
||||
// 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::ethereum_client::{bridge_contract, EthereumHighLevelRpc};
|
||||
use crate::rpc_errors::RpcError;
|
||||
use crate::{
|
||||
ethereum_client::{bridge_contract, EthereumHighLevelRpc},
|
||||
rpc_errors::RpcError,
|
||||
};
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use num_traits::Zero;
|
||||
use relay_ethereum_client::{
|
||||
Client as EthereumClient, ConnectionParams as EthereumConnectionParams, SigningParams as EthereumSigningParams,
|
||||
Client as EthereumClient, ConnectionParams as EthereumConnectionParams,
|
||||
SigningParams as EthereumSigningParams,
|
||||
};
|
||||
use relay_rialto_client::{HeaderId as RialtoHeaderId, Rialto};
|
||||
use relay_substrate_client::{
|
||||
Client as SubstrateClient, ConnectionParams as SubstrateConnectionParams, OpaqueGrandpaAuthoritiesSet,
|
||||
Client as SubstrateClient, ConnectionParams as SubstrateConnectionParams,
|
||||
OpaqueGrandpaAuthoritiesSet,
|
||||
};
|
||||
use relay_utils::HeaderId;
|
||||
|
||||
@@ -102,19 +106,18 @@ async fn prepare_initial_header(
|
||||
sub_initial_header: Option<Vec<u8>>,
|
||||
) -> Result<(RialtoHeaderId, Vec<u8>), String> {
|
||||
match sub_initial_header {
|
||||
Some(raw_initial_header) => match rialto_runtime::Header::decode(&mut &raw_initial_header[..]) {
|
||||
Ok(initial_header) => Ok((
|
||||
HeaderId(initial_header.number, initial_header.hash()),
|
||||
raw_initial_header,
|
||||
)),
|
||||
Err(error) => Err(format!("Error decoding initial header: {}", error)),
|
||||
},
|
||||
Some(raw_initial_header) =>
|
||||
match rialto_runtime::Header::decode(&mut &raw_initial_header[..]) {
|
||||
Ok(initial_header) =>
|
||||
Ok((HeaderId(initial_header.number, initial_header.hash()), raw_initial_header)),
|
||||
Err(error) => Err(format!("Error decoding initial header: {}", error)),
|
||||
},
|
||||
None => {
|
||||
let initial_header = sub_client.header_by_number(Zero::zero()).await;
|
||||
initial_header
|
||||
.map(|header| (HeaderId(Zero::zero(), header.hash()), header.encode()))
|
||||
.map_err(|error| format!("Error reading Substrate genesis header: {:?}", error))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +132,8 @@ async fn prepare_initial_authorities_set(
|
||||
None => sub_client.grandpa_authorities_set(sub_initial_header_hash).await,
|
||||
};
|
||||
|
||||
initial_authorities_set.map_err(|error| format!("Error reading GRANDPA authorities set: {:?}", error))
|
||||
initial_authorities_set
|
||||
.map_err(|error| format!("Error reading GRANDPA authorities set: {:?}", error))
|
||||
}
|
||||
|
||||
/// Deploy bridge contract to Ethereum chain.
|
||||
@@ -147,7 +151,12 @@ async fn deploy_bridge_contract(
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
bridge_contract::constructor(contract_code, initial_header, initial_set_id, initial_authorities),
|
||||
bridge_contract::constructor(
|
||||
contract_code,
|
||||
initial_header,
|
||||
initial_set_id,
|
||||
initial_authorities,
|
||||
),
|
||||
)
|
||||
.await
|
||||
.map_err(|error| format!("Error deploying contract: {:?}", error))
|
||||
|
||||
@@ -16,28 +16,34 @@
|
||||
|
||||
//! Relaying proofs of PoA -> Substrate exchange transactions.
|
||||
|
||||
use crate::instances::BridgeInstance;
|
||||
use crate::rialto_client::{SubmitEthereumExchangeTransactionProof, SubstrateHighLevelRpc};
|
||||
use crate::rpc_errors::RpcError;
|
||||
use crate::substrate_types::into_substrate_ethereum_receipt;
|
||||
use crate::{
|
||||
instances::BridgeInstance,
|
||||
rialto_client::{SubmitEthereumExchangeTransactionProof, SubstrateHighLevelRpc},
|
||||
rpc_errors::RpcError,
|
||||
substrate_types::into_substrate_ethereum_receipt,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_currency_exchange::MaybeLockFundsTransaction;
|
||||
use exchange_relay::exchange::{
|
||||
relay_single_transaction_proof, SourceBlock, SourceClient, SourceTransaction, TargetClient,
|
||||
TransactionProofPipeline,
|
||||
use exchange_relay::{
|
||||
exchange::{
|
||||
relay_single_transaction_proof, SourceBlock, SourceClient, SourceTransaction, TargetClient,
|
||||
TransactionProofPipeline,
|
||||
},
|
||||
exchange_loop::{run as run_loop, InMemoryStorage},
|
||||
};
|
||||
use exchange_relay::exchange_loop::{run as run_loop, InMemoryStorage};
|
||||
use relay_ethereum_client::{
|
||||
types::{
|
||||
HeaderId as EthereumHeaderId, HeaderWithTransactions as EthereumHeaderWithTransactions,
|
||||
Transaction as EthereumTransaction, TransactionHash as EthereumTransactionHash, H256, HEADER_ID_PROOF,
|
||||
Transaction as EthereumTransaction, TransactionHash as EthereumTransactionHash, H256,
|
||||
HEADER_ID_PROOF,
|
||||
},
|
||||
Client as EthereumClient, ConnectionParams as EthereumConnectionParams,
|
||||
};
|
||||
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_substrate_client::{
|
||||
Chain as SubstrateChain, Client as SubstrateClient, ConnectionParams as SubstrateConnectionParams,
|
||||
Chain as SubstrateChain, Client as SubstrateClient,
|
||||
ConnectionParams as SubstrateConnectionParams,
|
||||
};
|
||||
use relay_utils::{metrics::MetricsParams, relay_loop::Client as RelayClient, HeaderId};
|
||||
use rialto_runtime::exchange::EthereumTransactionInclusionProof;
|
||||
@@ -111,12 +117,7 @@ impl SourceBlock for EthereumSourceBlock {
|
||||
}
|
||||
|
||||
fn transactions(&self) -> Vec<Self::Transaction> {
|
||||
self.0
|
||||
.transactions
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(EthereumSourceTransaction)
|
||||
.collect()
|
||||
self.0.transactions.iter().cloned().map(EthereumSourceTransaction).collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,13 +179,12 @@ impl SourceClient<EthereumToSubstrateExchange> for EthereumTransactionsSource {
|
||||
};
|
||||
|
||||
// we need transaction to be mined => check if it is included in the block
|
||||
let (eth_header_id, eth_tx_index) = match (eth_tx.block_number, eth_tx.block_hash, eth_tx.transaction_index) {
|
||||
(Some(block_number), Some(block_hash), Some(transaction_index)) => (
|
||||
HeaderId(block_number.as_u64(), block_hash),
|
||||
transaction_index.as_u64() as _,
|
||||
),
|
||||
_ => return Ok(None),
|
||||
};
|
||||
let (eth_header_id, eth_tx_index) =
|
||||
match (eth_tx.block_number, eth_tx.block_hash, eth_tx.transaction_index) {
|
||||
(Some(block_number), Some(block_hash), Some(transaction_index)) =>
|
||||
(HeaderId(block_number.as_u64(), block_hash), transaction_index.as_u64() as _),
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
Ok(Some((eth_header_id, eth_tx_index)))
|
||||
}
|
||||
@@ -194,9 +194,11 @@ impl SourceClient<EthereumToSubstrateExchange> for EthereumTransactionsSource {
|
||||
block: &EthereumSourceBlock,
|
||||
tx_index: usize,
|
||||
) -> Result<EthereumTransactionInclusionProof, RpcError> {
|
||||
const TRANSACTION_HAS_RAW_FIELD_PROOF: &str = "RPC level checks that transactions from Ethereum\
|
||||
const TRANSACTION_HAS_RAW_FIELD_PROOF: &str =
|
||||
"RPC level checks that transactions from Ethereum\
|
||||
node are having `raw` field; qed";
|
||||
const BLOCK_HAS_HASH_FIELD_PROOF: &str = "RPC level checks that block has `hash` field; qed";
|
||||
const BLOCK_HAS_HASH_FIELD_PROOF: &str =
|
||||
"RPC level checks that block has `hash` field; qed";
|
||||
|
||||
let mut transaction_proof = Vec::with_capacity(block.0.transactions.len());
|
||||
for tx in &block.0.transactions {
|
||||
@@ -266,12 +268,15 @@ impl TargetClient<EthereumToSubstrateExchange> for SubstrateTransactionsTarget {
|
||||
self.client.best_ethereum_finalized_block().await
|
||||
}
|
||||
|
||||
async fn filter_transaction_proof(&self, proof: &EthereumTransactionInclusionProof) -> Result<bool, RpcError> {
|
||||
async fn filter_transaction_proof(
|
||||
&self,
|
||||
proof: &EthereumTransactionInclusionProof,
|
||||
) -> Result<bool, RpcError> {
|
||||
// let's try to parse transaction locally
|
||||
let (raw_tx, raw_tx_receipt) = &proof.proof[proof.index as usize];
|
||||
let parse_result = rialto_runtime::exchange::EthTransaction::parse(raw_tx);
|
||||
if parse_result.is_err() {
|
||||
return Ok(false);
|
||||
return Ok(false)
|
||||
}
|
||||
|
||||
// now let's check if transaction is successful
|
||||
@@ -285,8 +290,12 @@ impl TargetClient<EthereumToSubstrateExchange> for SubstrateTransactionsTarget {
|
||||
self.client.verify_exchange_transaction_proof(proof.clone()).await
|
||||
}
|
||||
|
||||
async fn submit_transaction_proof(&self, proof: EthereumTransactionInclusionProof) -> Result<(), RpcError> {
|
||||
let (sign_params, bridge_instance) = (self.sign_params.clone(), self.bridge_instance.clone());
|
||||
async fn submit_transaction_proof(
|
||||
&self,
|
||||
proof: EthereumTransactionInclusionProof,
|
||||
) -> Result<(), RpcError> {
|
||||
let (sign_params, bridge_instance) =
|
||||
(self.sign_params.clone(), self.bridge_instance.clone());
|
||||
self.client
|
||||
.submit_exchange_transaction_proof(sign_params, bridge_instance, proof)
|
||||
.await
|
||||
@@ -311,9 +320,10 @@ pub async fn run(params: EthereumExchangeParams) {
|
||||
err,
|
||||
),
|
||||
}
|
||||
}
|
||||
},
|
||||
ExchangeRelayMode::Auto(eth_start_with_block_number) => {
|
||||
let result = run_auto_transactions_relay_loop(params, eth_start_with_block_number).await;
|
||||
let result =
|
||||
run_auto_transactions_relay_loop(params, eth_start_with_block_number).await;
|
||||
if let Err(err) = result {
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
@@ -321,23 +331,18 @@ pub async fn run(params: EthereumExchangeParams) {
|
||||
err,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Run single transaction proof relay and stop.
|
||||
async fn run_single_transaction_relay(params: EthereumExchangeParams, eth_tx_hash: H256) -> Result<(), String> {
|
||||
let EthereumExchangeParams {
|
||||
eth_params,
|
||||
sub_params,
|
||||
sub_sign,
|
||||
instance,
|
||||
..
|
||||
} = params;
|
||||
async fn run_single_transaction_relay(
|
||||
params: EthereumExchangeParams,
|
||||
eth_tx_hash: H256,
|
||||
) -> Result<(), String> {
|
||||
let EthereumExchangeParams { eth_params, sub_params, sub_sign, instance, .. } = params;
|
||||
|
||||
let eth_client = EthereumClient::try_connect(eth_params)
|
||||
.await
|
||||
.map_err(RpcError::Ethereum)?;
|
||||
let eth_client = EthereumClient::try_connect(eth_params).await.map_err(RpcError::Ethereum)?;
|
||||
let sub_client = SubstrateClient::<Rialto>::try_connect(sub_params)
|
||||
.await
|
||||
.map_err(RpcError::Substrate)?;
|
||||
@@ -357,12 +362,7 @@ async fn run_auto_transactions_relay_loop(
|
||||
eth_start_with_block_number: Option<u64>,
|
||||
) -> anyhow::Result<()> {
|
||||
let EthereumExchangeParams {
|
||||
eth_params,
|
||||
sub_params,
|
||||
sub_sign,
|
||||
metrics_params,
|
||||
instance,
|
||||
..
|
||||
eth_params, sub_params, sub_sign, metrics_params, instance, ..
|
||||
} = params;
|
||||
|
||||
let eth_client = EthereumClient::new(eth_params).await;
|
||||
@@ -370,7 +370,7 @@ async fn run_auto_transactions_relay_loop(
|
||||
|
||||
let eth_start_with_block_number = match eth_start_with_block_number {
|
||||
Some(eth_start_with_block_number) => eth_start_with_block_number,
|
||||
None => {
|
||||
None =>
|
||||
sub_client
|
||||
.best_ethereum_finalized_block()
|
||||
.await
|
||||
@@ -380,8 +380,7 @@ async fn run_auto_transactions_relay_loop(
|
||||
err
|
||||
)
|
||||
})?
|
||||
.0
|
||||
}
|
||||
.0,
|
||||
};
|
||||
|
||||
run_loop(
|
||||
|
||||
@@ -22,7 +22,8 @@ use bp_eth_poa::{
|
||||
};
|
||||
use relay_ethereum_client::{
|
||||
types::{CallRequest, U256},
|
||||
Client as EthereumClient, ConnectionParams as EthereumConnectionParams, SigningParams as EthereumSigningParams,
|
||||
Client as EthereumClient, ConnectionParams as EthereumConnectionParams,
|
||||
SigningParams as EthereumSigningParams,
|
||||
};
|
||||
use rialto_runtime::exchange::LOCK_FUNDS_ADDRESS;
|
||||
|
||||
@@ -43,13 +44,8 @@ pub struct EthereumExchangeSubmitParams {
|
||||
|
||||
/// Submit single Ethereum -> Substrate exchange transaction.
|
||||
pub async fn run(params: EthereumExchangeSubmitParams) {
|
||||
let EthereumExchangeSubmitParams {
|
||||
eth_params,
|
||||
eth_sign,
|
||||
eth_nonce,
|
||||
eth_amount,
|
||||
sub_recipient,
|
||||
} = params;
|
||||
let EthereumExchangeSubmitParams { eth_params, eth_sign, eth_nonce, eth_amount, sub_recipient } =
|
||||
params;
|
||||
|
||||
let result: Result<_, String> = async move {
|
||||
let eth_client = EthereumClient::try_connect(eth_params)
|
||||
@@ -83,9 +79,8 @@ pub async fn run(params: EthereumExchangeSubmitParams) {
|
||||
value: eth_amount,
|
||||
payload: sub_recipient_encoded.to_vec(),
|
||||
};
|
||||
let eth_tx_signed = eth_tx_unsigned
|
||||
.clone()
|
||||
.sign_by(ð_sign.signer, Some(eth_sign.chain_id));
|
||||
let eth_tx_signed =
|
||||
eth_tx_unsigned.clone().sign_by(ð_sign.signer, Some(eth_sign.chain_id));
|
||||
eth_client
|
||||
.submit_transaction(eth_tx_signed)
|
||||
.await
|
||||
@@ -102,13 +97,13 @@ pub async fn run(params: EthereumExchangeSubmitParams) {
|
||||
"Exchange transaction has been submitted to Ethereum node: {:?}",
|
||||
eth_tx_unsigned,
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::error!(
|
||||
target: "bridge",
|
||||
"Error submitting exchange transaction to Ethereum node: {}",
|
||||
err,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
//! Ethereum PoA -> Rialto-Substrate synchronization.
|
||||
|
||||
use crate::ethereum_client::EthereumHighLevelRpc;
|
||||
use crate::instances::BridgeInstance;
|
||||
use crate::rialto_client::{SubmitEthereumHeaders, SubstrateHighLevelRpc};
|
||||
use crate::rpc_errors::RpcError;
|
||||
use crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts};
|
||||
use crate::{
|
||||
ethereum_client::EthereumHighLevelRpc,
|
||||
instances::BridgeInstance,
|
||||
rialto_client::{SubmitEthereumHeaders, SubstrateHighLevelRpc},
|
||||
rpc_errors::RpcError,
|
||||
substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts},
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use codec::Encode;
|
||||
@@ -35,12 +37,12 @@ use relay_ethereum_client::{
|
||||
};
|
||||
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_substrate_client::{
|
||||
Chain as SubstrateChain, Client as SubstrateClient, ConnectionParams as SubstrateConnectionParams,
|
||||
Chain as SubstrateChain, Client as SubstrateClient,
|
||||
ConnectionParams as SubstrateConnectionParams,
|
||||
};
|
||||
use relay_utils::{metrics::MetricsParams, relay_loop::Client as RelayClient};
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::{collections::HashSet, sync::Arc, time::Duration};
|
||||
use std::{collections::HashSet, fmt::Debug, sync::Arc, time::Duration};
|
||||
|
||||
pub mod consts {
|
||||
use super::*;
|
||||
@@ -57,7 +59,8 @@ pub mod consts {
|
||||
pub const MAX_FUTURE_HEADERS_TO_DOWNLOAD: usize = 128;
|
||||
/// Max Ethereum headers count we want to have in 'submitted' state.
|
||||
pub const MAX_SUBMITTED_HEADERS: usize = 128;
|
||||
/// Max depth of in-memory headers in all states. Past this depth they will be forgotten (pruned).
|
||||
/// Max depth of in-memory headers in all states. Past this depth they will be forgotten
|
||||
/// (pruned).
|
||||
pub const PRUNE_DEPTH: u32 = 4096;
|
||||
}
|
||||
|
||||
@@ -106,8 +109,8 @@ impl HeadersSyncPipeline for EthereumHeadersSyncPipeline {
|
||||
type Completion = ();
|
||||
|
||||
fn estimate_size(source: &QueuedHeader<Self>) -> usize {
|
||||
into_substrate_ethereum_header(source.header()).encode().len()
|
||||
+ into_substrate_ethereum_receipts(source.extra())
|
||||
into_substrate_ethereum_header(source.header()).encode().len() +
|
||||
into_substrate_ethereum_receipts(source.extra())
|
||||
.map(|extra| extra.encode().len())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
@@ -148,22 +151,17 @@ impl SourceClient<EthereumHeadersSyncPipeline> for EthereumHeadersSource {
|
||||
}
|
||||
|
||||
async fn header_by_hash(&self, hash: HeaderHash) -> Result<Header, RpcError> {
|
||||
self.client
|
||||
.header_by_hash(hash)
|
||||
.await
|
||||
.map(Into::into)
|
||||
.map_err(Into::into)
|
||||
self.client.header_by_hash(hash).await.map(Into::into).map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn header_by_number(&self, number: u64) -> Result<Header, RpcError> {
|
||||
self.client
|
||||
.header_by_number(number)
|
||||
.await
|
||||
.map(Into::into)
|
||||
.map_err(Into::into)
|
||||
self.client.header_by_number(number).await.map(Into::into).map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn header_completion(&self, id: EthereumHeaderId) -> Result<(EthereumHeaderId, Option<()>), RpcError> {
|
||||
async fn header_completion(
|
||||
&self,
|
||||
id: EthereumHeaderId,
|
||||
) -> Result<(EthereumHeaderId, Option<()>), RpcError> {
|
||||
Ok((id, None))
|
||||
}
|
||||
|
||||
@@ -172,9 +170,7 @@ impl SourceClient<EthereumHeadersSyncPipeline> for EthereumHeadersSource {
|
||||
id: EthereumHeaderId,
|
||||
header: QueuedEthereumHeader,
|
||||
) -> Result<(EthereumHeaderId, Vec<Receipt>), RpcError> {
|
||||
self.client
|
||||
.transaction_receipts(id, header.header().transactions.clone())
|
||||
.await
|
||||
self.client.transaction_receipts(id, header.header().transactions.clone()).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,12 +193,7 @@ impl SubstrateHeadersTarget {
|
||||
sign_params: RialtoSigningParams,
|
||||
bridge_instance: Arc<dyn BridgeInstance>,
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
sign_transactions,
|
||||
sign_params,
|
||||
bridge_instance,
|
||||
}
|
||||
Self { client, sign_transactions, sign_params, bridge_instance }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,16 +216,19 @@ impl TargetClient<EthereumHeadersSyncPipeline> for SubstrateHeadersTarget {
|
||||
self.client.best_ethereum_block().await
|
||||
}
|
||||
|
||||
async fn is_known_header(&self, id: EthereumHeaderId) -> Result<(EthereumHeaderId, bool), RpcError> {
|
||||
async fn is_known_header(
|
||||
&self,
|
||||
id: EthereumHeaderId,
|
||||
) -> Result<(EthereumHeaderId, bool), RpcError> {
|
||||
Ok((id, self.client.ethereum_header_known(id).await?))
|
||||
}
|
||||
|
||||
async fn submit_headers(&self, headers: Vec<QueuedEthereumHeader>) -> SubmittedHeaders<EthereumHeaderId, RpcError> {
|
||||
let (sign_params, bridge_instance, sign_transactions) = (
|
||||
self.sign_params.clone(),
|
||||
self.bridge_instance.clone(),
|
||||
self.sign_transactions,
|
||||
);
|
||||
async fn submit_headers(
|
||||
&self,
|
||||
headers: Vec<QueuedEthereumHeader>,
|
||||
) -> SubmittedHeaders<EthereumHeaderId, RpcError> {
|
||||
let (sign_params, bridge_instance, sign_transactions) =
|
||||
(self.sign_params.clone(), self.bridge_instance.clone(), self.sign_transactions);
|
||||
self.client
|
||||
.submit_ethereum_headers(sign_params, bridge_instance, headers, sign_transactions)
|
||||
.await
|
||||
@@ -245,11 +239,18 @@ impl TargetClient<EthereumHeadersSyncPipeline> for SubstrateHeadersTarget {
|
||||
}
|
||||
|
||||
#[allow(clippy::unit_arg)]
|
||||
async fn complete_header(&self, id: EthereumHeaderId, _completion: ()) -> Result<EthereumHeaderId, RpcError> {
|
||||
async fn complete_header(
|
||||
&self,
|
||||
id: EthereumHeaderId,
|
||||
_completion: (),
|
||||
) -> Result<EthereumHeaderId, RpcError> {
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
async fn requires_extra(&self, header: QueuedEthereumHeader) -> Result<(EthereumHeaderId, bool), RpcError> {
|
||||
async fn requires_extra(
|
||||
&self,
|
||||
header: QueuedEthereumHeader,
|
||||
) -> Result<(EthereumHeaderId, bool), RpcError> {
|
||||
// we can minimize number of receipts_check calls by checking header
|
||||
// logs bloom here, but it may give us false positives (when authorities
|
||||
// source is contract, we never need any logs)
|
||||
|
||||
@@ -18,16 +18,18 @@
|
||||
//! synchronizing a Substrate chain which can include multiple instances of the bridge pallet we
|
||||
//! must somehow decide which of the instances to sync.
|
||||
//!
|
||||
//! Note that each instance of the bridge pallet is coupled with an instance of the currency exchange
|
||||
//! pallet. We must also have a way to create `Call`s for the correct currency exchange instance.
|
||||
//! Note that each instance of the bridge pallet is coupled with an instance of the currency
|
||||
//! exchange pallet. We must also have a way to create `Call`s for the correct currency exchange
|
||||
//! instance.
|
||||
//!
|
||||
//! This module helps by preparing the correct `Call`s for each of the different pallet instances.
|
||||
|
||||
use crate::ethereum_sync_loop::QueuedEthereumHeader;
|
||||
use crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts};
|
||||
use crate::{
|
||||
ethereum_sync_loop::QueuedEthereumHeader,
|
||||
substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts},
|
||||
};
|
||||
|
||||
use rialto_runtime::exchange::EthereumTransactionInclusionProof as Proof;
|
||||
use rialto_runtime::Call;
|
||||
use rialto_runtime::{exchange::EthereumTransactionInclusionProof as Proof, Call};
|
||||
|
||||
/// Interface for `Calls` which are needed to correctly sync the bridge.
|
||||
///
|
||||
@@ -73,7 +75,8 @@ impl BridgeInstance for RialtoPoA {
|
||||
}
|
||||
|
||||
fn build_currency_exchange_call(&self, proof: Proof) -> Call {
|
||||
let pallet_call = rialto_runtime::BridgeCurrencyExchangeCall::import_peer_transaction(proof);
|
||||
let pallet_call =
|
||||
rialto_runtime::BridgeCurrencyExchangeCall::import_peer_transaction(proof);
|
||||
rialto_runtime::Call::BridgeRialtoCurrencyExchange(pallet_call)
|
||||
}
|
||||
}
|
||||
@@ -109,7 +112,8 @@ impl BridgeInstance for Kovan {
|
||||
}
|
||||
|
||||
fn build_currency_exchange_call(&self, proof: Proof) -> Call {
|
||||
let pallet_call = rialto_runtime::BridgeCurrencyExchangeCall::import_peer_transaction(proof);
|
||||
let pallet_call =
|
||||
rialto_runtime::BridgeCurrencyExchangeCall::import_peer_transaction(proof);
|
||||
rialto_runtime::Call::BridgeKovanCurrencyExchange(pallet_call)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ use sp_core::crypto::Pair;
|
||||
use substrate_sync_loop::SubstrateSyncParams;
|
||||
|
||||
use headers_relay::sync::HeadersSyncParams;
|
||||
use relay_ethereum_client::{ConnectionParams as EthereumConnectionParams, SigningParams as EthereumSigningParams};
|
||||
use relay_ethereum_client::{
|
||||
ConnectionParams as EthereumConnectionParams, SigningParams as EthereumSigningParams,
|
||||
};
|
||||
use relay_rialto_client::SigningParams as RialtoSigningParams;
|
||||
use relay_substrate_client::ConnectionParams as SubstrateConnectionParams;
|
||||
use std::sync::Arc;
|
||||
@@ -64,79 +66,83 @@ async fn run_command(matches: &clap::ArgMatches<'_>) {
|
||||
Ok(ethereum_sync_params) => ethereum_sync_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error parsing parameters: {}", err);
|
||||
return;
|
||||
}
|
||||
return
|
||||
},
|
||||
})
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
log::error!(target: "bridge", "Unable to get Substrate genesis block for Ethereum sync.");
|
||||
};
|
||||
}
|
||||
},
|
||||
("sub-to-eth", Some(sub_to_eth_matches)) => {
|
||||
log::info!(target: "bridge", "Starting SUB ➡ ETH relay.");
|
||||
if substrate_sync_loop::run(match substrate_sync_params(sub_to_eth_matches) {
|
||||
Ok(substrate_sync_params) => substrate_sync_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error parsing parameters: {}", err);
|
||||
return;
|
||||
}
|
||||
return
|
||||
},
|
||||
})
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
log::error!(target: "bridge", "Unable to get Substrate genesis block for Substrate sync.");
|
||||
};
|
||||
}
|
||||
},
|
||||
("eth-deploy-contract", Some(eth_deploy_matches)) => {
|
||||
log::info!(target: "bridge", "Deploying ETH contracts.");
|
||||
ethereum_deploy_contract::run(match ethereum_deploy_contract_params(eth_deploy_matches) {
|
||||
Ok(ethereum_deploy_params) => ethereum_deploy_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error during contract deployment: {}", err);
|
||||
return;
|
||||
}
|
||||
})
|
||||
ethereum_deploy_contract::run(
|
||||
match ethereum_deploy_contract_params(eth_deploy_matches) {
|
||||
Ok(ethereum_deploy_params) => ethereum_deploy_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error during contract deployment: {}", err);
|
||||
return
|
||||
},
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
},
|
||||
("eth-submit-exchange-tx", Some(eth_exchange_submit_matches)) => {
|
||||
log::info!(target: "bridge", "Submitting ETH ➡ SUB exchange transaction.");
|
||||
ethereum_exchange_submit::run(match ethereum_exchange_submit_params(eth_exchange_submit_matches) {
|
||||
Ok(eth_exchange_submit_params) => eth_exchange_submit_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error submitting Eethereum exchange transaction: {}", err);
|
||||
return;
|
||||
}
|
||||
})
|
||||
ethereum_exchange_submit::run(
|
||||
match ethereum_exchange_submit_params(eth_exchange_submit_matches) {
|
||||
Ok(eth_exchange_submit_params) => eth_exchange_submit_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error submitting Eethereum exchange transaction: {}", err);
|
||||
return
|
||||
},
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
},
|
||||
("eth-exchange-sub", Some(eth_exchange_matches)) => {
|
||||
log::info!(target: "bridge", "Starting ETH ➡ SUB exchange transactions relay.");
|
||||
ethereum_exchange::run(match ethereum_exchange_params(eth_exchange_matches) {
|
||||
Ok(eth_exchange_params) => eth_exchange_params,
|
||||
Err(err) => {
|
||||
log::error!(target: "bridge", "Error relaying Ethereum transactions proofs: {}", err);
|
||||
return;
|
||||
}
|
||||
return
|
||||
},
|
||||
})
|
||||
.await;
|
||||
}
|
||||
},
|
||||
("", _) => {
|
||||
log::error!(target: "bridge", "No subcommand specified");
|
||||
}
|
||||
},
|
||||
_ => unreachable!("all possible subcommands are checked above; qed"),
|
||||
}
|
||||
}
|
||||
|
||||
fn ethereum_connection_params(matches: &clap::ArgMatches) -> Result<EthereumConnectionParams, String> {
|
||||
fn ethereum_connection_params(
|
||||
matches: &clap::ArgMatches,
|
||||
) -> Result<EthereumConnectionParams, String> {
|
||||
let mut params = EthereumConnectionParams::default();
|
||||
if let Some(eth_host) = matches.value_of("eth-host") {
|
||||
params.host = eth_host.into();
|
||||
}
|
||||
if let Some(eth_port) = matches.value_of("eth-port") {
|
||||
params.port = eth_port
|
||||
.parse()
|
||||
.map_err(|e| format!("Failed to parse eth-port: {}", e))?;
|
||||
params.port = eth_port.parse().map_err(|e| format!("Failed to parse eth-port: {}", e))?;
|
||||
}
|
||||
Ok(params)
|
||||
}
|
||||
@@ -144,9 +150,10 @@ fn ethereum_connection_params(matches: &clap::ArgMatches) -> Result<EthereumConn
|
||||
fn ethereum_signing_params(matches: &clap::ArgMatches) -> Result<EthereumSigningParams, String> {
|
||||
let mut params = EthereumSigningParams::default();
|
||||
if let Some(eth_signer) = matches.value_of("eth-signer") {
|
||||
params.signer =
|
||||
SecretKey::parse_slice(&hex::decode(eth_signer).map_err(|e| format!("Failed to parse eth-signer: {}", e))?)
|
||||
.map_err(|e| format!("Invalid eth-signer: {}", e))?;
|
||||
params.signer = SecretKey::parse_slice(
|
||||
&hex::decode(eth_signer).map_err(|e| format!("Failed to parse eth-signer: {}", e))?,
|
||||
)
|
||||
.map_err(|e| format!("Invalid eth-signer: {}", e))?;
|
||||
}
|
||||
if let Some(eth_chain_id) = matches.value_of("eth-chain-id") {
|
||||
params.chain_id = eth_chain_id
|
||||
@@ -156,15 +163,15 @@ fn ethereum_signing_params(matches: &clap::ArgMatches) -> Result<EthereumSigning
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
fn substrate_connection_params(matches: &clap::ArgMatches) -> Result<SubstrateConnectionParams, String> {
|
||||
fn substrate_connection_params(
|
||||
matches: &clap::ArgMatches,
|
||||
) -> Result<SubstrateConnectionParams, String> {
|
||||
let mut params = SubstrateConnectionParams::default();
|
||||
if let Some(sub_host) = matches.value_of("sub-host") {
|
||||
params.host = sub_host.into();
|
||||
}
|
||||
if let Some(sub_port) = matches.value_of("sub-port") {
|
||||
params.port = sub_port
|
||||
.parse()
|
||||
.map_err(|e| format!("Failed to parse sub-port: {}", e))?;
|
||||
params.port = sub_port.parse().map_err(|e| format!("Failed to parse sub-port: {}", e))?;
|
||||
}
|
||||
Ok(params)
|
||||
}
|
||||
@@ -199,7 +206,7 @@ fn ethereum_sync_params(matches: &clap::ArgMatches) -> Result<EthereumSyncParams
|
||||
|
||||
// tx pool won't accept too much unsigned transactions
|
||||
sync_params.max_headers_in_submitted_status = 10;
|
||||
}
|
||||
},
|
||||
Some("backup") => sync_params.target_tx_mode = TargetTransactionMode::Backup,
|
||||
Some(mode) => return Err(format!("Invalid sub-tx-mode: {}", mode)),
|
||||
None => sync_params.target_tx_mode = TargetTransactionMode::Signed,
|
||||
@@ -252,10 +259,14 @@ fn substrate_sync_params(matches: &clap::ArgMatches) -> Result<SubstrateSyncPara
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
fn ethereum_deploy_contract_params(matches: &clap::ArgMatches) -> Result<EthereumDeployContractParams, String> {
|
||||
let eth_contract_code = parse_hex_argument(matches, "eth-contract-code")?.unwrap_or_else(|| {
|
||||
hex::decode(include_str!("../res/substrate-bridge-bytecode.hex")).expect("code is hardcoded, thus valid; qed")
|
||||
});
|
||||
fn ethereum_deploy_contract_params(
|
||||
matches: &clap::ArgMatches,
|
||||
) -> Result<EthereumDeployContractParams, String> {
|
||||
let eth_contract_code =
|
||||
parse_hex_argument(matches, "eth-contract-code")?.unwrap_or_else(|| {
|
||||
hex::decode(include_str!("../res/substrate-bridge-bytecode.hex"))
|
||||
.expect("code is hardcoded, thus valid; qed")
|
||||
});
|
||||
let sub_initial_authorities_set_id = matches
|
||||
.value_of("sub-authorities-set-id")
|
||||
.map(|set| {
|
||||
@@ -281,7 +292,9 @@ fn ethereum_deploy_contract_params(matches: &clap::ArgMatches) -> Result<Ethereu
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
fn ethereum_exchange_submit_params(matches: &clap::ArgMatches) -> Result<EthereumExchangeSubmitParams, String> {
|
||||
fn ethereum_exchange_submit_params(
|
||||
matches: &clap::ArgMatches,
|
||||
) -> Result<EthereumExchangeSubmitParams, String> {
|
||||
let eth_nonce = matches
|
||||
.value_of("eth-nonce")
|
||||
.map(|eth_nonce| {
|
||||
@@ -293,9 +306,7 @@ fn ethereum_exchange_submit_params(matches: &clap::ArgMatches) -> Result<Ethereu
|
||||
let eth_amount = matches
|
||||
.value_of("eth-amount")
|
||||
.map(|eth_amount| {
|
||||
eth_amount
|
||||
.parse()
|
||||
.map_err(|e| format!("Failed to parse eth-amount: {}", e))
|
||||
eth_amount.parse().map_err(|e| format!("Failed to parse eth-amount: {}", e))
|
||||
})
|
||||
.transpose()?
|
||||
.unwrap_or_else(|| {
|
||||
@@ -304,7 +315,8 @@ fn ethereum_exchange_submit_params(matches: &clap::ArgMatches) -> Result<Ethereu
|
||||
});
|
||||
|
||||
// This is the well-known Substrate account of Ferdie
|
||||
let default_recepient = hex!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c");
|
||||
let default_recepient =
|
||||
hex!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c");
|
||||
|
||||
let sub_recipient = if let Some(sub_recipient) = matches.value_of("sub-recipient") {
|
||||
hex::decode(&sub_recipient)
|
||||
@@ -340,9 +352,7 @@ fn ethereum_exchange_submit_params(matches: &clap::ArgMatches) -> Result<Ethereu
|
||||
fn ethereum_exchange_params(matches: &clap::ArgMatches) -> Result<EthereumExchangeParams, String> {
|
||||
let mode = match matches.value_of("eth-tx-hash") {
|
||||
Some(eth_tx_hash) => ethereum_exchange::ExchangeRelayMode::Single(
|
||||
eth_tx_hash
|
||||
.parse()
|
||||
.map_err(|e| format!("Failed to parse eth-tx-hash: {}", e))?,
|
||||
eth_tx_hash.parse().map_err(|e| format!("Failed to parse eth-tx-hash: {}", e))?,
|
||||
),
|
||||
None => ethereum_exchange::ExchangeRelayMode::Auto(
|
||||
matches
|
||||
@@ -372,7 +382,7 @@ fn ethereum_exchange_params(matches: &clap::ArgMatches) -> Result<EthereumExchan
|
||||
|
||||
fn metrics_params(matches: &clap::ArgMatches) -> Result<MetricsParams, String> {
|
||||
if matches.is_present("no-prometheus") {
|
||||
return Ok(None.into());
|
||||
return Ok(None.into())
|
||||
}
|
||||
|
||||
let mut metrics_params = MetricsAddress::default();
|
||||
@@ -405,9 +415,8 @@ fn instance_params(matches: &clap::ArgMatches) -> Result<Arc<dyn BridgeInstance>
|
||||
|
||||
fn parse_hex_argument(matches: &clap::ArgMatches, arg: &str) -> Result<Option<Vec<u8>>, String> {
|
||||
match matches.value_of(arg) {
|
||||
Some(value) => Ok(Some(
|
||||
hex::decode(value).map_err(|e| format!("Failed to parse {}: {}", arg, e))?,
|
||||
)),
|
||||
Some(value) =>
|
||||
Ok(Some(hex::decode(value).map_err(|e| format!("Failed to parse {}: {}", arg, e))?)),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
// 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::ethereum_sync_loop::QueuedEthereumHeader;
|
||||
use crate::instances::BridgeInstance;
|
||||
use crate::rpc_errors::RpcError;
|
||||
use crate::{
|
||||
ethereum_sync_loop::QueuedEthereumHeader, instances::BridgeInstance, rpc_errors::RpcError,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_eth_poa::AuraHeader as SubstrateEthereumHeader;
|
||||
@@ -24,7 +24,9 @@ use codec::{Decode, Encode};
|
||||
use headers_relay::sync_types::SubmittedHeaders;
|
||||
use relay_ethereum_client::types::HeaderId as EthereumHeaderId;
|
||||
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_substrate_client::{Client as SubstrateClient, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_substrate_client::{
|
||||
Client as SubstrateClient, TransactionSignScheme, UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::HeaderId;
|
||||
use sp_core::{crypto::Pair, Bytes};
|
||||
use std::{collections::VecDeque, sync::Arc};
|
||||
@@ -33,7 +35,8 @@ const ETH_API_IMPORT_REQUIRES_RECEIPTS: &str = "RialtoPoAHeaderApi_is_import_req
|
||||
const ETH_API_IS_KNOWN_BLOCK: &str = "RialtoPoAHeaderApi_is_known_block";
|
||||
const ETH_API_BEST_BLOCK: &str = "RialtoPoAHeaderApi_best_block";
|
||||
const ETH_API_BEST_FINALIZED_BLOCK: &str = "RialtoPoAHeaderApi_finalized_block";
|
||||
const EXCH_API_FILTER_TRANSACTION_PROOF: &str = "RialtoCurrencyExchangeApi_filter_transaction_proof";
|
||||
const EXCH_API_FILTER_TRANSACTION_PROOF: &str =
|
||||
"RialtoCurrencyExchangeApi_filter_transaction_proof";
|
||||
|
||||
type RpcResult<T> = std::result::Result<T, RpcError>;
|
||||
|
||||
@@ -58,7 +61,8 @@ impl SubstrateHighLevelRpc for SubstrateClient<Rialto> {
|
||||
let data = Bytes(Vec::new());
|
||||
|
||||
let encoded_response = self.state_call(call, data, None).await?;
|
||||
let decoded_response: (u64, bp_eth_poa::H256) = Decode::decode(&mut &encoded_response.0[..])?;
|
||||
let decoded_response: (u64, bp_eth_poa::H256) =
|
||||
Decode::decode(&mut &encoded_response.0[..])?;
|
||||
|
||||
let best_header_id = HeaderId(decoded_response.0, decoded_response.1);
|
||||
Ok(best_header_id)
|
||||
@@ -69,7 +73,8 @@ impl SubstrateHighLevelRpc for SubstrateClient<Rialto> {
|
||||
let data = Bytes(Vec::new());
|
||||
|
||||
let encoded_response = self.state_call(call, data, None).await?;
|
||||
let decoded_response: (u64, bp_eth_poa::H256) = Decode::decode(&mut &encoded_response.0[..])?;
|
||||
let decoded_response: (u64, bp_eth_poa::H256) =
|
||||
Decode::decode(&mut &encoded_response.0[..])?;
|
||||
|
||||
let best_header_id = HeaderId(decoded_response.0, decoded_response.1);
|
||||
Ok(best_header_id)
|
||||
@@ -157,17 +162,23 @@ impl SubmitEthereumHeaders for SubstrateClient<Rialto> {
|
||||
let ids = headers.iter().map(|header| header.id()).collect();
|
||||
let genesis_hash = *self.genesis_hash();
|
||||
let submission_result = async {
|
||||
self.submit_signed_extrinsic((*params.public().as_array_ref()).into(), move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Rialto::sign_transaction(
|
||||
genesis_hash,
|
||||
¶ms,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(instance.build_signed_header_call(headers), transaction_nonce),
|
||||
self.submit_signed_extrinsic(
|
||||
(*params.public().as_array_ref()).into(),
|
||||
move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Rialto::sign_transaction(
|
||||
genesis_hash,
|
||||
¶ms,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(
|
||||
instance.build_signed_header_call(headers),
|
||||
transaction_nonce,
|
||||
),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
})
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -209,8 +220,8 @@ impl SubmitEthereumHeaders for SubstrateClient<Rialto> {
|
||||
submitted_headers.rejected.push(id);
|
||||
submitted_headers.rejected.extend(ids);
|
||||
submitted_headers.fatal_error = Some(error.into());
|
||||
break;
|
||||
}
|
||||
break
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,23 +270,31 @@ impl SubmitEthereumExchangeTransactionProof for SubstrateClient<Rialto> {
|
||||
proof: rialto_runtime::exchange::EthereumTransactionInclusionProof,
|
||||
) -> RpcResult<()> {
|
||||
let genesis_hash = *self.genesis_hash();
|
||||
self.submit_signed_extrinsic((*params.public().as_array_ref()).into(), move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Rialto::sign_transaction(
|
||||
genesis_hash,
|
||||
¶ms,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(instance.build_currency_exchange_call(proof), transaction_nonce),
|
||||
self.submit_signed_extrinsic(
|
||||
(*params.public().as_array_ref()).into(),
|
||||
move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Rialto::sign_transaction(
|
||||
genesis_hash,
|
||||
¶ms,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(
|
||||
instance.build_currency_exchange_call(proof),
|
||||
transaction_nonce,
|
||||
),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
})
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Create unsigned Substrate transaction for submitting Ethereum header.
|
||||
fn create_unsigned_submit_transaction(call: rialto_runtime::Call) -> rialto_runtime::UncheckedExtrinsic {
|
||||
fn create_unsigned_submit_transaction(
|
||||
call: rialto_runtime::Call,
|
||||
) -> rialto_runtime::UncheckedExtrinsic {
|
||||
rialto_runtime::UncheckedExtrinsic::new_unsigned(call)
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
//! Rialto-Substrate -> Ethereum PoA synchronization.
|
||||
|
||||
use crate::ethereum_client::EthereumHighLevelRpc;
|
||||
use crate::rpc_errors::RpcError;
|
||||
use crate::{ethereum_client::EthereumHighLevelRpc, rpc_errors::RpcError};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use codec::Encode;
|
||||
@@ -38,8 +37,7 @@ use relay_substrate_client::{
|
||||
use relay_utils::{metrics::MetricsParams, relay_loop::Client as RelayClient};
|
||||
use sp_runtime::EncodedJustification;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
use std::{collections::HashSet, fmt::Debug, time::Duration};
|
||||
|
||||
pub mod consts {
|
||||
use super::*;
|
||||
@@ -50,7 +48,8 @@ pub mod consts {
|
||||
pub const MAX_FUTURE_HEADERS_TO_DOWNLOAD: usize = 8;
|
||||
/// Max Ethereum headers count we want to have in 'submitted' state.
|
||||
pub const MAX_SUBMITTED_HEADERS: usize = 4;
|
||||
/// Max depth of in-memory headers in all states. Past this depth they will be forgotten (pruned).
|
||||
/// Max depth of in-memory headers in all states. Past this depth they will be forgotten
|
||||
/// (pruned).
|
||||
pub const PRUNE_DEPTH: u32 = 256;
|
||||
}
|
||||
|
||||
@@ -110,11 +109,7 @@ struct EthereumHeadersTarget {
|
||||
|
||||
impl EthereumHeadersTarget {
|
||||
fn new(client: EthereumClient, contract: Address, sign_params: EthereumSigningParams) -> Self {
|
||||
Self {
|
||||
client,
|
||||
contract,
|
||||
sign_params,
|
||||
}
|
||||
Self { client, contract, sign_params }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,11 +132,17 @@ impl TargetClient<SubstrateHeadersSyncPipeline> for EthereumHeadersTarget {
|
||||
self.client.best_substrate_block(self.contract).await
|
||||
}
|
||||
|
||||
async fn is_known_header(&self, id: RialtoHeaderId) -> Result<(RialtoHeaderId, bool), RpcError> {
|
||||
async fn is_known_header(
|
||||
&self,
|
||||
id: RialtoHeaderId,
|
||||
) -> Result<(RialtoHeaderId, bool), RpcError> {
|
||||
self.client.substrate_header_known(self.contract, id).await
|
||||
}
|
||||
|
||||
async fn submit_headers(&self, headers: Vec<QueuedRialtoHeader>) -> SubmittedHeaders<RialtoHeaderId, RpcError> {
|
||||
async fn submit_headers(
|
||||
&self,
|
||||
headers: Vec<QueuedRialtoHeader>,
|
||||
) -> SubmittedHeaders<RialtoHeaderId, RpcError> {
|
||||
self.client
|
||||
.submit_substrate_headers(self.sign_params.clone(), self.contract, headers)
|
||||
.await
|
||||
@@ -161,7 +162,10 @@ impl TargetClient<SubstrateHeadersSyncPipeline> for EthereumHeadersTarget {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn requires_extra(&self, header: QueuedRialtoHeader) -> Result<(RialtoHeaderId, bool), RpcError> {
|
||||
async fn requires_extra(
|
||||
&self,
|
||||
header: QueuedRialtoHeader,
|
||||
) -> Result<(RialtoHeaderId, bool), RpcError> {
|
||||
Ok((header.header().id(), false))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
//! Converting between Ethereum headers and bridge module types.
|
||||
|
||||
use bp_eth_poa::{
|
||||
AuraHeader as SubstrateEthereumHeader, LogEntry as SubstrateEthereumLogEntry, Receipt as SubstrateEthereumReceipt,
|
||||
TransactionOutcome as SubstrateEthereumTransactionOutcome,
|
||||
AuraHeader as SubstrateEthereumHeader, LogEntry as SubstrateEthereumLogEntry,
|
||||
Receipt as SubstrateEthereumReceipt, TransactionOutcome as SubstrateEthereumTransactionOutcome,
|
||||
};
|
||||
use relay_ethereum_client::types::{
|
||||
Header as EthereumHeader, Receipt as EthereumReceipt, HEADER_ID_PROOF as ETHEREUM_HEADER_ID_PROOF,
|
||||
Header as EthereumHeader, Receipt as EthereumReceipt,
|
||||
HEADER_ID_PROOF as ETHEREUM_HEADER_ID_PROOF,
|
||||
};
|
||||
|
||||
/// Convert Ethereum header into Ethereum header for Substrate.
|
||||
@@ -68,7 +69,8 @@ pub fn into_substrate_ethereum_receipt(receipt: &EthereumReceipt) -> SubstrateEt
|
||||
})
|
||||
.collect(),
|
||||
outcome: match (receipt.status, receipt.root) {
|
||||
(Some(status), None) => SubstrateEthereumTransactionOutcome::StatusCode(status.as_u64() as u8),
|
||||
(Some(status), None) =>
|
||||
SubstrateEthereumTransactionOutcome::StatusCode(status.as_u64() as u8),
|
||||
(None, Some(root)) => SubstrateEthereumTransactionOutcome::StateRoot(root),
|
||||
_ => SubstrateEthereumTransactionOutcome::Unknown,
|
||||
},
|
||||
|
||||
@@ -41,41 +41,41 @@ impl CliEncodeCall for Kusama {
|
||||
|
||||
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
|
||||
Ok(match call {
|
||||
Call::Remark { remark_payload, .. } => {
|
||||
relay_kusama_client::runtime::Call::System(relay_kusama_client::runtime::SystemCall::remark(
|
||||
Call::Remark { remark_payload, .. } => relay_kusama_client::runtime::Call::System(
|
||||
relay_kusama_client::runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
Call::BridgeSendMessage {
|
||||
lane,
|
||||
payload,
|
||||
fee,
|
||||
bridge_instance_index,
|
||||
} => match *bridge_instance_index {
|
||||
bridge::KUSAMA_TO_POLKADOT_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_kusama_client::runtime::Call::BridgePolkadotMessages(
|
||||
relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message(lane.0, payload, fee.0),
|
||||
)
|
||||
}
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
),
|
||||
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
|
||||
match *bridge_instance_index {
|
||||
bridge::KUSAMA_TO_POLKADOT_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_kusama_client::runtime::Call::BridgePolkadotMessages(
|
||||
relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message(
|
||||
lane.0, payload, fee.0,
|
||||
),
|
||||
)
|
||||
},
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_dispatch_info(call: &relay_kusama_client::runtime::Call) -> anyhow::Result<DispatchInfo> {
|
||||
fn get_dispatch_info(
|
||||
call: &relay_kusama_client::runtime::Call,
|
||||
) -> anyhow::Result<DispatchInfo> {
|
||||
match *call {
|
||||
relay_kusama_client::runtime::Call::System(relay_kusama_client::runtime::SystemCall::remark(_)) => {
|
||||
Ok(DispatchInfo {
|
||||
weight: crate::chains::kusama::SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
})
|
||||
}
|
||||
relay_kusama_client::runtime::Call::System(
|
||||
relay_kusama_client::runtime::SystemCall::remark(_),
|
||||
) => Ok(DispatchInfo {
|
||||
weight: crate::chains::kusama::SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
}),
|
||||
_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,9 @@ impl CliChain for Kusama {
|
||||
bp_kusama::max_extrinsic_weight()
|
||||
}
|
||||
|
||||
fn encode_message(_message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
|
||||
fn encode_message(
|
||||
_message: encode_message::MessagePayload,
|
||||
) -> Result<Self::MessagePayload, String> {
|
||||
Err("Sending messages from Kusama is not yet supported.".into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,15 @@ use relay_kusama_client::{Kusama, SyncHeader as KusamaSyncHeader};
|
||||
use relay_polkadot_client::{Polkadot, SigningParams as PolkadotSigningParams};
|
||||
use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
use substrate_relay_helper::finality_pipeline::{
|
||||
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
|
||||
};
|
||||
|
||||
/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat
|
||||
/// relay as gone wild.
|
||||
///
|
||||
/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 21 DOT,
|
||||
/// but let's round up to 30 DOT here.
|
||||
/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 21
|
||||
/// DOT, but let's round up to 30 DOT here.
|
||||
pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 30_000_000_000;
|
||||
|
||||
/// Kusama-to-Polkadot finality sync pipeline.
|
||||
@@ -45,7 +47,10 @@ pub(crate) struct KusamaFinalityToPolkadot {
|
||||
impl KusamaFinalityToPolkadot {
|
||||
pub fn new(target_client: Client<Polkadot>, target_sign: PolkadotSigningParams) -> Self {
|
||||
Self {
|
||||
finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot::new(target_client, target_sign),
|
||||
finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot::new(
|
||||
target_client,
|
||||
target_sign,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +58,8 @@ impl KusamaFinalityToPolkadot {
|
||||
impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot {
|
||||
type FinalitySyncPipeline = FinalityPipelineKusamaFinalityToPolkadot;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
|
||||
type TargetChain = Polkadot;
|
||||
|
||||
@@ -116,29 +122,36 @@ pub(crate) mod tests {
|
||||
B: From<u32> + std::ops::Mul<Output = B>,
|
||||
W: WeightToFeePolynomial<Balance = B>,
|
||||
{
|
||||
// we assume that the GRANDPA is not lagging here => ancestry length will be near to 0 (let's round up to 2)
|
||||
// we assume that the GRANDPA is not lagging here => ancestry length will be near to 0
|
||||
// (let's round up to 2)
|
||||
const AVG_VOTES_ANCESTRIES_LEN: u32 = 2;
|
||||
// let's assume number of validators is 1024 (more than on any existing well-known chain atm)
|
||||
// => number of precommits is *2/3 + 1
|
||||
// let's assume number of validators is 1024 (more than on any existing well-known chain
|
||||
// atm) => number of precommits is *2/3 + 1
|
||||
const AVG_PRECOMMITS_LEN: u32 = 1024 * 2 / 3 + 1;
|
||||
|
||||
// GRANDPA pallet weights. We're now using Rialto weights everywhere.
|
||||
//
|
||||
// Using Rialto runtime is slightly incorrect, because `DbWeight` of other runtimes may differ
|
||||
// from the `DbWeight` of Rialto runtime. But now (and most probably forever) it is the same.
|
||||
type GrandpaPalletWeights = pallet_bridge_grandpa::weights::RialtoWeight<rialto_runtime::Runtime>;
|
||||
// Using Rialto runtime is slightly incorrect, because `DbWeight` of other runtimes may
|
||||
// differ from the `DbWeight` of Rialto runtime. But now (and most probably forever) it is
|
||||
// the same.
|
||||
type GrandpaPalletWeights =
|
||||
pallet_bridge_grandpa::weights::RialtoWeight<rialto_runtime::Runtime>;
|
||||
|
||||
// The following formula shall not be treated as super-accurate - guard is to protect from mad relays,
|
||||
// not to protect from over-average loses.
|
||||
// The following formula shall not be treated as super-accurate - guard is to protect from
|
||||
// mad relays, not to protect from over-average loses.
|
||||
|
||||
// increase number of headers a bit
|
||||
let expected_source_headers_per_day = expected_source_headers_per_day * 110 / 100;
|
||||
let single_source_header_submit_call_weight =
|
||||
GrandpaPalletWeights::submit_finality_proof(AVG_VOTES_ANCESTRIES_LEN, AVG_PRECOMMITS_LEN);
|
||||
// for simplicity - add extra weight for base tx fee + fee that is paid for the tx size + adjusted fee
|
||||
let single_source_header_submit_call_weight = GrandpaPalletWeights::submit_finality_proof(
|
||||
AVG_VOTES_ANCESTRIES_LEN,
|
||||
AVG_PRECOMMITS_LEN,
|
||||
);
|
||||
// for simplicity - add extra weight for base tx fee + fee that is paid for the tx size +
|
||||
// adjusted fee
|
||||
let single_source_header_submit_tx_weight = single_source_header_submit_call_weight * 3 / 2;
|
||||
let single_source_header_tx_cost = W::calc(&single_source_header_submit_tx_weight);
|
||||
let maximal_expected_decrease = single_source_header_tx_cost * B::from(expected_source_headers_per_day);
|
||||
let maximal_expected_decrease =
|
||||
single_source_header_tx_cost * B::from(expected_source_headers_per_day);
|
||||
|
||||
maximal_expected_decrease
|
||||
}
|
||||
|
||||
@@ -25,17 +25,23 @@ use bp_messages::MessageNonce;
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_kusama_client::{HeaderId as KusamaHeaderId, Kusama, SigningParams as KusamaSigningParams};
|
||||
use relay_polkadot_client::{HeaderId as PolkadotHeaderId, Polkadot, SigningParams as PolkadotSigningParams};
|
||||
use relay_kusama_client::{
|
||||
HeaderId as KusamaHeaderId, Kusama, SigningParams as KusamaSigningParams,
|
||||
};
|
||||
use relay_polkadot_client::{
|
||||
HeaderId as PolkadotHeaderId, Polkadot, SigningParams as PolkadotSigningParams,
|
||||
};
|
||||
use relay_substrate_client::{Chain, Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, SubstrateMessageLane,
|
||||
SubstrateMessageLaneToSubstrate,
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics,
|
||||
SubstrateMessageLane, SubstrateMessageLaneToSubstrate,
|
||||
},
|
||||
messages_source::SubstrateMessagesSource,
|
||||
messages_target::SubstrateMessagesTarget,
|
||||
};
|
||||
use substrate_relay_helper::messages_source::SubstrateMessagesSource;
|
||||
use substrate_relay_helper::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
/// Kusama-to-Polkadot message lane.
|
||||
pub type MessageLaneKusamaMessagesToPolkadot =
|
||||
@@ -49,24 +55,32 @@ pub struct KusamaMessagesToPolkadot {
|
||||
impl SubstrateMessageLane for KusamaMessagesToPolkadot {
|
||||
type MessageLane = MessageLaneKusamaMessagesToPolkadot;
|
||||
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = bp_polkadot::TO_POLKADOT_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_polkadot::TO_POLKADOT_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::TO_POLKADOT_LATEST_GENERATED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::TO_POLKADOT_LATEST_RECEIVED_NONCE_METHOD;
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_kusama::FROM_KUSAMA_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_kusama::FROM_KUSAMA_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str =
|
||||
bp_kusama::FROM_KUSAMA_LATEST_CONFIRMED_NONCE_METHOD;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = bp_kusama::FROM_KUSAMA_UNREWARDED_RELAYERS_STATE;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str =
|
||||
bp_kusama::FROM_KUSAMA_UNREWARDED_RELAYERS_STATE;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str =
|
||||
bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_kusama::WITH_POLKADOT_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_polkadot::WITH_KUSAMA_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str =
|
||||
bp_kusama::WITH_POLKADOT_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str =
|
||||
bp_polkadot::WITH_KUSAMA_MESSAGES_PALLET_NAME;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_polkadot::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight =
|
||||
bp_polkadot::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
|
||||
type SourceChain = Kusama;
|
||||
type TargetChain = Polkadot;
|
||||
@@ -117,11 +131,7 @@ impl SubstrateMessageLane for KusamaMessagesToPolkadot {
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let FromBridgedChainMessagesProof {
|
||||
ref nonces_start,
|
||||
ref nonces_end,
|
||||
..
|
||||
} = proof;
|
||||
let FromBridgedChainMessagesProof { ref nonces_start, ref nonces_end, .. } = proof;
|
||||
let messages_count = nonces_end - nonces_start + 1;
|
||||
|
||||
let call = relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
|
||||
@@ -180,14 +190,14 @@ pub async fn run(
|
||||
// we don't know exact weights of the Polkadot runtime. So to guess weights we'll be using
|
||||
// weights from Rialto and then simply dividing it by x2.
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
select_delivery_transaction_limits::<pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>>(
|
||||
select_delivery_transaction_limits::<
|
||||
pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>,
|
||||
>(
|
||||
bp_polkadot::max_extrinsic_weight(),
|
||||
bp_polkadot::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = (
|
||||
max_messages_in_single_batch / 2,
|
||||
max_messages_weight_in_single_batch / 2,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
(max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2);
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
@@ -219,8 +229,10 @@ pub async fn run(
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target: bp_polkadot::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target: bp_polkadot::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_unrewarded_relayer_entries_at_target:
|
||||
bp_polkadot::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target:
|
||||
bp_polkadot::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
@@ -252,8 +264,10 @@ pub(crate) fn add_standalone_metrics(
|
||||
metrics_params: MetricsParams,
|
||||
source_client: Client<Kusama>,
|
||||
) -> anyhow::Result<(MetricsParams, StandaloneMessagesMetrics)> {
|
||||
let polkadot_to_kusama_conversion_rate_key =
|
||||
bp_runtime::storage_parameter_key(bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME).0;
|
||||
let polkadot_to_kusama_conversion_rate_key = bp_runtime::storage_parameter_key(
|
||||
bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME,
|
||||
)
|
||||
.0;
|
||||
|
||||
substrate_relay_helper::messages_lane::add_standalone_metrics::<KusamaMessagesToPolkadot>(
|
||||
metrics_prefix,
|
||||
|
||||
@@ -37,31 +37,26 @@ impl CliEncodeCall for Millau {
|
||||
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
|
||||
Ok(match call {
|
||||
Call::Raw { data } => Decode::decode(&mut &*data.0)?,
|
||||
Call::Remark { remark_payload, .. } => millau_runtime::Call::System(millau_runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
)),
|
||||
Call::Remark { remark_payload, .. } =>
|
||||
millau_runtime::Call::System(millau_runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
)),
|
||||
Call::Transfer { recipient, amount } => millau_runtime::Call::Balances(
|
||||
millau_runtime::BalancesCall::transfer(recipient.raw_id(), amount.cast()),
|
||||
),
|
||||
Call::BridgeSendMessage {
|
||||
lane,
|
||||
payload,
|
||||
fee,
|
||||
bridge_instance_index,
|
||||
} => match *bridge_instance_index {
|
||||
bridge::MILLAU_TO_RIALTO_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message(
|
||||
lane.0,
|
||||
payload,
|
||||
fee.cast(),
|
||||
))
|
||||
}
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
|
||||
match *bridge_instance_index {
|
||||
bridge::MILLAU_TO_RIALTO_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
millau_runtime::Call::BridgeRialtoMessages(
|
||||
millau_runtime::MessagesCall::send_message(lane.0, payload, fee.cast()),
|
||||
)
|
||||
},
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -74,7 +69,12 @@ impl CliChain for Millau {
|
||||
const RUNTIME_VERSION: RuntimeVersion = millau_runtime::VERSION;
|
||||
|
||||
type KeyPair = sp_core::sr25519::Pair;
|
||||
type MessagePayload = MessagePayload<bp_millau::AccountId, bp_rialto::AccountSigner, bp_rialto::Signature, Vec<u8>>;
|
||||
type MessagePayload = MessagePayload<
|
||||
bp_millau::AccountId,
|
||||
bp_rialto::AccountSigner,
|
||||
bp_rialto::Signature,
|
||||
Vec<u8>,
|
||||
>;
|
||||
|
||||
fn ss58_format() -> u16 {
|
||||
millau_runtime::SS58Prefix::get() as u16
|
||||
@@ -85,7 +85,9 @@ impl CliChain for Millau {
|
||||
}
|
||||
|
||||
// TODO [#854|#843] support multiple bridges?
|
||||
fn encode_message(message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
|
||||
fn encode_message(
|
||||
message: encode_message::MessagePayload,
|
||||
) -> Result<Self::MessagePayload, String> {
|
||||
match message {
|
||||
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
|
||||
.map_err(|e| format!("Failed to decode Millau's MessagePayload: {:?}", e)),
|
||||
@@ -96,7 +98,10 @@ impl CliChain for Millau {
|
||||
sender.enforce_chain::<Source>();
|
||||
let spec_version = Target::RUNTIME_VERSION.spec_version;
|
||||
let origin = CallOrigin::SourceAccount(sender.raw_id());
|
||||
encode_call::preprocess_call::<Source, Target>(&mut call, bridge::MILLAU_TO_RIALTO_INDEX);
|
||||
encode_call::preprocess_call::<Source, Target>(
|
||||
&mut call,
|
||||
bridge::MILLAU_TO_RIALTO_INDEX,
|
||||
);
|
||||
let call = Target::encode_call(&call).map_err(|e| e.to_string())?;
|
||||
let weight = call.get_dispatch_info().weight;
|
||||
|
||||
@@ -107,7 +112,7 @@ impl CliChain for Millau {
|
||||
&call,
|
||||
DispatchFeePayment::AtSourceChain,
|
||||
))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,13 @@ use bp_header_chain::justification::GrandpaJustification;
|
||||
use relay_millau_client::{Millau, SyncHeader as MillauSyncHeader};
|
||||
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
|
||||
use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
use substrate_relay_helper::finality_pipeline::{
|
||||
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
|
||||
};
|
||||
|
||||
/// Millau-to-Rialto finality sync pipeline.
|
||||
pub(crate) type FinalityPipelineMillauToRialto = SubstrateFinalityToSubstrate<Millau, Rialto, RialtoSigningParams>;
|
||||
pub(crate) type FinalityPipelineMillauToRialto =
|
||||
SubstrateFinalityToSubstrate<Millau, Rialto, RialtoSigningParams>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MillauFinalityToRialto {
|
||||
@@ -35,16 +38,15 @@ pub(crate) struct MillauFinalityToRialto {
|
||||
|
||||
impl MillauFinalityToRialto {
|
||||
pub fn new(target_client: Client<Rialto>, target_sign: RialtoSigningParams) -> Self {
|
||||
Self {
|
||||
finality_pipeline: FinalityPipelineMillauToRialto::new(target_client, target_sign),
|
||||
}
|
||||
Self { finality_pipeline: FinalityPipelineMillauToRialto::new(target_client, target_sign) }
|
||||
}
|
||||
}
|
||||
|
||||
impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto {
|
||||
type FinalitySyncPipeline = FinalityPipelineMillauToRialto;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
|
||||
|
||||
type TargetChain = Rialto;
|
||||
|
||||
@@ -59,8 +61,11 @@ impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto {
|
||||
header: MillauSyncHeader,
|
||||
proof: GrandpaJustification<bp_millau::Header>,
|
||||
) -> Bytes {
|
||||
let call =
|
||||
rialto_runtime::BridgeGrandpaMillauCall::submit_finality_proof(Box::new(header.into_inner()), proof).into();
|
||||
let call = rialto_runtime::BridgeGrandpaMillauCall::submit_finality_proof(
|
||||
Box::new(header.into_inner()),
|
||||
proof,
|
||||
)
|
||||
.into();
|
||||
|
||||
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
|
||||
let transaction = Rialto::sign_transaction(
|
||||
|
||||
@@ -26,16 +26,22 @@ use bp_messages::MessageNonce;
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_millau_client::{HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams};
|
||||
use relay_rialto_client::{HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_millau_client::{
|
||||
HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams,
|
||||
};
|
||||
use relay_rialto_client::{
|
||||
HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams,
|
||||
};
|
||||
use relay_substrate_client::{Chain, Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, SubstrateMessageLane,
|
||||
SubstrateMessageLaneToSubstrate,
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics,
|
||||
SubstrateMessageLane, SubstrateMessageLaneToSubstrate,
|
||||
},
|
||||
messages_source::SubstrateMessagesSource,
|
||||
messages_target::SubstrateMessagesTarget,
|
||||
};
|
||||
use substrate_relay_helper::messages_source::SubstrateMessagesSource;
|
||||
use substrate_relay_helper::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
/// Millau-to-Rialto message lane.
|
||||
pub type MessageLaneMillauMessagesToRialto =
|
||||
@@ -49,23 +55,30 @@ pub struct MillauMessagesToRialto {
|
||||
impl SubstrateMessageLane for MillauMessagesToRialto {
|
||||
type MessageLane = MessageLaneMillauMessagesToRialto;
|
||||
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str =
|
||||
bp_rialto::TO_RIALTO_LATEST_GENERATED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_rialto::TO_RIALTO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_rialto::TO_RIALTO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_millau::FROM_MILLAU_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_millau::FROM_MILLAU_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str =
|
||||
bp_millau::FROM_MILLAU_LATEST_CONFIRMED_NONCE_METHOD;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = bp_millau::FROM_MILLAU_UNREWARDED_RELAYERS_STATE;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str =
|
||||
bp_millau::FROM_MILLAU_UNREWARDED_RELAYERS_STATE;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str =
|
||||
bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight =
|
||||
bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
|
||||
type SourceChain = Millau;
|
||||
type TargetChain = Rialto;
|
||||
@@ -82,7 +95,8 @@ impl SubstrateMessageLane for MillauMessagesToRialto {
|
||||
) -> Bytes {
|
||||
let (relayers_state, proof) = proof;
|
||||
let call: millau_runtime::Call =
|
||||
millau_runtime::MessagesCall::receive_messages_delivery_proof(proof, relayers_state).into();
|
||||
millau_runtime::MessagesCall::receive_messages_delivery_proof(proof, relayers_state)
|
||||
.into();
|
||||
let call_weight = call.get_dispatch_info().weight;
|
||||
let genesis_hash = *self.message_lane.source_client.genesis_hash();
|
||||
let transaction = Millau::sign_transaction(
|
||||
@@ -114,11 +128,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto {
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let FromBridgedChainMessagesProof {
|
||||
ref nonces_start,
|
||||
ref nonces_end,
|
||||
..
|
||||
} = proof;
|
||||
let FromBridgedChainMessagesProof { ref nonces_start, ref nonces_end, .. } = proof;
|
||||
let messages_count = nonces_end - nonces_start + 1;
|
||||
let call: rialto_runtime::Call = rialto_runtime::MessagesCall::receive_messages_proof(
|
||||
self.message_lane.relayer_id_at_source.clone(),
|
||||
@@ -176,7 +186,9 @@ pub async fn run(
|
||||
let max_messages_size_in_single_batch = bp_rialto::max_extrinsic_size() / 3;
|
||||
// TODO: use Millau weights after https://github.com/paritytech/parity-bridges-common/issues/390
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
select_delivery_transaction_limits::<pallet_bridge_messages::weights::RialtoWeight<millau_runtime::Runtime>>(
|
||||
select_delivery_transaction_limits::<
|
||||
pallet_bridge_messages::weights::RialtoWeight<millau_runtime::Runtime>,
|
||||
>(
|
||||
bp_rialto::max_extrinsic_weight(),
|
||||
bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
);
|
||||
@@ -211,8 +223,10 @@ pub async fn run(
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target: bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target: bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_unrewarded_relayer_entries_at_target:
|
||||
bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target:
|
||||
bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
@@ -251,7 +265,9 @@ pub(crate) fn add_standalone_metrics(
|
||||
Some(crate::chains::MILLAU_ASSOCIATED_TOKEN_ID),
|
||||
Some(crate::chains::RIALTO_ASSOCIATED_TOKEN_ID),
|
||||
Some((
|
||||
sp_core::storage::StorageKey(millau_runtime::rialto_messages::RialtoToMillauConversionRate::key().to_vec()),
|
||||
sp_core::storage::StorageKey(
|
||||
millau_runtime::rialto_messages::RialtoToMillauConversionRate::key().to_vec(),
|
||||
),
|
||||
millau_runtime::rialto_messages::INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE,
|
||||
)),
|
||||
)
|
||||
|
||||
@@ -38,9 +38,9 @@ mod rococo;
|
||||
mod westend;
|
||||
mod wococo;
|
||||
|
||||
// Millau/Rialto tokens have no any real value, so the conversion rate we use is always 1:1. But we want to
|
||||
// test our code that is intended to work with real-value chains. So to keep it close to 1:1, we'll be treating
|
||||
// Rialto as BTC and Millau as wBTC (only in relayer).
|
||||
// Millau/Rialto tokens have no any real value, so the conversion rate we use is always 1:1. But we
|
||||
// want to test our code that is intended to work with real-value chains. So to keep it close to
|
||||
// 1:1, we'll be treating Rialto as BTC and Millau as wBTC (only in relayer).
|
||||
|
||||
/// The identifier of token, which value is associated with Rialto token value by relayer.
|
||||
pub(crate) const RIALTO_ASSOCIATED_TOKEN_ID: &str = polkadot::TOKEN_ID;
|
||||
@@ -53,8 +53,8 @@ pub(crate) fn add_polkadot_kusama_price_metrics<T: finality_relay::FinalitySyncP
|
||||
prefix: Option<String>,
|
||||
params: MetricsParams,
|
||||
) -> anyhow::Result<MetricsParams> {
|
||||
// Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <-> Kusama
|
||||
// relays, but we want to test metrics/dashboards in advance
|
||||
// Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <->
|
||||
// Kusama relays, but we want to test metrics/dashboards in advance
|
||||
Ok(relay_utils::relay_metrics(prefix, params)
|
||||
.standalone_metric(|registry, prefix| {
|
||||
substrate_relay_helper::helpers::token_price_metric(registry, prefix, "polkadot")
|
||||
@@ -92,7 +92,8 @@ mod tests {
|
||||
rialto_runtime::VERSION.spec_version,
|
||||
);
|
||||
|
||||
let rialto_signer = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
|
||||
let rialto_signer =
|
||||
relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
|
||||
let signature = rialto_signer.sign(&digest);
|
||||
|
||||
assert!(signature.verify(&digest[..], &rialto_signer.public()));
|
||||
@@ -113,7 +114,8 @@ mod tests {
|
||||
millau_runtime::VERSION.spec_version,
|
||||
);
|
||||
|
||||
let millau_signer = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
|
||||
let millau_signer =
|
||||
relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
|
||||
let signature = millau_signer.sign(&digest);
|
||||
|
||||
assert!(signature.verify(&digest[..], &millau_signer.public()));
|
||||
@@ -128,7 +130,8 @@ mod tests {
|
||||
bp_millau::max_extrinsic_size(),
|
||||
);
|
||||
|
||||
let call: millau_runtime::Call = millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into();
|
||||
let call: millau_runtime::Call =
|
||||
millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into();
|
||||
let payload = send_message::message_payload(
|
||||
Default::default(),
|
||||
call.get_dispatch_info().weight,
|
||||
@@ -164,8 +167,9 @@ mod tests {
|
||||
fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() {
|
||||
use rialto_runtime::millau_messages::Millau;
|
||||
|
||||
let maximal_dispatch_weight =
|
||||
send_message::compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight());
|
||||
let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight(
|
||||
bp_millau::max_extrinsic_weight(),
|
||||
);
|
||||
let call: millau_runtime::Call = rialto_runtime::SystemCall::remark(vec![]).into();
|
||||
|
||||
let payload = send_message::message_payload(
|
||||
@@ -191,8 +195,9 @@ mod tests {
|
||||
fn maximal_weight_fill_block_to_rialto_is_generated_correctly() {
|
||||
use millau_runtime::rialto_messages::Rialto;
|
||||
|
||||
let maximal_dispatch_weight =
|
||||
send_message::compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight());
|
||||
let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight(
|
||||
bp_rialto::max_extrinsic_weight(),
|
||||
);
|
||||
let call: rialto_runtime::Call = millau_runtime::SystemCall::remark(vec![]).into();
|
||||
|
||||
let payload = send_message::message_payload(
|
||||
@@ -325,7 +330,10 @@ mod westend_tests {
|
||||
votes_ancestries: vec![],
|
||||
};
|
||||
|
||||
let actual = bp_westend::BridgeGrandpaRococoCall::submit_finality_proof(header.clone(), justification.clone());
|
||||
let actual = bp_westend::BridgeGrandpaRococoCall::submit_finality_proof(
|
||||
header.clone(),
|
||||
justification.clone(),
|
||||
);
|
||||
let expected = millau_runtime::BridgeGrandpaRialtoCall::<millau_runtime::Runtime>::submit_finality_proof(
|
||||
Box::new(header),
|
||||
justification,
|
||||
|
||||
@@ -41,41 +41,41 @@ impl CliEncodeCall for Polkadot {
|
||||
|
||||
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
|
||||
Ok(match call {
|
||||
Call::Remark { remark_payload, .. } => {
|
||||
relay_polkadot_client::runtime::Call::System(relay_polkadot_client::runtime::SystemCall::remark(
|
||||
Call::Remark { remark_payload, .. } => relay_polkadot_client::runtime::Call::System(
|
||||
relay_polkadot_client::runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
Call::BridgeSendMessage {
|
||||
lane,
|
||||
payload,
|
||||
fee,
|
||||
bridge_instance_index,
|
||||
} => match *bridge_instance_index {
|
||||
bridge::POLKADOT_TO_KUSAMA_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
|
||||
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message(lane.0, payload, fee.0),
|
||||
)
|
||||
}
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
),
|
||||
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
|
||||
match *bridge_instance_index {
|
||||
bridge::POLKADOT_TO_KUSAMA_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
|
||||
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message(
|
||||
lane.0, payload, fee.0,
|
||||
),
|
||||
)
|
||||
},
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_dispatch_info(call: &relay_polkadot_client::runtime::Call) -> anyhow::Result<DispatchInfo> {
|
||||
fn get_dispatch_info(
|
||||
call: &relay_polkadot_client::runtime::Call,
|
||||
) -> anyhow::Result<DispatchInfo> {
|
||||
match *call {
|
||||
relay_polkadot_client::runtime::Call::System(relay_polkadot_client::runtime::SystemCall::remark(_)) => {
|
||||
Ok(DispatchInfo {
|
||||
weight: crate::chains::polkadot::SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
})
|
||||
}
|
||||
relay_polkadot_client::runtime::Call::System(
|
||||
relay_polkadot_client::runtime::SystemCall::remark(_),
|
||||
) => Ok(DispatchInfo {
|
||||
weight: crate::chains::polkadot::SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
}),
|
||||
_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,9 @@ impl CliChain for Polkadot {
|
||||
bp_polkadot::max_extrinsic_weight()
|
||||
}
|
||||
|
||||
fn encode_message(_message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
|
||||
fn encode_message(
|
||||
_message: encode_message::MessagePayload,
|
||||
) -> Result<Self::MessagePayload, String> {
|
||||
Err("Sending messages from Polkadot is not yet supported.".into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,15 @@ use relay_kusama_client::{Kusama, SigningParams as KusamaSigningParams};
|
||||
use relay_polkadot_client::{Polkadot, SyncHeader as PolkadotSyncHeader};
|
||||
use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
use substrate_relay_helper::finality_pipeline::{
|
||||
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
|
||||
};
|
||||
|
||||
/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat
|
||||
/// relay as gone wild.
|
||||
///
|
||||
/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 0.001 KSM,
|
||||
/// but let's round up to 0.1 KSM here.
|
||||
/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 0.001
|
||||
/// KSM, but let's round up to 0.1 KSM here.
|
||||
pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 100_000_000_000;
|
||||
|
||||
/// Polkadot-to-Kusama finality sync pipeline.
|
||||
@@ -45,7 +47,10 @@ pub(crate) struct PolkadotFinalityToKusama {
|
||||
impl PolkadotFinalityToKusama {
|
||||
pub fn new(target_client: Client<Kusama>, target_sign: KusamaSigningParams) -> Self {
|
||||
Self {
|
||||
finality_pipeline: FinalityPipelinePolkadotFinalityToKusama::new(target_client, target_sign),
|
||||
finality_pipeline: FinalityPipelinePolkadotFinalityToKusama::new(
|
||||
target_client,
|
||||
target_sign,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +58,8 @@ impl PolkadotFinalityToKusama {
|
||||
impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama {
|
||||
type FinalitySyncPipeline = FinalityPipelinePolkadotFinalityToKusama;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
|
||||
type TargetChain = Kusama;
|
||||
|
||||
|
||||
@@ -25,17 +25,23 @@ use bp_messages::MessageNonce;
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_kusama_client::{HeaderId as KusamaHeaderId, Kusama, SigningParams as KusamaSigningParams};
|
||||
use relay_polkadot_client::{HeaderId as PolkadotHeaderId, Polkadot, SigningParams as PolkadotSigningParams};
|
||||
use relay_kusama_client::{
|
||||
HeaderId as KusamaHeaderId, Kusama, SigningParams as KusamaSigningParams,
|
||||
};
|
||||
use relay_polkadot_client::{
|
||||
HeaderId as PolkadotHeaderId, Polkadot, SigningParams as PolkadotSigningParams,
|
||||
};
|
||||
use relay_substrate_client::{Chain, Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, SubstrateMessageLane,
|
||||
SubstrateMessageLaneToSubstrate,
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics,
|
||||
SubstrateMessageLane, SubstrateMessageLaneToSubstrate,
|
||||
},
|
||||
messages_source::SubstrateMessagesSource,
|
||||
messages_target::SubstrateMessagesTarget,
|
||||
};
|
||||
use substrate_relay_helper::messages_source::SubstrateMessagesSource;
|
||||
use substrate_relay_helper::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
/// Polkadot-to-Kusama message lane.
|
||||
pub type MessageLanePolkadotMessagesToKusama =
|
||||
@@ -48,24 +54,32 @@ pub struct PolkadotMessagesToKusama {
|
||||
|
||||
impl SubstrateMessageLane for PolkadotMessagesToKusama {
|
||||
type MessageLane = MessageLanePolkadotMessagesToKusama;
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = bp_kusama::TO_KUSAMA_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_kusama::TO_KUSAMA_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str =
|
||||
bp_kusama::TO_KUSAMA_LATEST_GENERATED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_kusama::TO_KUSAMA_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_kusama::TO_KUSAMA_LATEST_RECEIVED_NONCE_METHOD;
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::FROM_POLKADOT_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::FROM_POLKADOT_LATEST_CONFIRMED_NONCE_METHOD;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = bp_polkadot::FROM_POLKADOT_UNREWARDED_RELAYERS_STATE;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str =
|
||||
bp_polkadot::FROM_POLKADOT_UNREWARDED_RELAYERS_STATE;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str =
|
||||
bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_polkadot::WITH_KUSAMA_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_kusama::WITH_POLKADOT_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str =
|
||||
bp_polkadot::WITH_KUSAMA_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str =
|
||||
bp_kusama::WITH_POLKADOT_MESSAGES_PALLET_NAME;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_kusama::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight =
|
||||
bp_kusama::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
|
||||
type SourceChain = Polkadot;
|
||||
type TargetChain = Kusama;
|
||||
@@ -116,11 +130,7 @@ impl SubstrateMessageLane for PolkadotMessagesToKusama {
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let FromBridgedChainMessagesProof {
|
||||
ref nonces_start,
|
||||
ref nonces_end,
|
||||
..
|
||||
} = proof;
|
||||
let FromBridgedChainMessagesProof { ref nonces_start, ref nonces_end, .. } = proof;
|
||||
let messages_count = nonces_end - nonces_start + 1;
|
||||
|
||||
let call = relay_kusama_client::runtime::Call::BridgePolkadotMessages(
|
||||
@@ -179,14 +189,14 @@ pub async fn run(
|
||||
// we don't know exact weights of the Kusama runtime. So to guess weights we'll be using
|
||||
// weights from Rialto and then simply dividing it by x2.
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
select_delivery_transaction_limits::<pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>>(
|
||||
select_delivery_transaction_limits::<
|
||||
pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>,
|
||||
>(
|
||||
bp_kusama::max_extrinsic_weight(),
|
||||
bp_kusama::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = (
|
||||
max_messages_in_single_batch / 2,
|
||||
max_messages_weight_in_single_batch / 2,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
(max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2);
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
@@ -218,8 +228,10 @@ pub async fn run(
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target: bp_kusama::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target: bp_kusama::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_unrewarded_relayer_entries_at_target:
|
||||
bp_kusama::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target:
|
||||
bp_kusama::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
@@ -251,8 +263,10 @@ pub(crate) fn add_standalone_metrics(
|
||||
metrics_params: MetricsParams,
|
||||
source_client: Client<Polkadot>,
|
||||
) -> anyhow::Result<(MetricsParams, StandaloneMessagesMetrics)> {
|
||||
let kusama_to_polkadot_conversion_rate_key =
|
||||
bp_runtime::storage_parameter_key(bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME).0;
|
||||
let kusama_to_polkadot_conversion_rate_key = bp_runtime::storage_parameter_key(
|
||||
bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME,
|
||||
)
|
||||
.0;
|
||||
|
||||
substrate_relay_helper::messages_lane::add_standalone_metrics::<PolkadotMessagesToKusama>(
|
||||
metrics_prefix,
|
||||
|
||||
@@ -37,29 +37,26 @@ impl CliEncodeCall for Rialto {
|
||||
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
|
||||
Ok(match call {
|
||||
Call::Raw { data } => Decode::decode(&mut &*data.0)?,
|
||||
Call::Remark { remark_payload, .. } => rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
)),
|
||||
Call::Remark { remark_payload, .. } =>
|
||||
rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
)),
|
||||
Call::Transfer { recipient, amount } => rialto_runtime::Call::Balances(
|
||||
rialto_runtime::BalancesCall::transfer(recipient.raw_id().into(), amount.0),
|
||||
),
|
||||
Call::BridgeSendMessage {
|
||||
lane,
|
||||
payload,
|
||||
fee,
|
||||
bridge_instance_index,
|
||||
} => match *bridge_instance_index {
|
||||
bridge::RIALTO_TO_MILLAU_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message(
|
||||
lane.0, payload, fee.0,
|
||||
))
|
||||
}
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
|
||||
match *bridge_instance_index {
|
||||
bridge::RIALTO_TO_MILLAU_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
rialto_runtime::Call::BridgeMillauMessages(
|
||||
rialto_runtime::MessagesCall::send_message(lane.0, payload, fee.0),
|
||||
)
|
||||
},
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -72,7 +69,12 @@ impl CliChain for Rialto {
|
||||
const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION;
|
||||
|
||||
type KeyPair = sp_core::sr25519::Pair;
|
||||
type MessagePayload = MessagePayload<bp_rialto::AccountId, bp_millau::AccountSigner, bp_millau::Signature, Vec<u8>>;
|
||||
type MessagePayload = MessagePayload<
|
||||
bp_rialto::AccountId,
|
||||
bp_millau::AccountSigner,
|
||||
bp_millau::Signature,
|
||||
Vec<u8>,
|
||||
>;
|
||||
|
||||
fn ss58_format() -> u16 {
|
||||
rialto_runtime::SS58Prefix::get() as u16
|
||||
@@ -82,7 +84,9 @@ impl CliChain for Rialto {
|
||||
bp_rialto::max_extrinsic_weight()
|
||||
}
|
||||
|
||||
fn encode_message(message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
|
||||
fn encode_message(
|
||||
message: encode_message::MessagePayload,
|
||||
) -> Result<Self::MessagePayload, String> {
|
||||
match message {
|
||||
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
|
||||
.map_err(|e| format!("Failed to decode Rialto's MessagePayload: {:?}", e)),
|
||||
@@ -93,7 +97,10 @@ impl CliChain for Rialto {
|
||||
sender.enforce_chain::<Source>();
|
||||
let spec_version = Target::RUNTIME_VERSION.spec_version;
|
||||
let origin = CallOrigin::SourceAccount(sender.raw_id());
|
||||
encode_call::preprocess_call::<Source, Target>(&mut call, bridge::RIALTO_TO_MILLAU_INDEX);
|
||||
encode_call::preprocess_call::<Source, Target>(
|
||||
&mut call,
|
||||
bridge::RIALTO_TO_MILLAU_INDEX,
|
||||
);
|
||||
let call = Target::encode_call(&call).map_err(|e| e.to_string())?;
|
||||
let weight = call.get_dispatch_info().weight;
|
||||
|
||||
@@ -104,7 +111,7 @@ impl CliChain for Rialto {
|
||||
&call,
|
||||
DispatchFeePayment::AtSourceChain,
|
||||
))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ use bp_header_chain::justification::GrandpaJustification;
|
||||
use relay_millau_client::{Millau, SigningParams as MillauSigningParams};
|
||||
use relay_rialto_client::{Rialto, SyncHeader as RialtoSyncHeader};
|
||||
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
|
||||
use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
use substrate_relay_helper::finality_pipeline::{
|
||||
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
|
||||
};
|
||||
|
||||
/// Rialto-to-Millau finality sync pipeline.
|
||||
pub(crate) type FinalityPipelineRialtoFinalityToMillau =
|
||||
@@ -37,7 +39,10 @@ pub struct RialtoFinalityToMillau {
|
||||
impl RialtoFinalityToMillau {
|
||||
pub fn new(target_client: Client<Millau>, target_sign: MillauSigningParams) -> Self {
|
||||
Self {
|
||||
finality_pipeline: FinalityPipelineRialtoFinalityToMillau::new(target_client, target_sign),
|
||||
finality_pipeline: FinalityPipelineRialtoFinalityToMillau::new(
|
||||
target_client,
|
||||
target_sign,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +50,8 @@ impl RialtoFinalityToMillau {
|
||||
impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau {
|
||||
type FinalitySyncPipeline = FinalityPipelineRialtoFinalityToMillau;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
|
||||
|
||||
type TargetChain = Millau;
|
||||
|
||||
|
||||
@@ -26,16 +26,22 @@ use bp_messages::MessageNonce;
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_millau_client::{HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams};
|
||||
use relay_rialto_client::{HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_millau_client::{
|
||||
HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams,
|
||||
};
|
||||
use relay_rialto_client::{
|
||||
HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams,
|
||||
};
|
||||
use relay_substrate_client::{Chain, Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, SubstrateMessageLane,
|
||||
SubstrateMessageLaneToSubstrate,
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics,
|
||||
SubstrateMessageLane, SubstrateMessageLaneToSubstrate,
|
||||
},
|
||||
messages_source::SubstrateMessagesSource,
|
||||
messages_target::SubstrateMessagesTarget,
|
||||
};
|
||||
use substrate_relay_helper::messages_source::SubstrateMessagesSource;
|
||||
use substrate_relay_helper::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
/// Rialto-to-Millau message lane.
|
||||
pub type MessageLaneRialtoMessagesToMillau =
|
||||
@@ -49,23 +55,30 @@ pub struct RialtoMessagesToMillau {
|
||||
impl SubstrateMessageLane for RialtoMessagesToMillau {
|
||||
type MessageLane = MessageLaneRialtoMessagesToMillau;
|
||||
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str =
|
||||
bp_millau::TO_MILLAU_LATEST_GENERATED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_millau::TO_MILLAU_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_millau::TO_MILLAU_LATEST_RECEIVED_NONCE_METHOD;
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_rialto::FROM_RIALTO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_rialto::FROM_RIALTO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str =
|
||||
bp_rialto::FROM_RIALTO_LATEST_CONFIRMED_NONCE_METHOD;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = bp_rialto::FROM_RIALTO_UNREWARDED_RELAYERS_STATE;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str =
|
||||
bp_rialto::FROM_RIALTO_UNREWARDED_RELAYERS_STATE;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str =
|
||||
bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight =
|
||||
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
|
||||
type SourceChain = Rialto;
|
||||
type TargetChain = Millau;
|
||||
@@ -82,7 +95,8 @@ impl SubstrateMessageLane for RialtoMessagesToMillau {
|
||||
) -> Bytes {
|
||||
let (relayers_state, proof) = proof;
|
||||
let call: rialto_runtime::Call =
|
||||
rialto_runtime::MessagesCall::receive_messages_delivery_proof(proof, relayers_state).into();
|
||||
rialto_runtime::MessagesCall::receive_messages_delivery_proof(proof, relayers_state)
|
||||
.into();
|
||||
let call_weight = call.get_dispatch_info().weight;
|
||||
let genesis_hash = *self.message_lane.source_client.genesis_hash();
|
||||
let transaction = Rialto::sign_transaction(
|
||||
@@ -114,11 +128,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau {
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let FromBridgedChainMessagesProof {
|
||||
ref nonces_start,
|
||||
ref nonces_end,
|
||||
..
|
||||
} = proof;
|
||||
let FromBridgedChainMessagesProof { ref nonces_start, ref nonces_end, .. } = proof;
|
||||
let messages_count = nonces_end - nonces_start + 1;
|
||||
let call: millau_runtime::Call = millau_runtime::MessagesCall::receive_messages_proof(
|
||||
self.message_lane.relayer_id_at_source.clone(),
|
||||
@@ -175,7 +185,9 @@ pub async fn run(
|
||||
// 2/3 is reserved for proofs and tx overhead
|
||||
let max_messages_size_in_single_batch = bp_millau::max_extrinsic_size() / 3;
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
select_delivery_transaction_limits::<pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>>(
|
||||
select_delivery_transaction_limits::<
|
||||
pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>,
|
||||
>(
|
||||
bp_millau::max_extrinsic_weight(),
|
||||
bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
);
|
||||
@@ -210,8 +222,10 @@ pub async fn run(
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target: bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target: bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_unrewarded_relayer_entries_at_target:
|
||||
bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target:
|
||||
bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
@@ -250,7 +264,9 @@ pub(crate) fn add_standalone_metrics(
|
||||
Some(crate::chains::RIALTO_ASSOCIATED_TOKEN_ID),
|
||||
Some(crate::chains::MILLAU_ASSOCIATED_TOKEN_ID),
|
||||
Some((
|
||||
sp_core::storage::StorageKey(rialto_runtime::millau_messages::MillauToRialtoConversionRate::key().to_vec()),
|
||||
sp_core::storage::StorageKey(
|
||||
rialto_runtime::millau_messages::MillauToRialtoConversionRate::key().to_vec(),
|
||||
),
|
||||
rialto_runtime::millau_messages::INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE,
|
||||
)),
|
||||
)
|
||||
|
||||
@@ -38,41 +38,41 @@ impl CliEncodeCall for Rococo {
|
||||
|
||||
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
|
||||
Ok(match call {
|
||||
Call::Remark { remark_payload, .. } => {
|
||||
relay_rococo_client::runtime::Call::System(relay_rococo_client::runtime::SystemCall::remark(
|
||||
Call::Remark { remark_payload, .. } => relay_rococo_client::runtime::Call::System(
|
||||
relay_rococo_client::runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
Call::BridgeSendMessage {
|
||||
lane,
|
||||
payload,
|
||||
fee,
|
||||
bridge_instance_index,
|
||||
} => match *bridge_instance_index {
|
||||
bridge::ROCOCO_TO_WOCOCO_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_rococo_client::runtime::Call::BridgeMessagesWococo(
|
||||
relay_rococo_client::runtime::BridgeMessagesWococoCall::send_message(lane.0, payload, fee.0),
|
||||
)
|
||||
}
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
),
|
||||
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
|
||||
match *bridge_instance_index {
|
||||
bridge::ROCOCO_TO_WOCOCO_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_rococo_client::runtime::Call::BridgeMessagesWococo(
|
||||
relay_rococo_client::runtime::BridgeMessagesWococoCall::send_message(
|
||||
lane.0, payload, fee.0,
|
||||
),
|
||||
)
|
||||
},
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
_ => anyhow::bail!("The call is not supported"),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_dispatch_info(call: &relay_rococo_client::runtime::Call) -> anyhow::Result<DispatchInfo> {
|
||||
fn get_dispatch_info(
|
||||
call: &relay_rococo_client::runtime::Call,
|
||||
) -> anyhow::Result<DispatchInfo> {
|
||||
match *call {
|
||||
relay_rococo_client::runtime::Call::System(relay_rococo_client::runtime::SystemCall::remark(_)) => {
|
||||
Ok(DispatchInfo {
|
||||
weight: SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
})
|
||||
}
|
||||
relay_rococo_client::runtime::Call::System(
|
||||
relay_rococo_client::runtime::SystemCall::remark(_),
|
||||
) => Ok(DispatchInfo {
|
||||
weight: SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
}),
|
||||
_ => anyhow::bail!("Unsupported Rococo call: {:?}", call),
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,9 @@ impl CliChain for Rococo {
|
||||
bp_wococo::max_extrinsic_weight()
|
||||
}
|
||||
|
||||
fn encode_message(_message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
|
||||
fn encode_message(
|
||||
_message: encode_message::MessagePayload,
|
||||
) -> Result<Self::MessagePayload, String> {
|
||||
Err("Sending messages from Rococo is not yet supported.".into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader};
|
||||
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo};
|
||||
use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
use substrate_relay_helper::finality_pipeline::{
|
||||
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
|
||||
};
|
||||
|
||||
use crate::chains::wococo_headers_to_rococo::MAXIMAL_BALANCE_DECREASE_PER_DAY;
|
||||
|
||||
@@ -40,7 +42,10 @@ pub(crate) struct RococoFinalityToWococo {
|
||||
impl RococoFinalityToWococo {
|
||||
pub fn new(target_client: Client<Wococo>, target_sign: WococoSigningParams) -> Self {
|
||||
Self {
|
||||
finality_pipeline: FinalityPipelineRococoFinalityToWococo::new(target_client, target_sign),
|
||||
finality_pipeline: FinalityPipelineRococoFinalityToWococo::new(
|
||||
target_client,
|
||||
target_sign,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +53,8 @@ impl RococoFinalityToWococo {
|
||||
impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo {
|
||||
type FinalitySyncPipeline = FinalityPipelineRococoFinalityToWococo;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
|
||||
|
||||
type TargetChain = Wococo;
|
||||
|
||||
|
||||
@@ -25,16 +25,22 @@ use bp_messages::MessageNonce;
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_rococo_client::{HeaderId as RococoHeaderId, Rococo, SigningParams as RococoSigningParams};
|
||||
use relay_rococo_client::{
|
||||
HeaderId as RococoHeaderId, Rococo, SigningParams as RococoSigningParams,
|
||||
};
|
||||
use relay_substrate_client::{Chain, Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use relay_wococo_client::{HeaderId as WococoHeaderId, SigningParams as WococoSigningParams, Wococo};
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, SubstrateMessageLane,
|
||||
SubstrateMessageLaneToSubstrate,
|
||||
use relay_wococo_client::{
|
||||
HeaderId as WococoHeaderId, SigningParams as WococoSigningParams, Wococo,
|
||||
};
|
||||
use substrate_relay_helper::{
|
||||
messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics,
|
||||
SubstrateMessageLane, SubstrateMessageLaneToSubstrate,
|
||||
},
|
||||
messages_source::SubstrateMessagesSource,
|
||||
messages_target::SubstrateMessagesTarget,
|
||||
};
|
||||
use substrate_relay_helper::messages_source::SubstrateMessagesSource;
|
||||
use substrate_relay_helper::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
/// Rococo-to-Wococo message lane.
|
||||
pub type MessageLaneRococoMessagesToWococo =
|
||||
@@ -48,23 +54,30 @@ pub struct RococoMessagesToWococo {
|
||||
impl SubstrateMessageLane for RococoMessagesToWococo {
|
||||
type MessageLane = MessageLaneRococoMessagesToWococo;
|
||||
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = bp_wococo::TO_WOCOCO_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str =
|
||||
bp_wococo::TO_WOCOCO_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str =
|
||||
bp_wococo::TO_WOCOCO_LATEST_GENERATED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_wococo::TO_WOCOCO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_wococo::TO_WOCOCO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_rococo::FROM_ROCOCO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_rococo::FROM_ROCOCO_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str =
|
||||
bp_rococo::FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = bp_rococo::FROM_ROCOCO_UNREWARDED_RELAYERS_STATE;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str =
|
||||
bp_rococo::FROM_ROCOCO_UNREWARDED_RELAYERS_STATE;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str =
|
||||
bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str =
|
||||
bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD;
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_rococo::WITH_WOCOCO_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_wococo::WITH_ROCOCO_MESSAGES_PALLET_NAME;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight =
|
||||
bp_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
|
||||
type SourceChain = Rococo;
|
||||
type TargetChain = Wococo;
|
||||
@@ -115,11 +128,7 @@ impl SubstrateMessageLane for RococoMessagesToWococo {
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let FromBridgedChainMessagesProof {
|
||||
ref nonces_start,
|
||||
ref nonces_end,
|
||||
..
|
||||
} = proof;
|
||||
let FromBridgedChainMessagesProof { ref nonces_start, ref nonces_end, .. } = proof;
|
||||
let messages_count = nonces_end - nonces_start + 1;
|
||||
|
||||
let call = relay_wococo_client::runtime::Call::BridgeMessagesRococo(
|
||||
@@ -178,14 +187,14 @@ pub async fn run(
|
||||
// we don't know exact weights of the Wococo runtime. So to guess weights we'll be using
|
||||
// weights from Rialto and then simply dividing it by x2.
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
select_delivery_transaction_limits::<pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>>(
|
||||
select_delivery_transaction_limits::<
|
||||
pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>,
|
||||
>(
|
||||
bp_wococo::max_extrinsic_weight(),
|
||||
bp_wococo::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = (
|
||||
max_messages_in_single_batch / 2,
|
||||
max_messages_weight_in_single_batch / 2,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
(max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2);
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
@@ -217,8 +226,10 @@ pub async fn run(
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target: bp_wococo::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target: bp_wococo::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_unrewarded_relayer_entries_at_target:
|
||||
bp_wococo::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target:
|
||||
bp_wococo::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user