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.
The sync engine already parsed every block and found owned/spent outputs, but never created TransactionRow records — so get_transfers() always returned empty. Now put_tx() is called at all 6 integration points (miner,
protocol, regular TXs in both process_bin_block and process_block_data).
Wallet: Fix per-output derivation in protocol TX key image override.
Protocol TXs use additional_pubkeys (tag 0x04) for output derivation,
but the two-step key image override always used the shared tx_pub_key.
This caused the P_change recovery to fail silently, leaving ~9268 SAL1
of spent stake-return outputs marked as unspent. Track the actual
derivation pubkey through FoundOutput so the override uses the correct
key. Also improve stake return matching to use origin TX linkage from
salvium_txs instead of blind asset-type matching.
Miner: Add background mining with system idle monitoring, AC power
detection, and CPU throttling. Matches C++ background_worker_thread()
behavior with zero overhead when unused.
- Schnorr signatures (CryptoNote-style) for authenticating KEX messages
- SignedKexMessage wrapper with ephemeral keypair matching C++ multisig_kex_msg
- Binary wire format: magic + base58(Epee) for KEX, raw Epee for TX sets
- TCP transport coordinator with star topology and length-delimited framing
- 32 new tests across all four modules
- New mainnet_validation.rs: 9 tests that sample blocks/TXs from every
hard fork era (HF1–HF10) against public mainnet daemons, covering
block parsing, header validation, tree hash, TX parsing, serialize
roundtrip, CLSAG/TCLSAG signature verification, tamper detection,
and BP+ structure checks.
- Extract shared verification helpers (fetch_and_parse_tx, fetch_mix_ring,
prepare_verification_data, etc.) into tests/common/mod.rs to avoid
duplication between testnet and mainnet test files.
- Refactor rct_verify_testnet.rs to use mod common.
- All tests are #[ignore] — run with:
cargo test -p salvium-tx --test mainnet_validation -- --ignored --nocapture
- Replace simplified challenge computation in partial_sign() with proper
CLSAG ring traversal via new ClsagContext (mirrors C++ CLSAG_context_t)
- Add MultisigTxBuilder for constructing PendingMultisigTx with signing
contexts (pseudo-outputs, BP+ proof, signing message, fake responses)
- Enhance PendingMultisigTx with per-input signing contexts and ring data
so other signers can reconstruct ClsagContext for partial signing
- Update wallet sign_multisig_tx() to use proper partial_sign() with ring
traversal instead of dummy sc_mul_sub
- Expose inv_eight() from salvium-crypto for commitment image computation
- Fix iOS build: set CROSS_TOP/CROSS_SDK for openssl-src and per-target
CC/CFLAGS/AR/RANLIB for cc crate (SQLCipher) cross-compilation
- Fix cargo fmt across workspace
macOS GitHub Actions runners ship bash 3.2, which does not support
declare -A (requires bash 4.0+). Rewrote build-ios.sh and
build-android.sh to use parallel indexed arrays instead.
Add salvium_txs table to track change output Kos from CONVERT/STAKE/AUDIT
TXs. During sync, populate this map and use it to perform two-step key
derivation for pre-CARROT PROTOCOL return outputs (C++ m_salvium_txs
equivalent). This fixes scanning of blocks between HF6-HF10 where
returned staked/audited/converted funds were invisible or had wrong key
images.
Replace difficulty_to_target() stub with bit-by-bit long division of
(2^256-1)/difficulty. Add 5 unit tests including round-trip verification
against check_hash().
Consolidate the overlapping release.yml and build-release.yml into one
workflow. Adds pre-release test gate (tests + clippy), miner binary
builds, SHA-256 checksums, and creates releases as drafts.
This covers the 15 clippy fixes (redundant closures, unnecessary casts, identity map_err), 16 rustdoc fixes (unresolved bracket links, bare URLs), and formatting across 11 files in salvium-crypto, salvium-wallet,
salvium-tx, salvium-ffi, and salvium-multisig.
- Version all crates at 1.0.7-r001 (tracking Salvium C++ 1.0.7)
- Source-available license: free for author/designees and non-commercial
use; annual commercial license required for any revenue-generating use
- Build scripts for Android/iOS/Linux/macOS/Windows producing both
libsalvium_crypto and libsalvium_ffi
- CI workflow publishes platform archives to salvium-rs-releases
- 23 new FFI functions: storage ops, address book, tx notes, attributes,
staked balance, key derivation, mnemonic
- Fix stake detection: count owned outputs regardless of spent state
- Auto-resume testnet integration tests from current chain height
Add 6 enhancements: sync parse-error tracking via SyncEvent channel,
balance assertions after each fork phase, TX-ID stake return verification
at HF6+, view-only wallet balance matching, sync idempotency check, and
subaddress (0,1) receive test at HF10.
y
Implement stratum v1 protocol client for Bitcoin-style pool mining
(mining.subscribe/authorize/notify/submit). Add salvium-miner-gr crate
with GhostRider PoW (15 SPH-512 + 3 CryptoNight rounds), verified
against XMRig test vectors. Extend MiningJob with optional nonce_offset
and target fields for backward-compatible stratum support.
Audited all validation rules against blockchain.cpp and
tx_verification_utils.cpp. Fixed every divergence found:
- Asset type HF segregation: enforce SAL before HF6, SAL1 from HF6+
(was ignoring hf_version parameter entirely)
- Output key sorting: use <= (strictly increasing, no duplicates)
to match C++ !(pubkey > last) comparison
- Output sorting boundary: enforce at HF > CARROT || is_carrot
(was HF >= CARROT for all TXs)
- Ring size unmixable exception: allow < 16 for unmixable non-RCT
outputs with ≤1 mixable input, gated behind HF >= 2
The CI workflow uses RUSTFLAGS="-Dwarnings" which promotes all warnings
to errors. This resolves every warning across the workspace so both
cargo build, cargo test, and cargo clippy pass cleanly.
Clippy fixes (~100 warnings across 9 crates):
- Replace manual assign ops with compound assignment (+=, *=) in
bulletproofs_plus Scalar arithmetic
- Use iterator patterns instead of index-based loops (enumerate, zip,
iter_mut) in elligator2, bulletproofs_plus, miner, mnemonic
- Replace manual div_ceil with .div_ceil() in consensus difficulty/fee
- Replace map_or(true, ..) with is_none_or(..) in stake filtering
- Replace inherent to_string() with Display impl in multisig types
- Collapse nested if statements in validation.rs
- Remove redundant closures (.map(hex::encode), .and_then(hex_to_32))
- Remove unnecessary .to_vec(), borrows, and return statements
- Use RangeInclusive::contains for range checks
- Derive Default instead of manual impl for BlockExtendedInfo
- Use unwrap_or_default/unwrap_or for simplified match expressions
- Use std::ptr::slice_from_raw_parts_mut in FFI free function
- Add #[allow(clippy::too_many_arguments)] where function signatures
match the C++ reference implementation (crypto scan, TCLSAG, RCT
verify, miner, RPC, stake lifecycle)
- Add #[allow(clippy::type_complexity)] for complex tuple return types
- Convert match-with-single-pattern to if-let in CLI commands
- Rename AssetType::from_str to ::parse to avoid std trait confusion
- Fix literal-in-format-string warnings in CLI table headers
Rustc warning fixes (from prior session, included for completeness):
- Remove unused constants, imports, and struct fields
- Fix deprecated Nonce::from_slice calls in AES-256-GCM functions
- Add missing protocol_tx_data field to all TxPrefix constructors
- Prefix unused variables with underscore
Port test/legacy-js/full-testnet.js to Rust: a single #[ignore] integration
test that mines from genesis through all 10 hard forks, testing transfers,
stakes, burns, and sweeps at each era boundary. Suppress unused-code warnings
in the miner crate (deserialized API fields, FFI stubs, stratum placeholder).
- Add method/url/endpoint context to every RpcError variant
- Default retries 0→2 with exponential backoff (500ms initial)
- HTTP status handling (401/4xx/5xx) with body capture
- Transient error classification for retry decisions
- Connection pooling (pool_max_idle_per_host=4)
- All NoResult errors now identify the failing call
CI now runs fmt, clippy, compile (debug+release), WASM target check,
per-crate test jobs (types+consensus, crypto, wallet+tx, miner+multisig+rpc),
doc tests, and a final ci-pass gate. Release workflow gates on tests,
fixes workspace target paths, and adds scaffolding for publishing
binaries to an external releases repo.
- Fix balance computation: staked amounts now included in total balance
to match C++ wallet behavior (balance = unspent + staked, locked =
immature + staked). Affects getBalance, getStorageBalance, and
integration sync test reporting.
- Add stake lifecycle methods to Rust storage (putStake, getStake,
getStakes, getStakeByOutputKey, markStakeReturned, deleteStakesAbove)
with FFI bindings and JS FfiStorage wrappers.
- Fix BigInt serialization in FfiStorage.putStake (JSON.stringify crash).
- Add balance diagnostic script (test/diagnose-balance.js) for verifying
key image spent status against the blockchain.
- Integration sync test: clear stale DB on fresh sync, add per-txType
and per-format unspent breakdowns, show staked balance in report.
The Monero/Salvium binary format serializes both L and R vectors with
their own varint length prefix, but the parser skipped R's varint and
reused Lcount. This 1-byte offset shift corrupted all subsequent
prunable data (TCLSAG sigs, pseudoOuts), causing RCT signature
verification to fail on every daemon-fetched transaction.
Crypto Backend Refactoring
──────────────────────────
- Delete src/ed25519.js — all scalar/point operations now route through
the crypto provider (WASM/FFI/JSI backends only)
- Remove duplicate JS BigInt implementations of scReduce32, scReduce64,
scalarAdd, scalarMul from scanning.js, carrot.js, and carrot-scanning.js;
delegate to Rust backend via crypto/index.js
- Remove debug/test exports from index.js (randomPoint, testDouble,
getBasePoint, isOnCurve, etc.) that were only used during development
- Rebuild WASM binary (476KB → 487KB) with updated Rust crate
Consolidated CryptoNote Scanner (cn_scan)
─────────────────────────────────────────
- New Rust module crates/salvium-crypto/src/cn_scan.rs replaces 5-12
individual FFI round-trips per output with a single native call:
view tag check → derive subaddress pubkey → subaddress map lookup →
amount decryption → commitment mask → key image generation
- FFI wrapper salvium_cn_scan_output in ffi.rs + C header declaration
- FFI backend scanCnOutput() with full subaddress map marshaling
(32-byte key + u32 major/minor LE per entry) and JSON result parsing
- JSI backend delegation via this.native.cnScanOutput()
- wallet-sync.js _scanCNOutput() tries native path first when available
(FFI/JSI), falls through to existing JS pipeline for WASM/JS backends
- Change pub(crate) visibility on subaddress.rs cn_subaddress_secret_key
- 8 Rust unit tests covering view tag, amount, commitment mask,
subaddress matching, and key image generation
- Verified identical results: WASM (JS fallback) and FFI (native cn_scan)
produce same 964 outputs at same chain height; FFI is 3x faster sync
(0.8s vs 2.5s) with 12x less heap (12MB vs 150MB)
RCT Batch Signature Verification
─────────────────────────────────
- New Rust module crates/salvium-crypto/src/rct_verify.rs — single-call
verification of all ring signatures in a transaction (CLSAG + TCLSAG),
avoiding N individual JS↔Rust boundary crossings
- Computes pre-MLSAG message hash matching C++ get_pre_mlsag_hash
- FFI export salvium_verify_rct_signatures with flat byte array interface
- FFI backend verifyRctSignatures() method
- JS backend stub returns null (validation.js handles JS fallback)
- validation.js: 200+ lines of RCT verification logic including
flattenKeyImages, packTclsagSigsFlat, packClsagSigsFlat helpers
Transaction Expansion
─────────────────────
- transaction.js: add expandTransaction() matching C++ expand_transaction_2
(copies key images from prefix inputs into TCLSAG/CLSAG signature structs)
- New test/expand-transaction.test.js (634 lines)
- New test/rct-verify-testnet.test.js (430 lines)
Mining Resilience
─────────────────
- salvium-miner main.rs: retry get_info and get_block_template up to 5
times with 2s delay for transient daemon errors
- full-testnet.js mineTo(): retry miner up to 3 times with 3s delay,
check for partial progress between attempts
Testnet Tooling
───────────────
- sync-only.js: CRYPTO_BACKEND env var for A/B testing (wasm vs ffi)
- full-testnet.js: daemon URL update (node12.whiskymine.io)
- Debug scripts for cn_scan development (debug-cn-scan/marshal/match/wasm)
- Android .gitignore and build-bundle.sh for mobile builds