Commit Graph

473 Commits

Author SHA1 Message Date
Sami Ahmed 48cf7277dd init: auto-rebuild trigger + remove FastImport as primary path
Two operational changes that together fulfill the 'snapshot as
universal sync start' vision:

1. -autorerebuild=<n> CLI flag (default 0=disabled)
   After Step 7 loads the chain DB, MaybeAutoRebuild() compares our
   local nBestHeight to the median peer-reported height (collected via
   CNode::nStartingHeight from the version handshake). If lag >= n,
   wipe the chain DB (preserve wallet.dat, onion, smsg state) and
   request shutdown. On restart, the daemon sees no chain DB and the
   snapshot path takes over.

   WaitForPeerHeights() polls up to 60s for at least 3 peers.

2. -allowfastimport CLI flag (default OFF)
   The FastImportBlockFile() rebuild path is now gated behind this
   flag. If the chain DB is empty and blk0001.dat exists, the daemon
   fails with a clear error message that tells the operator how to
   recover (place utxo-snapshot.bin, delete blk0001.dat, or set
   -allowfastimport). FastImport is now operator opt-in only — the
   snapshot path is the canonical sync start.

   This matches Sami's vision: 'Everything should be transferred over
   to the UTXO jump and then they should be able to put the blockchain
   together exactly how it's supposed to be from all the peers
   filling in all the blank spots.'
2026-06-19 02:36:09 -07:00
Sami Ahmed d6b47b5a0d checkpoints: drop 2207680 entry (signature is the snapshot gate now)
When I added the 2207680 checkpoint, I was treating checkpoints as the
authentication gate for snapshot loading. Sami corrected: 'It shouldn't
require a checkpoint, all it should require is a signature.'

Commit 2866a94 already replaced requireCheckpoint=true with signature
verification in DownloadUtxoSnapshot. This commit removes the now-
unnecessary checkpoint entry so the source stays clean — the signature
is the only gate for snapshots, period.

(2205000/2206004 checkpoints remain — they're separate concerns for
chain finality validation, not snapshot acceptance.)
2026-06-19 02:28:23 -07:00
Sami Ahmed 2866a94be1 bootstrap: signature-based snapshot authentication
DownloadUtxoSnapshot now authenticates snapshots via Triangles signed
messages instead of relying on hardcoded checkpoints.

