Merge commit 'f9c24ef0db390c355241445af37a5c7999a7dc66' into hc-bump-bridges-subtree-take-2

This commit is contained in:
Hernando Castano
2021-05-04 15:27:09 -04:00
82 changed files with 2056 additions and 816 deletions
+176
View File
@@ -0,0 +1,176 @@
90
annualised/MS
Apache-2.0/M
AccountId/MS
api/SM
auth
auths/SM
API/SM
APIs
arg
args
aren
async
Best/MS
BlockId
BFT/M
bitfield/MS
blake2/MS
blockchain/MS
borked
BridgeStorage
BlockNumber
BTC/S
CLI/MS
Chain1
Chain2
ChainSpec
ChainTime
chain_getBlock
choosen
config/MS
crypto/MS
customizable/B
debian/M
decodable/MS
DOT/S
doesn
dispatchables
ed25519
enum/MS
ERC-20
ethereum/MS
externality/MS
extrinsic/MS
extrinsics
fedora/M
FN
FinalizationError
GiB/S
GPL/M
GPLv3/M
Handler/MS
HeaderA
HeaderId
https
implementers
inherent/MS
initialize/RG
instantiate/B
intrinsic/MS
intrinsics
InitiateChange
isn
io
js
keccak256/M
KSM/S
Lane1
Lane2
Lane3
LaneId
kusama/S
KYC/M
keccak
Kovan
merkle/MS
MessageNonce
MessageNonces
Merklized
MaybeOrphan
MaybeExtra
MetricsParams
MessagePayload
misbehavior/SM
misbehaviors
MIN_SIZE
MIT/M
max_value
multivalidator/SM
natively
OldHeader
nonces
number
no_std
ok
oneshot/MS
others'
OutboundMessages
parablock/MS
parachain/MS
parameterize/D
pallet_message_lane
polkadot/MS
pov-block/MS
PoA
PoV/MS
precommit
promethius
promethius'
prune_end
prune_depth
provisioner/MS
redhat/M
repo/MS
receival
RPC/MS
RLP
runtime/MS
Runtime1
Runtime2
rustc/MS
ServiceFactory/MS
SignedExtension
SIZE_FACTOR
sr25519
SS58
SS58Prefix
src
S|N
SURI
source
struct/MS
Submitter1
submitters/MS
subsystem/MS
subsystems'
shouldn
synchronizer
taskmanager/MS
teleport/RG
teleportation/SM
teleporter/SM
teleporters
testnet/MS
trie/MS
trustless/Y
ThisChain
TCP
ubuntu/M
union/MSG
undeliverable
unfinalized
unpruned
unservable/B
unsynced
ve
vec
Vec
validator/SM
verifier
w3f/MS
wasm/M
WND/S
XCM/S
XCMP/M
include/BG
isolate/BG
Instance1
Instance2
Instance42
Pre
Rialto
stringified
Stringified
millau
Millau
+11
View File
@@ -0,0 +1,11 @@
[hunspell]
lang = "en_US"
search_dirs = ["."]
extra_dictionaries = ["lingua.dic"]
[hunspell.quirks]
# `Type`'s
# 5x
transform_regex = ["^'([^\\s])'$", "^[0-9]+(?:\\.[0-9]*)?x$", "^'s$", "^\\+$", "[><+-]"]
allow_concatenation = true
allow_dashes = true
-22
View File
@@ -1,22 +0,0 @@
version: 1
update_configs:
- package_manager: "rust:cargo"
directory: "/"
update_schedule: "weekly"
ignored_updates:
- match:
dependency_name: "sp-*"
- match:
dependency_name: "sc-*"
- match:
dependency_name: "substrate-*"
- match:
dependency_name: "frame-*"
- match:
dependency_name: "pallet-*"
- match:
dependency_name: "node-inspect"
automerged_updates:
- match:
update_type: "all"
version_requirement_updates: "auto"
+42
View File
@@ -0,0 +1,42 @@
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: weekly
time: "03:00"
timezone: Europe/Berlin
open-pull-requests-limit: 20
ignore:
- dependency-name: frame-*
versions:
- ">= 0"
- dependency-name: node-inspect
versions:
- ">= 0"
- dependency-name: pallet-*
versions:
- ">= 0"
- dependency-name: sc-*
versions:
- ">= 0"
- dependency-name: sp-*
versions:
- ">= 0"
- dependency-name: substrate-*
versions:
- ">= 0"
- dependency-name: vergen
versions:
- 4.0.1
- 4.0.2
- 4.1.0
- 4.2.0
- dependency-name: jsonrpc-core
versions:
- 17.0.0
- dependency-name: finality-grandpa
versions:
- 0.13.0
- 0.14.0
rebase-strategy: disabled
+22
View File
@@ -41,3 +41,25 @@ jobs:
with:
command: fmt
args: --all -- --check
check-spellcheck:
name: Check For Spelling and/or Grammar Mistakes
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: full
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.4.1
with:
access_token: ${{ github.token }}
- name: Checkout sources & submodules
uses: actions/checkout@master
with:
fetch-depth: 5
submodules: recursive
- name: Add cargo-spellcheck
run: cargo install cargo-spellcheck
- name: Run spellcheck
run: cargo spellcheck check -m 1 -vv $(find modules/currency-exchange/src -name "*.rs")
+1 -1
View File
@@ -86,7 +86,7 @@ jobs:
toolchain:
- stable
#- beta
- nightly
- nightly-2021-04-10
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: full
+320 -180
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -126,8 +126,8 @@ both Substrate chains it must be run last.
```bash
# In `parity-bridges-common` folder
./deployments/local-scripts/run-rialto-bridge-node.sh
./deployments/local-scripts/run-millau-bridge-node.sh
./deployments/local-scripts/run-rialto-node.sh
./deployments/local-scripts/run-millau-node.sh
./deployments/local-scripts/relay-millau-to-rialto.sh
```
@@ -12,6 +12,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
jsonrpc-core = "15.1.0"
structopt = "0.3.21"
serde_json = "1.0.59"
# Bridge dependencies
@@ -46,6 +47,7 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
[build-dependencies]
@@ -67,6 +67,18 @@ pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, GrandpaId) {
impl Alternative {
/// Get an actual chain config from one of the alternatives.
pub(crate) fn load(self) -> ChainSpec {
let properties = Some(
serde_json::json!({
"tokenDecimals": 9,
"tokenSymbol": "MLAU",
"bridgeIds": {
"Rialto": bp_runtime::RIALTO_BRIDGE_INSTANCE,
}
})
.as_object()
.expect("Map given; qed")
.clone(),
);
match self {
Alternative::Development => ChainSpec::from_genesis(
"Development",
@@ -81,6 +93,9 @@ impl Alternative {
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Alice"),
)),
],
true,
)
@@ -88,7 +103,7 @@ impl Alternative {
vec![],
None,
None,
None,
properties,
None,
),
Alternative::LocalTestnet => ChainSpec::from_genesis(
@@ -127,7 +142,13 @@ impl Alternative {
pallet_bridge_messages::DefaultInstance,
>::relayer_fund_account_id(),
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Alice"),
)),
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Charlie"),
)),
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Eve"),
)),
],
true,
@@ -136,7 +157,7 @@ impl Alternative {
vec![],
None,
None,
None,
properties,
None,
),
}
@@ -155,11 +176,11 @@ fn testnet_genesis(
) -> GenesisConfig {
GenesisConfig {
frame_system: SystemConfig {
code: WASM_BINARY.to_vec(),
code: WASM_BINARY.expect("Millau development WASM not available").to_vec(),
changes_trie_config: Default::default(),
},
pallet_balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(),
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 40)).collect(),
},
pallet_aura: AuraConfig {
authorities: Vec::new(),
+1 -1
View File
@@ -63,7 +63,7 @@ pub enum Subcommand {
Revert(sc_cli::RevertCmd),
/// Inspect blocks or extrinsics.
Inspect(node_inspect::cli::InspectCmd),
Inspect(node_inspect::cli::InspectKeyCmd),
/// Benchmark runtime pallets.
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
+42 -15
View File
@@ -37,8 +37,8 @@ use sc_finality_grandpa::SharedVoterState;
use sc_keystore::LocalKeystore;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker};
use sp_consensus::SlotData;
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
use sp_inherents::InherentDataProviders;
use std::sync::Arc;
use std::time::Duration;
@@ -80,8 +80,6 @@ pub fn new_partial(
if config.keystore_remote.is_some() {
return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
}
let inherent_data_providers = InherentDataProviders::new();
let telemetry = config
.telemetry_endpoints
.clone()
@@ -124,14 +122,24 @@ pub fn new_partial(
let aura_block_import =
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(ImportQueueParams {
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: aura_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import)),
client: client.clone(),
inherent_data_providers: inherent_data_providers.clone(),
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
slot_duration,
);
Ok((timestamp, slot))
},
spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
@@ -145,7 +153,6 @@ pub fn new_partial(
keystore_container,
select_chain,
transaction_pool,
inherent_data_providers,
other: (aura_block_import, grandpa_link, telemetry),
})
}
@@ -167,7 +174,6 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
mut keystore_container,
select_chain,
transaction_pool,
inherent_data_providers,
other: (block_import, grandpa_link, mut telemetry),
} = new_partial(&config)?;
@@ -277,13 +283,25 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _>(StartAuraParams {
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
client: client.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,
inherent_data_providers,
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
raw_slot_duration,
);
Ok((timestamp, slot))
},
force_authoring,
backoff_authoring_blocks,
keystore: keystore_container.sync_keystore(),
@@ -394,14 +412,23 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
let aura_block_import =
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(ImportQueueParams {
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: aura_block_import,
justification_import: Some(Box::new(grandpa_block_import)),
client: client.clone(),
inherent_data_providers: InherentDataProviders::new(),
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
slot_duration,
);
Ok((timestamp, slot))
},
spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::NeverCanAuthor,
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
@@ -56,7 +56,7 @@ sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" ,
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
[build-dependencies]
wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "2.0.0" }
substrate-wasm-builder = "3.0.0"
[features]
default = ["std"]
+2 -3
View File
@@ -14,13 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use wasm_builder_runner::WasmBuilder;
use substrate_wasm_builder::WasmBuilder;
fn main() {
WasmBuilder::new()
.with_current_project()
.with_wasm_builder_from_crates("1.0.11")
.export_heap_base()
.import_memory()
.export_heap_base()
.build()
}
@@ -55,7 +55,7 @@ use sp_version::RuntimeVersion;
// A few exports that help ease life for downstream crates.
pub use frame_support::{
construct_runtime, parameter_types,
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem, Randomness},
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem},
weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, RuntimeDbWeight, Weight},
StorageValue,
};
@@ -308,7 +308,6 @@ parameter_types! {
// Note that once this is hit the pallet will essentially throttle incoming requests down to one
// call per block.
pub const MaxRequests: u32 = 50;
pub const WestendValidatorCount: u32 = 255;
// Number of headers to keep.
//
@@ -478,10 +477,6 @@ impl_runtime_apis! {
) -> sp_inherents::CheckInherentsResult {
data.check_extrinsics(&block)
}
fn random_seed() -> <Block as BlockT>::Hash {
RandomnessCollectiveFlip::random_seed().0
}
}
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
@@ -31,7 +31,7 @@ use frame_support::{
weights::{DispatchClass, Weight},
RuntimeDebug,
};
use sp_runtime::{FixedPointNumber, FixedU128};
use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128};
use sp_std::{convert::TryFrom, ops::RangeInclusive};
/// Initial value of `RialtoToMillauConversionRate` parameter.
@@ -214,7 +214,9 @@ 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>(proof)
messages::source::verify_messages_delivery_proof::<WithRialtoMessageBridge, Runtime, crate::RialtoGrandpaInstance>(
proof,
)
}
}
@@ -231,7 +233,10 @@ 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>(proof, messages_count)
messages::target::verify_messages_proof::<WithRialtoMessageBridge, Runtime, crate::RialtoGrandpaInstance>(
proof,
messages_count,
)
}
}
@@ -12,6 +12,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
jsonrpc-core = "15.1.0"
structopt = "0.3.21"
serde_json = "1.0.59"
# Bridge dependencies
@@ -47,6 +48,7 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
[build-dependencies]
@@ -19,6 +19,7 @@ use rialto_runtime::{
AccountId, AuraConfig, BalancesConfig, BridgeKovanConfig, BridgeRialtoPoAConfig, GenesisConfig, GrandpaConfig,
SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
};
use serde_json::json;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{sr25519, Pair, Public};
use sp_finality_grandpa::AuthorityId as GrandpaId;
@@ -67,6 +68,18 @@ pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, GrandpaId) {
impl Alternative {
/// Get an actual chain config from one of the alternatives.
pub(crate) fn load(self) -> ChainSpec {
let properties = Some(
json!({
"tokenDecimals": 9,
"tokenSymbol": "RLT",
"bridgeIds": {
"Millau": bp_runtime::MILLAU_BRIDGE_INSTANCE,
}
})
.as_object()
.expect("Map given; qed")
.clone(),
);
match self {
Alternative::Development => ChainSpec::from_genesis(
"Development",
@@ -81,6 +94,9 @@ impl Alternative {
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Bob"),
)),
],
true,
)
@@ -88,7 +104,7 @@ impl Alternative {
vec![],
None,
None,
None,
properties,
None,
),
Alternative::LocalTestnet => ChainSpec::from_genesis(
@@ -126,9 +142,15 @@ impl Alternative {
rialto_runtime::Runtime,
pallet_bridge_messages::DefaultInstance,
>::relayer_fund_account_id(),
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Bob"),
)),
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Dave"),
)),
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
)),
],
true,
)
@@ -136,7 +158,7 @@ impl Alternative {
vec![],
None,
None,
None,
properties,
None,
),
}
@@ -155,11 +177,11 @@ fn testnet_genesis(
) -> GenesisConfig {
GenesisConfig {
frame_system: SystemConfig {
code: WASM_BINARY.to_vec(),
code: WASM_BINARY.expect("Rialto development WASM not available").to_vec(),
changes_trie_config: Default::default(),
},
pallet_balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(),
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 40)).collect(),
},
pallet_aura: AuraConfig {
authorities: Vec::new(),
+1 -1
View File
@@ -63,7 +63,7 @@ pub enum Subcommand {
Revert(sc_cli::RevertCmd),
/// Inspect blocks or extrinsics.
Inspect(node_inspect::cli::InspectCmd),
Inspect(node_inspect::cli::InspectKeyCmd),
/// Benchmark runtime pallets.
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
+41 -14
View File
@@ -37,8 +37,8 @@ use sc_finality_grandpa::SharedVoterState;
use sc_keystore::LocalKeystore;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker};
use sp_consensus::SlotData;
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
use sp_inherents::InherentDataProviders;
use std::sync::Arc;
use std::time::Duration;
@@ -80,7 +80,6 @@ pub fn new_partial(
if config.keystore_remote.is_some() {
return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
}
let inherent_data_providers = InherentDataProviders::new();
let telemetry = config
.telemetry_endpoints
@@ -124,14 +123,24 @@ pub fn new_partial(
let aura_block_import =
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(ImportQueueParams {
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: aura_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import)),
client: client.clone(),
inherent_data_providers: inherent_data_providers.clone(),
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
slot_duration,
);
Ok((timestamp, slot))
},
spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
@@ -145,7 +154,6 @@ pub fn new_partial(
keystore_container,
select_chain,
transaction_pool,
inherent_data_providers,
other: (aura_block_import, grandpa_link, telemetry),
})
}
@@ -167,7 +175,6 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
mut keystore_container,
select_chain,
transaction_pool,
inherent_data_providers,
other: (block_import, grandpa_link, mut telemetry),
} = new_partial(&config)?;
@@ -278,13 +285,24 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _>(StartAuraParams {
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
client: client.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,
inherent_data_providers,
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
raw_slot_duration,
);
Ok((timestamp, slot))
},
force_authoring,
backoff_authoring_blocks,
keystore: keystore_container.sync_keystore(),
@@ -395,14 +413,23 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
let aura_block_import =
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(ImportQueueParams {
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: aura_block_import,
justification_import: Some(Box::new(grandpa_block_import)),
client: client.clone(),
inherent_data_providers: InherentDataProviders::new(),
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
slot_duration,
);
Ok((timestamp, slot))
},
spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::NeverCanAuthor,
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
@@ -68,7 +68,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master
libsecp256k1 = { version = "0.3.4", features = ["hmac"] }
[build-dependencies]
wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "2.0.0" }
substrate-wasm-builder = "3.0.0"
[features]
default = ["std"]
+2 -3
View File
@@ -14,13 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use wasm_builder_runner::WasmBuilder;
use substrate_wasm_builder::WasmBuilder;
fn main() {
WasmBuilder::new()
.with_current_project()
.with_wasm_builder_from_crates("1.0.11")
.export_heap_base()
.import_memory()
.export_heap_base()
.build()
}
+27 -16
View File
@@ -61,7 +61,7 @@ use sp_version::RuntimeVersion;
// A few exports that help ease life for downstream crates.
pub use frame_support::{
construct_runtime, parameter_types,
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem, Randomness},
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem},
weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, RuntimeDbWeight, Weight},
StorageValue,
};
@@ -409,19 +409,34 @@ impl pallet_session::Config for Runtime {
}
parameter_types! {
// This is a pretty unscientific cap.
//
// Note that once this is hit the pallet will essentially throttle incoming requests down to one
// call per block.
/// This is a pretty unscientific cap.
///
/// Note that once this is hit the pallet will essentially throttle incoming requests down to one
/// call per block.
pub const MaxRequests: u32 = 50;
}
// Number of headers to keep.
//
// Assuming the worst case of every header being finalized, we will keep headers at least for a
// week.
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
/// Number of headers to keep in benchmarks.
///
/// In benchmarks we always populate with full number of `HeadersToKeep` to make sure that
/// pruning is taken into account.
///
/// Note: This is lower than regular value, to speed up benchmarking setup.
pub const HeadersToKeep: u32 = 1024;
}
#[cfg(not(feature = "runtime-benchmarks"))]
parameter_types! {
/// Number of headers to keep.
///
/// Assuming the worst case of every header being finalized, we will keep headers at least for a
/// week.
pub const HeadersToKeep: u32 = 7 * bp_rialto::DAYS as u32;
}
pub type MillauGrandpaInstance = ();
impl pallet_bridge_grandpa::Config for Runtime {
type BridgedChain = bp_millau::Millau;
type MaxRequests = MaxRequests;
@@ -572,10 +587,6 @@ impl_runtime_apis! {
) -> sp_inherents::CheckInherentsResult {
data.check_extrinsics(&block)
}
fn random_seed() -> <Block as BlockT>::Hash {
RandomnessCollectiveFlip::random_seed().0
}
}
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
@@ -874,7 +885,7 @@ impl_runtime_apis! {
params: MessageParams<Self::AccountId>,
) -> (millau_messages::ToMillauMessagePayload, Balance) {
let message_payload = vec![0; params.size as usize];
let dispatch_origin = pallet_bridge_dispatch::CallOrigin::SourceAccount(
let dispatch_origin = bp_message_dispatch::CallOrigin::SourceAccount(
params.sender_account,
);
@@ -944,10 +955,10 @@ impl_runtime_apis! {
make_millau_outbound_lane_data_key,
make_millau_header,
call_weight,
pallet_bridge_dispatch::MessagePayload {
bp_message_dispatch::MessagePayload {
spec_version: VERSION.spec_version,
weight: call_weight,
origin: pallet_bridge_dispatch::CallOrigin::<
origin: bp_message_dispatch::CallOrigin::<
bp_millau::AccountId,
MultiSigner,
Signature,
@@ -31,7 +31,7 @@ use frame_support::{
weights::{DispatchClass, Weight},
RuntimeDebug,
};
use sp_runtime::{FixedPointNumber, FixedU128};
use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128};
use sp_std::{convert::TryFrom, ops::RangeInclusive};
/// Initial value of `MillauToRialtoConversionRate` parameter.
@@ -214,7 +214,9 @@ 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>(proof)
messages::source::verify_messages_delivery_proof::<WithMillauMessageBridge, Runtime, crate::MillauGrandpaInstance>(
proof,
)
}
}
@@ -231,7 +233,10 @@ 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>(proof, messages_count)
messages::target::verify_messages_proof::<WithMillauMessageBridge, Runtime, crate::MillauGrandpaInstance>(
proof,
messages_count,
)
}
}
@@ -8,7 +8,7 @@ messages module into your runtime. Basic prerequisites of these helpers are:
- all message lanes are identical and may be used to transfer the same messages;
- the messages sent over the bridge are dispatched using
[call dispatch module](../../modules/dispatch/README.md);
- the messages are `pallet_bridge_dispatch::MessagePayload` structures, where `call` field is
- the messages are `bp_message_dispatch::MessagePayload` structures, where `call` field is
encoded `Call` of the target chain. This means that the `Call` is opaque to the
[messages module](../../modules/messages/README.md) instance at the source chain.
It is pre-encoded by the message submitter;
@@ -118,7 +118,7 @@ are: `maximal_message_size`, `verify_chain_message`, `verify_messages_delivery_p
`estimate_message_dispatch_and_delivery_fee`.
`FromThisChainMessagePayload` is a message that the sender sends through our bridge. It is the
`pallet_bridge_dispatch::MessagePayload`, where `call` field is encoded target chain call. So
`bp_message_dispatch::MessagePayload`, where `call` field is encoded target chain call. So
at this chain we don't see internals of this call - we just know its size.
`FromThisChainMessageVerifier` is an implementation of `bp_messages::LaneMessageVerifier`. It
@@ -131,8 +131,8 @@ has following checks in its `verify_message` method:
1. it'll reject a message if it has the wrong dispatch origin declared. Like if the submitter is not
the root of this chain, but it tries to dispatch the message at the target chain using
`pallet_bridge_dispatch::CallOrigin::SourceRoot` origin. Or he has provided wrong signature
in the `pallet_bridge_dispatch::CallOrigin::TargetAccount` origin;
`bp_message_dispatch::CallOrigin::SourceRoot` origin. Or he has provided wrong signature
in the `bp_message_dispatch::CallOrigin::TargetAccount` origin;
1. it'll reject a message if the delivery and dispatch fee that the submitter wants to pay is lesser
than the fee that is computed using the `estimate_message_dispatch_and_delivery_fee` function.
@@ -180,7 +180,7 @@ pub mod source {
pub type BridgedChainOpaqueCall = Vec<u8>;
/// Message payload for This -> Bridged chain messages.
pub type FromThisChainMessagePayload<B> = pallet_bridge_dispatch::MessagePayload<
pub type FromThisChainMessagePayload<B> = bp_message_dispatch::MessagePayload<
AccountIdOf<ThisChain<B>>,
SignerOf<BridgedChain<B>>,
SignatureOf<BridgedChain<B>>,
@@ -352,20 +352,21 @@ pub mod source {
}
/// Verify proof of This -> Bridged chain messages delivery.
pub fn verify_messages_delivery_proof<B: MessageBridge, ThisRuntime>(
pub fn verify_messages_delivery_proof<B: MessageBridge, ThisRuntime, GrandpaInstance: 'static>(
proof: FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChain<B>>>,
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
where
ThisRuntime: pallet_bridge_grandpa::Config,
ThisRuntime: pallet_bridge_grandpa::Config<GrandpaInstance>,
ThisRuntime: pallet_bridge_messages::Config<MessagesInstanceOf<BridgedChain<B>>>,
HashOf<BridgedChain<B>>: Into<bp_runtime::HashOf<<ThisRuntime as pallet_bridge_grandpa::Config>::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;
pallet_bridge_grandpa::Pallet::<ThisRuntime>::parse_finalized_storage_proof(
pallet_bridge_grandpa::Pallet::<ThisRuntime, GrandpaInstance>::parse_finalized_storage_proof(
bridged_header_hash.into(),
StorageProof::new(storage_proof),
|storage| {
@@ -394,14 +395,14 @@ pub mod target {
use super::*;
/// Call origin for Bridged -> This chain messages.
pub type FromBridgedChainMessageCallOrigin<B> = pallet_bridge_dispatch::CallOrigin<
pub type FromBridgedChainMessageCallOrigin<B> = bp_message_dispatch::CallOrigin<
AccountIdOf<BridgedChain<B>>,
SignerOf<ThisChain<B>>,
SignatureOf<ThisChain<B>>,
>;
/// Decoded Bridged -> This message payload.
pub type FromBridgedChainMessagePayload<B> = pallet_bridge_dispatch::MessagePayload<
pub type FromBridgedChainMessagePayload<B> = bp_message_dispatch::MessagePayload<
AccountIdOf<BridgedChain<B>>,
SignerOf<ThisChain<B>>,
SignatureOf<ThisChain<B>>,
@@ -504,20 +505,21 @@ pub mod target {
/// The `messages_count` argument verification (sane limits) is supposed to be made
/// outside of this function. This function only verifies that the proof declares exactly
/// `messages_count` messages.
pub fn verify_messages_proof<B: MessageBridge, ThisRuntime>(
pub fn verify_messages_proof<B: MessageBridge, ThisRuntime, GrandpaInstance: 'static>(
proof: FromBridgedChainMessagesProof<HashOf<BridgedChain<B>>>,
messages_count: u32,
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
where
ThisRuntime: pallet_bridge_grandpa::Config,
ThisRuntime: pallet_bridge_grandpa::Config<GrandpaInstance>,
ThisRuntime: pallet_bridge_messages::Config<MessagesInstanceOf<BridgedChain<B>>>,
HashOf<BridgedChain<B>>: Into<bp_runtime::HashOf<<ThisRuntime as pallet_bridge_grandpa::Config>::BridgedChain>>,
HashOf<BridgedChain<B>>:
Into<bp_runtime::HashOf<<ThisRuntime as pallet_bridge_grandpa::Config<GrandpaInstance>>::BridgedChain>>,
{
verify_messages_proof_with_parser::<B, _, _>(
proof,
messages_count,
|bridged_header_hash, bridged_storage_proof| {
pallet_bridge_grandpa::Pallet::<ThisRuntime>::parse_finalized_storage_proof(
pallet_bridge_grandpa::Pallet::<ThisRuntime, GrandpaInstance>::parse_finalized_storage_proof(
bridged_header_hash.into(),
StorageProof::new(bridged_storage_proof),
|storage_adapter| storage_adapter,
@@ -929,7 +931,7 @@ mod tests {
let message_on_bridged_chain = source::FromThisChainMessagePayload::<OnBridgedChainBridge> {
spec_version: 1,
weight: 100,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: ThisChainCall::Transfer.encode(),
}
.encode();
@@ -943,7 +945,7 @@ mod tests {
target::FromBridgedChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: 100,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: target::FromBridgedChainEncodedMessageCall::<OnThisChainBridge> {
encoded_call: ThisChainCall::Transfer.encode(),
_marker: PhantomData::default(),
@@ -960,7 +962,7 @@ mod tests {
source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: 100,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: vec![42],
}
}
@@ -1010,7 +1012,7 @@ mod tests {
let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: 100,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: vec![42],
};
@@ -1053,7 +1055,7 @@ mod tests {
let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: 100,
origin: pallet_bridge_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)),
origin: bp_message_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)),
call: vec![42],
};
@@ -1120,7 +1122,7 @@ mod tests {
> {
spec_version: 1,
weight: 5,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: vec![1, 2, 3, 4, 5, 6],
},)
.is_err()
@@ -1135,7 +1137,7 @@ mod tests {
> {
spec_version: 1,
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT + 1,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: vec![1, 2, 3, 4, 5, 6],
},)
.is_err()
@@ -1150,7 +1152,7 @@ mod tests {
> {
spec_version: 1,
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as usize + 1],
},)
.is_err()
@@ -1165,7 +1167,7 @@ mod tests {
> {
spec_version: 1,
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as _],
},),
Ok(()),
@@ -1407,6 +1409,8 @@ mod tests {
#[test]
fn transaction_payment_works_with_zero_multiplier() {
use sp_runtime::traits::Zero;
assert_eq!(
transaction_payment(
100,
@@ -1424,6 +1428,8 @@ mod tests {
#[test]
fn transaction_payment_works_with_non_zero_multiplier() {
use sp_runtime::traits::One;
assert_eq!(
transaction_payment(
100,
@@ -1,24 +0,0 @@
#!/bin/bash
#
# Run an instance of the Rococo -> Westend header sync.
#
# Right now this relies on local Westend and Rococo networks
# running (which include `pallet-bridge-grandpa` in their
# runtimes), but in the future it could use use public RPC nodes.
set -xeu
RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay init-bridge RococoToWestend \
--source-host 127.0.0.1 \
--source-port 9955 \
--target-host 127.0.0.1 \
--target-port 9944 \
--target-signer //Eve
RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay relay-headers RococoToWestend \
--source-host 127.0.0.1 \
--source-port 9955 \
--target-host 127.0.0.1 \
--target-port 9944 \
--target-signer //Bob \
--prometheus-host=0.0.0.0 \
@@ -1,24 +0,0 @@
#!/bin/bash
#
# Run an instance of the Westend -> Rococo header sync.
#
# Right now this relies on local Westend and Rococo networks
# running (which include `pallet-bridge-grandpa` in their
# runtimes), but in the future it could use use public RPC nodes.
set -xeu
RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay init-bridge WestendToRococo \
--source-host 127.0.0.1 \
--source-port 9944 \
--target-host 127.0.0.1 \
--target-port 9955 \
--target-signer //Dave
RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay relay-headers WestendToRococo \
--source-host 127.0.0.1 \
--source-port 9944 \
--target-host 127.0.0.1 \
--target-port 9955 \
--target-signer //Charlie \
--prometheus-host=0.0.0.0 \
+1 -1
View File
@@ -172,6 +172,6 @@ source chain needs to prove ownership of this account by using their target chai
sign: `(Call, SourceChainAccountId).encode()`. This will be included in the message payload and
verified by the target chain before dispatch.
See [`CallOrigin` documentation](../modules/dispatch/src/lib.rs) for more details.
See [`CallOrigin` documentation](../primitives/message-dispatch/src/lib.rs) for more details.
#### Message Relayers Strategy
@@ -70,7 +70,7 @@ decl_error! {
InvalidRecipient,
/// Cannot map from peer recipient to this blockchain recipient.
FailedToMapRecipients,
/// Failed to convert from peer blockchain currency to this blockhain currency.
/// Failed to convert from peer blockchain currency to this blockchain currency.
FailedToConvertCurrency,
/// Deposit has failed.
DepositFailed,
+2 -2
View File
@@ -13,7 +13,7 @@ Every message that is being dispatched has three main characteristics:
- `id` is the unique id of the message within the given bridge. For messages coming from the
[messages module](../messages/README.md), it may worth to use a tuple
`(LaneId, MessageNonce)` to identify a message;
- `message` is the `pallet_bridge_dispatch::MessagePayload` structure. The `call` field is set
- `message` is the `bp_message_dispatch::MessagePayload` structure. The `call` field is set
to the (potentially) encoded `Call` of this chain.
The easiest way to understand what is happening when a `Call` is being dispatched, is to look at the
@@ -33,7 +33,7 @@ module events set:
chain storage has been corrupted. The `Call` is decoded after `spec_version` check, so we'll never
try to decode `Call` from other runtime version;
- `MessageSignatureMismatch` event is emitted if submitter has chose to dispatch message using
specified this chain account (`pallet_bridge_dispatch::CallOrigin::TargetAccount` origin),
specified this chain account (`bp_message_dispatch::CallOrigin::TargetAccount` origin),
but he has failed to prove that he owns the private key for this account;
- `MessageCallRejected` event is emitted if the module has been deployed with some call filter and
this filter has rejected the `Call`. In your bridge you may choose to reject all messages except
+3 -77
View File
@@ -24,8 +24,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
use bp_message_dispatch::{MessageDispatch, Weight};
use bp_runtime::{derive_account_id, InstanceId, Size, SourceAccount};
use bp_message_dispatch::{CallOrigin, MessageDispatch, MessagePayload, SpecVersion, Weight};
use bp_runtime::{derive_account_id, InstanceId, SourceAccount};
use codec::{Decode, Encode};
use frame_support::{
decl_event, decl_module, decl_storage,
@@ -33,7 +33,6 @@ use frame_support::{
ensure,
traits::{Filter, Get},
weights::{extract_actual_weight, GetDispatchInfo},
RuntimeDebug,
};
use frame_system::RawOrigin;
use sp_runtime::{
@@ -42,78 +41,6 @@ use sp_runtime::{
};
use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};
/// Spec version type.
pub type SpecVersion = u32;
// TODO [#895] move to primitives
/// Origin of a Call when it is dispatched on the target chain.
///
/// The source chain can (and should) verify that the message can be dispatched on the target chain
/// with a particular origin given the source chain's origin. This can be done with the
/// `verify_message_origin()` function.
#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)]
pub enum CallOrigin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature> {
/// Call is sent by the Root origin on the source chain. On the target chain it is dispatched
/// from a derived account.
///
/// The derived account represents the source Root account on the target chain. This is useful
/// if the target chain needs some way of knowing that a call came from a priviledged origin on
/// the source chain (maybe to allow a configuration change for example).
SourceRoot,
/// Call is sent by `SourceChainAccountId` on the source chain. On the target chain it is
/// dispatched from an account controlled by a private key on the target chain.
///
/// The account can be identified by `TargetChainAccountPublic`. The proof that the
/// `SourceChainAccountId` controls `TargetChainAccountPublic` is the `TargetChainSignature`
/// over `(Call, SourceChainAccountId, TargetChainSpecVersion, SourceChainBridgeId).encode()`.
///
/// NOTE sending messages using this origin (or any other) does not have replay protection!
/// The assumption is that both the source account and the target account is controlled by
/// the same entity, so source-chain replay protection is sufficient.
/// As a consequence, it's extremely important for the target chain user to never produce
/// a signature with their target-private key on something that could be sent over the bridge,
/// i.e. if the target user signs `(<some-source-account-id>, Call::Transfer(X, 5))`
/// The owner of `some-source-account-id` can send that message multiple times, which would
/// result with multiple transfer calls being dispatched on the target chain.
/// So please, NEVER USE YOUR PRIVATE KEY TO SIGN SOMETHING YOU DON'T FULLY UNDERSTAND!
TargetAccount(SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature),
/// Call is sent by the `SourceChainAccountId` on the source chain. On the target chain it is
/// dispatched from a derived account ID.
///
/// The account ID on the target chain is derived from the source account ID This is useful if
/// you need a way to represent foreign accounts on this chain for call dispatch purposes.
///
/// Note that the derived account does not need to have a private key on the target chain. This
/// origin can therefore represent proxies, pallets, etc. as well as "regular" accounts.
SourceAccount(SourceChainAccountId),
}
// TODO [#895] move to primitives
/// Message payload type used by dispatch module.
#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)]
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,
/// Weight of the call, declared by the message sender. If it is less than actual
/// static weight, the call is not dispatched.
pub weight: Weight,
/// Call origin to be used during dispatch.
pub origin: CallOrigin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature>,
/// The call itself.
pub call: Call,
}
impl<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature> Size
for MessagePayload<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Vec<u8>>
{
fn size_hint(&self) -> u32 {
self.call.len() as _
}
}
/// The module configuration trait.
pub trait Config<I = DefaultInstance>: frame_system::Config {
/// The overarching event type.
@@ -314,8 +241,7 @@ impl<T: Config<I>, I: Instance> MessageDispatch<T::MessageId> for Pallet<T, I> {
// finally dispatch message
let origin = RawOrigin::Signed(origin_account).into();
log::trace!(target: "runtime::bridge-dispatch", "Message being dispatched is: {:?}", &call);
log::trace!(target: "runtime::bridge-dispatch", "Message being dispatched is: {:.4096?}", &call);
let dispatch_result = call.dispatch(origin);
let actual_call_weight = extract_actual_weight(&dispatch_result, &dispatch_info);
@@ -51,9 +51,10 @@ use bp_test_utils::{
TEST_GRANDPA_ROUND, TEST_GRANDPA_SET_ID,
};
use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller};
use frame_support::traits::Get;
use frame_system::RawOrigin;
use sp_finality_grandpa::AuthorityId;
use sp_runtime::traits::{One, Zero};
use sp_runtime::traits::Zero;
use sp_std::{vec, vec::Vec};
// The maximum number of vote ancestries to include in a justification.
@@ -66,6 +67,14 @@ const MAX_VOTE_ANCESTRIES: u32 = 1000;
// number of validators.
const MAX_VALIDATOR_SET_SIZE: u32 = 1024;
/// Returns number of first header to be imported.
///
/// Since we boostrap the pallet with `HeadersToKeep` already imported headers,
/// this function computes the next expected header number to import.
fn header_number<T: Config<I>, I: 'static, N: From<u32>>() -> N {
(T::HeadersToKeep::get() + 1).into()
}
benchmarks_instance_pallet! {
// This is the "gold standard" benchmark for this extrinsic, and it's what should be used to
// annotate the weight in the pallet.
@@ -90,9 +99,9 @@ benchmarks_instance_pallet! {
is_halted: false,
};
initialize_bridge::<T, I>(init_data);
let header: BridgedHeader<T, I> = bp_test_utils::test_header(One::one());
bootstrap_bridge::<T, I>(init_data);
let header: BridgedHeader<T, I> = bp_test_utils::test_header(header_number::<T, I, _>());
let params = JustificationGeneratorParams {
header: header.clone(),
round: TEST_GRANDPA_ROUND,
@@ -106,7 +115,7 @@ benchmarks_instance_pallet! {
}: _(RawOrigin::Signed(caller), header, justification)
verify {
let header: BridgedHeader<T, I> = bp_test_utils::test_header(One::one());
let header: BridgedHeader<T, I> = bp_test_utils::test_header(header_number::<T, I, _>());
let expected_hash = header.hash();
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
@@ -127,8 +136,8 @@ benchmarks_instance_pallet! {
is_halted: false,
};
initialize_bridge::<T, I>(init_data);
let header: BridgedHeader<T, I> = bp_test_utils::test_header(One::one());
bootstrap_bridge::<T, I>(init_data);
let header: BridgedHeader<T, I> = bp_test_utils::test_header(header_number::<T, I, _>());
let params = JustificationGeneratorParams {
header: header.clone(),
@@ -143,7 +152,7 @@ benchmarks_instance_pallet! {
}: submit_finality_proof(RawOrigin::Signed(caller), header, justification)
verify {
let header: BridgedHeader<T, I> = bp_test_utils::test_header(One::one());
let header: BridgedHeader<T, I> = bp_test_utils::test_header(header_number::<T, I, _>());
let expected_hash = header.hash();
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
@@ -170,8 +179,8 @@ benchmarks_instance_pallet! {
is_halted: false,
};
initialize_bridge::<T, I>(init_data);
let header: BridgedHeader<T, I> = bp_test_utils::test_header(One::one());
bootstrap_bridge::<T, I>(init_data);
let header: BridgedHeader<T, I> = bp_test_utils::test_header(header_number::<T, I, _>());
let params = JustificationGeneratorParams {
header: header.clone(),
@@ -186,7 +195,7 @@ benchmarks_instance_pallet! {
}: submit_finality_proof(RawOrigin::Signed(caller), header, justification)
verify {
let header: BridgedHeader<T, I> = bp_test_utils::test_header(One::one());
let header: BridgedHeader<T, I> = bp_test_utils::test_header(header_number::<T, I, _>());
let expected_hash = header.hash();
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
+65 -20
View File
@@ -42,7 +42,7 @@ use bp_header_chain::justification::GrandpaJustification;
use bp_header_chain::InitializationData;
use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf};
use finality_grandpa::voter_set::VoterSet;
use frame_support::ensure;
use frame_support::{ensure, fail};
use frame_system::{ensure_signed, RawOrigin};
use sp_finality_grandpa::{ConsensusLog, GRANDPA_ENGINE_ID};
use sp_runtime::traits::{BadOrigin, Header as HeaderT, Zero};
@@ -143,11 +143,17 @@ pub mod pallet {
let (hash, number) = (finality_target.hash(), finality_target.number());
log::trace!(target: "runtime::bridge-grandpa", "Going to try and finalize header {:?}", finality_target);
let best_finalized = <ImportedHeaders<T, I>>::get(<BestFinalized<T, I>>::get()).expect(
"In order to reach this point the bridge must have been initialized. Afterwards,
every time `BestFinalized` is updated `ImportedHeaders` is also updated. Therefore
`ImportedHeaders` must contain an entry for `BestFinalized`.",
let best_finalized = match <ImportedHeaders<T, I>>::get(<BestFinalized<T, I>>::get()) {
Some(best_finalized) => best_finalized,
None => {
log::error!(
target: "runtime::bridge-grandpa",
"Cannot finalize header {:?} because pallet is not yet initialized",
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).
@@ -158,20 +164,8 @@ pub mod pallet {
verify_justification::<T, I>(&justification, hash, *number, authority_set)?;
let _enacted = try_enact_authority_change::<T, I>(&finality_target, set_id)?;
let index = <ImportedHashesPointer<T, I>>::get();
let pruning = <ImportedHashes<T, I>>::try_get(index);
<BestFinalized<T, I>>::put(hash);
<ImportedHeaders<T, I>>::insert(hash, finality_target);
<ImportedHashes<T, I>>::insert(index, hash);
<RequestCount<T, I>>::mutate(|count| *count += 1);
// Update ring buffer pointer and remove old header.
<ImportedHashesPointer<T, I>>::put((index + 1) % T::HeadersToKeep::get());
if let Ok(hash) = pruning {
log::debug!(target: "runtime::bridge-grandpa", "Pruning old header: {:?}.", hash);
<ImportedHeaders<T, I>>::remove(hash);
}
insert_header::<T, I>(finality_target, hash);
log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash);
Ok(().into())
@@ -346,6 +340,8 @@ pub mod pallet {
///
/// This is the case for non-standard (e.g forced) authority set changes.
UnsupportedScheduledChange,
/// The pallet is not yet initialized.
NotInitialized,
/// The pallet has already been initialized.
AlreadyInitialized,
/// All pallet operations are halted.
@@ -427,6 +423,25 @@ pub mod pallet {
)
}
/// 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 validaty of such import.
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);
<ImportedHeaders<T, I>>::insert(hash, header);
<ImportedHashes<T, I>>::insert(index, hash);
// Update ring buffer pointer and remove old header.
<ImportedHashesPointer<T, I>>::put((index + 1) % T::HeadersToKeep::get());
if let Ok(hash) = pruning {
log::debug!(target: "runtime::bridge-grandpa", "Pruning old header: {:?}.", hash);
<ImportedHeaders<T, I>>::remove(hash);
}
}
/// Since this writes to storage with no real checks this should only be used in functions that
/// were called by a trusted origin.
pub(crate) fn initialize_bridge<T: Config<I>, I: 'static>(
@@ -441,8 +456,8 @@ pub mod pallet {
let initial_hash = header.hash();
<InitialHash<T, I>>::put(initial_hash);
<BestFinalized<T, I>>::put(initial_hash);
<ImportedHeaders<T, I>>::insert(initial_hash, header);
<ImportedHashesPointer<T, I>>::put(0);
insert_header::<T, I>(header, initial_hash);
let authority_set = bp_header_chain::AuthoritySet::new(authority_list, set_id);
<CurrentAuthoritySet<T, I>>::put(authority_set);
@@ -450,6 +465,29 @@ pub mod pallet {
<IsHalted<T, I>>::put(is_halted);
}
#[cfg(feature = "runtime-benchmarks")]
pub(crate) fn bootstrap_bridge<T: Config<I>, I: 'static>(
init_params: super::InitializationData<BridgedHeader<T, I>>,
) {
let start_number = *init_params.header.number();
let end_number = start_number + T::HeadersToKeep::get().into();
initialize_bridge::<T, I>(init_params);
let mut number = start_number;
while number < end_number {
number = number + sp_runtime::traits::One::one();
let header = <BridgedHeader<T, I>>::new(
number,
Default::default(),
Default::default(),
Default::default(),
Default::default(),
);
let hash = header.hash();
insert_header::<T, I>(header, hash);
}
}
/// Ensure that the origin is either root, or `PalletOwner`.
fn ensure_owner_or_root<T: Config<I>, I: 'static>(origin: T::Origin) -> Result<(), BadOrigin> {
match origin.into() {
@@ -737,6 +775,13 @@ mod tests {
})
}
#[test]
fn pallet_rejects_header_if_not_initialized_yet() {
run_test(|| {
assert_noop!(submit_finality_proof(1), Error::<TestRuntime>::NotInitialized);
});
}
#[test]
fn succesfully_imports_header_with_valid_finality() {
run_test(|| {
+25 -25
View File
@@ -17,7 +17,7 @@
//! Autogenerated weights for pallet_bridge_grandpa
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
//! DATE: 2021-04-14, STEPS: [50, ], REPEAT: 20
//! DATE: 2021-04-21, STEPS: [50, ], REPEAT: 20
//! LOW RANGE: [], HIGH RANGE: []
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
//! CHAIN: Some("dev"), DB CACHE: 128
@@ -60,29 +60,29 @@ pub struct RialtoWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
fn submit_finality_proof(v: u32, p: u32) -> Weight {
(0 as Weight)
.saturating_add((837_084_000 as Weight).saturating_mul(v as Weight))
.saturating_add((874_929_000 as Weight).saturating_mul(p as Weight))
.saturating_add((756_462_000 as Weight).saturating_mul(v as Weight))
.saturating_add((791_236_000 as Weight).saturating_mul(p as Weight))
.saturating_add(T::DbWeight::get().reads(7 as Weight))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
.saturating_add(T::DbWeight::get().writes(6 as Weight))
}
fn submit_finality_proof_on_single_fork(v: u32) -> Weight {
(276_463_000 as Weight)
.saturating_add((14_149_000 as Weight).saturating_mul(v as Weight))
(280_121_000 as Weight)
.saturating_add((14_098_000 as Weight).saturating_mul(v as Weight))
.saturating_add(T::DbWeight::get().reads(7 as Weight))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
.saturating_add(T::DbWeight::get().writes(6 as Weight))
}
fn submit_finality_proof_on_many_forks(p: u32) -> Weight {
(10_676_019_000 as Weight)
.saturating_add((97_598_000 as Weight).saturating_mul(p as Weight))
(10_370_940_000 as Weight)
.saturating_add((96_902_000 as Weight).saturating_mul(p as Weight))
.saturating_add(T::DbWeight::get().reads(7 as Weight))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
.saturating_add(T::DbWeight::get().writes(6 as Weight))
}
fn find_scheduled_change(n: u32) -> Weight {
(618_000 as Weight).saturating_add((8_000 as Weight).saturating_mul(n as Weight))
(479_000 as Weight).saturating_add((11_000 as Weight).saturating_mul(n as Weight))
}
fn read_write_authority_sets(n: u32) -> Weight {
(8_582_000 as Weight)
.saturating_add((234_000 as Weight).saturating_mul(n as Weight))
(8_030_000 as Weight)
.saturating_add((232_000 as Weight).saturating_mul(n as Weight))
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
@@ -92,29 +92,29 @@ impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
impl WeightInfo for () {
fn submit_finality_proof(v: u32, p: u32) -> Weight {
(0 as Weight)
.saturating_add((837_084_000 as Weight).saturating_mul(v as Weight))
.saturating_add((874_929_000 as Weight).saturating_mul(p as Weight))
.saturating_add((756_462_000 as Weight).saturating_mul(v as Weight))
.saturating_add((791_236_000 as Weight).saturating_mul(p as Weight))
.saturating_add(RocksDbWeight::get().reads(7 as Weight))
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(6 as Weight))
}
fn submit_finality_proof_on_single_fork(v: u32) -> Weight {
(276_463_000 as Weight)
.saturating_add((14_149_000 as Weight).saturating_mul(v as Weight))
(280_121_000 as Weight)
.saturating_add((14_098_000 as Weight).saturating_mul(v as Weight))
.saturating_add(RocksDbWeight::get().reads(7 as Weight))
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(6 as Weight))
}
fn submit_finality_proof_on_many_forks(p: u32) -> Weight {
(10_676_019_000 as Weight)
.saturating_add((97_598_000 as Weight).saturating_mul(p as Weight))
(10_370_940_000 as Weight)
.saturating_add((96_902_000 as Weight).saturating_mul(p as Weight))
.saturating_add(RocksDbWeight::get().reads(7 as Weight))
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(6 as Weight))
}
fn find_scheduled_change(n: u32) -> Weight {
(618_000 as Weight).saturating_add((8_000 as Weight).saturating_mul(n as Weight))
(479_000 as Weight).saturating_add((11_000 as Weight).saturating_mul(n as Weight))
}
fn read_write_authority_sets(n: u32) -> Weight {
(8_582_000 as Weight)
.saturating_add((234_000 as Weight).saturating_mul(n as Weight))
(8_030_000 as Weight)
.saturating_add((232_000 as Weight).saturating_mul(n as Weight))
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
@@ -17,7 +17,7 @@
//! Autogenerated weights for pallet_bridge_messages
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
//! DATE: 2021-04-14, STEPS: [50, ], REPEAT: 20
//! DATE: 2021-04-21, STEPS: [50, ], REPEAT: 20
//! LOW RANGE: [], HIGH RANGE: []
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
//! CHAIN: Some("dev"), DB CACHE: 128
@@ -73,105 +73,105 @@ pub trait WeightInfo {
pub struct RialtoWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
fn send_minimal_message_worst_case() -> Weight {
(149_497_000 as Weight)
(149_643_000 as Weight)
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().writes(12 as Weight))
}
fn send_1_kb_message_worst_case() -> Weight {
(154_339_000 as Weight)
(153_329_000 as Weight)
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().writes(12 as Weight))
}
fn send_16_kb_message_worst_case() -> Weight {
(200_066_000 as Weight)
(200_113_000 as Weight)
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().writes(12 as Weight))
}
fn increase_message_fee() -> Weight {
(6_432_637_000 as Weight)
(6_407_252_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
fn receive_single_message_proof() -> Weight {
(141_671_000 as Weight)
(141_256_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_two_messages_proof() -> Weight {
(247_393_000 as Weight)
(247_723_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_single_message_proof_with_outbound_lane_state() -> Weight {
(159_312_000 as Weight)
(159_731_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_single_message_proof_1_kb() -> Weight {
(167_935_000 as Weight)
(168_546_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_single_message_proof_16_kb() -> Weight {
(449_846_000 as Weight)
(450_087_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_delivery_proof_for_single_message() -> Weight {
(127_322_000 as Weight)
(164_519_000 as Weight)
.saturating_add(T::DbWeight::get().reads(6 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight {
(134_120_000 as Weight)
(173_300_000 as Weight)
.saturating_add(T::DbWeight::get().reads(7 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight {
(191_193_000 as Weight)
(246_205_000 as Weight)
.saturating_add(T::DbWeight::get().reads(8 as Weight))
.saturating_add(T::DbWeight::get().writes(4 as Weight))
}
fn send_messages_of_various_lengths(i: u32) -> Weight {
(115_699_000 as Weight)
(149_551_000 as Weight)
.saturating_add((3_000 as Weight).saturating_mul(i as Weight))
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().writes(12 as Weight))
}
fn receive_multiple_messages_proof(i: u32) -> Weight {
(0 as Weight)
.saturating_add((113_551_000 as Weight).saturating_mul(i as Weight))
.saturating_add((114_817_000 as Weight).saturating_mul(i as Weight))
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_message_proofs_with_extra_nodes(i: u32) -> Weight {
(458_731_000 as Weight)
.saturating_add((9_000 as Weight).saturating_mul(i as Weight))
(437_797_000 as Weight)
.saturating_add((10_000 as Weight).saturating_mul(i as Weight))
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_message_proofs_with_large_leaf(i: u32) -> Weight {
(82_314_000 as Weight)
(137_633_000 as Weight)
.saturating_add((7_000 as Weight).saturating_mul(i as Weight))
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_multiple_messages_proof_with_outbound_lane_state(i: u32) -> Weight {
(16_766_000 as Weight)
.saturating_add((115_533_000 as Weight).saturating_mul(i as Weight))
(0 as Weight)
.saturating_add((118_482_000 as Weight).saturating_mul(i as Weight))
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn receive_delivery_proof_for_multiple_messages_by_single_relayer(i: u32) -> Weight {
(122_146_000 as Weight)
.saturating_add((6_789_000 as Weight).saturating_mul(i as Weight))
(116_036_000 as Weight)
.saturating_add((7_118_000 as Weight).saturating_mul(i as Weight))
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
fn receive_delivery_proof_for_multiple_messages_by_multiple_relayers(i: u32) -> Weight {
(155_671_000 as Weight)
.saturating_add((63_020_000 as Weight).saturating_mul(i as Weight))
(172_780_000 as Weight)
.saturating_add((63_718_000 as Weight).saturating_mul(i as Weight))
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
@@ -182,105 +182,105 @@ impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
// For backwards compatibility and tests
impl WeightInfo for () {
fn send_minimal_message_worst_case() -> Weight {
(149_497_000 as Weight)
(149_643_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
}
fn send_1_kb_message_worst_case() -> Weight {
(154_339_000 as Weight)
(153_329_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
}
fn send_16_kb_message_worst_case() -> Weight {
(200_066_000 as Weight)
(200_113_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
}
fn increase_message_fee() -> Weight {
(6_432_637_000 as Weight)
(6_407_252_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
fn receive_single_message_proof() -> Weight {
(141_671_000 as Weight)
(141_256_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_two_messages_proof() -> Weight {
(247_393_000 as Weight)
(247_723_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_single_message_proof_with_outbound_lane_state() -> Weight {
(159_312_000 as Weight)
(159_731_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_single_message_proof_1_kb() -> Weight {
(167_935_000 as Weight)
(168_546_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_single_message_proof_16_kb() -> Weight {
(449_846_000 as Weight)
(450_087_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_delivery_proof_for_single_message() -> Weight {
(127_322_000 as Weight)
(164_519_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(6 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight {
(134_120_000 as Weight)
(173_300_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(7 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight {
(191_193_000 as Weight)
(246_205_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(8 as Weight))
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
}
fn send_messages_of_various_lengths(i: u32) -> Weight {
(115_699_000 as Weight)
(149_551_000 as Weight)
.saturating_add((3_000 as Weight).saturating_mul(i as Weight))
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
}
fn receive_multiple_messages_proof(i: u32) -> Weight {
(0 as Weight)
.saturating_add((113_551_000 as Weight).saturating_mul(i as Weight))
.saturating_add((114_817_000 as Weight).saturating_mul(i as Weight))
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_message_proofs_with_extra_nodes(i: u32) -> Weight {
(458_731_000 as Weight)
.saturating_add((9_000 as Weight).saturating_mul(i as Weight))
(437_797_000 as Weight)
.saturating_add((10_000 as Weight).saturating_mul(i as Weight))
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_message_proofs_with_large_leaf(i: u32) -> Weight {
(82_314_000 as Weight)
(137_633_000 as Weight)
.saturating_add((7_000 as Weight).saturating_mul(i as Weight))
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_multiple_messages_proof_with_outbound_lane_state(i: u32) -> Weight {
(16_766_000 as Weight)
.saturating_add((115_533_000 as Weight).saturating_mul(i as Weight))
(0 as Weight)
.saturating_add((118_482_000 as Weight).saturating_mul(i as Weight))
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
fn receive_delivery_proof_for_multiple_messages_by_single_relayer(i: u32) -> Weight {
(122_146_000 as Weight)
.saturating_add((6_789_000 as Weight).saturating_mul(i as Weight))
(116_036_000 as Weight)
.saturating_add((7_118_000 as Weight).saturating_mul(i as Weight))
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
fn receive_delivery_proof_for_multiple_messages_by_multiple_relayers(i: u32) -> Weight {
(155_671_000 as Weight)
.saturating_add((63_020_000 as Weight).saturating_mul(i as Weight))
(172_780_000 as Weight)
.saturating_add((63_718_000 as Weight).saturating_mul(i as Weight))
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
@@ -259,31 +259,6 @@ pub const FROM_MILLAU_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromMillauInboundLa
pub const FROM_MILLAU_UNREWARDED_RELAYERS_STATE: &str = "FromMillauInboundLaneApi_unrewarded_relayers_state";
sp_api::decl_runtime_apis! {
/// API for querying information about Millau headers from the Bridge Pallet instance.
///
/// This API is implemented by runtimes that are bridging with the Millau chain, not the
/// Millau runtime itself.
pub trait MillauHeaderApi {
/// Returns number and hash of the best blocks known to the bridge module.
///
/// Will return multiple headers if there are many headers at the same "best" height.
///
/// The caller should only submit an `import_header` transaction that makes
/// (or leads to making) other header the best one.
fn best_blocks() -> Vec<(BlockNumber, Hash)>;
/// Returns number and hash of the best finalized block known to the bridge module.
fn finalized_block() -> (BlockNumber, Hash);
/// Returns numbers and hashes of headers that require finality proofs.
///
/// An empty response means that there are no headers which currently require a
/// finality proof.
fn incomplete_headers() -> Vec<(BlockNumber, Hash)>;
/// Returns true if the header is known to the runtime.
fn is_known_block(hash: Hash) -> bool;
/// Returns true if the header is considered finalized by the runtime.
fn is_finalized_block(hash: Hash) -> bool;
}
/// API for querying information about the finalized Millau headers.
///
/// This API is implemented by runtimes that are bridging with the Millau chain, not the
@@ -220,31 +220,6 @@ pub const FROM_RIALTO_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromRialtoInboundLa
pub const FROM_RIALTO_UNREWARDED_RELAYERS_STATE: &str = "FromRialtoInboundLaneApi_unrewarded_relayers_state";
sp_api::decl_runtime_apis! {
/// API for querying information about Rialto headers from the Bridge Pallet instance.
///
/// This API is implemented by runtimes that are bridging with the Rialto chain, not the
/// Rialto runtime itself.
pub trait RialtoHeaderApi {
/// Returns number and hash of the best blocks known to the bridge module.
///
/// Will return multiple headers if there are many headers at the same "best" height.
///
/// The caller should only submit an `import_header` transaction that makes
/// (or leads to making) other header the best one.
fn best_blocks() -> Vec<(BlockNumber, Hash)>;
/// Returns number and hash of the best finalized block known to the bridge module.
fn finalized_block() -> (BlockNumber, Hash);
/// Returns numbers and hashes of headers that require finality proofs.
///
/// An empty response means that there are no headers which currently require a
/// finality proof.
fn incomplete_headers() -> Vec<(BlockNumber, Hash)>;
/// Returns true if the header is known to the runtime.
fn is_known_block(hash: Hash) -> bool;
/// Returns true if the header is considered finalized by the runtime.
fn is_finalized_block(hash: Hash) -> bool;
}
/// API for querying information about the finalized Rialto headers.
///
/// This API is implemented by runtimes that are bridging with the Rialto chain, not the
@@ -37,7 +37,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: sp_version::create_runtime_str!("rococo"),
impl_name: sp_version::create_runtime_str!("parity-rococo-v1.5"),
authoring_version: 0,
spec_version: 231,
spec_version: 232,
impl_version: 0,
apis: sp_version::create_apis_vec![[]],
transaction_version: 0,
@@ -55,14 +55,14 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
/// See: https://github.com/paritytech/polkadot/blob/master/runtime/rococo/src/lib.rs
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)]
pub enum Call {
/// Westend bridge pallet.
#[codec(index = 40)]
BridgeGrandpaWestend(BridgeGrandpaWestendCall),
/// Wococo bridge pallet.
#[codec(index = 41)]
BridgeGrandpaWococo(BridgeGrandpaWococoCall),
}
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)]
#[allow(non_camel_case_types)]
pub enum BridgeGrandpaWestendCall {
pub enum BridgeGrandpaWococoCall {
#[codec(index = 0)]
submit_finality_proof(
<PolkadotLike as Chain>::Header,
@@ -83,13 +83,6 @@ impl sp_runtime::traits::Dispatchable for Call {
}
}
// We use this to get the account on Rococo (target) which is derived from Westend's (source)
// account.
pub fn derive_account_from_westend_id(id: bp_runtime::SourceAccount<AccountId>) -> AccountId {
let encoded_id = bp_runtime::derive_account_id(bp_runtime::WESTEND_BRIDGE_INSTANCE, id);
AccountIdConverter::convert(encoded_id)
}
/// Name of the `RococoFinalityApi::best_finalized` runtime method.
pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized";
/// Name of the `RococoFinalityApi::is_known_header` runtime method.
@@ -0,0 +1,36 @@
[package]
name = "bp-wococo"
description = "Primitives of Wococo runtime."
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
parity-scale-codec = { version = "2.0.0", default-features = false, features = ["derive"] }
# Bridge Dependencies
bp-header-chain = { path = "../header-chain", default-features = false }
bp-messages = { path = "../messages", default-features = false }
bp-polkadot-core = { path = "../polkadot-core", default-features = false }
bp-runtime = { path = "../runtime", default-features = false }
# Substrate Based Dependencies
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
[features]
default = ["std"]
std = [
"bp-header-chain/std",
"bp-messages/std",
"bp-polkadot-core/std",
"bp-runtime/std",
"parity-scale-codec/std",
"sp-api/std",
"sp-runtime/std",
"sp-std/std",
"sp-version/std",
]
@@ -0,0 +1,172 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
#![cfg_attr(not(feature = "std"), no_std)]
// RuntimeApi generated functions
#![allow(clippy::too_many_arguments)]
// Runtime-generated DecodeLimit::decode_all_with_depth_limit
#![allow(clippy::unnecessary_mut_passed)]
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight};
use bp_runtime::Chain;
use sp_std::prelude::*;
use sp_version::RuntimeVersion;
pub use bp_polkadot_core::*;
/// Wococo Chain
pub type Wococo = PolkadotLike;
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
// NOTE: This needs to be kept up to date with the Rococo runtime found in the Polkadot repo.
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: sp_version::create_runtime_str!("rococo"),
impl_name: sp_version::create_runtime_str!("parity-rococo-v1.5"),
authoring_version: 0,
spec_version: 232,
impl_version: 0,
apis: sp_version::create_apis_vec![[]],
transaction_version: 0,
};
/// Wococo Runtime `Call` enum.
///
/// The enum represents a subset of possible `Call`s we can send to Rococo chain.
/// Ideally this code would be auto-generated from Metadata, because we want to
/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s.
///
/// All entries here (like pretty much in the entire file) must be kept in sync with Rococo
/// `construct_runtime`, so that we maintain SCALE-compatibility.
///
/// See: https://github.com/paritytech/polkadot/blob/master/runtime/rococo/src/lib.rs
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)]
pub enum Call {
/// Rococo bridge pallet.
#[codec(index = 40)]
BridgeGrandpaRococo(BridgeGrandpaRococoCall),
}
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)]
#[allow(non_camel_case_types)]
pub enum BridgeGrandpaRococoCall {
#[codec(index = 0)]
submit_finality_proof(
<PolkadotLike as Chain>::Header,
bp_header_chain::justification::GrandpaJustification<<PolkadotLike as Chain>::Header>,
),
#[codec(index = 1)]
initialize(bp_header_chain::InitializationData<<PolkadotLike as Chain>::Header>),
}
impl sp_runtime::traits::Dispatchable for Call {
type Origin = ();
type Config = ();
type Info = ();
type PostInfo = ();
fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo<Self::PostInfo> {
unimplemented!("The Call is not expected to be dispatched.")
}
}
// We use this to get the account on Wococo (target) which is derived from Rococo's (source)
// account.
pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount<AccountId>) -> AccountId {
let encoded_id = bp_runtime::derive_account_id(bp_runtime::ROCOCO_BRIDGE_INSTANCE, id);
AccountIdConverter::convert(encoded_id)
}
/// Name of the `WococoFinalityApi::best_finalized` runtime method.
pub const BEST_FINALIZED_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_best_finalized";
/// 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.
pub const TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str =
"ToWococoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee";
/// Name of the `ToWococoOutboundLaneApi::messages_dispatch_weight` runtime method.
pub const TO_WOCOCO_MESSAGES_DISPATCH_WEIGHT_METHOD: &str = "ToWococoOutboundLaneApi_messages_dispatch_weight";
/// Name of the `ToWococoOutboundLaneApi::latest_generated_nonce` runtime method.
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";
/// Name of the `FromWococoInboundLaneApi::latest_received_nonce` runtime method.
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";
/// Name of the `FromWococoInboundLaneApi::unrewarded_relayers_state` runtime method.
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.
///
/// This API is implemented by runtimes that are bridging with the Wococo chain, not the
/// Wococo runtime itself.
pub trait WococoFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
}
/// Outbound message lane API for messages that are sent to Wococo chain.
///
/// This API is implemented by runtimes that are sending messages to Wococo chain, not the
/// Wococo runtime itself.
pub trait ToWococoOutboundLaneApi<OutboundMessageFee: Parameter, OutboundPayload: Parameter> {
/// Estimate message delivery and dispatch fee that needs to be paid by the sender on
/// this chain.
///
/// Returns `None` if message is too expensive to be sent to Wococo from this chain.
///
/// Please keep in mind that this method returns lowest message fee required for message
/// to be accepted to the lane. It may be good idea to pay a bit over this price to account
/// future exchange rate changes and guarantee that relayer would deliver your message
/// to the target chain.
fn estimate_message_delivery_and_dispatch_fee(
lane_id: LaneId,
payload: OutboundPayload,
) -> Option<OutboundMessageFee>;
/// Returns total dispatch weight and encoded payload size of all messages in given inclusive range.
///
/// If some (or all) messages are missing from the storage, they'll also will
/// be missing from the resulting vector. The vector is ordered by the nonce.
fn messages_dispatch_weight(
lane: LaneId,
begin: MessageNonce,
end: MessageNonce,
) -> Vec<(MessageNonce, Weight, u32)>;
/// Returns nonce of the latest message, received by bridged chain.
fn latest_received_nonce(lane: LaneId) -> MessageNonce;
/// Returns nonce of the latest message, generated by given lane.
fn latest_generated_nonce(lane: LaneId) -> MessageNonce;
}
/// Inbound message lane API for messages sent by Wococo chain.
///
/// This API is implemented by runtimes that are receiving messages from Wococo chain, not the
/// Wococo runtime itself.
pub trait FromWococoInboundLaneApi {
/// Returns nonce of the latest message, received by given lane.
fn latest_received_nonce(lane: LaneId) -> MessageNonce;
/// Nonce of latest message that has been confirmed to the bridged chain.
fn latest_confirmed_nonce(lane: LaneId) -> MessageNonce;
/// State of the unrewarded relayers set at given lane.
fn unrewarded_relayers_state(lane: LaneId) -> UnrewardedRelayersState;
}
}
@@ -10,9 +10,16 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
bp-runtime = { path = "../runtime", default-features = false }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
# Substrate Dependencies
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
[features]
default = ["std"]
std = [
"bp-runtime/std",
"codec/std",
"frame-support/std",
"sp-std/std",
]
@@ -19,11 +19,17 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
use bp_runtime::InstanceId;
use bp_runtime::{InstanceId, Size};
use codec::{Decode, Encode};
use frame_support::RuntimeDebug;
use sp_std::prelude::*;
/// Message dispatch weight.
pub type Weight = u64;
/// Spec version type.
pub type SpecVersion = u32;
/// A generic trait to dispatch arbitrary messages delivered over the bridge.
pub trait MessageDispatch<MessageId> {
/// A type of the message to be dispatched.
@@ -47,3 +53,70 @@ pub trait MessageDispatch<MessageId> {
/// the whole message).
fn dispatch(bridge: InstanceId, id: MessageId, message: Result<Self::Message, ()>);
}
/// Origin of a Call when it is dispatched on the target chain.
///
/// The source chain can (and should) verify that the message can be dispatched on the target chain
/// with a particular origin given the source chain's origin. This can be done with the
/// `verify_message_origin()` function.
#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)]
pub enum CallOrigin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature> {
/// Call is sent by the Root origin on the source chain. On the target chain it is dispatched
/// from a derived account.
///
/// The derived account represents the source Root account on the target chain. This is useful
/// if the target chain needs some way of knowing that a call came from a priviledged origin on
/// the source chain (maybe to allow a configuration change for example).
SourceRoot,
/// Call is sent by `SourceChainAccountId` on the source chain. On the target chain it is
/// dispatched from an account controlled by a private key on the target chain.
///
/// The account can be identified by `TargetChainAccountPublic`. The proof that the
/// `SourceChainAccountId` controls `TargetChainAccountPublic` is the `TargetChainSignature`
/// over `(Call, SourceChainAccountId, TargetChainSpecVersion, SourceChainBridgeId).encode()`.
///
/// NOTE sending messages using this origin (or any other) does not have replay protection!
/// The assumption is that both the source account and the target account is controlled by
/// the same entity, so source-chain replay protection is sufficient.
/// As a consequence, it's extremely important for the target chain user to never produce
/// a signature with their target-private key on something that could be sent over the bridge,
/// i.e. if the target user signs `(<some-source-account-id>, Call::Transfer(X, 5))`
/// The owner of `some-source-account-id` can send that message multiple times, which would
/// result with multiple transfer calls being dispatched on the target chain.
/// So please, NEVER USE YOUR PRIVATE KEY TO SIGN SOMETHING YOU DON'T FULLY UNDERSTAND!
TargetAccount(SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature),
/// Call is sent by the `SourceChainAccountId` on the source chain. On the target chain it is
/// dispatched from a derived account ID.
///
/// The account ID on the target chain is derived from the source account ID This is useful if
/// you need a way to represent foreign accounts on this chain for call dispatch purposes.
///
/// Note that the derived account does not need to have a private key on the target chain. This
/// origin can therefore represent proxies, pallets, etc. as well as "regular" accounts.
SourceAccount(SourceChainAccountId),
}
/// Message payload type used by dispatch module.
#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)]
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,
/// Weight of the call, declared by the message sender. If it is less than actual
/// static weight, the call is not dispatched.
pub weight: Weight,
/// Call origin to be used during dispatch.
pub origin: CallOrigin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature>,
/// The call itself.
pub call: Call,
}
impl<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature> Size
for MessagePayload<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Vec<u8>>
{
fn size_hint(&self) -> u32 {
self.call.len() as _
}
}
@@ -50,8 +50,8 @@ pub const KUSAMA_BRIDGE_INSTANCE: InstanceId = *b"ksma";
/// Bridge-with-Rococo instance id.
pub const ROCOCO_BRIDGE_INSTANCE: InstanceId = *b"roco";
/// Bridge-with-Westend instance id.
pub const WESTEND_BRIDGE_INSTANCE: InstanceId = *b"wend";
/// Bridge-with-Wococo instance id.
pub const WOCOCO_BRIDGE_INSTANCE: InstanceId = *b"woco";
/// Call-dispatch module prefix.
pub const CALL_DISPATCH_MODULE_PREFIX: &[u8] = b"pallet-bridge/dispatch";
@@ -23,10 +23,12 @@ structopt = "0.3"
bp-header-chain = { path = "../../primitives/header-chain" }
bp-kusama = { path = "../../primitives/chain-kusama" }
bp-messages = { path = "../../primitives/messages" }
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
bp-millau = { path = "../../primitives/chain-millau" }
bp-polkadot = { path = "../../primitives/chain-polkadot" }
bp-rialto = { path = "../../primitives/chain-rialto" }
bp-rococo = { path = "../../primitives/chain-rococo" }
bp-wococo = { path = "../../primitives/chain-wococo" }
bp-runtime = { path = "../../primitives/runtime" }
bp-westend = { path = "../../primitives/chain-westend" }
bridge-runtime-common = { path = "../../bin/runtime-common" }
@@ -35,13 +37,13 @@ finality-relay = { path = "../finality" }
headers-relay = { path = "../headers" }
messages-relay = { path = "../messages" }
millau-runtime = { path = "../../bin/millau/runtime" }
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
pallet-bridge-messages = { path = "../../modules/messages" }
relay-kusama-client = { path = "../client-kusama" }
relay-millau-client = { path = "../client-millau" }
relay-polkadot-client = { path = "../client-polkadot" }
relay-rialto-client = { path = "../client-rialto" }
relay-rococo-client = { path = "../client-rococo" }
relay-wococo-client = { path = "../client-wococo" }
relay-substrate-client = { path = "../client-substrate" }
relay-utils = { path = "../utils" }
relay-westend-client = { path = "../client-westend" }
@@ -21,9 +21,9 @@ use crate::cli::{
encode_call::{self, Call, CliEncodeCall},
encode_message, send_message, CliChain,
};
use bp_message_dispatch::{CallOrigin, MessagePayload};
use codec::Decode;
use frame_support::weights::{GetDispatchInfo, Weight};
use pallet_bridge_dispatch::{CallOrigin, MessagePayload};
use relay_millau_client::Millau;
use sp_version::RuntimeVersion;
@@ -20,14 +20,15 @@ pub mod millau_headers_to_rialto;
pub mod millau_messages_to_rialto;
pub mod rialto_headers_to_millau;
pub mod rialto_messages_to_millau;
pub mod rococo_headers_to_westend;
pub mod rococo_headers_to_wococo;
pub mod westend_headers_to_millau;
pub mod westend_headers_to_rococo;
pub mod wococo_headers_to_rococo;
mod millau;
mod rialto;
mod rococo;
mod westend;
mod wococo;
use relay_utils::metrics::{FloatJsonValueMetric, MetricsParams};
@@ -131,7 +132,7 @@ mod tests {
let payload = send_message::message_payload(
Default::default(),
call.get_dispatch_info().weight,
pallet_bridge_dispatch::CallOrigin::SourceRoot,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
);
assert_eq!(Millau::verify_message(&payload), Ok(()));
@@ -141,7 +142,7 @@ mod tests {
let payload = send_message::message_payload(
Default::default(),
call.get_dispatch_info().weight,
pallet_bridge_dispatch::CallOrigin::SourceRoot,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
);
assert!(Millau::verify_message(&payload).is_err());
@@ -168,7 +169,7 @@ mod tests {
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight,
pallet_bridge_dispatch::CallOrigin::SourceRoot,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
);
assert_eq!(Millau::verify_message(&payload), Ok(()));
@@ -176,7 +177,7 @@ mod tests {
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight + 1,
pallet_bridge_dispatch::CallOrigin::SourceRoot,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
);
assert!(Millau::verify_message(&payload).is_err());
@@ -193,7 +194,7 @@ mod tests {
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight,
pallet_bridge_dispatch::CallOrigin::SourceRoot,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
);
assert_eq!(Rialto::verify_message(&payload), Ok(()));
@@ -201,7 +202,7 @@ mod tests {
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight + 1,
pallet_bridge_dispatch::CallOrigin::SourceRoot,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
);
assert!(Rialto::verify_message(&payload).is_err());
@@ -270,7 +271,7 @@ mod rococo_tests {
votes_ancestries: vec![],
};
let actual = bp_rococo::BridgeGrandpaWestendCall::submit_finality_proof(header.clone(), justification.clone());
let actual = bp_rococo::BridgeGrandpaWococoCall::submit_finality_proof(header.clone(), justification.clone());
let expected = millau_runtime::BridgeGrandpaRialtoCall::<millau_runtime::Runtime>::submit_finality_proof(
header,
justification,
@@ -21,9 +21,9 @@ use crate::cli::{
encode_call::{self, Call, CliEncodeCall},
encode_message, send_message, CliChain,
};
use bp_message_dispatch::{CallOrigin, MessagePayload};
use codec::Decode;
use frame_support::weights::{GetDispatchInfo, Weight};
use pallet_bridge_dispatch::{CallOrigin, MessagePayload};
use relay_rialto_client::Rialto;
use sp_version::RuntimeVersion;
@@ -14,7 +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/>.
//! Rococo-to-Westend headers sync entrypoint.
//! Rococo-to-Wococo headers sync entrypoint.
use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
@@ -23,37 +23,37 @@ use codec::Encode;
use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader};
use relay_substrate_client::{Chain, TransactionSignScheme};
use relay_utils::metrics::MetricsParams;
use relay_westend_client::{SigningParams as WestendSigningParams, Westend};
use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo};
use sp_core::{Bytes, Pair};
/// Rococo-to-Westend finality sync pipeline.
pub(crate) type RococoFinalityToWestend = SubstrateFinalityToSubstrate<Rococo, Westend, WestendSigningParams>;
/// Rococo-to-Wococo finality sync pipeline.
pub(crate) type RococoFinalityToWococo = SubstrateFinalityToSubstrate<Rococo, Wococo, WococoSigningParams>;
impl SubstrateFinalitySyncPipeline for RococoFinalityToWestend {
impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo {
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
type TargetChain = Westend;
type TargetChain = Wococo;
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> {
crate::chains::add_polkadot_kusama_price_metrics::<Self>(params)
}
fn transactions_author(&self) -> bp_westend::AccountId {
fn transactions_author(&self) -> bp_wococo::AccountId {
(*self.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
transaction_nonce: <Westend as Chain>::Index,
transaction_nonce: <Wococo as Chain>::Index,
header: RococoSyncHeader,
proof: GrandpaJustification<bp_rococo::Header>,
) -> Bytes {
let call = bp_westend::Call::BridgeGrandpaRococo(bp_westend::BridgeGrandpaRococoCall::submit_finality_proof(
let call = bp_wococo::Call::BridgeGrandpaRococo(bp_wococo::BridgeGrandpaRococoCall::submit_finality_proof(
header.into_inner(),
proof,
));
let genesis_hash = *self.target_client.genesis_hash();
let transaction = Westend::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call);
let transaction = Wococo::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call);
Bytes(transaction.encode())
}
@@ -48,7 +48,7 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToRococo {
header: WestendSyncHeader,
proof: GrandpaJustification<bp_westend::Header>,
) -> Bytes {
let call = bp_rococo::Call::BridgeGrandpaWestend(bp_rococo::BridgeGrandpaWestendCall::submit_finality_proof(
let call = bp_rococo::Call::BridgeGrandpaWestend(bp_rococo::BridgeGrandpaCall::submit_finality_proof(
header.into_inner(),
proof,
));
@@ -0,0 +1,39 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::cli::{encode_message, CliChain};
use frame_support::weights::Weight;
use relay_wococo_client::Wococo;
use sp_version::RuntimeVersion;
impl CliChain for Wococo {
const RUNTIME_VERSION: RuntimeVersion = bp_wococo::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = ();
fn ss58_format() -> u16 {
42
}
fn max_extrinsic_weight() -> Weight {
0
}
fn encode_message(_message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
Err("Sending messages from Wococo is not yet supported.".into())
}
}
@@ -0,0 +1,60 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Wococo-to-Rococo headers sync entrypoint.
use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
use bp_header_chain::justification::GrandpaJustification;
use codec::Encode;
use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams};
use relay_substrate_client::{Chain, TransactionSignScheme};
use relay_utils::metrics::MetricsParams;
use relay_wococo_client::{SyncHeader as WococoSyncHeader, Wococo};
use sp_core::{Bytes, Pair};
/// Wococo-to-Rococo finality sync pipeline.
pub(crate) type WococoFinalityToRococo = SubstrateFinalityToSubstrate<Wococo, Rococo, RococoSigningParams>;
impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo {
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD;
type TargetChain = Rococo;
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> {
crate::chains::add_polkadot_kusama_price_metrics::<Self>(params)
}
fn transactions_author(&self) -> bp_rococo::AccountId {
(*self.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
transaction_nonce: <Rococo as Chain>::Index,
header: WococoSyncHeader,
proof: GrandpaJustification<bp_wococo::Header>,
) -> Bytes {
let call = bp_rococo::Call::BridgeGrandpaWococo(bp_rococo::BridgeGrandpaWococoCall::submit_finality_proof(
header.into_inner(),
proof,
));
let genesis_hash = *self.target_client.genesis_hash();
let transaction = Rococo::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call);
Bytes(transaction.encode())
}
}
@@ -53,7 +53,7 @@ macro_rules! select_full_bridge {
// Derive-account
#[allow(unused_imports)]
use bp_millau::derive_account_from_rialto_id as derive_account;
use bp_rialto::derive_account_from_millau_id as derive_account;
// Relay-messages
#[allow(unused_imports)]
@@ -75,7 +75,7 @@ macro_rules! select_full_bridge {
// Derive-account
#[allow(unused_imports)]
use bp_rialto::derive_account_from_millau_id as derive_account;
use bp_millau::derive_account_from_rialto_id as derive_account;
// Relay-messages
#[allow(unused_imports)]
@@ -91,11 +91,11 @@ mod tests {
assert_eq!(
format!("{}", rialto_derived),
"73gLnUwrAdH4vMjbXCiNEpgyz1PLk9JxCaY4cKzvfSZT73KE"
"74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5"
);
assert_eq!(
format!("{}", millau_derived),
"5rpTJqGv1BPAYy2sXzkPpc3Wx1ZpQtgfuBsrDpNV4HsXAmbi"
"5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2"
);
assert_eq!(millau_derived, millau2_derived);
}
@@ -44,8 +44,8 @@ arg_enum! {
MillauToRialto,
RialtoToMillau,
WestendToMillau,
WestendToRococo,
RococoToWestend,
RococoToWococo,
WococoToRococo,
}
}
@@ -102,26 +102,26 @@ macro_rules! select_bridge {
$generic
}
InitBridgeName::WestendToRococo => {
type Source = relay_westend_client::Westend;
InitBridgeName::RococoToWococo => {
type Source = relay_rococo_client::Rococo;
type Target = relay_wococo_client::Wococo;
fn encode_init_bridge(
init_data: InitializationData<<Source as ChainBase>::Header>,
) -> <Target as Chain>::Call {
bp_wococo::Call::BridgeGrandpaRococo(bp_wococo::BridgeGrandpaRococoCall::initialize(init_data))
}
$generic
}
InitBridgeName::WococoToRococo => {
type Source = relay_wococo_client::Wococo;
type Target = relay_rococo_client::Rococo;
fn encode_init_bridge(
init_data: InitializationData<<Source as ChainBase>::Header>,
) -> <Target as Chain>::Call {
bp_rococo::Call::BridgeGrandpaWestend(bp_rococo::BridgeGrandpaWestendCall::initialize(init_data))
}
$generic
}
InitBridgeName::RococoToWestend => {
type Source = relay_rococo_client::Rococo;
type Target = relay_westend_client::Westend;
fn encode_init_bridge(
init_data: InitializationData<<Source as ChainBase>::Header>,
) -> <Target as Chain>::Call {
bp_westend::Call::BridgeGrandpaRococo(bp_westend::BridgeGrandpaRococoCall::initialize(init_data))
bp_rococo::Call::BridgeGrandpaWococo(bp_rococo::BridgeGrandpaWococoCall::initialize(init_data))
}
$generic
@@ -89,8 +89,23 @@ pub enum Command {
}
impl Command {
// Initialize logger depending on the command.
fn init_logger(&self) {
use relay_utils::initialize::{initialize_logger, initialize_relay};
match self {
Self::RelayHeaders(_) | Self::RelayMessages(_) | Self::RelayHeadersAndMessages(_) | Self::InitBridge(_) => {
initialize_relay();
}
_ => {
initialize_logger(false);
}
}
}
/// Run the command.
pub async fn run(self) -> anyhow::Result<()> {
self.init_logger();
match self {
Self::RelayHeaders(arg) => arg.run().await?,
Self::RelayMessages(arg) => arg.run().await?,
@@ -42,8 +42,8 @@ arg_enum! {
MillauToRialto,
RialtoToMillau,
WestendToMillau,
WestendToRococo,
RococoToWestend,
RococoToWococo,
WococoToRococo,
}
}
@@ -71,17 +71,17 @@ macro_rules! select_bridge {
$generic
}
RelayHeadersBridge::WestendToRococo => {
type Source = relay_westend_client::Westend;
type Target = relay_rococo_client::Rococo;
type Finality = crate::chains::westend_headers_to_rococo::WestendFinalityToRococo;
RelayHeadersBridge::RococoToWococo => {
type Source = relay_rococo_client::Rococo;
type Target = relay_wococo_client::Wococo;
type Finality = crate::chains::rococo_headers_to_wococo::RococoFinalityToWococo;
$generic
}
RelayHeadersBridge::RococoToWestend => {
type Source = relay_rococo_client::Rococo;
type Target = relay_westend_client::Westend;
type Finality = crate::chains::rococo_headers_to_westend::RococoFinalityToWestend;
RelayHeadersBridge::WococoToRococo => {
type Source = relay_wococo_client::Wococo;
type Target = relay_rococo_client::Rococo;
type Finality = crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo;
$generic
}
@@ -102,6 +102,7 @@ impl RelayHeaders {
Finality::new(target_client.clone(), target_sign),
source_client,
target_client,
false,
metrics_params,
)
.await
@@ -96,6 +96,9 @@ macro_rules! select_bridge {
type LeftToRightMessages = crate::chains::millau_messages_to_rialto::MillauMessagesToRialto;
type RightToLeftMessages = crate::chains::rialto_messages_to_millau::RialtoMessagesToMillau;
const MAX_MISSING_LEFT_HEADERS_AT_RIGHT: bp_millau::BlockNumber = bp_millau::SESSION_LENGTH;
const MAX_MISSING_RIGHT_HEADERS_AT_LEFT: bp_rialto::BlockNumber = bp_rialto::SESSION_LENGTH;
use crate::chains::millau_messages_to_rialto::run as left_to_right_messages;
use crate::chains::rialto_messages_to_millau::run as right_to_left_messages;
@@ -131,11 +134,13 @@ impl RelayHeadersAndMessages {
left_client.clone(),
right_client.clone(),
LeftToRightFinality::new(right_client.clone(), right_sign.clone()),
MAX_MISSING_LEFT_HEADERS_AT_RIGHT,
);
let right_to_left_on_demand_headers = OnDemandHeadersRelay::new(
right_client.clone(),
left_client.clone(),
RightToLeftFinality::new(left_client.clone(), left_sign.clone()),
MAX_MISSING_RIGHT_HEADERS_AT_LEFT,
);
let left_to_right_messages = left_to_right_messages(MessagesRelayParams {
@@ -21,9 +21,9 @@ use crate::cli::{
Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams,
TargetSigningParams,
};
use bp_message_dispatch::{CallOrigin, MessagePayload};
use codec::Encode;
use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
use pallet_bridge_dispatch::{CallOrigin, MessagePayload};
use relay_substrate_client::{Chain, TransactionSignScheme};
use sp_core::{Bytes, Pair};
use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner};
@@ -96,7 +96,7 @@ where
SourceChain: Clone + Chain + Debug,
BlockNumberOf<SourceChain>: BlockNumberBase,
TargetChain: Clone + Chain + Debug,
TargetSign: Clone + Send + Sync,
TargetSign: 'static + Clone + Send + Sync,
{
const SOURCE_NAME: &'static str = SourceChain::NAME;
const TARGET_NAME: &'static str = TargetChain::NAME;
@@ -112,6 +112,7 @@ pub async fn run<SourceChain, TargetChain, P>(
pipeline: P,
source_client: Client<SourceChain>,
target_client: Client<TargetChain>,
is_on_demand_task: bool,
metrics_params: MetricsParams,
) -> anyhow::Result<()>
where
@@ -137,6 +138,7 @@ where
FinalitySource::new(source_client),
SubstrateFinalityTarget::new(target_client, pipeline),
FinalitySyncParams {
is_on_demand_task,
tick: std::cmp::max(SourceChain::AVERAGE_BLOCK_INTERVAL, TargetChain::AVERAGE_BLOCK_INTERVAL),
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
stall_timeout: STALL_TIMEOUT,
@@ -18,8 +18,6 @@
#![warn(missing_docs)]
use relay_utils::initialize::initialize_logger;
mod chains;
mod cli;
mod finality_pipeline;
@@ -31,7 +29,6 @@ mod messages_target;
mod on_demand_headers;
fn main() {
initialize_logger(false);
let command = cli::parse_args();
let run = command.run();
let result = async_std::task::block_on(run);
@@ -203,7 +203,7 @@ mod tests {
// reserved for messages dispatch allows dispatch of non-trivial messages.
//
// Any significant change in this values should attract additional attention.
(1020, 216_583_333_334),
(1013, 216_583_333_334),
);
}
}
@@ -93,7 +93,7 @@ impl<C, P, R, I> RelayClient for SubstrateMessagesSource<C, P, R, I>
where
C: Chain,
P: SubstrateMessageLane,
R: Send + Sync,
R: 'static + Send + Sync,
I: Send + Sync + Instance,
{
type Error = SubstrateError;
@@ -93,7 +93,7 @@ impl<C, P, R, I> RelayClient for SubstrateMessagesTarget<C, P, R, I>
where
C: Chain,
P: SubstrateMessageLane,
R: Send + Sync,
R: 'static + Send + Sync,
I: Send + Sync + Instance,
{
type Error = SubstrateError;
@@ -20,14 +20,22 @@ use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityT
use crate::finality_target::SubstrateFinalityTarget;
use bp_header_chain::justification::GrandpaJustification;
use finality_relay::TargetClient as FinalityTargetClient;
use finality_relay::{
FinalitySyncPipeline, SourceClient as FinalitySourceClient, TargetClient as FinalityTargetClient,
};
use futures::{
channel::{mpsc, oneshot},
select, FutureExt, StreamExt,
};
use num_traits::Zero;
use relay_substrate_client::{BlockNumberOf, Chain, Client, HashOf, HeaderIdOf, SyncHeader};
use relay_utils::{metrics::MetricsParams, BlockNumberBase, HeaderId};
use num_traits::{CheckedSub, Zero};
use relay_substrate_client::{
finality_source::FinalitySource as SubstrateFinalitySource, BlockNumberOf, Chain, Client, HashOf, HeaderIdOf,
SyncHeader,
};
use relay_utils::{
metrics::MetricsParams, relay_loop::Client as RelayClient, BlockNumberBase, FailedClient, HeaderId,
MaybeConnectionError,
};
use std::fmt::Debug;
/// On-demand Substrate <-> Substrate headers relay.
@@ -49,6 +57,7 @@ impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> {
source_client: Client<SourceChain>,
target_client: Client<TargetChain>,
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
maximal_headers_difference: SourceChain::BlockNumber,
) -> Self
where
SourceChain: Chain + Debug,
@@ -68,7 +77,14 @@ impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> {
{
let (required_header_tx, required_header_rx) = mpsc::channel(1);
async_std::task::spawn(async move {
background_task(source_client, target_client, pipeline, required_header_rx).await;
background_task(
source_client,
target_client,
pipeline,
maximal_headers_difference,
required_header_rx,
)
.await;
});
let background_task_name = format!(
@@ -100,6 +116,7 @@ async fn background_task<SourceChain, TargetChain, TargetSign>(
source_client: Client<SourceChain>,
target_client: Client<TargetChain>,
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
maximal_headers_difference: SourceChain::BlockNumber,
mut required_header_rx: mpsc::Receiver<HeaderIdOf<SourceChain>>,
) where
SourceChain: Chain + Debug,
@@ -118,7 +135,11 @@ async fn background_task<SourceChain, TargetChain, TargetSign>(
FinalityTargetClient<SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>>,
{
let relay_task_name = on_demand_headers_relay_name::<SourceChain, TargetChain>();
let finality_target = SubstrateFinalityTarget::new(target_client.clone(), pipeline.clone());
let mut finality_source = SubstrateFinalitySource::<
_,
SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
>::new(source_client.clone());
let mut finality_target = SubstrateFinalityTarget::new(target_client.clone(), pipeline.clone());
let mut active_headers_relay = None;
let mut required_header_number = Zero::zero();
@@ -150,30 +171,45 @@ async fn background_task<SourceChain, TargetChain, TargetSign>(
},
}
// read best finalized source block from target
let available_header_number = match finality_target.best_finalized_source_block_number().await {
Ok(available_header_number) => available_header_number,
Err(error) => {
log::error!(
target: "bridge",
"Failed to read best finalized {} header from {} in {} relay: {:?}",
SourceChain::NAME,
TargetChain::NAME,
relay_task_name,
error,
);
// we don't know what's happening with target client, so better to stop on-demand relay than
// submit unneeded transactions
// => assume that required header is known to the target node
required_header_number
// read best finalized source header number from source
let best_finalized_source_header_at_source =
best_finalized_source_header_at_source(&finality_source, &relay_task_name).await;
if matches!(best_finalized_source_header_at_source, Err(ref e) if e.is_connection_error()) {
relay_utils::relay_loop::reconnect_failed_client(
FailedClient::Source,
relay_utils::relay_loop::RECONNECT_DELAY,
&mut finality_source,
&mut finality_target,
)
.await;
continue;
}
// read best finalized source header number from target
let best_finalized_source_header_at_target =
best_finalized_source_header_at_target::<SourceChain, _, _>(&finality_target, &relay_task_name).await;
if matches!(best_finalized_source_header_at_target, Err(ref e) if e.is_connection_error()) {
relay_utils::relay_loop::reconnect_failed_client(
FailedClient::Target,
relay_utils::relay_loop::RECONNECT_DELAY,
&mut finality_source,
&mut finality_target,
)
.await;
continue;
}
};
// start or stop headers relay if required
let activate = required_header_number > available_header_number;
match (activate, active_headers_relay.is_some()) {
(true, false) => {
let action = select_on_demand_relay_action::<SourceChain>(
best_finalized_source_header_at_source.ok(),
best_finalized_source_header_at_target.ok(),
required_header_number,
maximal_headers_difference,
&relay_task_name,
active_headers_relay.is_some(),
);
match action {
OnDemandRelayAction::Start => {
let (relay_exited_tx, new_relay_exited_rx) = oneshot::channel();
active_headers_relay = start_on_demand_headers_relay(
relay_task_name.clone(),
@@ -186,14 +222,127 @@ async fn background_task<SourceChain, TargetChain, TargetSign>(
relay_exited_rx = new_relay_exited_rx.right_future();
}
}
(false, true) => {
OnDemandRelayAction::Stop => {
stop_on_demand_headers_relay(active_headers_relay.take()).await;
}
_ => (),
OnDemandRelayAction::None => (),
}
}
}
/// Read best finalized source block number from source client.
///
/// Returns `None` if we have failed to read the number.
async fn best_finalized_source_header_at_source<SourceChain: Chain, P>(
finality_source: &SubstrateFinalitySource<SourceChain, P>,
relay_task_name: &str,
) -> Result<SourceChain::BlockNumber, <SubstrateFinalitySource<SourceChain, P> as RelayClient>::Error>
where
SubstrateFinalitySource<SourceChain, P>: FinalitySourceClient<P>,
P: FinalitySyncPipeline<Number = SourceChain::BlockNumber>,
{
finality_source.best_finalized_block_number().await.map_err(|error| {
log::error!(
target: "bridge",
"Failed to read best finalized source header from source in {} relay: {:?}",
relay_task_name,
error,
);
error
})
}
/// Read best finalized source block number from target client.
///
/// Returns `None` if we have failed to read the number.
async fn best_finalized_source_header_at_target<SourceChain: Chain, TargetChain: Chain, P>(
finality_target: &SubstrateFinalityTarget<TargetChain, P>,
relay_task_name: &str,
) -> Result<SourceChain::BlockNumber, <SubstrateFinalityTarget<TargetChain, P> as RelayClient>::Error>
where
SubstrateFinalityTarget<TargetChain, P>: FinalityTargetClient<P>,
P: FinalitySyncPipeline<Number = SourceChain::BlockNumber>,
{
finality_target
.best_finalized_source_block_number()
.await
.map_err(|error| {
log::error!(
target: "bridge",
"Failed to read best finalized source header from target in {} relay: {:?}",
relay_task_name,
error,
);
error
})
}
/// What to do with the on-demand relay task?
#[derive(Debug, PartialEq)]
enum OnDemandRelayAction {
Start,
Stop,
None,
}
fn select_on_demand_relay_action<C: Chain>(
best_finalized_source_header_at_source: Option<C::BlockNumber>,
best_finalized_source_header_at_target: Option<C::BlockNumber>,
mut required_source_header_at_target: C::BlockNumber,
maximal_headers_difference: C::BlockNumber,
relay_task_name: &str,
is_active: bool,
) -> OnDemandRelayAction {
// if we have been unable to read header number from the target, then let's assume
// that it is the same as required header number. Otherwise we risk submitting
// unneeded transactions
let best_finalized_source_header_at_target =
best_finalized_source_header_at_target.unwrap_or(required_source_header_at_target);
// if we have been unable to read header number from the source, then let's assume
// that it is the same as at the target
let best_finalized_source_header_at_source =
best_finalized_source_header_at_source.unwrap_or(best_finalized_source_header_at_target);
// if there are too many source headers missing from the target node, require some
// new headers at target
//
// why do we need that? When complex headers+messages relay is used, it'll normally only relay
// headers when there are undelivered messages/confirmations. But security model of the
// `pallet-bridge-grandpa` module relies on the fact that headers are synced in real-time and
// that it'll see authorities-change header before unbonding period will end for previous
// authorities set.
let current_headers_difference = best_finalized_source_header_at_source
.checked_sub(&best_finalized_source_header_at_target)
.unwrap_or_else(Zero::zero);
if current_headers_difference > maximal_headers_difference {
required_source_header_at_target = best_finalized_source_header_at_source;
// don't log if relay is already running
if !is_active {
log::trace!(
target: "bridge",
"Too many {} headers missing at target in {} relay ({} vs {}). Going to sync up to the {}",
C::NAME,
relay_task_name,
best_finalized_source_header_at_source,
best_finalized_source_header_at_target,
best_finalized_source_header_at_source,
);
}
}
// now let's select what to do with relay
let needs_to_be_active = required_source_header_at_target > best_finalized_source_header_at_target;
match (needs_to_be_active, is_active) {
(true, false) => OnDemandRelayAction::Start,
(false, true) => OnDemandRelayAction::Stop,
_ => OnDemandRelayAction::None,
}
}
/// On-demand headers relay task name.
fn on_demand_headers_relay_name<SourceChain: Chain, TargetChain: Chain>() -> String {
format!("on-demand-{}-to-{}", SourceChain::NAME, TargetChain::NAME)
@@ -219,7 +368,7 @@ where
TargetSign: 'static,
{
let headers_relay_future =
crate::finality_pipeline::run(pipeline, source_client, target_client, MetricsParams::disabled());
crate::finality_pipeline::run(pipeline, source_client, target_client, true, MetricsParams::disabled());
let closure_task_name = task_name.clone();
async_std::task::Builder::new()
.name(task_name.clone())
@@ -253,3 +402,52 @@ async fn stop_on_demand_headers_relay(task: Option<async_std::task::JoinHandle<(
log::info!(target: "bridge", "Cancelled {} headers relay", task_name);
}
}
#[cfg(test)]
mod tests {
use super::*;
type TestChain = relay_millau_client::Millau;
const AT_SOURCE: Option<bp_millau::BlockNumber> = Some(10);
const AT_TARGET: Option<bp_millau::BlockNumber> = Some(1);
#[test]
fn starts_relay_when_headers_are_required() {
assert_eq!(
select_on_demand_relay_action::<TestChain>(AT_SOURCE, AT_TARGET, 5, 100, "test", false),
OnDemandRelayAction::Start,
);
assert_eq!(
select_on_demand_relay_action::<TestChain>(AT_SOURCE, AT_TARGET, 5, 100, "test", true),
OnDemandRelayAction::None,
);
}
#[test]
fn starts_relay_when_too_many_headers_missing() {
assert_eq!(
select_on_demand_relay_action::<TestChain>(AT_SOURCE, AT_TARGET, 0, 5, "test", false),
OnDemandRelayAction::Start,
);
assert_eq!(
select_on_demand_relay_action::<TestChain>(AT_SOURCE, AT_TARGET, 0, 5, "test", true),
OnDemandRelayAction::None,
);
}
#[test]
fn stops_relay_if_required_header_is_synced() {
assert_eq!(
select_on_demand_relay_action::<TestChain>(AT_SOURCE, AT_TARGET, AT_TARGET.unwrap(), 100, "test", true),
OnDemandRelayAction::Stop,
);
assert_eq!(
select_on_demand_relay_action::<TestChain>(AT_SOURCE, AT_TARGET, AT_TARGET.unwrap(), 100, "test", false),
OnDemandRelayAction::None,
);
}
}
@@ -10,8 +10,8 @@ bp-eth-poa = { path = "../../primitives/ethereum-poa" }
codec = { package = "parity-scale-codec", version = "2.0.0" }
headers-relay = { path = "../headers" }
hex-literal = "0.3"
jsonrpsee-proc-macros = "=0.2.0-alpha.5"
jsonrpsee-ws-client = "=0.2.0-alpha.5"
jsonrpsee-proc-macros = "=0.2.0-alpha.6"
jsonrpsee-ws-client = "=0.2.0-alpha.6"
libsecp256k1 = { version = "0.3.4", default-features = false, features = ["hmac"] }
log = "0.4.11"
relay-utils = { path = "../utils" }
@@ -9,8 +9,8 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
async-std = "1.6.5"
async-trait = "0.1.40"
codec = { package = "parity-scale-codec", version = "2.0.0" }
jsonrpsee-proc-macros = "=0.2.0-alpha.5"
jsonrpsee-ws-client = "=0.2.0-alpha.5"
jsonrpsee-proc-macros = "=0.2.0-alpha.6"
jsonrpsee-ws-client = "=0.2.0-alpha.6"
log = "0.4.11"
num-traits = "0.2"
rand = "0.7"
@@ -0,0 +1,23 @@
[package]
name = "relay-wococo-client"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0" }
headers-relay = { path = "../headers" }
relay-substrate-client = { path = "../client-substrate" }
relay-utils = { path = "../utils" }
# Bridge dependencies
bp-wococo = { path = "../../primitives/chain-wococo" }
# Substrate Dependencies
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -0,0 +1,97 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Types used to connect to the Wococo-Substrate chain.
use codec::Encode;
use relay_substrate_client::{Chain, ChainBase, ChainWithBalances, TransactionSignScheme};
use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
use std::time::Duration;
/// Wococo header id.
pub type HeaderId = relay_utils::HeaderId<bp_wococo::Hash, bp_wococo::BlockNumber>;
/// Wococo header type used in headers sync.
pub type SyncHeader = relay_substrate_client::SyncHeader<bp_wococo::Header>;
/// Wococo chain definition
#[derive(Debug, Clone, Copy)]
pub struct Wococo;
impl ChainBase for Wococo {
type BlockNumber = bp_wococo::BlockNumber;
type Hash = bp_wococo::Hash;
type Hasher = bp_wococo::Hashing;
type Header = bp_wococo::Header;
}
impl Chain for Wococo {
const NAME: &'static str = "Wococo";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
type AccountId = bp_wococo::AccountId;
type Index = bp_wococo::Index;
type SignedBlock = bp_wococo::SignedBlock;
type Call = bp_wococo::Call;
}
impl ChainWithBalances for Wococo {
type NativeBalance = bp_wococo::Balance;
fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
StorageKey(bp_wococo::account_info_storage_key(account_id))
}
}
impl TransactionSignScheme for Wococo {
type Chain = Wococo;
type AccountKeyPair = sp_core::sr25519::Pair;
type SignedTransaction = bp_wococo::UncheckedExtrinsic;
fn sign_transaction(
genesis_hash: <Self::Chain as ChainBase>::Hash,
signer: &Self::AccountKeyPair,
signer_nonce: <Self::Chain as Chain>::Index,
call: <Self::Chain as Chain>::Call,
) -> Self::SignedTransaction {
let raw_payload = SignedPayload::new(
call,
bp_wococo::SignedExtensions::new(
bp_wococo::VERSION,
sp_runtime::generic::Era::Immortal,
genesis_hash,
signer_nonce,
0,
),
)
.expect("SignedExtension never fails.");
let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
let signer: sp_runtime::MultiSigner = signer.public().into();
let (call, extra, _) = raw_payload.deconstruct();
bp_wococo::UncheckedExtrinsic::new_signed(
call,
sp_runtime::MultiAddress::Id(signer.into_account()),
signature.into(),
extra,
)
}
}
/// Wococo signing params.
pub type SigningParams = sp_core::sr25519::Pair;
@@ -26,7 +26,7 @@ use std::{
};
/// Transaction proof pipeline.
pub trait TransactionProofPipeline {
pub trait TransactionProofPipeline: 'static {
/// Name of the transaction proof source.
const SOURCE_NAME: &'static str;
/// Name of the transaction proof target.
@@ -35,18 +35,21 @@ pub trait TransactionProofPipeline {
/// Block type.
type Block: SourceBlock;
/// Transaction inclusion proof type.
type TransactionProof;
type TransactionProof: 'static + Send + Sync;
}
/// Block that is participating in exchange.
pub trait SourceBlock {
pub trait SourceBlock: 'static + Send + Sync {
/// Block hash type.
type Hash: Clone + Debug + Display;
type Hash: 'static + Clone + Send + Sync + Debug + Display;
/// Block number type.
type Number: Debug
type Number: 'static
+ Debug
+ Display
+ Clone
+ Copy
+ Send
+ Sync
+ Into<u64>
+ std::cmp::Ord
+ std::ops::Add<Output = Self::Number>
@@ -61,7 +64,7 @@ pub trait SourceBlock {
}
/// Transaction that is participating in exchange.
pub trait SourceTransaction {
pub trait SourceTransaction: 'static + Send {
/// Transaction hash type.
type Hash: Debug + Display;
@@ -39,9 +39,9 @@ pub struct TransactionProofsRelayState<BlockNumber> {
}
/// Transactions proofs relay storage.
pub trait TransactionProofsRelayStorage: Clone {
pub trait TransactionProofsRelayStorage: 'static + Clone + Send + Sync {
/// Associated block number.
type BlockNumber;
type BlockNumber: 'static + Send + Sync;
/// Get relay state.
fn state(&self) -> TransactionProofsRelayState<Self::BlockNumber>;
@@ -64,7 +64,7 @@ impl<BlockNumber> InMemoryStorage<BlockNumber> {
}
}
impl<BlockNumber: Clone + Copy> TransactionProofsRelayStorage for InMemoryStorage<BlockNumber> {
impl<BlockNumber: 'static + Clone + Copy + Send + Sync> TransactionProofsRelayStorage for InMemoryStorage<BlockNumber> {
type BlockNumber = BlockNumber;
fn state(&self) -> TransactionProofsRelayState<BlockNumber> {
@@ -89,7 +89,7 @@ pub async fn run<P: TransactionProofPipeline>(
source_client: impl SourceClient<P>,
target_client: impl TargetClient<P>,
metrics_params: MetricsParams,
exit_signal: impl Future<Output = ()>,
exit_signal: impl Future<Output = ()> + 'static + Send,
) -> Result<(), String> {
let exit_signal = exit_signal.shared();
@@ -99,7 +99,7 @@ pub async fn run<P: TransactionProofPipeline>(
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
.expose()
.await?
.run(|source_client, target_client, metrics| {
.run(metrics_prefix::<P>(), move |source_client, target_client, metrics| {
run_until_connection_lost(
storage.clone(),
source_client,
@@ -117,7 +117,7 @@ async fn run_until_connection_lost<P: TransactionProofPipeline>(
source_client: impl SourceClient<P>,
target_client: impl TargetClient<P>,
metrics_exch: Option<ExchangeLoopMetrics>,
exit_signal: impl Future<Output = ()>,
exit_signal: impl Future<Output = ()> + Send,
) -> Result<(), FailedClient> {
let mut retry_backoff = retry_backoff();
let mut state = storage.state();
@@ -39,6 +39,8 @@ use std::{
/// Finality proof synchronization loop parameters.
#[derive(Debug, Clone)]
pub struct FinalitySyncParams {
/// If `true`, then the separate async task for running finality loop is NOT spawned.
pub is_on_demand_task: bool,
/// Interval at which we check updates on both clients. Normally should be larger than
/// `min(source_block_time, target_block_time)`.
///
@@ -65,7 +67,7 @@ pub struct FinalitySyncParams {
pub trait SourceClient<P: FinalitySyncPipeline>: RelayClient {
/// Stream of new finality proofs. The stream is allowed to miss proofs for some
/// headers, even if those headers are mandatory.
type FinalityProofsStream: Stream<Item = P::FinalityProof>;
type FinalityProofsStream: Stream<Item = P::FinalityProof> + Send;
/// Get best finalized block number.
async fn best_finalized_block_number(&self) -> Result<P::Number, Self::Error>;
@@ -101,16 +103,17 @@ pub async fn run<P: FinalitySyncPipeline>(
target_client: impl TargetClient<P>,
sync_params: FinalitySyncParams,
metrics_params: MetricsParams,
exit_signal: impl Future<Output = ()>,
exit_signal: impl Future<Output = ()> + 'static + Send,
) -> Result<(), String> {
let exit_signal = exit_signal.shared();
relay_utils::relay_loop(source_client, target_client)
.spawn_loop_task(!sync_params.is_on_demand_task)
.with_metrics(Some(metrics_prefix::<P>()), metrics_params)
.loop_metric(|registry, prefix| SyncLoopMetrics::new(registry, prefix))?
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
.expose()
.await?
.run(|source_client, target_client, metrics| {
.run(metrics_prefix::<P>(), move |source_client, target_client, metrics| {
run_until_connection_lost(
source_client,
target_client,
@@ -106,7 +106,7 @@ impl RelayClient for TestSourceClient {
#[async_trait]
impl SourceClient<TestFinalitySyncPipeline> for TestSourceClient {
type FinalityProofsStream = Pin<Box<dyn Stream<Item = TestFinalityProof>>>;
type FinalityProofsStream = Pin<Box<dyn Stream<Item = TestFinalityProof> + 'static + Send>>;
async fn best_finalized_block_number(&self) -> Result<TestNumber, TestError> {
let mut data = self.data.lock();
@@ -197,6 +197,7 @@ fn run_sync_loop(state_function: impl Fn(&mut ClientsData) -> bool + Send + Sync
data: clients_data.clone(),
};
let sync_params = FinalitySyncParams {
is_on_demand_task: false,
tick: Duration::from_secs(0),
recent_finality_proofs_limit: 1024,
stall_timeout: Duration::from_secs(1),
+1 -1
View File
@@ -28,7 +28,7 @@ mod finality_loop;
mod finality_loop_tests;
/// Finality proofs synchronization pipeline.
pub trait FinalitySyncPipeline: Clone + Debug + Send + Sync {
pub trait FinalitySyncPipeline: 'static + Clone + Debug + Send + Sync {
/// Name of the finality proofs source.
const SOURCE_NAME: &'static str;
/// Name of the finality proofs target.
@@ -102,7 +102,7 @@ pub trait TargetClient<P: HeadersSyncPipeline>: RelayClient {
/// Synchronization maintain procedure.
#[async_trait]
pub trait SyncMaintain<P: HeadersSyncPipeline>: Clone + Send + Sync {
pub trait SyncMaintain<P: HeadersSyncPipeline>: 'static + Clone + Send + Sync {
/// Run custom maintain procedures. This is guaranteed to be called when both source and target
/// clients are unoccupied.
async fn maintain(&self, _sync: &mut HeadersSync<P>) {}
@@ -125,7 +125,7 @@ pub async fn run<P: HeadersSyncPipeline, TC: TargetClient<P>>(
sync_maintain: impl SyncMaintain<P>,
sync_params: HeadersSyncParams,
metrics_params: MetricsParams,
exit_signal: impl Future<Output = ()>,
exit_signal: impl Future<Output = ()> + 'static + Send,
) -> Result<(), String> {
let exit_signal = exit_signal.shared();
relay_utils::relay_loop(source_client, target_client)
@@ -134,7 +134,7 @@ pub async fn run<P: HeadersSyncPipeline, TC: TargetClient<P>>(
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
.expose()
.await?
.run(|source_client, target_client, metrics| {
.run(metrics_prefix::<P>(), move |source_client, target_client, metrics| {
run_until_connection_lost(
source_client,
source_tick,
@@ -159,7 +159,7 @@ async fn run_until_connection_lost<P: HeadersSyncPipeline, TC: TargetClient<P>>(
sync_maintain: impl SyncMaintain<P>,
sync_params: HeadersSyncParams,
metrics_sync: Option<SyncLoopMetrics>,
exit_signal: impl Future<Output = ()>,
exit_signal: impl Future<Output = ()> + Send,
) -> Result<(), FailedClient> {
let mut progress_context = (Instant::now(), None, None);
@@ -43,7 +43,7 @@ pub enum HeaderStatus {
}
/// Headers synchronization pipeline.
pub trait HeadersSyncPipeline: Clone + Send + Sync {
pub trait HeadersSyncPipeline: 'static + Clone + Send + Sync {
/// Name of the headers source.
const SOURCE_NAME: &'static str;
/// Name of the headers target.
@@ -23,7 +23,7 @@ use relay_utils::{BlockNumberBase, HeaderId};
use std::fmt::Debug;
/// One-way message lane.
pub trait MessageLane: Clone + Send + Sync {
pub trait MessageLane: 'static + Clone + Send + Sync {
/// Name of the messages source.
const SOURCE_NAME: &'static str;
/// Name of the messages target.
@@ -227,7 +227,7 @@ pub async fn run<P: MessageLane>(
source_client: impl SourceClient<P>,
target_client: impl TargetClient<P>,
metrics_params: MetricsParams,
exit_signal: impl Future<Output = ()>,
exit_signal: impl Future<Output = ()> + Send + 'static,
) -> Result<(), String> {
let exit_signal = exit_signal.shared();
relay_utils::relay_loop(source_client, target_client)
@@ -237,7 +237,9 @@ pub async fn run<P: MessageLane>(
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
.expose()
.await?
.run(|source_client, target_client, metrics| {
.run(
metrics_prefix::<P>(&params.lane),
move |source_client, target_client, metrics| {
run_until_connection_lost(
params.clone(),
source_client,
@@ -245,7 +247,8 @@ pub async fn run<P: MessageLane>(
metrics,
exit_signal.clone(),
)
})
},
)
.await
}
@@ -579,6 +582,9 @@ pub(crate) mod tests {
) -> Result<(), TestError> {
let mut data = self.data.lock();
(self.tick)(&mut *data);
data.source_state.best_self =
HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1);
data.source_state.best_finalized_self = data.source_state.best_self;
data.submitted_messages_receiving_proofs.push(proof);
data.source_latest_confirmed_received_nonce = proof;
Ok(())
@@ -681,6 +687,7 @@ pub(crate) mod tests {
}
data.target_state.best_self =
HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1);
data.target_state.best_finalized_self = data.target_state.best_self;
data.target_latest_received_nonce = *proof.0.end();
if let Some(target_latest_confirmed_received_nonce) = proof.1 {
data.target_latest_confirmed_received_nonce = target_latest_confirmed_received_nonce;
@@ -701,7 +708,7 @@ pub(crate) mod tests {
data: TestClientData,
source_tick: Arc<dyn Fn(&mut TestClientData) + Send + Sync>,
target_tick: Arc<dyn Fn(&mut TestClientData) + Send + Sync>,
exit_signal: impl Future<Output = ()>,
exit_signal: impl Future<Output = ()> + 'static + Send,
) -> TestClientData {
async_std::task::block_on(async {
let data = Arc::new(Mutex::new(data));
@@ -809,37 +816,37 @@ pub(crate) mod tests {
..Default::default()
},
Arc::new(|data: &mut TestClientData| {
// blocks are produced on every tick
data.source_state.best_self =
HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1);
data.source_state.best_finalized_self = data.source_state.best_self;
// headers relay must only be started when we need new target headers at source node
if data.target_to_source_header_required.is_some() {
assert!(data.source_state.best_finalized_peer_at_best_self.0 < data.target_state.best_self.0);
data.target_to_source_header_required = None;
}
// syncing target headers -> source chain
if let Some(last_requirement) = data.target_to_source_header_requirements.last() {
if *last_requirement != data.source_state.best_finalized_peer_at_best_self {
data.source_state.best_finalized_peer_at_best_self = *last_requirement;
}
}
}),
Arc::new(move |data: &mut TestClientData| {
// blocks are produced on every tick
data.target_state.best_self =
HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1);
data.target_state.best_finalized_self = data.target_state.best_self;
// headers relay must only be started when we need new source headers at target node
if data.source_to_target_header_required.is_some() {
assert!(data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_self.0);
data.source_to_target_header_required = None;
}
// syncing source headers -> target chain (all at once)
if data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_finalized_self.0 {
data.target_state.best_finalized_peer_at_best_self = data.source_state.best_finalized_self;
// syncing source headers -> target chain
if let Some(last_requirement) = data.source_to_target_header_requirements.last() {
if *last_requirement != data.target_state.best_finalized_peer_at_best_self {
data.target_state.best_finalized_peer_at_best_self = *last_requirement;
}
// syncing source headers -> target chain (all at once)
if data.source_state.best_finalized_peer_at_best_self.0 < data.target_state.best_finalized_self.0 {
data.source_state.best_finalized_peer_at_best_self = data.target_state.best_finalized_self;
}
// if target has received messages batch => increase blocks so that confirmations may be sent
if data.target_latest_received_nonce == 4
|| data.target_latest_received_nonce == 8
|| data.target_latest_received_nonce == 10
{
data.target_state.best_self =
HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.0 + 1);
data.target_state.best_finalized_self = data.target_state.best_self;
data.source_state.best_self =
HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.0 + 1);
data.source_state.best_finalized_self = data.source_state.best_self;
}
// if source has received all messages receiving confirmations => stop
if data.source_latest_confirmed_received_nonce == 10 {
@@ -292,7 +292,16 @@ impl<P: MessageLane> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::M
}
fn required_source_header_at_target(&self, current_best: &SourceHeaderIdOf<P>) -> Option<SourceHeaderIdOf<P>> {
self.strategy.required_source_header_at_target(current_best)
let header_required_for_messages_delivery = self.strategy.required_source_header_at_target(current_best);
let header_required_for_reward_confirmations_delivery =
self.latest_confirmed_nonces_at_source.back().map(|(id, _)| id.clone());
match (
header_required_for_messages_delivery,
header_required_for_reward_confirmations_delivery,
) {
(Some(id1), Some(id2)) => Some(if id1.0 > id2.0 { id1 } else { id2 }),
(a, b) => a.or(b),
}
}
fn best_at_source(&self) -> Option<MessageNonce> {
@@ -876,4 +885,46 @@ mod tests {
Some(((20..=23), proof_parameters(true, 4)))
);
}
#[test]
fn source_header_is_requied_when_confirmations_are_required() {
// let's prepare situation when:
// - all messages [20; 23] have been generated at source block#1;
let (mut state, mut strategy) = prepare_strategy();
// - messages [20; 21] have been delivered, but messages [11; 20] can't be delivered because of unrewarded
// relayers vector capacity;
strategy.max_unconfirmed_nonces_at_target = 2;
assert_eq!(
strategy.select_nonces_to_deliver(&state),
Some(((20..=21), proof_parameters(false, 2)))
);
strategy.finalized_target_nonces_updated(
TargetClientNonces {
latest_nonce: 21,
nonces_data: DeliveryRaceTargetNoncesData {
confirmed_nonce: 19,
unrewarded_relayers: UnrewardedRelayersState {
unrewarded_relayer_entries: 2,
messages_in_oldest_entry: 2,
total_messages: 2,
},
},
},
&mut state,
);
assert_eq!(strategy.select_nonces_to_deliver(&state), None);
// - messages [1; 10] receiving confirmation has been delivered at source block#2;
strategy.source_nonces_updated(
header_id(2),
SourceClientNonces {
new_nonces: BTreeMap::new(),
confirmed_nonce: Some(21),
},
);
// - so now we'll need to relay source block#11 to be able to accept messages [11; 20].
assert_eq!(
strategy.required_source_header_at_target(&header_id(1)),
Some(header_id(2))
);
}
}
@@ -16,7 +16,11 @@
//! Relayer initialization functions.
use std::{fmt::Display, io::Write};
use std::{cell::RefCell, fmt::Display, io::Write};
async_std::task_local! {
pub(crate) static LOOP_NAME: RefCell<String> = RefCell::new(String::default());
}
/// Initialize relay environment.
pub fn initialize_relay() {
@@ -43,20 +47,56 @@ pub fn initialize_logger(with_timestamp: bool) {
Either::Right(ansi_term::Colour::Fixed(8).bold().paint(timestamp))
};
writeln!(buf, "{} {} {} {}", timestamp, log_level, log_target, record.args(),)
writeln!(
buf,
"{}{} {} {} {}",
loop_name_prefix(),
timestamp,
log_level,
log_target,
record.args(),
)
});
} else {
builder.format(move |buf, record| {
let log_level = color_level(record.level());
let log_target = color_target(record.target());
writeln!(buf, "{} {} {}", log_level, log_target, record.args(),)
writeln!(
buf,
"{}{} {} {}",
loop_name_prefix(),
log_level,
log_target,
record.args(),
)
});
}
builder.init();
}
/// Initialize relay loop. Must only be called once per every loop task.
pub(crate) fn initialize_loop(loop_name: String) {
LOOP_NAME.with(|g_loop_name| *g_loop_name.borrow_mut() = loop_name);
}
/// Returns loop name prefix to use in logs. The prefix is initialized with the `initialize_loop` call.
fn loop_name_prefix() -> String {
// try_with to avoid panic outside of async-std task context
LOOP_NAME
.try_with(|loop_name| {
// using borrow is ok here, because loop is only initialized once (=> borrow_mut will only be called once)
let loop_name = loop_name.borrow();
if loop_name.is_empty() {
String::new()
} else {
format!("[{}] ", loop_name)
}
})
.unwrap_or_else(|_| String::new())
}
enum Either<A, B> {
Left(A),
Right(B),
+88 -46
View File
@@ -26,9 +26,9 @@ pub const RECONNECT_DELAY: Duration = Duration::from_secs(10);
/// Basic blockchain client from relay perspective.
#[async_trait]
pub trait Client: Clone + Send + Sync {
pub trait Client: 'static + Clone + Send + Sync {
/// Type of error this clients returns.
type Error: Debug + MaybeConnectionError;
type Error: 'static + Debug + MaybeConnectionError + Send + Sync;
/// Try to reconnect to source node.
async fn reconnect(&mut self) -> Result<(), Self::Error>;
@@ -38,6 +38,7 @@ pub trait Client: Clone + Send + Sync {
pub fn relay_loop<SC, TC>(source_client: SC, target_client: TC) -> Loop<SC, TC, ()> {
Loop {
reconnect_delay: RECONNECT_DELAY,
spawn_loop_task: true,
source_client,
target_client,
loop_metric: None,
@@ -49,6 +50,7 @@ pub fn relay_metrics(prefix: Option<String>, params: MetricsParams) -> LoopMetri
LoopMetrics {
relay_loop: Loop {
reconnect_delay: RECONNECT_DELAY,
spawn_loop_task: true,
source_client: (),
target_client: (),
loop_metric: None,
@@ -63,6 +65,7 @@ pub fn relay_metrics(prefix: Option<String>, params: MetricsParams) -> LoopMetri
/// Generic relay loop.
pub struct Loop<SC, TC, LM> {
reconnect_delay: Duration,
spawn_loop_task: bool,
source_client: SC,
target_client: TC,
loop_metric: Option<LM>,
@@ -84,11 +87,23 @@ impl<SC, TC, LM> Loop<SC, TC, LM> {
self
}
/// Set spawn-dedicated-loop-task flag.
///
/// If `true` (default), separate async task is spawned to run relay loop. This is the default
/// behavior for all loops. If `false`, then loop is executed as a part of the current
/// task. The `false` is used for on-demand tasks, which are cancelled from time to time
/// and there's already a dedicated on-demand task for running such loops.
pub fn spawn_loop_task(mut self, spawn_loop_task: bool) -> Self {
self.spawn_loop_task = spawn_loop_task;
self
}
/// Start building loop metrics using given prefix.
pub fn with_metrics(self, prefix: Option<String>, params: MetricsParams) -> LoopMetrics<SC, TC, ()> {
LoopMetrics {
relay_loop: Loop {
reconnect_delay: self.reconnect_delay,
spawn_loop_task: self.spawn_loop_task,
source_client: self.source_client,
target_client: self.target_client,
loop_metric: None,
@@ -105,63 +120,47 @@ impl<SC, TC, LM> Loop<SC, TC, LM> {
/// This function represents an outer loop, which in turn calls provided `run_loop` function to do
/// actual job. When `run_loop` returns, this outer loop reconnects to failed client (source,
/// target or both) and calls `run_loop` again.
pub async fn run<R, F>(mut self, run_loop: R) -> Result<(), String>
pub async fn run<R, F>(mut self, loop_name: String, run_loop: R) -> Result<(), String>
where
R: Fn(SC, TC, Option<LM>) -> F,
F: Future<Output = Result<(), FailedClient>>,
SC: Client,
TC: Client,
LM: Clone,
R: 'static + Send + Fn(SC, TC, Option<LM>) -> F,
F: 'static + Send + Future<Output = Result<(), FailedClient>>,
SC: 'static + Client,
TC: 'static + Client,
LM: 'static + Send + Clone,
{
let spawn_loop_task = self.spawn_loop_task;
let run_loop_task = async move {
crate::initialize::initialize_loop(loop_name);
loop {
let result = run_loop(
self.source_client.clone(),
self.target_client.clone(),
self.loop_metric.clone(),
)
.await;
let loop_metric = self.loop_metric.clone();
let future_result = run_loop(self.source_client.clone(), self.target_client.clone(), loop_metric);
let result = future_result.await;
match result {
Ok(()) => break,
Err(failed_client) => loop {
async_std::task::sleep(self.reconnect_delay).await;
if failed_client == FailedClient::Both || failed_client == FailedClient::Source {
match self.source_client.reconnect().await {
Ok(()) => (),
Err(error) => {
log::warn!(
target: "bridge",
"Failed to reconnect to source client. Going to retry in {}s: {:?}",
self.reconnect_delay.as_secs(),
error,
);
continue;
Err(failed_client) => {
reconnect_failed_client(
failed_client,
self.reconnect_delay,
&mut self.source_client,
&mut self.target_client,
)
.await
}
}
}
if failed_client == FailedClient::Both || failed_client == FailedClient::Target {
match self.target_client.reconnect().await {
Ok(()) => (),
Err(error) => {
log::warn!(
target: "bridge",
"Failed to reconnect to target client. Going to retry in {}s: {:?}",
self.reconnect_delay.as_secs(),
error,
);
continue;
}
}
}
break;
},
}
log::debug!(target: "bridge", "Restarting relay loop");
}
Ok(())
};
if spawn_loop_task {
async_std::task::spawn(run_loop_task).await
} else {
run_loop_task.await
}
}
}
@@ -237,6 +236,7 @@ impl<SC, TC, LM> LoopMetrics<SC, TC, LM> {
Ok(Loop {
reconnect_delay: self.relay_loop.reconnect_delay,
spawn_loop_task: self.relay_loop.spawn_loop_task,
source_client: self.relay_loop.source_client,
target_client: self.relay_loop.target_client,
loop_metric: self.loop_metric,
@@ -244,6 +244,48 @@ impl<SC, TC, LM> LoopMetrics<SC, TC, LM> {
}
}
/// Deal with the client who has returned connection error.
pub async fn reconnect_failed_client(
failed_client: FailedClient,
reconnect_delay: Duration,
source_client: &mut impl Client,
target_client: &mut impl Client,
) {
loop {
async_std::task::sleep(reconnect_delay).await;
if failed_client == FailedClient::Both || failed_client == FailedClient::Source {
match source_client.reconnect().await {
Ok(()) => (),
Err(error) => {
log::warn!(
target: "bridge",
"Failed to reconnect to source client. Going to retry in {}s: {:?}",
reconnect_delay.as_secs(),
error,
);
continue;
}
}
}
if failed_client == FailedClient::Both || failed_client == FailedClient::Target {
match target_client.reconnect().await {
Ok(()) => (),
Err(error) => {
log::warn!(
target: "bridge",
"Failed to reconnect to target client. Going to retry in {}s: {:?}",
reconnect_delay.as_secs(),
error,
);
continue;
}
}
}
break;
}
}
/// Create new registry with global metrics.
fn create_metrics_registry(prefix: Option<String>) -> Registry {
match prefix {
+4 -4
View File
@@ -15,10 +15,10 @@ cd $LOGS_DIR
SERVICES=(\
deployments_relay-messages-millau-to-rialto-generator_1 \
deployments_relay-messages-rialto-to-millau-generator_1 \
deployments_relay-messages-millau-to-rialto_1 \
deployments_relay-messages-rialto-to-millau_1 \
deployments_relay-headers-millau-to-rialto_1 \
deployments_relay-headers-rialto-to-millau_1 \
deployments_relay-messages-millau-to-rialto-lane-00000001_1 \
deployments_relay-messages-rialto-to-millau-lane-00000001_1 \
deployments_relay-millau-rialto_1 \
deployments_relay-headers-westend-to-millau_1 \
deployments_rialto-node-alice_1 \
deployments_rialto-node-bob_1 \
deployments_millau-node-alice_1 \