Page MenuHomePhabricator

[Chronik] Add `finalization_timeout_secs` to `BroadcastTx(s)Request`
ClosedPublic

Authored by tobias_ruck on Nov 27 2025, 11:51.

Details

Summary

This is a convenience for a common usage of Avalanche, which is to broadcast a transaction and then wait for it to finalize before considering the transaction "done".

This creates a nice dev UX, where, if this call returns successfully, the transaction(s) can already be considered fully accepted, and no further status change will happen (barring something catastropic happens).

By default (0), this timeout is disabled and ignored, and the endpoint returns immediately after broadcast.

If a non-zero timeout is set, the request waits until the tx is finalized (or all txs are finalized in case there's multiple).

In case of a timeout, we return a 504 error, which normally indicates a timeout from the server side, aka. "Gateway timeout".

To limit abuse, a 120s maximum timeout is picked, which seems like a good maximal wait amount for a "pay" request (browsers usually time out HTTP requests after 5 minutes). Users that want to wait beyond this can also use the WebSocket interface.

Test Plan

./test/functional/test_runner.py chronik_broadcast_tx

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Tail of the build log:

   Compiling serde_spanned v0.6.9
   Compiling serde_path_to_error v0.1.17
   Compiling toml_datetime v0.6.11
   Compiling pyo3 v0.23.5
   Compiling ring v0.17.14
   Compiling strsim v0.11.1
   Compiling matchit v0.7.3
   Compiling toml_write v0.1.2
   Compiling base64 v0.22.1
   Compiling bech32 v0.7.3
   Compiling arrayvec v0.7.6
   Compiling hyper v0.14.32
   Compiling clap_lex v0.7.5
   Compiling qrcodegen v1.8.0
   Compiling bitcoin_hashes v0.9.7
   Compiling winnow v0.7.11
   Compiling matchit v0.5.0
   Compiling qrcode-generator v4.1.9
   Compiling clap_builder v4.5.40
   Compiling num-format v0.4.4
   Compiling askama v0.10.5
   Compiling maud v0.22.3
   Compiling axum v0.7.9
   Compiling tower-http v0.5.2
   Compiling chronik_lib v0.1.0 (/work/chronik/chronik-lib)
   Compiling clap_derive v4.5.40
   Compiling chrono-humanize v0.1.2
   Compiling toml_edit v0.22.27
   Compiling webpki-roots v1.0.1
   Compiling indoc v2.0.6
   Compiling base64 v0.13.1
   Compiling unindent v0.2.4
   Compiling avalanche-lib-wasm v0.1.0 (/work/modules/avalanche-lib-wasm)
   Compiling tokio-tungstenite v0.26.2
   Compiling bs58 v0.5.1
   Compiling pyo3-macros v0.23.5
   Compiling hyper-tls v0.5.0
   Compiling reqwest v0.11.27
   Compiling axum v0.5.17
   Compiling bitcoin v0.25.2
   Compiling clap v4.5.40
   Compiling toml v0.8.23
   Compiling proof-manager-cli v0.1.0 (/work/apps/proof-manager-cli)
   Compiling bitcoinsuite-chronik-client v0.1.0 (/work/modules/bitcoinsuite-chronik-client)
error[E0063]: missing field `finalization_timeout_secs` in initializer of `BroadcastTxRequest`
   --> modules/bitcoinsuite-chronik-client/src/lib.rs:115:23
    |
115 |         let request = proto::BroadcastTxRequest {
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `finalization_timeout_secs`

error[E0063]: missing field `finalization_timeout_secs` in initializer of `BroadcastTxsRequest`
   --> modules/bitcoinsuite-chronik-client/src/lib.rs:127:23
    |
127 |         let request = proto::BroadcastTxsRequest {
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `finalization_timeout_secs`

For more information about this error, try `rustc --explain E0063`.
error: could not compile `bitcoinsuite-chronik-client` (lib) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
Build build-explorer failed with exit code 101

add test, change http code to 504

tobias_ruck edited the test plan for this revision. (Show Details)

Tail of the build log:

    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:466:56
    |
466 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:524:56
    |
524 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:592:56
    |
592 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:650:56
    |
650 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:718:56
    |
718 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:776:56
    |
776 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:809:56
    |
809 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:845:56
    |
845 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:894:56
    |
894 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

For more information about this error, try `rustc --explain E0063`.
error: could not compile `bitcoinsuite-chronik-client` (test "websocket") due to 13 previous errors
warning: build failed, waiting for other jobs to finish...
Build build-bitcoinsuite-chronik-client failed with exit code 101

Tail of the build log:

    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:466:56
    |
466 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:524:56
    |
524 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:592:56
    |
592 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:650:56
    |
650 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:718:56
    |
718 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:776:56
    |
776 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:809:56
    |
809 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:845:56
    |
845 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:894:56
    |
894 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

For more information about this error, try `rustc --explain E0063`.
error: could not compile `bitcoinsuite-chronik-client` (test "websocket") due to 13 previous errors
warning: build failed, waiting for other jobs to finish...
Build build-bitcoinsuite-chronik-client failed with exit code 101

Tail of the build log:

    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:466:56
    |
466 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:524:56
    |
524 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:592:56
    |
592 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:650:56
    |
650 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:718:56
    |
718 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:776:56
    |
776 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:809:56
    |
809 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:845:56
    |
845 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

error[E0063]: missing field `finalization_reason` in initializer of `MsgTx`
   --> modules/bitcoinsuite-chronik-client/tests/websocket.rs:894:56
    |
894 | ...                   msg_type: Some(MsgType::Tx(MsgTx {
    |                                                  ^^^^^ missing `finalization_reason`

For more information about this error, try `rustc --explain E0063`.
error: could not compile `bitcoinsuite-chronik-client` (test "websocket") due to 13 previous errors
warning: build failed, waiting for other jobs to finish...
Build build-bitcoinsuite-chronik-client failed with exit code 101

unrebase, don't mention bitcoinsuite-chronik-client until its many issues are fixed...

Tail of the build log:

   Compiling clap_lex v0.7.5
   Compiling winnow v0.7.11
   Compiling arrayvec v0.7.6
   Compiling toml_write v0.1.2
   Compiling clap_builder v4.5.40
   Compiling num-format v0.4.4
   Compiling qrcode-generator v4.1.9
   Compiling askama v0.10.5
   Compiling maud v0.22.3
   Compiling axum v0.7.9
   Compiling tower-http v0.5.2
   Compiling clap_derive v4.5.40
   Compiling chronik_lib v0.1.0 (/work/chronik/chronik-lib)
   Compiling chrono-humanize v0.1.2
   Compiling webpki-roots v1.0.1
   Compiling base64 v0.13.1
   Compiling toml_edit v0.22.27
   Compiling unindent v0.2.4
   Compiling indoc v2.0.6
   Compiling avalanche-lib-wasm v0.1.0 (/work/modules/avalanche-lib-wasm)
   Compiling tokio-tungstenite v0.26.2
   Compiling bs58 v0.5.1
   Compiling pyo3-macros v0.23.5
   Compiling clap v4.5.40
   Compiling hyper-tls v0.5.0
   Compiling axum v0.5.17
   Compiling reqwest v0.11.27
   Compiling toml v0.8.23
   Compiling bitcoin v0.25.2
   Compiling proof-manager-cli v0.1.0 (/work/apps/proof-manager-cli)
   Compiling bitcoinsuite-chronik-client v0.1.0 (/work/modules/bitcoinsuite-chronik-client)
error[E0063]: missing field `finalization_timeout_secs` in initializer of `BroadcastTxRequest`
   --> modules/bitcoinsuite-chronik-client/src/lib.rs:115:23
    |
115 |         let request = proto::BroadcastTxRequest {
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `finalization_timeout_secs`

error[E0063]: missing field `finalization_timeout_secs` in initializer of `BroadcastTxsRequest`
   --> modules/bitcoinsuite-chronik-client/src/lib.rs:127:23
    |
127 |         let request = proto::BroadcastTxsRequest {
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `finalization_timeout_secs`

   Compiling explorer-server v0.1.0 (/work/web/explorer/explorer-server)
For more information about this error, try `rustc --explain E0063`.
error: could not compile `bitcoinsuite-chronik-client` (lib) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
warning: field `confirmations` is never read
  --> web/explorer/explorer-server/src/templating.rs:25:9
   |
22 | pub struct BlockTemplate<'a> {
   |            ------------- field in this struct
...
25 |     pub confirmations: i32,
   |         ^^^^^^^^^^^^^
   |
   = note: `#[warn(dead_code)]` on by default

warning: `explorer-server` (lib) generated 1 warning
Build build-explorer failed with exit code 101

deunrebase onto D19130, add broadcast_and_finalize_tx(s)

bytesofman added inline comments.
chronik/chronik-indexer/src/query/broadcast.rs
60 ↗(On Diff #57127)
  1. what does this look like? doesn't seem to be a test that is exactly matching this return shape
  1. Could we return the time it took to finalize? this would be useful for app devs, where we want as close to the "true" finalization time as possible, i.e. the time for this from the chronik server that broadcasts the tx is probably the "best" time vs something like an app UX that starts a timer on broadcast and stops when it hears a finalized ws msg from the server; as such a time would include latency not directly related to finalization time. Not critical but it is cool info to show on a tx confirmation screen.
Fabien added inline comments.
chronik/chronik-indexer/src/query/broadcast.rs
60 ↗(On Diff #57127)
  1. The functional test is also exercising the error cases. This structure is not returned to the user it's only used to forward the errors.
  2. If you want this to be useful for app devs, then it should be made user visible (i.e. be part of the protobuf return structure). Also please note this only applies to the txs you broadcast yourself so this is a limited use case. IMO this could be discussed but is out of scope for this diff.
This revision is now accepted and ready to land.Mon, Dec 15, 10:00
chronik/chronik-indexer/src/query/broadcast.rs
60 ↗(On Diff #57127)
  1. this is just a helper struct that is returned internally after broadcast
  2. what's the point of that? The client can just measure how long the entire HTTP request took. That's a more useful measure anyway