mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 08:41:02 +00:00
use transaction tracker in parachains relay (#1575)
* use transaction tracker in parachains relay * actually return tx tracker from target client implementation
This commit is contained in:
committed by
Bastian Köcher
parent
6ab6a876a1
commit
86be60ad40
@@ -34,7 +34,7 @@ use parachains_relay::{
|
|||||||
use relay_substrate_client::{
|
use relay_substrate_client::{
|
||||||
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf,
|
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf,
|
||||||
HeaderIdOf, HeaderOf, RelayChain, SignParam, TransactionEra, TransactionSignScheme,
|
HeaderIdOf, HeaderOf, RelayChain, SignParam, TransactionEra, TransactionSignScheme,
|
||||||
UnsignedTransaction,
|
TransactionTracker, UnsignedTransaction,
|
||||||
};
|
};
|
||||||
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
||||||
use sp_core::{Bytes, Pair};
|
use sp_core::{Bytes, Pair};
|
||||||
@@ -86,6 +86,8 @@ where
|
|||||||
P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
|
P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
|
||||||
AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TransactionSignScheme> as Pair>::Public>,
|
AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TransactionSignScheme> as Pair>::Public>,
|
||||||
{
|
{
|
||||||
|
type TransactionTracker = TransactionTracker<P::TargetChain>;
|
||||||
|
|
||||||
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error> {
|
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error> {
|
||||||
let best_header = self.client.best_header().await?;
|
let best_header = self.client.best_header().await?;
|
||||||
let best_id = best_header.id();
|
let best_id = best_header.id();
|
||||||
@@ -172,7 +174,7 @@ where
|
|||||||
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
||||||
updated_parachains: Vec<(ParaId, ParaHash)>,
|
updated_parachains: Vec<(ParaId, ParaHash)>,
|
||||||
proof: ParaHeadsProof,
|
proof: ParaHeadsProof,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<Self::TransactionTracker, Self::Error> {
|
||||||
let genesis_hash = *self.client.genesis_hash();
|
let genesis_hash = *self.client.genesis_hash();
|
||||||
let transaction_params = self.transaction_params.clone();
|
let transaction_params = self.transaction_params.clone();
|
||||||
let (spec_version, transaction_version) = self.client.simple_runtime_version().await?;
|
let (spec_version, transaction_version) = self.client.simple_runtime_version().await?;
|
||||||
@@ -182,7 +184,7 @@ where
|
|||||||
proof,
|
proof,
|
||||||
);
|
);
|
||||||
self.client
|
self.client
|
||||||
.submit_signed_extrinsic(
|
.submit_and_watch_signed_extrinsic(
|
||||||
self.transaction_params.signer.public().into(),
|
self.transaction_params.signer.public().into(),
|
||||||
SignParam::<P::TransactionSignScheme> {
|
SignParam::<P::TransactionSignScheme> {
|
||||||
spec_version,
|
spec_version,
|
||||||
@@ -196,6 +198,5 @@ where
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(drop)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,13 +22,21 @@ use bp_polkadot_core::{
|
|||||||
parachains::{ParaHash, ParaHeadsProof, ParaId},
|
parachains::{ParaHash, ParaHeadsProof, ParaId},
|
||||||
BlockNumber as RelayBlockNumber,
|
BlockNumber as RelayBlockNumber,
|
||||||
};
|
};
|
||||||
use futures::{future::FutureExt, select};
|
use futures::{
|
||||||
|
future::{FutureExt, Shared},
|
||||||
|
poll, select,
|
||||||
|
};
|
||||||
use relay_substrate_client::{BlockNumberOf, Chain, HeaderIdOf};
|
use relay_substrate_client::{BlockNumberOf, Chain, HeaderIdOf};
|
||||||
use relay_utils::{metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient};
|
use relay_utils::{
|
||||||
|
metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient,
|
||||||
|
TrackedTransactionStatus, TransactionTracker,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
future::Future,
|
future::Future,
|
||||||
time::{Duration, Instant},
|
pin::Pin,
|
||||||
|
task::Poll,
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parachain heads synchronization params.
|
/// Parachain heads synchronization params.
|
||||||
@@ -115,6 +123,9 @@ pub trait SourceClient<P: ParachainsPipeline>: RelayClient {
|
|||||||
/// Target client used in parachain heads synchronization loop.
|
/// Target client used in parachain heads synchronization loop.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
|
pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
|
||||||
|
/// Transaction tracker to track submitted transactions.
|
||||||
|
type TransactionTracker: TransactionTracker;
|
||||||
|
|
||||||
/// Get best block id.
|
/// Get best block id.
|
||||||
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error>;
|
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error>;
|
||||||
|
|
||||||
@@ -141,7 +152,7 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
|
|||||||
at_source_block: HeaderIdOf<P::SourceChain>,
|
at_source_block: HeaderIdOf<P::SourceChain>,
|
||||||
updated_parachains: Vec<(ParaId, ParaHash)>,
|
updated_parachains: Vec<(ParaId, ParaHash)>,
|
||||||
proof: ParaHeadsProof,
|
proof: ParaHeadsProof,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<Self::TransactionTracker, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return prefix that will be used by default to expose Prometheus metrics of the parachains
|
/// Return prefix that will be used by default to expose Prometheus metrics of the parachains
|
||||||
@@ -196,7 +207,7 @@ where
|
|||||||
P::TargetChain::AVERAGE_BLOCK_INTERVAL,
|
P::TargetChain::AVERAGE_BLOCK_INTERVAL,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut tx_tracker: Option<TransactionTracker<P>> = None;
|
let mut submitted_heads_tracker: Option<SubmittedHeadsTracker<P>> = None;
|
||||||
|
|
||||||
futures::pin_mut!(exit_signal);
|
futures::pin_mut!(exit_signal);
|
||||||
|
|
||||||
@@ -246,9 +257,29 @@ where
|
|||||||
&sync_params.parachains,
|
&sync_params.parachains,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
tx_tracker = tx_tracker.take().and_then(|tx_tracker| tx_tracker.update(&heads_at_target));
|
|
||||||
if tx_tracker.is_some() {
|
// check if our transaction has been mined
|
||||||
|
if let Some(tracker) = submitted_heads_tracker.take() {
|
||||||
|
match tracker.update(&heads_at_target).await {
|
||||||
|
SubmittedHeadsStatus::Waiting(tracker) => {
|
||||||
|
// no news about our transaction and we shall keep waiting
|
||||||
|
submitted_heads_tracker = Some(tracker);
|
||||||
continue
|
continue
|
||||||
|
},
|
||||||
|
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Finalized) => {
|
||||||
|
// all heads have been updated, we don't need this tracker anymore
|
||||||
|
},
|
||||||
|
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost) => {
|
||||||
|
log::warn!(
|
||||||
|
target: "bridge",
|
||||||
|
"Parachains synchronization from {} to {} has stalled. Going to restart",
|
||||||
|
P::SourceChain::NAME,
|
||||||
|
P::TargetChain::NAME,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(FailedClient::Both)
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have no active transaction and may need to update heads, but do we have something for
|
// we have no active transaction and may need to update heads, but do we have something for
|
||||||
@@ -317,7 +348,7 @@ where
|
|||||||
"Incorrect parachains SourceClient implementation"
|
"Incorrect parachains SourceClient implementation"
|
||||||
);
|
);
|
||||||
|
|
||||||
target_client
|
let transaction_tracker = target_client
|
||||||
.submit_parachain_heads_proof(
|
.submit_parachain_heads_proof(
|
||||||
best_finalized_relay_block,
|
best_finalized_relay_block,
|
||||||
updated_ids.iter().cloned().zip(head_hashes).collect(),
|
updated_ids.iter().cloned().zip(head_hashes).collect(),
|
||||||
@@ -334,11 +365,10 @@ where
|
|||||||
);
|
);
|
||||||
FailedClient::Target
|
FailedClient::Target
|
||||||
})?;
|
})?;
|
||||||
|
submitted_heads_tracker = Some(SubmittedHeadsTracker::<P>::new(
|
||||||
tx_tracker = Some(TransactionTracker::<P>::new(
|
|
||||||
updated_ids,
|
updated_ids,
|
||||||
best_finalized_relay_block.0,
|
best_finalized_relay_block.0,
|
||||||
sync_params.stall_timeout,
|
transaction_tracker,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,19 +524,27 @@ async fn read_heads_at_target<P: ParachainsPipeline>(
|
|||||||
Ok(para_best_head_hashes)
|
Ok(para_best_head_hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parachain heads transaction tracker.
|
/// Submitted heads status.
|
||||||
struct TransactionTracker<P: ParachainsPipeline> {
|
enum SubmittedHeadsStatus<P: ParachainsPipeline> {
|
||||||
|
/// Heads are not yet updated.
|
||||||
|
Waiting(SubmittedHeadsTracker<P>),
|
||||||
|
/// Heads transaction has either been finalized or lost (i.e. received its "final" status).
|
||||||
|
Final(TrackedTransactionStatus),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submitted parachain heads transaction.
|
||||||
|
struct SubmittedHeadsTracker<P: ParachainsPipeline> {
|
||||||
/// Ids of parachains which heads were updated in the tracked transaction.
|
/// Ids of parachains which heads were updated in the tracked transaction.
|
||||||
awaiting_update: BTreeSet<ParaId>,
|
awaiting_update: BTreeSet<ParaId>,
|
||||||
/// Number of relay chain block that has been used to craft parachain heads proof.
|
/// Number of relay chain block that has been used to craft parachain heads proof.
|
||||||
relay_block_number: BlockNumberOf<P::SourceChain>,
|
relay_block_number: BlockNumberOf<P::SourceChain>,
|
||||||
/// Transaction submit time.
|
/// Future that waits for submitted transaction finality or loss.
|
||||||
submitted_at: Instant,
|
///
|
||||||
/// Transaction death time.
|
/// It needs to be shared because of `poll` macro and our consuming `update` method.
|
||||||
death_time: Instant,
|
transaction_tracker: Shared<Pin<Box<dyn Future<Output = TrackedTransactionStatus> + Send>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: ParachainsPipeline> TransactionTracker<P>
|
impl<P: ParachainsPipeline> SubmittedHeadsTracker<P>
|
||||||
where
|
where
|
||||||
P::SourceChain: Chain<BlockNumber = RelayBlockNumber>,
|
P::SourceChain: Chain<BlockNumber = RelayBlockNumber>,
|
||||||
{
|
{
|
||||||
@@ -514,22 +552,20 @@ where
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
awaiting_update: impl IntoIterator<Item = ParaId>,
|
awaiting_update: impl IntoIterator<Item = ParaId>,
|
||||||
relay_block_number: BlockNumberOf<P::SourceChain>,
|
relay_block_number: BlockNumberOf<P::SourceChain>,
|
||||||
stall_timeout: Duration,
|
transaction_tracker: impl TransactionTracker + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let now = Instant::now();
|
SubmittedHeadsTracker {
|
||||||
TransactionTracker {
|
|
||||||
awaiting_update: awaiting_update.into_iter().collect(),
|
awaiting_update: awaiting_update.into_iter().collect(),
|
||||||
relay_block_number,
|
relay_block_number,
|
||||||
submitted_at: now,
|
transaction_tracker: transaction_tracker.wait().fuse().boxed().shared(),
|
||||||
death_time: now + stall_timeout,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `None` if all parachain heads have been updated or we consider our transaction dead.
|
/// Returns `None` if all submitted parachain heads have been updated.
|
||||||
pub fn update(
|
pub async fn update(
|
||||||
mut self,
|
mut self,
|
||||||
heads_at_target: &BTreeMap<ParaId, Option<BestParaHeadHash>>,
|
heads_at_target: &BTreeMap<ParaId, Option<BestParaHeadHash>>,
|
||||||
) -> Option<Self> {
|
) -> SubmittedHeadsStatus<P> {
|
||||||
// remove all pending heads that were synced
|
// remove all pending heads that were synced
|
||||||
for (para, best_para_head) in heads_at_target {
|
for (para, best_para_head) in heads_at_target {
|
||||||
if best_para_head
|
if best_para_head
|
||||||
@@ -554,23 +590,17 @@ where
|
|||||||
|
|
||||||
// if we have synced all required heads, we are done
|
// if we have synced all required heads, we are done
|
||||||
if self.awaiting_update.is_empty() {
|
if self.awaiting_update.is_empty() {
|
||||||
return None
|
return SubmittedHeadsStatus::Final(TrackedTransactionStatus::Finalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if our transaction is dead now, we may start over again
|
// if underlying transaction tracker has reported that the transaction is lost, we may
|
||||||
let now = Instant::now();
|
// then restart our sync
|
||||||
if now >= self.death_time {
|
let transaction_tracker = self.transaction_tracker.clone();
|
||||||
log::warn!(
|
if let Poll::Ready(TrackedTransactionStatus::Lost) = poll!(transaction_tracker) {
|
||||||
target: "bridge",
|
return SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost)
|
||||||
"Parachain heads update transaction {} has been lost: no updates for {}s",
|
|
||||||
P::TargetChain::NAME,
|
|
||||||
(now - self.submitted_at).as_secs(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(self)
|
SubmittedHeadsStatus::Waiting(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,6 +643,16 @@ mod tests {
|
|||||||
data: Arc<Mutex<TestClientData>>,
|
data: Arc<Mutex<TestClientData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct TestTransactionTracker(TrackedTransactionStatus);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl TransactionTracker for TestTransactionTracker {
|
||||||
|
async fn wait(self) -> TrackedTransactionStatus {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct TestClientData {
|
struct TestClientData {
|
||||||
source_sync_status: Result<bool, TestError>,
|
source_sync_status: Result<bool, TestError>,
|
||||||
@@ -711,6 +751,8 @@ mod tests {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl TargetClient<TestParachainsPipeline> for TestClient {
|
impl TargetClient<TestParachainsPipeline> for TestClient {
|
||||||
|
type TransactionTracker = TestTransactionTracker;
|
||||||
|
|
||||||
async fn best_block(&self) -> Result<HeaderIdOf<TestChain>, TestError> {
|
async fn best_block(&self) -> Result<HeaderIdOf<TestChain>, TestError> {
|
||||||
self.data.lock().await.target_best_block.clone()
|
self.data.lock().await.target_best_block.clone()
|
||||||
}
|
}
|
||||||
@@ -736,13 +778,14 @@ mod tests {
|
|||||||
_at_source_block: HeaderIdOf<TestChain>,
|
_at_source_block: HeaderIdOf<TestChain>,
|
||||||
_updated_parachains: Vec<(ParaId, ParaHash)>,
|
_updated_parachains: Vec<(ParaId, ParaHash)>,
|
||||||
_proof: ParaHeadsProof,
|
_proof: ParaHeadsProof,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<TestTransactionTracker, Self::Error> {
|
||||||
self.data.lock().await.target_submit_result.clone()?;
|
let mut data = self.data.lock().await;
|
||||||
|
data.target_submit_result.clone()?;
|
||||||
|
|
||||||
if let Some(mut exit_signal_sender) = self.data.lock().await.exit_signal_sender.take() {
|
if let Some(mut exit_signal_sender) = data.exit_signal_sender.take() {
|
||||||
exit_signal_sender.send(()).await.unwrap();
|
exit_signal_sender.send(()).await.unwrap();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(TestTransactionTracker(TrackedTransactionStatus::Finalized))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,27 +934,35 @@ mod tests {
|
|||||||
const PARA_1_ID: u32 = PARA_ID + 1;
|
const PARA_1_ID: u32 = PARA_ID + 1;
|
||||||
const SOURCE_BLOCK_NUMBER: u32 = 100;
|
const SOURCE_BLOCK_NUMBER: u32 = 100;
|
||||||
|
|
||||||
fn test_tx_tracker() -> TransactionTracker<TestParachainsPipeline> {
|
fn test_tx_tracker() -> SubmittedHeadsTracker<TestParachainsPipeline> {
|
||||||
TransactionTracker::new(
|
SubmittedHeadsTracker::new(
|
||||||
vec![ParaId(PARA_ID), ParaId(PARA_1_ID)],
|
vec![ParaId(PARA_ID), ParaId(PARA_1_ID)],
|
||||||
SOURCE_BLOCK_NUMBER,
|
SOURCE_BLOCK_NUMBER,
|
||||||
Duration::from_secs(1),
|
TestTransactionTracker(TrackedTransactionStatus::Finalized),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
impl From<SubmittedHeadsStatus<TestParachainsPipeline>> for Option<BTreeSet<ParaId>> {
|
||||||
fn tx_tracker_update_when_nothing_is_updated() {
|
fn from(status: SubmittedHeadsStatus<TestParachainsPipeline>) -> Option<BTreeSet<ParaId>> {
|
||||||
|
match status {
|
||||||
|
SubmittedHeadsStatus::Waiting(tracker) => Some(tracker.awaiting_update),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn tx_tracker_update_when_nothing_is_updated() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_tx_tracker()
|
|
||||||
.update(&vec![].into_iter().collect())
|
|
||||||
.map(|t| t.awaiting_update),
|
|
||||||
Some(test_tx_tracker().awaiting_update),
|
Some(test_tx_tracker().awaiting_update),
|
||||||
|
test_tx_tracker().update(&vec![].into_iter().collect()).await.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[async_std::test]
|
||||||
fn tx_tracker_update_when_one_of_heads_is_updated_to_previous_value() {
|
async fn tx_tracker_update_when_one_of_heads_is_updated_to_previous_value() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Some(test_tx_tracker().awaiting_update),
|
||||||
test_tx_tracker()
|
test_tx_tracker()
|
||||||
.update(
|
.update(
|
||||||
&vec![(
|
&vec![(
|
||||||
@@ -924,14 +975,15 @@ mod tests {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect()
|
.collect()
|
||||||
)
|
)
|
||||||
.map(|t| t.awaiting_update),
|
.await
|
||||||
Some(test_tx_tracker().awaiting_update),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[async_std::test]
|
||||||
fn tx_tracker_update_when_one_of_heads_is_updated() {
|
async fn tx_tracker_update_when_one_of_heads_is_updated() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Some(vec![ParaId(PARA_1_ID)].into_iter().collect::<BTreeSet<_>>()),
|
||||||
test_tx_tracker()
|
test_tx_tracker()
|
||||||
.update(
|
.update(
|
||||||
&vec![(
|
&vec![(
|
||||||
@@ -944,14 +996,15 @@ mod tests {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect()
|
.collect()
|
||||||
)
|
)
|
||||||
.map(|t| t.awaiting_update),
|
.await
|
||||||
Some(vec![ParaId(PARA_1_ID)].into_iter().collect()),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[async_std::test]
|
||||||
fn tx_tracker_update_when_all_heads_are_updated() {
|
async fn tx_tracker_update_when_all_heads_are_updated() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Option::<BTreeSet<_>>::None,
|
||||||
test_tx_tracker()
|
test_tx_tracker()
|
||||||
.update(
|
.update(
|
||||||
&vec![
|
&vec![
|
||||||
@@ -973,21 +1026,33 @@ mod tests {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect()
|
.collect()
|
||||||
)
|
)
|
||||||
.map(|t| t.awaiting_update),
|
.await
|
||||||
None,
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[async_std::test]
|
||||||
fn tx_tracker_update_when_tx_is_stalled() {
|
async fn tx_tracker_update_when_tx_is_stalled() {
|
||||||
let mut tx_tracker = test_tx_tracker();
|
let mut tx_tracker = test_tx_tracker();
|
||||||
tx_tracker.death_time = Instant::now();
|
tx_tracker.transaction_tracker =
|
||||||
|
futures::future::ready(TrackedTransactionStatus::Lost).boxed().shared();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tx_tracker.update(&vec![].into_iter().collect()).map(|t| t.awaiting_update),
|
Option::<BTreeSet<_>>::None,
|
||||||
None,
|
tx_tracker.update(&vec![].into_iter().collect()).await.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn tx_tracker_update_when_tx_is_finalized() {
|
||||||
|
let mut tx_tracker = test_tx_tracker();
|
||||||
|
tx_tracker.transaction_tracker =
|
||||||
|
futures::future::ready(TrackedTransactionStatus::Finalized).boxed().shared();
|
||||||
|
assert!(matches!(
|
||||||
|
tx_tracker.update(&vec![].into_iter().collect()).await,
|
||||||
|
SubmittedHeadsStatus::Waiting(_),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parachain_is_not_updated_if_it_is_unknown_to_both_clients() {
|
fn parachain_is_not_updated_if_it_is_unknown_to_both_clients() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in New Issue
Block a user