I just made a request, and the UTXO’s outpoint height has reverted to 81836, matching mempool.space.
However, yesterday for a prolonged period (around 3–4 hours) it remained inconsistent with mempool.space, even though at that time the latest block hash tracked by the Bitcoin canister matched mempool.space (indicating the canister did not undergo a fork). I’m not sure what caused this issue.
I’ve encountered an issue on Bitcoin Testnet4 where, for the same address, the Bitcoin canister’s tip height matches mempool.space (both height and block hash are identical), yet the reported height for the same UTXO’s OutPoint differs between the two sources. The timestamp of occurrence was UTC 2025-05-13T04:01:18.610673Z.
Expected Behavior
The UTXO’s height reported by the Bitcoin canister should match the one shown on mempool.space (i.e., 81973).
Actual Behavior
The Bitcoin canister reports the UTXO’s height as 81969, while mempool.space reports 81973.
Questions
• Is this discrepancy indicative of a bug in the Bitcoin canister?
• If not a bug, what might cause the canister to report an outdated height for this OutPoint?
Thanks for reporting this!
The discrepancy is probably due to the output occurring in multiple blocks on different forks at different heights. As @maksym showed here, there can be many forks on Testnet4.
It is possible that blockchain explorers and the Bitcoin canister occasionally see a slightly different state when there are several forks and temporarily disagree on what blocks are part of the main chain.
As you observed, once there is agreement on the main chain, the discrepancy goes away and all sources report the same information.
Unfortunately, there is no way to guarantee that this never happens.
Hi all, let me provide a bit more context to the issue.
Often mempool and bitcoin canister heights are not in sync. Bitcoin canister often lags behind a little bit, which is mostly caused by several competing branches, when it’s not possible to decide what is the main branch, so the canister decides on some earlier ‘safe’ block. The bitcoin canister tip height may even go back and forth.
The original issue depends heavily on the timing of 3 data points:
refreshing mempool page
reading current tip heigh from bitcoin canister
reading address with transactions from bitcoin canister
Calls 2. and 3. are different and cannot be done in the same time. So my assumption is that the developer sees the same block hash and height from data points 1. and 2., then at some point it receives different heights from the call 3., which looks like a bug.
My current evaluation – the culprit is ‘bitcoin canister lagging behind due to competing branches on testnet4’. And the pattern of ‘different heights’ should look like on the picture above. It is also supported by the fact that after some time when the block becomes stable the height values do converge.
To rule out this hypothesis one may want to do a more rigorous testing with many data points (all 3, or at least many points 2.+3.) that show a pattern different from the one I provided above.
Hi,
I saw it mentioned here that the stability threshold for unstable blocks is 144 blocks.
I’d like to ask: what stability threshold is currently set for the Bitcoin canister on Testnet4?
And can UTXOs at heights earlier than (tip height − stability threshold) returned by the Bitcoin canister be considered fully confirmed and up-to-date?
Unfortunately ‘stability threshold’ setting only makes sense in context of Mainnet, not for Testnet4. 144=24*6 is the number of blocks generated every 10 minutes for 24 hours.
Back in the days when we supported Testnet3 it was possible to see many blocks generated with low difficulty, so internally we changed the formula for ‘stability threshold’ to account for difficulty (many blocks of low difficulty should not overtake few blocks of high difficulty). But this change also broke the direct mental connection between the ‘number of blocks’ and ‘stability threshold’ for testnets.
You can see the current settings for Bitcoin Testnet Canister on the dashboard page by calling get_config query.
Current value is 100, but since on Testnet4 blocks can have high and minimum difficulty it turns to about 200-250 blocks. This number also changes depending on the activity on the testnet, so I don’t think this parameter is meaningful for the developers to rely on.
Question
I would assume that the real question developers might have is actually – how can I know that the block is stable enough so I can rely on it?
The block becomes stable for the bitcoin canister when it moves from ‘unstable blocks tree’ structure (with potentially many branches) to a stable chain structure (never changes after that), which takes 200-250 blocks currently or 1.5-2 days. I understand that this is a bit long.
But there’s another observation made on Testnet4 that shows high difficulty blocks appear roughly every 3 blocks, so you should multiply it by your Mainnet confirmation value (say 12 blocks) which turns into 6 hours. After that it is highly unlikely that another competing branch will take over.
Here’s a chart of number of blocks by which bitcoin canister on testnet4 lags behind (past 30 days). You can see the 50 pct value is -3 blocks with minimum of -21 blocks.
Unfortunately this is all the nature of current testnet and we cannot do much about it. At least it should give you some intuition on how long to wait before considering the block reliable.
Thank you for the explanation. I think it’s reasonable to allow for more compromises and understanding on the testnet.
It won’t be the same on mainnet as it is on Testnet4.
Ah, don’t worry, it’s not a big issue.
A friend of mine came across this problem while testing UTXOs on testnet4, and I’m equally puzzled, so I’m here to seek some help.