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.
I have an additional question regarding the fluctuation in the Bitcoin subnet’s block finalize rate:
Back in February this year, the Bitcoin subnet’s block finalize rate dropped to 0.5 blocks per second. Before that, it had maintained a rate of 1–1.5 blocks per second for quite a long time. Currently, it’s at 2 blocks per second.
Could you explain the reason behind these fluctuations in the block finalize rate?
Also, is it reasonable to expect that the Bitcoin subnet’s block finalize rate will consistently remain at 2 blocks per second in the future?
What factors determine the stability of a subnet’s block finalize rate?
Back in February this year, the Bitcoin subnet’s block finalize rate dropped to 0.5 blocks per second. Before that, it had maintained a rate of 1–1.5 blocks per second for quite a long time.
Back in February, the Bitcoin subnet’s finalization rate dropped to 0.5 blocks/sec due to a combination of factors.
We were migrating from testnet3 to testnet4, which required a newly migrated canister either syncing from genesis (1–2 days) or uploading a precomputed state (5-6 hours) – both resource-intensive operations.
At the same time, testnet4 experienced unusually high activity, which led to several canister fixes and reinstallations, repeatedly triggering the expensive initialization process.
Meanwhile, the mainnet canister continued running, adding further load.
These factors combined caused the temporary FR dropdown.
We are constantly working on improving the FR stability for all the networks, including bitcoin subnet.