Yes, yes, yes(*), and no.
The blockchain-related on-disk data Bitcoin Core keeps generally fall into these three categories:
- The block data (flat
blocks/blk?????.dat files with concatenated blocks).
- The block index (LevelDB database
- The UTXO set (LevelDB database
In this list, the later entries contain references to the previous ones. The chainstate contains the hash of the block that is currently considered "active" (i.e., the UTXO corresponds to it). This hash must exist in the block index at all times. Further, the block index stores in which block file and position within that file each block is stored.
To maintain consistency:
- Whenever block index writes to disk happen, the currently open block files are flushed. It is possible that bitcoind crashes during the block file write, which may leave a partially written block on disk, but since this block will not be written to the block index, after restart, it will be as if this block wasn't received at all; it will be redownloaded, and written to disk again (possibly in the same file byte range that the earlier attempt was written to as well).
- Block index writes are done using a LevelDB batch(*), which either makes it entirely to disk, or not at all.
- Whenever chainstate writes to disk happen, the block index is flushed.
- When the chainstate is written to disk, and there is a large number of modified entries, the write is split up into multiple LevelDB batches, to reduce peak memory usage during writing. Before this happens, a "flush in progress" entry is written to the database, which is removed after the flush completes. If bitcoind crashes in the middle, the chainstate will be in an inconsistent state, but on restart the "in progress" record will be detected, and the relevant range of blocks will be processed and applied again to the UTXO set.
(*) There have been reports of LevelDB itself causing corruption of its on-disk files if interrupted during a write, on some platforms.