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:
hacpy
2021-09-24 19:29:31 +08:00
committed by Bastian Köcher
parent 87cbb382d9
commit bd70de8b8b
174 changed files with 6095 additions and 4962 deletions
+8 -13
View File
@@ -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());
}
+25 -40
View File
@@ -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)
})
}
},
}
}
+131 -110
View File
@@ -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;
+43 -28
View File
@@ -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(),
}
+2 -9
View File
@@ -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(&params.chain.clone().unwrap_or_default())?)?;
let raw_wasm_blob =
extract_genesis_wasm(&*cli.load_spec(&params.chain.clone().unwrap_or_default())?)?;
let output_buf = if params.raw {
raw_wasm_blob
} else {
@@ -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: &parachain_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: &parachain_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))
}
+22 -18
View File
@@ -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)
}
+16 -27
View File
@@ -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());
}
+30 -41
View File
@@ -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),
}
})
}
},
}
}
+14 -8
View File
@@ -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())
}
}
+3 -6
View File
@@ -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 }
}
}
+104 -106
View File
@@ -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)
}
+2 -1
View File
@@ -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! {
+7 -9
View File
@@ -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]
+20 -11
View File
@@ -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())
+77 -45
View File
@@ -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,
);
});
+9 -13
View File
@@ -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;
+17 -9
View File
@@ -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())
+256 -216
View File
@@ -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.
+30 -28
View File
@@ -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
View File
@@ -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";
+2 -2
View File
@@ -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};
+2 -1
View File
@@ -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",
+45 -44
View File
@@ -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>(
&current_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(),
+44 -52
View File
@@ -14,11 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::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,
+94 -97
View File
@@ -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(&current_id.hash) {
return votes;
return votes
}
// if we have found cached votes => stop
let cached_votes = FinalityCache::<T, I>::get(&current_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()
+8 -11
View File
@@ -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.
+16 -13
View File
@@ -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,
],
}],
}
+45 -62
View File
@@ -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,);
}
}
+123 -95
View File
@@ -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(&current_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(&current_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(&current_set_signal_block.hash).expect(
"header that is associated with this change is not pruned;\
Some(current_set_signal_block) =>
storage.scheduled_change(&current_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(),],
)),
);
}
+2 -1
View File
@@ -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;
+116 -73
View File
@@ -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();
+15 -18
View File
@@ -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,
+27 -28
View File
@@ -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);
File diff suppressed because it is too large Load Diff
+31 -47
View File
@@ -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)
}
+51 -34
View File
@@ -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()
+69 -39
View File
@@ -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)),
+167 -120
View File
@@ -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()),
+1 -3
View File
@@ -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)],
}
+17 -8
View File
@@ -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.
+27 -19
View File
@@ -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.
+19 -10
View File
@@ -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.
+26 -17
View File
@@ -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.
+22 -12
View File
@@ -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! {
+17 -9
View File
@@ -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.
+12 -6
View File
@@ -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.
+24 -29
View File
@@ -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(&current_hash);
current_hash = match self.parents.get(&current_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),
};
}
+5 -7
View File
@@ -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(&current_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,
+37 -32
View File
@@ -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(
+11 -11
View File
@@ -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,
+35 -30
View File
@@ -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);
+12 -4
View File
@@ -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
+46 -22
View File
@@ -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 {
+2 -2
View File
@@ -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));
+5 -6
View File
@@ -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.
+19 -43
View File
@@ -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);
+18 -14
View File
@@ -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(&params.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(&eth_sign.signer, Some(eth_sign.chain_id));
let eth_tx_signed =
eth_tx_unsigned.clone().sign_by(&eth_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)
+12 -8
View File
@@ -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)
}
}
+64 -55
View File
@@ -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,
&params,
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,
&params,
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,
&params,
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,
&params,
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,
)),
)
+21 -13
View File
@@ -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