mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 10:31:03 +00:00
Merge commit 'f9c24ef0db390c355241445af37a5c7999a7dc66' into hc-bump-bridges-subtree-take-2
This commit is contained in:
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
@@ -41,3 +41,25 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
command: fmt
|
command: fmt
|
||||||
args: --all -- --check
|
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")
|
||||||
|
|||||||
+2
-2
@@ -85,8 +85,8 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
#- beta
|
#- beta
|
||||||
- nightly
|
- nightly-2021-04-10
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
RUST_BACKTRACE: full
|
RUST_BACKTRACE: full
|
||||||
|
|||||||
Generated
+320
-180
File diff suppressed because it is too large
Load Diff
@@ -126,8 +126,8 @@ both Substrate chains it must be run last.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# In `parity-bridges-common` folder
|
# In `parity-bridges-common` folder
|
||||||
./deployments/local-scripts/run-rialto-bridge-node.sh
|
./deployments/local-scripts/run-rialto-node.sh
|
||||||
./deployments/local-scripts/run-millau-bridge-node.sh
|
./deployments/local-scripts/run-millau-node.sh
|
||||||
./deployments/local-scripts/relay-millau-to-rialto.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]
|
[dependencies]
|
||||||
jsonrpc-core = "15.1.0"
|
jsonrpc-core = "15.1.0"
|
||||||
structopt = "0.3.21"
|
structopt = "0.3.21"
|
||||||
|
serde_json = "1.0.59"
|
||||||
|
|
||||||
# Bridge dependencies
|
# 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-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-inherents = { 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-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -67,6 +67,18 @@ pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, GrandpaId) {
|
|||||||
impl Alternative {
|
impl Alternative {
|
||||||
/// Get an actual chain config from one of the alternatives.
|
/// Get an actual chain config from one of the alternatives.
|
||||||
pub(crate) fn load(self) -> ChainSpec {
|
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 {
|
match self {
|
||||||
Alternative::Development => ChainSpec::from_genesis(
|
Alternative::Development => ChainSpec::from_genesis(
|
||||||
"Development",
|
"Development",
|
||||||
@@ -81,6 +93,9 @@ impl Alternative {
|
|||||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||||
|
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
@@ -88,7 +103,7 @@ impl Alternative {
|
|||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
properties,
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
Alternative::LocalTestnet => ChainSpec::from_genesis(
|
Alternative::LocalTestnet => ChainSpec::from_genesis(
|
||||||
@@ -127,7 +142,13 @@ impl Alternative {
|
|||||||
pallet_bridge_messages::DefaultInstance,
|
pallet_bridge_messages::DefaultInstance,
|
||||||
>::relayer_fund_account_id(),
|
>::relayer_fund_account_id(),
|
||||||
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
|
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,
|
true,
|
||||||
@@ -136,7 +157,7 @@ impl Alternative {
|
|||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
properties,
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -155,11 +176,11 @@ fn testnet_genesis(
|
|||||||
) -> GenesisConfig {
|
) -> GenesisConfig {
|
||||||
GenesisConfig {
|
GenesisConfig {
|
||||||
frame_system: SystemConfig {
|
frame_system: SystemConfig {
|
||||||
code: WASM_BINARY.to_vec(),
|
code: WASM_BINARY.expect("Millau development WASM not available").to_vec(),
|
||||||
changes_trie_config: Default::default(),
|
changes_trie_config: Default::default(),
|
||||||
},
|
},
|
||||||
pallet_balances: BalancesConfig {
|
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 {
|
pallet_aura: AuraConfig {
|
||||||
authorities: Vec::new(),
|
authorities: Vec::new(),
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ pub enum Subcommand {
|
|||||||
Revert(sc_cli::RevertCmd),
|
Revert(sc_cli::RevertCmd),
|
||||||
|
|
||||||
/// Inspect blocks or extrinsics.
|
/// Inspect blocks or extrinsics.
|
||||||
Inspect(node_inspect::cli::InspectCmd),
|
Inspect(node_inspect::cli::InspectKeyCmd),
|
||||||
|
|
||||||
/// Benchmark runtime pallets.
|
/// Benchmark runtime pallets.
|
||||||
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
|
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ use sc_finality_grandpa::SharedVoterState;
|
|||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
|
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
|
||||||
use sc_telemetry::{Telemetry, TelemetryWorker};
|
use sc_telemetry::{Telemetry, TelemetryWorker};
|
||||||
|
use sp_consensus::SlotData;
|
||||||
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
||||||
use sp_inherents::InherentDataProviders;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -80,8 +80,6 @@ pub fn new_partial(
|
|||||||
if config.keystore_remote.is_some() {
|
if config.keystore_remote.is_some() {
|
||||||
return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
|
return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
|
||||||
}
|
}
|
||||||
let inherent_data_providers = InherentDataProviders::new();
|
|
||||||
|
|
||||||
let telemetry = config
|
let telemetry = config
|
||||||
.telemetry_endpoints
|
.telemetry_endpoints
|
||||||
.clone()
|
.clone()
|
||||||
@@ -124,14 +122,24 @@ pub fn new_partial(
|
|||||||
let aura_block_import =
|
let aura_block_import =
|
||||||
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
|
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(),
|
block_import: aura_block_import.clone(),
|
||||||
justification_import: Some(Box::new(grandpa_block_import)),
|
justification_import: Some(Box::new(grandpa_block_import)),
|
||||||
client: client.clone(),
|
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(),
|
spawner: &task_manager.spawn_essential_handle(),
|
||||||
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
|
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
|
||||||
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
|
|
||||||
registry: config.prometheus_registry(),
|
registry: config.prometheus_registry(),
|
||||||
check_for_equivocation: Default::default(),
|
check_for_equivocation: Default::default(),
|
||||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||||
@@ -145,7 +153,6 @@ pub fn new_partial(
|
|||||||
keystore_container,
|
keystore_container,
|
||||||
select_chain,
|
select_chain,
|
||||||
transaction_pool,
|
transaction_pool,
|
||||||
inherent_data_providers,
|
|
||||||
other: (aura_block_import, grandpa_link, telemetry),
|
other: (aura_block_import, grandpa_link, telemetry),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -167,7 +174,6 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
mut keystore_container,
|
mut keystore_container,
|
||||||
select_chain,
|
select_chain,
|
||||||
transaction_pool,
|
transaction_pool,
|
||||||
inherent_data_providers,
|
|
||||||
other: (block_import, grandpa_link, mut telemetry),
|
other: (block_import, grandpa_link, mut telemetry),
|
||||||
} = new_partial(&config)?;
|
} = 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 can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
|
||||||
|
|
||||||
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _>(StartAuraParams {
|
let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
|
||||||
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
|
let raw_slot_duration = slot_duration.slot_duration();
|
||||||
client: client.clone(),
|
|
||||||
|
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _, _>(StartAuraParams {
|
||||||
|
slot_duration,
|
||||||
|
client,
|
||||||
select_chain,
|
select_chain,
|
||||||
block_import,
|
block_import,
|
||||||
proposer_factory,
|
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,
|
force_authoring,
|
||||||
backoff_authoring_blocks,
|
backoff_authoring_blocks,
|
||||||
keystore: keystore_container.sync_keystore(),
|
keystore: keystore_container.sync_keystore(),
|
||||||
@@ -394,14 +412,23 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
let aura_block_import =
|
let aura_block_import =
|
||||||
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
|
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,
|
block_import: aura_block_import,
|
||||||
justification_import: Some(Box::new(grandpa_block_import)),
|
justification_import: Some(Box::new(grandpa_block_import)),
|
||||||
client: client.clone(),
|
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(),
|
spawner: &task_manager.spawn_essential_handle(),
|
||||||
can_author_with: sp_consensus::NeverCanAuthor,
|
can_author_with: sp_consensus::NeverCanAuthor,
|
||||||
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
|
|
||||||
registry: config.prometheus_registry(),
|
registry: config.prometheus_registry(),
|
||||||
check_for_equivocation: Default::default(),
|
check_for_equivocation: Default::default(),
|
||||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
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 }
|
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "2.0.0" }
|
substrate-wasm-builder = "3.0.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -14,13 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use wasm_builder_runner::WasmBuilder;
|
use substrate_wasm_builder::WasmBuilder;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
WasmBuilder::new()
|
WasmBuilder::new()
|
||||||
.with_current_project()
|
.with_current_project()
|
||||||
.with_wasm_builder_from_crates("1.0.11")
|
|
||||||
.export_heap_base()
|
|
||||||
.import_memory()
|
.import_memory()
|
||||||
|
.export_heap_base()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ use sp_version::RuntimeVersion;
|
|||||||
// A few exports that help ease life for downstream crates.
|
// A few exports that help ease life for downstream crates.
|
||||||
pub use frame_support::{
|
pub use frame_support::{
|
||||||
construct_runtime, parameter_types,
|
construct_runtime, parameter_types,
|
||||||
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem, Randomness},
|
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem},
|
||||||
weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, RuntimeDbWeight, Weight},
|
weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, RuntimeDbWeight, Weight},
|
||||||
StorageValue,
|
StorageValue,
|
||||||
};
|
};
|
||||||
@@ -308,7 +308,6 @@ parameter_types! {
|
|||||||
// Note that once this is hit the pallet will essentially throttle incoming requests down to one
|
// Note that once this is hit the pallet will essentially throttle incoming requests down to one
|
||||||
// call per block.
|
// call per block.
|
||||||
pub const MaxRequests: u32 = 50;
|
pub const MaxRequests: u32 = 50;
|
||||||
pub const WestendValidatorCount: u32 = 255;
|
|
||||||
|
|
||||||
// Number of headers to keep.
|
// Number of headers to keep.
|
||||||
//
|
//
|
||||||
@@ -478,10 +477,6 @@ impl_runtime_apis! {
|
|||||||
) -> sp_inherents::CheckInherentsResult {
|
) -> sp_inherents::CheckInherentsResult {
|
||||||
data.check_extrinsics(&block)
|
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 {
|
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use frame_support::{
|
|||||||
weights::{DispatchClass, Weight},
|
weights::{DispatchClass, Weight},
|
||||||
RuntimeDebug,
|
RuntimeDebug,
|
||||||
};
|
};
|
||||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128};
|
||||||
use sp_std::{convert::TryFrom, ops::RangeInclusive};
|
use sp_std::{convert::TryFrom, ops::RangeInclusive};
|
||||||
|
|
||||||
/// Initial value of `RialtoToMillauConversionRate` parameter.
|
/// Initial value of `RialtoToMillauConversionRate` parameter.
|
||||||
@@ -214,7 +214,9 @@ impl TargetHeaderChain<ToRialtoMessagePayload, bp_rialto::AccountId> for Rialto
|
|||||||
fn verify_messages_delivery_proof(
|
fn verify_messages_delivery_proof(
|
||||||
proof: Self::MessagesDeliveryProof,
|
proof: Self::MessagesDeliveryProof,
|
||||||
) -> Result<(LaneId, InboundLaneData<bp_millau::AccountId>), Self::Error> {
|
) -> 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,
|
proof: Self::MessagesProof,
|
||||||
messages_count: u32,
|
messages_count: u32,
|
||||||
) -> Result<ProvedMessages<Message<bp_rialto::Balance>>, Self::Error> {
|
) -> 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]
|
[dependencies]
|
||||||
jsonrpc-core = "15.1.0"
|
jsonrpc-core = "15.1.0"
|
||||||
structopt = "0.3.21"
|
structopt = "0.3.21"
|
||||||
|
serde_json = "1.0.59"
|
||||||
|
|
||||||
# Bridge dependencies
|
# 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-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-inherents = { 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-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use rialto_runtime::{
|
|||||||
AccountId, AuraConfig, BalancesConfig, BridgeKovanConfig, BridgeRialtoPoAConfig, GenesisConfig, GrandpaConfig,
|
AccountId, AuraConfig, BalancesConfig, BridgeKovanConfig, BridgeRialtoPoAConfig, GenesisConfig, GrandpaConfig,
|
||||||
SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
|
SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
|
||||||
};
|
};
|
||||||
|
use serde_json::json;
|
||||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
use sp_core::{sr25519, Pair, Public};
|
use sp_core::{sr25519, Pair, Public};
|
||||||
use sp_finality_grandpa::AuthorityId as GrandpaId;
|
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 {
|
impl Alternative {
|
||||||
/// Get an actual chain config from one of the alternatives.
|
/// Get an actual chain config from one of the alternatives.
|
||||||
pub(crate) fn load(self) -> ChainSpec {
|
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 {
|
match self {
|
||||||
Alternative::Development => ChainSpec::from_genesis(
|
Alternative::Development => ChainSpec::from_genesis(
|
||||||
"Development",
|
"Development",
|
||||||
@@ -81,6 +94,9 @@ impl Alternative {
|
|||||||
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||||
|
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
@@ -88,7 +104,7 @@ impl Alternative {
|
|||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
properties,
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
Alternative::LocalTestnet => ChainSpec::from_genesis(
|
Alternative::LocalTestnet => ChainSpec::from_genesis(
|
||||||
@@ -126,9 +142,15 @@ impl Alternative {
|
|||||||
rialto_runtime::Runtime,
|
rialto_runtime::Runtime,
|
||||||
pallet_bridge_messages::DefaultInstance,
|
pallet_bridge_messages::DefaultInstance,
|
||||||
>::relayer_fund_account_id(),
|
>::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(
|
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
|
||||||
get_account_id_from_seed::<sr25519::Public>("Dave"),
|
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,
|
true,
|
||||||
)
|
)
|
||||||
@@ -136,7 +158,7 @@ impl Alternative {
|
|||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
properties,
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -155,11 +177,11 @@ fn testnet_genesis(
|
|||||||
) -> GenesisConfig {
|
) -> GenesisConfig {
|
||||||
GenesisConfig {
|
GenesisConfig {
|
||||||
frame_system: SystemConfig {
|
frame_system: SystemConfig {
|
||||||
code: WASM_BINARY.to_vec(),
|
code: WASM_BINARY.expect("Rialto development WASM not available").to_vec(),
|
||||||
changes_trie_config: Default::default(),
|
changes_trie_config: Default::default(),
|
||||||
},
|
},
|
||||||
pallet_balances: BalancesConfig {
|
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 {
|
pallet_aura: AuraConfig {
|
||||||
authorities: Vec::new(),
|
authorities: Vec::new(),
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ pub enum Subcommand {
|
|||||||
Revert(sc_cli::RevertCmd),
|
Revert(sc_cli::RevertCmd),
|
||||||
|
|
||||||
/// Inspect blocks or extrinsics.
|
/// Inspect blocks or extrinsics.
|
||||||
Inspect(node_inspect::cli::InspectCmd),
|
Inspect(node_inspect::cli::InspectKeyCmd),
|
||||||
|
|
||||||
/// Benchmark runtime pallets.
|
/// Benchmark runtime pallets.
|
||||||
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
|
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ use sc_finality_grandpa::SharedVoterState;
|
|||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
|
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
|
||||||
use sc_telemetry::{Telemetry, TelemetryWorker};
|
use sc_telemetry::{Telemetry, TelemetryWorker};
|
||||||
|
use sp_consensus::SlotData;
|
||||||
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
|
||||||
use sp_inherents::InherentDataProviders;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -80,7 +80,6 @@ pub fn new_partial(
|
|||||||
if config.keystore_remote.is_some() {
|
if config.keystore_remote.is_some() {
|
||||||
return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
|
return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
|
||||||
}
|
}
|
||||||
let inherent_data_providers = InherentDataProviders::new();
|
|
||||||
|
|
||||||
let telemetry = config
|
let telemetry = config
|
||||||
.telemetry_endpoints
|
.telemetry_endpoints
|
||||||
@@ -124,14 +123,24 @@ pub fn new_partial(
|
|||||||
let aura_block_import =
|
let aura_block_import =
|
||||||
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
|
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(),
|
block_import: aura_block_import.clone(),
|
||||||
justification_import: Some(Box::new(grandpa_block_import)),
|
justification_import: Some(Box::new(grandpa_block_import)),
|
||||||
client: client.clone(),
|
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(),
|
spawner: &task_manager.spawn_essential_handle(),
|
||||||
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
|
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
|
||||||
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
|
|
||||||
registry: config.prometheus_registry(),
|
registry: config.prometheus_registry(),
|
||||||
check_for_equivocation: Default::default(),
|
check_for_equivocation: Default::default(),
|
||||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
||||||
@@ -145,7 +154,6 @@ pub fn new_partial(
|
|||||||
keystore_container,
|
keystore_container,
|
||||||
select_chain,
|
select_chain,
|
||||||
transaction_pool,
|
transaction_pool,
|
||||||
inherent_data_providers,
|
|
||||||
other: (aura_block_import, grandpa_link, telemetry),
|
other: (aura_block_import, grandpa_link, telemetry),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -167,7 +175,6 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
mut keystore_container,
|
mut keystore_container,
|
||||||
select_chain,
|
select_chain,
|
||||||
transaction_pool,
|
transaction_pool,
|
||||||
inherent_data_providers,
|
|
||||||
other: (block_import, grandpa_link, mut telemetry),
|
other: (block_import, grandpa_link, mut telemetry),
|
||||||
} = new_partial(&config)?;
|
} = 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 can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
|
||||||
|
|
||||||
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _>(StartAuraParams {
|
let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
|
||||||
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
|
let raw_slot_duration = slot_duration.slot_duration();
|
||||||
client: client.clone(),
|
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _, _>(StartAuraParams {
|
||||||
|
slot_duration,
|
||||||
|
client,
|
||||||
select_chain,
|
select_chain,
|
||||||
block_import,
|
block_import,
|
||||||
proposer_factory,
|
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,
|
force_authoring,
|
||||||
backoff_authoring_blocks,
|
backoff_authoring_blocks,
|
||||||
keystore: keystore_container.sync_keystore(),
|
keystore: keystore_container.sync_keystore(),
|
||||||
@@ -395,14 +413,23 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
let aura_block_import =
|
let aura_block_import =
|
||||||
sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(grandpa_block_import.clone(), client.clone());
|
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,
|
block_import: aura_block_import,
|
||||||
justification_import: Some(Box::new(grandpa_block_import)),
|
justification_import: Some(Box::new(grandpa_block_import)),
|
||||||
client: client.clone(),
|
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(),
|
spawner: &task_manager.spawn_essential_handle(),
|
||||||
can_author_with: sp_consensus::NeverCanAuthor,
|
can_author_with: sp_consensus::NeverCanAuthor,
|
||||||
slot_duration: sc_consensus_aura::slot_duration(&*client)?,
|
|
||||||
registry: config.prometheus_registry(),
|
registry: config.prometheus_registry(),
|
||||||
check_for_equivocation: Default::default(),
|
check_for_equivocation: Default::default(),
|
||||||
telemetry: telemetry.as_ref().map(|x| x.handle()),
|
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"] }
|
libsecp256k1 = { version = "0.3.4", features = ["hmac"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "2.0.0" }
|
substrate-wasm-builder = "3.0.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -14,13 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use wasm_builder_runner::WasmBuilder;
|
use substrate_wasm_builder::WasmBuilder;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
WasmBuilder::new()
|
WasmBuilder::new()
|
||||||
.with_current_project()
|
.with_current_project()
|
||||||
.with_wasm_builder_from_crates("1.0.11")
|
|
||||||
.export_heap_base()
|
|
||||||
.import_memory()
|
.import_memory()
|
||||||
|
.export_heap_base()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ use sp_version::RuntimeVersion;
|
|||||||
// A few exports that help ease life for downstream crates.
|
// A few exports that help ease life for downstream crates.
|
||||||
pub use frame_support::{
|
pub use frame_support::{
|
||||||
construct_runtime, parameter_types,
|
construct_runtime, parameter_types,
|
||||||
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem, Randomness},
|
traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem},
|
||||||
weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, RuntimeDbWeight, Weight},
|
weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, RuntimeDbWeight, Weight},
|
||||||
StorageValue,
|
StorageValue,
|
||||||
};
|
};
|
||||||
@@ -409,19 +409,34 @@ impl pallet_session::Config for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
// This is a pretty unscientific cap.
|
/// This is a pretty unscientific cap.
|
||||||
//
|
///
|
||||||
// Note that once this is hit the pallet will essentially throttle incoming requests down to one
|
/// Note that once this is hit the pallet will essentially throttle incoming requests down to one
|
||||||
// call per block.
|
/// call per block.
|
||||||
pub const MaxRequests: u32 = 50;
|
pub const MaxRequests: u32 = 50;
|
||||||
|
}
|
||||||
|
|
||||||
// Number of headers to keep.
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
//
|
parameter_types! {
|
||||||
// Assuming the worst case of every header being finalized, we will keep headers at least for a
|
/// Number of headers to keep in benchmarks.
|
||||||
// week.
|
///
|
||||||
|
/// 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 const HeadersToKeep: u32 = 7 * bp_rialto::DAYS as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type MillauGrandpaInstance = ();
|
||||||
impl pallet_bridge_grandpa::Config for Runtime {
|
impl pallet_bridge_grandpa::Config for Runtime {
|
||||||
type BridgedChain = bp_millau::Millau;
|
type BridgedChain = bp_millau::Millau;
|
||||||
type MaxRequests = MaxRequests;
|
type MaxRequests = MaxRequests;
|
||||||
@@ -572,10 +587,6 @@ impl_runtime_apis! {
|
|||||||
) -> sp_inherents::CheckInherentsResult {
|
) -> sp_inherents::CheckInherentsResult {
|
||||||
data.check_extrinsics(&block)
|
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 {
|
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
|
||||||
@@ -874,7 +885,7 @@ impl_runtime_apis! {
|
|||||||
params: MessageParams<Self::AccountId>,
|
params: MessageParams<Self::AccountId>,
|
||||||
) -> (millau_messages::ToMillauMessagePayload, Balance) {
|
) -> (millau_messages::ToMillauMessagePayload, Balance) {
|
||||||
let message_payload = vec![0; params.size as usize];
|
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,
|
params.sender_account,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -944,10 +955,10 @@ impl_runtime_apis! {
|
|||||||
make_millau_outbound_lane_data_key,
|
make_millau_outbound_lane_data_key,
|
||||||
make_millau_header,
|
make_millau_header,
|
||||||
call_weight,
|
call_weight,
|
||||||
pallet_bridge_dispatch::MessagePayload {
|
bp_message_dispatch::MessagePayload {
|
||||||
spec_version: VERSION.spec_version,
|
spec_version: VERSION.spec_version,
|
||||||
weight: call_weight,
|
weight: call_weight,
|
||||||
origin: pallet_bridge_dispatch::CallOrigin::<
|
origin: bp_message_dispatch::CallOrigin::<
|
||||||
bp_millau::AccountId,
|
bp_millau::AccountId,
|
||||||
MultiSigner,
|
MultiSigner,
|
||||||
Signature,
|
Signature,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use frame_support::{
|
|||||||
weights::{DispatchClass, Weight},
|
weights::{DispatchClass, Weight},
|
||||||
RuntimeDebug,
|
RuntimeDebug,
|
||||||
};
|
};
|
||||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128};
|
||||||
use sp_std::{convert::TryFrom, ops::RangeInclusive};
|
use sp_std::{convert::TryFrom, ops::RangeInclusive};
|
||||||
|
|
||||||
/// Initial value of `MillauToRialtoConversionRate` parameter.
|
/// Initial value of `MillauToRialtoConversionRate` parameter.
|
||||||
@@ -214,7 +214,9 @@ impl TargetHeaderChain<ToMillauMessagePayload, bp_millau::AccountId> for Millau
|
|||||||
fn verify_messages_delivery_proof(
|
fn verify_messages_delivery_proof(
|
||||||
proof: Self::MessagesDeliveryProof,
|
proof: Self::MessagesDeliveryProof,
|
||||||
) -> Result<(LaneId, InboundLaneData<bp_rialto::AccountId>), Self::Error> {
|
) -> 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,
|
proof: Self::MessagesProof,
|
||||||
messages_count: u32,
|
messages_count: u32,
|
||||||
) -> Result<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
|
) -> 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;
|
- all message lanes are identical and may be used to transfer the same messages;
|
||||||
- the messages sent over the bridge are dispatched using
|
- the messages sent over the bridge are dispatched using
|
||||||
[call dispatch module](../../modules/dispatch/README.md);
|
[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
|
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.
|
[messages module](../../modules/messages/README.md) instance at the source chain.
|
||||||
It is pre-encoded by the message submitter;
|
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`.
|
`estimate_message_dispatch_and_delivery_fee`.
|
||||||
|
|
||||||
`FromThisChainMessagePayload` is a message that the sender sends through our bridge. It is the
|
`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.
|
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
|
`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
|
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
|
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
|
`bp_message_dispatch::CallOrigin::SourceRoot` origin. Or he has provided wrong signature
|
||||||
in the `pallet_bridge_dispatch::CallOrigin::TargetAccount` origin;
|
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
|
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.
|
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>;
|
pub type BridgedChainOpaqueCall = Vec<u8>;
|
||||||
|
|
||||||
/// Message payload for This -> Bridged chain messages.
|
/// 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>>,
|
AccountIdOf<ThisChain<B>>,
|
||||||
SignerOf<BridgedChain<B>>,
|
SignerOf<BridgedChain<B>>,
|
||||||
SignatureOf<BridgedChain<B>>,
|
SignatureOf<BridgedChain<B>>,
|
||||||
@@ -352,20 +352,21 @@ pub mod source {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify proof of This -> Bridged chain messages delivery.
|
/// 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>>>,
|
proof: FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChain<B>>>,
|
||||||
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
|
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
|
||||||
where
|
where
|
||||||
ThisRuntime: pallet_bridge_grandpa::Config,
|
ThisRuntime: pallet_bridge_grandpa::Config<GrandpaInstance>,
|
||||||
ThisRuntime: pallet_bridge_messages::Config<MessagesInstanceOf<BridgedChain<B>>>,
|
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 {
|
let FromBridgedChainMessagesDeliveryProof {
|
||||||
bridged_header_hash,
|
bridged_header_hash,
|
||||||
storage_proof,
|
storage_proof,
|
||||||
lane,
|
lane,
|
||||||
} = proof;
|
} = proof;
|
||||||
pallet_bridge_grandpa::Pallet::<ThisRuntime>::parse_finalized_storage_proof(
|
pallet_bridge_grandpa::Pallet::<ThisRuntime, GrandpaInstance>::parse_finalized_storage_proof(
|
||||||
bridged_header_hash.into(),
|
bridged_header_hash.into(),
|
||||||
StorageProof::new(storage_proof),
|
StorageProof::new(storage_proof),
|
||||||
|storage| {
|
|storage| {
|
||||||
@@ -394,14 +395,14 @@ pub mod target {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Call origin for Bridged -> This chain messages.
|
/// 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>>,
|
AccountIdOf<BridgedChain<B>>,
|
||||||
SignerOf<ThisChain<B>>,
|
SignerOf<ThisChain<B>>,
|
||||||
SignatureOf<ThisChain<B>>,
|
SignatureOf<ThisChain<B>>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/// Decoded Bridged -> This message payload.
|
/// Decoded Bridged -> This message payload.
|
||||||
pub type FromBridgedChainMessagePayload<B> = pallet_bridge_dispatch::MessagePayload<
|
pub type FromBridgedChainMessagePayload<B> = bp_message_dispatch::MessagePayload<
|
||||||
AccountIdOf<BridgedChain<B>>,
|
AccountIdOf<BridgedChain<B>>,
|
||||||
SignerOf<ThisChain<B>>,
|
SignerOf<ThisChain<B>>,
|
||||||
SignatureOf<ThisChain<B>>,
|
SignatureOf<ThisChain<B>>,
|
||||||
@@ -504,20 +505,21 @@ pub mod target {
|
|||||||
/// The `messages_count` argument verification (sane limits) is supposed to be made
|
/// 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
|
/// outside of this function. This function only verifies that the proof declares exactly
|
||||||
/// `messages_count` messages.
|
/// `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>>>,
|
proof: FromBridgedChainMessagesProof<HashOf<BridgedChain<B>>>,
|
||||||
messages_count: u32,
|
messages_count: u32,
|
||||||
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
|
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
|
||||||
where
|
where
|
||||||
ThisRuntime: pallet_bridge_grandpa::Config,
|
ThisRuntime: pallet_bridge_grandpa::Config<GrandpaInstance>,
|
||||||
ThisRuntime: pallet_bridge_messages::Config<MessagesInstanceOf<BridgedChain<B>>>,
|
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, _, _>(
|
verify_messages_proof_with_parser::<B, _, _>(
|
||||||
proof,
|
proof,
|
||||||
messages_count,
|
messages_count,
|
||||||
|bridged_header_hash, bridged_storage_proof| {
|
|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(),
|
bridged_header_hash.into(),
|
||||||
StorageProof::new(bridged_storage_proof),
|
StorageProof::new(bridged_storage_proof),
|
||||||
|storage_adapter| storage_adapter,
|
|storage_adapter| storage_adapter,
|
||||||
@@ -929,7 +931,7 @@ mod tests {
|
|||||||
let message_on_bridged_chain = source::FromThisChainMessagePayload::<OnBridgedChainBridge> {
|
let message_on_bridged_chain = source::FromThisChainMessagePayload::<OnBridgedChainBridge> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: 100,
|
weight: 100,
|
||||||
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
origin: bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
call: ThisChainCall::Transfer.encode(),
|
call: ThisChainCall::Transfer.encode(),
|
||||||
}
|
}
|
||||||
.encode();
|
.encode();
|
||||||
@@ -943,7 +945,7 @@ mod tests {
|
|||||||
target::FromBridgedChainMessagePayload::<OnThisChainBridge> {
|
target::FromBridgedChainMessagePayload::<OnThisChainBridge> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: 100,
|
weight: 100,
|
||||||
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
origin: bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
call: target::FromBridgedChainEncodedMessageCall::<OnThisChainBridge> {
|
call: target::FromBridgedChainEncodedMessageCall::<OnThisChainBridge> {
|
||||||
encoded_call: ThisChainCall::Transfer.encode(),
|
encoded_call: ThisChainCall::Transfer.encode(),
|
||||||
_marker: PhantomData::default(),
|
_marker: PhantomData::default(),
|
||||||
@@ -960,7 +962,7 @@ mod tests {
|
|||||||
source::FromThisChainMessagePayload::<OnThisChainBridge> {
|
source::FromThisChainMessagePayload::<OnThisChainBridge> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: 100,
|
weight: 100,
|
||||||
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
origin: bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
call: vec![42],
|
call: vec![42],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1012,7 @@ mod tests {
|
|||||||
let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
|
let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: 100,
|
weight: 100,
|
||||||
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
origin: bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
call: vec![42],
|
call: vec![42],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1053,7 +1055,7 @@ mod tests {
|
|||||||
let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
|
let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: 100,
|
weight: 100,
|
||||||
origin: pallet_bridge_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)),
|
origin: bp_message_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)),
|
||||||
call: vec![42],
|
call: vec![42],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1120,7 +1122,7 @@ mod tests {
|
|||||||
> {
|
> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: 5,
|
weight: 5,
|
||||||
origin: pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
origin: bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
call: vec![1, 2, 3, 4, 5, 6],
|
call: vec![1, 2, 3, 4, 5, 6],
|
||||||
},)
|
},)
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -1135,7 +1137,7 @@ mod tests {
|
|||||||
> {
|
> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT + 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],
|
call: vec![1, 2, 3, 4, 5, 6],
|
||||||
},)
|
},)
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -1150,7 +1152,7 @@ mod tests {
|
|||||||
> {
|
> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
|
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],
|
call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as usize + 1],
|
||||||
},)
|
},)
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -1165,7 +1167,7 @@ mod tests {
|
|||||||
> {
|
> {
|
||||||
spec_version: 1,
|
spec_version: 1,
|
||||||
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
|
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 _],
|
call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as _],
|
||||||
},),
|
},),
|
||||||
Ok(()),
|
Ok(()),
|
||||||
@@ -1407,6 +1409,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn transaction_payment_works_with_zero_multiplier() {
|
fn transaction_payment_works_with_zero_multiplier() {
|
||||||
|
use sp_runtime::traits::Zero;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
transaction_payment(
|
transaction_payment(
|
||||||
100,
|
100,
|
||||||
@@ -1424,6 +1428,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn transaction_payment_works_with_non_zero_multiplier() {
|
fn transaction_payment_works_with_non_zero_multiplier() {
|
||||||
|
use sp_runtime::traits::One;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
transaction_payment(
|
transaction_payment(
|
||||||
100,
|
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 \
|
|
||||||
@@ -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
|
sign: `(Call, SourceChainAccountId).encode()`. This will be included in the message payload and
|
||||||
verified by the target chain before dispatch.
|
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
|
#### Message Relayers Strategy
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ decl_error! {
|
|||||||
InvalidRecipient,
|
InvalidRecipient,
|
||||||
/// Cannot map from peer recipient to this blockchain recipient.
|
/// Cannot map from peer recipient to this blockchain recipient.
|
||||||
FailedToMapRecipients,
|
FailedToMapRecipients,
|
||||||
/// Failed to convert from peer blockchain currency to this blockhain currency.
|
/// Failed to convert from peer blockchain currency to this blockchain currency.
|
||||||
FailedToConvertCurrency,
|
FailedToConvertCurrency,
|
||||||
/// Deposit has failed.
|
/// Deposit has failed.
|
||||||
DepositFailed,
|
DepositFailed,
|
||||||
|
|||||||
@@ -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
|
- `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
|
[messages module](../messages/README.md), it may worth to use a tuple
|
||||||
`(LaneId, MessageNonce)` to identify a message;
|
`(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.
|
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
|
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
|
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;
|
try to decode `Call` from other runtime version;
|
||||||
- `MessageSignatureMismatch` event is emitted if submitter has chose to dispatch message using
|
- `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;
|
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
|
- `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
|
this filter has rejected the `Call`. In your bridge you may choose to reject all messages except
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use bp_message_dispatch::{MessageDispatch, Weight};
|
use bp_message_dispatch::{CallOrigin, MessageDispatch, MessagePayload, SpecVersion, Weight};
|
||||||
use bp_runtime::{derive_account_id, InstanceId, Size, SourceAccount};
|
use bp_runtime::{derive_account_id, InstanceId, SourceAccount};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_event, decl_module, decl_storage,
|
decl_event, decl_module, decl_storage,
|
||||||
@@ -33,7 +33,6 @@ use frame_support::{
|
|||||||
ensure,
|
ensure,
|
||||||
traits::{Filter, Get},
|
traits::{Filter, Get},
|
||||||
weights::{extract_actual_weight, GetDispatchInfo},
|
weights::{extract_actual_weight, GetDispatchInfo},
|
||||||
RuntimeDebug,
|
|
||||||
};
|
};
|
||||||
use frame_system::RawOrigin;
|
use frame_system::RawOrigin;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
@@ -42,78 +41,6 @@ use sp_runtime::{
|
|||||||
};
|
};
|
||||||
use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};
|
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.
|
/// The module configuration trait.
|
||||||
pub trait Config<I = DefaultInstance>: frame_system::Config {
|
pub trait Config<I = DefaultInstance>: frame_system::Config {
|
||||||
/// The overarching event type.
|
/// The overarching event type.
|
||||||
@@ -314,8 +241,7 @@ impl<T: Config<I>, I: Instance> MessageDispatch<T::MessageId> for Pallet<T, I> {
|
|||||||
|
|
||||||
// finally dispatch message
|
// finally dispatch message
|
||||||
let origin = RawOrigin::Signed(origin_account).into();
|
let origin = RawOrigin::Signed(origin_account).into();
|
||||||
|
log::trace!(target: "runtime::bridge-dispatch", "Message being dispatched is: {:.4096?}", &call);
|
||||||
log::trace!(target: "runtime::bridge-dispatch", "Message being dispatched is: {:?}", &call);
|
|
||||||
let dispatch_result = call.dispatch(origin);
|
let dispatch_result = call.dispatch(origin);
|
||||||
let actual_call_weight = extract_actual_weight(&dispatch_result, &dispatch_info);
|
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,
|
TEST_GRANDPA_ROUND, TEST_GRANDPA_SET_ID,
|
||||||
};
|
};
|
||||||
use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller};
|
use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller};
|
||||||
|
use frame_support::traits::Get;
|
||||||
use frame_system::RawOrigin;
|
use frame_system::RawOrigin;
|
||||||
use sp_finality_grandpa::AuthorityId;
|
use sp_finality_grandpa::AuthorityId;
|
||||||
use sp_runtime::traits::{One, Zero};
|
use sp_runtime::traits::Zero;
|
||||||
use sp_std::{vec, vec::Vec};
|
use sp_std::{vec, vec::Vec};
|
||||||
|
|
||||||
// The maximum number of vote ancestries to include in a justification.
|
// The maximum number of vote ancestries to include in a justification.
|
||||||
@@ -66,6 +67,14 @@ const MAX_VOTE_ANCESTRIES: u32 = 1000;
|
|||||||
// number of validators.
|
// number of validators.
|
||||||
const MAX_VALIDATOR_SET_SIZE: u32 = 1024;
|
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! {
|
benchmarks_instance_pallet! {
|
||||||
// This is the "gold standard" benchmark for this extrinsic, and it's what should be used to
|
// This is the "gold standard" benchmark for this extrinsic, and it's what should be used to
|
||||||
// annotate the weight in the pallet.
|
// annotate the weight in the pallet.
|
||||||
@@ -90,9 +99,9 @@ benchmarks_instance_pallet! {
|
|||||||
is_halted: false,
|
is_halted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
initialize_bridge::<T, I>(init_data);
|
bootstrap_bridge::<T, I>(init_data);
|
||||||
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 params = JustificationGeneratorParams {
|
let params = JustificationGeneratorParams {
|
||||||
header: header.clone(),
|
header: header.clone(),
|
||||||
round: TEST_GRANDPA_ROUND,
|
round: TEST_GRANDPA_ROUND,
|
||||||
@@ -106,7 +115,7 @@ benchmarks_instance_pallet! {
|
|||||||
|
|
||||||
}: _(RawOrigin::Signed(caller), header, justification)
|
}: _(RawOrigin::Signed(caller), header, justification)
|
||||||
verify {
|
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();
|
let expected_hash = header.hash();
|
||||||
|
|
||||||
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
|
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
|
||||||
@@ -127,8 +136,8 @@ benchmarks_instance_pallet! {
|
|||||||
is_halted: false,
|
is_halted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
initialize_bridge::<T, I>(init_data);
|
bootstrap_bridge::<T, I>(init_data);
|
||||||
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 params = JustificationGeneratorParams {
|
let params = JustificationGeneratorParams {
|
||||||
header: header.clone(),
|
header: header.clone(),
|
||||||
@@ -143,7 +152,7 @@ benchmarks_instance_pallet! {
|
|||||||
|
|
||||||
}: submit_finality_proof(RawOrigin::Signed(caller), header, justification)
|
}: submit_finality_proof(RawOrigin::Signed(caller), header, justification)
|
||||||
verify {
|
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();
|
let expected_hash = header.hash();
|
||||||
|
|
||||||
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
|
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
|
||||||
@@ -170,8 +179,8 @@ benchmarks_instance_pallet! {
|
|||||||
is_halted: false,
|
is_halted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
initialize_bridge::<T, I>(init_data);
|
bootstrap_bridge::<T, I>(init_data);
|
||||||
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 params = JustificationGeneratorParams {
|
let params = JustificationGeneratorParams {
|
||||||
header: header.clone(),
|
header: header.clone(),
|
||||||
@@ -186,7 +195,7 @@ benchmarks_instance_pallet! {
|
|||||||
|
|
||||||
}: submit_finality_proof(RawOrigin::Signed(caller), header, justification)
|
}: submit_finality_proof(RawOrigin::Signed(caller), header, justification)
|
||||||
verify {
|
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();
|
let expected_hash = header.hash();
|
||||||
|
|
||||||
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
|
assert_eq!(<BestFinalized<T, I>>::get(), expected_hash);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ use bp_header_chain::justification::GrandpaJustification;
|
|||||||
use bp_header_chain::InitializationData;
|
use bp_header_chain::InitializationData;
|
||||||
use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf};
|
use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf};
|
||||||
use finality_grandpa::voter_set::VoterSet;
|
use finality_grandpa::voter_set::VoterSet;
|
||||||
use frame_support::ensure;
|
use frame_support::{ensure, fail};
|
||||||
use frame_system::{ensure_signed, RawOrigin};
|
use frame_system::{ensure_signed, RawOrigin};
|
||||||
use sp_finality_grandpa::{ConsensusLog, GRANDPA_ENGINE_ID};
|
use sp_finality_grandpa::{ConsensusLog, GRANDPA_ENGINE_ID};
|
||||||
use sp_runtime::traits::{BadOrigin, Header as HeaderT, Zero};
|
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());
|
let (hash, number) = (finality_target.hash(), finality_target.number());
|
||||||
log::trace!(target: "runtime::bridge-grandpa", "Going to try and finalize header {:?}", finality_target);
|
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(
|
let best_finalized = match <ImportedHeaders<T, I>>::get(<BestFinalized<T, I>>::get()) {
|
||||||
"In order to reach this point the bridge must have been initialized. Afterwards,
|
Some(best_finalized) => best_finalized,
|
||||||
every time `BestFinalized` is updated `ImportedHeaders` is also updated. Therefore
|
None => {
|
||||||
`ImportedHeaders` must contain an entry for `BestFinalized`.",
|
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
|
// We do a quick check here to ensure that our header chain is making progress and isn't
|
||||||
// "travelling back in time" (which could be indicative of something bad, e.g a hard-fork).
|
// "travelling back in time" (which could be indicative of something bad, e.g a hard-fork).
|
||||||
@@ -158,20 +164,8 @@ pub mod pallet {
|
|||||||
verify_justification::<T, I>(&justification, hash, *number, authority_set)?;
|
verify_justification::<T, I>(&justification, hash, *number, authority_set)?;
|
||||||
|
|
||||||
let _enacted = try_enact_authority_change::<T, I>(&finality_target, set_id)?;
|
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);
|
<RequestCount<T, I>>::mutate(|count| *count += 1);
|
||||||
|
insert_header::<T, I>(finality_target, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash);
|
log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash);
|
||||||
|
|
||||||
Ok(().into())
|
Ok(().into())
|
||||||
@@ -346,6 +340,8 @@ pub mod pallet {
|
|||||||
///
|
///
|
||||||
/// This is the case for non-standard (e.g forced) authority set changes.
|
/// This is the case for non-standard (e.g forced) authority set changes.
|
||||||
UnsupportedScheduledChange,
|
UnsupportedScheduledChange,
|
||||||
|
/// The pallet is not yet initialized.
|
||||||
|
NotInitialized,
|
||||||
/// The pallet has already been initialized.
|
/// The pallet has already been initialized.
|
||||||
AlreadyInitialized,
|
AlreadyInitialized,
|
||||||
/// All pallet operations are halted.
|
/// 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
|
/// Since this writes to storage with no real checks this should only be used in functions that
|
||||||
/// were called by a trusted origin.
|
/// were called by a trusted origin.
|
||||||
pub(crate) fn initialize_bridge<T: Config<I>, I: 'static>(
|
pub(crate) fn initialize_bridge<T: Config<I>, I: 'static>(
|
||||||
@@ -441,8 +456,8 @@ pub mod pallet {
|
|||||||
|
|
||||||
let initial_hash = header.hash();
|
let initial_hash = header.hash();
|
||||||
<InitialHash<T, I>>::put(initial_hash);
|
<InitialHash<T, I>>::put(initial_hash);
|
||||||
<BestFinalized<T, I>>::put(initial_hash);
|
<ImportedHashesPointer<T, I>>::put(0);
|
||||||
<ImportedHeaders<T, I>>::insert(initial_hash, header);
|
insert_header::<T, I>(header, initial_hash);
|
||||||
|
|
||||||
let authority_set = bp_header_chain::AuthoritySet::new(authority_list, set_id);
|
let authority_set = bp_header_chain::AuthoritySet::new(authority_list, set_id);
|
||||||
<CurrentAuthoritySet<T, I>>::put(authority_set);
|
<CurrentAuthoritySet<T, I>>::put(authority_set);
|
||||||
@@ -450,6 +465,29 @@ pub mod pallet {
|
|||||||
<IsHalted<T, I>>::put(is_halted);
|
<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`.
|
/// Ensure that the origin is either root, or `PalletOwner`.
|
||||||
fn ensure_owner_or_root<T: Config<I>, I: 'static>(origin: T::Origin) -> Result<(), BadOrigin> {
|
fn ensure_owner_or_root<T: Config<I>, I: 'static>(origin: T::Origin) -> Result<(), BadOrigin> {
|
||||||
match origin.into() {
|
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]
|
#[test]
|
||||||
fn succesfully_imports_header_with_valid_finality() {
|
fn succesfully_imports_header_with_valid_finality() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
//! Autogenerated weights for pallet_bridge_grandpa
|
//! Autogenerated weights for pallet_bridge_grandpa
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
|
//! 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: []
|
//! LOW RANGE: [], HIGH RANGE: []
|
||||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
||||||
//! CHAIN: Some("dev"), DB CACHE: 128
|
//! 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> {
|
impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
|
||||||
fn submit_finality_proof(v: u32, p: u32) -> Weight {
|
fn submit_finality_proof(v: u32, p: u32) -> Weight {
|
||||||
(0 as Weight)
|
(0 as Weight)
|
||||||
.saturating_add((837_084_000 as Weight).saturating_mul(v as Weight))
|
.saturating_add((756_462_000 as Weight).saturating_mul(v as Weight))
|
||||||
.saturating_add((874_929_000 as Weight).saturating_mul(p 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().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 {
|
fn submit_finality_proof_on_single_fork(v: u32) -> Weight {
|
||||||
(276_463_000 as Weight)
|
(280_121_000 as Weight)
|
||||||
.saturating_add((14_149_000 as Weight).saturating_mul(v 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().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 {
|
fn submit_finality_proof_on_many_forks(p: u32) -> Weight {
|
||||||
(10_676_019_000 as Weight)
|
(10_370_940_000 as Weight)
|
||||||
.saturating_add((97_598_000 as Weight).saturating_mul(p 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().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 {
|
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 {
|
fn read_write_authority_sets(n: u32) -> Weight {
|
||||||
(8_582_000 as Weight)
|
(8_030_000 as Weight)
|
||||||
.saturating_add((234_000 as Weight).saturating_mul(n 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().reads(1 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(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 () {
|
impl WeightInfo for () {
|
||||||
fn submit_finality_proof(v: u32, p: u32) -> Weight {
|
fn submit_finality_proof(v: u32, p: u32) -> Weight {
|
||||||
(0 as Weight)
|
(0 as Weight)
|
||||||
.saturating_add((837_084_000 as Weight).saturating_mul(v as Weight))
|
.saturating_add((756_462_000 as Weight).saturating_mul(v as Weight))
|
||||||
.saturating_add((874_929_000 as Weight).saturating_mul(p 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().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 {
|
fn submit_finality_proof_on_single_fork(v: u32) -> Weight {
|
||||||
(276_463_000 as Weight)
|
(280_121_000 as Weight)
|
||||||
.saturating_add((14_149_000 as Weight).saturating_mul(v 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().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 {
|
fn submit_finality_proof_on_many_forks(p: u32) -> Weight {
|
||||||
(10_676_019_000 as Weight)
|
(10_370_940_000 as Weight)
|
||||||
.saturating_add((97_598_000 as Weight).saturating_mul(p 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().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 {
|
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 {
|
fn read_write_authority_sets(n: u32) -> Weight {
|
||||||
(8_582_000 as Weight)
|
(8_030_000 as Weight)
|
||||||
.saturating_add((234_000 as Weight).saturating_mul(n 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().reads(1 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
//! Autogenerated weights for pallet_bridge_messages
|
//! Autogenerated weights for pallet_bridge_messages
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
|
//! 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: []
|
//! LOW RANGE: [], HIGH RANGE: []
|
||||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
|
||||||
//! CHAIN: Some("dev"), DB CACHE: 128
|
//! CHAIN: Some("dev"), DB CACHE: 128
|
||||||
@@ -73,105 +73,105 @@ pub trait WeightInfo {
|
|||||||
pub struct RialtoWeight<T>(PhantomData<T>);
|
pub struct RialtoWeight<T>(PhantomData<T>);
|
||||||
impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
|
impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
|
||||||
fn send_minimal_message_worst_case() -> Weight {
|
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().reads(5 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn send_1_kb_message_worst_case() -> 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().reads(5 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn send_16_kb_message_worst_case() -> 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().reads(5 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn increase_message_fee() -> 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().reads(4 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_two_messages_proof() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof_with_outbound_lane_state() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof_1_kb() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof_16_kb() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_single_message() -> 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().reads(6 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_two_messages_by_single_relayer() -> 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().reads(7 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_two_messages_by_two_relayers() -> 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().reads(8 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(4 as Weight))
|
.saturating_add(T::DbWeight::get().writes(4 as Weight))
|
||||||
}
|
}
|
||||||
fn send_messages_of_various_lengths(i: u32) -> 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((3_000 as Weight).saturating_mul(i as Weight))
|
||||||
.saturating_add(T::DbWeight::get().reads(5 as Weight))
|
.saturating_add(T::DbWeight::get().reads(5 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_multiple_messages_proof(i: u32) -> Weight {
|
fn receive_multiple_messages_proof(i: u32) -> Weight {
|
||||||
(0 as 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_message_proofs_with_extra_nodes(i: u32) -> Weight {
|
fn receive_message_proofs_with_extra_nodes(i: u32) -> Weight {
|
||||||
(458_731_000 as Weight)
|
(437_797_000 as Weight)
|
||||||
.saturating_add((9_000 as Weight).saturating_mul(i 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_message_proofs_with_large_leaf(i: u32) -> 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((7_000 as Weight).saturating_mul(i as Weight))
|
||||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_multiple_messages_proof_with_outbound_lane_state(i: u32) -> Weight {
|
fn receive_multiple_messages_proof_with_outbound_lane_state(i: u32) -> Weight {
|
||||||
(16_766_000 as Weight)
|
(0 as Weight)
|
||||||
.saturating_add((115_533_000 as Weight).saturating_mul(i 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().reads(3 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_multiple_messages_by_single_relayer(i: u32) -> Weight {
|
fn receive_delivery_proof_for_multiple_messages_by_single_relayer(i: u32) -> Weight {
|
||||||
(122_146_000 as Weight)
|
(116_036_000 as Weight)
|
||||||
.saturating_add((6_789_000 as Weight).saturating_mul(i 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(5 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i 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))
|
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_multiple_messages_by_multiple_relayers(i: u32) -> Weight {
|
fn receive_delivery_proof_for_multiple_messages_by_multiple_relayers(i: u32) -> Weight {
|
||||||
(155_671_000 as Weight)
|
(172_780_000 as Weight)
|
||||||
.saturating_add((63_020_000 as Weight).saturating_mul(i 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(5 as Weight))
|
||||||
.saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(i 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))
|
.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
|
// For backwards compatibility and tests
|
||||||
impl WeightInfo for () {
|
impl WeightInfo for () {
|
||||||
fn send_minimal_message_worst_case() -> Weight {
|
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().reads(5 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn send_1_kb_message_worst_case() -> 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().reads(5 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn send_16_kb_message_worst_case() -> 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().reads(5 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn increase_message_fee() -> 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().reads(4 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_two_messages_proof() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof_with_outbound_lane_state() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof_1_kb() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_single_message_proof_16_kb() -> 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_single_message() -> 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().reads(6 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_two_messages_by_single_relayer() -> 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().reads(7 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_two_messages_by_two_relayers() -> 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().reads(8 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
|
||||||
}
|
}
|
||||||
fn send_messages_of_various_lengths(i: u32) -> 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((3_000 as Weight).saturating_mul(i as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
|
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_multiple_messages_proof(i: u32) -> Weight {
|
fn receive_multiple_messages_proof(i: u32) -> Weight {
|
||||||
(0 as 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_message_proofs_with_extra_nodes(i: u32) -> Weight {
|
fn receive_message_proofs_with_extra_nodes(i: u32) -> Weight {
|
||||||
(458_731_000 as Weight)
|
(437_797_000 as Weight)
|
||||||
.saturating_add((9_000 as Weight).saturating_mul(i 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_message_proofs_with_large_leaf(i: u32) -> 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((7_000 as Weight).saturating_mul(i as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_multiple_messages_proof_with_outbound_lane_state(i: u32) -> Weight {
|
fn receive_multiple_messages_proof_with_outbound_lane_state(i: u32) -> Weight {
|
||||||
(16_766_000 as Weight)
|
(0 as Weight)
|
||||||
.saturating_add((115_533_000 as Weight).saturating_mul(i 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().reads(3 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_multiple_messages_by_single_relayer(i: u32) -> Weight {
|
fn receive_delivery_proof_for_multiple_messages_by_single_relayer(i: u32) -> Weight {
|
||||||
(122_146_000 as Weight)
|
(116_036_000 as Weight)
|
||||||
.saturating_add((6_789_000 as Weight).saturating_mul(i 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(5 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
|
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||||
}
|
}
|
||||||
fn receive_delivery_proof_for_multiple_messages_by_multiple_relayers(i: u32) -> Weight {
|
fn receive_delivery_proof_for_multiple_messages_by_multiple_relayers(i: u32) -> Weight {
|
||||||
(155_671_000 as Weight)
|
(172_780_000 as Weight)
|
||||||
.saturating_add((63_020_000 as Weight).saturating_mul(i 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(5 as Weight))
|
||||||
.saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
|
.saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(i as Weight)))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3 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";
|
pub const FROM_MILLAU_UNREWARDED_RELAYERS_STATE: &str = "FromMillauInboundLaneApi_unrewarded_relayers_state";
|
||||||
|
|
||||||
sp_api::decl_runtime_apis! {
|
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.
|
/// API for querying information about the finalized Millau headers.
|
||||||
///
|
///
|
||||||
/// This API is implemented by runtimes that are bridging with the Millau chain, not the
|
/// 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";
|
pub const FROM_RIALTO_UNREWARDED_RELAYERS_STATE: &str = "FromRialtoInboundLaneApi_unrewarded_relayers_state";
|
||||||
|
|
||||||
sp_api::decl_runtime_apis! {
|
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.
|
/// API for querying information about the finalized Rialto headers.
|
||||||
///
|
///
|
||||||
/// This API is implemented by runtimes that are bridging with the Rialto chain, not the
|
/// 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"),
|
spec_name: sp_version::create_runtime_str!("rococo"),
|
||||||
impl_name: sp_version::create_runtime_str!("parity-rococo-v1.5"),
|
impl_name: sp_version::create_runtime_str!("parity-rococo-v1.5"),
|
||||||
authoring_version: 0,
|
authoring_version: 0,
|
||||||
spec_version: 231,
|
spec_version: 232,
|
||||||
impl_version: 0,
|
impl_version: 0,
|
||||||
apis: sp_version::create_apis_vec![[]],
|
apis: sp_version::create_apis_vec![[]],
|
||||||
transaction_version: 0,
|
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
|
/// 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)]
|
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Call {
|
pub enum Call {
|
||||||
/// Westend bridge pallet.
|
/// Wococo bridge pallet.
|
||||||
#[codec(index = 40)]
|
#[codec(index = 41)]
|
||||||
BridgeGrandpaWestend(BridgeGrandpaWestendCall),
|
BridgeGrandpaWococo(BridgeGrandpaWococoCall),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)]
|
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum BridgeGrandpaWestendCall {
|
pub enum BridgeGrandpaWococoCall {
|
||||||
#[codec(index = 0)]
|
#[codec(index = 0)]
|
||||||
submit_finality_proof(
|
submit_finality_proof(
|
||||||
<PolkadotLike as Chain>::Header,
|
<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.
|
/// Name of the `RococoFinalityApi::best_finalized` runtime method.
|
||||||
pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized";
|
pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized";
|
||||||
/// Name of the `RococoFinalityApi::is_known_header` runtime method.
|
/// 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 }
|
bp-runtime = { path = "../runtime", default-features = false }
|
||||||
codec = { package = "parity-scale-codec", version = "2.0.0", 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]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
"bp-runtime/std",
|
"bp-runtime/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
|
"frame-support/std",
|
||||||
|
"sp-std/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -19,11 +19,17 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![warn(missing_docs)]
|
#![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.
|
/// Message dispatch weight.
|
||||||
pub type Weight = u64;
|
pub type Weight = u64;
|
||||||
|
|
||||||
|
/// Spec version type.
|
||||||
|
pub type SpecVersion = u32;
|
||||||
|
|
||||||
/// A generic trait to dispatch arbitrary messages delivered over the bridge.
|
/// A generic trait to dispatch arbitrary messages delivered over the bridge.
|
||||||
pub trait MessageDispatch<MessageId> {
|
pub trait MessageDispatch<MessageId> {
|
||||||
/// A type of the message to be dispatched.
|
/// A type of the message to be dispatched.
|
||||||
@@ -47,3 +53,70 @@ pub trait MessageDispatch<MessageId> {
|
|||||||
/// the whole message).
|
/// the whole message).
|
||||||
fn dispatch(bridge: InstanceId, id: MessageId, message: Result<Self::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.
|
/// Bridge-with-Rococo instance id.
|
||||||
pub const ROCOCO_BRIDGE_INSTANCE: InstanceId = *b"roco";
|
pub const ROCOCO_BRIDGE_INSTANCE: InstanceId = *b"roco";
|
||||||
|
|
||||||
/// Bridge-with-Westend instance id.
|
/// Bridge-with-Wococo instance id.
|
||||||
pub const WESTEND_BRIDGE_INSTANCE: InstanceId = *b"wend";
|
pub const WOCOCO_BRIDGE_INSTANCE: InstanceId = *b"woco";
|
||||||
|
|
||||||
/// Call-dispatch module prefix.
|
/// Call-dispatch module prefix.
|
||||||
pub const CALL_DISPATCH_MODULE_PREFIX: &[u8] = b"pallet-bridge/dispatch";
|
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-header-chain = { path = "../../primitives/header-chain" }
|
||||||
bp-kusama = { path = "../../primitives/chain-kusama" }
|
bp-kusama = { path = "../../primitives/chain-kusama" }
|
||||||
bp-messages = { path = "../../primitives/messages" }
|
bp-messages = { path = "../../primitives/messages" }
|
||||||
|
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
|
||||||
bp-millau = { path = "../../primitives/chain-millau" }
|
bp-millau = { path = "../../primitives/chain-millau" }
|
||||||
bp-polkadot = { path = "../../primitives/chain-polkadot" }
|
bp-polkadot = { path = "../../primitives/chain-polkadot" }
|
||||||
bp-rialto = { path = "../../primitives/chain-rialto" }
|
bp-rialto = { path = "../../primitives/chain-rialto" }
|
||||||
bp-rococo = { path = "../../primitives/chain-rococo" }
|
bp-rococo = { path = "../../primitives/chain-rococo" }
|
||||||
|
bp-wococo = { path = "../../primitives/chain-wococo" }
|
||||||
bp-runtime = { path = "../../primitives/runtime" }
|
bp-runtime = { path = "../../primitives/runtime" }
|
||||||
bp-westend = { path = "../../primitives/chain-westend" }
|
bp-westend = { path = "../../primitives/chain-westend" }
|
||||||
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
||||||
@@ -35,13 +37,13 @@ finality-relay = { path = "../finality" }
|
|||||||
headers-relay = { path = "../headers" }
|
headers-relay = { path = "../headers" }
|
||||||
messages-relay = { path = "../messages" }
|
messages-relay = { path = "../messages" }
|
||||||
millau-runtime = { path = "../../bin/millau/runtime" }
|
millau-runtime = { path = "../../bin/millau/runtime" }
|
||||||
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
|
|
||||||
pallet-bridge-messages = { path = "../../modules/messages" }
|
pallet-bridge-messages = { path = "../../modules/messages" }
|
||||||
relay-kusama-client = { path = "../client-kusama" }
|
relay-kusama-client = { path = "../client-kusama" }
|
||||||
relay-millau-client = { path = "../client-millau" }
|
relay-millau-client = { path = "../client-millau" }
|
||||||
relay-polkadot-client = { path = "../client-polkadot" }
|
relay-polkadot-client = { path = "../client-polkadot" }
|
||||||
relay-rialto-client = { path = "../client-rialto" }
|
relay-rialto-client = { path = "../client-rialto" }
|
||||||
relay-rococo-client = { path = "../client-rococo" }
|
relay-rococo-client = { path = "../client-rococo" }
|
||||||
|
relay-wococo-client = { path = "../client-wococo" }
|
||||||
relay-substrate-client = { path = "../client-substrate" }
|
relay-substrate-client = { path = "../client-substrate" }
|
||||||
relay-utils = { path = "../utils" }
|
relay-utils = { path = "../utils" }
|
||||||
relay-westend-client = { path = "../client-westend" }
|
relay-westend-client = { path = "../client-westend" }
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ use crate::cli::{
|
|||||||
encode_call::{self, Call, CliEncodeCall},
|
encode_call::{self, Call, CliEncodeCall},
|
||||||
encode_message, send_message, CliChain,
|
encode_message, send_message, CliChain,
|
||||||
};
|
};
|
||||||
|
use bp_message_dispatch::{CallOrigin, MessagePayload};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use frame_support::weights::{GetDispatchInfo, Weight};
|
use frame_support::weights::{GetDispatchInfo, Weight};
|
||||||
use pallet_bridge_dispatch::{CallOrigin, MessagePayload};
|
|
||||||
use relay_millau_client::Millau;
|
use relay_millau_client::Millau;
|
||||||
use sp_version::RuntimeVersion;
|
use sp_version::RuntimeVersion;
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,15 @@ pub mod millau_headers_to_rialto;
|
|||||||
pub mod millau_messages_to_rialto;
|
pub mod millau_messages_to_rialto;
|
||||||
pub mod rialto_headers_to_millau;
|
pub mod rialto_headers_to_millau;
|
||||||
pub mod rialto_messages_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_millau;
|
||||||
pub mod westend_headers_to_rococo;
|
pub mod wococo_headers_to_rococo;
|
||||||
|
|
||||||
mod millau;
|
mod millau;
|
||||||
mod rialto;
|
mod rialto;
|
||||||
mod rococo;
|
mod rococo;
|
||||||
mod westend;
|
mod westend;
|
||||||
|
mod wococo;
|
||||||
|
|
||||||
use relay_utils::metrics::{FloatJsonValueMetric, MetricsParams};
|
use relay_utils::metrics::{FloatJsonValueMetric, MetricsParams};
|
||||||
|
|
||||||
@@ -131,7 +132,7 @@ mod tests {
|
|||||||
let payload = send_message::message_payload(
|
let payload = send_message::message_payload(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
call.get_dispatch_info().weight,
|
call.get_dispatch_info().weight,
|
||||||
pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
&call,
|
&call,
|
||||||
);
|
);
|
||||||
assert_eq!(Millau::verify_message(&payload), Ok(()));
|
assert_eq!(Millau::verify_message(&payload), Ok(()));
|
||||||
@@ -141,7 +142,7 @@ mod tests {
|
|||||||
let payload = send_message::message_payload(
|
let payload = send_message::message_payload(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
call.get_dispatch_info().weight,
|
call.get_dispatch_info().weight,
|
||||||
pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
&call,
|
&call,
|
||||||
);
|
);
|
||||||
assert!(Millau::verify_message(&payload).is_err());
|
assert!(Millau::verify_message(&payload).is_err());
|
||||||
@@ -168,7 +169,7 @@ mod tests {
|
|||||||
let payload = send_message::message_payload(
|
let payload = send_message::message_payload(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
maximal_dispatch_weight,
|
maximal_dispatch_weight,
|
||||||
pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
&call,
|
&call,
|
||||||
);
|
);
|
||||||
assert_eq!(Millau::verify_message(&payload), Ok(()));
|
assert_eq!(Millau::verify_message(&payload), Ok(()));
|
||||||
@@ -176,7 +177,7 @@ mod tests {
|
|||||||
let payload = send_message::message_payload(
|
let payload = send_message::message_payload(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
maximal_dispatch_weight + 1,
|
maximal_dispatch_weight + 1,
|
||||||
pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
&call,
|
&call,
|
||||||
);
|
);
|
||||||
assert!(Millau::verify_message(&payload).is_err());
|
assert!(Millau::verify_message(&payload).is_err());
|
||||||
@@ -193,7 +194,7 @@ mod tests {
|
|||||||
let payload = send_message::message_payload(
|
let payload = send_message::message_payload(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
maximal_dispatch_weight,
|
maximal_dispatch_weight,
|
||||||
pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
&call,
|
&call,
|
||||||
);
|
);
|
||||||
assert_eq!(Rialto::verify_message(&payload), Ok(()));
|
assert_eq!(Rialto::verify_message(&payload), Ok(()));
|
||||||
@@ -201,7 +202,7 @@ mod tests {
|
|||||||
let payload = send_message::message_payload(
|
let payload = send_message::message_payload(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
maximal_dispatch_weight + 1,
|
maximal_dispatch_weight + 1,
|
||||||
pallet_bridge_dispatch::CallOrigin::SourceRoot,
|
bp_message_dispatch::CallOrigin::SourceRoot,
|
||||||
&call,
|
&call,
|
||||||
);
|
);
|
||||||
assert!(Rialto::verify_message(&payload).is_err());
|
assert!(Rialto::verify_message(&payload).is_err());
|
||||||
@@ -270,7 +271,7 @@ mod rococo_tests {
|
|||||||
votes_ancestries: vec![],
|
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(
|
let expected = millau_runtime::BridgeGrandpaRialtoCall::<millau_runtime::Runtime>::submit_finality_proof(
|
||||||
header,
|
header,
|
||||||
justification,
|
justification,
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ use crate::cli::{
|
|||||||
encode_call::{self, Call, CliEncodeCall},
|
encode_call::{self, Call, CliEncodeCall},
|
||||||
encode_message, send_message, CliChain,
|
encode_message, send_message, CliChain,
|
||||||
};
|
};
|
||||||
|
use bp_message_dispatch::{CallOrigin, MessagePayload};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use frame_support::weights::{GetDispatchInfo, Weight};
|
use frame_support::weights::{GetDispatchInfo, Weight};
|
||||||
use pallet_bridge_dispatch::{CallOrigin, MessagePayload};
|
|
||||||
use relay_rialto_client::Rialto;
|
use relay_rialto_client::Rialto;
|
||||||
use sp_version::RuntimeVersion;
|
use sp_version::RuntimeVersion;
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Rococo-to-Westend headers sync entrypoint.
|
//! Rococo-to-Wococo headers sync entrypoint.
|
||||||
|
|
||||||
use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||||
|
|
||||||
@@ -23,37 +23,37 @@ use codec::Encode;
|
|||||||
use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader};
|
use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader};
|
||||||
use relay_substrate_client::{Chain, TransactionSignScheme};
|
use relay_substrate_client::{Chain, TransactionSignScheme};
|
||||||
use relay_utils::metrics::MetricsParams;
|
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};
|
use sp_core::{Bytes, Pair};
|
||||||
|
|
||||||
/// Rococo-to-Westend finality sync pipeline.
|
/// Rococo-to-Wococo finality sync pipeline.
|
||||||
pub(crate) type RococoFinalityToWestend = SubstrateFinalityToSubstrate<Rococo, Westend, WestendSigningParams>;
|
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;
|
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> {
|
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> {
|
||||||
crate::chains::add_polkadot_kusama_price_metrics::<Self>(params)
|
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()
|
(*self.target_sign.public().as_array_ref()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_submit_finality_proof_transaction(
|
fn make_submit_finality_proof_transaction(
|
||||||
&self,
|
&self,
|
||||||
transaction_nonce: <Westend as Chain>::Index,
|
transaction_nonce: <Wococo as Chain>::Index,
|
||||||
header: RococoSyncHeader,
|
header: RococoSyncHeader,
|
||||||
proof: GrandpaJustification<bp_rococo::Header>,
|
proof: GrandpaJustification<bp_rococo::Header>,
|
||||||
) -> Bytes {
|
) -> 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(),
|
header.into_inner(),
|
||||||
proof,
|
proof,
|
||||||
));
|
));
|
||||||
let genesis_hash = *self.target_client.genesis_hash();
|
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())
|
Bytes(transaction.encode())
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToRococo {
|
|||||||
header: WestendSyncHeader,
|
header: WestendSyncHeader,
|
||||||
proof: GrandpaJustification<bp_westend::Header>,
|
proof: GrandpaJustification<bp_westend::Header>,
|
||||||
) -> Bytes {
|
) -> 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(),
|
header.into_inner(),
|
||||||
proof,
|
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
|
// Derive-account
|
||||||
#[allow(unused_imports)]
|
#[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
|
// Relay-messages
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@@ -75,7 +75,7 @@ macro_rules! select_full_bridge {
|
|||||||
|
|
||||||
// Derive-account
|
// Derive-account
|
||||||
#[allow(unused_imports)]
|
#[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
|
// Relay-messages
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
|
|||||||
@@ -91,11 +91,11 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", rialto_derived),
|
format!("{}", rialto_derived),
|
||||||
"73gLnUwrAdH4vMjbXCiNEpgyz1PLk9JxCaY4cKzvfSZT73KE"
|
"74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", millau_derived),
|
format!("{}", millau_derived),
|
||||||
"5rpTJqGv1BPAYy2sXzkPpc3Wx1ZpQtgfuBsrDpNV4HsXAmbi"
|
"5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2"
|
||||||
);
|
);
|
||||||
assert_eq!(millau_derived, millau2_derived);
|
assert_eq!(millau_derived, millau2_derived);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ arg_enum! {
|
|||||||
MillauToRialto,
|
MillauToRialto,
|
||||||
RialtoToMillau,
|
RialtoToMillau,
|
||||||
WestendToMillau,
|
WestendToMillau,
|
||||||
WestendToRococo,
|
RococoToWococo,
|
||||||
RococoToWestend,
|
WococoToRococo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,26 +102,26 @@ macro_rules! select_bridge {
|
|||||||
|
|
||||||
$generic
|
$generic
|
||||||
}
|
}
|
||||||
InitBridgeName::WestendToRococo => {
|
InitBridgeName::RococoToWococo => {
|
||||||
type Source = relay_westend_client::Westend;
|
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;
|
type Target = relay_rococo_client::Rococo;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
) -> <Target as Chain>::Call {
|
) -> <Target as Chain>::Call {
|
||||||
bp_rococo::Call::BridgeGrandpaWestend(bp_rococo::BridgeGrandpaWestendCall::initialize(init_data))
|
bp_rococo::Call::BridgeGrandpaWococo(bp_rococo::BridgeGrandpaWococoCall::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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$generic
|
$generic
|
||||||
|
|||||||
@@ -89,8 +89,23 @@ pub enum Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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.
|
/// Run the command.
|
||||||
pub async fn run(self) -> anyhow::Result<()> {
|
pub async fn run(self) -> anyhow::Result<()> {
|
||||||
|
self.init_logger();
|
||||||
match self {
|
match self {
|
||||||
Self::RelayHeaders(arg) => arg.run().await?,
|
Self::RelayHeaders(arg) => arg.run().await?,
|
||||||
Self::RelayMessages(arg) => arg.run().await?,
|
Self::RelayMessages(arg) => arg.run().await?,
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ arg_enum! {
|
|||||||
MillauToRialto,
|
MillauToRialto,
|
||||||
RialtoToMillau,
|
RialtoToMillau,
|
||||||
WestendToMillau,
|
WestendToMillau,
|
||||||
WestendToRococo,
|
RococoToWococo,
|
||||||
RococoToWestend,
|
WococoToRococo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,17 +71,17 @@ macro_rules! select_bridge {
|
|||||||
|
|
||||||
$generic
|
$generic
|
||||||
}
|
}
|
||||||
RelayHeadersBridge::WestendToRococo => {
|
RelayHeadersBridge::RococoToWococo => {
|
||||||
type Source = relay_westend_client::Westend;
|
type Source = relay_rococo_client::Rococo;
|
||||||
type Target = relay_rococo_client::Rococo;
|
type Target = relay_wococo_client::Wococo;
|
||||||
type Finality = crate::chains::westend_headers_to_rococo::WestendFinalityToRococo;
|
type Finality = crate::chains::rococo_headers_to_wococo::RococoFinalityToWococo;
|
||||||
|
|
||||||
$generic
|
$generic
|
||||||
}
|
}
|
||||||
RelayHeadersBridge::RococoToWestend => {
|
RelayHeadersBridge::WococoToRococo => {
|
||||||
type Source = relay_rococo_client::Rococo;
|
type Source = relay_wococo_client::Wococo;
|
||||||
type Target = relay_westend_client::Westend;
|
type Target = relay_rococo_client::Rococo;
|
||||||
type Finality = crate::chains::rococo_headers_to_westend::RococoFinalityToWestend;
|
type Finality = crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo;
|
||||||
|
|
||||||
$generic
|
$generic
|
||||||
}
|
}
|
||||||
@@ -102,6 +102,7 @@ impl RelayHeaders {
|
|||||||
Finality::new(target_client.clone(), target_sign),
|
Finality::new(target_client.clone(), target_sign),
|
||||||
source_client,
|
source_client,
|
||||||
target_client,
|
target_client,
|
||||||
|
false,
|
||||||
metrics_params,
|
metrics_params,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ macro_rules! select_bridge {
|
|||||||
type LeftToRightMessages = crate::chains::millau_messages_to_rialto::MillauMessagesToRialto;
|
type LeftToRightMessages = crate::chains::millau_messages_to_rialto::MillauMessagesToRialto;
|
||||||
type RightToLeftMessages = crate::chains::rialto_messages_to_millau::RialtoMessagesToMillau;
|
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::millau_messages_to_rialto::run as left_to_right_messages;
|
||||||
use crate::chains::rialto_messages_to_millau::run as right_to_left_messages;
|
use crate::chains::rialto_messages_to_millau::run as right_to_left_messages;
|
||||||
|
|
||||||
@@ -131,11 +134,13 @@ impl RelayHeadersAndMessages {
|
|||||||
left_client.clone(),
|
left_client.clone(),
|
||||||
right_client.clone(),
|
right_client.clone(),
|
||||||
LeftToRightFinality::new(right_client.clone(), right_sign.clone()),
|
LeftToRightFinality::new(right_client.clone(), right_sign.clone()),
|
||||||
|
MAX_MISSING_LEFT_HEADERS_AT_RIGHT,
|
||||||
);
|
);
|
||||||
let right_to_left_on_demand_headers = OnDemandHeadersRelay::new(
|
let right_to_left_on_demand_headers = OnDemandHeadersRelay::new(
|
||||||
right_client.clone(),
|
right_client.clone(),
|
||||||
left_client.clone(),
|
left_client.clone(),
|
||||||
RightToLeftFinality::new(left_client.clone(), left_sign.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 {
|
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,
|
Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams,
|
||||||
TargetSigningParams,
|
TargetSigningParams,
|
||||||
};
|
};
|
||||||
|
use bp_message_dispatch::{CallOrigin, MessagePayload};
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
|
use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
|
||||||
use pallet_bridge_dispatch::{CallOrigin, MessagePayload};
|
|
||||||
use relay_substrate_client::{Chain, TransactionSignScheme};
|
use relay_substrate_client::{Chain, TransactionSignScheme};
|
||||||
use sp_core::{Bytes, Pair};
|
use sp_core::{Bytes, Pair};
|
||||||
use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner};
|
use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner};
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ where
|
|||||||
SourceChain: Clone + Chain + Debug,
|
SourceChain: Clone + Chain + Debug,
|
||||||
BlockNumberOf<SourceChain>: BlockNumberBase,
|
BlockNumberOf<SourceChain>: BlockNumberBase,
|
||||||
TargetChain: Clone + Chain + Debug,
|
TargetChain: Clone + Chain + Debug,
|
||||||
TargetSign: Clone + Send + Sync,
|
TargetSign: 'static + Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
const SOURCE_NAME: &'static str = SourceChain::NAME;
|
const SOURCE_NAME: &'static str = SourceChain::NAME;
|
||||||
const TARGET_NAME: &'static str = TargetChain::NAME;
|
const TARGET_NAME: &'static str = TargetChain::NAME;
|
||||||
@@ -112,6 +112,7 @@ pub async fn run<SourceChain, TargetChain, P>(
|
|||||||
pipeline: P,
|
pipeline: P,
|
||||||
source_client: Client<SourceChain>,
|
source_client: Client<SourceChain>,
|
||||||
target_client: Client<TargetChain>,
|
target_client: Client<TargetChain>,
|
||||||
|
is_on_demand_task: bool,
|
||||||
metrics_params: MetricsParams,
|
metrics_params: MetricsParams,
|
||||||
) -> anyhow::Result<()>
|
) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
@@ -137,6 +138,7 @@ where
|
|||||||
FinalitySource::new(source_client),
|
FinalitySource::new(source_client),
|
||||||
SubstrateFinalityTarget::new(target_client, pipeline),
|
SubstrateFinalityTarget::new(target_client, pipeline),
|
||||||
FinalitySyncParams {
|
FinalitySyncParams {
|
||||||
|
is_on_demand_task,
|
||||||
tick: std::cmp::max(SourceChain::AVERAGE_BLOCK_INTERVAL, TargetChain::AVERAGE_BLOCK_INTERVAL),
|
tick: std::cmp::max(SourceChain::AVERAGE_BLOCK_INTERVAL, TargetChain::AVERAGE_BLOCK_INTERVAL),
|
||||||
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
|
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
|
||||||
stall_timeout: STALL_TIMEOUT,
|
stall_timeout: STALL_TIMEOUT,
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use relay_utils::initialize::initialize_logger;
|
|
||||||
|
|
||||||
mod chains;
|
mod chains;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod finality_pipeline;
|
mod finality_pipeline;
|
||||||
@@ -31,7 +29,6 @@ mod messages_target;
|
|||||||
mod on_demand_headers;
|
mod on_demand_headers;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
initialize_logger(false);
|
|
||||||
let command = cli::parse_args();
|
let command = cli::parse_args();
|
||||||
let run = command.run();
|
let run = command.run();
|
||||||
let result = async_std::task::block_on(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.
|
// reserved for messages dispatch allows dispatch of non-trivial messages.
|
||||||
//
|
//
|
||||||
// Any significant change in this values should attract additional attention.
|
// 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
|
where
|
||||||
C: Chain,
|
C: Chain,
|
||||||
P: SubstrateMessageLane,
|
P: SubstrateMessageLane,
|
||||||
R: Send + Sync,
|
R: 'static + Send + Sync,
|
||||||
I: Send + Sync + Instance,
|
I: Send + Sync + Instance,
|
||||||
{
|
{
|
||||||
type Error = SubstrateError;
|
type Error = SubstrateError;
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ impl<C, P, R, I> RelayClient for SubstrateMessagesTarget<C, P, R, I>
|
|||||||
where
|
where
|
||||||
C: Chain,
|
C: Chain,
|
||||||
P: SubstrateMessageLane,
|
P: SubstrateMessageLane,
|
||||||
R: Send + Sync,
|
R: 'static + Send + Sync,
|
||||||
I: Send + Sync + Instance,
|
I: Send + Sync + Instance,
|
||||||
{
|
{
|
||||||
type Error = SubstrateError;
|
type Error = SubstrateError;
|
||||||
|
|||||||
@@ -20,14 +20,22 @@ use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityT
|
|||||||
use crate::finality_target::SubstrateFinalityTarget;
|
use crate::finality_target::SubstrateFinalityTarget;
|
||||||
|
|
||||||
use bp_header_chain::justification::GrandpaJustification;
|
use bp_header_chain::justification::GrandpaJustification;
|
||||||
use finality_relay::TargetClient as FinalityTargetClient;
|
use finality_relay::{
|
||||||
|
FinalitySyncPipeline, SourceClient as FinalitySourceClient, TargetClient as FinalityTargetClient,
|
||||||
|
};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{mpsc, oneshot},
|
channel::{mpsc, oneshot},
|
||||||
select, FutureExt, StreamExt,
|
select, FutureExt, StreamExt,
|
||||||
};
|
};
|
||||||
use num_traits::Zero;
|
use num_traits::{CheckedSub, Zero};
|
||||||
use relay_substrate_client::{BlockNumberOf, Chain, Client, HashOf, HeaderIdOf, SyncHeader};
|
use relay_substrate_client::{
|
||||||
use relay_utils::{metrics::MetricsParams, BlockNumberBase, HeaderId};
|
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;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// On-demand Substrate <-> Substrate headers relay.
|
/// On-demand Substrate <-> Substrate headers relay.
|
||||||
@@ -49,6 +57,7 @@ impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> {
|
|||||||
source_client: Client<SourceChain>,
|
source_client: Client<SourceChain>,
|
||||||
target_client: Client<TargetChain>,
|
target_client: Client<TargetChain>,
|
||||||
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
|
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
|
||||||
|
maximal_headers_difference: SourceChain::BlockNumber,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
SourceChain: Chain + Debug,
|
SourceChain: Chain + Debug,
|
||||||
@@ -68,7 +77,14 @@ impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> {
|
|||||||
{
|
{
|
||||||
let (required_header_tx, required_header_rx) = mpsc::channel(1);
|
let (required_header_tx, required_header_rx) = mpsc::channel(1);
|
||||||
async_std::task::spawn(async move {
|
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!(
|
let background_task_name = format!(
|
||||||
@@ -100,6 +116,7 @@ async fn background_task<SourceChain, TargetChain, TargetSign>(
|
|||||||
source_client: Client<SourceChain>,
|
source_client: Client<SourceChain>,
|
||||||
target_client: Client<TargetChain>,
|
target_client: Client<TargetChain>,
|
||||||
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
|
pipeline: SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
|
||||||
|
maximal_headers_difference: SourceChain::BlockNumber,
|
||||||
mut required_header_rx: mpsc::Receiver<HeaderIdOf<SourceChain>>,
|
mut required_header_rx: mpsc::Receiver<HeaderIdOf<SourceChain>>,
|
||||||
) where
|
) where
|
||||||
SourceChain: Chain + Debug,
|
SourceChain: Chain + Debug,
|
||||||
@@ -118,7 +135,11 @@ async fn background_task<SourceChain, TargetChain, TargetSign>(
|
|||||||
FinalityTargetClient<SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>>,
|
FinalityTargetClient<SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>>,
|
||||||
{
|
{
|
||||||
let relay_task_name = on_demand_headers_relay_name::<SourceChain, TargetChain>();
|
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 active_headers_relay = None;
|
||||||
let mut required_header_number = Zero::zero();
|
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
|
// read best finalized source header number from source
|
||||||
let available_header_number = match finality_target.best_finalized_source_block_number().await {
|
let best_finalized_source_header_at_source =
|
||||||
Ok(available_header_number) => available_header_number,
|
best_finalized_source_header_at_source(&finality_source, &relay_task_name).await;
|
||||||
Err(error) => {
|
if matches!(best_finalized_source_header_at_source, Err(ref e) if e.is_connection_error()) {
|
||||||
log::error!(
|
relay_utils::relay_loop::reconnect_failed_client(
|
||||||
target: "bridge",
|
FailedClient::Source,
|
||||||
"Failed to read best finalized {} header from {} in {} relay: {:?}",
|
relay_utils::relay_loop::RECONNECT_DELAY,
|
||||||
SourceChain::NAME,
|
&mut finality_source,
|
||||||
TargetChain::NAME,
|
&mut finality_target,
|
||||||
relay_task_name,
|
)
|
||||||
error,
|
.await;
|
||||||
);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// we don't know what's happening with target client, so better to stop on-demand relay than
|
// read best finalized source header number from target
|
||||||
// submit unneeded transactions
|
let best_finalized_source_header_at_target =
|
||||||
// => assume that required header is known to the target node
|
best_finalized_source_header_at_target::<SourceChain, _, _>(&finality_target, &relay_task_name).await;
|
||||||
required_header_number
|
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
|
// start or stop headers relay if required
|
||||||
let activate = required_header_number > available_header_number;
|
let action = select_on_demand_relay_action::<SourceChain>(
|
||||||
match (activate, active_headers_relay.is_some()) {
|
best_finalized_source_header_at_source.ok(),
|
||||||
(true, false) => {
|
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();
|
let (relay_exited_tx, new_relay_exited_rx) = oneshot::channel();
|
||||||
active_headers_relay = start_on_demand_headers_relay(
|
active_headers_relay = start_on_demand_headers_relay(
|
||||||
relay_task_name.clone(),
|
relay_task_name.clone(),
|
||||||
@@ -186,14 +222,127 @@ async fn background_task<SourceChain, TargetChain, TargetSign>(
|
|||||||
relay_exited_rx = new_relay_exited_rx.right_future();
|
relay_exited_rx = new_relay_exited_rx.right_future();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(false, true) => {
|
OnDemandRelayAction::Stop => {
|
||||||
stop_on_demand_headers_relay(active_headers_relay.take()).await;
|
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.
|
/// On-demand headers relay task name.
|
||||||
fn on_demand_headers_relay_name<SourceChain: Chain, TargetChain: Chain>() -> String {
|
fn on_demand_headers_relay_name<SourceChain: Chain, TargetChain: Chain>() -> String {
|
||||||
format!("on-demand-{}-to-{}", SourceChain::NAME, TargetChain::NAME)
|
format!("on-demand-{}-to-{}", SourceChain::NAME, TargetChain::NAME)
|
||||||
@@ -219,7 +368,7 @@ where
|
|||||||
TargetSign: 'static,
|
TargetSign: 'static,
|
||||||
{
|
{
|
||||||
let headers_relay_future =
|
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();
|
let closure_task_name = task_name.clone();
|
||||||
async_std::task::Builder::new()
|
async_std::task::Builder::new()
|
||||||
.name(task_name.clone())
|
.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);
|
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" }
|
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||||
headers-relay = { path = "../headers" }
|
headers-relay = { path = "../headers" }
|
||||||
hex-literal = "0.3"
|
hex-literal = "0.3"
|
||||||
jsonrpsee-proc-macros = "=0.2.0-alpha.5"
|
jsonrpsee-proc-macros = "=0.2.0-alpha.6"
|
||||||
jsonrpsee-ws-client = "=0.2.0-alpha.5"
|
jsonrpsee-ws-client = "=0.2.0-alpha.6"
|
||||||
libsecp256k1 = { version = "0.3.4", default-features = false, features = ["hmac"] }
|
libsecp256k1 = { version = "0.3.4", default-features = false, features = ["hmac"] }
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
relay-utils = { path = "../utils" }
|
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-std = "1.6.5"
|
||||||
async-trait = "0.1.40"
|
async-trait = "0.1.40"
|
||||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||||
jsonrpsee-proc-macros = "=0.2.0-alpha.5"
|
jsonrpsee-proc-macros = "=0.2.0-alpha.6"
|
||||||
jsonrpsee-ws-client = "=0.2.0-alpha.5"
|
jsonrpsee-ws-client = "=0.2.0-alpha.6"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
rand = "0.7"
|
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.
|
/// Transaction proof pipeline.
|
||||||
pub trait TransactionProofPipeline {
|
pub trait TransactionProofPipeline: 'static {
|
||||||
/// Name of the transaction proof source.
|
/// Name of the transaction proof source.
|
||||||
const SOURCE_NAME: &'static str;
|
const SOURCE_NAME: &'static str;
|
||||||
/// Name of the transaction proof target.
|
/// Name of the transaction proof target.
|
||||||
@@ -35,18 +35,21 @@ pub trait TransactionProofPipeline {
|
|||||||
/// Block type.
|
/// Block type.
|
||||||
type Block: SourceBlock;
|
type Block: SourceBlock;
|
||||||
/// Transaction inclusion proof type.
|
/// Transaction inclusion proof type.
|
||||||
type TransactionProof;
|
type TransactionProof: 'static + Send + Sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block that is participating in exchange.
|
/// Block that is participating in exchange.
|
||||||
pub trait SourceBlock {
|
pub trait SourceBlock: 'static + Send + Sync {
|
||||||
/// Block hash type.
|
/// Block hash type.
|
||||||
type Hash: Clone + Debug + Display;
|
type Hash: 'static + Clone + Send + Sync + Debug + Display;
|
||||||
/// Block number type.
|
/// Block number type.
|
||||||
type Number: Debug
|
type Number: 'static
|
||||||
|
+ Debug
|
||||||
+ Display
|
+ Display
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Copy
|
+ Copy
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
+ Into<u64>
|
+ Into<u64>
|
||||||
+ std::cmp::Ord
|
+ std::cmp::Ord
|
||||||
+ std::ops::Add<Output = Self::Number>
|
+ std::ops::Add<Output = Self::Number>
|
||||||
@@ -61,7 +64,7 @@ pub trait SourceBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Transaction that is participating in exchange.
|
/// Transaction that is participating in exchange.
|
||||||
pub trait SourceTransaction {
|
pub trait SourceTransaction: 'static + Send {
|
||||||
/// Transaction hash type.
|
/// Transaction hash type.
|
||||||
type Hash: Debug + Display;
|
type Hash: Debug + Display;
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ pub struct TransactionProofsRelayState<BlockNumber> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Transactions proofs relay storage.
|
/// Transactions proofs relay storage.
|
||||||
pub trait TransactionProofsRelayStorage: Clone {
|
pub trait TransactionProofsRelayStorage: 'static + Clone + Send + Sync {
|
||||||
/// Associated block number.
|
/// Associated block number.
|
||||||
type BlockNumber;
|
type BlockNumber: 'static + Send + Sync;
|
||||||
|
|
||||||
/// Get relay state.
|
/// Get relay state.
|
||||||
fn state(&self) -> TransactionProofsRelayState<Self::BlockNumber>;
|
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;
|
type BlockNumber = BlockNumber;
|
||||||
|
|
||||||
fn state(&self) -> TransactionProofsRelayState<BlockNumber> {
|
fn state(&self) -> TransactionProofsRelayState<BlockNumber> {
|
||||||
@@ -89,7 +89,7 @@ pub async fn run<P: TransactionProofPipeline>(
|
|||||||
source_client: impl SourceClient<P>,
|
source_client: impl SourceClient<P>,
|
||||||
target_client: impl TargetClient<P>,
|
target_client: impl TargetClient<P>,
|
||||||
metrics_params: MetricsParams,
|
metrics_params: MetricsParams,
|
||||||
exit_signal: impl Future<Output = ()>,
|
exit_signal: impl Future<Output = ()> + 'static + Send,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let exit_signal = exit_signal.shared();
|
let exit_signal = exit_signal.shared();
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ pub async fn run<P: TransactionProofPipeline>(
|
|||||||
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
||||||
.expose()
|
.expose()
|
||||||
.await?
|
.await?
|
||||||
.run(|source_client, target_client, metrics| {
|
.run(metrics_prefix::<P>(), move |source_client, target_client, metrics| {
|
||||||
run_until_connection_lost(
|
run_until_connection_lost(
|
||||||
storage.clone(),
|
storage.clone(),
|
||||||
source_client,
|
source_client,
|
||||||
@@ -117,7 +117,7 @@ async fn run_until_connection_lost<P: TransactionProofPipeline>(
|
|||||||
source_client: impl SourceClient<P>,
|
source_client: impl SourceClient<P>,
|
||||||
target_client: impl TargetClient<P>,
|
target_client: impl TargetClient<P>,
|
||||||
metrics_exch: Option<ExchangeLoopMetrics>,
|
metrics_exch: Option<ExchangeLoopMetrics>,
|
||||||
exit_signal: impl Future<Output = ()>,
|
exit_signal: impl Future<Output = ()> + Send,
|
||||||
) -> Result<(), FailedClient> {
|
) -> Result<(), FailedClient> {
|
||||||
let mut retry_backoff = retry_backoff();
|
let mut retry_backoff = retry_backoff();
|
||||||
let mut state = storage.state();
|
let mut state = storage.state();
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ use std::{
|
|||||||
/// Finality proof synchronization loop parameters.
|
/// Finality proof synchronization loop parameters.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FinalitySyncParams {
|
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
|
/// Interval at which we check updates on both clients. Normally should be larger than
|
||||||
/// `min(source_block_time, target_block_time)`.
|
/// `min(source_block_time, target_block_time)`.
|
||||||
///
|
///
|
||||||
@@ -65,7 +67,7 @@ pub struct FinalitySyncParams {
|
|||||||
pub trait SourceClient<P: FinalitySyncPipeline>: RelayClient {
|
pub trait SourceClient<P: FinalitySyncPipeline>: RelayClient {
|
||||||
/// Stream of new finality proofs. The stream is allowed to miss proofs for some
|
/// Stream of new finality proofs. The stream is allowed to miss proofs for some
|
||||||
/// headers, even if those headers are mandatory.
|
/// 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.
|
/// Get best finalized block number.
|
||||||
async fn best_finalized_block_number(&self) -> Result<P::Number, Self::Error>;
|
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>,
|
target_client: impl TargetClient<P>,
|
||||||
sync_params: FinalitySyncParams,
|
sync_params: FinalitySyncParams,
|
||||||
metrics_params: MetricsParams,
|
metrics_params: MetricsParams,
|
||||||
exit_signal: impl Future<Output = ()>,
|
exit_signal: impl Future<Output = ()> + 'static + Send,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let exit_signal = exit_signal.shared();
|
let exit_signal = exit_signal.shared();
|
||||||
relay_utils::relay_loop(source_client, target_client)
|
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)
|
.with_metrics(Some(metrics_prefix::<P>()), metrics_params)
|
||||||
.loop_metric(|registry, prefix| SyncLoopMetrics::new(registry, prefix))?
|
.loop_metric(|registry, prefix| SyncLoopMetrics::new(registry, prefix))?
|
||||||
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
||||||
.expose()
|
.expose()
|
||||||
.await?
|
.await?
|
||||||
.run(|source_client, target_client, metrics| {
|
.run(metrics_prefix::<P>(), move |source_client, target_client, metrics| {
|
||||||
run_until_connection_lost(
|
run_until_connection_lost(
|
||||||
source_client,
|
source_client,
|
||||||
target_client,
|
target_client,
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ impl RelayClient for TestSourceClient {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl SourceClient<TestFinalitySyncPipeline> for TestSourceClient {
|
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> {
|
async fn best_finalized_block_number(&self) -> Result<TestNumber, TestError> {
|
||||||
let mut data = self.data.lock();
|
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(),
|
data: clients_data.clone(),
|
||||||
};
|
};
|
||||||
let sync_params = FinalitySyncParams {
|
let sync_params = FinalitySyncParams {
|
||||||
|
is_on_demand_task: false,
|
||||||
tick: Duration::from_secs(0),
|
tick: Duration::from_secs(0),
|
||||||
recent_finality_proofs_limit: 1024,
|
recent_finality_proofs_limit: 1024,
|
||||||
stall_timeout: Duration::from_secs(1),
|
stall_timeout: Duration::from_secs(1),
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ mod finality_loop;
|
|||||||
mod finality_loop_tests;
|
mod finality_loop_tests;
|
||||||
|
|
||||||
/// Finality proofs synchronization pipeline.
|
/// 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.
|
/// Name of the finality proofs source.
|
||||||
const SOURCE_NAME: &'static str;
|
const SOURCE_NAME: &'static str;
|
||||||
/// Name of the finality proofs target.
|
/// Name of the finality proofs target.
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ pub trait TargetClient<P: HeadersSyncPipeline>: RelayClient {
|
|||||||
|
|
||||||
/// Synchronization maintain procedure.
|
/// Synchronization maintain procedure.
|
||||||
#[async_trait]
|
#[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
|
/// Run custom maintain procedures. This is guaranteed to be called when both source and target
|
||||||
/// clients are unoccupied.
|
/// clients are unoccupied.
|
||||||
async fn maintain(&self, _sync: &mut HeadersSync<P>) {}
|
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_maintain: impl SyncMaintain<P>,
|
||||||
sync_params: HeadersSyncParams,
|
sync_params: HeadersSyncParams,
|
||||||
metrics_params: MetricsParams,
|
metrics_params: MetricsParams,
|
||||||
exit_signal: impl Future<Output = ()>,
|
exit_signal: impl Future<Output = ()> + 'static + Send,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let exit_signal = exit_signal.shared();
|
let exit_signal = exit_signal.shared();
|
||||||
relay_utils::relay_loop(source_client, target_client)
|
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))?
|
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
||||||
.expose()
|
.expose()
|
||||||
.await?
|
.await?
|
||||||
.run(|source_client, target_client, metrics| {
|
.run(metrics_prefix::<P>(), move |source_client, target_client, metrics| {
|
||||||
run_until_connection_lost(
|
run_until_connection_lost(
|
||||||
source_client,
|
source_client,
|
||||||
source_tick,
|
source_tick,
|
||||||
@@ -159,7 +159,7 @@ async fn run_until_connection_lost<P: HeadersSyncPipeline, TC: TargetClient<P>>(
|
|||||||
sync_maintain: impl SyncMaintain<P>,
|
sync_maintain: impl SyncMaintain<P>,
|
||||||
sync_params: HeadersSyncParams,
|
sync_params: HeadersSyncParams,
|
||||||
metrics_sync: Option<SyncLoopMetrics>,
|
metrics_sync: Option<SyncLoopMetrics>,
|
||||||
exit_signal: impl Future<Output = ()>,
|
exit_signal: impl Future<Output = ()> + Send,
|
||||||
) -> Result<(), FailedClient> {
|
) -> Result<(), FailedClient> {
|
||||||
let mut progress_context = (Instant::now(), None, None);
|
let mut progress_context = (Instant::now(), None, None);
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ pub enum HeaderStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Headers synchronization pipeline.
|
/// Headers synchronization pipeline.
|
||||||
pub trait HeadersSyncPipeline: Clone + Send + Sync {
|
pub trait HeadersSyncPipeline: 'static + Clone + Send + Sync {
|
||||||
/// Name of the headers source.
|
/// Name of the headers source.
|
||||||
const SOURCE_NAME: &'static str;
|
const SOURCE_NAME: &'static str;
|
||||||
/// Name of the headers target.
|
/// Name of the headers target.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use relay_utils::{BlockNumberBase, HeaderId};
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// One-way message lane.
|
/// One-way message lane.
|
||||||
pub trait MessageLane: Clone + Send + Sync {
|
pub trait MessageLane: 'static + Clone + Send + Sync {
|
||||||
/// Name of the messages source.
|
/// Name of the messages source.
|
||||||
const SOURCE_NAME: &'static str;
|
const SOURCE_NAME: &'static str;
|
||||||
/// Name of the messages target.
|
/// Name of the messages target.
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ pub async fn run<P: MessageLane>(
|
|||||||
source_client: impl SourceClient<P>,
|
source_client: impl SourceClient<P>,
|
||||||
target_client: impl TargetClient<P>,
|
target_client: impl TargetClient<P>,
|
||||||
metrics_params: MetricsParams,
|
metrics_params: MetricsParams,
|
||||||
exit_signal: impl Future<Output = ()>,
|
exit_signal: impl Future<Output = ()> + Send + 'static,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let exit_signal = exit_signal.shared();
|
let exit_signal = exit_signal.shared();
|
||||||
relay_utils::relay_loop(source_client, target_client)
|
relay_utils::relay_loop(source_client, target_client)
|
||||||
@@ -237,15 +237,18 @@ pub async fn run<P: MessageLane>(
|
|||||||
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
.standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))?
|
||||||
.expose()
|
.expose()
|
||||||
.await?
|
.await?
|
||||||
.run(|source_client, target_client, metrics| {
|
.run(
|
||||||
run_until_connection_lost(
|
metrics_prefix::<P>(¶ms.lane),
|
||||||
params.clone(),
|
move |source_client, target_client, metrics| {
|
||||||
source_client,
|
run_until_connection_lost(
|
||||||
target_client,
|
params.clone(),
|
||||||
metrics,
|
source_client,
|
||||||
exit_signal.clone(),
|
target_client,
|
||||||
)
|
metrics,
|
||||||
})
|
exit_signal.clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,6 +582,9 @@ pub(crate) mod tests {
|
|||||||
) -> Result<(), TestError> {
|
) -> Result<(), TestError> {
|
||||||
let mut data = self.data.lock();
|
let mut data = self.data.lock();
|
||||||
(self.tick)(&mut *data);
|
(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.submitted_messages_receiving_proofs.push(proof);
|
||||||
data.source_latest_confirmed_received_nonce = proof;
|
data.source_latest_confirmed_received_nonce = proof;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -681,6 +687,7 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
data.target_state.best_self =
|
data.target_state.best_self =
|
||||||
HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1);
|
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();
|
data.target_latest_received_nonce = *proof.0.end();
|
||||||
if let Some(target_latest_confirmed_received_nonce) = proof.1 {
|
if let Some(target_latest_confirmed_received_nonce) = proof.1 {
|
||||||
data.target_latest_confirmed_received_nonce = target_latest_confirmed_received_nonce;
|
data.target_latest_confirmed_received_nonce = target_latest_confirmed_received_nonce;
|
||||||
@@ -701,7 +708,7 @@ pub(crate) mod tests {
|
|||||||
data: TestClientData,
|
data: TestClientData,
|
||||||
source_tick: Arc<dyn Fn(&mut TestClientData) + Send + Sync>,
|
source_tick: Arc<dyn Fn(&mut TestClientData) + Send + Sync>,
|
||||||
target_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 {
|
) -> TestClientData {
|
||||||
async_std::task::block_on(async {
|
async_std::task::block_on(async {
|
||||||
let data = Arc::new(Mutex::new(data));
|
let data = Arc::new(Mutex::new(data));
|
||||||
@@ -809,37 +816,37 @@ pub(crate) mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Arc::new(|data: &mut TestClientData| {
|
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
|
// headers relay must only be started when we need new target headers at source node
|
||||||
if data.target_to_source_header_required.is_some() {
|
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);
|
assert!(data.source_state.best_finalized_peer_at_best_self.0 < data.target_state.best_self.0);
|
||||||
data.target_to_source_header_required = None;
|
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| {
|
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
|
// headers relay must only be started when we need new source headers at target node
|
||||||
if data.source_to_target_header_required.is_some() {
|
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);
|
assert!(data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_self.0);
|
||||||
data.source_to_target_header_required = None;
|
data.source_to_target_header_required = None;
|
||||||
}
|
}
|
||||||
// syncing source headers -> target chain (all at once)
|
// syncing source headers -> target chain
|
||||||
if data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_finalized_self.0 {
|
if let Some(last_requirement) = data.source_to_target_header_requirements.last() {
|
||||||
data.target_state.best_finalized_peer_at_best_self = data.source_state.best_finalized_self;
|
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 source has received all messages receiving confirmations => stop
|
||||||
if data.source_latest_confirmed_received_nonce == 10 {
|
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>> {
|
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> {
|
fn best_at_source(&self) -> Option<MessageNonce> {
|
||||||
@@ -876,4 +885,46 @@ mod tests {
|
|||||||
Some(((20..=23), proof_parameters(true, 4)))
|
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.
|
//! 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.
|
/// Initialize relay environment.
|
||||||
pub fn initialize_relay() {
|
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))
|
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 {
|
} else {
|
||||||
builder.format(move |buf, record| {
|
builder.format(move |buf, record| {
|
||||||
let log_level = color_level(record.level());
|
let log_level = color_level(record.level());
|
||||||
let log_target = color_target(record.target());
|
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();
|
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> {
|
enum Either<A, B> {
|
||||||
Left(A),
|
Left(A),
|
||||||
Right(B),
|
Right(B),
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ pub const RECONNECT_DELAY: Duration = Duration::from_secs(10);
|
|||||||
|
|
||||||
/// Basic blockchain client from relay perspective.
|
/// Basic blockchain client from relay perspective.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Client: Clone + Send + Sync {
|
pub trait Client: 'static + Clone + Send + Sync {
|
||||||
/// Type of error this clients returns.
|
/// Type of error this clients returns.
|
||||||
type Error: Debug + MaybeConnectionError;
|
type Error: 'static + Debug + MaybeConnectionError + Send + Sync;
|
||||||
|
|
||||||
/// Try to reconnect to source node.
|
/// Try to reconnect to source node.
|
||||||
async fn reconnect(&mut self) -> Result<(), Self::Error>;
|
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, ()> {
|
pub fn relay_loop<SC, TC>(source_client: SC, target_client: TC) -> Loop<SC, TC, ()> {
|
||||||
Loop {
|
Loop {
|
||||||
reconnect_delay: RECONNECT_DELAY,
|
reconnect_delay: RECONNECT_DELAY,
|
||||||
|
spawn_loop_task: true,
|
||||||
source_client,
|
source_client,
|
||||||
target_client,
|
target_client,
|
||||||
loop_metric: None,
|
loop_metric: None,
|
||||||
@@ -49,6 +50,7 @@ pub fn relay_metrics(prefix: Option<String>, params: MetricsParams) -> LoopMetri
|
|||||||
LoopMetrics {
|
LoopMetrics {
|
||||||
relay_loop: Loop {
|
relay_loop: Loop {
|
||||||
reconnect_delay: RECONNECT_DELAY,
|
reconnect_delay: RECONNECT_DELAY,
|
||||||
|
spawn_loop_task: true,
|
||||||
source_client: (),
|
source_client: (),
|
||||||
target_client: (),
|
target_client: (),
|
||||||
loop_metric: None,
|
loop_metric: None,
|
||||||
@@ -63,6 +65,7 @@ pub fn relay_metrics(prefix: Option<String>, params: MetricsParams) -> LoopMetri
|
|||||||
/// Generic relay loop.
|
/// Generic relay loop.
|
||||||
pub struct Loop<SC, TC, LM> {
|
pub struct Loop<SC, TC, LM> {
|
||||||
reconnect_delay: Duration,
|
reconnect_delay: Duration,
|
||||||
|
spawn_loop_task: bool,
|
||||||
source_client: SC,
|
source_client: SC,
|
||||||
target_client: TC,
|
target_client: TC,
|
||||||
loop_metric: Option<LM>,
|
loop_metric: Option<LM>,
|
||||||
@@ -84,11 +87,23 @@ impl<SC, TC, LM> Loop<SC, TC, LM> {
|
|||||||
self
|
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.
|
/// Start building loop metrics using given prefix.
|
||||||
pub fn with_metrics(self, prefix: Option<String>, params: MetricsParams) -> LoopMetrics<SC, TC, ()> {
|
pub fn with_metrics(self, prefix: Option<String>, params: MetricsParams) -> LoopMetrics<SC, TC, ()> {
|
||||||
LoopMetrics {
|
LoopMetrics {
|
||||||
relay_loop: Loop {
|
relay_loop: Loop {
|
||||||
reconnect_delay: self.reconnect_delay,
|
reconnect_delay: self.reconnect_delay,
|
||||||
|
spawn_loop_task: self.spawn_loop_task,
|
||||||
source_client: self.source_client,
|
source_client: self.source_client,
|
||||||
target_client: self.target_client,
|
target_client: self.target_client,
|
||||||
loop_metric: None,
|
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
|
/// 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,
|
/// actual job. When `run_loop` returns, this outer loop reconnects to failed client (source,
|
||||||
/// target or both) and calls `run_loop` again.
|
/// 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
|
where
|
||||||
R: Fn(SC, TC, Option<LM>) -> F,
|
R: 'static + Send + Fn(SC, TC, Option<LM>) -> F,
|
||||||
F: Future<Output = Result<(), FailedClient>>,
|
F: 'static + Send + Future<Output = Result<(), FailedClient>>,
|
||||||
SC: Client,
|
SC: 'static + Client,
|
||||||
TC: Client,
|
TC: 'static + Client,
|
||||||
LM: Clone,
|
LM: 'static + Send + Clone,
|
||||||
{
|
{
|
||||||
loop {
|
let spawn_loop_task = self.spawn_loop_task;
|
||||||
let result = run_loop(
|
let run_loop_task = async move {
|
||||||
self.source_client.clone(),
|
crate::initialize::initialize_loop(loop_name);
|
||||||
self.target_client.clone(),
|
|
||||||
self.loop_metric.clone(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match result {
|
loop {
|
||||||
Ok(()) => break,
|
let loop_metric = self.loop_metric.clone();
|
||||||
Err(failed_client) => loop {
|
let future_result = run_loop(self.source_client.clone(), self.target_client.clone(), loop_metric);
|
||||||
async_std::task::sleep(self.reconnect_delay).await;
|
let result = future_result.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
match result {
|
||||||
},
|
Ok(()) => break,
|
||||||
|
Err(failed_client) => {
|
||||||
|
reconnect_failed_client(
|
||||||
|
failed_client,
|
||||||
|
self.reconnect_delay,
|
||||||
|
&mut self.source_client,
|
||||||
|
&mut self.target_client,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!(target: "bridge", "Restarting relay loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!(target: "bridge", "Restarting relay loop");
|
Ok(())
|
||||||
}
|
};
|
||||||
|
|
||||||
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 {
|
Ok(Loop {
|
||||||
reconnect_delay: self.relay_loop.reconnect_delay,
|
reconnect_delay: self.relay_loop.reconnect_delay,
|
||||||
|
spawn_loop_task: self.relay_loop.spawn_loop_task,
|
||||||
source_client: self.relay_loop.source_client,
|
source_client: self.relay_loop.source_client,
|
||||||
target_client: self.relay_loop.target_client,
|
target_client: self.relay_loop.target_client,
|
||||||
loop_metric: self.loop_metric,
|
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.
|
/// Create new registry with global metrics.
|
||||||
fn create_metrics_registry(prefix: Option<String>) -> Registry {
|
fn create_metrics_registry(prefix: Option<String>) -> Registry {
|
||||||
match prefix {
|
match prefix {
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ cd $LOGS_DIR
|
|||||||
SERVICES=(\
|
SERVICES=(\
|
||||||
deployments_relay-messages-millau-to-rialto-generator_1 \
|
deployments_relay-messages-millau-to-rialto-generator_1 \
|
||||||
deployments_relay-messages-rialto-to-millau-generator_1 \
|
deployments_relay-messages-rialto-to-millau-generator_1 \
|
||||||
deployments_relay-messages-millau-to-rialto_1 \
|
deployments_relay-messages-millau-to-rialto-lane-00000001_1 \
|
||||||
deployments_relay-messages-rialto-to-millau_1 \
|
deployments_relay-messages-rialto-to-millau-lane-00000001_1 \
|
||||||
deployments_relay-headers-millau-to-rialto_1 \
|
deployments_relay-millau-rialto_1 \
|
||||||
deployments_relay-headers-rialto-to-millau_1 \
|
deployments_relay-headers-westend-to-millau_1 \
|
||||||
deployments_rialto-node-alice_1 \
|
deployments_rialto-node-alice_1 \
|
||||||
deployments_rialto-node-bob_1 \
|
deployments_rialto-node-bob_1 \
|
||||||
deployments_millau-node-alice_1 \
|
deployments_millau-node-alice_1 \
|
||||||
|
|||||||
Reference in New Issue
Block a user