Skip to content

Commit 26d4f01

Browse files
committed
Don't get verbose transaction for getTransactionConfirmations
As Esplora/Electrs doesn't support verbose transactions details in the response, that would contain the confirmations number we need to workaround it. (See: Blockstream/electrs#36) The workaround: 1. Get the raw transaction 2. Deserialize the raw transaction 3. Find transaction block height by finding it in a history of transactions for the output script included in the transaction. 4. Get the latest block height 5. Calculate number of confirmations by subtracting the transaction block height from the latest block height and adding one.
1 parent e95ab1f commit 26d4f01

File tree

1 file changed

+71
-5
lines changed

1 file changed

+71
-5
lines changed

typescript/src/electrum.ts

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,81 @@ export class Client implements BitcoinClient {
203203
getTransactionConfirmations(
204204
transactionHash: TransactionHash
205205
): Promise<number> {
206+
// We cannot use `blockchain_transaction_get` with `verbose = true` argument
207+
// to get the the transaction details as Esplora/Electrs doesn't support verbose
208+
// transactions.
209+
// See: https://github.com/Blockstream/electrs/pull/36
210+
206211
return this.withElectrum<number>(async (electrum: any) => {
207-
const transaction = await electrum.blockchain_transaction_get(
212+
const rawTransaction: string = await electrum.blockchain_transaction_get(
208213
transactionHash.toString(),
209-
true
214+
false
210215
)
211216

212-
// For unconfirmed transactions `confirmations` property may be undefined, so
213-
// we will return 0 instead.
214-
return transaction.confirmations ?? 0
217+
// Decode the raw transaction.
218+
const transaction = bcoin.TX.fromRaw(rawTransaction, "hex")
219+
220+
// As a workaround for the problem described in https://github.com/Blockstream/electrs/pull/36
221+
// we need to calculate the number of confirmations based on the latest
222+
// block height and block height of the transaction.
223+
// Electrum protocol doesn't expose a function to get the transaction's block
224+
// height (other that the `GetTransaction` that is unsupported by Esplora/Electrs).
225+
// To get the block height of the transaction we query the history of transactions
226+
// for the output script hash, as the history contains the transaction's block
227+
// height.
228+
229+
// Initialize txBlockHeigh with minimum int32 value to identify a problem when
230+
// a block height was not found in a history of any of the script hashes.
231+
//
232+
// The history is expected to return a block height for confirmed transaction.
233+
// If a transaction is unconfirmed (is still in the mempool) the height will
234+
// have a value of `0` or `-1`.
235+
let txBlockHeight: number = Math.min()
236+
for (const output of transaction.outputs) {
237+
const scriptHash: Buffer = output.script.sha256()
238+
239+
type HistoryEntry = {
240+
// eslint-disable-next-line camelcase
241+
tx_hash: string
242+
height: number
243+
}
244+
245+
const scriptHashHistory: HistoryEntry[] =
246+
await electrum.blockchain_scripthash_getHistory(
247+
scriptHash.reverse().toString("hex")
248+
)
249+
250+
const tx = scriptHashHistory.find(
251+
(t) => t.tx_hash === transactionHash.toString()
252+
)
253+
254+
if (tx) {
255+
txBlockHeight = tx.height
256+
break
257+
}
258+
}
259+
260+
// History querying didn't come up with the transaction's block height. Return
261+
// an error.
262+
if (txBlockHeight === Math.min()) {
263+
throw new Error(
264+
"failed to find the transaction block height in script hashes' histories"
265+
)
266+
}
267+
268+
// If the block height is greater than `0` the transaction is confirmed.
269+
if (txBlockHeight > 0) {
270+
const latestBlockHeight: number = await this.latestBlockHeight()
271+
272+
if (latestBlockHeight >= txBlockHeight) {
273+
// Add `1` to the calculated difference as if the transaction block
274+
// height equals the latest block height the transaction is already
275+
// confirmed, so it has one confirmation.
276+
return latestBlockHeight - txBlockHeight + 1
277+
}
278+
}
279+
280+
return 0
215281
})
216282
}
217283

0 commit comments

Comments
 (0)