mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 06:21:02 +00:00
Read extrinsic dispatch result for mined transaction (#1582)
* read extrinsic dispatch result for mined transaction * commit for the history * Revert "commit for the history" This reverts commit 99341b04750639db296172cc1432bd70e458ef4b. * Revert "read extrinsic dispatch result for mined transaction" This reverts commit 662b776cbf992be9f1637e52f023b782e8c441d1. * check for successfult transaction in finality relay * check for successful transaction in parachains relay * TrackedTransactionStatus ->TrackedTransactionStatus<HeaderId> * check for successful transaction in messages relay * fix compilation * message_lane_loop_is_able_to_recover_from_unsuccessful_transaction * fixed too-complex-type clippy error * aaand compilation
This commit is contained in:
committed by
Bastian Köcher
parent
1abd5cb60d
commit
43afa02372
@@ -124,7 +124,7 @@ pub trait SourceClient<P: ParachainsPipeline>: RelayClient {
|
||||
#[async_trait]
|
||||
pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
|
||||
/// Transaction tracker to track submitted transactions.
|
||||
type TransactionTracker: TransactionTracker;
|
||||
type TransactionTracker: TransactionTracker<HeaderId = HeaderIdOf<P::TargetChain>>;
|
||||
|
||||
/// Get best block id.
|
||||
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error>;
|
||||
@@ -260,13 +260,13 @@ where
|
||||
|
||||
// check if our transaction has been mined
|
||||
if let Some(tracker) = submitted_heads_tracker.take() {
|
||||
match tracker.update(&heads_at_target).await {
|
||||
match tracker.update(&best_target_block, &heads_at_target).await {
|
||||
SubmittedHeadsStatus::Waiting(tracker) => {
|
||||
// no news about our transaction and we shall keep waiting
|
||||
submitted_heads_tracker = Some(tracker);
|
||||
continue
|
||||
},
|
||||
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Finalized) => {
|
||||
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Finalized(_)) => {
|
||||
// all heads have been updated, we don't need this tracker anymore
|
||||
},
|
||||
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost) => {
|
||||
@@ -529,9 +529,24 @@ 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),
|
||||
Final(TrackedTransactionStatus<HeaderIdOf<P::TargetChain>>),
|
||||
}
|
||||
|
||||
/// Type of the transaction tracker that the `SubmittedHeadsTracker` is using.
|
||||
///
|
||||
/// It needs to be shared because of `poll` macro and our consuming `update` method.
|
||||
type SharedTransactionTracker<P> = Shared<
|
||||
Pin<
|
||||
Box<
|
||||
dyn Future<
|
||||
Output = TrackedTransactionStatus<
|
||||
HeaderIdOf<<P as ParachainsPipeline>::TargetChain>,
|
||||
>,
|
||||
> + Send,
|
||||
>,
|
||||
>,
|
||||
>;
|
||||
|
||||
/// Submitted parachain heads transaction.
|
||||
struct SubmittedHeadsTracker<P: ParachainsPipeline> {
|
||||
/// Ids of parachains which heads were updated in the tracked transaction.
|
||||
@@ -541,7 +556,7 @@ struct SubmittedHeadsTracker<P: ParachainsPipeline> {
|
||||
/// Future that waits for submitted transaction finality or loss.
|
||||
///
|
||||
/// It needs to be shared because of `poll` macro and our consuming `update` method.
|
||||
transaction_tracker: Shared<Pin<Box<dyn Future<Output = TrackedTransactionStatus> + Send>>>,
|
||||
transaction_tracker: SharedTransactionTracker<P>,
|
||||
}
|
||||
|
||||
impl<P: ParachainsPipeline> SubmittedHeadsTracker<P>
|
||||
@@ -552,7 +567,7 @@ where
|
||||
pub fn new(
|
||||
awaiting_update: impl IntoIterator<Item = ParaId>,
|
||||
relay_block_number: BlockNumberOf<P::SourceChain>,
|
||||
transaction_tracker: impl TransactionTracker + 'static,
|
||||
transaction_tracker: impl TransactionTracker<HeaderId = HeaderIdOf<P::TargetChain>> + 'static,
|
||||
) -> Self {
|
||||
SubmittedHeadsTracker {
|
||||
awaiting_update: awaiting_update.into_iter().collect(),
|
||||
@@ -564,6 +579,7 @@ where
|
||||
/// Returns `None` if all submitted parachain heads have been updated.
|
||||
pub async fn update(
|
||||
mut self,
|
||||
at_target_block: &HeaderIdOf<P::TargetChain>,
|
||||
heads_at_target: &BTreeMap<ParaId, Option<BestParaHeadHash>>,
|
||||
) -> SubmittedHeadsStatus<P> {
|
||||
// remove all pending heads that were synced
|
||||
@@ -590,14 +606,23 @@ where
|
||||
|
||||
// if we have synced all required heads, we are done
|
||||
if self.awaiting_update.is_empty() {
|
||||
return SubmittedHeadsStatus::Final(TrackedTransactionStatus::Finalized)
|
||||
return SubmittedHeadsStatus::Final(TrackedTransactionStatus::Finalized(
|
||||
*at_target_block,
|
||||
))
|
||||
}
|
||||
|
||||
// if underlying transaction tracker has reported that the transaction is lost, we may
|
||||
// then restart our sync
|
||||
let transaction_tracker = self.transaction_tracker.clone();
|
||||
if let Poll::Ready(TrackedTransactionStatus::Lost) = poll!(transaction_tracker) {
|
||||
return SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost)
|
||||
match poll!(transaction_tracker) {
|
||||
Poll::Ready(TrackedTransactionStatus::Lost) =>
|
||||
return SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost),
|
||||
Poll::Ready(TrackedTransactionStatus::Finalized(_)) => {
|
||||
// so we are here and our transaction is mined+finalized, but some of heads were not
|
||||
// updated => we're considering our loop as stalled
|
||||
return SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost)
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
SubmittedHeadsStatus::Waiting(self)
|
||||
@@ -644,12 +669,17 @@ mod tests {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct TestTransactionTracker(TrackedTransactionStatus);
|
||||
struct TestTransactionTracker(Option<TrackedTransactionStatus<HeaderIdOf<TestChain>>>);
|
||||
|
||||
#[async_trait]
|
||||
impl TransactionTracker for TestTransactionTracker {
|
||||
async fn wait(self) -> TrackedTransactionStatus {
|
||||
self.0
|
||||
type HeaderId = HeaderIdOf<TestChain>;
|
||||
|
||||
async fn wait(self) -> TrackedTransactionStatus<HeaderIdOf<TestChain>> {
|
||||
match self.0 {
|
||||
Some(status) => status,
|
||||
None => futures::future::pending().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -785,7 +815,9 @@ mod tests {
|
||||
if let Some(mut exit_signal_sender) = data.exit_signal_sender.take() {
|
||||
exit_signal_sender.send(()).await.unwrap();
|
||||
}
|
||||
Ok(TestTransactionTracker(TrackedTransactionStatus::Finalized))
|
||||
Ok(TestTransactionTracker(Some(
|
||||
TrackedTransactionStatus::Finalized(Default::default()),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,10 +970,31 @@ mod tests {
|
||||
SubmittedHeadsTracker::new(
|
||||
vec![ParaId(PARA_ID), ParaId(PARA_1_ID)],
|
||||
SOURCE_BLOCK_NUMBER,
|
||||
TestTransactionTracker(TrackedTransactionStatus::Finalized),
|
||||
TestTransactionTracker(None),
|
||||
)
|
||||
}
|
||||
|
||||
fn all_expected_tracker_heads() -> BTreeMap<ParaId, Option<BestParaHeadHash>> {
|
||||
vec![
|
||||
(
|
||||
ParaId(PARA_ID),
|
||||
Some(BestParaHeadHash {
|
||||
at_relay_block_number: SOURCE_BLOCK_NUMBER,
|
||||
head_hash: PARA_0_HASH,
|
||||
}),
|
||||
),
|
||||
(
|
||||
ParaId(PARA_1_ID),
|
||||
Some(BestParaHeadHash {
|
||||
at_relay_block_number: SOURCE_BLOCK_NUMBER,
|
||||
head_hash: PARA_0_HASH,
|
||||
}),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl From<SubmittedHeadsStatus<TestParachainsPipeline>> for Option<BTreeSet<ParaId>> {
|
||||
fn from(status: SubmittedHeadsStatus<TestParachainsPipeline>) -> Option<BTreeSet<ParaId>> {
|
||||
match status {
|
||||
@@ -955,7 +1008,10 @@ mod tests {
|
||||
async fn tx_tracker_update_when_nothing_is_updated() {
|
||||
assert_eq!(
|
||||
Some(test_tx_tracker().awaiting_update),
|
||||
test_tx_tracker().update(&vec![].into_iter().collect()).await.into(),
|
||||
test_tx_tracker()
|
||||
.update(&HeaderId(0, Default::default()), &vec![].into_iter().collect())
|
||||
.await
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -965,6 +1021,7 @@ mod tests {
|
||||
Some(test_tx_tracker().awaiting_update),
|
||||
test_tx_tracker()
|
||||
.update(
|
||||
&HeaderId(0, Default::default()),
|
||||
&vec![(
|
||||
ParaId(PARA_ID),
|
||||
Some(BestParaHeadHash {
|
||||
@@ -986,6 +1043,7 @@ mod tests {
|
||||
Some(vec![ParaId(PARA_1_ID)].into_iter().collect::<BTreeSet<_>>()),
|
||||
test_tx_tracker()
|
||||
.update(
|
||||
&HeaderId(0, Default::default()),
|
||||
&vec![(
|
||||
ParaId(PARA_ID),
|
||||
Some(BestParaHeadHash {
|
||||
@@ -1006,50 +1064,52 @@ mod tests {
|
||||
assert_eq!(
|
||||
Option::<BTreeSet<_>>::None,
|
||||
test_tx_tracker()
|
||||
.update(
|
||||
&vec![
|
||||
(
|
||||
ParaId(PARA_ID),
|
||||
Some(BestParaHeadHash {
|
||||
at_relay_block_number: SOURCE_BLOCK_NUMBER,
|
||||
head_hash: PARA_0_HASH,
|
||||
})
|
||||
),
|
||||
(
|
||||
ParaId(PARA_1_ID),
|
||||
Some(BestParaHeadHash {
|
||||
at_relay_block_number: SOURCE_BLOCK_NUMBER,
|
||||
head_hash: PARA_0_HASH,
|
||||
})
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
.update(&HeaderId(0, Default::default()), &all_expected_tracker_heads())
|
||||
.await
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn tx_tracker_update_when_tx_is_stalled() {
|
||||
async fn tx_tracker_update_when_tx_is_lost() {
|
||||
let mut tx_tracker = test_tx_tracker();
|
||||
tx_tracker.transaction_tracker =
|
||||
futures::future::ready(TrackedTransactionStatus::Lost).boxed().shared();
|
||||
assert_eq!(
|
||||
Option::<BTreeSet<_>>::None,
|
||||
tx_tracker.update(&vec![].into_iter().collect()).await.into(),
|
||||
);
|
||||
assert!(matches!(
|
||||
tx_tracker
|
||||
.update(&HeaderId(0, Default::default()), &vec![].into_iter().collect())
|
||||
.await,
|
||||
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost),
|
||||
));
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn tx_tracker_update_when_tx_is_finalized() {
|
||||
async fn tx_tracker_update_when_tx_is_finalized_but_heads_are_not_updated() {
|
||||
let mut tx_tracker = test_tx_tracker();
|
||||
tx_tracker.transaction_tracker =
|
||||
futures::future::ready(TrackedTransactionStatus::Finalized).boxed().shared();
|
||||
futures::future::ready(TrackedTransactionStatus::Finalized(Default::default()))
|
||||
.boxed()
|
||||
.shared();
|
||||
assert!(matches!(
|
||||
tx_tracker.update(&vec![].into_iter().collect()).await,
|
||||
SubmittedHeadsStatus::Waiting(_),
|
||||
tx_tracker
|
||||
.update(&HeaderId(0, Default::default()), &vec![].into_iter().collect())
|
||||
.await,
|
||||
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Lost),
|
||||
));
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn tx_tracker_update_when_tx_is_finalized_and_heads_are_updated() {
|
||||
let mut tx_tracker = test_tx_tracker();
|
||||
tx_tracker.transaction_tracker =
|
||||
futures::future::ready(TrackedTransactionStatus::Finalized(Default::default()))
|
||||
.boxed()
|
||||
.shared();
|
||||
assert!(matches!(
|
||||
tx_tracker
|
||||
.update(&HeaderId(0, Default::default()), &all_expected_tracker_heads())
|
||||
.await,
|
||||
SubmittedHeadsStatus::Final(TrackedTransactionStatus::Finalized(_)),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user