Distribute block fetch requests across up to 4 fastest nodes in the
NodePool, selected by latency-weighted racing. All configured nodes
are probed but only the top 4 are used for parallel fetching.
NodePool (salvium-rpc):
- Add max_fetch_nodes to PoolConfig (default 4)
- Add force_race() to probe all nodes on demand
- Add fetch_batch_distributed() with latency-weighted range splitting
- Add compute_assignments() with 6 unit tests
- Add DistributedBatchResult type
Sync engine (salvium-wallet):
- Call force_race() at sync start to populate latency data
- Replace all 3 fetch sites with fetch_batch_distributed
- Simplify PrefetchResult to use DistributedBatchResult
Explorer FFI (salvium-ffi):
- Add salvium_daemon_get_blocks_by_height (JSON heights → blocks)
- Add salvium_daemon_get_transactions (JSON hashes → tx hex)
- Add salvium_daemon_add_nodes (batch add from JSON array)
- Add salvium_daemon_force_race (probe all nodes)
CLI & bench:
- Add --nodes flag to salvium-wallet-cli and salvium-sync-bench
- Wire extra nodes into NodePool for sync commands
Docs:
- Document multi-node setup in wallet-sync-spec.md
- Document FFI block/tx fetching in explorer-spec.md
The transfer pipeline was passing asset-type-specific asset_type to get_output_distribution and get_outs but using global output indices from the wallet DB, causing an index space mismatch that made the daemon return HTTP
500. Switched to empty asset_type (global index space) for both calls, matching the existing salvium-cli pattern. Removed unused is_global_out field from OutputRequest. Bumped version to r012.
Correct camelCase field names in FFI source comments, fix build script
target description, bigint→number types for u64 params, address format
values (legacy not CryptoNote), verify_rct binary return format, and
stale line number references.
Allows Android/FFI callers to interrupt an in-progress wallet sync
cleanly between batches. Adds salvium_wallet_stop_sync FFI export,
WalletError::Cancelled, SyncEvent::Cancelled, and WalletHandle
wrapper that pairs each wallet with its cancellation flag.