New flow:
1. Fetch big manifest.json, find canonical snapshot entry
2. Fetch the per-snapshot manifest (utxo-snapshot-{h}.manifest.json)
3. Verify the signer address is in the trusted signers list (currently
   Sami's TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX)
4. Verify the signature cryptographically (Triangles compact-message
   protocol with strMessageMagic prefix, same construction as
   signmessage/verifymessage RPC)
5. Download snapshot file, verify SHA256 against manifest
6. Load with requireCheckpoint=false — signature is the gate

Per Sami: 'It shouldn't require a checkpoint all it should require
is a signature.' This removes the checkpoint coupling that was
breaking fresh-node sync (the 2207680 checkpoint gate rejected the
canonical snapshot even though it was validly signed).

Trusted signer list is currently a hardcoded constant. Future work:
-snapshotsigner=<addr> CLI arg (repeatable).
2026-06-19 02:24:07 -07:00
Sami Ahmed 2a7c89a91e bootstrap: read manifest.json for canonical snapshot + verify SHA256
DownloadUtxoSnapshot now:
1. Fetches manifest.json from the bootstrap server
2. Locates the utxo_snapshot entry (filename + expected sha256)
3. Downloads THAT file
4. Verifies file SHA256 matches manifest
5. Falls back to legacy 'utxo-snapshot.bin' if manifest unavailable

Also add 2207680 checkpoint to mapCheckpoints so the canonical signed
snapshot (per 2026-06-18 manifest) passes the requireCheckpoint gate.

Defense in depth: server symlinks + daemon verifies the file matches.
2026-06-19 02:02:53 -07:00
Sami Ahmed 677a8ea79a build: ignore build-*/ directories and build artifacts 2026-06-19 00:17:10 -07:00
hermes d8af2aa17c scripts: add sign-snapshot.sh for signed UTXO snapshot provenance
Generates a UTXO snapshot via dumputxoset RPC, signs a provenance message
(height, blockhash, snapshot sha256) with signmessage, and emits a signed
manifest.json. Verification via ./sign-snapshot.sh verify <manifest> <snap>
or verifymessage RPC on any node.

Pairs with the requireCheckpoint trust-gate patch — local snapshots no
longer require a known checkpoint, so signing provenance is the way to
establish authority for a snapshot.
v5.9.18
2026-06-18 02:39:43 -07:00
hermes e15de97be3 utxosnapshot: gate requireCheckpoint on trust source
Local file snapshots (init.cpp) skip the known-checkpoint gate; P2P-delivered
snapshots (bootstrap.cpp) keep it. Rationale: the checkpoint gate exists to
prevent malicious peers from injecting fake UTXO sets. Local file loads come
from operator-trusted sources (filesystem access already grants equal power),
so the gate is unnecessary friction.
2026-06-18 02:34:51 -07:00
triangles-bot c606253c41 utxosnapshot: build address index when loading a UTXO snapshot (fast-start nodes get balances) [v5.9.17] v5.9.17 2026-06-16 20:37:44 -07:00
triangles-bot b2dfb627cc main: build address index during FastImport (fix-in-place, v5.9.16) v5.9.16 2026-06-16 20:24:26 -07:00
triangles-bot d0a76f8ae2 qt: show Seed Phrase (HD Backup) in the visible Operations menu (v5.9.15)
The HD seed action was only added to the standard Qt menu bar, which the
skinned GUI hides. Add it to menuOperationsRequested() so users can actually
reach Generate / Reveal-for-backup / Restore from the Operations menu.
v5.9.15
2026-06-16 16:24:12 -07:00
SamiAhmed7777 cc57c906b4 Merge PR #6: HD seed-phrase wallet + fast-sync checkpoint/snapshot (v5.9.14)
HD wallet (BIP39/BIP32 seed phrases) - daemon + Qt
v5.9.14
2026-06-15 20:44:52 -07:00
Sami e80d672833 checkpoints: add 2206004 checkpoint + UTXO snapshot hash (fast new-node sync) 2026-06-15 20:31:02 -07:00
Sami fcdc9a58b0 ci(lint): checkout secp256k1 submodule for clang-tidy (fixes configure) 2026-06-15 19:26:43 -07:00
Sami 514867c5d9 wallet(HD): flush keypool on seed set so getnewaddress yields HD keys immediately 2026-06-15 19:16:03 -07:00
Sami c464e6c59d wallet(HD): Qt UI - Seed Phrase dialog (generate/restore/backup)
Adds HDSeedDialog (Settings > Seed Phrase) with Generate New / Reveal for Backup / Restore from Phrase, driven by new WalletModel HD methods. Restore rescans the chain. Requires wallet unlock via the standard UnlockContext.
2026-06-15 19:16:03 -07:00
Sami 11ed086d1e wallet(HD): native BIP39/BIP32 HD wallet - daemon side
Adds deterministic HD key derivation (path m/44'/2222'/0'/0/i, matching the TRIdock web wallet) wired into CWallet: HD seed stored in wallet.dat (encrypted with the wallet master key when the wallet is encrypted), keypool derived from the seed, and new RPC commands hdnew/hdrestore/hdshow/hdinfo. Crypto core verified standalone against the official BIP39 vector and triWallet.js addresses.
2026-06-15 19:15:43 -07:00
Hermes 5511cfae6b v5.9.14 + pitfall #61 guard: initialize pindexFinalized on startup
ROOT CAUSE of the 2026-06-16 minority-fork reorg:

The v5.9.14 getheaders handler serves headers from pindexGenesisBlock
when a fork peer sends a locator that doesn't match our main chain. The
intent was to help fork peers learn the canonical chain. The bug: this
allows the fork peer to feed us THEIR short chain back via getheaders,
and we accept it because:

1. pindexFinalized is NULL on a fresh restart (the auto-checkpoint code
   in ActivateBestChain() at main.cpp:2459 only sets it when
   !IsInitialBlockDownload(), but a synced daemon restarting with a
   chain tip > 24h stale is considered IBD by the time check at
   main.cpp:1331).

2. With pindexFinalized = NULL, the reorg guard at main.cpp:2198
   short-circuits: 'if (pindexFinalized && pfork->nHeight < ...)'.

3. The fork peer's 3,755-block chain gets accepted, overwriting our
   healthy 2,206,004-block chain.

THE FIX (two parts):

A. init.cpp:1083-1113 — after LoadBlockIndex(), call
   Checkpoints::GetLastCheckpoint(mapBlockIndex) to initialize
   pindexFinalized from the hardcoded checkpoint (block 2,205,000).
   This is a no-op on the first ~10 seconds of the daemon's life
   (during the initial IBD walk), but as soon as we sync past block
   2,205,000, the checkpoint is in mapBlockIndex and pindexFinalized
   is set for the daemon's entire lifetime.

B. main.cpp:4473-4496 — in the getheaders fork-detection branch,
   serve from pindexFinalized->pnext (the block after our last
   finalized checkpoint) instead of pindexGenesisBlock. This is the
   safe equivalent of the v5.9.14 'serve from genesis' logic — the
   peer learns our canonical chain from the most recently finalized
   point forward, and their short fork gets rejected at the reorg
   guard in Reorganize() because the fork point is below
   pindexFinalized.

Combined: a fork peer can no longer drag us below block 2,205,000
because (a) pindexFinalized is always set on a synced restart, and
(b) the reorg guard now sees a non-NULL pindexFinalized and rejects
any fork below it.

Tested manually by simulating a restart with the v5.9.14 binary on
a chain that had been reorged to a minority fork; the new build
refuses the reorg and prints 'STARTUP-CHECKPOINT: pindexFinalized set
to block 2205000' on startup, then 'getheaders: fork detected from
peer ... serving headers from finalized block 2205000' on the first
fork peer's getheaders request.
2026-06-15 18:37:53 -07:00
Sami Ahmed 1dda8b3006 Auto-repair corrupt Tor state file on daemon startup (pitfall #19)
Tor's atomic state-write is: write state.tmp, then rename to state.
If the daemon is killed mid-write (pkill -9, OOM, power loss, disk-full),
the rename can fail and 'state' is left as a regular file instead of a
directory. On next start, Tor's config validator refuses to use it:

  [warn] State file '...' is not a file? Failing.
  [err] set_options: Bug: Acting on config options left us in a broken state. Dying.
  [err] Reading config failed--see warnings above.

The daemon then reports 'Tor failed to start. Triangles requires Tor to
operate.' (the error from the 2026-06-15 TRI-LAPTOP GUI wallet
screenshot) and refuses to come up at all.

Hit before on DNS3 (2026-05-24, fixed by manual 'mv state state.file.bak;
mkdir state' on the operator) and on the laptop today. The fix was always
the same one-liner; this patch makes the daemon do it itself.

Behavior:
- Detect: if tor_data/state exists and is NOT a directory, it's corrupt
- Quarantine: rename to tor_data/state.corrupt-YYYYMMDD-HHMMSS for
  inspection (the user might want to recover the file's contents)
- If rename fails (Windows anti-virus holds the file, etc.), retry with
  remove-then-rename, and as a last resort just remove() so Tor can
  proceed
- Print a clear 'Tor state was a file (corrupt) — quarantined to ...'
  log line so the operator can see it happened
- Tor then recreates state/ as a fresh directory and bootstraps normally

This is a pure-additive change (no existing behavior modified). Builds
clean with the existing C++20 + libtor.a toolchain. No version bump
needed - will roll into the next CI cycle.
2026-06-15 16:29:05 -07:00
Sami Ahmed 68c4e38411 Fix getheaders pnext null bug: serve main chain from genesis, tip-backwards fallback
Two related bugs in the getheaders handler at main.cpp:4441:

1. Locator-mismatch returns 0 headers:
   GetBlockIndex() falls through to pindexGenesisBlock when no locator
   hash matches the main chain. pindexGenesisBlock->pnext is null, so
   the for-loop exits immediately and the peer gets an empty headers
   response. This was the DNS3 headers-first sync stall (pitfall #36):
   'getheaders -1 to 0000...' logged repeatedly.

   Mirror the getblocks handler (line 4387): detect the mismatch, log
   a warning, and serve headers from genesis so the peer can discover
   the canonical chain.

2. Broken pnext chain at any height:
   Even when GetBlockIndex() returns a valid (non-genesis) block, its
   pnext can be null — this happens when LoadBlockIndex() didn't fully
   heal pnext links (e.g., the node was bootstrapped from a snapshot,
   or the chain was interrupted by a crash). On tridock every pnext
   link was null despite 2.2M blocks (the June 11 'Heal pnext links'
   commit addressed a similar symptom for GetKernelStakeModifier() but
   doesn't reach into the getheaders handler).

   Fall back to a tip-backwards walk from pindexBest when pnext is
   null: O(N) but correct, and only triggers on the broken path.

   (References the design in references/getheaders-pnext-fix.md from
   the v5.9.10 deploy notes — that fix was never actually committed,
   only prototyped and dropped during the June 4 git cleanup.)

Bump to v5.9.14 (also embeds the embedded-Tor 0700 fix from ed996c8).

Refs: SKILL.md pitfall #36
2026-06-15 15:43:03 -07:00
Sami Ahmed ed996c8e9d Fix embedded Tor bootstrap (code -1): force 0700 on hidden service dir
Tor's config validator refuses to start a hidden service on any directory
whose permissions are not 0700. The daemon's fs::create_directories() honors
the process umask (0022 on Linux), leaving hidden_service/ at 0755. tor_run_main()
returned -1 with:

  [warn] Permissions on directory .../hidden_service are too permissive.
  [warn] Failed to parse/validate config: Failed to configure rendezvous options.

This was misdiagnosed as a libtor.a build problem (the June 4 rebuild was a
red herring). The real fix is two fs::permissions() calls after create_directories().

Reproduced with a standalone harness linking libtor.a, fixed, SOCKS port 19099
came up in 1 second and Tor began bootstrapping normally.

Also force 0700 on the DataDirectory itself - same validator, same rule.

Refs: SKILL.md pitfall #59
2026-06-15 15:32:28 -07:00
Sami Ahmed cd9e023865 Bump version to v5.9.13 (transparent Qt wallet icon) v5.9.13 2026-06-13 20:49:29 -07:00
Sami Ahmed f273d651ed Make Qt wallet icon transparent (remove white field around triangle) 2026-06-13 20:45:23 -07:00
Sami Ahmed 2ac88b4e0a Add finality checkpoint at 2205000 (anti-fork); v5.9.12 v5.9.12 2026-06-13 15:09:44 -07:00
sami7777 c1340441cc Bump version to v5.9.11 v5.9.11 2026-06-11 02:57:42 -07:00
sami7777 c99d859781 Fix use-after-move crash in orphan block handling; add -ignoredupstake recovery flag
mapOrphanBlocksByPrev.insert dereferenced pblock2 after std::move'ing it into mapOrphanBlocks - guaranteed null deref (segfault at offset 4) on every orphan block received. Capture hashPrevBlock and the raw pointer before the move.

Also add -ignoredupstake (default off): bypasses the duplicate proof-of-stake rejection so canonical blocks can be imported when a fork twin staking the same outpoint was seen first. Recovery/diagnostic use only.
2026-06-11 01:34:34 -07:00
sami7777 713f69e137 Gate 7-day coin-age soft cap behind activation timestamp
The soft cap (1c068f4, 2026-04-20) shipped without a height/time gate, retroactively invalidating blocks staked earlier with long-aged coins (e.g. coins idle through the 2022-2026 freeze; block f9f976d0 at 2203410 stakes a 3.4-year-old coin). Apply the cap only to stakes at/after 1776000000 (2026-04-12 ~13:20 UTC); historical stakes validate under the rules they were created with.
2026-06-11 01:34:21 -07:00
sami7777 e3f397c7e5 Heal pnext links on active chain at LoadBlockIndex
Persisted hashNext can be stale or zeroed by crash-interrupted reorgs, breaking GetKernelStakeModifier()'s forward walk and silently rejecting valid new PoS blocks ('check kernel failed', hashProof=0). On DNS3 every one of 2,201,458 links was zeroed on disk. Root cause of the 2026-04-24 chain halt. Rebuild the in-memory links from pindexBest at every startup.
2026-06-11 01:34:20 -07:00
Krystie f80fb98f68 Merge master into cpp20-modernization (RPC fix, auto-bootstrap, tor_data fix)
Brings in:
- 79b0c4a: Fix RPC thread crash on bad auth (T001) — adapted to C++20 style
- d0fb2dc: Enable auto-bootstrap for GUI wallets
- 89a480a: Fix tor_data/state directory trap + make -notor work
- 372b252: Fix Windows CI shell for git submodule
- 6c56e41: Init secp256k1 submodule before build

Kept v5.9.9 version (cpp20-modernization's, newer than master's v5.9.7).
CI workflow kept cpp20-modernization's version (submodule init already present).
2026-06-04 18:25:12 -07:00
Krystie 610b61b1b1 Fix chain reorg crash: coinbase timestamp check + corrupted checkpoint hash
CheckBlock() at line 2825 used the heightless FutureDrift() overload,
which hardcodes 90-second drift (post-FORK_HEIGHT_V5_4). During reorgs
from the block-570 fork chain, block 571 (July 2014) has a coinbase
timestamp that legitimately exceeds 90s before block time, causing:
  ERROR: CheckBlock() : coinbase timestamp is too early
  ERROR: Reorganize() : ConnectBlock failed
  -> infinite crash loop (791 iterations recorded)

Root cause: commit a671708 (v5.8.3) tightened drift from 3min to 90sec.
The heightless overload applies this to ALL blocks regardless of height.

Fix: use explicit 10-minute tolerance in CheckBlock (context-free, no
nHeight available). The tight 90-second check is still enforced in
AcceptBlock/ConnectBlock with proper height context.

Also fix corrupted checkpoint hash at block 3935: truncated '07' in
both mainnet and testnet tables during C++20 modernization.
2026-06-04 18:21:43 -07:00
Krystie e8edcd4aa6 Merge remote-tracking branch 'gitea/master' 2026-05-30 23:01:53 -07:00
Krystie 3928f86657 Merge remote-tracking branch 'gitea/master' into cpp20-modernization 2026-05-30 23:00:56 -07:00
Krystie 67d838433d Fix getblocks: serve main chain to fork peers instead of banning them
Build All Platforms / test-linux-unit (push) Failing after 40s
Build All Platforms / test-linux-sanitizers (push) Failing after 40s
Build All Platforms / build-linux-qt (push) Failing after 40s
Build All Platforms / build-linux-daemon (push) Failing after 40s
Build All Platforms / build-windows-qt (push) Has been cancelled
Build All Platforms / build-windows-daemon (push) Has been cancelled
Build All Platforms / build-macos (push) Has been cancelled
Build All Platforms / release (push) Has been cancelled
Build All Platforms / Trigger TRI-PI ARM64 Build (push) Has been cancelled
Fork nodes (DNS3/DNS2 stuck on block 570 chain) send locators that
don't match any main chain block. Instead of disconnecting/ banning
after 3 failed getblocks attempts, this change:

- Serves main chain blocks from genesis when locator has no match
- Resets nIncompatibleGetblocks counter after 10 (so we never ban)
- Fork nodes will receive, validate, and automatically reorg to the
  longer/higher-work main chain once they see it

This fixes the 'no common blocks' deadlock while preserving chain
integrity — only a genuinely longer chain can trigger the reorg.
v5.9.10
2026-05-24 22:36:13 -07:00
Krystie e3aeff002c Remove block 570 checkpoint - let nodes sync naturally to main chain
Build All Platforms / test-linux-unit (push) Failing after 40s
Build All Platforms / test-linux-sanitizers (push) Failing after 40s
Build All Platforms / build-linux-qt (push) Failing after 40s
Build All Platforms / build-linux-daemon (push) Failing after 40s
Build All Platforms / build-windows-qt (push) Has been cancelled
Build All Platforms / build-windows-daemon (push) Has been cancelled
Build All Platforms / build-macos (push) Has been cancelled
Build All Platforms / release (push) Has been cancelled
Build All Platforms / Trigger TRI-PI ARM64 Build (push) Has been cancelled
v5.9.9
2026-05-24 21:54:42 -07:00
Krystie 09ccd4339c IBD stall fix: restore IsInitialBlockDownload() time check, add block 570 checkpoint, fix version handler IBD bypass 2026-05-24 15:40:29 -07:00
sami7777 03aa38f1b4 Promote NewIterator() override to public in both chain DB backends
The base class CTxDBBase declares NewIterator() public, but both
backends overrode it in their protected: section. That narrowed the
static access through the derived type, so the migration utility
(which holds concrete CTxDB / CRocksTxDB instances) couldn't call it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 01:01:44 -07:00
sami7777 9389a883f1 Wire CSyncManager + LevelDB->RocksDB chain DB migration
CSyncManager extracts the headers-first IBD planner from main.cpp into
its own translation unit. main.cpp loses ~570 lines of file-scope state
and helper functions; the headers handler, block-delivery latency
tracking, stall-recovery, and per-peer Tick cadence now route through
g_syncManager.

MaybeMigrateLevelDbToRocksDb() is now reachable via -migratechaindb /
-migratechaindbforce in init.cpp. Reads from <datadir>/txleveldb and
writes byte-for-byte identical records into <datadir>/rocksdb via a
new CRocksTxDB::WriteRawRecordForMigration() shim over WriteRaw.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 00:44:08 -07:00
sami7777 31fa26f03a Drop checkpoints > 2,000,000
Trim mainnet and testnet checkpoint tables to the 2,000,000 entry.
Clears the snapshot-hash entry at 2,203,594 since its corresponding
checkpoint is now gone (per the invariant noted in the comment block).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 03:07:58 -07:00
sami7777 ce96d278cd Bump client version to v6.0.0
Internal refactor milestone for the C++20 modernization series.
No protocol or on-disk format change (version.h untouched).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 03:07:57 -07:00
Krystie 7166b76bad ci: fix test-linux-sanitizers submodule checkout 2026-05-10 19:36:16 -07:00
Krystie 540db0e210 Fix wallet logging and Qt min-fee enum regressions 2026-05-10 19:18:47 -07:00
Krystie 59b75476ca ci: autonomous fix iteration 2
Generated by triangles-ci-loop.sh on 2026-05-10 18:20:35 PDT. See /var/log/triangles-ci-loop.log.
2026-05-10 18:20:35 -07:00
Krystie 0029b34698 ci: autonomous fix iteration 1
Generated by triangles-ci-loop.sh on 2026-05-10 18:02:40 PDT. See /var/log/triangles-ci-loop.log.
2026-05-10 18:02:40 -07:00
Sami 8e03e89764 ci: trigger Build All Platforms on push to cpp20-modernization 2026-05-10 17:47:35 -07:00
Krystie 3b1850af9d ci: autonomous fix iteration 1
Generated by triangles-ci-loop.sh on 2026-05-10 12:24:48 PDT. See /var/log/triangles-ci-loop.log.
2026-05-10 12:24:48 -07:00
Krystie 223029785c Fix Qt wallet model ownership calls pre-autonomous-loop-2026-05-10 2026-05-10 02:52:39 -07:00
Krystie ce8be45ea5 Fix reserve key wallet pointer ownership 2026-05-10 02:40:47 -07:00
Krystie e6d8c6dbfe Fix REST path parsing redeclarations 2026-05-10 02:33:40 -07:00
Krystie 74ec53040c Fix duplicate auto declaration regressions 2026-05-10 02:22:37 -07:00
Krystie e251a85d7a Fix string GetArg overload ambiguities 2026-05-10 02:14:17 -07:00
Krystie a16533f11b Fix accounting test wallet pointer usage 2026-05-10 02:03:52 -07:00