Skip to content
GitLab
Explore
Sign in
parity
Mirrored projects
polkadot-sdk
Compare revisions
be1d7d05e5f32b1bfa67aec2f6344d2c6ff60f50 to aceda4659509d426d364188fa72555de58b887ba
Show whitespace changes
Inline
Side-by-side
bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs
View file @
aceda465
...
...
@@ -40,7 +40,7 @@ use crate::{
cli
::{
bridge
::
MessagesCliBridge
,
HexLaneId
,
PrometheusParams
},
messages_lane
::{
MessagesRelayLimits
,
MessagesRelayParams
},
on_demand
::
OnDemandRelay
,
TaggedAccount
,
TransactionParams
,
HeadersToRelay
,
TaggedAccount
,
TransactionParams
,
};
use
bp_messages
::
LaneId
;
use
bp_runtime
::
BalanceOf
;
...
...
@@ -61,11 +61,25 @@ pub struct HeadersAndMessagesSharedParams {
/// are relayed.
#[structopt(long)]
pub
only_mandatory_headers
:
bool
,
/// If passed, only free headers (mandatory and every Nth header, if configured in runtime)
/// are relayed. Overrides `only_mandatory_headers`.
#[structopt(long)]
pub
only_free_headers
:
bool
,
#[structopt(flatten)]
/// Prometheus metrics params.
pub
prometheus_params
:
PrometheusParams
,
}
impl
HeadersAndMessagesSharedParams
{
fn
headers_to_relay
(
&
self
)
->
HeadersToRelay
{
match
(
self
.only_mandatory_headers
,
self
.only_free_headers
)
{
(
_
,
true
)
=>
HeadersToRelay
::
Free
,
(
true
,
false
)
=>
HeadersToRelay
::
Mandatory
,
_
=>
HeadersToRelay
::
All
,
}
}
}
/// Bridge parameters, shared by all bridge types.
pub
struct
Full2WayBridgeCommonParams
<
Left
:
ChainWithTransactions
+
ChainWithRuntimeVersion
,
...
...
@@ -418,6 +432,7 @@ mod tests {
shared
:
HeadersAndMessagesSharedParams
{
lane
:
vec!
[
HexLaneId
([
0x00
,
0x00
,
0x00
,
0x00
])],
only_mandatory_headers
:
false
,
only_free_headers
:
false
,
prometheus_params
:
PrometheusParams
{
no_prometheus
:
false
,
prometheus_host
:
"0.0.0.0"
.into
(),
...
...
bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs
View file @
aceda465
...
...
@@ -180,7 +180,7 @@ where
self
.left_relay
.clone
(),
self
.common.right.client
.clone
(),
self
.common.right.tx_params
.clone
(),
self
.common.shared.
only_mandatory_headers
,
self
.common.shared
.
headers_to_relay
()
,
Some
(
self
.common.metrics_params
.clone
()),
);
let
right_relay_to_left_on_demand_headers
=
...
...
@@ -188,7 +188,7 @@ where
self
.right_relay
.clone
(),
self
.common.left.client
.clone
(),
self
.common.left.tx_params
.clone
(),
self
.common.shared.
only_mandatory_headers
,
self
.common.shared
.
headers_to_relay
()
,
Some
(
self
.common.metrics_params
.clone
()),
);
...
...
bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs
View file @
aceda465
...
...
@@ -171,7 +171,7 @@ where
self
.common.left.client
.clone
(),
self
.common.right.client
.clone
(),
self
.common.right.tx_params
.clone
(),
self
.common.shared.
only_mandatory_headers
,
self
.common.shared
.
headers_to_relay
()
,
None
,
);
let
right_relay_to_left_on_demand_headers
=
...
...
@@ -179,7 +179,7 @@ where
self
.right_relay
.clone
(),
self
.common.left.client
.clone
(),
self
.common.left.tx_params
.clone
(),
self
.common.shared.
only_mandatory_headers
,
self
.common.shared
.
headers_to_relay
()
,
Some
(
self
.common.metrics_params
.clone
()),
);
let
right_to_left_on_demand_parachains
=
OnDemandParachainsRelay
::
<
...
...
bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_relay.rs
View file @
aceda465
...
...
@@ -152,7 +152,7 @@ where
self
.common.left.client
.clone
(),
self
.common.right.client
.clone
(),
self
.common.right.tx_params
.clone
(),
self
.common.shared.
only_mandatory_headers
,
self
.common.shared
.
headers_to_relay
()
,
None
,
);
let
right_to_left_on_demand_headers
=
...
...
@@ -160,7 +160,7 @@ where
self
.common.right.client
.clone
(),
self
.common.left.client
.clone
(),
self
.common.left.tx_params
.clone
(),
self
.common.shared.
only_mandatory_headers
,
self
.common.shared
.
headers_to_relay
()
,
None
,
);
...
...
bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs
View file @
aceda465
...
...
@@ -43,6 +43,10 @@ pub struct RelayParachainsParams {
target
:
TargetConnectionParams
,
#[structopt(flatten)]
target_sign
:
TargetSigningParams
,
/// If passed, only free headers (those, available at "free" relay chain headers)
/// are relayed.
#[structopt(long)]
only_free_headers
:
bool
,
#[structopt(flatten)]
prometheus_params
:
PrometheusParams
,
}
...
...
@@ -59,9 +63,9 @@ where
{
/// Start relaying parachains finality.
async
fn
relay_parachains
(
data
:
RelayParachainsParams
)
->
anyhow
::
Result
<
()
>
{
let
source_client
=
data
.source.into_client
::
<
Self
::
SourceRelay
>
()
.await
?
;
let
source_
chain_
client
=
data
.source.into_client
::
<
Self
::
SourceRelay
>
()
.await
?
;
let
source_client
=
ParachainsSource
::
<
Self
::
ParachainFinality
>
::
new
(
source_c
lient
,
source_c
hain_client
.clone
()
,
Arc
::
new
(
Mutex
::
new
(
AvailableHeader
::
Missing
)),
);
...
...
@@ -69,9 +73,10 @@ where
signer
:
data
.target_sign.to_keypair
::
<
Self
::
Target
>
()
?
,
mortality
:
data
.target_sign.target_transactions_mortality
,
};
let
target_client
=
data
.target.into_client
::
<
Self
::
Target
>
()
.await
?
;
let
target_
chain_
client
=
data
.target.into_client
::
<
Self
::
Target
>
()
.await
?
;
let
target_client
=
ParachainsTarget
::
<
Self
::
ParachainFinality
>
::
new
(
target_client
.clone
(),
source_chain_client
,
target_chain_client
,
target_transaction_params
,
);
...
...
@@ -83,6 +88,7 @@ where
source_client
,
target_client
,
metrics_params
,
data
.only_free_headers
,
futures
::
future
::
pending
(),
)
.await
...
...
bridges/relays/lib-substrate-relay/src/finality/mod.rs
View file @
aceda465
...
...
@@ -25,13 +25,15 @@ use crate::{
use
async_trait
::
async_trait
;
use
bp_header_chain
::
justification
::{
GrandpaJustification
,
JustificationVerificationContext
};
use
finality_relay
::{
FinalityPipeline
,
FinalitySyncPipeline
};
use
finality_relay
::{
FinalityPipeline
,
FinalitySyncPipeline
,
HeadersToRelay
,
SourceClient
,
TargetClient
,
};
use
pallet_bridge_grandpa
::{
Call
as
BridgeGrandpaCall
,
Config
as
BridgeGrandpaConfig
};
use
relay_substrate_client
::{
transaction_stall_timeout
,
AccountIdOf
,
AccountKeyPairOf
,
BlockNumberOf
,
CallOf
,
Chain
,
ChainWithTransactions
,
Client
,
HashOf
,
HeaderOf
,
SyncHeader
,
};
use
relay_utils
::
metrics
::
MetricsParams
;
use
relay_utils
::
{
metrics
::
MetricsParams
,
TrackedTransactionStatus
,
TransactionTracker
}
;
use
sp_core
::
Pair
;
use
std
::{
fmt
::
Debug
,
marker
::
PhantomData
};
...
...
@@ -115,6 +117,7 @@ pub trait SubmitFinalityProofCallBuilder<P: SubstrateFinalitySyncPipeline> {
fn
build_submit_finality_proof_call
(
header
:
SyncHeader
<
HeaderOf
<
P
::
SourceChain
>>
,
proof
:
SubstrateFinalityProof
<
P
>
,
is_free_execution_expected
:
bool
,
context
:
<<
P
as
SubstrateFinalityPipeline
>
::
FinalityEngine
as
Engine
<
P
::
SourceChain
>>
::
FinalityVerificationContext
,
)
->
CallOf
<
P
::
TargetChain
>
;
}
...
...
@@ -142,6 +145,7 @@ where
fn
build_submit_finality_proof_call
(
header
:
SyncHeader
<
HeaderOf
<
P
::
SourceChain
>>
,
proof
:
GrandpaJustification
<
HeaderOf
<
P
::
SourceChain
>>
,
_is_free_execution_expected
:
bool
,
_context
:
JustificationVerificationContext
,
)
->
CallOf
<
P
::
TargetChain
>
{
BridgeGrandpaCall
::
<
R
,
I
>
::
submit_finality_proof
{
...
...
@@ -176,6 +180,7 @@ macro_rules! generate_submit_finality_proof_call_builder {
<
$pipeline
as
$crate
::
finality_base
::
SubstrateFinalityPipeline
>
::
SourceChain
>
>
,
_is_free_execution_expected
:
bool
,
_context
:
bp_header_chain
::
justification
::
JustificationVerificationContext
,
)
->
relay_substrate_client
::
CallOf
<
<
$pipeline
as
$crate
::
finality_base
::
SubstrateFinalityPipeline
>
::
TargetChain
...
...
@@ -215,6 +220,7 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
<
$pipeline
as
$crate
::
finality_base
::
SubstrateFinalityPipeline
>
::
SourceChain
>
>
,
is_free_execution_expected
:
bool
,
context
:
bp_header_chain
::
justification
::
JustificationVerificationContext
,
)
->
relay_substrate_client
::
CallOf
<
<
$pipeline
as
$crate
::
finality_base
::
SubstrateFinalityPipeline
>
::
TargetChain
...
...
@@ -223,7 +229,8 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
$bridge_grandpa
(
$submit_finality_proof
{
finality_target
:
Box
::
new
(
header
.into_inner
()),
justification
:
proof
,
current_set_id
:
context
.authority_set_id
current_set_id
:
context
.authority_set_id
,
is_free_execution_expected
,
})
}
}
...
...
@@ -235,15 +242,16 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
pub
async
fn
run
<
P
:
SubstrateFinalitySyncPipeline
>
(
source_client
:
Client
<
P
::
SourceChain
>
,
target_client
:
Client
<
P
::
TargetChain
>
,
only_mandatory_headers
:
bool
,
headers_to_relay
:
HeadersToRelay
,
transaction_params
:
TransactionParams
<
AccountKeyPairOf
<
P
::
TargetChain
>>
,
metrics_params
:
MetricsParams
,
)
->
anyhow
::
Result
<
()
>
{
log
::
info!
(
target
:
"bridge"
,
"Starting {} -> {} finality proof relay"
,
"Starting {} -> {} finality proof relay
: relaying {:?} headers
"
,
P
::
SourceChain
::
NAME
,
P
::
TargetChain
::
NAME
,
headers_to_relay
,
);
finality_relay
::
run
(
...
...
@@ -260,7 +268,7 @@ pub async fn run<P: SubstrateFinalitySyncPipeline>(
P
::
TargetChain
::
AVERAGE_BLOCK_INTERVAL
,
relay_utils
::
STALL_TIMEOUT
,
),
only_mandatory_headers
,
headers_to_relay
,
},
metrics_params
,
futures
::
future
::
pending
(),
...
...
@@ -268,3 +276,34 @@ pub async fn run<P: SubstrateFinalitySyncPipeline>(
.await
.map_err
(|
e
|
anyhow
::
format_err!
(
"{}"
,
e
))
}
/// Relay single header. No checks are made to ensure that transaction will succeed.
pub
async
fn
relay_single_header
<
P
:
SubstrateFinalitySyncPipeline
>
(
source_client
:
Client
<
P
::
SourceChain
>
,
target_client
:
Client
<
P
::
TargetChain
>
,
transaction_params
:
TransactionParams
<
AccountKeyPairOf
<
P
::
TargetChain
>>
,
header_number
:
BlockNumberOf
<
P
::
SourceChain
>
,
)
->
anyhow
::
Result
<
()
>
{
let
finality_source
=
SubstrateFinalitySource
::
<
P
>
::
new
(
source_client
,
None
);
let
(
header
,
proof
)
=
finality_source
.header_and_finality_proof
(
header_number
)
.await
?
;
let
Some
(
proof
)
=
proof
else
{
return
Err
(
anyhow
::
format_err!
(
"Unable to submit {} header #{} to {}: no finality proof"
,
P
::
SourceChain
::
NAME
,
header_number
,
P
::
TargetChain
::
NAME
,
));
};
let
finality_target
=
SubstrateFinalityTarget
::
<
P
>
::
new
(
target_client
,
transaction_params
);
let
tx_tracker
=
finality_target
.submit_finality_proof
(
header
,
proof
,
false
)
.await
?
;
match
tx_tracker
.wait
()
.await
{
TrackedTransactionStatus
::
Finalized
(
_
)
=>
Ok
(()),
TrackedTransactionStatus
::
Lost
=>
Err
(
anyhow
::
format_err!
(
"Transaction with {} header #{} is considered lost at {}"
,
P
::
SourceChain
::
NAME
,
header_number
,
P
::
TargetChain
::
NAME
,
)),
}
}
bridges/relays/lib-substrate-relay/src/finality/target.rs
View file @
aceda465
...
...
@@ -25,9 +25,10 @@ use crate::{
};
use
async_trait
::
async_trait
;
use
bp_runtime
::
BlockNumberOf
;
use
finality_relay
::
TargetClient
;
use
relay_substrate_client
::{
AccountKeyPairOf
,
Client
,
Error
,
HeaderIdOf
,
HeaderOf
,
SyncHeader
,
TransactionEra
,
AccountKeyPairOf
,
Chain
,
Client
,
Error
,
HeaderIdOf
,
HeaderOf
,
SyncHeader
,
TransactionEra
,
TransactionTracker
,
UnsignedTransaction
,
};
use
relay_utils
::
relay_loop
::
Client
as
RelayClient
;
...
...
@@ -103,10 +104,23 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter<
.ok_or
(
Error
::
BridgePalletIsNotInitialized
)
?
)
}
async
fn
free_source_headers_interval
(
&
self
,
)
->
Result
<
Option
<
BlockNumberOf
<
P
::
SourceChain
>>
,
Self
::
Error
>
{
self
.client
.typed_state_call
(
P
::
SourceChain
::
FREE_HEADERS_INTERVAL_METHOD
.into
(),
(),
Some
(
self
.client
.best_header
()
.await
?
.hash
()),
)
.await
}
async
fn
submit_finality_proof
(
&
self
,
header
:
SyncHeader
<
HeaderOf
<
P
::
SourceChain
>>
,
mut
proof
:
SubstrateFinalityProof
<
P
>
,
is_free_execution_expected
:
bool
,
)
->
Result
<
Self
::
TransactionTracker
,
Error
>
{
// verify and runtime module at target chain may require optimized finality proof
let
context
=
...
...
@@ -115,7 +129,10 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter<
// now we may submit optimized finality proof
let
mortality
=
self
.transaction_params.mortality
;
let
call
=
P
::
SubmitFinalityProofCallBuilder
::
build_submit_finality_proof_call
(
header
,
proof
,
context
,
header
,
proof
,
is_free_execution_expected
,
context
,
);
self
.client
.submit_and_watch_signed_extrinsic
(
...
...
bridges/relays/lib-substrate-relay/src/lib.rs
View file @
aceda465
...
...
@@ -22,6 +22,9 @@ use relay_substrate_client::{Chain, ChainWithUtilityPallet, UtilityPallet};
use
std
::
marker
::
PhantomData
;
// to avoid `finality_relay` dependency in other crates
pub
use
finality_relay
::
HeadersToRelay
;
pub
mod
cli
;
pub
mod
equivocation
;
pub
mod
error
;
...
...
bridges/relays/lib-substrate-relay/src/on_demand/headers.rs
View file @
aceda465
...
...
@@ -28,7 +28,7 @@ use futures::{select, FutureExt};
use
num_traits
::{
One
,
Saturating
,
Zero
};
use
sp_runtime
::
traits
::
Header
;
use
finality_relay
::{
FinalitySyncParams
,
TargetClient
as
FinalityTargetClient
};
use
finality_relay
::{
FinalitySyncParams
,
HeadersToRelay
,
TargetClient
as
FinalityTargetClient
};
use
relay_substrate_client
::{
AccountIdOf
,
AccountKeyPairOf
,
BlockNumberOf
,
CallOf
,
Chain
,
Client
,
Error
as
SubstrateError
,
HeaderIdOf
,
...
...
@@ -75,7 +75,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> {
source_client
:
Client
<
P
::
SourceChain
>
,
target_client
:
Client
<
P
::
TargetChain
>
,
target_transaction_params
:
TransactionParams
<
AccountKeyPairOf
<
P
::
TargetChain
>>
,
only_mandatory_headers
:
bool
,
headers_to_relay
:
HeadersToRelay
,
metrics_params
:
Option
<
MetricsParams
>
,
)
->
Self
where
...
...
@@ -94,7 +94,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> {
source_client
,
target_client
,
target_transaction_params
,
only_mandatory_headers
,
headers_to_relay
,
required_header_number
,
metrics_params
,
)
...
...
@@ -191,7 +191,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandRelay<P::SourceChain, P::TargetCh
// and then craft the submit-proof call
let
call
=
P
::
SubmitFinalityProofCallBuilder
::
build_submit_finality_proof_call
(
header
,
proof
,
context
,
header
,
proof
,
false
,
context
,
);
return
Ok
((
header_id
,
vec!
[
call
]));
...
...
@@ -204,7 +204,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
source_client
:
Client
<
P
::
SourceChain
>
,
target_client
:
Client
<
P
::
TargetChain
>
,
target_transaction_params
:
TransactionParams
<
AccountKeyPairOf
<
P
::
TargetChain
>>
,
only_mandatory_headers
:
bool
,
headers_to_relay
:
HeadersToRelay
,
required_header_number
:
RequiredHeaderNumberRef
<
P
::
SourceChain
>
,
metrics_params
:
Option
<
MetricsParams
>
,
)
where
...
...
@@ -346,11 +346,11 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
log
::
info!
(
target
:
"bridge"
,
"[{}] Starting on-demand headers relay task
\n\t
\
Only mandatory headers
: {}
\n\t
\
Headers to relay
: {
:?
}
\n\t
\
Tx mortality: {:?} (~{}m)
\n\t
\
Stall timeout: {:?}"
,
relay_task_name
,
only_mandatory_headers
,
headers_to_relay
,
target_transactions_mortality
,
stall_timeout
.as_secs_f64
()
/
60.0f64
,
stall_timeout
,
...
...
@@ -367,7 +367,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
),
recent_finality_proofs_limit
:
RECENT_FINALITY_PROOFS_LIMIT
,
stall_timeout
,
only_mandatory_headers
,
headers_to_relay
,
},
metrics_params
.clone
()
.unwrap_or_else
(
MetricsParams
::
disabled
),
futures
::
future
::
pending
(),
...
...
bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs
View file @
aceda465
...
...
@@ -222,6 +222,7 @@ where
proved_relay_block
,
vec!
[(
para_id
,
para_hash
)],
para_proof
,
false
,
));
Ok
((
proved_parachain_block
,
calls
))
...
...
@@ -256,8 +257,11 @@ async fn background_task<P: SubstrateParachainsPipeline>(
let
mut
parachains_source
=
ParachainsSource
::
<
P
>
::
new
(
source_relay_client
.clone
(),
required_para_header_ref
.clone
());
let
mut
parachains_target
=
ParachainsTarget
::
<
P
>
::
new
(
target_client
.clone
(),
target_transaction_params
.clone
());
let
mut
parachains_target
=
ParachainsTarget
::
<
P
>
::
new
(
source_relay_client
.clone
(),
target_client
.clone
(),
target_transaction_params
.clone
(),
);
loop
{
select!
{
...
...
@@ -392,6 +396,8 @@ async fn background_task<P: SubstrateParachainsPipeline>(
parachains_source
.clone
(),
parachains_target
.clone
(),
MetricsParams
::
disabled
(),
// we do not support free parachain headers relay in on-demand relays
false
,
futures
::
future
::
pending
(),
)
.fuse
(),
...
...
@@ -481,7 +487,7 @@ where
let
para_header_at_target
=
best_finalized_peer_header_at_self
::
<
P
::
TargetChain
,
P
::
SourceParachain
,
>
(
target
.client
(),
best_target_block_hash
)
>
(
target
.
target_
client
(),
best_target_block_hash
)
.await
;
// if there are no parachain heads at the target (`NoParachainHeadAtTarget`), we'll need to
// submit at least one. Otherwise the pallet will be treated as uninitialized and messages
...
...
@@ -504,7 +510,7 @@ where
let
relay_header_at_target
=
best_finalized_peer_header_at_self
::
<
P
::
TargetChain
,
P
::
SourceRelayChain
,
>
(
target
.client
(),
best_target_block_hash
)
>
(
target
.
target_
client
(),
best_target_block_hash
)
.await
.map_err
(
map_target_err
)
?
;
...
...
bridges/relays/lib-substrate-relay/src/parachains/mod.rs
View file @
aceda465
...
...
@@ -71,6 +71,7 @@ pub trait SubmitParachainHeadsCallBuilder<P: SubstrateParachainsPipeline>:
at_relay_block
:
HeaderIdOf
<
P
::
SourceRelayChain
>
,
parachains
:
Vec
<
(
ParaId
,
ParaHash
)
>
,
parachain_heads_proof
:
ParaHeadsProof
,
is_free_execution_expected
:
bool
,
)
->
CallOf
<
P
::
TargetChain
>
;
}
...
...
@@ -97,6 +98,7 @@ where
at_relay_block
:
HeaderIdOf
<
P
::
SourceRelayChain
>
,
parachains
:
Vec
<
(
ParaId
,
ParaHash
)
>
,
parachain_heads_proof
:
ParaHeadsProof
,
_is_free_execution_expected
:
bool
,
)
->
CallOf
<
P
::
TargetChain
>
{
BridgeParachainsCall
::
<
R
,
I
>
::
submit_parachain_heads
{
at_relay_block
:
(
at_relay_block
.0
,
at_relay_block
.1
),
...
...
bridges/relays/lib-substrate-relay/src/parachains/target.rs
View file @
aceda465
...
...
@@ -24,42 +24,53 @@ use crate::{
};
use
async_trait
::
async_trait
;
use
bp_polkadot_core
::
parachains
::{
ParaHash
,
ParaHeadsProof
,
ParaId
};
use
bp_runtime
::
HeaderIdProvider
;
use
codec
::
Decode
;
use
bp_parachains
::{
ImportedParaHeadsKeyProvider
,
ParaInfo
,
ParaStoredHeaderData
,
ParasInfoKeyProvider
,
};
use
bp_polkadot_core
::{
parachains
::{
ParaHash
,
ParaHeadsProof
,
ParaId
},
BlockNumber
as
RelayBlockNumber
,
};
use
bp_runtime
::{
Chain
as
ChainBase
,
HeaderId
,
HeaderIdProvider
,
StorageDoubleMapKeyProvider
,
StorageMapKeyProvider
,
};
use
parachains_relay
::
parachains_loop
::
TargetClient
;
use
relay_substrate_client
::{
AccountIdOf
,
AccountKeyPairOf
,
Chain
,
Client
,
Error
as
SubstrateError
,
HeaderIdOf
,
ParachainBase
,
TransactionEra
,
TransactionTracker
,
UnsignedTransaction
,
AccountIdOf
,
AccountKeyPairOf
,
BlockNumberOf
,
Chain
,
Client
,
Error
as
SubstrateError
,
HeaderIdOf
,
ParachainBase
,
RelayChain
,
TransactionEra
,
TransactionTracker
,
UnsignedTransaction
,
};
use
relay_utils
::
relay_loop
::
Client
as
RelayClient
;
use
sp_core
::
{
Bytes
,
Pair
}
;
use
sp_core
::
Pair
;
/// Substrate client as parachain heads source.
pub
struct
ParachainsTarget
<
P
:
SubstrateParachainsPipeline
>
{
client
:
Client
<
P
::
TargetChain
>
,
source_client
:
Client
<
P
::
SourceRelayChain
>
,
target_client
:
Client
<
P
::
TargetChain
>
,
transaction_params
:
TransactionParams
<
AccountKeyPairOf
<
P
::
TargetChain
>>
,
}
impl
<
P
:
SubstrateParachainsPipeline
>
ParachainsTarget
<
P
>
{
/// Creates new parachains target client.
pub
fn
new
(
client
:
Client
<
P
::
TargetChain
>
,
source_client
:
Client
<
P
::
SourceRelayChain
>
,
target_client
:
Client
<
P
::
TargetChain
>
,
transaction_params
:
TransactionParams
<
AccountKeyPairOf
<
P
::
TargetChain
>>
,
)
->
Self
{
ParachainsTarget
{
client
,
transaction_params
}
ParachainsTarget
{
source_client
,
target_
client
,
transaction_params
}
}
/// Returns reference to the underlying RPC client.
pub
fn
client
(
&
self
)
->
&
Client
<
P
::
TargetChain
>
{
&
self
.client
pub
fn
target_
client
(
&
self
)
->
&
Client
<
P
::
TargetChain
>
{
&
self
.
target_
client
}
}
impl
<
P
:
SubstrateParachainsPipeline
>
Clone
for
ParachainsTarget
<
P
>
{
fn
clone
(
&
self
)
->
Self
{
ParachainsTarget
{
client
:
self
.client
.clone
(),
source_client
:
self
.source_client
.clone
(),
target_client
:
self
.target_client
.clone
(),
transaction_params
:
self
.transaction_params
.clone
(),
}
}
...
...
@@ -70,7 +81,9 @@ impl<P: SubstrateParachainsPipeline> RelayClient for ParachainsTarget<P> {
type
Error
=
SubstrateError
;
async
fn
reconnect
(
&
mut
self
)
->
Result
<
(),
SubstrateError
>
{
self
.client
.reconnect
()
.await
self
.target_client
.reconnect
()
.await
?
;
self
.source_client
.reconnect
()
.await
?
;
Ok
(())
}
}
...
...
@@ -79,11 +92,13 @@ impl<P> TargetClient<ParachainsPipelineAdapter<P>> for ParachainsTarget<P>
where
P
:
SubstrateParachainsPipeline
,
AccountIdOf
<
P
::
TargetChain
>
:
From
<<
AccountKeyPairOf
<
P
::
TargetChain
>
as
Pair
>
::
Public
>
,
P
::
SourceParachain
:
ChainBase
<
Hash
=
ParaHash
>
,
P
::
SourceRelayChain
:
ChainBase
<
BlockNumber
=
RelayBlockNumber
>
,
{
type
TransactionTracker
=
TransactionTracker
<
P
::
TargetChain
,
Client
<
P
::
TargetChain
>>
;
async
fn
best_block
(
&
self
)
->
Result
<
HeaderIdOf
<
P
::
TargetChain
>
,
Self
::
Error
>
{
let
best_header
=
self
.client
.best_header
()
.await
?
;
let
best_header
=
self
.
target_
client
.best_header
()
.await
?
;
let
best_id
=
best_header
.id
();
Ok
(
best_id
)
...
...
@@ -93,7 +108,7 @@ where
&
self
,
at_block
:
&
HeaderIdOf
<
P
::
TargetChain
>
,
)
->
Result
<
HeaderIdOf
<
P
::
SourceRelayChain
>
,
Self
::
Error
>
{
self
.client
self
.
target_
client
.typed_state_call
::
<
_
,
Option
<
HeaderIdOf
<
P
::
SourceRelayChain
>>>
(
P
::
SourceRelayChain
::
BEST_FINALIZED_HEADER_ID_METHOD
.into
(),
(),
...
...
@@ -104,23 +119,57 @@ where
.unwrap_or
(
Err
(
SubstrateError
::
BridgePalletIsNotInitialized
))
}
async
fn
free_source_relay_headers_interval
(
&
self
,
)
->
Result
<
Option
<
BlockNumberOf
<
P
::
SourceRelayChain
>>
,
Self
::
Error
>
{
self
.target_client
.typed_state_call
(
P
::
SourceRelayChain
::
FREE_HEADERS_INTERVAL_METHOD
.into
(),
(),
None
)
.await
}
async
fn
parachain_head
(
&
self
,
at_block
:
HeaderIdOf
<
P
::
TargetChain
>
,
)
->
Result
<
Option
<
HeaderIdOf
<
P
::
SourceParachain
>>
,
Self
::
Error
>
{
let
encoded_best_finalized_source_para_block
=
self
.client
.state_call
(
P
::
SourceParachain
::
BEST_FINALIZED_HEADER_ID_METHOD
.into
(),
Bytes
(
Vec
::
new
()),
Some
(
at_block
.1
),
)
.await
?
;
)
->
Result
<
Option
<
(
HeaderIdOf
<
P
::
SourceRelayChain
>
,
HeaderIdOf
<
P
::
SourceParachain
>
)
>
,
Self
::
Error
,
>
{
// read best parachain head from the target bridge-parachains pallet
let
storage_key
=
ParasInfoKeyProvider
::
final_key
(
P
::
SourceRelayChain
::
WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME
,
&
P
::
SourceParachain
::
PARACHAIN_ID
.into
(),
);
let
storage_value
:
Option
<
ParaInfo
>
=
self
.target_client
.storage_value
(
storage_key
,
Some
(
at_block
.hash
()))
.await
?
;
let
para_info
=
match
storage_value
{
Some
(
para_info
)
=>
para_info
,
None
=>
return
Ok
(
None
),
};
Ok
(
Option
::
<
HeaderIdOf
<
P
::
SourceParachain
>>
::
decode
(
&
mut
&
encoded_best_finalized_source_para_block
.0
[
..
],
)
.map_err
(
SubstrateError
::
ResponseParseFailed
)
?
)
// now we need to get full header ids. For source relay chain it is simple, because we
// are connected
let
relay_header_id
=
self
.source_client
.header_by_number
(
para_info
.best_head_hash.at_relay_block_number
)
.await
?
.id
();
// for parachain, we need to read from the target chain runtime storage
let
storage_key
=
ImportedParaHeadsKeyProvider
::
final_key
(
P
::
SourceRelayChain
::
WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME
,
&
P
::
SourceParachain
::
PARACHAIN_ID
.into
(),
&
para_info
.best_head_hash.head_hash
,
);
let
storage_value
:
Option
<
ParaStoredHeaderData
>
=
self
.target_client
.storage_value
(
storage_key
,
Some
(
at_block
.hash
()))
.await
?
;
let
para_head_number
=
match
storage_value
{
Some
(
para_head_data
)
=>
para_head_data
.decode_parachain_head_data
::
<
P
::
SourceParachain
>
()
?
.number
,
None
=>
return
Ok
(
None
),
};
let
para_head_id
=
HeaderId
(
para_head_number
,
para_info
.best_head_hash.head_hash
);
Ok
(
Some
((
relay_header_id
,
para_head_id
)))
}
async
fn
submit_parachain_head_proof
(
...
...
@@ -128,14 +177,16 @@ where
at_relay_block
:
HeaderIdOf
<
P
::
SourceRelayChain
>
,
updated_head_hash
:
ParaHash
,
proof
:
ParaHeadsProof
,
is_free_execution_expected
:
bool
,
)
->
Result
<
Self
::
TransactionTracker
,
Self
::
Error
>
{
let
transaction_params
=
self
.transaction_params
.clone
();
let
call
=
P
::
SubmitParachainHeadsCallBuilder
::
build_submit_parachain_heads_call
(
at_relay_block
,
vec!
[(
ParaId
(
P
::
SourceParachain
::
PARACHAIN_ID
),
updated_head_hash
)],
proof
,
is_free_execution_expected
,
);
self
.client
self
.
target_
client
.submit_and_watch_signed_extrinsic
(
&
transaction_params
.signer
,
move
|
best_block_id
,
transaction_nonce
|
{
...
...
bridges/relays/parachains/src/parachains_loop.rs
View file @
aceda465
...
...
@@ -25,7 +25,7 @@ use futures::{
future
::{
FutureExt
,
Shared
},
poll
,
select_biased
,
};
use
relay_substrate_client
::{
Chain
,
HeaderIdOf
,
ParachainBase
};
use
relay_substrate_client
::{
BlockNumberOf
,
Chain
,
HeaderIdOf
,
ParachainBase
};
use
relay_utils
::{
metrics
::
MetricsParams
,
relay_loop
::
Client
as
RelayClient
,
FailedClient
,
TrackedTransactionStatus
,
TransactionTracker
,
...
...
@@ -96,17 +96,27 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
/// Get best block id.
async
fn
best_block
(
&
self
)
->
Result
<
HeaderIdOf
<
P
::
TargetChain
>
,
Self
::
Error
>
;
/// Get best finalized source relay chain block id.
/// Get best finalized source relay chain block id. If `free_source_relay_headers_interval`
/// is `Some(_)`, the returned
async
fn
best_finalized_source_relay_chain_block
(
&
self
,
at_block
:
&
HeaderIdOf
<
P
::
TargetChain
>
,
)
->
Result
<
HeaderIdOf
<
P
::
SourceRelayChain
>
,
Self
::
Error
>
;
/// Get free source **relay** headers submission interval, if it is configured in the
/// target runtime. We assume that the target chain will accept parachain header, proved
/// at such relay header for free.
async
fn
free_source_relay_headers_interval
(
&
self
,
)
->
Result
<
Option
<
BlockNumberOf
<
P
::
SourceRelayChain
>>
,
Self
::
Error
>
;
/// Get parachain head id at given block.
async
fn
parachain_head
(
&
self
,
at_block
:
HeaderIdOf
<
P
::
TargetChain
>
,
)
->
Result
<
Option
<
HeaderIdOf
<
P
::
SourceParachain
>>
,
Self
::
Error
>
;
)
->
Result
<
Option
<
(
HeaderIdOf
<
P
::
SourceRelayChain
>
,
HeaderIdOf
<
P
::
SourceParachain
>
)
>
,
Self
::
Error
,
>
;
/// Submit parachain heads proof.
async
fn
submit_parachain_head_proof
(
...
...
@@ -114,6 +124,7 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
at_source_block
:
HeaderIdOf
<
P
::
SourceRelayChain
>
,
para_head_hash
:
ParaHash
,
proof
:
ParaHeadsProof
,
is_free_execution_expected
:
bool
,
)
->
Result
<
Self
::
TransactionTracker
,
Self
::
Error
>
;
}
...
...
@@ -133,6 +144,7 @@ pub async fn run<P: ParachainsPipeline>(
source_client
:
impl
SourceClient
<
P
>
,
target_client
:
impl
TargetClient
<
P
>
,
metrics_params
:
MetricsParams
,
only_free_headers
:
bool
,
exit_signal
:
impl
Future
<
Output
=
()
>
+
'static
+
Send
,
)
->
Result
<
(),
relay_utils
::
Error
>
where
...
...
@@ -145,7 +157,13 @@ where
.expose
()
.await
?
.run
(
metrics_prefix
::
<
P
>
(),
move
|
source_client
,
target_client
,
metrics
|
{
run_until_connection_lost
(
source_client
,
target_client
,
metrics
,
exit_signal
.clone
())
run_until_connection_lost
(
source_client
,
target_client
,
metrics
,
only_free_headers
,
exit_signal
.clone
(),
)
})
.await
}
...
...
@@ -155,6 +173,7 @@ async fn run_until_connection_lost<P: ParachainsPipeline>(
source_client
:
impl
SourceClient
<
P
>
,
target_client
:
impl
TargetClient
<
P
>
,
metrics
:
Option
<
ParachainsLoopMetrics
>
,
only_free_headers
:
bool
,
exit_signal
:
impl
Future
<
Output
=
()
>
+
Send
,
)
->
Result
<
(),
FailedClient
>
where
...
...
@@ -166,6 +185,47 @@ where
P
::
TargetChain
::
AVERAGE_BLOCK_INTERVAL
,
);
// free parachain header = header, available (proved) at free relay chain block. Let's
// read interval of free source relay chain blocks from target client
let
free_source_relay_headers_interval
=
if
only_free_headers
{
let
free_source_relay_headers_interval
=
target_client
.free_source_relay_headers_interval
()
.await
.map_err
(|
e
|
{
log
::
warn!
(
target
:
"bridge"
,
"Failed to read free {} headers interval at {}: {:?}"
,
P
::
SourceRelayChain
::
NAME
,
P
::
TargetChain
::
NAME
,
e
,
);
FailedClient
::
Target
})
?
;
match
free_source_relay_headers_interval
{
Some
(
free_source_relay_headers_interval
)
if
free_source_relay_headers_interval
!=
0
=>
{
log
::
trace!
(
target
:
"bridge"
,
"Free {} headers interval at {}: {:?}"
,
P
::
SourceRelayChain
::
NAME
,
P
::
TargetChain
::
NAME
,
free_source_relay_headers_interval
,
);
free_source_relay_headers_interval
},
_
=>
{
log
::
warn!
(
target
:
"bridge"
,
"Invalid free {} headers interval at {}: {:?}"
,
P
::
SourceRelayChain
::
NAME
,
P
::
TargetChain
::
NAME
,
free_source_relay_headers_interval
,
);
return
Err
(
FailedClient
::
Target
)
},
}
}
else
{
// ignore - we don't need it
0
};
let
mut
submitted_heads_tracker
:
Option
<
SubmittedHeadsTracker
<
P
>>
=
None
;
futures
::
pin_mut!
(
exit_signal
);
...
...
@@ -211,7 +271,7 @@ where
log
::
warn!
(
target
:
"bridge"
,
"Failed to read best {} block: {:?}"
,
P
::
SourceRelayChain
::
NAME
,
e
);
FailedClient
::
Target
})
?
;
let
head_at_target
=
let
(
relay_of_
head_at_target
,
head_at_target
)
=
read_head_at_target
(
&
target_client
,
metrics
.as_ref
(),
&
best_target_block
)
.await
?
;
// check if our transaction has been mined
...
...
@@ -238,9 +298,9 @@ where
}
}
//
we have no active transaction and may need to update
head
s
,
but do we have something for
//
update?
let
best_finalized_relay_block
=
target_client
//
in all-headers strategy we'll be submitting para
head,
available at
//
`best_finalized_relay_block_at_target`
let
best_finalized_relay_block
_at_target
=
target_client
.best_finalized_source_relay_chain_block
(
&
best_target_block
)
.await
.map_err
(|
e
|
{
...
...
@@ -253,21 +313,56 @@ where
);
FailedClient
::
Target
})
?
;
// ..but if we only need to submit free headers, we need to submit para
// head, available at best free source relay chain header, known to the
// target chain
let
prove_at_relay_block
=
if
only_free_headers
{
match
relay_of_head_at_target
{
Some
(
relay_of_head_at_target
)
=>
{
// find last free relay chain header in the range that we are interested in
let
scan_range_begin
=
relay_of_head_at_target
.number
();
let
scan_range_end
=
best_finalized_relay_block_at_target
.number
();
if
scan_range_end
.saturating_sub
(
scan_range_begin
)
<
free_source_relay_headers_interval
{
// there are no new **free** relay chain headers in the range
log
::
trace!
(
target
:
"bridge"
,
"Waiting for new free {} headers at {}: scanned {:?}..={:?}"
,
P
::
SourceRelayChain
::
NAME
,
P
::
TargetChain
::
NAME
,
scan_range_begin
,
scan_range_end
,
);
continue
;
}
// we may submit new parachain head for free
best_finalized_relay_block_at_target
},
None
=>
{
// no parachain head at target => let's submit first one
best_finalized_relay_block_at_target
},
}
}
else
{
best_finalized_relay_block_at_target
};
// now let's check if we need to update parachain head at all
let
head_at_source
=
read_head_at_source
(
&
source_client
,
metrics
.as_ref
(),
&
best_finalized_relay_block
)
.await
?
;
read_head_at_source
(
&
source_client
,
metrics
.as_ref
(),
&
prove_at_relay_block
)
.await
?
;
let
is_update_required
=
is_update_required
::
<
P
>
(
head_at_source
,
head_at_target
,
best_finalized
_relay_block
,
prove_at
_relay_block
,
best_target_block
,
);
if
is_update_required
{
let
(
head_proof
,
head_hash
)
=
source_client
.prove_parachain_head
(
best_finalized_relay_block
)
.await
.map_err
(|
e
|
{
let
(
head_proof
,
head_hash
)
=
source_client
.prove_parachain_head
(
prove_at_relay_block
)
.await
.map_err
(|
e
|
{
log
::
warn!
(
target
:
"bridge"
,
"Failed to prove {} parachain ParaId({}) heads: {:?}"
,
...
...
@@ -283,12 +378,17 @@ where
P
::
SourceRelayChain
::
NAME
,
P
::
SourceParachain
::
PARACHAIN_ID
,
P
::
TargetChain
::
NAME
,
best_finalized
_relay_block
,
prove_at
_relay_block
,
head_hash
,
);
let
transaction_tracker
=
target_client
.submit_parachain_head_proof
(
best_finalized_relay_block
,
head_hash
,
head_proof
)
.submit_parachain_head_proof
(
prove_at_relay_block
,
head_hash
,
head_proof
,
only_free_headers
,
)
.await
.map_err
(|
e
|
{
log
::
warn!
(
...
...
@@ -311,7 +411,7 @@ where
fn
is_update_required
<
P
:
ParachainsPipeline
>
(
head_at_source
:
AvailableHeader
<
HeaderIdOf
<
P
::
SourceParachain
>>
,
head_at_target
:
Option
<
HeaderIdOf
<
P
::
SourceParachain
>>
,
best_finalized
_relay_block
_at_source
:
HeaderIdOf
<
P
::
SourceRelayChain
>
,
prove_at
_relay_block
:
HeaderIdOf
<
P
::
SourceRelayChain
>
,
best_target_block
:
HeaderIdOf
<
P
::
TargetChain
>
,
)
->
bool
where
...
...
@@ -326,7 +426,7 @@ where
P
::
SourceParachain
::
PARACHAIN_ID
,
P
::
TargetChain
::
NAME
,
P
::
SourceRelayChain
::
NAME
,
best_finalized
_relay_block
_at_source
,
prove_at
_relay_block
,
head_at_source
,
P
::
TargetChain
::
NAME
,
best_target_block
,
...
...
@@ -413,24 +513,28 @@ async fn read_head_at_source<P: ParachainsPipeline>(
}
}
/// Reads parachain head from the target client.
/// Reads parachain head from the target client. Also returns source relay chain header
/// that has been used to prove that head.
async
fn
read_head_at_target
<
P
:
ParachainsPipeline
>
(
target_client
:
&
impl
TargetClient
<
P
>
,
metrics
:
Option
<&
ParachainsLoopMetrics
>
,
at_block
:
&
HeaderIdOf
<
P
::
TargetChain
>
,
)
->
Result
<
Option
<
HeaderIdOf
<
P
::
SourceParachain
>>
,
FailedClient
>
{
)
->
Result
<
(
Option
<
HeaderIdOf
<
P
::
SourceRelayChain
>>
,
Option
<
HeaderIdOf
<
P
::
SourceParachain
>>
),
FailedClient
,
>
{
let
para_head_id
=
target_client
.parachain_head
(
*
at_block
)
.await
;
match
para_head_id
{
Ok
(
Some
(
para_head_id
))
=>
{
Ok
(
Some
(
(
relay_header_id
,
para_head_id
))
)
=>
{
if
let
Some
(
metrics
)
=
metrics
{
metrics
.update_best_parachain_block_at_target
(
ParaId
(
P
::
SourceParachain
::
PARACHAIN_ID
),
para_head_id
.number
(),
);
}
Ok
(
Some
(
para_head_id
))
Ok
(
(
Some
(
relay_header_id
),
Some
(
para_head_id
))
)
},
Ok
(
None
)
=>
Ok
(
None
),
Ok
(
None
)
=>
Ok
(
(
None
,
None
)
),
Err
(
e
)
=>
{
log
::
warn!
(
target
:
"bridge"
,
...
...
@@ -543,6 +647,7 @@ mod tests {
use
relay_substrate_client
::
test_chain
::{
TestChain
,
TestParachain
};
use
relay_utils
::{
HeaderId
,
MaybeConnectionError
};
use
sp_core
::
H256
;
use
std
::
collections
::
HashMap
;
const
PARA_10_HASH
:
ParaHash
=
H256
([
10u8
;
32
]);
const
PARA_20_HASH
:
ParaHash
=
H256
([
20u8
;
32
]);
...
...
@@ -590,14 +695,21 @@ mod tests {
#[derive(Clone,
Debug)]
struct
TestClientData
{
source_sync_status
:
Result
<
bool
,
TestError
>
,
source_head
:
Result
<
AvailableHeader
<
HeaderIdOf
<
TestParachain
>>
,
TestError
>
,
source_head
:
HashMap
<
BlockNumberOf
<
TestChain
>
,
Result
<
AvailableHeader
<
HeaderIdOf
<
TestParachain
>>
,
TestError
>
,
>
,
source_proof
:
Result
<
(),
TestError
>
,
target_free_source_relay_headers_interval
:
Result
<
Option
<
BlockNumberOf
<
TestChain
>>
,
TestError
>
,
target_best_block
:
Result
<
HeaderIdOf
<
TestChain
>
,
TestError
>
,
target_best_finalized_source_block
:
Result
<
HeaderIdOf
<
TestChain
>
,
TestError
>
,
target_head
:
Result
<
Option
<
HeaderIdOf
<
TestParachain
>>
,
TestError
>
,
#[allow(clippy::type_complexity)]
target_head
:
Result
<
Option
<
(
HeaderIdOf
<
TestChain
>
,
HeaderIdOf
<
TestParachain
>
)
>
,
TestError
>
,
target_submit_result
:
Result
<
(),
TestError
>
,
submitted_proof_at_source_relay_block
:
Option
<
HeaderIdOf
<
TestChain
>>
,
exit_signal_sender
:
Option
<
Box
<
futures
::
channel
::
mpsc
::
UnboundedSender
<
()
>>>
,
}
...
...
@@ -605,14 +717,18 @@ mod tests {
pub
fn
minimal
()
->
Self
{
TestClientData
{
source_sync_status
:
Ok
(
true
),
source_head
:
Ok
(
AvailableHeader
::
Available
(
HeaderId
(
0
,
PARA_20_HASH
))),
source_head
:
vec!
[(
0
,
Ok
(
AvailableHeader
::
Available
(
HeaderId
(
0
,
PARA_20_HASH
))))]
.into_iter
()
.collect
(),
source_proof
:
Ok
(()),
target_free_source_relay_headers_interval
:
Ok
(
None
),
target_best_block
:
Ok
(
HeaderId
(
0
,
Default
::
default
())),
target_best_finalized_source_block
:
Ok
(
HeaderId
(
0
,
Default
::
default
())),
target_head
:
Ok
(
None
),
target_submit_result
:
Ok
(()),
submitted_proof_at_source_relay_block
:
None
,
exit_signal_sender
:
None
,
}
}
...
...
@@ -649,16 +765,24 @@ mod tests {
async
fn
parachain_head
(
&
self
,
_
at_block
:
HeaderIdOf
<
TestChain
>
,
at_block
:
HeaderIdOf
<
TestChain
>
,
)
->
Result
<
AvailableHeader
<
HeaderIdOf
<
TestParachain
>>
,
TestError
>
{
self
.data
.lock
()
.await
.source_head
.clone
()
self
.data
.lock
()
.await
.source_head
.get
(
&
at_block
.0
)
.expect
(
&
format!
(
"SourceClient::parachain_head({})"
,
at_block
.0
))
.clone
()
}
async
fn
prove_parachain_head
(
&
self
,
_
at_block
:
HeaderIdOf
<
TestChain
>
,
at_block
:
HeaderIdOf
<
TestChain
>
,
)
->
Result
<
(
ParaHeadsProof
,
ParaHash
),
TestError
>
{
let
head
=
*
self
.data
.lock
()
.await
.source_head
.clone
()
?
.as_available
()
.unwrap
();
let
head_result
=
SourceClient
::
<
TestParachainsPipeline
>
::
parachain_head
(
self
,
at_block
)
.await
?
;
let
head
=
head_result
.as_available
()
.unwrap
();
let
storage_proof
=
vec!
[
head
.hash
()
.encode
()];
let
proof
=
(
ParaHeadsProof
{
storage_proof
},
head
.hash
());
self
.data
.lock
()
.await
.source_proof
.clone
()
.map
(|
_
|
proof
)
...
...
@@ -680,21 +804,29 @@ mod tests {
self
.data
.lock
()
.await
.target_best_finalized_source_block
.clone
()
}
async
fn
free_source_relay_headers_interval
(
&
self
,
)
->
Result
<
Option
<
BlockNumberOf
<
TestParachain
>>
,
TestError
>
{
self
.data
.lock
()
.await
.target_free_source_relay_headers_interval
.clone
()
}
async
fn
parachain_head
(
&
self
,
_at_block
:
HeaderIdOf
<
TestChain
>
,
)
->
Result
<
Option
<
HeaderIdOf
<
TestParachain
>>
,
TestError
>
{
)
->
Result
<
Option
<
(
HeaderIdOf
<
TestChain
>
,
HeaderIdOf
<
TestParachain
>
)
>
,
TestError
>
{
self
.data
.lock
()
.await
.target_head
.clone
()
}
async
fn
submit_parachain_head_proof
(
&
self
,
_
at_source_block
:
HeaderIdOf
<
TestChain
>
,
at_source_block
:
HeaderIdOf
<
TestChain
>
,
_updated_parachain_head
:
ParaHash
,
_proof
:
ParaHeadsProof
,
_is_free_execution_expected
:
bool
,
)
->
Result
<
TestTransactionTracker
,
Self
::
Error
>
{
let
mut
data
=
self
.data
.lock
()
.await
;
data
.target_submit_result
.clone
()
?
;
data
.submitted_proof_at_source_relay_block
=
Some
(
at_source_block
);
if
let
Some
(
mut
exit_signal_sender
)
=
data
.exit_signal_sender
.take
()
{
exit_signal_sender
.send
(())
.await
.unwrap
();
...
...
@@ -715,6 +847,7 @@ mod tests {
TestClient
::
from
(
test_source_client
),
TestClient
::
from
(
TestClientData
::
minimal
()),
None
,
false
,
futures
::
future
::
pending
(),
)),
Err
(
FailedClient
::
Source
),
...
...
@@ -731,6 +864,7 @@ mod tests {
TestClient
::
from
(
TestClientData
::
minimal
()),
TestClient
::
from
(
test_target_client
),
None
,
false
,
futures
::
future
::
pending
(),
)),
Err
(
FailedClient
::
Target
),
...
...
@@ -747,6 +881,7 @@ mod tests {
TestClient
::
from
(
TestClientData
::
minimal
()),
TestClient
::
from
(
test_target_client
),
None
,
false
,
futures
::
future
::
pending
(),
)),
Err
(
FailedClient
::
Target
),
...
...
@@ -763,6 +898,7 @@ mod tests {
TestClient
::
from
(
TestClientData
::
minimal
()),
TestClient
::
from
(
test_target_client
),
None
,
false
,
futures
::
future
::
pending
(),
)),
Err
(
FailedClient
::
Target
),
...
...
@@ -772,13 +908,14 @@ mod tests {
#[test]
fn
when_source_client_fails_to_read_heads
()
{
let
mut
test_source_client
=
TestClientData
::
minimal
();
test_source_client
.source_head
=
Err
(
TestError
::
Error
);
test_source_client
.source_head
.insert
(
0
,
Err
(
TestError
::
Error
)
)
;
assert_eq!
(
async_std
::
task
::
block_on
(
run_until_connection_lost
(
TestClient
::
from
(
test_source_client
),
TestClient
::
from
(
TestClientData
::
minimal
()),
None
,
false
,
futures
::
future
::
pending
(),
)),
Err
(
FailedClient
::
Source
),
...
...
@@ -795,6 +932,7 @@ mod tests {
TestClient
::
from
(
test_source_client
),
TestClient
::
from
(
TestClientData
::
minimal
()),
None
,
false
,
futures
::
future
::
pending
(),
)),
Err
(
FailedClient
::
Source
),
...
...
@@ -811,6 +949,7 @@ mod tests {
TestClient
::
from
(
TestClientData
::
minimal
()),
TestClient
::
from
(
test_target_client
),
None
,
false
,
futures
::
future
::
pending
(),
)),
Err
(
FailedClient
::
Target
),
...
...
@@ -825,12 +964,108 @@ mod tests {
TestClient
::
from
(
TestClientData
::
minimal
()),
TestClient
::
from
(
TestClientData
::
with_exit_signal_sender
(
exit_signal_sender
)),
None
,
false
,
exit_signal
.into_future
()
.map
(|(
_
,
_
)|
()),
)),
Ok
(()),
);
}
#[async_std::test]
async
fn
free_headers_are_relayed
()
{
// prepare following case:
// 1) best source relay at target: 95
// 2) best source parachain at target: 5 at relay 50
// 3) free headers interval: 10
// 4) at source relay chain block 90 source parachain block is 9
// +
// 5) best finalized source relay chain block is 95
// 6) at source relay chain block 95 source parachain block is 42
// =>
// parachain block 42 would have been relayed, because 95 - 50 > 10
let
(
exit_signal_sender
,
exit_signal
)
=
futures
::
channel
::
mpsc
::
unbounded
();
let
clients_data
=
TestClientData
{
source_sync_status
:
Ok
(
true
),
source_head
:
vec!
[
(
90
,
Ok
(
AvailableHeader
::
Available
(
HeaderId
(
9
,
[
9u8
;
32
]
.into
())))),
(
95
,
Ok
(
AvailableHeader
::
Available
(
HeaderId
(
42
,
[
42u8
;
32
]
.into
())))),
]
.into_iter
()
.collect
(),
source_proof
:
Ok
(()),
target_free_source_relay_headers_interval
:
Ok
(
Some
(
10
)),
target_best_block
:
Ok
(
HeaderId
(
200
,
[
200u8
;
32
]
.into
())),
target_best_finalized_source_block
:
Ok
(
HeaderId
(
95
,
[
95u8
;
32
]
.into
())),
target_head
:
Ok
(
Some
((
HeaderId
(
50
,
[
50u8
;
32
]
.into
()),
HeaderId
(
5
,
[
5u8
;
32
]
.into
())))),
target_submit_result
:
Ok
(()),
submitted_proof_at_source_relay_block
:
None
,
exit_signal_sender
:
Some
(
Box
::
new
(
exit_signal_sender
)),
};
let
source_client
=
TestClient
::
from
(
clients_data
.clone
());
let
target_client
=
TestClient
::
from
(
clients_data
);
assert_eq!
(
run_until_connection_lost
(
source_client
,
target_client
.clone
(),
None
,
true
,
exit_signal
.into_future
()
.map
(|(
_
,
_
)|
()),
)
.await
,
Ok
(()),
);
assert_eq!
(
target_client
.data
.lock
()
.await
.submitted_proof_at_source_relay_block
.map
(|
id
|
id
.0
),
Some
(
95
)
);
// now source relay block chain 104 is mined with parachain head #84
// => since 104 - 95 < 10, there are no free headers
// => nothing is submitted
let
mut
clients_data
:
TestClientData
=
target_client
.data
.lock
()
.await
.clone
();
clients_data
.source_head
.insert
(
104
,
Ok
(
AvailableHeader
::
Available
(
HeaderId
(
84
,
[
84u8
;
32
]
.into
()))));
clients_data
.target_best_finalized_source_block
=
Ok
(
HeaderId
(
104
,
[
104u8
;
32
]
.into
()));
clients_data
.target_head
=
Ok
(
Some
((
HeaderId
(
95
,
[
95u8
;
32
]
.into
()),
HeaderId
(
42
,
[
42u8
;
32
]
.into
()))));
clients_data
.target_best_block
=
Ok
(
HeaderId
(
255
,
[
255u8
;
32
]
.into
()));
clients_data
.exit_signal_sender
=
None
;
let
source_client
=
TestClient
::
from
(
clients_data
.clone
());
let
target_client
=
TestClient
::
from
(
clients_data
);
assert_eq!
(
run_until_connection_lost
(
source_client
,
target_client
.clone
(),
None
,
true
,
async_std
::
task
::
sleep
(
std
::
time
::
Duration
::
from_millis
(
100
)),
)
.await
,
Ok
(()),
);
assert_eq!
(
target_client
.data
.lock
()
.await
.submitted_proof_at_source_relay_block
.map
(|
id
|
id
.0
),
Some
(
95
)
);
}
fn
test_tx_tracker
()
->
SubmittedHeadsTracker
<
TestParachainsPipeline
>
{
SubmittedHeadsTracker
::
new
(
AvailableHeader
::
Available
(
HeaderId
(
20
,
PARA_20_HASH
)),
...
...
bridges/snowbridge/primitives/router/src/inbound/mod.rs
View file @
aceda465
...
...
@@ -273,8 +273,10 @@ where
},
None
=>
{
instructions
.extend
(
vec!
[
// Deposit asset to beneficiary.
DepositAsset
{
assets
:
Definite
(
asset
.into
()),
beneficiary
},
// Deposit both asset and fees to beneficiary so the fees will not get
// trapped. Another benefit is when fees left more than ED on AssetHub could be
// used to create the beneficiary account in case it does not exist.
DepositAsset
{
assets
:
Wild
(
AllCounted
(
2
)),
beneficiary
},
]);
},
}
...
...
bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml
View file @
aceda465
...
...
@@ -40,7 +40,7 @@ cumulus_based = true
rpc_port
=
8933
ws_port
=
8943
args
=
[
"-lparachain=debug,runtime::bridge
-hub
=trace,
runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm
=
trace
"
"-lparachain=debug,runtime::bridge=trace,
xcm=trace,txpool
=
trace
"
]
# run bob as parachain collator
...
...
@@ -51,7 +51,7 @@ cumulus_based = true
rpc_port
=
8934
ws_port
=
8944
args
=
[
"-lparachain=
trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages
=trace,
xcm
=
trace
"
"-lparachain=
debug,runtime::bridge=trace,xcm
=trace,
txpool
=
trace
"
]
[[
parachains
]]
...
...
@@ -65,14 +65,14 @@ cumulus_based = true
ws_port
=
9910
command
=
"{{POLKADOT_PARACHAIN_BINARY}}"
args
=
[
"-lparachain=debug,xcm=trace,runtime::bridge
-
tra
nsfer
=
trace
"
"-lparachain=debug,xcm=trace,runtime::bridge
=
tra
ce,txpool
=
trace
"
]
[[
parachains.collators
]]
name
=
"asset-hub-rococo-collator2"
command
=
"{{POLKADOT_PARACHAIN_BINARY}}"
args
=
[
"-lparachain=debug,xcm=trace,runtime::bridge
-
tra
nsfer
=
trace
"
"-lparachain=debug,xcm=trace,runtime::bridge
=
tra
ce,txpool
=
trace
"
]
#[[hrmp_channels]]
...
...
bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml
View file @
aceda465
...
...
@@ -40,7 +40,7 @@ cumulus_based = true
rpc_port
=
8935
ws_port
=
8945
args
=
[
"-lparachain=debug,runtime::
mmr=info,substrate=info,runtime=info,runtime::
bridge
-hub
=trace,
runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm
=
trace
"
"-lparachain=debug,runtime::bridge=trace,
xcm=trace,txpool
=
trace
"
]
# run bob as parachain collator
...
...
@@ -51,7 +51,7 @@ cumulus_based = true
rpc_port
=
8936
ws_port
=
8946
args
=
[
"-lparachain=
trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages
=trace,
xcm
=
trace
"
"-lparachain=
debug,runtime::bridge=trace,xcm
=trace,
txpool
=
trace
"
]
[[
parachains
]]
...
...
@@ -65,14 +65,14 @@ cumulus_based = true
ws_port
=
9010
command
=
"{{POLKADOT_PARACHAIN_BINARY}}"
args
=
[
"-lparachain=debug,xcm=trace,runtime::bridge
-
tra
nsfer
=
trace
"
"-lparachain=debug,xcm=trace,runtime::bridge
=
tra
ce,txpool
=
trace
"
]
[[
parachains.collators
]]
name
=
"asset-hub-westend-collator2"
command
=
"{{POLKADOT_PARACHAIN_BINARY}}"
args
=
[
"-lparachain=debug,xcm=trace,runtime::bridge
-
tra
nsfer
=
trace
"
"-lparachain=debug,xcm=trace,runtime::bridge
=
tra
ce,txpool
=
trace
"
]
#[[hrmp_channels]]
...
...
bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh
View file @
aceda465
...
...
@@ -169,12 +169,107 @@ function run_relay() {
--lane
"
${
LANE_ID
}
"
}
function
run_finality_relay
()
{
local
relayer_path
=
$(
ensure_relayer
)
RUST_LOG
=
runtime
=
trace,rpc
=
trace,bridge
=
trace
\
$relayer_path
relay-headers rococo-to-bridge-hub-westend
\
--only-free-headers
\
--source-host
localhost
\
--source-port
9942
\
--target-host
localhost
\
--target-port
8945
\
--target-version-mode
Auto
\
--target-signer
//Charlie
\
--target-transactions-mortality
4&
RUST_LOG
=
runtime
=
trace,rpc
=
trace,bridge
=
trace
\
$relayer_path
relay-headers westend-to-bridge-hub-rococo
\
--only-free-headers
\
--source-host
localhost
\
--source-port
9945
\
--target-host
localhost
\
--target-port
8943
\
--target-version-mode
Auto
\
--target-signer
//Charlie
\
--target-transactions-mortality
4
}
function
run_parachains_relay
()
{
local
relayer_path
=
$(
ensure_relayer
)
RUST_LOG
=
runtime
=
trace,rpc
=
trace,bridge
=
trace
\
$relayer_path
relay-parachains rococo-to-bridge-hub-westend
\
--only-free-headers
\
--source-host
localhost
\
--source-port
9942
\
--target-host
localhost
\
--target-port
8945
\
--target-version-mode
Auto
\
--target-signer
//Dave
\
--target-transactions-mortality
4&
RUST_LOG
=
runtime
=
trace,rpc
=
trace,bridge
=
trace
\
$relayer_path
relay-parachains westend-to-bridge-hub-rococo
\
--only-free-headers
\
--source-host
localhost
\
--source-port
9945
\
--target-host
localhost
\
--target-port
8943
\
--target-version-mode
Auto
\
--target-signer
//Dave
\
--target-transactions-mortality
4
}
function
run_messages_relay
()
{
local
relayer_path
=
$(
ensure_relayer
)
RUST_LOG
=
runtime
=
trace,rpc
=
trace,bridge
=
trace
\
$relayer_path
relay-messages bridge-hub-rococo-to-bridge-hub-westend
\
--source-host
localhost
\
--source-port
8943
\
--source-version-mode
Auto
\
--source-signer
//Eve
\
--source-transactions-mortality
4
\
--target-host
localhost
\
--target-port
8945
\
--target-version-mode
Auto
\
--target-signer
//Eve
\
--target-transactions-mortality
4
\
--lane
$LANE_ID
&
RUST_LOG
=
runtime
=
trace,rpc
=
trace,bridge
=
trace
\
$relayer_path
relay-messages bridge-hub-westend-to-bridge-hub-rococo
\
--source-host
localhost
\
--source-port
8945
\
--source-version-mode
Auto
\
--source-signer
//Ferdie
\
--source-transactions-mortality
4
\
--target-host
localhost
\
--target-port
8943
\
--target-version-mode
Auto
\
--target-signer
//Ferdie
\
--target-transactions-mortality
4
\
--lane
$LANE_ID
}
case
"
$1
"
in
run-relay
)
init_wnd_ro
init_ro_wnd
run_relay
;;
run-finality-relay
)
init_wnd_ro
init_ro_wnd
run_finality_relay
;;
run-parachains-relay
)
run_parachains_relay
;;
run-messages-relay
)
run_messages_relay
;;
init-asset-hub-rococo-local
)
ensure_polkadot_js_api
# create foreign assets for native Westend token (governance call on Rococo)
...
...
@@ -386,6 +481,9 @@ case "$1" in
echo
"A command is require. Supported commands for:
Local (zombienet) run:
- run-relay
- run-finality-relay
- run-parachains-relay
- run-messages-relay
- init-asset-hub-rococo-local
- init-bridge-hub-rococo-local
- init-asset-hub-westend-local
...
...
bridges/testing/environments/rococo-westend/explorers.sh
0 → 100755
View file @
aceda465
#!/bin/bash
# Rococo AH
xdg-open https://polkadot.js.org/apps/?rpc
=
ws://127.0.0.1:9910#/explorer&
# Rococo BH
xdg-open https://polkadot.js.org/apps/?rpc
=
ws://127.0.0.1:8943#/explorer&
# Westend BH
xdg-open https://polkadot.js.org/apps/?rpc
=
ws://127.0.0.1:8945#/explorer&
# Westend AH
xdg-open https://polkadot.js.org/apps/?rpc
=
ws://127.0.0.1:9010#/explorer&
bridges/testing/environments/rococo-westend/helper.sh
View file @
aceda465
#!/bin/bash
if
[
$1
==
"auto-log"
]
;
then
shift
# ignore "auto-log"
log_name
=
$1
$ENV_PATH
/bridges_rococo_westend.sh
"
$@
"
>
$TEST_DIR
/logs/
$log_name
.log
else
$ENV_PATH
/bridges_rococo_westend.sh
"
$@
"
fi
bridges/testing/environments/rococo-westend/spawn.sh
View file @
aceda465
...
...
@@ -59,12 +59,12 @@ if [[ $init -eq 1 ]]; then
fi
if
[[
$start_relayer
-eq
1
]]
;
then
${
BASH_SOURCE
%/*
}
/start_relayer.sh
$rococo_dir
$westend_dir
relayer_pid
${
BASH_SOURCE
%/*
}
/start_relayer.sh
$rococo_dir
$westend_dir
finality_relayer_pid parachains_relayer_pid messages_
relayer_pid
fi
echo
$rococo_dir
>
$TEST_DIR
/rococo.env
echo
$westend_dir
>
$TEST_DIR
/westend.env
echo
wait
-n
$rococo_pid
$westend_pid
$relayer_pid
wait
-n
$rococo_pid
$westend_pid
$
finality_relayer_pid
$parachains_relayer_pid
$messages_
relayer_pid
kill
-9
-
$$
Prev
1
2
3
4
5
6
7
…
17
Next