Summary
blockchain.transaction.get(tx_hash, true) currently returns:
{"code":-32603,"message":"verbose transactions are currently unsupported"}
Implement verbose transaction lookup using a Bitcoin Core-compatible response, with the confirming block height exposed as an electrs extension.
Motivation
Some clients are given a transaction ID and an address associated with that transaction and need to determine whether it is confirmed and, if so, its confirming block height.
The Electrum 1.4 workflow is to derive the address's script hash, call blockchain.scripthash.get_history, find the transaction, and optionally verify it with blockchain.transaction.get_merkle.
This breaks down for very active addresses because get_history can fail with Too many history entries, even with a high --electrum-txs-limit. Raising the limit further is not robust: a lookup for one transaction becomes proportional to the address's entire history.
blockchain.transaction.get_merkle(tx_hash, height) verifies a candidate height but cannot discover it. electrs already has a direct indexed lookup for this information:
self.query.chain().tx_confirming_block(&txid)
Proposed response
Keep verbose=false unchanged and continue returning raw transaction hex.
For verbose=true, return the Bitcoin Core getrawtransaction(txid, true) object and add a namespaced electrs extension:
{
"txid": "<txid>",
"hash": "<wtxid>",
"version": 2,
"size": 194,
"vsize": 113,
"weight": 449,
"locktime": 0,
"vin": [],
"vout": [],
"hex": "<raw transaction>",
"blockhash": "<confirming block hash>",
"confirmations": 10,
"blocktime": 1234567890,
"time": 1234567890,
"electrs": {
"confirmed": true,
"block_height": 962126
}
}
For a known mempool transaction:
{
"txid": "<txid>",
"hex": "<raw transaction>",
"electrs": {
"confirmed": false,
"block_height": null
}
}
An unknown transaction should continue to return a missing-transaction error. Looking up the raw transaction first distinguishes an unknown transaction from a known unconfirmed transaction when tx_confirming_block() returns None.
Compatibility
The Electrum protocol defines the verbose=true result as the daemon-specific verbose transaction dictionary. Preserving Bitcoin Core's existing fields and meanings maintains that contract.
Putting additional fields under electrs makes the implementation-specific extension explicit, avoids collisions with current or future Bitcoin Core fields, and leaves room for future electrs-specific metadata. Existing clients can ignore the additional object.
A top-level block_height field would be simpler, but namespacing appears safer for compatibility.
Existing implementation in romanz/electrs
Current romanz/electrs already implements the core verbose lookup behavior:
transaction_get() in romanz/electrs
For verbose=true, it looks up the transaction in the electrs index, obtains the confirming block hash when confirmed, supplies that block hash to the daemon, and returns Bitcoin Core's verbose transaction response:
if verbose {
let blockhash = self
.tracker
.lookup_transaction(txid)?
.map(|(blockhash, _tx)| blockhash);
return self.daemon.get_transaction(&txid, blockhash, verbose);
}
This avoids requiring Bitcoin Core's global txindex for confirmed transactions. The proposed implementation here could follow the same approach, then add the height already known by electrs. The romanz/electrs implementation does not currently add block_height; that is the additional behavior proposed in this issue.
Implementation outline
- Use
tx_confirming_block() to determine confirmation status, height, and block hash.
- For a confirmed transaction, request
getrawtransaction(txid, true, blockhash) from Bitcoin Core. Supplying electrs's indexed block hash avoids requiring Bitcoin Core's global txindex.
- For a mempool transaction, request the normal verbose transaction response.
- Add the
electrs object before returning the response.
Constructing the verbose object locally would avoid another daemon RPC, but matching Bitcoin Core's response accurately would be more complex, particularly for Liquid/Elements builds.
Relationship to Electrum Protocol 1.7
Electrum Protocol 1.7 proposes blockchain.outpoint.get_status, which returns funder_height and addresses this use case when the output index and scriptPubKey are known. Protocol 1.7 support is tracked in #231.
Verbose transaction support remains useful independently because:
- deployed clients and servers still commonly negotiate protocol 1.4;
- the query is naturally TXID-oriented;
- clients may not yet know the matching output index;
- it avoids fetching the complete history of a high-activity address;
romanz/electrs already demonstrates a practical implementation using the existing index and Bitcoin Core's verbose response.
This can provide a backward-compatible near-term solution while #231 tracks the broader protocol upgrade.
Summary
blockchain.transaction.get(tx_hash, true)currently returns:{"code":-32603,"message":"verbose transactions are currently unsupported"}Implement verbose transaction lookup using a Bitcoin Core-compatible response, with the confirming block height exposed as an electrs extension.
Motivation
Some clients are given a transaction ID and an address associated with that transaction and need to determine whether it is confirmed and, if so, its confirming block height.
The Electrum 1.4 workflow is to derive the address's script hash, call
blockchain.scripthash.get_history, find the transaction, and optionally verify it withblockchain.transaction.get_merkle.This breaks down for very active addresses because
get_historycan fail withToo many history entries, even with a high--electrum-txs-limit. Raising the limit further is not robust: a lookup for one transaction becomes proportional to the address's entire history.blockchain.transaction.get_merkle(tx_hash, height)verifies a candidate height but cannot discover it. electrs already has a direct indexed lookup for this information:Proposed response
Keep
verbose=falseunchanged and continue returning raw transaction hex.For
verbose=true, return the Bitcoin Coregetrawtransaction(txid, true)object and add a namespaced electrs extension:{ "txid": "<txid>", "hash": "<wtxid>", "version": 2, "size": 194, "vsize": 113, "weight": 449, "locktime": 0, "vin": [], "vout": [], "hex": "<raw transaction>", "blockhash": "<confirming block hash>", "confirmations": 10, "blocktime": 1234567890, "time": 1234567890, "electrs": { "confirmed": true, "block_height": 962126 } }For a known mempool transaction:
{ "txid": "<txid>", "hex": "<raw transaction>", "electrs": { "confirmed": false, "block_height": null } }An unknown transaction should continue to return a missing-transaction error. Looking up the raw transaction first distinguishes an unknown transaction from a known unconfirmed transaction when
tx_confirming_block()returnsNone.Compatibility
The Electrum protocol defines the
verbose=trueresult as the daemon-specific verbose transaction dictionary. Preserving Bitcoin Core's existing fields and meanings maintains that contract.Putting additional fields under
electrsmakes the implementation-specific extension explicit, avoids collisions with current or future Bitcoin Core fields, and leaves room for future electrs-specific metadata. Existing clients can ignore the additional object.A top-level
block_heightfield would be simpler, but namespacing appears safer for compatibility.Existing implementation in
romanz/electrsCurrent
romanz/electrsalready implements the core verbose lookup behavior:transaction_get()in romanz/electrsFor
verbose=true, it looks up the transaction in the electrs index, obtains the confirming block hash when confirmed, supplies that block hash to the daemon, and returns Bitcoin Core's verbose transaction response:This avoids requiring Bitcoin Core's global
txindexfor confirmed transactions. The proposed implementation here could follow the same approach, then add the height already known by electrs. Theromanz/electrsimplementation does not currently addblock_height; that is the additional behavior proposed in this issue.Implementation outline
tx_confirming_block()to determine confirmation status, height, and block hash.getrawtransaction(txid, true, blockhash)from Bitcoin Core. Supplying electrs's indexed block hash avoids requiring Bitcoin Core's globaltxindex.electrsobject before returning the response.Constructing the verbose object locally would avoid another daemon RPC, but matching Bitcoin Core's response accurately would be more complex, particularly for Liquid/Elements builds.
Relationship to Electrum Protocol 1.7
Electrum Protocol 1.7 proposes
blockchain.outpoint.get_status, which returnsfunder_heightand addresses this use case when the output index and scriptPubKey are known. Protocol 1.7 support is tracked in #231.Verbose transaction support remains useful independently because:
romanz/electrsalready demonstrates a practical implementation using the existing index and Bitcoin Core's verbose response.This can provide a backward-compatible near-term solution while #231 tracks the broader protocol upgrade.