Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
62e9afd
evo: make CEvoDB consistency state per-chainstate
PastaPastaPasta Jul 11, 2026
8c1ec1e
evo: wire per-chainstate transactions into validation
PastaPastaPasta Jul 11, 2026
19da2c2
test: add dual-chainstate EvoDB consistency coverage
PastaPastaPasta Jul 11, 2026
b11ee85
dash: bind block validation to the calling chainstate
PastaPastaPasta Jul 11, 2026
4e48fbf
validation: suppress background chainstate notifications
PastaPastaPasta Jul 11, 2026
6551d1a
dash: guard serving unavailable snapshot history
PastaPastaPasta Jul 11, 2026
f268dd1
dash: refuse masternode duty on unvalidated snapshots
PastaPastaPasta Jul 11, 2026
d36983c
fix: canonicalize serialization of block-derived EvoDB payloads
PastaPastaPasta Jul 11, 2026
0d36ceb
test: adapt AssumeUTXO fixtures after txindex removal
PastaPastaPasta Jul 14, 2026
03cb36c
evo: abort node on WriteDerived mismatch instead of consensus rejection
PastaPastaPasta Aug 1, 2026
7a12dba
evo: preserve EvoDB inconsistency classification across GetForBlock r…
PastaPastaPasta Aug 1, 2026
04c6158
evo: resolve transaction-less EvoDB access against the active chainstate
PastaPastaPasta Aug 1, 2026
993d53b
dash: tolerate unavailable masternode list in scheduler-thread callbacks
PastaPastaPasta Aug 1, 2026
c2c21fa
Merge bitcoin/bitcoin#25740: assumeutxo: background validation comple…
PastaPastaPasta Jul 11, 2026
dbc14eb
backport: adapt Dash EvoDB completion path for bitcoin#25740
PastaPastaPasta Jul 11, 2026
62fc4c4
Merge bitcoin/bitcoin#27862: validation: Stricter assumeutxo error ha…
PastaPastaPasta Jul 11, 2026
d8f2f35
backport: adapt bitcoin#27862 for Dash crash recovery
PastaPastaPasta Jul 11, 2026
5295e37
Merge bitcoin/bitcoin#28050: test: make assumeUTXO test capture the e…
PastaPastaPasta Jul 11, 2026
df5e0c9
test: adapt bitcoin#28050 coverage for Dash shutdown
PastaPastaPasta Jul 11, 2026
d370b01
Merge bitcoin/bitcoin#27746: Rework validation logic for assumeutxo
ryanofsky Jul 31, 2023
eb14304
backport: adapt bitcoin#27746 for Dash
PastaPastaPasta Jul 11, 2026
e322fda
test: drop obsolete txindex restarts from snapshot tests
PastaPastaPasta Jul 14, 2026
266aaea
evo: reset default EvoDB identity when snapshot markers are promoted …
PastaPastaPasta Aug 1, 2026
97e5416
feat: assumeutxo evo snapshot format (v3, quorum reconstruction history)
PastaPastaPasta Jul 11, 2026
03457d3
feat: emit and seed evo snapshot section in dump/populate (v3)
PastaPastaPasta Jul 11, 2026
def4769
fix: assumeutxo init-order integration (B6)
PastaPastaPasta Jul 11, 2026
c7ab1be
refactor: break new circular dependencies from evo snapshot work
PastaPastaPasta Jul 11, 2026
c879f12
llmq: fix snapshot-aware quorum modifier use
PastaPastaPasta Jul 14, 2026
abb7a0c
test: make evo_snapshot_tests order-independent and debug-assert clean
PastaPastaPasta Aug 1, 2026
570c6d3
partial merge bitcoin/bitcoin#27596: validation: add ChainstateRole
jamesob Nov 10, 2022
290b109
Merge bitcoin/bitcoin#27596: assumeutxo (2)
PastaPastaPasta Jul 11, 2026
680fd45
backport: adapt Dash for bitcoin#27596
PastaPastaPasta Jul 11, 2026
28606ae
test: adapt bitcoin#27596 coverage for Dash
PastaPastaPasta Jul 11, 2026
e759a99
Merge bitcoin/bitcoin#28562: AssumeUTXO follow-ups
fanquake Oct 7, 2023
f34e5ae
Merge bitcoin/bitcoin#28589: test: assumeutxo func test race fixes
achow101 Oct 4, 2023
79e0e72
Merge bitcoin/bitcoin#28590: assumeutxo: change getchainstates RPC to…
achow101 Oct 5, 2023
bb0239f
Merge bitcoin/bitcoin#28618: doc: assumeutxo prune and index notes
ryanofsky Oct 23, 2023
83dd4dd
Merge bitcoin/bitcoin#28625: test: check that loading snapshot not ma…
achow101 Oct 11, 2023
f7ae6ae
Merge bitcoin/bitcoin#28647: test: Add assumeutxo test for wrong hash
ryanofsky Oct 17, 2023
9ab0696
Merge bitcoin/bitcoin#28652: assumeutxo: fail early if snapshot block…
fanquake Oct 17, 2023
ae26fbe
Merge bitcoin/bitcoin#28666: test: assumeutxo file with unknown block…
ryanofsky Oct 18, 2023
9f1e9fa
Merge bitcoin/bitcoin#28669: test: check assumeutxo file for changed …
achow101 Oct 20, 2023
17041f6
Merge bitcoin/bitcoin#28685: coinstats, assumeutxo: fix hash_serializ…
achow101 Oct 23, 2023
3fffa72
Merge bitcoin/bitcoin#28698: assumeutxo, blockstorage: Prevent core d…
fanquake Oct 29, 2023
8600163
Merge bitcoin/bitcoin#28835: test: Check error details with assert_de…
fanquake Nov 10, 2023
ada1f95
Merge bitcoin/bitcoin#28838: test: add assumeutxo wallet test
achow101 Jan 11, 2024
6e62116
feat: allow exact regtest AssumeUTXO authorization
PastaPastaPasta Jul 11, 2026
3fa6bc8
fix: preserve assumed-valid block index state
PastaPastaPasta Jul 11, 2026
28fedfe
fix: keep snapshot quorum lookups cache-only
PastaPastaPasta Jul 11, 2026
4ba7fe5
fix: initialize BLS before snapshot cleanup
PastaPastaPasta Jul 11, 2026
64905ee
test: expand feature_assumeutxo_dash.py to full E2E
PastaPastaPasta Jul 11, 2026
7ecf551
refactor: break blockfilter circular dependency from bitcoin#27596 work
PastaPastaPasta Jul 11, 2026
ae51f69
test: avoid restoring removed global txindex
PastaPastaPasta Jul 14, 2026
faaf158
kernel: deduplicate BlockInfo declarations
PastaPastaPasta Jul 14, 2026
0cb8644
Merge bitcoin/bitcoin#29370: assumeutxo: Get rid of faked nTx and nCh…
achow101 Jul 11, 2026
8bfa663
backport: adapt Dash for bitcoin#29370
PastaPastaPasta Jul 11, 2026
72560c1
test: fix Dash assumeutxo transaction count coverage
PastaPastaPasta Jul 11, 2026
abf5f05
Merge bitcoin/bitcoin#29215: test: assumeutxo: spend coin from snapsh…
glozow Jan 10, 2024
493b127
Merge bitcoin/bitcoin#29354: test: Assumeutxo with more than just coi…
glozow Feb 5, 2024
bd640c6
Merge bitcoin/bitcoin#29394: test, assumeutxo: Add test to ensure fai…
fanquake Feb 13, 2024
2a9b4aa
Merge bitcoin/bitcoin#29428: test: Assumeutxo: snapshots with less wo…
achow101 Jun 4, 2024
062781f
Merge bitcoin/bitcoin#29519: p2p: For assumeutxo, download snapshot c…
achow101 Aug 9, 2024
c08fe3c
Merge bitcoin/bitcoin#29553: assumeutxo: Add dumptxoutset height para…
achow101 Sep 3, 2024
1a8eff3
Merge bitcoin/bitcoin#29726: assumeutxo: Fix -reindex before snapshot…
ryanofsky Apr 16, 2024
8657901
Merge bitcoin/bitcoin#29973: test: Assumeutxo: ensure failure when im…
achow101 May 9, 2024
f30144d
Merge bitcoin/bitcoin#29996: Assumeutxo: bugfix on loadtxoutset with …
achow101 Jul 10, 2024
9772302
Merge bitcoin/bitcoin#30267: assumeutxo: Check snapshot base block is…
achow101 Jul 2, 2024
150458b
Merge bitcoin/bitcoin#30320: assumeutxo: Don't load a snapshot if it'…
achow101 Jul 18, 2024
65505f2
Merge bitcoin/bitcoin#30403: test, assumeutxo: Remove resolved todo c…
achow101 Jul 23, 2024
71b3cf7
backport: adapt assumeutxo hardening tests for Dash
PastaPastaPasta Jul 12, 2026
241a2ce
test: make the isolated-block lifecycle deterministic in feature_assu…
PastaPastaPasta Aug 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 0 additions & 104 deletions contrib/devtools/utxo_snapshot.sh

