If I submit a transaction via "author_submitAndWatchExtrinsic", I start getting back TransactionStatus updates, which look like one of these:

pub enum TransactionStatus<Hash, BlockHash> {
    /// Transaction is part of the future queue.
    /// Transaction is part of the ready queue.
    /// The transaction has been broadcast to the given peers.
    /// Transaction has been included in block with given hash
    /// at the given position.
    #[serde(with = "v1_compatible")]
    InBlock((BlockHash, TxIndex)),
    /// The block this transaction was included in has been retracted.
    /// Maximum number of finality watchers has been reached,
    /// old watchers are being removed.
    /// Transaction has been finalized by a finality-gadget, e.g GRANDPA.
    #[serde(with = "v1_compatible")]
    Finalized((BlockHash, TxIndex)),
    /// Transaction has been replaced in the pool, by another transaction
    /// that provides the same tags. (e.g. same (sender, nonce)).
    /// Transaction has been dropped from the pool because of the limit.
    /// Transaction is no longer valid in the current state.

(see https://github.com/paritytech/substrate/blob/4bf67fb3dc0f095e4210b5ebc5f1f2ea24bf36c0/client/transaction-pool/api/src/lib.rs#L107)

The docs above this enum state:

/// The stream is considered finished only when either `Finalized` or `FinalityTimeout`
/// event is triggered. You are however free to unsubscribe from notifications at any point.

So my questions are:

  1. Will I always eventually receive either a Finalized or FinalityTimeout notification for some transaction I submit (even if it becomes Invalid, say)?
  2. If the answer is "no" to the above: Would I be right to assume that the last TransactionStatus received before the stream is dropped is indicative of what happened to the transaction (ie perhaps it became Invalid or whatever).
  3. If I set a fixed mortality on some transaction, will it lead to the subscription being ended sooner (either with Finalized or FinalityTimeout or perhaps just with Invalid)?

Ultimately, I am asking these with this Subxt logic in mind, and want to see if there is any way to improve it: https://github.com/paritytech/subxt/blob/42bcddeecb39db98e711075b44331d24a8fbeb4d/subxt/src/tx/tx_progress.rs#L102

1 Answer 1


I have made an investigation, and find something interesting. The Stream trait implemented for TxProgress will end only when the event FinalityTimeout or Finalized received. But I found the RPC server of substrate will remove subscribers when the usurped, invalid, dropped, finalized or finality_timeout received. So I'm curious whether TxProgress would drop the connection and stop waiting for new events?

Please find below some relevant code snippets:


Below is Listener, the server side corresponding to the client of subscribition. It will fire a event when the transaction status changed, and it will close the connection if h.is_done() returns true. You could find the code here

impl<H: hash::Hash + traits::Member + Serialize, C: ChainApi> Listener<H, C> {
    fn fire<F>(&mut self, hash: &H, fun: F)
        F: FnOnce(&mut watcher::Sender<H, ExtrinsicHash<C>>),
        let clean = if let Some(h) = self.watchers.get_mut(hash) {
        } else {

        if clean {

And h is a instance of Sender. It's method is_done returns true if is_finalized is true, or it's subscribers is empty.

pub fn is_done(&self) -> bool {
        self.is_finalized || self.receivers.is_empty()

And you could find relevent codes here, the Sender will change is_finalized to true, if the event is usurped, finalized, finality_timeout, invalid or dropped.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.