Skip to content

Commit ca707f3

Browse files
committed
Document internal wallet startup cache behavior
1 parent 050cd45 commit ca707f3

3 files changed

Lines changed: 58 additions & 6 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Internal Wallet Snapshot
2+
3+
The Crosslink internal wallet keeps an optional restart cache at:
4+
5+
```text
6+
<state.cache_dir>/wallet.snapshot
7+
```
8+
9+
The snapshot is a local cache for the internal wallet's derived state: manual wallet records, known transactions, the PoW hash cache, and the Orchard shard tree. Zebra state, `pos.chain`, and `secret.seed` remain the authoritative node state.
10+
11+
## When snapshots are used
12+
13+
- Persistent state runs save and load `wallet.snapshot` from `state.cache_dir`.
14+
- Ephemeral state runs do not save or load the snapshot.
15+
- A snapshot is used only if its stored `secret.seed` bytes and genesis hash match the current run.
16+
- Missing, mismatched, or invalid snapshots are ignored and the internal wallet scans from genesis.
17+
18+
The file is written atomically via a temporary file and rename. The reader checks the snapshot magic, version, seed, genesis hash, bounded lengths, and trailing bytes before accepting it.
19+
20+
## Operational notes
21+
22+
- Treat `wallet.snapshot` as a local plaintext cache; do not share it as a recovery authority.
23+
- After rollback or state rebuild, move `wallet.snapshot` aside and let it regenerate from the rebuilt chain state.
24+
- The internal wallet requires zaino. If zaino is enabled but cannot start, `zebrad start` fails rather than continuing into a wallet sync loop that cannot make progress.
25+
26+
## Related config
27+
28+
```toml
29+
[crosslink]
30+
disable_the_headless_wallet = false
31+
disable_zaino = false
32+
reset_zaino_on_startup = false
33+
```
34+
35+
- `disable_the_headless_wallet`: skips the internal wallet task.
36+
- `disable_zaino`: skips zaino startup. Use this only when the internal wallet is also disabled.
37+
- `reset_zaino_on_startup`: deletes the zaino cache under `state.cache_dir` before starting zaino.

zebra-crosslink/sams_config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ checkpoint_sync = true
4646
[crosslink]
4747
do_not_manipulate_config = false
4848
i_am_the_unstaker = true
49+
# Set to true to skip starting the internal wallet task.
50+
disable_the_headless_wallet = false
51+
# Set to true to skip starting zaino. The internal wallet requires zaino.
52+
disable_zaino = false
53+
# Set to true to delete the zaino cache under state.cache_dir on startup.
54+
reset_zaino_on_startup = false
4955
bft_peers = []
5056

5157
[mempool]

zebra-crosslink/zebrad/src/commands/start.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,21 @@ impl StartCmd {
117117
async fn start(&self) -> Result<(), Report> {
118118

119119
let config = APPLICATION.config();
120-
let mut wallet_snapshot_path = config.state.cache_dir.clone();
121-
wallet_snapshot_path.push("wallet.snapshot");
122-
*wallet::WALLET_SNAPSHOT_PATH.lock().unwrap() = Some(wallet_snapshot_path.clone());
120+
let wallet_snapshot_path = if config.state.ephemeral {
121+
None
122+
} else {
123+
let mut path = config.state.cache_dir.clone();
124+
path.push("wallet.snapshot");
125+
Some(path)
126+
};
127+
*wallet::WALLET_SNAPSHOT_PATH.lock().unwrap() = wallet_snapshot_path.clone();
128+
let wallet_requires_zaino = cfg!(feature = "viz_gui") || !config.crosslink.disable_the_headless_wallet;
123129

124130
#[cfg(not(feature = "viz_gui"))]
125131
{
126132
if config.crosslink.disable_the_headless_wallet == false {
127133
let wallet_state = Arc::new(std::sync::Mutex::new(wallet::WalletState::new()));
128-
tokio::spawn(zebra_crosslink::wallet::wallet_main(wallet_state, Some(wallet_snapshot_path)));
134+
tokio::spawn(zebra_crosslink::wallet::wallet_main(wallet_state, wallet_snapshot_path.clone()));
129135
}
130136
}
131137
*zebra_crosslink::wallet::GUI_ENABLE_MINE.lock().unwrap() = config.mining.internal_miner;
@@ -221,8 +227,6 @@ impl StartCmd {
221227
// },
222228
mining: zebra_rpc::config::mining::Config {
223229
miner_address: Some(config.mining.miner_address.clone().unwrap_or_else(||{
224-
use zcash_address::ToAddress;
225-
226230
let t_addr = wallet::default_p2pkh_from_entropy(&config.network.network, &global_seed).expect("unable to initialize miner");
227231
info!("Miner address unspecified. Mining to {}", wallet::string_from_t_addr(&config.network.network, t_addr));
228232
t_addr.to_zcash_address(config.network.network.kind().into())
@@ -834,6 +838,11 @@ impl StartCmd {
834838
*zebra_crosslink::wallet::wallet_main_zaino_port.lock().unwrap() = zebra_port_base + 10001;
835839

836840
if let Err(err) = zainodlib::indexer::spawn_indexer(zaino_config).await {
841+
if wallet_requires_zaino {
842+
return Err(eyre!(
843+
"failed to start zaino indexer required by the internal wallet: {err:?}"
844+
));
845+
}
837846
warn!(
838847
?err,
839848
"failed to start zaino indexer; continuing without zaino"

0 commit comments

Comments
 (0)