Repository navigation
Regression: indexing bitcoin mainnet from scratch makes electrs panic #214
Copy link
Copy link
Open
Description
On the latest commit (currently 503b740), running
cargo run --release --bin electrs -- -vvvv --daemon-dir=/data/blockchains/BTC/ --db-dir=/data/blockchains/BTC/electrs/ --network mainnet --address-search --index-unspendables
Yields the following backtrace:
> thread 'main' (2618) panicked at src/new_index/schema.rs:520:76:called Result::unwrap() on an Err value: Error(Msg("missing txo 3c04284d2ba5f65d15122953eba8329adb778c5b3881ecd2830926cb57161400:0"), State { next_error: None, backtrace: InternalBacktrace { backtrace: Some(
0: error_chain::backtrace::imp::InternalBacktrace::new
1: electrs::new_index::schema::lookup_txos
2: electrs::new_index::schema::Indexer::_index
3: electrs::new_index::fetch::Fetcher<T>::map
4: electrs::new_index::schema::Indexer::update
5: electrs::main
6: std::sys::backtrace::__rust_begin_short_backtrace
7: main
8: __libc_start_call_main
9: __libc_start_main_impl
10: _start) } })stack backtrace:
0: 0x565389ea9f95 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h0bf65c5ade08ad27
1: 0x565389d1abe7 - core::fmt::write::he00acd824749ac8b
2: 0x565389ea7491 - std::io::Write::write_fmt::h90fe4513e04f986c
3: 0x565389ea9e2f - std::sys::backtrace::BacktraceLock::print::h3775b21ceaf4ad1d
4: 0x565389e9cc66 - std::panicking::panic_with_hook::h0fc085f8b6efb327
5: 0x565389eaa3f7 - std::panicking::panic_handler::{{closure}}::h9d26b9b04a44e043
6: 0x565389eaa3a9 - std::sys::backtrace::__rust_end_short_backtrace::hce0c26d73f44f74b
7: 0x565389e9adac - __rustc[881eff9798cad629]::rust_begin_unwind 8: 0x565389b843eb - core::panicking::panic_fmt::h7509f5fc1f52ade1
9: 0x565389b846f1 - core::result::unwrap_failed::h4811fcb6dcdb23ec
10: 0x565389e2431c - electrs::new_index::schema::Indexer::_index::h704b5e9859f0197d
11: 0x565389e26f8f - electrs::new_index::fetch::Fetcher<T>::map::h57fb5b5bf9fd1422
12: 0x565389e1edc1 - electrs::new_index::schema::Indexer::update::had48397a4a9f640b
13: 0x565389ca69ec - electrs::main::h323dd1c456f6e711
14: 0x565389c9e063 - std::sys::backtrace::__rust_begin_short_backtrace::h918d2ba5502615b1
15: 0x565389cab2e6 - main
16: 0x7f57fe14ebd7 - __libc_start_call_main
17: 0x7f57fe14ec95 - __libc_start_main_impl
18: 0x565389c9d941 - _start
19: 0x0 - <unknown>fish: Job 1, 'RUST_BACKTRACE=full cargo run -…' terminated by signal SIGABRT (Abort)
Reverting back to 2c33745 solves the problem.
I checked the state of /data/blockchains/BTC/ for the incriminated txo:
bitcoin-cli -datadir=/data/blockchains/BTC/ getblockhash 119041
0000000000001f30f8e6e01b410f5b2001d6aee69401f5a97a28aceb33e99352
bitcoin-cli -datadir=/data/blockchains/BTC/ getrawtransaction \
3c04284d2ba5f65d15122953eba8329adb778c5b3881ecd2830926cb57161400
\
true 0000000000001f30f8e6e01b410f5b2001d6aee69401f5a97a28aceb33e99352 | jq '.vout[0]'
{
"value": 9.80000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 b010ba17bb034873991301660a6a73654f744eb3 OP_EQUALVERIFY OP_CHECKSIG",
"desc": "addr(1H3wxyDZH5MNgz9Au7tQmYfVgyXhk3qsjd)#4ueqfdcd",
"hex": "76a914b010ba17bb034873991301660a6a73654f744eb388ac",
"address": "1H3wxyDZH5MNgz9Au7tQmYfVgyXhk3qsjd",
"type": "pubkeyhash"
}
}
which looks correct to me.
I'm in a pickle here and can't investigate further right now. I'll stay on 2c33745 for the time being, in the meantime I hope this report is useful.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
EddieHouston commentedon May 7, 2026
Thanks for reporting this and sorry it is causing you troubles. It's possible that
something is happening with the blk*.dat fetcher in that it may not send blocks
in chain order as the new single pass indexing seems to require.
...more investigation needed to fully root cause and resolve.
Workaround: add
--jsonrpc-importto your invocation:That routes block fetching through bitcoind's JSON-RPC, which delivers blocks in
chain order and avoids the ordering assumption that f66e7fb relies on. It's
slightly slower than reading blk files directly, but should let you sync from scratch on
the latest commit without reverting.
EddieHouston commentedon May 7, 2026
btw... the blk file fetcher is likely going away in the future and --jsonrpc-import will become the default.
nikicat commentedon Aug 4, 2026
We hit this on a fresh mainnet sync and root-caused it. Confirming your suspicion: the blk*.dat fetcher is the trigger, and f66e7fb is the regression point.
Environment:
new-index@ ef15bf9 (+1 private electrum-RPC commit, no index changes), bitcoind v31.1 (txindex=1, no prune, node originally synced headers-first), aarch64, fresh empty DB, default fetch (no--jsonrpc-import).Symptom: deterministic panic at ~12.5% of initial sync, always in the same region:
Last progress line:
processing blocks 120014/960999 (12.5%).Root cause: before f66e7fb, ordering never mattered: pass 1 (
add) wrote the T/O rows for every block before pass 2 (index) performed anylookup_txos(). The single-pass merge made per-batch indexing depend on an implicit invariant — blocks arrive in dependency (height) order — which the blk-file fetcher does not provide.blk*.datfiles store blocks in arrival order: headers-first IBD downloads from many peers across a ~1024-block moving window (BLOCK_DOWNLOAD_WINDOW), so blocks land in the files out of height order routinely. Whenever a spending tx is processed in a batch before the batch containing its funding tx,lookup_txos()finds nothing and theunwrapat schema.rs:535 aborts. Any node whose block files were written by a headers-first sync (i.e., every node synced with Core ≥0.10) can reproduce this; exact panic height varies with the node's individual download history.Worth noting: #206 (closed as suspected local corruption) failed at height ~119937 with the same signature — that is the same bug, not a corrupt datadir; the reporter's files were merely out of order in the same early region where fast respends were common.
Fix directions we see, in increasing order of effort:
--jsonrpc-importthe default (as you suggested) — correct by construction, but slower and it abandons the blk fast path entirely.lookup_txos()report missing outpoints instead of panicking; blocks with unresolved spends are skipped — not marked inindexed_blockhashes— whileadd()still runs for every block. After the main sweep, re-process the deferred blocks; a single retry round is guaranteed to succeed because by then every funding tx has been added. Bounded extra work (only blocks containing out-of-window spends), keeps the single-pass memory/pipelining win, and the existing done-marker crash-recovery machinery already models "added but not indexed".EddieHouston commentedon Aug 28, 2026
Please see MR #217 which we are seeing significantly speed up initial sync... from taking over a week to now taking about 47 hours.
Hoping that this lands in new-index in the next week or so.