This file was deleted.

85 changes: 85 additions & 0 deletions doc/assumeutxo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Assumeutxo Usage

Assumeutxo is a feature that allows fast bootstrapping of a validating dashd
instance.

For notes on the design of Assumeutxo, please refer to [the design doc](/doc/design/assumeutxo.md).

## Loading a snapshot

There is currently no canonical source for snapshots, but any downloaded snapshot
will be checked against a hash that's been hardcoded in source code. If there is
no source for the snapshot you need, you can generate it yourself using
`dumptxoutset` on another node that is already synced (see
[Generating a snapshot](#generating-a-snapshot)).

Once you've obtained the snapshot, you can use the RPC command `loadtxoutset` to
load it.

```
$ dash-cli loadtxoutset /path/to/input
```

After the snapshot has loaded, the syncing process of both the snapshot chain
and the background IBD chain can be monitored with the `getchainstates` RPC.

### Pruning

A pruned node can load a snapshot. To save space, it's possible to delete the
snapshot file as soon as `loadtxoutset` finishes.

The minimum `-prune` setting is 550 MiB, but this functionality ignores that
minimum and uses at least 1100 MiB.

As the background sync continues there will be temporarily two chainstate
directories, each multiple gigabytes in size (likely growing larger than the
downloaded snapshot).

### Indexes

Indexes work but don't take advantage of this feature. They always start building
from the genesis block and can only apply blocks in order. Once the background
validation reaches the snapshot block, indexes will continue to build all the
way to the tip.


For indexes that support pruning, note that these indexes only allow blocks that
were already indexed to be pruned. Blocks that are not indexed yet will also
not be pruned.

This means that, if the snapshot is old, then a lot of blocks after the snapshot
block will need to be downloaded, and these blocks can't be pruned until they
are indexed, so they could consume a lot of disk space until indexing catches up
to the snapshot block.

## Generating a snapshot

The RPC command `dumptxoutset` can be used to generate a snapshot for the current
tip (using type "latest") or a recent height (using type "rollback"). A generated
snapshot from one node can then be loaded
on any other node. However, keep in mind that the snapshot hash needs to be
listed in the chainparams to make it usable. If there is no snapshot hash for
the height you have chosen already, you will need to change the code there and
re-compile.

Using the type parameter "rollback", `dumptxoutset` can also be used to verify the
hardcoded snapshot hash in the source code by regenerating the snapshot and
comparing the hash.

Example usage:

```
$ dash-cli -rpcclienttimeout=0 dumptxoutset /path/to/output rollback
```

For most of the duration of `dumptxoutset` running the node is in a temporary
state that does not actually reflect reality, i.e. blocks are marked invalid
although we know they are not invalid. Because of this it is discouraged to
interact with the node in any other way during this time to avoid inconsistent
results and race conditions, particularly RPCs that interact with blockstorage.
This inconsistent state is also why network activity is temporarily disabled,
causing us to disconnect from all peers.

`dumptxoutset` takes some time to complete, independent of hardware and
what parameter is chosen. Because of that it is recommended to increase the RPC
client timeout value (use `-rpcclienttimeout=0` for no timeout).
77 changes: 33 additions & 44 deletions doc/design/assumeutxo.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
# assumeutxo
# Assumeutxo Design

Assumeutxo is a feature that allows fast bootstrapping of a validating dashd
instance with a very similar security model to assumevalid.

The RPC commands `dumptxoutset` and `loadtxoutset` are used to respectively generate
and load UTXO snapshots. The utility script `./contrib/devtools/utxo_snapshot.sh` may
be of use.
For notes on the usage of Assumeutxo, please refer to [the usage doc](/doc/assumeutxo.md).

## General background

Expand All @@ -15,23 +10,12 @@ be of use.

## Design notes

- A new block index `nStatus` flag is introduced, `BLOCK_ASSUMED_VALID`, to mark block
index entries that are required to be assumed-valid by a chainstate created
from a UTXO snapshot. This flag is mostly used as a way to modify certain
CheckBlockIndex() logic to account for index entries that are pending validation by a
chainstate running asynchronously in the background. We also use this flag to control
which index entries are added to setBlockIndexCandidates during LoadBlockIndex().

- Indexing implementations via BaseIndex can no longer assume that indexation happens
sequentially, since background validation chainstates can submit BlockConnected
events out of order with the active chain.

- The concept of UTXO snapshots is treated as an implementation detail that lives
behind the ChainstateManager interface. The external presentation of the changes
required to facilitate the use of UTXO snapshots is the understanding that there are
now certain regions of the chain that can be temporarily assumed to be valid (using
the nStatus flag mentioned above). In certain cases, e.g. wallet rescanning, this is
very similar to dealing with a pruned chain.
now certain regions of the chain that can be temporarily assumed to be valid.
In certain cases, e.g. wallet rescanning, this is very similar to dealing with
a pruned chain.

Logic outside ChainstateManager should try not to know about snapshots, instead
preferring to work in terms of more general states like assumed-valid.
Expand All @@ -54,7 +38,7 @@ data.
### "Normal" operation via initial block download

`ChainstateManager` manages a single Chainstate object, for which
`m_snapshot_blockhash` is null. This chainstate is (maybe obviously)
`m_from_snapshot_blockhash` is `std::nullopt`. This chainstate is (maybe obviously)
considered active. This is the "traditional" mode of operation for dashd.

| | |
Expand All @@ -76,9 +60,15 @@ original chainstate remains in use as active.

Once the snapshot chainstate is loaded and validated, it is promoted to active
chainstate and a sync to tip begins. A new chainstate directory is created in the
datadir for the snapshot chainstate called `chainstate_snapshot`. When this directory
is present in the datadir, the snapshot chainstate will be detected and loaded as
active on node startup (via `DetectSnapshotChainstate()`).
datadir for the snapshot chainstate called `chainstate_snapshot`.

When this directory is present in the datadir, the snapshot chainstate will be detected
and loaded as active on node startup (via `DetectSnapshotChainstate()`).

A special file is created within that directory, `base_blockhash`, which contains the
serialized `uint256` of the base block of the snapshot. This is used to reinitialize
the snapshot chainstate on subsequent inits. Otherwise, the directory is a normal
leveldb database.

| | |
| ---------- | ----------- |
Expand All @@ -88,7 +78,7 @@ active on node startup (via `DetectSnapshotChainstate()`).
The snapshot begins to sync to tip from its base block, technically in parallel with
the original chainstate, but it is given priority during block download and is
allocated most of the cache (see `MaybeRebalanceCaches()` and usages) as our chief
consideration is getting to network tip.
goal is getting to network tip.

**Failure consideration:** if shutdown happens at any point during this phase, both
chainstates will be detected during the next init and the process will resume.
Expand All @@ -107,33 +97,32 @@ sequentially.
### Background chainstate hits snapshot base block

Once the tip of the background chainstate hits the base block of the snapshot
chainstate, we stop use of the background chainstate by setting `m_stop_use` (not yet
committed - see bitcoin#15606), in `CompleteSnapshotValidation()`, which is checked in
`ActivateBestChain()`). We hash the background chainstate's UTXO set contents and
ensure it matches the compiled value in `CMainParams::m_assumeutxo_data`.

The background chainstate data lingers on disk until shutdown, when in
`ChainstateManager::Reset()`, the background chainstate is cleaned up with
`ValidatedSnapshotShutdownCleanup()`, which renames the `chainstate_[hash]` datadir as
`chainstate`.
chainstate, we stop use of the background chainstate by setting `m_disabled`, in
`CompleteSnapshotValidation()`, which is checked in `ActivateBestChain()`). We hash the
background chainstate's UTXO set contents and ensure it matches the compiled value in
`CMainParams::m_assumeutxo_data`.

| | |
| ---------- | ----------- |
| number of chainstates | 2 (ibd has `m_stop_use=true`) |
| number of chainstates | 2 (ibd has `m_disabled=true`) |
| active chainstate | snapshot |

**Failure consideration:** if dashd unexpectedly halts after `m_stop_use` is set on
the background chainstate but before `CompleteSnapshotValidation()` can finish, the
need to complete snapshot validation will be detected on subsequent init by
`ChainstateManager::CheckForUncleanShutdown()`.
The background chainstate data lingers on disk until the program is restarted.

### Dashd restarts sometime after snapshot validation has completed

When dashd initializes again, what began as the snapshot chainstate is now
indistinguishable from a chainstate that has been built from the traditional IBD
process, and will be initialized as such.
After a shutdown and subsequent restart, `LoadChainstate()` cleans up the background
chainstate with `ValidatedSnapshotCleanup()`, which renames the `chainstate_snapshot`
datadir as `chainstate` and removes the now unnecessary background chainstate data.

| | |
| ---------- | ----------- |
| number of chainstates | 1 |
| active chainstate | ibd |
| active chainstate | ibd (was snapshot, but is now fully validated) |

What began as the snapshot chainstate is now indistinguishable from a chainstate that
has been built from the traditional IBD process, and will be initialized as such.

A file will be left in `chainstate/base_blockhash`, which indicates that the
chainstate, even though now fully validated, was originally started from a snapshot
with the corresponding base blockhash.
28 changes: 28 additions & 0 deletions doc/release-notes-27596.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Pruning
-------

When using assumeutxo with `-prune`, the prune budget may be exceeded if it is set
lower than 1100MB (i.e. `MIN_DISK_SPACE_FOR_BLOCK_FILES * 2`). Prune budget is normally
split evenly across each chainstate, unless the resulting prune budget per chainstate
is beneath `MIN_DISK_SPACE_FOR_BLOCK_FILES` in which case that value will be used.

RPC
---

`loadtxoutset` has been added, which allows loading a UTXO snapshot of the format
generated by `dumptxoutset`. Once this snapshot is loaded, its contents will be
deserialized into a second chainstate data structure, which is then used to sync to
the network's tip.

Meanwhile, the original chainstate will complete the initial block download process in
the background, eventually validating up to the block that the snapshot is based upon.

The result is a usable dashd instance that is current with the network tip in a
matter of minutes rather than hours. UTXO snapshot are typically obtained via
third-party sources (HTTP, torrent, etc.) which is reasonable since their contents
are always checked by hash.

You can find more information on this process in the `assumeutxo` design
document (<https://github.com/dashpay/dash/blob/master/doc/design/assumeutxo.md>).

`getchainstates` has been added to aid in monitoring the assumeutxo sync process.
4 changes: 4 additions & 0 deletions doc/release-notes-28685.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
RPC
---

The `hash_serialized_2` value has been removed from `gettxoutsetinfo` since the value it calculated contained a bug and did not take all data into account. It is superseded by `hash_serialized_3` which provides the same functionality but serves the correctly calculated hash.
4 changes: 2 additions & 2 deletions doc/zmq.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ Where the 8-byte uints correspond to the mempool sequence number.
| hashtx | <32-byte transaction hash in Little Endian> | <uint32 sequence number in Little Endian>


`rawblock`: Notifies when the chain tip is updated. Messages are ZMQ multipart messages with three parts. The first part is the topic (`rawblock`), the second part is the serialized block, and the last part is a sequence number (representing the message count to detect lost messages).
`rawblock`: Notifies when the chain tip is updated. When assumeutxo is in use, this notification will not be issued for historical blocks connected to the background validation chainstate. Messages are ZMQ multipart messages with three parts. The first part is the topic (`rawblock`), the second part is the serialized block, and the last part is a sequence number (representing the message count to detect lost messages).

| rawblock | <serialized block> | <uint32 sequence number in Little Endian>

`hashblock`: Notifies when the chain tip is updated. Messages are ZMQ multipart messages with three parts. The first part is the topic (`hashblock`), the second part is the 32-byte block hash, and the last part is a sequence number (representing the message count to detect lost messages).
`hashblock`: Notifies when the chain tip is updated. When assumeutxo is in use, this notification will not be issued for historical blocks connected to the background validation chainstate. Messages are ZMQ multipart messages with three parts. The first part is the topic (`hashblock`), the second part is the 32-byte block hash, and the last part is a sequence number (representing the message count to detect lost messages).

| hashblock | <32-byte block hash in Little Endian> | <uint32 sequence number in Little Endian>

Expand Down
Loading
Loading