diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 5cbc8d793b5..915da2bd129 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -2,4 +2,7 @@ paths-ignore: - 'depends/**' - 'contrib/**' - '**/depends/**' - - '**/contrib/**' \ No newline at end of file + - '**/contrib/**' + # Archived merge/debug snapshot retained for reference; do not analyze as + # live release code or executable tests. + - 'test/test_old_v26.2_mergev1/**' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb86ffcfcee..4e303c66d3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,8 @@ name: CI on: # See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request. pull_request: + # Allow manual triggering from the Actions tab. + workflow_dispatch: # See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push. push: branches: @@ -15,6 +17,9 @@ on: tags-ignore: - '**' +permissions: + contents: read + concurrency: group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }} cancel-in-progress: true @@ -131,7 +136,10 @@ jobs: run: ./src/test/test_digibyte --show_progress - name: Run Functional Tests - run: test/functional/test_runner.py --jobs=1 + run: >- + test/functional/test_runner.py + --jobs=1 + --timeout-factor=3 - name: Upload Test Suite Log uses: actions/upload-artifact@v4 @@ -237,7 +245,7 @@ jobs: run: ./src/test/test_digibyte --show_progress - name: Run Functional Tests - run: test/functional/test_runner.py --jobs=1 + run: test/functional/test_runner.py --jobs=1 --timeout-factor=2 - name: Upload Test Suite Log uses: actions/upload-artifact@v4 diff --git a/.gitignore b/.gitignore index d7a70737d73..0b089e7e26a 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,29 @@ dist/ DigiByte-Core.dmg .wslconfig APPLICATION_BUGS.md +testnet_miner.sh + +# Audit files +audit/ +CERT_FIX_ORACLE.md +final_audit.MD +MVP_PLAN.md +reports/*.md +reports/**/*.md +.audit_proposals/agent4.md +.audit_proposals/agent3.md +.audit_proposals/agent2.md +.audit_proposals/agent1.md +RC39_ISSUES.md +RC40_ISSUES.md +RC40_FIXES.md +RC41_FIX_WORK_PROMPT.md +RC41_ISSUES.md +TREASURY_PROPOSAL.MD +RC43_ISSUES.md +DIGIDOLLAR_SAFE_LAUNCH.md +RC43_TESTNET25_FORK_EXPLAINER.md +RC43_FIX_WORK_PROMPT.md +Z_RED_HORNET_FINAL_PROMPT.md +Z_RED_HORNET_v2.md +Z_DOC_VALIDATION_v9.26.2_PROMPT.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000000..c4518f2cbe8 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,1513 @@ +# DigiByte Blockchain Architecture +**DigiByte Core v9.26.2 (Based on Bitcoin Core v26.2)** +*Comprehensive Technical Documentation* +*Last Updated: 2026-05-20* +*Validation Status: Spot-validated against live `feature/digidollar-v1` code surfaces listed in Appendix D* + +--- + +## Executive Summary + +DigiByte is a decentralized, open-source blockchain focused on speed, security, and decentralization. This document provides a complete architectural overview of the DigiByte Core implementation, validated against the actual codebase. + +### Key Differentiators from Bitcoin + +| Feature | Bitcoin | DigiByte | +|---------|---------|----------| +| Block Time | 10 minutes | **15 seconds** | +| Mining Algorithms | SHA256D only | **5 algorithms** (multi-algo) | +| Difficulty Adjustment | 2016 blocks | **Real-time per block** | +| Max Supply | 21 million | **21 billion** | +| Coinbase Maturity | 100 blocks | **8 blocks** (early), 100 (later) | +| Privacy | Standard relay | **Dandelion++** | +| Stablecoin | None | **DigiDollar (native)** | + +--- + +## Table of Contents + +1. [System Overview](#1-system-overview) +2. [Directory Structure](#2-directory-structure) +3. [Consensus Layer](#3-consensus-layer) +4. [Multi-Algorithm Mining](#4-multi-algorithm-mining) +5. [Difficulty Adjustment](#5-difficulty-adjustment) +6. [Block & Chain Management](#6-block--chain-management) +7. [Transaction Processing](#7-transaction-processing) +8. [Script & Signature Verification](#8-script--signature-verification) +9. [P2P Networking](#9-p2p-networking) +10. [Wallet System](#10-wallet-system) +11. [RPC Interface](#11-rpc-interface) +12. [DigiDollar Stablecoin](#12-digidollar-stablecoin) +13. [Oracle System](#13-oracle-system) + +--- + +## 1. System Overview + +### 1.1 Architecture Diagram + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ DigiByte Core Node │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ RPC API │ │ REST API │ │ ZMQ Pub │ │ GUI │ │ +│ │ (JSON-RPC) │ │ (HTTP) │ │ (Events) │ │ (Qt) │ │ +│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ +│ │ │ │ │ │ +│ ┌──────┴─────────────────┴─────────────────┴─────────────────┴──────┐ │ +│ │ Node Interface Layer │ │ +│ └────────────────────────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────────────────────┴──────────────────────────────────┐ │ +│ │ ChainstateManager │ │ +│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ +│ │ │ Chainstate │ │ BlockManager │ │ Mempool │ │ │ +│ │ │ (UTXO Set) │ │ (Block Index) │ │ (+ Stempool) │ │ │ +│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ +│ └────────────────────────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────────────────────┴──────────────────────────────────┐ │ +│ │ Consensus Layer │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │ │ +│ │ │ Validation │ │ PoW Check │ │ Difficulty │ │ DigiDollar│ │ │ +│ │ │ Rules │ │ (5 Algos) │ │ Adjustment │ │ Consensus │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ └──────────┘ │ │ +│ └────────────────────────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────────────────────┴──────────────────────────────────┐ │ +│ │ P2P Network Layer │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │ │ +│ │ │ CConnman │ │ V1/V2 │ │ Dandelion++ │ │ Oracle │ │ │ +│ │ │ (Peers) │ │ Transport │ │ (Privacy) │ │ P2P │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ └──────────┘ │ │ +│ └───────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌───────────────────────────────────────────────────────────────────┐ │ +│ │ Storage Layer │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │ │ +│ │ │ LevelDB │ │ Block │ │ Wallet │ │ Oracle │ │ │ +│ │ │ (UTXO/Idx) │ │ Files │ │ DB │ │ Cache │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ └──────────┘ │ │ +│ └───────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 1.2 Core Components + +| Component | Purpose | Key Files | +|-----------|---------|-----------| +| **Consensus** | Block/tx validation rules | `src/validation.cpp`, `src/consensus/` | +| **Mining** | Multi-algorithm PoW | `src/pow.cpp`, `src/crypto/` | +| **Chain** | Block index & UTXO | `src/chain.cpp`, `src/coins.cpp` | +| **Network** | P2P communication | `src/net.cpp`, `src/net_processing.cpp` | +| **Wallet** | Key & transaction mgmt | `src/wallet/` | +| **RPC** | External API | `src/rpc/` | +| **DigiDollar** | Stablecoin system | `src/digidollar/`, `src/oracle/` | + +--- + +## 2. Directory Structure + +``` +digibyte/ +├── src/ +│ ├── consensus/ # Consensus rules +│ │ ├── params.h # Chain parameters (difficulty, timing) +│ │ ├── validation.h # Validation state enums +│ │ ├── tx_check.cpp # Transaction validation +│ │ ├── dca.cpp # Dynamic Collateral Adjustment +│ │ ├── err.cpp # Emergency Redemption Ratio +│ │ └── volatility.cpp # Volatility protection +│ │ +│ ├── primitives/ # Core data structures +│ │ ├── block.h # CBlock, CBlockHeader (multi-algo) +│ │ ├── transaction.h # CTransaction, CTxIn, CTxOut +│ │ └── oracle.h # Oracle message structures +│ │ +│ ├── crypto/ # Cryptographic algorithms +│ │ ├── sha256.cpp # SHA256D (algo 0) +│ │ ├── scrypt.cpp # Scrypt (algo 1) +│ │ ├── hashgroestl.h # Groestl (algo 2) +│ │ ├── hashskein.h # Skein (algo 3) +│ │ ├── hashqubit.h # Qubit (algo 4) +│ │ ├── odocrypt.cpp # Odocrypt (algo 7) +│ │ └── hashodo.h # Odo hash wrapper +│ │ +│ ├── script/ # Script system +│ │ ├── interpreter.cpp # Script execution (2308 lines) +│ │ ├── script.h # Opcodes, CScript class +│ │ └── sigcache.cpp # Signature caching +│ │ +│ ├── wallet/ # Wallet implementation +│ │ ├── wallet.h # CWallet class +│ │ ├── scriptpubkeyman.h # Key management +│ │ ├── spend.cpp # Transaction creation +│ │ └── digidollarwallet.cpp # DD wallet integration +│ │ +│ ├── net.cpp # P2P networking (~3900 lines, V1+V2 BIP324 transport) +│ ├── net_processing.cpp # Message handling (~7500 lines, includes oracle msg handlers) +│ ├── dandelion.cpp # Dandelion++ privacy (~500 lines) +│ ├── validation.cpp # Block validation (~7050 lines; DD-aware ConnectBlock) +│ ├── pow.cpp # Difficulty adjustment +│ │ +│ ├── digidollar/ # DigiDollar stablecoin +│ │ ├── digidollar.h # Core DD structures +│ │ ├── txbuilder.cpp # Mint/Transfer/Redeem builders +│ │ ├── validation.cpp # DD consensus rules +│ │ ├── health.cpp # System health monitoring +│ │ └── scripts.cpp # DD script handling +│ │ +│ ├── oracle/ # Oracle system +│ │ ├── bundle_manager.cpp # Oracle bundle management +│ │ ├── exchange.cpp # Exchange API integration +│ │ ├── node.cpp # Oracle node operations +│ │ └── mock_oracle.cpp # Testing mock oracle +│ │ +│ ├── rpc/ # RPC commands +│ │ ├── blockchain.cpp # Chain queries +│ │ ├── mining.cpp # Mining commands +│ │ ├── net.cpp # Network commands +│ │ ├── rawtransaction.cpp # Raw tx handling +│ │ └── digidollar.cpp # DD RPC commands +│ │ +│ ├── kernel/ # Chain parameters +│ │ └── chainparams.cpp # Network configurations +│ │ +│ └── qt/ # GUI components +│ ├── digidollartab.cpp # DD main tab +│ └── digidollar*.cpp # DD widgets +│ +├── src/test/ # C++ unit tests and fuzz targets +├── src/wallet/test/ # Wallet C++ tests (linked into test_digibyte) +├── src/qt/test/ # Qt C++ tests +├── test/ +│ └── functional/ # Python integration tests +│ +└── doc/ # Documentation +``` + +--- + +## 3. Consensus Layer + +### 3.1 Block Validation Flow + +``` +AcceptBlockHeader() + ↓ +CheckBlockHeader() [PoW verification - algorithm-specific] + ↓ +ContextualCheckBlockHeader() [Difficulty target validation] + ↓ +AcceptBlock() / ProcessNewBlock() + ↓ +CheckBlock() [Context-independent: merkle root, size, transactions] + ↓ +ContextualCheckBlock() [Context-dependent: finality, witness, oracle] + ↓ +ActivateBestChain() → ActivateBestChainStep() + ↓ +ConnectTip() → ConnectBlock() [Full UTXO validation, script execution] + ↓ +UpdateTip() [Chain state update, notifications] +``` + +**Key Files:** +- `src/validation.cpp` - Main validation logic +- `src/consensus/tx_check.cpp` - Transaction validation +- `src/pow.cpp` - PoW and difficulty + +### 3.2 Consensus Parameters + +**File:** `src/consensus/params.h` (struct Params is roughly lines 83-238) + +```cpp +struct Params { + // Block timing + int64_t nPowTargetSpacing = 15; // 15-second blocks + + // Multi-algorithm + int64_t nAveragingInterval = 10; // 10 blocks per algo + int64_t multiAlgoTargetSpacing = 150; // 30s × 5 algos (V3 MultiShield) + int64_t multiAlgoTargetSpacingV4 = 75; // 15s × 5 algos (V4 DigiSpeed) + + // Hard fork heights + int64_t multiAlgoDiffChangeTarget = 145000; // MultiAlgo V2 + int64_t alwaysUpdateDiffChangeTarget = 400000; // MultiShield V3 + int64_t workComputationChangeTarget = 1430000; // DigiSpeed V4 + int OdoHeight = 9112320; // Odocrypt activation (BuriedDeployment) + + // DigiDollar / Oracle + int nDDActivationHeight{0}; // BIP9 alignment height + int nOracleActivationHeight{std::numeric_limits::max()}; // Live-feed activation height + int nOracleEpochLength{1440}; // Blocks per oracle epoch (default: 1440 = 24 hours) + int nOracleRequiredMessages{1}; // Off-chain quorum threshold + int nOracleTotalOracles{1}; // Total reserved oracle slots + std::vector vOraclePublicKeys; // Hardcoded XOnlyPubKeys (hex) + int nDigiDollarMuSig2Height{std::numeric_limits::max()}; // MuSig2 v0x03 bundle activation + int nOraclePubkeyCount{0}; // MuSig2 pubkey count + int nOracleConsensusRequired{0}; // MuSig2 quorum threshold +}; +``` + +`Consensus::DEPLOYMENT_DIGIDOLLAR` (bit 23) is the BIP9 deployment that gates `SCRIPT_VERIFY_DIGIDOLLAR`; production `min_activation_height`, `nDDActivationHeight`, `nOracleActivationHeight`, and `nDigiDollarMuSig2Height` are aligned in `src/kernel/chainparams.cpp` (mainnet 23627520, testnet26 600). Testnet26 uses default P2P port 12033, data directory `testnet26`, reset genesis timestamp 1780156800, and the same timestamp as its BIP9 start. Default regtest uses BIP9 `ALWAYS_ACTIVE` / `min_activation_height=0` with DD/oracle height gates at 650; `nDigiDollarMuSig2Height` follows the effective BIP9 boundary (`0`) so v0x03 quotes are valid whenever DigiDollar is active. The direct `-digidollaractivationheight=N` knob retargets both BIP9 and the DD/oracle/MuSig2 gates. Startup oracle-price cache reconstruction follows the BIP9 predicate used by block connection so regtest BIP9-active oracle bundles below 650 are not skipped on restart/reindex. MuSig2 v0x03 oracle bundles are required as soon as DigiDollar is active, not before the DD/oracle activation height. + +### 3.3 Block Validation Results + +**File:** `src/consensus/validation.h` (lines 64-84) + +```cpp +enum class BlockValidationResult { + BLOCK_RESULT_UNSET = 0, + BLOCK_CONSENSUS, // Consensus rule violation + BLOCK_RECENT_CONSENSUS_CHANGE, // Consensus change (soft-fork grace period) + BLOCK_CACHED_INVALID, // Previously invalid + BLOCK_INVALID_HEADER, // PoW/timestamp invalid + BLOCK_MUTATED, // Data corruption + BLOCK_MISSING_PREV, // Missing parent + BLOCK_INVALID_PREV, // Invalid parent + BLOCK_TIME_FUTURE, // Too far in future + BLOCK_CHECKPOINT, // Checkpoint violation + BLOCK_INVALID_ALGO, // Invalid algorithm (DigiByte-specific) + BLOCK_HEADER_LOW_WORK // Insufficient work +}; +``` + +### 3.4 Key Constants + +**File:** `src/consensus/consensus.h` + +| Constant | Value | Purpose | +|----------|-------|---------| +| `COINBASE_MATURITY` | 8 | Blocks before coinbase spendable | +| `COINBASE_MATURITY_2` | 100 | Later period maturity | +| `MAX_BLOCK_WEIGHT` | 4,000,000 | Max block weight (BIP141) | +| `MAX_BLOCK_SIGOPS_COST` | 80,000 | Max signature operations | +| `WITNESS_SCALE_FACTOR` | 4 | Witness discount factor | + +--- + +## 4. Multi-Algorithm Mining + +### 4.1 Supported Algorithms + +**File:** `src/primitives/block.h` (lines 16-44) + +```cpp +enum { + ALGO_SHA256D = 0, // Bitcoin-compatible + ALGO_SCRYPT = 1, // Memory-hard (Litecoin-style) + ALGO_GROESTL = 2, // Groestl-512 → SHA256 + ALGO_SKEIN = 3, // Skein-512 → SHA256 + ALGO_QUBIT = 4, // 5-hash chain + ALGO_ODO = 7, // Odocrypt (replaces Groestl post-9.1M) + NUM_ALGOS = 5 // Active algorithms at any time +}; + +// Version encoding (bits 8-11) +BLOCK_VERSION_SHA256D = (2 << 8) // 0x0200 +BLOCK_VERSION_SCRYPT = (0 << 8) // 0x0000 +BLOCK_VERSION_GROESTL = (4 << 8) // 0x0400 +BLOCK_VERSION_SKEIN = (6 << 8) // 0x0600 +BLOCK_VERSION_QUBIT = (8 << 8) // 0x0800 +BLOCK_VERSION_ODO = (14 << 8) // 0x0E00 +``` + +### 4.2 Algorithm Timeline + +| Era | Block Range | Active Algorithms | +|-----|-------------|-------------------| +| 1 | 0 - 144,999 | Scrypt only | +| 2 | 145,000 - 9,099,999 | SHA256D, Scrypt, Groestl, Skein, Qubit | +| 3 | 9,100,000+ | SHA256D, Scrypt, Skein, Qubit, **Odocrypt** | + +### 4.3 PoW Hash Computation + +**File:** `src/primitives/block.cpp` (lines 56-106) + +```cpp +uint256 CBlockHeader::GetPoWAlgoHash(const Consensus::Params& params) const +{ + switch (GetAlgo()) { + case ALGO_SHA256D: return GetHash(); // Double SHA256 + case ALGO_SCRYPT: return scrypt_1024_1_1_256(...); + case ALGO_GROESTL: return HashGroestl(...); // Groestl-512 → SHA256 + case ALGO_SKEIN: return HashSkein(...); // Skein-512 → SHA256 + case ALGO_QUBIT: return HashQubit(...); // Luffa→Cubehash→Shavite→SIMD→Echo + case ALGO_ODO: return HashOdo(..., OdoKey(params, nTime)); + } +} +``` + +### 4.4 Odocrypt Key Generation + +**File:** `src/crypto/odocrypt.cpp` + +Odocrypt uses a time-based key that changes every 10 days: + +```cpp +uint32_t OdoKey(const Consensus::Params& params, uint32_t nTime) { + uint32_t nShapechangeInterval = 864000; // 10 days in seconds + return nTime - nTime % nShapechangeInterval; +} +``` + +The cipher uses: +- **84 rounds** of encryption +- **S-boxes**: 6-bit (10 boxes) + 10-bit (10 boxes) +- **P-boxes**: 2 permutation boxes with 6 subrounds +- **Keccak-p[800]** finalization + +### 4.5 Algorithm Lookup Cache + +**File:** `src/chain.h` (line 212) + +```cpp +// Fast per-algorithm block tracking +CBlockIndex *lastAlgoBlocks[NUM_ALGOS_IMPL]; +``` + +This cache enables O(1) lookup of the last block for each algorithm, critical for difficulty adjustment. + +--- + +## 5. Difficulty Adjustment + +### 5.1 Evolution of Algorithms + +| Version | Block Range | Name | Key Feature | +|---------|-------------|------|-------------| +| V1 | 0 - 144,999 | DigiShield | 144-block interval | +| V2 | 145,000 - 399,999 | MultiAlgo | Per-algorithm targeting | +| V3 | 400,000 - 1,429,999 | MultiShield | Median time + global adjustment | +| V4 | 1,430,000+ | DigiSpeed | Optimized 15s targeting | + +### 5.2 Difficulty Selection Logic + +**File:** `src/pow.cpp` (lines 256-285) + +```cpp +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, + const CBlockHeader *pblock, + const Consensus::Params& params, + int algo) +{ + if (pindexLast->nHeight < params.multiAlgoDiffChangeTarget) + return GetNextWorkRequiredV1(pindexLast, params, algo); + else if (pindexLast->nHeight < params.alwaysUpdateDiffChangeTarget) + return GetNextWorkRequiredV2(pindexLast, params, algo); + else if (pindexLast->nHeight < params.workComputationChangeTarget) + return GetNextWorkRequiredV3(pindexLast, params, algo); + else + return GetNextWorkRequiredV4(pindexLast, params, algo); +} +``` + +### 5.3 V4 DigiSpeed Algorithm + +**File:** `src/pow.cpp` (lines 192-254) + +```cpp +// Parameters +nAveragingTargetTimespanV4 = 10 * 75; // 750 seconds +nMinActualTimespanV4 = 690; // 92% of target +nMaxActualTimespanV4 = 870; // 116% of target +nLocalTargetAdjustment = 4; // 4% per-algo adjustment + +// Algorithm +1. Look back 50 blocks (10 per algorithm × 5 algorithms) +2. Use GetMedianTimePast() to prevent time-warp attacks +3. Calculate actual timespan with damping: target + (actual - target) / 4 +4. Apply limits (690-870 seconds) +5. Global retarget: bnNew *= nActualTimespan / 750 +6. Per-algo adjustment: ±4% based on algorithm's block share +``` + +### 5.4 Difficulty Adjustment Parameters + +**File:** `src/kernel/chainparams.cpp` (lines 142-163) + +| Parameter | V1-V2 | V3 | V4 | +|-----------|-------|-------|-------| +| Target Spacing | 150s (30s×5) | 150s | 75s (15s×5) | +| Averaging Window | 10 blocks | 50 blocks | 50 blocks | +| Max Adjust Down | 40% | 16% | 16% | +| Max Adjust Up | 20% | 8% | 8% | +| Local Adjustment | N/A | 4% | 4% | + +--- + +## 6. Block & Chain Management + +### 6.1 Block Structure + +**File:** `src/primitives/block.h` + +```cpp +class CBlockHeader { + int32_t nVersion; // Algorithm encoded in bits 8-11 + uint256 hashPrevBlock; // Previous block hash + uint256 hashMerkleRoot; // Merkle root of transactions + uint32_t nTime; // Block timestamp + uint32_t nBits; // Difficulty target (compact) + uint32_t nNonce; // PoW counter +}; + +class CBlock : public CBlockHeader { + std::vector vtx; // Block transactions + mutable bool fChecked; // Validation cache +}; +``` + +### 6.2 Block Index Structure + +**File:** `src/chain.h` (lines 146-384) + +```cpp +class CBlockIndex { + // Identity + const uint256* phashBlock; // Block hash pointer + CBlockIndex* pprev; // Previous block + CBlockIndex* pskip; // Skip pointer for fast traversal + + // Chain position + int nHeight; // Block height + int nFile; // Block file index + unsigned int nDataPos; // Position in block file + unsigned int nUndoPos; // Position in undo file + + // Validation + uint32_t nStatus; // BlockStatus flags + arith_uint256 nChainWork; // Cumulative work + + // Transactions + unsigned int nTx; // Transactions in block + unsigned int nChainTx; // Cumulative transactions + + // DigiByte multi-algo + CBlockIndex *lastAlgoBlocks[NUM_ALGOS_IMPL]; // Per-algo tracking +}; +``` + +### 6.3 Chain State Management + +**File:** `src/validation.h` (lines 491-815) + +``` +ChainstateManager +├── m_ibd_chainstate (Normal IBD chainstate) +├── m_snapshot_chainstate (Optional assumed-valid snapshot) +├── m_active_chainstate (Points to active one) +└── m_blockman (Shared BlockManager) + └── m_block_index (All blocks ever seen) + +Chainstate +├── m_chain (CChain - active chain by height) +├── m_coins_views (UTXO cache hierarchy) +│ ├── m_dbview (LevelDB on disk) +│ ├── m_catcherview (Error handler) +│ └── m_cacheview (Memory cache) +├── m_mempool (Transaction memory pool) +└── m_stempool (Dandelion++ stem pool) +``` + +### 6.4 UTXO Management + +**File:** `src/coins.h` + +```cpp +struct Coin { + CTxOut out; // The unspent output + unsigned int fCoinBase : 1; + uint32_t nHeight : 31; // Inclusion height +}; + +// Three-level cache hierarchy +CCoinsViewDB → LevelDB on disk +CCoinsViewBacked → Composable wrapper +CCoinsViewCache → In-memory cache with DIRTY/FRESH flags +``` + +### 6.5 Block Storage + +**Files:** `blocks/blk?????.dat` (128 MiB max each) + +``` +Block File Format: +[4-byte magic][4-byte size][block data][4-byte magic][4-byte size][block data]... + +Undo File Format (rev?????.dat): +[CBlockUndo data for reverting transactions] + +Index Database (blocks/index/): +- 'b' + hash → CDiskBlockIndex +- 'f' + num → CBlockFileInfo +- 'l' → Last file number +``` + +--- + +## 7. Transaction Processing + +### 7.1 Transaction Structure + +**File:** `src/primitives/transaction.h` + +```cpp +class CTxIn { + COutPoint prevout; // Previous output reference + CScript scriptSig; // Signature script + uint32_t nSequence; // Sequence number (BIP68) + CScriptWitness scriptWitness; // SegWit witness +}; + +class CTxOut { + CAmount nValue; // Value in satoshis + CScript scriptPubKey; // Output script +}; + +class CTransaction { + std::vector vin; + std::vector vout; + int32_t nVersion; // 2 for standard, DD marker for DigiDollar + uint32_t nLockTime; + const uint256 hash; // Cached txid + const uint256 m_witness_hash; // Cached wtxid +}; +``` + +### 7.2 DigiDollar Transaction Encoding + +**File:** `src/primitives/transaction.h` (lines 34-58) + +```cpp +static constexpr int32_t DD_TX_VERSION = 0x0D1D0770; // "DigiDollar" marker + +enum DigiDollarTxType : uint8_t { + DD_TX_NONE = 0, // Regular transaction + DD_TX_MINT = 1, // Lock DGB, create DigiDollars + DD_TX_TRANSFER = 2, // Transfer DigiDollars + DD_TX_REDEEM = 3 // Burn DigiDollars, unlock DGB +}; + +// Version encoding: (type << 24) | (flags << 16) | (DD_TX_VERSION & 0xFFFF) +``` + +### 7.3 Transaction Validation Flow + +``` +CheckTransaction() [Context-free] + ↓ + ├── Non-empty inputs/outputs + ├── Size within limits + ├── Output values valid (0 ≤ v ≤ MAX_MONEY) + ├── No duplicate inputs (CVE-2018-17144) + ├── Coinbase scriptSig length (2-100 bytes) + └── DigiDollar type validation + +MemPoolAccept::PreChecks() [Mempool validation] + ↓ + ├── DigiDollar validation context + ├── Standard transaction checks + ├── Minimum size (65 bytes) + ├── Locktime finality + ├── Duplicate/conflict detection + ├── UTXO availability + └── BIP68 sequence lock validation + +ConnectBlock() [Consensus validation] + ↓ + ├── CheckTxInputs() - UTXO availability + ├── SequenceLocks() - Relative timelocks + ├── CheckInputScripts() - Script execution + └── UpdateCoins() - UTXO set update +``` + +### 7.4 Fee Policy + +**File:** `src/policy/policy.h` + +| Constant | Value | Purpose | +|----------|-------|---------| +| `DEFAULT_MIN_RELAY_TX_FEE` | 100,000 sat/kvB | Minimum relay fee | +| `DUST_RELAY_TX_FEE` | 30,000 sat/kvB | Dust threshold | +| `DEFAULT_INCREMENTAL_RELAY_FEE` | 10,000 sat/kvB | RBF increment | +| `MAX_STANDARD_TX_WEIGHT` | 400,000 | Max relay weight | +| `DEFAULT_ANCESTOR_LIMIT` | 25 | Max mempool ancestors | +| `DEFAULT_DESCENDANT_LIMIT` | 25 | Max mempool descendants | + +--- + +## 8. Script & Signature Verification + +### 8.1 Script Interpreter + +**File:** `src/script/interpreter.cpp` (~2300 lines) + +```cpp +bool EvalScript( + std::vector>& stack, + const CScript& script, + unsigned int flags, + const BaseSignatureChecker& checker, + SigVersion sigversion, + ScriptExecutionData& execdata, + ScriptError* serror +); +``` + +### 8.2 Signature Versions + +**File:** `src/script/interpreter.h` (lines 210-216) + +```cpp +enum class SigVersion { + BASE = 0, // Legacy (P2PKH, P2SH) + WITNESS_V0 = 1, // SegWit v0 (P2WPKH, P2WSH) + TAPROOT = 2, // Taproot key path + TAPSCRIPT = 3 // Taproot script path +}; +``` + +### 8.3 Verification Flags + +**File:** `src/script/interpreter.h` (script verify flags around lines 43-150) + +| Flag | Purpose | +|------|---------| +| `SCRIPT_VERIFY_P2SH` | BIP16 P2SH support | +| `SCRIPT_VERIFY_DERSIG` | Strict DER encoding | +| `SCRIPT_VERIFY_LOW_S` | Low S signatures | +| `SCRIPT_VERIFY_NULLDUMMY` | Zero-length CHECKMULTISIG dummy | +| `SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY` | BIP65 CLTV | +| `SCRIPT_VERIFY_CHECKSEQUENCEVERIFY` | BIP112 CSV | +| `SCRIPT_VERIFY_WITNESS` | BIP141 SegWit | +| `SCRIPT_VERIFY_TAPROOT` | BIP341/342 Taproot | +| `SCRIPT_VERIFY_DIGIDOLLAR` | DigiDollar opcodes (`OP_DIGIDOLLAR`/`OP_DDVERIFY`/`OP_CHECKPRICE`/`OP_CHECKCOLLATERAL`/`OP_ORACLE`); set in `GetBlockScriptFlags()` (`validation.cpp:2755, 2796-2797`) only when BIP9 `DEPLOYMENT_DIGIDOLLAR` is active. | + +### 8.4 DigiDollar Opcodes + +**File:** `src/script/script.h:210-214` + +```cpp +OP_DIGIDOLLAR = 0xbb, // DD output / payload marker (Tapscript OP_SUCCESSx slot) +OP_DDVERIFY = 0xbc, // Verify DD conditions (Tapscript OP_SUCCESSx slot) +OP_CHECKPRICE = 0xbd, // Reserved/disabled price check (Tapscript OP_SUCCESSx slot) +OP_CHECKCOLLATERAL = 0xbe, // Verify collateral ratio (Tapscript OP_SUCCESSx slot) +OP_ORACLE = 0xbf // Coinbase oracle bundle marker (Tapscript OP_SUCCESSx slot) +``` + +`MAX_OPCODE` is now `OP_ORACLE` (`script.h:220`). These opcodes consume BIP-342 OP_SUCCESSx slots (script.h's `OP_NOP10` is `0xb9`, not `0xb8`); they behave as OP_SUCCESSx until `SCRIPT_VERIFY_DIGIDOLLAR` is set, at which point the interpreter dispatches them via `IsDigiDollarOpcode` / `IsOpSuccessForFlags` (`src/script/interpreter.cpp:439-453`) and the per-opcode handlers (around lines 660-754). `OP_CHECKPRICE` is reserved and deterministically disabled; when reached under DigiDollar script flags it consumes its operand and pushes false instead of consulting node-local oracle state. + +### 8.5 Taproot Support + +**Files:** `src/script/interpreter.cpp` (lines 1980-2106) + +- **Key path spending**: Single Schnorr signature (64 bytes) +- **Script path spending**: Control block + script + witness +- **Leaf versions**: 0xc0 for Tapscript (BIP342) +- **CHECKSIGADD** (0xba): Multi-sig accumulator for Tapscript + +```cpp +// Taproot constants +TAPROOT_LEAF_MASK = 0xfe +TAPROOT_LEAF_TAPSCRIPT = 0xc0 +TAPROOT_CONTROL_BASE_SIZE = 33 +TAPROOT_CONTROL_NODE_SIZE = 32 +TAPROOT_CONTROL_MAX_NODE_COUNT = 128 +``` + +--- + +## 9. P2P Networking + +### 9.1 Network Architecture + +**Files:** `src/net.cpp` (~3900 lines), `src/net_processing.cpp` (~7300 lines) + +``` +CConnman (Connection Manager) +├── m_nodes[] Active peer connections +├── ThreadSocketHandler() I/O polling +├── ThreadOpenConnections() Outbound connections +├── ThreadMessageHandler() Message processing +└── ThreadDandelionShuffle() Privacy route reshuffling + +CNode (Peer Connection) +├── m_transport V1 or V2 (BIP324) transport +├── vSendMsg Outgoing message queue +├── vRecvMsg Received message queue +└── Connection metadata (type, services, latency) + +PeerManagerImpl (Message Processing) +├── ProcessMessages() Route incoming messages +├── SendMessages() Queue outgoing messages +└── RelayTransaction() Broadcast transactions +``` + +### 9.2 Connection Types + +| Type | Purpose | Count | +|------|---------|-------| +| OUTBOUND_FULL_RELAY | Full tx/block/addr relay | 16 | +| BLOCK_RELAY | Blocks only (privacy) | 2 | +| MANUAL | -addnode connections | 8 | +| INBOUND | Peer-initiated | Up to 125 total | +| FEELER | Quality testing | 1 | + +### 9.3 Dandelion++ Privacy + +**File:** `src/dandelion.cpp` (~500 lines) + +``` +Transaction Privacy Flow: +1. Local tx enters stempool (private) +2. Embargo set: random(10-30 seconds) +3. Send to single Dandelion destination (stem phase) +4. Embargo expires → move to mempool (fluff phase) +5. Broadcast to all peers (normal relay) + +Route Shuffling: +- Every 10 minutes: reshuffle destination mapping +- 2 maximum destinations per node +- Discovery via special INV message (DANDELION_DISCOVERYHASH) +``` + +**Key Constants:** +```cpp +DANDELION_MAX_DESTINATIONS = 2 +DANDELION_SHUFFLE_INTERVAL = 10 minutes +DANDELION_EMBARGO_MINIMUM = 10 seconds +DANDELION_EMBARGO_AVG_ADD = 20 seconds +DANDELION_FLUFF = 10 // 10% immediate fluff probability +``` + +### 9.4 V2 Transport (BIP324) + +**Files:** `src/bip324.cpp`, `src/net.cpp`/`src/net.h` (`V2Transport` declared around `net.h:469`) + +- **Key exchange**: Elliptic Curve Diffie-Hellman (ElligatorSwift, BIP324) +- **Encryption**: ChaCha20-Poly1305 AEAD with forward-secure rekeying +- **Garbage padding**: Up to 4095 bytes +- **Fallback**: Automatic V1 detection on protocol-magic mismatch +- **Enable flag**: `-v2transport=1` (off by default; outbound use is gated by per-connection `use_v2transport` in `CConnman::OpenNetworkConnection`) + +### 9.5 Message Types + +**File:** `src/protocol.h` + +| Message | Purpose | +|---------|---------| +| VERSION/VERACK | Handshake | +| INV/GETDATA/TX/BLOCK | Data exchange | +| HEADERS/GETHEADERS | Headers-first sync | +| PING/PONG | Keepalive | +| ADDR/ADDRV2 | Address gossip | +| CMPCTBLOCK | Compact blocks (BIP152) | +| **DANDELIONTX** | Stem phase transaction | +| **ORACLEPRICE** | Individual oracle price message | +| **ORACLEBUNDLE** | Legacy oracle bundle wrapper; V1 block data uses MuSig2 coinbase bundles | +| **GETORACLES** | Oracle data request | +| **ORACLECONSENSUS** / **ORACLEATTESTATION** | MuSig2 oracle consensus/attestation coordination | +| **ORACLEMUSIGNONCE** / **ORACLEMUSIGCONTEXT** / **ORACLEMUSIGPARTIALSIG** | MuSig2 nonce/context/partial-signature exchange | +| **ORACLEHEARTBEAT** | Oracle liveness heartbeat | + +--- + +## 10. Wallet System + +### 10.1 Wallet Architecture + +**File:** `src/wallet/wallet.h` + +```cpp +class CWallet { + // Transaction management + std::map mapWallet; + + // Key management + std::map> m_spk_managers; + + // Address book + std::map m_address_book; + + // DigiDollar integration + std::unique_ptr m_dd_wallet; + + // Locking + mutable RecursiveMutex cs_wallet; +}; +``` + +### 10.2 Key Management + +**File:** `src/wallet/scriptpubkeyman.h` + +``` +ScriptPubKeyMan (Abstract Base) +├── LegacyScriptPubKeyMan +│ ├── HD derivation (external/internal chains) +│ ├── Keypool management (1000 keys default) +│ └── P2PKH, P2SH-P2WPKH, P2WPKH support +│ +└── DescriptorScriptPubKeyMan + ├── BIP32/44/49/84/86 descriptors + ├── Taproot (tr()) support + └── DigiDollar key derivation +``` + +### 10.3 Transaction Creation + +**File:** `src/wallet/spend.cpp` + +``` +CreateTransaction() Flow: +1. SelectCoins() - Choose UTXOs + ├── BNB (Branch and Bound) - Optimal + ├── Knapsack - Fallback + └── SRD (Single Random Draw) - Simple +2. Build outputs with fees +3. Add change output +4. SignTransaction() - Sign inputs + ├── ECDSA for legacy/SegWit + └── Schnorr for Taproot +``` + +### 10.4 DigiDollar Wallet + +**File:** `src/wallet/digidollarwallet.h` + +```cpp +class DigiDollarWallet { + // Key management + std::map dd_owner_keys; // For vault redemption + std::map dd_address_keys; // For received DD + + // UTXO tracking + std::map dd_utxos; // DD amount per UTXO + + // Position tracking + std::map collateral_positions; + + // Operations + bool MintDigiDollar(...); + bool TransferDigiDollar(...); + bool RedeemDigiDollar(...); +}; +``` + +--- + +## 11. RPC Interface + +### 11.1 RPC Architecture + +**Files:** `src/rpc/server.cpp`, `src/httprpc.cpp` + +``` +HTTP POST → Authorization → JSON Parse → CRPCTable::execute() → Response + +Authentication Methods: +1. Cookie-based (default, secure) +2. Username/password (deprecated) +3. RPC auth with salt/hash (multi-user) +``` + +### 11.2 Command Categories + +| Category | Commands | File | +|----------|----------|------| +| **blockchain** | getblock, getblockcount, getdifficulty... | blockchain.cpp | +| **mining** | getmininginfo, getblocktemplate, submitblock... | mining.cpp | +| **network** | getpeerinfo, addnode, getnetworkinfo... | net.cpp | +| **rawtransaction** | createrawtransaction, signrawtransaction... | rawtransaction.cpp | +| **wallet** | getnewaddress, sendtoaddress, listunspent... | wallet/rpc/*.cpp | +| **digidollar** | mintdigidollar, redeemdigidollar, getoracleprice... | digidollar.cpp | + +### 11.3 DigiByte-Specific RPC + +**Files:** `src/rpc/blockchain.cpp` (DigiByte-specific helpers), `src/rpc/digidollar.cpp` (DigiDollar / oracle), wallet-context DD RPCs in `src/wallet/rpc/wallet.cpp`. + +| Command | File | Purpose | +|---------|------|---------| +| `getblockreward` | `rpc/blockchain.cpp` | Current block subsidy with multi-algo awareness | +| `getdigidollarstats` | `rpc/digidollar.cpp` | Network-wide DD statistics | +| `getdcamultiplier` | `rpc/digidollar.cpp` | DCA collateral multiplier | +| `getoracleprice` / `getalloracleprices` | `rpc/digidollar.cpp` | Live oracle consensus / per-oracle prices | +| `getoracles` / `listoracle` / `getoraclepubkey` | `rpc/digidollar.cpp` | Oracle roster introspection | +| `validateddaddress` (wallet) | `wallet/rpc/wallet.cpp` | Validate DD address | +| `mintdigidollar` / `senddigidollar` / `redeemdigidollar` (wallet) | `wallet/rpc/wallet.cpp` | DigiDollar mint/transfer/redeem | +| `setmockoracleprice` / `getmockoracleprice` / `simulatepricevolatility` / `enablemockoracle` | `rpc/digidollar.cpp` | Regtest-only oracle helpers | + +Both `sendoracleprice` and `submitoracleprice` are absent from the source tree — `sendoracleprice` was removed as a fake-price-injection vulnerability and `submitoracleprice` never existed. Oracle prices come exclusively from live exchange aggregation. See `REPO_MAP_DIGIDOLLAR.md` for the complete RPC inventory. + +### 11.4 Error Codes + +**File:** `src/rpc/protocol.h` + +| Code | Meaning | +|------|---------| +| -1 | Misc error | +| -5 | Invalid address/key | +| -6 | Insufficient funds | +| -8 | Invalid parameter | +| -25 | Verification error | +| -32600 | Invalid JSON-RPC request | +| -32601 | Method not found | +| -32602 | Invalid params | + +--- + +## 12. DigiDollar Stablecoin + +### 12.1 System Overview + +DigiDollar is a native, decentralized stablecoin built on DigiByte using over-collateralized DGB positions. + +``` +User Action Flow: + +MINT: Lock DGB → Create DigiDollars +┌─────────────────────────────────────────────────────┐ +│ 1. Select lock period (1 hour - 10 years) │ +│ 2. Get oracle price │ +│ 3. Calculate collateral (200-1000% based on tier) │ +│ 4. Apply DCA multiplier if system health < 150% │ +│ 5. Create P2TR vault (collateral locked) │ +│ 6. Create P2TR DD tokens (transferable) │ +│ 7. Record position in OP_RETURN metadata │ +└─────────────────────────────────────────────────────┘ + +TRANSFER: Send DigiDollars +┌─────────────────────────────────────────────────────┐ +│ 1. Validate DD address (DD/TD/RD prefix) │ +│ 2. Select DD UTXOs │ +│ 3. Create DD outputs to recipient │ +│ 4. Sign with Schnorr (P2TR key-path) │ +│ 5. Include OP_RETURN with DD amounts │ +└─────────────────────────────────────────────────────┘ + +REDEEM: Burn DigiDollars → Unlock DGB +┌─────────────────────────────────────────────────────┐ +│ 1. Check timelock expired (REQUIRED) │ +│ 2. Determine path (NORMAL or ERR) │ +│ NORMAL: health ≥ 100% → burn original DD │ +│ ERR: health < 100% → burn MORE DD (105-125%) │ +│ 3. Burn DD tokens (remove from UTXO) │ +│ 4. Return 100% collateral (ALWAYS full amount) │ +└─────────────────────────────────────────────────────┘ +``` + +### 12.2 Collateral Tiers + +**File:** `src/consensus/digidollar.cpp` + +| Lock Period | Collateral Ratio | Use Case | +|-------------|------------------|----------| +| 1 hour | 1000% | Testing/onboarding tier | +| 30 days | 500% | Short-term | +| 3 months | 400% | Quarterly | +| 6 months | 350% | Semi-annual | +| 1 year | 300% | Annual | +| 2 years | 275% | Bi-annual | +| 3 years | 250% | Medium-term | +| 5 years | 225% | Long-term | +| 7 years | 212% | Extended | +| 10 years | 200% | Maximum lock | + +### 12.3 Protection Systems + +#### DCA (Dynamic Collateral Adjustment) + +**File:** `src/consensus/dca.cpp` + +``` +System Health Tiers: +≥150%: Healthy → 1.0x multiplier (no change) +120-149%: Warning → 1.25x multiplier (+25%) +110-119%: Critical → 1.5x multiplier (+50%) +<110%: Emergency → 2.0x multiplier (+100%) +``` + +#### ERR (Emergency Redemption Ratio) + +**File:** `src/consensus/err.cpp` + +``` +ERR increases DD burn requirement (NOT reduces collateral): + +System Health → ERR Ratio → DD Burn Required +95-100% → 0.95 → 105.3% (burn more DD) +90-95% → 0.90 → 111.1% +85-90% → 0.85 → 117.6% +<85% → 0.80 → 125.0% (maximum) + +Collateral return: ALWAYS 100% of locked DGB +New minting: BLOCKED during ERR +``` + +#### Volatility Protection + +**File:** `src/consensus/volatility.cpp` + +- Monitors hourly/daily/weekly price changes +- Freezes minting during high volatility (>20%) +- Prevents destabilizing transactions + +### 12.4 Address Formats + +**File:** `src/base58.cpp` + +```cpp +// 2-byte Base58Check version prefixes +DD_P2TR_MAINNET = {0x52, 0x85} // "DD" prefix +DD_P2TR_TESTNET = {0xb1, 0x29} // "TD" prefix +DD_P2TR_REGTEST = {0xa3, 0xa4} // "RD" prefix + +// Examples: +Mainnet: DD1q2w3e4r5t6y7u8i9o0p... +Testnet: TD1q2w3e4r5t6y7u8i9o0p... +Regtest: RD1q2w3e4r5t6y7u8i9o0p... +``` + +### 12.5 Transaction Structure + +``` +MINT Transaction: +├── Inputs: DGB UTXOs +├── Outputs: +│ ├── [0] P2TR collateral vault (locked DGB) +│ ├── [1] P2TR DD token (0 DGB value) +│ ├── [2] OP_RETURN: "DD" 1 +│ └── [3+] DGB change +└── Version: 0x0D1D0770 | (1 << 24) + +TRANSFER Transaction: +├── Inputs: DD UTXOs + fee UTXOs +├── Outputs: +│ ├── [0-N] P2TR DD outputs to recipients +│ ├── [N+1] OP_RETURN: "DD" 2 ... +│ └── [N+2] DGB change for fees +└── Version: 0x0D1D0770 | (2 << 24) + +REDEEM Transaction: +├── Inputs: +│ ├── [0] Collateral vault (with CLTV) +│ ├── [1+] DD UTXOs to burn +│ └── [N+] Fee UTXOs +├── Outputs: +│ ├── [0] DGB returned to owner (100% collateral) +│ ├── [1] DD change (if partial burn) +│ ├── [2] OP_RETURN: "DD" 3 +│ └── [3] DGB fee change +└── Version: 0x0D1D0770 | (3 << 24) +``` + +### 12.6 Network-Wide Tracking + +**File:** `src/digidollar/health.cpp` + +#### Baseline: UTXO Scanning + +The system uses UTXO scanning for initial decentralized statistics: + +```cpp +void SystemHealthMonitor::ScanUTXOSet(CCoinsView* view, ...) +{ + // Iterate ALL UTXOs in blockchain + std::unique_ptr pcursor(view->Cursor()); + + while (pcursor->Valid()) { + // Find DD vaults: P2TR output 0 with value > 0 + if (key.n == 0 && coin.out.scriptPubKey[0] == OP_1 && coin.out.nValue > 0) { + CTransactionRef tx = GetTransaction(...); + if (DigiDollar::ExtractDDAmount(tx->vout[2].scriptPubKey, ddAmount)) { + s_currentMetrics.totalDDSupply += ddAmount; + s_currentMetrics.totalCollateral += dgbCollateral; + } + } + pcursor->Next(); + } +} +``` + +#### Incremental Tracking (T5-06) + +After the initial UTXO scan, DD supply and collateral are tracked incrementally via `ConnectBlock()`/`DisconnectBlock()` callbacks: + +```cpp +// Called from ConnectBlock() under cs_main when a DD mint is connected: +static void OnMintConnected(CAmount ddAmount, CAmount dgbCollateral); + +// Called from ConnectBlock() under cs_main when a DD redeem is connected: +static void OnRedeemConnected(CAmount ddAmount, CAmount dgbCollateral); + +// Reverse operations for DisconnectBlock() (reorgs): +static void OnMintDisconnected(CAmount ddAmount, CAmount dgbCollateral); +static void OnRedeemDisconnected(CAmount ddAmount, CAmount dgbCollateral); +``` + +This avoids rescanning the entire UTXO set for every health check. The ERR system uses these live metrics to determine whether emergency redemption is active. + +**Result:** All nodes see identical network statistics, updated incrementally per block. + +--- + +## 13. Oracle System + +### 13.1 Architecture Overview + +**Files:** `src/oracle/`, `src/primitives/oracle.h` + +``` +DigiDollar V1 ships with MuSig2 v0x03 oracle bundles only — legacy single-oracle +and multi-oracle bundle paths have been removed (commits f2bb0a19a4, bbb85cf363). + +Data Flow: +Exchange APIs → Per-oracle Schnorr quote → MuSig2 nonce/partial-sig session → +Aggregate Schnorr signature + participation bitmap → Coinbase OP_RETURN + ↓ + Block validation extracts COracleBundle (v0x03) + ↓ + IQR outlier filtering → median consensus price (deterministic) + ↓ + Block-extracted oracle price → DigiDollar tx validation +``` + +#### Activation + +| Network | DD activation (`nDDActivationHeight`) | Oracle activation (`nOracleActivationHeight`) | MuSig2 (`nDigiDollarMuSig2Height`) | On-chain quorum | +|---------|--------------------------------------|----------------------------------------------|-----------------------------------|-----------------| +| Mainnet | 23,627,520 | 23,627,520 (= DD) | 23,627,520 (= DD) | 7 signatures from 35 configured active keys | +| Testnet26 | 600 | 600 (= DD) | 600 (= DD) | 7 signatures from 35 configured active keys | +| Regtest | 650 | 650 (= DD) | 0 (= BIP9 ALWAYS_ACTIVE boundary) | 4-of-7 | + +`nDigiDollarMuSig2Height` now collapses to the effective DigiDollar activation boundary: `nDDActivationHeight` on mainnet/testnet, and BIP9 `min_activation_height=0` on default regtest where DigiDollar is `ALWAYS_ACTIVE`. The legacy `nDigiDollarPhase2Height` / `nDigiDollarPhase3Height` fields no longer exist. + +### 13.2 Price Message Structure + +**File:** `src/primitives/oracle.h` + +```cpp +class COraclePriceMessage { + uint32_t oracle_id; // 4 bytes + uint64_t price_micro_usd; // 8 bytes (1,000,000 = $1.00) + int64_t timestamp; // 8 bytes + int32_t block_height; // 4 bytes + uint64_t nonce; // 8 bytes + XOnlyPubKey oracle_pubkey; // 32 bytes + std::vector schnorr_sig; // 64 bytes + // Total: 128 bytes +}; +``` + +### 13.3 Exchange Integration + +**Files:** `src/oracle/exchange.h`, `src/oracle/exchange.cpp` (~1230 lines) + +12 fetcher classes derive from `BaseExchangeFetcher` (`exchange.h:23+`): +Binance, Coinbase, Kraken, CoinGecko, Bittrex, Poloniex, Messari, KuCoin, Crypto.com, Gate.io, HTX, plus the base. Active exchange selection is per oracle operator (see `DIGIDOLLAR_ORACLE_ARCHITECTURE.md` for the configurable subset). + +```cpp +MultiExchangeAggregator: +1. Fetch prices in parallel (libcurl) +2. Filter failures and stale quotes +3. Remove outliers +4. Calculate median (per-source weights honoured) +5. Convert to micro-USD before signing +``` + +### 13.4 V1 Oracle Coinbase Format + +**File:** `src/oracle/bundle_manager.cpp` + +``` +Coinbase OP_RETURN: +┌──────────────────────────────────────────────────────────────┐ +│ OP_RETURN OP_ORACLE <0x03> │ +└──────────────────────────────────────────────────────────────┘ +``` + +Legacy v0x01/v0x02 oracle payloads are not accepted on-chain in V1. + +### 13.5 Consensus Price Calculation (IQR) + +**File:** `src/oracle/bundle_manager.cpp` — `CalculateConsensusPrice()` + +The consensus price is computed deterministically from bundle messages using IQR (Interquartile Range) outlier filtering: + +``` +1. Filter messages by price range only (NOT timestamp — avoids wall-clock dependency) +2. Sort valid prices +3. If < 4 prices: return simple median (no outlier filtering possible) +4. Compute Q1 (25th percentile) and Q3 (75th percentile) +5. IQR = Q3 - Q1 +6. Lower bound = Q1 - 1.5 × IQR +7. Upper bound = Q3 + 1.5 × IQR +8. Filter outliers outside [lower, upper] +9. Return median of remaining prices +``` + +**SECURITY:** `CalculateConsensusPrice()` deliberately avoids `GetTime()` for timestamp checks. Timestamp validation uses `block.nTime` in `ValidateBlockOracleData()` to ensure deterministic consensus independent of wall-clock time (prevents chain splits during IBD or delayed relay). + +### 13.6 Block-Extracted Oracle Price + +**File:** `src/validation.cpp` + +During `ConnectBlock()`, the oracle price is extracted directly from the block's coinbase OP_RETURN rather than queried from memory. This ensures DD transaction validation uses the exact same price the miner used: + +```cpp +// In ConnectBlock(): +COracleBundle extractedBundle; +if (oracleManager.ExtractOracleBundle(*block.vtx[0], extractedBundle) && + extractedBundle.median_price_micro_usd > 0) { + blockOraclePrice = extractedBundle.median_price_micro_usd; +} +// This price is passed to DD validation — deterministic, block-local +``` + +### 13.7 Bundle Validation (V1: MuSig2 only) + +**File:** `src/oracle/bundle_manager.cpp` (also `src/validation.cpp`) + +```cpp +// On-chain validation path: +ValidateBundle(bundle, height, params) + → bundle.version must be 3 (v0x03 MuSig2); + legacy v0x01/v0x02 bundles are rejected once DEPLOYMENT_DIGIDOLLAR is active + (src/oracle/bundle_manager.cpp commit f2bb0a19a4 / bbb85cf363). + → Validate aggregate Schnorr signature against the MuSig2 aggregate of + `consensus.vOraclePublicKeys` and the participation bitmap. + → Apply IQR (1.5×) outlier filtering on the input price quotes used to + compute the bundle's median price (deterministic; uses block.nTime, not + GetTime()). +``` + +### 13.8 Mock Oracle (Regtest only) + +**File:** `src/oracle/mock_oracle.cpp` + +Mock prices are only available on regtest under the `OracleManagerInterface` shim. Mock-related RPCs (`setmockoracleprice`, `getmockoracleprice`, `simulatepricevolatility`, `enablemockoracle`) are gated to regtest in `src/rpc/digidollar.cpp`. `OP_CHECKPRICE` is reserved and deterministically disabled, so it does not read either mock prices or live node-local oracle state. + +### 13.9 Mining Graceful Degradation (DD txs) + +**File:** `src/node/miner.cpp` + +`BlockAssembler::CreateNewBlock` strips DigiDollar transactions that fail validation in `mapModifiedTx` rather than aborting block assembly (commit `6b5ff516c3`). When no MuSig2 oracle bundle is ready for the candidate height, `addPackageTxs` skips DD-marker transactions and the resulting template falls back to a non-DD block; if a DD tx slips through and `TestBlockValidity` reports a retryable DD-only failure, the block is reassembled without DD txs (`miner.cpp` around lines 165-461). + +--- + +## Appendix A: Key Line Number References + +### Consensus & Validation +| File | Function/Class | Approx. Lines | +|------|---------------|---------------| +| validation.cpp | CheckBlock() | 4624+ | +| validation.cpp | ContextualCheckBlock() | 4842+ | +| validation.cpp | ContextualCheckBlockHeader() | 4784+ | +| validation.cpp | Chainstate::ConnectBlock() | 2808+ | +| validation.cpp | GetBlockSubsidy() | 2119-2194 | +| validation.cpp | IsAlgoActive() | 2196+ | +| validation.cpp | GetOraclePriceForTransaction() | 2073+ | +| pow.cpp | GetNextWorkRequiredV4() | 192-254 | +| pow.cpp | GetNextWorkRequired() (dispatcher) | 256-285 | +| pow.cpp | CheckProofOfWork() | 376+ | + +### Block & Chain +| File | Function/Class | Lines | +|------|---------------|-------| +| chain.h | CBlockIndex | 146-384 | +| chain.h | BlockStatus enum | 85-139 | +| chain.cpp | GetAlgoForBlockIndex() | 152-174 | +| primitives/block.h | CBlockHeader | 85-139 | +| primitives/block.cpp | GetPoWAlgoHash() | 56-106 | + +### Script & Crypto +| File | Function/Class | Lines | +|------|---------------|-------| +| interpreter.cpp | EvalScript() | 439-1380 | +| interpreter.cpp | CheckSchnorrSignature() | 1819-1847 | +| interpreter.cpp | Taproot verification | 2055-2098 | +| interpreter.cpp | DigiDollar opcodes | 651-754 | +| script.h | Opcodes enum | 70-217 | + +### Networking +| File | Function/Class | Lines | +|------|---------------|-------| +| net.h | CNode | 696-1029 | +| net.h | CConnman | 1074-1698 | +| net.cpp | SocketHandler() | 2052-2186 | +| dandelion.cpp | DandelionShuffle() | 329-383 | +| net_processing.cpp | ProcessMessages() | 5560+ | + +### DigiDollar +| File | Function/Class | Lines | +|------|---------------|-------| +| digidollar/digidollar.h | CCollateralPosition | 65-112 | +| digidollar/txbuilder.cpp | BuildMintTransaction() | 278-422 | +| digidollar/txbuilder.cpp | BuildRedemptionTransaction() | 1041-1265 | +| digidollar/health.cpp | ScanUTXOSet() | 291-502 | +| consensus/dca.cpp | GetDCAMultiplier() | 85+ | +| consensus/err.cpp | GetRequiredDDBurn() | 112+ | + +--- + +## Appendix B: Configuration Files + +### Main Configuration +- `~/.digibyte/digibyte.conf` - Node configuration +- `~/.digibyte/wallet.dat` - Legacy wallet +- `~/.digibyte/wallets/` - Descriptor wallets + +### Data Directories +- `~/.digibyte/blocks/` - Block data files +- `~/.digibyte/chainstate/` - UTXO database +- `~/.digibyte/indexes/` - Optional indexes + +### Key Parameters +```ini +# Network +testnet=1 +regtest=1 + +# Mining +algo=sha256d|scrypt|groestl|skein|qubit|odocrypt + +# DigiDollar (regtest helpers shown; live oracle aggregation has no static price config) +digidollar=1 +digidollarstatsindex=1 # Maintain DigiDollar stats index +# mockoracle=1 # regtest only — see init.cpp -enablemockoracle args +# oracleprice=6500 # regtest mock seeding (RPC setmockoracleprice preferred) + +# P2P +v2transport=1 # Opt in to BIP324 V2 transport (off by default) + +# Debug +debug=digidollar +debug=net +debug=validation +``` + +--- + +## Appendix C: Test Suites + +### Unit Tests +- `src/test/` - C++ unit tests (Boost.Test); see `REPO_MAP_DIGIDOLLAR.md` for the granular DigiDollar/Oracle/MuSig2/Red-Hornet test inventory (~150 unit suites at last count). +- `src/wallet/test/` - DigiDollar wallet suites cover persistence, security, Wave 16/17 spendability, helper asymmetry, and rh59 lock-bypass, plus base wallet tests. +- `src/qt/test/` - DigiDollar Qt widget tests (`digidollarwidgettests.cpp`, `digidollarwave19widgettests.cpp`); generated `moc_*.cpp` files are build products. + +### Functional Tests +- `test/functional/` - Python integration tests; current DD/oracle coverage is registered through `digidollar_*`, `wallet_digidollar_*`, and `feature_oracle_p2p.py` entries in `test_runner.py`. + +### Running Tests +```bash +# Unit tests +make check + +# Specific test suite +./src/test/test_digibyte --run_test=digidollar_validation_tests +./src/test/test_digibyte --list_content | grep -Ei 'digidollar|oracle|musig|^rh' + +# Functional tests +./test/functional/test_runner.py + +# Single functional test +./test/functional/digidollar_basic.py --nocleanup +``` + +--- + +## Appendix D: Codebase Validation Report + +### Validation Date: 2026-05-20 + +This architecture document has been spot-validated against the active DigiByte Core v9.26.2 codebase on `feature/digidollar-v1` across the major subsystems. Generated/build trees (`.deps`, `.libs`, `*.o`, `*.lo`, Qt `moc_*.cpp`, Qt `forms/ui_*.h`) were ignored. + +### Validation Summary + +| Subsystem | Status | Key Files Verified | +|-----------|--------|-------------------| +| Consensus Layer | Verified | `validation.cpp`, `consensus/params.h`, `consensus/consensus.h` | +| Multi-Algorithm Mining | Verified | `primitives/block.h`, `primitives/block.cpp`, `crypto/*` | +| Difficulty Adjustment | Verified | `pow.cpp`, `kernel/chainparams.cpp` | +| Block/Chain Management | Verified | `chain.h`, `coins.h`, `txdb.h` | +| Transaction Processing | Verified | `primitives/transaction.h`, `validation.cpp` | +| Script & Signatures | Verified | `script/interpreter.cpp`, `script/script.h` | +| P2P Networking | Verified | `net.cpp`, `net_processing.cpp`, `dandelion.cpp`, `bip324.cpp` | +| Wallet System | Verified | `wallet/wallet.h`, `wallet/scriptpubkeyman.h`, `wallet/digidollarwallet.h` | +| RPC Interface | Verified | `rpc/server.cpp`, `rpc/digidollar.cpp`, `httprpc.cpp`, `wallet/rpc/wallet.cpp` | +| DigiDollar Stablecoin | Verified | `digidollar/*`, `consensus/dca.cpp`, `consensus/err.cpp` | +| Oracle System | Verified | `oracle/*`, `primitives/oracle.h` | + +### Key Verified Constants + +| Constant | Value | File:Line | +|----------|-------|-----------| +| COINBASE_MATURITY | 8 | consensus/consensus.h:20 | +| COINBASE_MATURITY_2 | 100 | consensus/consensus.h:21 | +| MAX_BLOCK_WEIGHT | 4,000,000 | consensus/consensus.h:15 | +| MAX_BLOCK_SERIALIZED_SIZE | 4,000,000 | consensus/consensus.h:13 | +| MAX_BLOCK_SIGOPS_COST | 80,000 | consensus/consensus.h:18 | +| WITNESS_SCALE_FACTOR | 4 | consensus/consensus.h:25 | +| nPowTargetSpacing | 15 seconds | kernel/chainparams.cpp:107 | +| multiAlgoDiffChangeTarget | 145,000 | kernel/chainparams.cpp:122 | +| alwaysUpdateDiffChangeTarget | 400,000 | kernel/chainparams.cpp:123 | +| workComputationChangeTarget | 1,430,000 | kernel/chainparams.cpp:124 | +| OdoHeight | 9,112,320 | kernel/chainparams.cpp:126 | +| DD_TX_VERSION | 0x0D1D0770 | primitives/transaction.h:47 | +| OP_DIGIDOLLAR..OP_ORACLE | 0xbb..0xbf | script/script.h:210-214 | +| DEPLOYMENT_DIGIDOLLAR bit | 23 | kernel/chainparams.cpp:177,517,969,1099 | +| nDigiDollarMuSig2Height | equals effective DigiDollar activation boundary (mainnet 23,627,520; testnet26 600; default regtest 0) | kernel/chainparams.cpp | + +### Verified Algorithm Implementations + +| Algorithm | Enum Value | Hash Function | +|-----------|------------|---------------| +| SHA256D | 0 | GetHash() | +| Scrypt | 1 | scrypt_1024_1_1_256() | +| Groestl | 2 | HashGroestl() | +| Skein | 3 | HashSkein() | +| Qubit | 4 | HashQubit() | +| Odocrypt | 7 | HashOdo() | + +### DigiDollar Verification + +| Feature | Implementation | +|---------|---------------| +| 10 Collateral Tiers | consensus/digidollar.h | +| DCA Multipliers (1.0x-2.0x) | consensus/dca.cpp | +| ERR Ratios (0.80-0.95) | consensus/err.cpp | +| DD Address Prefixes | base58.cpp | +| Transaction Types (0-3) | primitives/transaction.h:38-44 | +| Confirmed-only DD transfers | validation.cpp / wallet/digidollarwallet.cpp (commit 0b4959f563) | + +### Oracle System Verification + +| Feature | Implementation | +|---------|---------------| +| COraclePriceMessage | primitives/oracle.h:31+ | +| COracleBundle v0x03 (MuSig2 only on V1) | primitives/oracle.h, oracle/bundle_manager.cpp (commits f2bb0a19a4, bbb85cf363) | +| MuSig2 Aggregator/Session/Orchestrator | oracle/musig2_*.{cpp,h} | +| IQR Outlier Filtering | oracle/bundle_manager.cpp:CalculateConsensusPrice | +| Block-Extracted Oracle Price | validation.cpp:ConnectBlock (around lines 3084-3098) | +| Incremental DD Supply Tracking | digidollar/health.cpp:OnMintConnected/OnRedeemConnected | +| Mining graceful degradation for DD txs | node/miner.cpp (commit 6b5ff516c3) | + +### Cross-Reference Documents + +This document is consistent with: +- **DIGIDOLLAR_ARCHITECTURE.md** - Complete stablecoin implementation details +- **DIGIDOLLAR_ORACLE_ARCHITECTURE.md** - Complete oracle system specification +- **REPO_MAP.md** - Granular core-DigiByte file index +- **REPO_MAP_DIGIDOLLAR.md** - Granular DigiDollar/oracle file index + +--- + +*Document Version: 2.1* +*Generated from DigiByte Core v9.26.2 codebase analysis (`feature/digidollar-v1`)* +*Updated: 2026-05-20* diff --git a/CLAUDE.md b/CLAUDE.md index 6210515f339..3ccddee698b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,118 +1,203 @@ -# CLAUDE.md - AI Assistant Guide for DigiByte Development - -## Overview -This file provides essential context for AI assistants working on the DigiByte codebase, particularly for the Bitcoin Core v26.2 merge creating DigiByte v8.26. - -## Repository Structure -``` -digibyte/ # Current v8.26 working directory -├── src/ # Source code -├── test/functional/ # Python functional tests -├── bitcoin-v26.2-for-digibyte/ # Bitcoin v26.2 reference -├── digibyte-v8.22.2/ # DigiByte v8.22.2 (SOURCE OF TRUTH) -└── doc/ # Documentation -``` - -## Test Fix Workflow Documentation - -### For Orchestrator Agents -- **MAIN_WORK_PROMPT.md** - Instructions for managing sub-agents -- **WORK_GROUPS.md** - Test groups with status tracking -- **TEST_FIX_PROGRESS.md** - Overall progress dashboard - -### For Sub-Agent Workers -- **SUBAGENT_TEST_FIX_PROMPT.md** - Test fix methodology -- **COMMON_FIXES.md** - Reusable fix patterns (CHECK FIRST!) -- **APPLICATION_BUGS.md** - Track real bugs found - -### Current Status (2025-08-24) -- **Total Tests**: 315 (109 failing) -- **Strategy**: Orchestrator deploys sub-agents on test groups -- **Phase 1**: Groups 1-3 (sequential - critical foundation) -- **Phase 2**: Groups 4-9 (parallel - max 3 agents) -- **Phase 3**: Groups 10-13 (parallel - cleanup) - -## Critical DigiByte Constants - -### Always use these values instead of Bitcoin defaults: -```python -# Block & Mining -BLOCK_TIME = 15 # seconds (NOT 600!) -COINBASE_MATURITY = 8 # blocks (NOT 100!) -COINBASE_MATURITY_2 = 100 # After certain height -SUBSIDY = 72000 # DGB (NOT 50!) -MAX_MONEY = 21000000000 # 21 billion DGB - -# Fees (DigiByte uses KvB not vB!) -MIN_RELAY_TX_FEE = Decimal('0.001') # DGB/kB -DEFAULT_TRANSACTION_FEE = Decimal('0.1') # DGB/kB - -# Network -P2P_PORT = 12024 # Mainnet -P2P_PORT_TESTNET = 12025 # Testnet - -# Address Formats -REGTEST_BECH32 = 'dgbrt' # NOT 'bcrt' -TESTNET_BECH32 = 'dgbt' # NOT 'tb' -``` - -## DigiByte Unique Features - -### Multi-Algorithm Mining -- 5 algorithms: SHA256D (0), Scrypt (1), Groestl (2), Skein (3), Qubit (4) -- Odocrypt (7) activates at height 9,112,320 -- Each targets 75-second block time (15s × 5 algos) - -### Custom RPC Commands -- `getblockreward` - Current block reward -- Enhanced `getmininginfo` - Per-algorithm stats -- Enhanced `getdifficulty` - All algorithm difficulties - -### Dandelion++ Privacy -- Two-pool system: stempool (private) and mempool (public) -- **CRITICAL**: Read doc/DANDELION_INFO.md before changes -- Files: src/dandelion.cpp, src/stempool.h - -### Difficulty Adjustment Evolution -- DigiShield V1 (block 67,200) -- MultiAlgo V2 (block 145,000) -- MultiShield V3 (block 400,000) -- DigiSpeed V4 (block 1,430,000) - -## Quick Debug Commands - -```bash -# Check for Bitcoin constants that need updating -grep -r "50.*BTC\|600.*seconds\|100.*blocks\|bcrt1" test/functional/ - -# Compare with working v8.22.2 -diff digibyte-v8.22.2/test/functional/[test].py test/functional/[test].py - -# Run test with debug info -./test/functional/[test].py --loglevel=debug --nocleanup - -# Check current failing tests -python3 test/functional/test_runner.py --list-failing -``` - -## Common Test Fix Patterns - -1. **Block Rewards**: 50 → 72000 -2. **Block Time**: 600s → 15s -3. **Maturity**: 100 → 8 (or keep 100 for COINBASE_MATURITY_2) -4. **Fees**: vB → KvB (multiply by 1000) -5. **Address**: bcrt1 → dgbrt1 - -For detailed patterns, see COMMON_FIXES.md - -## Important Notes - -- **Three-way comparison**: Always compare v8.26 ↔ v8.22.2 ↔ Bitcoin v26.2 -- **Test all variants**: --descriptors, --legacy-wallet, --usecli, --v2transport -- **Document everything**: Update tracking files immediately -- **Mock scrypt**: Currently using mock, causes PoW validation issues -- **V2 transport**: BIP324 V2 P2P transport is fully supported and tested (disabled by default, enable with `-v2transport=1`) - ---- - -*For detailed test fix instructions, see the workflow documentation files listed above.* \ No newline at end of file +# CLAUDE.md — AI Agent Guide for DigiByte Core / DigiDollar + +## What this repo is + +DigiByte Core v9.26 (Bitcoin Core v26.2 lineage) on the `feature/digidollar-v1` branch, augmented with the **DigiDollar** native USD-pegged stablecoin and a multi-oracle DGB/USD price feed network with MuSig2 Schnorr threshold consensus. + +Working directory: `/home/jared/Code/digibyte`. Current DigiDollar v1 campaign branch: `feature/digidollar-v1`. Upstream main branch: `develop`. + +## Required reading order before any DigiDollar / oracle work + +1. `CLAUDE.md` — This guide, branch rules, and current code-surface warnings +2. `ARCHITECTURE.md` — Core DigiByte system design +3. `REPO_MAP.md` — Core DigiByte file index (excludes DigiDollar/oracle subsystem) +4. `REPO_MAP_GUIDE.md` — How to maintain and interpret the repo maps +5. `DIGIDOLLAR_ARCHITECTURE.md` — DigiDollar mint/transfer/redeem/collateral/health/state +6. `DIGIDOLLAR_ORACLE_ARCHITECTURE.md` — Exchange aggregation, bundle lifecycle, MuSig2, P2P +7. `REPO_MAP_DIGIDOLLAR.md` — DigiDollar/oracle file index (production, wallet, RPC, Qt, tests, fuzz) +8. `DIGIDOLLAR_EXPLAINER.md` — User-facing DigiDollar V1 protocol summary +9. `DIGIDOLLAR_ORACLE_EXPLAINER.md` — User-facing oracle/MuSig2 summary +10. `DIGIDOLLAR_ACTIVATION_EXPLAINER.md` — BIP9 gating of DD/oracle surface +11. `DIGIDOLLAR_WALLET_INTEGRATION.md` — Wallet/RPC integration guide +12. `DIGIDOLLAR_EXCHANGE_INTEGRATION.md` — Exchange/custody integration guide +13. `ORACLE_DISCOVERY_ARCHITECTURE.md` — Oracle endpoint discovery design +14. `DIGIDOLLAR_ORACLE_SETUP.md` — Oracle setup and migration runbook + +Also check `docs/ORACLE_OPERATOR_GUIDE.md` for operator-facing steps and the newest relevant `RELEASE_v9.26.0-rc*.md` before public instructions or release claims. + +## Repo layout (DigiDollar / oracle surface) + +``` +src/digidollar/ # 5 modules: digidollar, health, scripts, txbuilder, validation +src/oracle/ # Oracle daemon + MuSig2: bundle_manager, exchange, mock_oracle, + # node, signing_orchestrator, musig2_{aggregator,session, + # session_manager,orchestrator,oracle_participation,messages, + # session_mining} +src/consensus/ # dca, err, digidollar, digidollar_transaction_validation, + # digidollar_tx, volatility (DigiDollar/oracle consensus rules) +src/index/ # digidollarstatsindex (DD supply/health index) +src/primitives/ # oracle.h (price message + bundle types) +src/rpc/ # digidollar.cpp (18 base RPCs); digidollar_transactions.cpp is + # legacy / unregistered +src/wallet/ # digidollarwallet.{cpp,h}, ddcoincontrol.h; wallet/rpc/wallet.cpp + # registers 17 wallet-context DD/oracle RPCs +src/qt/ # DD tab + widgets/dialogs: digidollar{tab,mintwidget,sendwidget, + # receivewidget,redeemwidget,overviewwidget,positionswidget, + # transactionswidget,coincontroldialog,receiverequest}, + # ddaddressbookpage, digidollar_qt_translate +src/test/ # ~150 DigiDollar/oracle/MuSig2/Red-Hornet unit tests + fuzz/ +src/wallet/test/ # 6 DD wallet test sources (persistence, security, Wave 16/17, + # rh59 lock-bypass) + # — linked into src/test/test_digibyte, not a separate binary +src/qt/test/ # digidollarwidgettests, digidollarwave19widgettests +test/functional/ # ~80 DD/oracle Python tests registered in test_runner.py +``` + +## DigiDollar opcode soft-fork additions + +Defined in `src/script/script.h:209-220`: +- `OP_DIGIDOLLAR = 0xbb` (Tapscript OP_SUCCESSx slot pre-activation) +- `OP_DDVERIFY = 0xbc` (Tapscript OP_SUCCESSx slot pre-activation) +- `OP_CHECKPRICE = 0xbd` — **deterministically DISABLED (reserved)** as of DD-FINAL-005 / AR-0. Post-activation it consumes its witness operand and always pushes `vchFalse` (fail closed); it no longer consults any oracle price. It previously consulted the live node-local/wall-clock price (`g_get_oracle_consensus_price` → `OracleBundleManager::GetLatestPrice`), which was non-deterministic across nodes and a chain-split risk; no DigiDollar script emits OP_CHECKPRICE, so disabling it has zero protocol impact. A future price opcode must bind to the block's own committed v0x03 bundle price (`src/script/interpreter.cpp:708`). +- `OP_CHECKCOLLATERAL = 0xbe` — compares stack ratio to threshold; consumes ` ` and pushes `ratio>=threshold` +- `OP_ORACLE = 0xbf` — coinbase oracle bundle marker + +These are OP_SUCCESSx-class opcodes that become functional only when `SCRIPT_VERIFY_DIGIDOLLAR` is set, which only happens when BIP9 `DEPLOYMENT_DIGIDOLLAR` is ACTIVE (bit 23). See `IsDigiDollarOpcode` / `IsOpSuccessForFlags` at `src/script/interpreter.cpp:439-453`. + +## Activation summary (BIP9 bit 23) + +| Network | Start | Min activation height | Window | Threshold | Status | +|---------|-------|----------------------|--------|-----------|--------| +| Mainnet | 2026-06-01 (epoch 1780272000) | 23,627,520 | 40,320 blocks (~1 week) | 70% (28,224 of 40,320) | Pending | +| Testnet (testnet26) | BIP9 start/reset genesis 1780156800 | 600 | 200 blocks | 70% (140 of 200) | Check `getdigidollardeploymentinfo` | +| Regtest | ALWAYS_ACTIVE | 0 | 144 blocks (BIP9 default) | 75% (108 of 144) | Active | + +`nDDActivationHeight`, `nOracleActivationHeight`, and `nDigiDollarMuSig2Height` collapse to the same height trigger on mainnet (23,627,520 / 23,627,520 / 23,627,520) and testnet (600 / 600 / 600). Default regtest keeps DD/oracle height gates at 650 / 650 while the BIP9 deployment is `ALWAYS_ACTIVE` with `min_activation_height=0`; `nDigiDollarMuSig2Height` follows that effective BIP9 boundary and is `0`, so v0x03 quotes are valid whenever DigiDollar is active. The direct `-digidollaractivationheight=N` regtest knob retargets both the BIP9 minimum and the static DD/oracle/MuSig2 height gates. Generic `-vbparams=digidollar:...` still overrides BIP9 only; because MuSig2 follows the effective DigiDollar BIP9 boundary, a BIP9-only test override can move MuSig2 validation without moving the static DD/oracle P2P gates. Startup oracle-price reconstruction follows the same BIP9 predicate as block connection, so default-regtest BIP9-active blocks below 650 are not dropped during restart/reindex cache rebuilds. The variable in code is `nDigiDollarMuSig2Height`, not the older `nDigiDollarPhase3Height` (`src/consensus/params.h:195`). Once DigiDollar is active, v0x03 MuSig2 is the only on-chain bundle format ever accepted. + +## Oracle roster + +| Network | Total slots | Active | Consensus | +|---------|-------------|--------|-----------| +| Mainnet | 35 (`vOracleNodes`) | 35 (`consensus.vOraclePublicKeys` slots 0-34) | 7 signatures from active keyset | +| Testnet | 35 | 35 (slots 0-34) | 7 signatures from active keyset | +| Regtest | 7 | 7 | 4-of-7 | + +Slots 0-34 on mainnet and testnet are active. Slot 28 uses the DigiHash Mining +Pool key, slot 31 uses the Peer2Peer / DigiRoos key, and all 35 configured +slots contain valid compressed secp256k1 oracle keys. ID 35 is outside the +configured roster and must be rejected by RPC/P2P/bitmap bounds checks. + +`src/primitives/oracle.h:19-21` declares header defaults `ORACLE_CONSENSUS_REQUIRED=7`, `ORACLE_ACTIVE_COUNT=35`, `ORACLE_TOTAL_COUNT=35`. Chainparams sets `nOracleConsensusRequired`, `nOraclePubkeyCount`, and `nOracleTotalOracles` per network at startup, so those chainparams values are what the validator and MuSig2 aggregator use. + +## DigiDollar critical constants + +```python +# DigiByte chain values (do not use Bitcoin defaults) +BLOCK_TIME = 15 # seconds +COINBASE_MATURITY = 8 # blocks (100 after height threshold = COINBASE_MATURITY_2) +SUBSIDY = 72000 # DGB +MAX_MONEY = 21_000_000_000 + +# Fees (DigiByte uses DGB/kB, not DGB/vB) +MIN_RELAY_TX_FEE = 0.001 # DGB/kB +DEFAULT_TRANSACTION_FEE = 0.1 # DGB/kB + +# Network +P2P_PORT_MAINNET = 12024 +P2P_PORT_TESTNET = 12033 # testnet26 per src/kernel/chainparams.cpp + +# Address formats +REGTEST_BECH32 = 'dgbrt' +TESTNET_BECH32 = 'dgbt' +DD_ADDR_PREFIX = 'DD' / 'TD' / 'RD' (mainnet/testnet/regtest) + +# DigiDollar-specific +DD_AMOUNT_UNIT = 1 cent (10000 = $100.00) +DD_TX_VERSION_MARKER = 0x0770 (low 16 bits of nVersion) +DD_TX_TYPE_FIELD = (nVersion >> 24) & 0xFF # 1=MINT, 2=TRANSFER, 3=REDEEM +MINT_MIN = 10_000 cents +MINT_MAX = 10_000_000 cents +LOCK_TIERS = 0..9 (1h, 30d, 90d, 180d, 1y, 2y, 3y, 5y, 7y, 10y) + # canonical durations enforced at consensus — + # mint lock height must be in the claimed tier window + # [canonical_blocks, canonical_blocks + 100] + # under-locked/custom durations rejected + # (src/digidollar/validation.cpp) +LOCK_TIER_OPRETURN = stored explicitly in mint OP_RETURN; consensus rejects + bad-mint-lock-tier-duration when remaining lock blocks + fall outside the canonical confirmation window for the + claimed tier +``` + +## Where DigiDollar/oracle is gated at runtime + +| Layer | Gate | Reference | +|-------|------|-----------| +| RPC | `DigiDollar::IsDigiDollarEnabled(tip, chainman)` at the top of each DD/oracle RPC | `src/rpc/digidollar.cpp` (10+ callsites) | +| Mempool | `IsDigiDollarEnabled` + `HasDigiDollarMarker`; DD txs additionally require a recent valid MuSig2 oracle quote via `HasRecentValidMuSig2OracleQuote` | `src/validation.cpp:224-286, 976-989` | +| Block | `IsDigiDollarEnabled` + `HasDigiDollarMarker` during `ConnectBlock`; coinbase oracle bundles require V1 MuSig2 version via `CheckMuSig2OracleBundleVersion` | `src/validation.cpp:185, 2808-3214` | +| Script | `SCRIPT_VERIFY_DIGIDOLLAR` flag | `src/validation.cpp` | +| P2P | `IsOracleP2PActive` at the top of all oracle handlers, including `oraclehb`, `oracleprice`, `oraclebundle` (accepted-and-dropped — V1 puts the bundle on-chain), `oracleconsns`, `oracleattest`, `oramusnonce`, `oramusigctx`, `oramusigpsig`, and `getoracles`. Wire names defined in `src/protocol.cpp:53-62`. | `src/net_processing.cpp` | +| Qt | `DigiDollarTab` activation overlay; widgets check `isVisible()` before polling | `src/qt/digidollartab.cpp` | +| Price cache | `UpdatePriceCache` gated on `DEPLOYMENT_DIGIDOLLAR` | `src/validation.cpp` (rh61 fix) | + +## RPC surface (35 commands) + +18 commands registered via `RegisterDigiDollarRPCCommands()` in `src/rpc/digidollar.cpp:6266`: +`getdigidollarstats`, `getdcamultiplier`, `calculatecollateralrequirement`, `getdigidollardeploymentinfo`, `importdigidollaraddress`, `estimatecollateral`, `getoracleprice`, `getalloracleprices`, `getprotectionstatus`, `getoracles`, `getoraclesigners`, `listoracle`, `stoporacle`, `getoraclepubkey`, `setmockoracleprice` (regtest), `getmockoracleprice` (regtest), `simulatepricevolatility` (regtest), `enablemockoracle` (regtest). + +17 wallet-context commands registered in `GetWalletRPCCommands()` at `src/wallet/rpc/wallet.cpp:888`: +`mintdigidollar`, `senddigidollar`, `sendmanydigidollar`, `redeemdigidollar`, `listdigidollarpositions`, `listdigidollaraddresses`, `getredemptioninfo`, `getdigidollarbalance`, `getdigidollaraddress`, `listdigidollartxs`, `listdigidollarunspent`, `listdigidollarutxos`, `validateddaddress`, `createoraclekey`, `exportoracleprivkey`, `importoracleprivkey`, `startoracle`. + +`createoraclekey`, `exportoracleprivkey`, and `importoracleprivkey` are local wallet key-management RPCs and are intentionally usable before DigiDollar activation. They do not start an oracle, sign prices, relay oracle data, or change consensus state. `startoracle` and the price/DD operational RPCs remain activation-gated. + +`sendoracleprice` and `submitoracleprice` are intentionally **absent** from the registration tables: `sendoracleprice` was removed as a fake-price-injection vulnerability, and `submitoracleprice` does not exist anywhere in the source tree. Oracle prices come exclusively from live exchange aggregation. + +`src/rpc/digidollar_transactions.cpp` declares legacy entry points (`getdigidollarinfo`, `transferdigidollar`, `createrawddtransaction`, `listredeemablepositions`) plus duplicate names that are also defined in `src/rpc/digidollar.cpp` and `src/wallet/rpc/wallet.cpp` (`getdigidollaraddress`, `getdigidollarbalance`, `mintdigidollar`, `redeemdigidollar`, `getredemptioninfo`). Its `GetDigiDollarTransactionRPCCommands()` is **never called** — no caller exists in the build — so all RPCs in this file are inert. Treat as legacy/dead code unless rewired. + +## Build / test commands + +```bash +# Build +./autogen.sh && ./configure && make -j$(nproc) + +# Run a specific C++ test suite +./src/test/test_digibyte --run_test=digidollar_validation_tests +./src/test/test_digibyte --list_content | grep -Ei 'digidollar|oracle|musig|^rh' + +# Wallet-context DD tests (require ENABLE_WALLET; built into the same +# test_digibyte binary via src/Makefile.test.include when --enable-wallet is on, +# *not* a separate test_wallet_digibyte binary): +./src/test/test_digibyte --run_test=digidollar_persistence_wallet_tests +./src/test/test_digibyte --run_test=digidollar_wallet_security_tests +./src/test/test_digibyte --run_test=rh59_coincontrol_dd_lock_bypass_tests + +# Run a functional test +./test/functional/digidollar_basic.py + +# Find DigiDollar/oracle source without generated/build products +rg -n 'digidollar|DigiDollar|oracle|MuSig|musig' src/ test/ \ + -g '*.cpp' -g '*.h' -g '*.hpp' -g '*.py' \ + -g '!**/.deps/**' -g '!**/.libs/**' -g '!*.o' -g '!*.lo' \ + -g '!src/qt/moc_*.cpp' -g '!src/qt/test/moc_*.cpp' -g '!src/qt/forms/ui_*.h' +``` + +## Important notes + +- **Confirmed-only DigiDollar transfers.** Unconfirmed DD chaining was removed (commit `0b4959f563`). Consensus refuses to resolve DD amounts from `MEMPOOL_HEIGHT` inputs for transfer/redeem; wallets must wait for confirmation between sends. +- **OP_CHECKPRICE is deterministically disabled (DD-FINAL-005).** Post-activation the opcode consumes its operand and unconditionally pushes `vchFalse` (`src/script/interpreter.cpp:708-735`); it no longer calls `g_get_oracle_consensus_price` (the hook is left null in production — see `src/init.cpp` Step 13). This removed the AR-0 fork vector (the old live-price consult was node-local/wall-clock dependent). The standalone `libdigibyteconsensus.so` behaviour is unchanged (also fails closed). +- **Mainnet/testnet validator parity.** The mainnet oracle-validation short-circuit was removed (commit `f0d9a7b2c7`). `OracleDataValidator::ValidateBlockOracleData` (`src/oracle/bundle_manager.cpp:2151`) now runs identically on mainnet and testnet, and only v0x03 MuSig2 bundles are accepted (commits `bbb85cf363`, `fa29405adc`, `f2bb0a19a4`). Raw v0x01/v0x02 OP_RETURN payloads short-circuit inside `ExtractOracleBundle`, so the validator emits `bad-oracle-malformed`. The `bad-oracle-legacy` branch only fires when extraction succeeds with a non-MuSig2 version, which is structurally unreachable for current v0x03 wire payloads — it remains as a defense-in-depth gate. +- **Price-dependent DD blocks must include exactly one v0x03 MuSig2 bundle.** Commit `1e08bd811f`: `ValidateBlockOracleData` returns `bad-oracle-missing` if a DD mint/redeem block has no oracle output, `bad-oracle-multiple-outputs` if it has more than one, and `bad-oracle-malformed` if extraction fails (which is the canonical reason raw v0x01/v0x02 produce). DD transfer-only and non-DD blocks may omit the bundle entirely. +- **Mempool requires an oracle quote for DD txs.** Commit `81bf974f40`: DD txs are not accepted into the mempool unless `HasRecentValidMuSig2OracleQuote` finds a recent valid v0x03 quote (`src/validation.cpp:224-286, 976-989`). +- **Custom lock durations rejected.** Consensus enforces canonical lock tiers with a 100-block confirmation buffer: `bad-mint-lock-period` for non-canonical periods, `bad-mint-lock-tier` for tier outside 0–9, and `bad-mint-lock-tier-duration` when remaining lock blocks fall outside `[canonical_blocks, canonical_blocks + 100]` for the claimed tier (commits `e1dd69f99b`, `11728a6980`). +- **DD supply alert, not a cap.** `AlertThresholds::ALERT_DD_SUPPLY` (`src/digidollar/health.h:84`, 10000000000 = 100M DD) is a monitoring threshold, not a consensus cap. `MAX_DIGIDOLLAR` is a per-output serialization bound. There is no global circulating-supply cap; total DD is constrained only by available collateral and the per-block minting rate. +- **Collateral vault spends require DD burn.** Non-DD transactions that try to spend a registered DigiDollar collateral vault are rejected with `bad-collateral-spend-missing-dd-burn`. Inside DD redemptions, `ValidateCollateralReleaseAmount` rejects partial burns with `bad-collateral-release-partial-burn` (`src/digidollar/validation.cpp`). +- **Qt mint derives HD owner keys.** Commit `1e95478b7e` made the Qt mint flow derive DD owner keys from the wallet's HD chain and persist them via `DigiDollarWallet::StoreOwnerKey` *before* broadcasting the mint tx, instead of generating an ephemeral random key after broadcast. Mint now requires an HD wallet with private keys enabled. RPC mint already used the same path. +- **Mining graceful degradation.** `CreateNewBlock` strips price-dependent DD mint/redeem txs when no valid oracle bundle is available, keeps ordinary DGB and price-independent DD transfer candidates flowing when valid, and continues block assembly instead of hanging (commit `6b5ff516c3`). +- **BIP324 V2 P2P transport** is supported and enabled with `-v2transport=1` (off by default). +- **Three-way comparison still applies for non-DigiDollar work.** Compare v9.26 ↔ v8.22.2 ↔ Bitcoin v26.2 in `digibyte-v8.22.2/` and `bitcoin-v26.2-for-digibyte/` when making changes to inherited code. +- **Avoid widening doc claims beyond what code shows.** All material claims in the approved docs (16 listed in `Z_PROMPTS.md`) must match `src/`. Treat code as truth. + +## Quick orientation for sub-agents + +When spawning a sub-agent on DigiDollar/oracle work, point it at this file plus the four most relevant docs (`DIGIDOLLAR_ARCHITECTURE.md`, `DIGIDOLLAR_ORACLE_ARCHITECTURE.md`, `REPO_MAP_DIGIDOLLAR.md`, `DIGIDOLLAR_ACTIVATION_EXPLAINER.md`) and an explicit list of files it should read/modify. Do not ask sub-agents to redesign architecture; treat existing approved docs as the contract. diff --git a/DIGIDOLLAR_ACTIVATION_EXPLAINER.md b/DIGIDOLLAR_ACTIVATION_EXPLAINER.md new file mode 100644 index 00000000000..1cded4be8e2 --- /dev/null +++ b/DIGIDOLLAR_ACTIVATION_EXPLAINER.md @@ -0,0 +1,269 @@ +# DigiDollar BIP9 Activation — Complete Explainer + +## Overview + +DigiDollar activates on the DigiByte blockchain through **BIP9 version bit signaling** — the same proven mechanism used by Bitcoin for SegWit and other soft forks. This ensures DigiDollar only activates when a supermajority of miners explicitly signal support, preventing chain splits and ensuring network consensus. + +**Key principle:** Nothing consensus-critical for DigiDollar works until activation. DD/oracle RPCs, DD transactions, DD opcodes, oracle price relay, oracle consensus relay, MuSig2 relay, `getoracles`, and signed oracle version heartbeats are dormant until the activation predicates below pass. + +--- + +## BIP9 Deployment Parameters + +### Mainnet +| Parameter | Value | +|-----------|-------| +| Bit | 23 | +| Start Time | June 1, 2026 (epoch 1780272000) | +| Timeout | June 1, 2027 (epoch 1811808000) | +| Min Activation Height | 23,627,520 | +| Confirmation Window | 40,320 blocks (~1 week) | +| Threshold | 70% (28,224 of 40,320) | + +### Testnet (testnet26) +| Parameter | Value | +|-----------|-------| +| Bit | 23 | +| Start Time | Genesis timestamp (already past) | +| Timeout | Jan 1, 2028 (epoch 1830297600) | +| Min Activation Height | 600 | +| Confirmation Window | 200 blocks | +| Threshold | 70% (140 of 200) | + +### Regtest +| Parameter | Value | +|-----------|-------| +| Status | ALWAYS_ACTIVE | +| Min Activation Height | 0 | + +--- + +## BIP9 State Machine + +DigiDollar follows the standard BIP9 state transitions: + +``` +DEFINED ──→ STARTED ──→ LOCKED_IN ──→ ACTIVE + │ │ + │ └──→ FAILED (if timeout reached) + └──→ FAILED (if timeout reached before start) +``` + +### Phase 1: DEFINED (blocks 0–199 on testnet) +- **What happens:** Nothing. DigiDollar deployment exists in the code but signaling hasn't begun. +- **Miner behavior:** Miners don't need to do anything. Block versions don't include bit 23. +- **User experience:** DigiDollar tab visible in Qt but shows "DigiDollar is not yet active on this blockchain" with current BIP9 status. +- **RPC behavior:** DD price/position/transaction/oracle-operation RPCs return error: "DigiDollar is not yet active on this blockchain". Local wallet oracle key-management RPCs (`createoraclekey`, `exportoracleprivkey`, `importoracleprivkey`) remain available so operators can prepare or recover keys before activation. +- **P2P behavior:** Oracle price/bundle/consensus/attestation/MuSig2 nonce/context/partial-sig/getoracles messages, including signed `oraclehb` heartbeats, are silently dropped until `IsOracleP2PActive` returns true. +- **Consensus:** DD transactions rejected with "digidollar-not-active". DD opcodes are not dispatched with DigiDollar semantics until `SCRIPT_VERIFY_DIGIDOLLAR` is set. + +### Phase 2: STARTED (blocks 200–399 on testnet) +- **What happens:** Miners can now signal support by setting bit 23 in their block version. +- **Miner behavior:** `getblocktemplate` automatically includes bit 23 in the version field because `gbt_force=true`. Any miner using GBT (including cpuminer) signals automatically — no configuration needed. +- **Signaling check:** `getdeploymentinfo` RPC shows signal count and progress toward threshold. +- **User experience:** Same as DEFINED — everything still blocked. Qt overlay shows "STARTED" status. +- **Threshold:** 140 of 200 blocks in the window must signal bit 23 (70%). + +### Phase 3: LOCKED_IN (blocks 400–599 on testnet) +- **What happens:** Threshold reached! Activation is guaranteed but delayed until `min_activation_height`. +- **Miner behavior:** Bit 23 is forced into block versions (`nVersion |= Mask`). All blocks signal. +- **User experience:** Still blocked. Qt overlay shows "LOCKED_IN" status. Users know activation is imminent. +- **Why the delay:** `min_activation_height` ensures all nodes have time to upgrade before DD transactions become valid. + +### Phase 4: ACTIVE (block 600+ on testnet) +- **What happens:** DigiDollar is fully operational. MuSig2 oracle bundles are required in DD mint/redeem blocks; DD transfer-only and ordinary DGB blocks can omit the coinbase oracle bundle. +- **RPC behavior:** DD/oracle RPCs become functional (18 base in `src/rpc/digidollar.cpp`, 17 wallet-context in `src/wallet/rpc/wallet.cpp`). +- **P2P behavior:** Oracle messages (`oracleprice`, `oracleconsns`, `oracleattest`, `oramusnonce`, `oramusigctx`, `oramusigpsig`, `oraclehb`, `getoracles`) are processed, relayed, and validated according to the table below. Legacy `oraclebundle` messages are accepted on-wire but explicitly dropped — V1 carries the bundle on-chain in the coinbase, not via the bundle gossip message. +- **Consensus:** DD transactions are validated. DD opcodes are enforced via `SCRIPT_VERIFY_DIGIDOLLAR` (set in script flags when `DeploymentActiveAt(DEPLOYMENT_DIGIDOLLAR)` returns true). +- **Qt behavior:** Activation overlay disappears. Full DD tab (overview, send, receive, mint, redeem, positions, transactions) becomes accessible. +- **Oracle behavior:** Authorized oracle operators (slots 0-34 in `consensus.vOraclePublicKeys`, mainnet/testnet) can start their daemon, broadcast off-chain attestations and version heartbeats, participate in MuSig2 nonce/context/partial-sig rounds, and aggregate into the v0x03 on-chain bundle that miners embed in the coinbase for price-dependent DD blocks. `nDigiDollarMuSig2Height` is aligned with the effective DigiDollar activation boundary — MuSig2 v0x03 is the only accepted on-chain format from the moment DigiDollar/oracle consensus activates. + +> **Activation boundary nuance (1-block off-by-one).** `getdeploymentinfo` exposes a BIP9 view (`bip9.status = active`) that flips at the period boundary block — i.e. the block whose `pindexPrev->nHeight + 1 == min_activation_height`. The height-based gate `Consensus::IsOracleActive(params, height) == (height >= nOracleActivationHeight)` flips one block later, at `height == min_activation_height` itself. There is therefore a single-block window where `bip9.status` reports `active` but `IsOracleActive(tip)` is still `false`. This is harmless on production because `IsDigiDollarEnabled(prev_block)` already returns true at the period boundary and the miner refuses price-dependent DD mint/redeem templates without a valid v0x03 bundle. DD transfer-only blocks do not need a block oracle price. Boundary tests should use the height-based predicate (`IsOracleActive`/`IsDigiDollarEnabled`) rather than `getdeploymentinfo.bip9.status` when they need the consensus-rule moment, and Wave 12's `DD-FA-SEC-010` fix in `SpendsDigiDollarCollateralVault` deliberately uses `min(nDDActivationHeight, BIP9 min_activation_height)` for the same reason. + +> **Regtest activation knobs.** The direct `-digidollaractivationheight=N` regtest knob defined in `src/chainparams.cpp:102-109` now retargets both BIP9 `min_activation_height` and the static DD/oracle height gates (`nDDActivationHeight` / `nOracleActivationHeight`) in `src/kernel/chainparams.cpp:1222-1225`. Generic `-vbparams=digidollar:start:timeout:minheight` still overrides BIP9 only; because MuSig2 follows the effective DigiDollar BIP9 boundary, a BIP9-only test override can move MuSig2 validation without moving the static DD/oracle P2P gates. Default regtest remains intentionally special: BIP9 is `ALWAYS_ACTIVE` with `min_activation_height=0`, while the DD/oracle P2P height gates default to `650` for local testing. `nDigiDollarMuSig2Height` follows the effective BIP9 boundary (`0`) so v0x03 quotes are valid whenever DigiDollar is active. Startup oracle-price reconstruction follows the BIP9 predicate used by block connection, so BIP9-active default-regtest blocks below 650 are not skipped during restart/reindex cache rebuilds. + +--- + +## What Gets Gated (Complete List) + +### RPC Commands + +The DigiDollar/oracle RPC surface is split between the node-context registration in `src/rpc/digidollar.cpp` (registered via `RegisterDigiDollarRPCCommands`) and the wallet-context registration in `src/wallet/rpc/wallet.cpp` (added inside `GetWalletRPCCommands`). + +**Node-context (18, registered in `src/rpc/digidollar.cpp:6266`):** +- `getdigidollarstats`, `getdcamultiplier`, `calculatecollateralrequirement`, `getdigidollardeploymentinfo`, `importdigidollaraddress`, `estimatecollateral` +- `getoracleprice`, `getalloracleprices`, `getprotectionstatus`, `getoracles`, `getoraclesigners`, `listoracle`, `stoporacle`, `getoraclepubkey` +- Regtest helpers: `setmockoracleprice`, `getmockoracleprice`, `simulatepricevolatility`, `enablemockoracle` + +**Wallet-context (17, added in `src/wallet/rpc/wallet.cpp:888`):** +`mintdigidollar`, `senddigidollar`, `sendmanydigidollar`, `redeemdigidollar`, `listdigidollarpositions`, `listdigidollaraddresses`, `getredemptioninfo`, `getdigidollarbalance`, `getdigidollaraddress`, `listdigidollartxs`, `listdigidollarunspent`, `listdigidollarutxos`, `validateddaddress`, `createoraclekey`, `exportoracleprivkey`, `importoracleprivkey`, `startoracle`. + +`createoraclekey`, `exportoracleprivkey`, and `importoracleprivkey` are not activation-gated because they only manage wallet-local oracle signing keys. They do not start an oracle or publish prices. `startoracle` remains activation-gated. + +**Removed / never present:** `sendoracleprice` was deleted as a fake-price-injection vulnerability; `submitoracleprice` does not exist anywhere in the source tree. Oracle prices come exclusively from live exchange aggregation aggregated under MuSig2. `src/rpc/digidollar_transactions.cpp` declares `getdigidollarinfo`, `transferdigidollar`, `createrawddtransaction`, and `listredeemablepositions`, but the file is **not registered** anywhere — treat it as legacy/unused. + +**Gate pattern:** DD price/position/transaction/oracle-operation RPCs call `DigiDollar::IsDigiDollarEnabled(tip, chainman)` near the top of their handler. That helper checks the BIP9 `DEPLOYMENT_DIGIDOLLAR` state via `DeploymentActiveAfter()`. Local wallet key-management RPCs (`createoraclekey`, `exportoracleprivkey`, `importoracleprivkey`) and the deployment-status probe are intentionally usable before activation. + +### P2P Message Handlers + +`src/protocol.cpp` defines the on-wire command names; `src/net_processing.cpp` handles each one. Price, consensus, MuSig2, and `getoracles` handlers bail out early when `Consensus::IsOracleActive(params, height)` is false. + +| Wire command (`src/protocol.cpp`) | C++ constant | Handler in `src/net_processing.cpp` | Notes | +|-----------------------------------|--------------|-------------------------------------|-------| +| `oracleprice` | `NetMsgType::ORACLEPRICE` | line 5452 | Off-chain oracle attestation (input to MuSig2) | +| `oraclebundle` | `NetMsgType::ORACLEBUNDLE` | line 5619 | **Accepted on the wire but always dropped** — V1 puts the bundle on-chain in the coinbase, not via gossip | +| `oracleconsns` | `NetMsgType::ORACLECONSENSUS` | line 5636 | Off-chain consensus proposal driving MuSig2 | +| `oracleattest` | `NetMsgType::ORACLEATTESTATION` | line 5755 | Per-oracle attestation supporting a consensus proposal | +| `oramusnonce` | `NetMsgType::ORACLEMUSIGNONCE` | line 5859 | MuSig2 round-1 public nonces | +| `oramusigctx` | `NetMsgType::ORACLEMUSIGCONTEXT` | line 5971 | MuSig2 context proposal fixing participant/nonce/quote set before partial signatures | +| `oramusigpsig` | `NetMsgType::ORACLEMUSIGPARTIALSIG` | line 6064 | MuSig2 round-2 partial signatures bound to a session context | +| `oraclehb` | `NetMsgType::ORACLEHEARTBEAT` | line 6175 | Signed oracle software/protocol heartbeat; telemetry, not a price input | +| `getoracles` | `NetMsgType::GETORACLES` | line 6262 | Pull request for missing oracle messages; replies with fresh `oracleprice` messages and recent `oraclehb` heartbeats | + +**Note:** The price/consensus/MuSig2/getoracles gates use `Consensus::IsOracleActive(params, ActiveChain().Height())`, which is `nHeight >= params.nOracleActivationHeight`. On mainnet and testnet `nOracleActivationHeight` equals `nDDActivationHeight` and the BIP9 `min_activation_height`; on default regtest BIP9 is `ALWAYS_ACTIVE` at min height 0 while the P2P height gates default to 650. A peer sending gated oracle messages before the height gate is silently ignored — no ban, no misbehaviour penalty — just dropped at the start of each handler. + +> **AUDIT NOTE:** As of the current code, `NetMsgType::ORACLEHEARTBEAT` uses `IsOracleP2PActive`, the same top-level activation helper used by the price, consensus, MuSig2, and `getoracles` handlers. It is also restricted to active consensus-roster oracle IDs, Schnorr-authenticated against chainparams, capped at 240 messages per peer per hour, deduplicated, and only returned by `getoracles` when recent. + +> **Caveat.** The height predicate `IsOracleActive` is independent of the BIP9 deployment view (`getdeploymentinfo.bip9.status`). On production they collapse to the same trigger because chainparams pins `nOracleActivationHeight == nDDActivationHeight == BIP9 min_activation_height`. There is a single-block boundary window described in the Phase 4 nuance above where the BIP9 view says `active` but the height gate is still `false`. On default regtest, BIP9 `ALWAYS_ACTIVE` means block validation can be DD-active before the 650 P2P height gate; use `IsOracleActive` and `IsDigiDollarEnabled` deliberately for boundary tests when the P2P moment and consensus-rule moment differ. + +### Consensus Validation (all BIP9-gated) + +1. **Mempool acceptance** (`src/validation.cpp:976-989`): `DigiDollar::HasDigiDollarMarker(tx)` + `IsDigiDollarEnabled()` → rejects DD TXs with `TX_CONSENSUS "digidollar-not-active"`. After activation, mempool acceptance also requires that an oracle quote is available for any DD transaction (commit `81bf974f40`). +2. **Block validation** (`src/validation.cpp:2816-2854`): `DeploymentActiveAt(DEPLOYMENT_DIGIDOLLAR)` during `ConnectBlock()` delegates to `DeploymentActiveAfter(index.pprev, ...)`, so the candidate block is judged using the previous block's BIP9 state. Blocks containing DD TXs before activation are rejected. After activation, `ValidateBlockOracleData` (`src/oracle/bundle_manager.cpp:2151`) requires DD mint/redeem blocks to carry exactly one v0x03 MuSig2 oracle bundle in the coinbase. DD transfer-only and non-DD blocks may omit oracle data; if any block includes one it must still be a valid v0x03 bundle (commit `1e08bd811f`). +3. **Script verification** (`validation.cpp` script-flag setup): `SCRIPT_VERIFY_DIGIDOLLAR` flag only set when `DeploymentActiveAt()` returns true, so the Tapscript OP_SUCCESSx-class DD opcodes are not interpreted as DigiDollar operations before activation. Once active, `OP_CHECKPRICE` is reserved and deterministically disabled (`src/script/interpreter.cpp:708-735`): it consumes one stack item and pushes false rather than reading node-local oracle state. +4. **Mining graceful degradation** (`src/node/miner.cpp`, commit `6b5ff516c3`): `CreateNewBlock` strips price-dependent DD mint/redeem txs when no valid oracle bundle is available rather than aborting block assembly. Transfer-only DD txs are validated with oracle-price validation skipped because they do not need a block oracle price. The block is still produced; rejected DD txs remain in the mempool until either they confirm in a later attempt or are evicted. + +Historical validation, IBD, and reorg handling follow the same predicates. `ValidateBlockOracleData()` returns true before the historical activation state, startup price-cache reconstruction only loads blocks that are BIP9-active for their historical context, IBD/catch-up skips oracle-dependent DD validation where the code cannot safely re-evaluate old wall-clock freshness with current state, and `DisconnectBlock()` removes the connected block's price-cache entry during reorg. + +### Qt GUI + +- **DigiDollar tab:** Always visible, but shows activation status overlay (QStackedWidget) when DD inactive +- **Sub-widget polling:** All DD widgets check `isVisible()` before making RPC calls — prevents RPC queue flooding when DD tab is hidden behind overlay +- **Activation check timer:** Runs every 5 seconds, calls `DigiDollar::IsDigiDollarEnabled()`. Stops and reveals DD functionality once active. + +--- + +## Miner Signaling — How It Works + +### Why miners signal automatically + +The `VBDeploymentInfo` for DigiDollar has `gbt_force = true` (in `src/deploymentinfo.cpp`). This means: + +1. During `STARTED` state, `getblocktemplate` includes bit 23 in `vbavailable` +2. Because `gbt_force=true`, the bit is NOT cleared even if the miner doesn't explicitly support "digidollar" in its GBT rules +3. The version field returned by `getblocktemplate` already has bit 23 set +4. cpuminer (and any GBT-based miner) uses this version directly → automatic signaling + +### Block version format + +``` +Base version: 0x20000000 (BIP9 base) ++ Taproot bit: 0x00000004 (bit 2) ++ DD bit: 0x00800000 (bit 23) += Combined: 0x20800004 +``` + +During STARTED/LOCKED_IN, blocks should have version `0x20800004` or similar (with bit 23 set). Note: SegWit is a buried deployment in DigiByte (activated at a fixed height), not a version bits deployment, so it does not set any bit. + +--- + +## Testing BIP9 Activation + +### Functional Tests + +1. **`digidollar_activation.py`** — Tests the full activation lifecycle: + - Mines through DEFINED → STARTED → LOCKED_IN → ACTIVE + - Verifies DD RPCs fail before activation, work after + - Tests DD minting, sending, redeeming after activation + - Checks version bits in block headers + +2. **`digidollar_activation_boundary.py`** — Tests edge cases: + - Exact block boundaries between phases + - Threshold calculation (exactly 140/200) + - Below-threshold signaling (remains STARTED) + - min_activation_height enforcement + +### Manual Testing Checklist + +Before activation (any block < 600): +- [ ] DD price/position/transaction/oracle-operation RPCs return "DigiDollar is not yet active on this blockchain" +- [ ] Local oracle key-management RPCs (`createoraclekey`, `exportoracleprivkey`, `importoracleprivkey`) remain usable for pre-activation operator setup/recovery +- [ ] `getdeploymentinfo` shows correct BIP9 state +- [ ] Qt DD tab shows activation overlay +- [ ] No oracle messages processed (check debug.log; `IsOracleActive` returns false) +- [ ] DD transactions rejected from mempool with "digidollar-not-active" +- [ ] Block version includes bit 23 after STARTED (block 200+) + +After activation (block 600+): +- [ ] DD RPCs functional +- [ ] Can mint DigiDollar (requires a valid MuSig2 oracle bundle in the mining template) +- [ ] Can send DigiDollar +- [ ] Can redeem DigiDollar +- [ ] Oracles can start (`createoraclekey` + `startoracle`) and broadcast attestations +- [ ] Oracle attestations, version heartbeats, and MuSig2 nonce/context/partial-sig messages propagate via P2P +- [ ] Qt DD tab shows full functionality +- [ ] `SCRIPT_VERIFY_DIGIDOLLAR` enabled in block script flags +- [ ] DD mint/redeem blocks include a v0x03 MuSig2 oracle bundle in the coinbase; DD transfer-only blocks can omit it (raw v0x01 / v0x02 wire payloads short-circuit inside `ExtractOracleBundle` and surface as `bad-oracle-malformed`; the `bad-oracle-legacy` branch is defense-in-depth and is not reached by current wire shapes) + +--- + +## Mainnet Activation Timeline + +On mainnet, the process is: + +1. **Release:** Publish binaries with DigiDollar code and BIP9 deployment +2. **Upgrade period:** Miners and nodes upgrade (BIP9 start time: June 1, 2026) +3. **Signaling begins:** After start time (June 1, 2026), miners signal bit 23 in blocks +4. **Threshold reached:** 70% of blocks in a 40,320-block window (~1 week) signal support +5. **Lock-in period:** One more 40,320-block window for remaining nodes to upgrade +6. **Activation:** Block height reaches `min_activation_height` (23,627,520) and BIP9 is ACTIVE +7. **DigiDollar live:** All DD functionality enabled across the network + +**Timeout:** If 70% signaling is not reached by June 1, 2027, the deployment transitions to FAILED. A new deployment with different parameters would be needed. + +--- + +## Security Considerations + +1. **Pre-activation protection:** All DD code paths are gated. A malicious node cannot trick other nodes into processing DD transactions or oracle messages before activation. + +2. **No premature mining:** DD opcodes are not enforced as DigiDollar operations before activation. Even if someone crafts a transaction with DD opcodes, the DigiDollar semantics have no effect until `SCRIPT_VERIFY_DIGIDOLLAR` is set. + +3. **Oracle P2P safety:** Price, consensus, MuSig2, `getoracles`, and signed `oraclehb` heartbeat messages received before `IsOracleP2PActive` are silently dropped (not banned). + +4. **Consensus safety:** Mempool policy rejects DD-marker transactions before activation, but block consensus preserves base-chain compatibility: pre-activation DD-looking markers are treated as ordinary DGB data and DigiDollar semantics are not applied until BIP9 is ACTIVE. + +5. **BIP9 guarantees:** The activation mechanism is the same one Bitcoin used for SegWit. It's battle-tested across multiple blockchains and provides clear upgrade coordination. + +--- + +## Mainnet `nOracleActivationHeight` and `nDDActivationHeight` + +Both heights are intentionally aligned in `src/kernel/chainparams.cpp`: + +| Network | `nDDActivationHeight` | `nOracleActivationHeight` | `nDigiDollarMuSig2Height` | +|---------|-----------------------|---------------------------|---------------------------| +| Mainnet | `23627520` | `consensus.nDDActivationHeight` (i.e. `23627520`) | `consensus.nDDActivationHeight` (i.e. `23627520`) | +| Testnet26 | `600` | `600` | `600` | +| Regtest | `650` | `650` | `0` | + +A practical implication: there is no period in which the oracle P2P surface is live but DD itself is not, and there is no period in which DD is active but MuSig2 v0x03 is not yet the on-chain bundle format. On mainnet/testnet the three numeric heights collapse to one event; on default regtest MuSig2 follows the BIP9 `ALWAYS_ACTIVE` boundary while DD/oracle height gates remain at 650 for local testing. Documents that say "mainnet `nOracleActivationHeight = 3000000`" are stale; that earlier staging configuration was removed before V1 launch. + +## File Reference + +| Component | File | Function | +|-----------|------|----------| +| BIP9 deployment params | `src/kernel/chainparams.cpp` | `vDeployments[DEPLOYMENT_DIGIDOLLAR]` | +| BIP9 state machine | `src/versionbits.cpp` | `AbstractThresholdConditionChecker` / `VersionBitsConditionChecker` | +| Deployment info | `src/deploymentinfo.cpp` | `VersionBitsDeploymentInfo[]` | +| RPC activation gate | `src/rpc/digidollar.cpp` | `IsDigiDollarEnabled()` check in each RPC | +| P2P activation gate | `src/net_processing.cpp` | `IsOracleP2PActive()` in `ORACLEPRICE`/`ORACLEBUNDLE`/`ORACLECONSENSUS`/`ORACLEATTESTATION`/`ORACLEMUSIGNONCE`/`ORACLEMUSIGCONTEXT`/`ORACLEMUSIGPARTIALSIG`/`GETORACLES`/`ORACLEHEARTBEAT` | +| Mempool gate | `src/validation.cpp:976-989` | `IsDigiDollarEnabled()` in `AcceptToMemoryPool`; recent MuSig2 quote required for DD txs | +| Block validation gate | `src/validation.cpp:2816-2854` | `DeploymentActiveAt(DEPLOYMENT_DIGIDOLLAR)` in `ConnectBlock` | +| Script flags | `src/validation.cpp:2755-2798` | `SCRIPT_VERIFY_DIGIDOLLAR` flag (set in `GetBlockScriptFlags`) | +| Qt activation overlay | `src/qt/digidollartab.cpp` | `checkActivationStatus()` timer | +| Qt widget polling guard | `src/qt/digidollar*widget.cpp` | `if (!isVisible()) return;` | +| Oracle height gate | `src/consensus/params.h:243-245` | `IsOracleActive()` | +| DD enabled check | `src/digidollar/digidollar.cpp` | `IsDigiDollarEnabled()` | +| Oracle bundle V1 enforcement | `src/oracle/bundle_manager.cpp` (`ValidateBlockOracleData`, `ExtractOracleBundle`, `CreateOracleScript`) | Raw v0x01/v0x02 OP_RETURN payloads short-circuit in `ExtractOracleBundle` (returns false), surfaced by the validator as `bad-oracle-malformed`. Only v0x03 MuSig2 bundles are accepted; the `bad-oracle-legacy` branch is defense-in-depth | +| Reserved `OP_CHECKPRICE` behavior | `src/script/interpreter.cpp:708-735` | `OP_CHECKPRICE` is reserved and deterministically disabled; the old `g_get_oracle_consensus_price` hook remains only for tests | diff --git a/DIGIDOLLAR_ARCHITECTURE.md b/DIGIDOLLAR_ARCHITECTURE.md new file mode 100644 index 00000000000..15879ea8216 --- /dev/null +++ b/DIGIDOLLAR_ARCHITECTURE.md @@ -0,0 +1,1719 @@ +# DigiDollar Implementation Architecture +**DigiByte v9.26.2 - Current Implementation Status** +*Updated: 2026-05-20* +*Implementation Status: V1 / `feature/digidollar-v1`* +*Document Version: 6.8 - Validated against codebase* +*Validation Status: Validated Against Codebase (2026-05-20)* + +## Executive Summary + +### What is DigiDollar? + +DigiDollar is a decentralized USD-denominated token design built natively on DigiByte's UTXO model. Unlike traditional stablecoins controlled by companies or banks, DigiDollar does not use custodial bank reserves. Every DigiDollar is backed by locked DigiByte (DGB) coins held in secure, time-locked digital vaults that users control with their own private keys. + +**Think of it like this**: Imagine you have $1,000 worth of gold that you want to convert to cash for spending, but you don't want to sell the gold and lose future gains. DigiDollar lets you lock that gold in a secure vault and get $500 in spending money today. The gold never leaves your vault - you just can't access it until the time-lock expires. When it does, you can burn the $500 DigiDollar and get your gold back, keeping all the appreciation. + +### Current Implementation Status + +The DigiDollar V1 stack on `feature/digidollar-v1` is feature-complete; remaining work is operational hardening and mainnet rollout. Highlights: + +- **Address System** — DD/TD/RD addresses live on mainnet/testnet/regtest (`src/base58.{h,cpp}`). +- **Minting / Transferring / Redeeming** — Full P2TR pipeline (`src/digidollar/txbuilder.cpp`, `src/digidollar/validation.cpp`). +- **Confirmed-only DD chaining** — Consensus refuses `MEMPOOL_HEIGHT` DD inputs for transfers and redeems (`src/digidollar/validation.cpp:1811, 1955`). +- **Network-Wide Tracking** — `SystemHealthMonitor::ScanUTXOSet` plus incremental `OnMintConnected/OnRedeemConnected` hooks (`src/digidollar/health.cpp`); `DigiDollarStatsIndex` provides per-block aggregates (`src/index/digidollarstatsindex.{cpp,h}`). +- **Protection Systems** — DCA (`src/consensus/dca.cpp`), ERR (`src/consensus/err.cpp`) and Volatility (`src/consensus/volatility.cpp`) all production-wired. ERR enforces extra DD burn (no DGB haircut) via integer `__int128` math. +- **Canonical Lock Tiers** — Mint OP_RETURNs must declare tier 0-9. Validation accepts only the claimed canonical tier window `[tier_blocks, tier_blocks + 100]`, so under-locked/custom terms are rejected while delayed mining remains valid. +- **OP_CHECKPRICE reserved opcode** — `OP_CHECKPRICE` is reserved and deterministically disabled; the interpreter consumes its operand and pushes false instead of reading node-local oracle state (`src/script/interpreter.cpp:708-735`). +- **MuSig2 V1 oracle path only** — Block validation rejects pre-V1 (legacy) oracle bundles in coinbase once DigiDollar is active (`src/validation.cpp:185-217`); mempool acceptance requires a recent valid MuSig2 oracle quote (`src/validation.cpp:224-283`). +- **Mining graceful degradation** — DD txs that fail validation are stripped from `mapModifiedTx` rather than blocking block assembly (`src/node/miner.cpp:707-744`). +- **Comprehensive Testing** — Unit tests under `src/test/digidollar_*` and `src/test/rh*`/`src/test/oracle_*`/`src/test/musig2_*`; functional tests under `test/functional/digidollar_*.py` and `test/functional/wallet_digidollar_*.py`. See `REPO_MAP_DIGIDOLLAR.md` for the full inventory. + +This document explains how each piece works, where the code lives, and how the runtime gates are wired together. + +--- + +## 1. How DigiDollar Works - The Big Picture + +### 1.1 The Four Main Things You Can Do + +**Think of DigiDollar like a high-tech bank vault system where you're always in control:** + +1. **🏦 MINT (Create DigiDollars)**: Lock your DGB in a digital vault, get DigiDollars to spend +2. **💸 SEND (Transfer DigiDollars)**: Send DigiDollars to anyone with a DD address +3. **📨 RECEIVE (Get DigiDollars)**: Generate DD addresses to receive DigiDollars from others +4. **🔓 REDEEM (Get Your DGB Back)**: Burn DigiDollars to unlock your original DGB + +### 1.2 Where the Code Lives + +The DigiDollar system is split across these directories: + +- **`src/digidollar/`** — Core DigiDollar logic (`digidollar`, `health`, `scripts`, `txbuilder`, `validation`) +- **`src/consensus/`** — DigiDollar consensus rules (`digidollar`, `digidollar_transaction_validation`, `digidollar_tx`, `dca`, `err`, `volatility`) +- **`src/oracle/`** — Oracle daemon, exchange aggregator, MuSig2 (`bundle_manager`, `exchange`, `mock_oracle`, `node`, `signing_orchestrator`, `musig2_*`) +- **`src/primitives/oracle.{h,cpp}`** — Price message + bundle types +- **`src/index/digidollarstatsindex.{h,cpp}`** — Block-level DD supply / collateral / vault count index +- **`src/script/script.h`** — DigiDollar opcode definitions (0xbb–0xbf) +- **`src/script/interpreter.cpp`** — `SCRIPT_VERIFY_DIGIDOLLAR` evaluation, OP_CHECKPRICE/OP_CHECKCOLLATERAL/OP_DDVERIFY/OP_DIGIDOLLAR/OP_ORACLE +- **`src/rpc/digidollar.{cpp,h}`** — Registered DigiDollar RPC surface +- **`src/wallet/digidollarwallet.{cpp,h}`**, **`src/wallet/ddcoincontrol.{cpp,h}`** — Wallet integration +- **`src/qt/digidollar*.{cpp,h}`** — Qt widgets +- **`src/test/`**, **`src/wallet/test/`**, **`src/qt/test/`**, **`src/test/fuzz/`**, **`test/functional/`** — Tests + +`src/rpc/digidollar_transactions.{cpp,h}` declares `getdigidollarinfo`, `transferdigidollar`, `createrawddtransaction`, `listredeemablepositions` and a `GetDigiDollarTransactionRPCCommands()` helper, but the helper has no caller — treat that file as legacy/dead code unless explicitly rewired. + +### 1.3 Phasing + +Phase 1 (data structures, P2TR scripts, DD addresses, transaction versioning) and Phase 2 (mint/transfer/redeem core operations) are complete. The current branch (`feature/digidollar-v1`) lands the V1 production gates: live MuSig2 oracle bundles, reserved/disabled `OP_CHECKPRICE`, confirmed-only DD chaining, integer-only DCA/ERR math, and the supply alert (no hard cap). + +--- + +## 2. DigiDollar Process Flowchart + +``` +┌─────────────────┐ +│ USER ACTION │ +└────────┬────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ DETERMINE ACTION TYPE │ +├─────────────────────────────────────────────────────────────┤ +│ • Mint: Create new DigiDollars │ +│ • Transfer: Send DigiDollars to DD address │ +│ • Redeem: Burn DigiDollars, recover DGB │ +│ • Receive: Generate DD addresses, detect incoming DD │ +└─────────────────────────────────────────────────────────────┘ + │ + ┌────┴────┬──────────┬───────────┐ + ▼ ▼ ▼ ▼ +┌────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐ +│ MINT │ │ TRANSFER │ │ RECEIVE │ │ REDEEM │ +└────┬───┘ └────┬─────┘ └────┬────┘ └────┬────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ +┌─────────────────────────────────────────────┐ +│ MINT PROCESS │ +├─────────────────────────────────────────────┤ +│ 1. Select lock period (1h to 10y) │ +│ 2. Get current oracle price │ +│ 3. Check system health (DCA status) │ +│ 4. Calculate required collateral: │ +│ Base Ratio × DCA Multiplier × DD Amount │ +│ 5. Lock DGB in P2TR output with MAST │ +│ 6. Create DigiDollar P2TR output │ +│ 7. Record collateral position in database │ +│ 8. Sign transaction with Schnorr + ECDSA │ +│ 9. Broadcast to network via wallet chain │ +└──────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────┐ +│ TRANSFER PROCESS │ +├─────────────────────────────────────────────┤ +│ 1. Validate DD address (DD/TD/RD prefix) │ +│ 2. Select DD UTXOs for input (greedy) │ +│ 3. Select DGB UTXOs for fees │ +│ 4. Create DD outputs to recipient │ +│ 5. Add DD change output if needed │ +│ 6. Sign DD inputs with Schnorr (P2TR) │ +│ 7. Sign fee inputs with ECDSA │ +│ 8. Broadcast via wallet chain interface │ +│ 9. Update UTXO database (remove spent) │ +│ 10. Add new UTXOs (change, self-transfers) │ +└──────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────┐ +│ RECEIVE PROCESS │ +├─────────────────────────────────────────────┤ +│ 1. Generate new P2TR DD address │ +│ 2. Encode with DD/TD/RD prefix │ +│ 3. Create QR code for payment request │ +│ 4. Add to address book with label │ +│ 5. Monitor incoming transactions │ +│ 6. Detect DD outputs via SyncTransaction │ +│ 7. Verify ownership with IsMine() │ +│ 8. Extract DD amount from script │ +│ 9. Add to UTXO tracking database │ +│ 10. Update balance and notify (pending) │ +└──────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────┐ +│ REDEMPTION PROCESS │ +├─────────────────────────────────────────────┤ +│ 1. Check redemption path (exactly 2 paths │ +│ in the MAST tree, both timelock-gated): │ +│ • Normal: Timelock expired, health ≥100% │ +│ → Burn original DD, get 100% collateral│ +│ • ERR: Timelock expired, health < 100% │ +│ → Burn MORE DD (up to 125% via integer │ +│ ceil math), get 100% collateral back │ +│ 2. DD inputs MUST be confirmed — consensus │ +│ rejects DD inputs with nHeight = │ +│ MEMPOOL_HEIGHT (commit 0b4959f563). │ +│ 3. Select DD UTXOs to burn: │ +│ • Normal: Burn original minted amount │ +│ • ERR: ceil(originalDD * 10000 / │ +│ ratioBps) (src/consensus/err.cpp:122) │ +│ 4. Create redemption transaction with: │ +│ • Input 0: Collateral vault (P2TR │ +│ script-path; CLTV must be expired) │ +│ • Input 1+: DD tokens to burn │ +│ • Input N: DGB for fees │ +│ 5. Sign inputs: │ +│ • Collateral: Schnorr script-path sig │ +│ (NUMS internal key blocks key-path) │ +│ • DD tokens: Schnorr key-path sig │ +│ • Fees: Standard ECDSA │ +│ 6. Validation: ValidateCollateralRelease │ +│ Amount enforces full burn AND full │ +│ collateral release (no partial). │ +│ 7. Release FULL collateral to owner. │ +│ 8. Close position in wallet database. │ +└──────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────┐ +│ PROTECTION SYSTEMS CHECK │ +├─────────────────────────────────────────────┤ +│ DCA (src/consensus/dca.cpp HEALTH_TIERS): │ +│ • >=150%: Healthy (1.00x / 10000 bps) │ +│ • 120-149%: Warning (1.25x / 12500 bps) │ +│ • 110-119%: Critical (1.50x / 15000 bps) │ +│ • <110%: Emergency (2.00x / 20000 bps) │ +│ Health and DCA use __int128 ceiling math │ +│ (commit 9cca6970ae) and ApplyDCA fails │ +│ closed when canonical health is missing. │ +├─────────────────────────────────────────────┤ +│ ERR (src/consensus/err.cpp ERR_TIERS): │ +│ * BURNS MORE DD, NOT LESS COLLATERAL * │ +│ • 95-100%: 1/0.95 -> 105.3% DD burn │ +│ • 90-95%: 1/0.90 -> 111.1% DD burn │ +│ • 85-90%: 1/0.85 -> 117.6% DD burn │ +│ • <85%: 1/0.80 -> 125.0% DD burn │ +│ requiredDD = ceil(originalDD*10000/ratioBps)│ +│ (commit 55926c372a). Collateral always 100%;│ +│ ShouldBlockMinting() blocks new mints while │ +│ active. │ +├─────────────────────────────────────────────┤ +│ Volatility (src/consensus/volatility.cpp): │ +│ • 1h vol > 20% -> freeze new mints │ +│ • 24h vol > 30% -> freeze ALL DD ops │ +│ • Cooldown: 8640 blocks (~36h) │ +│ • Pre-mutation gate: WouldCandidateFreeze │ +│ Minting() rejects bad mints before they │ +│ can poison the history (03f4af47a7). │ +├─────────────────────────────────────────────┤ +│ Oracle System Integration: │ +│ • V1 mainnet/testnet: 35 active oracle │ +│ slots, 7 MuSig2 signatures │ +│ required (BIP-340 aggregate, │ +│ BIP-327 MuSig2) │ +│ • Regtest: 4-of-7 (chainparams override) │ +│ • Median price in micro-USD format │ +│ • 6 active exchange APIs via libcurl │ +└──────────────────────────────────────────────┘ +``` + +--- + +## 3. How DigiDollar Stores and Tracks Your Money + +### 3.1 The Digital Receipt System + +**Simple Explanation**: Every DigiDollar transaction creates digital "receipts" that track exactly how much you have and where it came from. Think of it like a sophisticated digital ledger that never loses track of your money. + +#### **DigiDollar Outputs - Your Digital Money** +**Where the code lives**: `/src/digidollar/digidollar.h` - `CDigiDollarOutput` class + +**What it stores**: +- **Amount**: How many DigiDollars (stored in cents internally, 100 cents = $1.00 DD) +- **Vault Connection**: Which DGB vault this came from (if any) +- **Lock Time**: When a vault can be opened (measured in blocks) +- **Digital Keys**: Cryptographic data for security and privacy + +**For developers**: Complete Taproot/P2TR integration with MAST support, robust serialization, overflow protection, and links to collateral positions. + +**Status**: ✅ **100% Complete and Production Ready** + +#### **Collateral Positions - Your DGB Vaults** +**Where the code lives**: `/src/digidollar/digidollar.h` - `CCollateralPosition` class + +**Simple Explanation**: Every time you create DigiDollars by locking DGB, the system creates a "vault record" that tracks your locked DGB and gives you multiple ways to get it back. + +**What each vault record contains**: +- **Vault Location**: Exactly where your DGB is locked on the blockchain +- **DGB Amount**: How much DGB you locked up +- **DigiDollars Created**: How many DigiDollars you got for locking the DGB +- **Unlock Date**: When you can normally get your DGB back (measured in block height) +- **Safety Ratio**: How much extra DGB you locked (200%-1000% depending on time period) +- **Exit Options**: 2 functional redemption paths (see below) + +**The 2 Ways to Get Your DGB Back** (Verified in Code): +1. **Normal**: Timelock expired + system health ≥100% → Burn original DD, get 100% collateral back +2. **ERR (Emergency Redemption Ratio)**: Timelock expired + system health <100% → Burn MORE DD (105-125%), get 100% collateral back (FULL amount always returned) + +**CRITICAL RULE**: DGB locked as collateral **CAN NEVER BE UNLOCKED** until the timelock expires. No exceptions. No early redemption. Ever. Both paths REQUIRE the timelock to be expired first. + +**For developers**: Advanced features include real-time health calculations, dynamic path management, integration with system monitoring, and overflow protection. + +**Status**: ✅ **V1 production-wired; wallet/GUI polish tracked in their sections** + +### 3.2 Address System Implementation + +#### **DigiDollar Address Format** (`/src/base58.cpp`) +**Status: ✅ Complete with Full Network Support** + +```cpp +class CDigiDollarAddress { + // Network prefixes (2-byte Base58Check version bytes) + DD_P2TR_MAINNET = {0x52, 0x85}, // "DD" prefix + DD_P2TR_TESTNET = {0xb1, 0x29}, // "TD" prefix + DD_P2TR_REGTEST = {0xa3, 0xa4} // "RD" prefix +}; +``` + +**Implementation Highlights:** +- ✅ Proper 2-byte version prefixes for Base58Check encoding +- ✅ Only supports P2TR (Taproot) destinations for future extensibility +- ✅ Complete validation and error handling +- ✅ Full serialization support for wallet persistence + +**Address Examples:** +- Mainnet: `DD1q2w3e4r5t6y7u8i9o0p1a2s3d4f5g6h7j8k9l0m1n2` +- Testnet: `TD1q2w3e4r5t6y7u8i9o0p1a2s3d4f5g6h7j8k9l0m1n2` +- Regtest: `RD1q2w3e4r5t6y7u8i9o0p1a2s3d4f5g6h7j8k9l0m1n2` + +### 3.3 Transaction Type System + +#### **Version Encoding** (`/src/primitives/transaction.h`) + +```cpp +// Transaction type encoding in nVersion field +// Bits 0-15 (DD_VERSION_MASK 0x0000FFFF) — marker (low 16 bits = 0x0770) +// Bits 16-23 (DD_FLAGS_MASK 0x00FF0000) — flags (currently unused) +// Bits 24-31 (DD_TYPE_MASK 0xFF000000) — transaction type +// Full constructed marker: DD_TX_VERSION = 0x0D1D0770. HasDigiDollarMarker +// only checks the low 16 bits, so the upper 16 bits encode (type, flags). + +static constexpr int32_t DD_TX_VERSION = 0x0D1D0770; + +enum DigiDollarTxType : uint8_t { + DD_TX_NONE = 0, // Not a DD transaction + DD_TX_MINT = 1, // Lock DGB, create DigiDollars + DD_TX_TRANSFER = 2, // Transfer DigiDollars between addresses + DD_TX_REDEEM = 3, // Burn DigiDollars, unlock DGB (NORMAL or ERR path) + DD_TX_MAX = 4 // Sentinel for validation +}; + +// ERR is a redemption *path* in the MAST tree, not a transaction type. +// Both NORMAL and ERR redemptions are DD_TX_REDEEM; the path is selected +// at spend time and the burn requirement adjusts via err.cpp. + +inline int32_t MakeDigiDollarVersion(DigiDollarTxType type, uint8_t flags = 0); // (type << 24) | (flags << 16) | (DD_TX_VERSION & 0xFFFF) +``` + +This unique marker prevents collisions with non-DD transactions, allows policy/relay code to detect DD txs cheaply, and lets `IsStandardTx` whitelist DD-specific output shapes (e.g. zero-value DD token outputs) without affecting standard transactions. + +--- + +## 3. Minting Process Architecture + +### 3.1 Minting Process Flow (Recently Refactored) + +```mermaid +flowchart TD + A[User Initiates Mint] --> B[Parameter Validation] + B --> C[Get Oracle Price] + C --> D[Calculate Collateral Requirement] + D --> E[Apply DCA Multiplier] + E --> F[Select UTXOs] + F --> G[Build Transaction] + G --> H[Create P2TR Outputs] + H --> I[Sign Transaction] + I --> J[Broadcast] + J --> K[Update Position Database] + + C --> L[Check Volatility Freeze] + L --> M{Frozen?} + M -->|Yes| N[Reject Mint] + M -->|No| D + + D --> O[Check System Health] + O --> P{DCA Active?} + P -->|Yes| Q[Increase Requirement] + P -->|No| E + Q --> E +``` + +### 3.2 Collateral Calculation Engine + +#### **10-Tier Lock System** (`/src/consensus/digidollar.h`) +**Status: ✅ Production Ready** + +| Lock Period | Collateral Ratio | Rationale | +|-------------|------------------|-----------| +| 1 hour | 1000% | Testing/onboarding tier (canonical on all networks) | +| 30 days | 500% | Maximum safety for short-term | +| 3 months | 400% | High collateral for quarterly | +| 6 months | 350% | Semi-annual with strong buffer | +| 1 year | 300% | Annual with 3x safety | +| 2 years | 275% | Medium-term commitment | +| 3 years | 250% | Medium-term stability | +| 5 years | 225% | Long-term commitment | +| 7 years | 212% | Extended positions | +| 10 years | 200% | Minimum 2x for maximum lock | + +#### **Dynamic Collateral Adjustment (DCA)** (`/src/consensus/dca.cpp`) + +```cpp +// DCA class HEALTH_TIERS in src/consensus/dca.cpp (basis points): +// >=150% : 10000 bps (1.00x) "healthy" +// 120-149% : 12500 bps (1.25x) "warning" +// 110-119% : 15000 bps (1.50x) "critical" +// <110% : 20000 bps (2.00x) "emergency" +// +// Both ConsensusParams::dcaLevels (src/consensus/digidollar.h) and the runtime +// DCA::HEALTH_TIERS use the same values; the runtime tier table is the +// authoritative source consulted by ApplyDCA(). +// +// ApplyDCA() runs ceil(baseRatio * multiplierBps / 10000) using __int128 to +// avoid overflow (commit 9cca6970ae) and fails closed (returns INT_MAX) when +// the caller-supplied health is stale relative to the canonical cached value. +int DynamicCollateralAdjustment::ApplyDCA(int baseRatio, int systemHealth); +``` + +### 3.3 Minting Transaction Builder + +#### **MintTxBuilder** (`/src/digidollar/txbuilder.cpp`) +**Status: ✅ Advanced Implementation** + +**Core Features:** +- ✅ Real-time collateral calculation with DCA integration +- ✅ Sophisticated UTXO selection with overflow protection +- ✅ OP_RETURN metadata for cross-node validation +- ✅ Proper fee estimation and change handling +- ✅ Dual P2TR output creation: collateral with MAST, DD token with key-path only +- ✅ Canonical lock-tier validation: OP_RETURN stores tier/lock height/owner key, and consensus checks the remaining lock blocks against `[canonical_blocks, canonical_blocks + 100]` + +**Transaction Output Structure (~lines 344-370):** +```cpp +// Output 0: Collateral vault (P2TR with CLTV timelock) +CScript collateralScript = CreateCollateralScript(params); // MAST structure +tx.vout.push_back(CTxOut(result.collateralRequired, collateralScript)); + +// Output 1: DD token (SIMPLE P2TR - key-path only, NO MAST, NO CLTV) +// DD tokens must be freely transferable, unlike collateral which has timelock +CScript ddScript = CreateDDOutputScript(params.ownerKey, params.ddAmount); +tx.vout.push_back(CTxOut(0, ddScript)); // 0 DGB value +``` + +**Critical Design Decision:** +- **Collateral (vout[0])**: P2TR with CLTV timelock (2 redemption paths: Normal and ERR, both require timelock expiry) +- **DD Token (vout[1])**: Simple P2TR key-path only - freely transferable, no scripts, no timelock +- **Why Different**: DD tokens need to move freely between users; only collateral needs locking/redemption paths + +**Witness Structure:** +- **Collateral spending (redemption)**: `[signature] [script] [control_block]` - SCRIPT-PATH +- **DD token spending (transfers)**: `[signature]` - KEY-PATH (64 bytes only) + +**Recent Refactoring Highlights:** +- Enhanced system health integration for DCA +- Improved fee calculation and UTXO management +- Better error handling and validation +- Optimized coin selection algorithms +- **Fixed DD token output**: Changed from CreateCollateralScript() to CreateDDOutputScript() for free transferability + +### 3.4 Minting GUI Implementation + +#### **DigiDollar Mint Widget** (`/src/qt/digidollarmintwidget.cpp`) +**Status: ✅ Complete User Interface** + +**Features:** +- ✅ Lock period dropdown with 10 tiers +- ✅ Real-time collateral calculator +- ✅ Oracle price display from the live consensus/MuSig2 price source +- ✅ Available balance checking +- ✅ Progress indicators and error handling +- ✅ Theme-aware styling + +**Backend Integration:** +- ✅ Connected to WalletModel::mintDigiDollar() +- ✅ Real-time parameter validation +- ✅ Transaction confirmation dialogs +- ✅ Uses live oracle pricing on mainnet/testnet; regtest may use deterministic mock helpers + +--- + +## 4. Transfer/Send System Architecture + +### 4.1 Transfer Process Flow (Fully Implemented) + +```mermaid +flowchart TD + A[User Input DD Address] --> B[Validate DD Address Format] + B --> C[Check DD Balance] + C --> D[Select DD UTXOs] + D --> E[Select Fee UTXOs] + E --> F[Build Transfer Transaction] + F --> G[Create DD Outputs] + G --> H[Calculate Change] + H --> I[Sign DD Inputs] + I --> J[Sign Fee Inputs] + J --> K[Broadcast Transaction] + K --> L[Update UTXO Database] +``` + +### 4.2 UTXO Management Innovation + +#### **DD UTXO Tracking** (`/src/wallet/digidollarwallet.cpp`) +**Status: ✅ Sophisticated Implementation** + +```cpp +// Maps (txid, vout) → DD amount in cents +std::map dd_utxos; + +// UTXO selection for transfers +std::vector SelectDDCoins(CAmount target) { + // Greedy selection with dust awareness + // Overflow protection + // Change calculation optimization +} +``` + +**Key Innovation**: Solves the challenge of tracking DigiDollar amounts through transfers by maintaining explicit UTXO-to-amount mapping rather than relying on position-based assumptions. + +### 4.3 Address Validation System + +#### **Real-Time Validation** (`/src/qt/digidollarsendwidget.cpp`) +**Status: ✅ Complete Implementation** + +Address validation is integrated directly into the send widget, using `CDigiDollarAddress::IsValidDigiDollarAddress()` from `src/base58.h` to validate DD/TD/RD prefixes and Base58Check format in real-time. + +> **Note**: There is no separate `digidollaraddressvalidator.cpp` file; validation logic resides in `CDigiDollarAddress` and the send widget. + +### 4.4 Transaction Signing + +#### **P2TR Signature Support** (`/src/wallet/digidollarwallet.cpp`) +**Status: ✅ Complete Schnorr Implementation** + +- ✅ Schnorr signatures for DigiDollar P2TR inputs +- ✅ Standard ECDSA signatures for DGB fee inputs +- ✅ Multi-input coordination +- ✅ Key management for DD positions + +**Verification**: The claim that "send/sign/broadcast is complete" is **confirmed accurate** by this analysis. + +--- + +## 5. Receiving System Architecture + +### 5.1 Receive Process Flow + +```mermaid +flowchart TD + A[Generate DD Address] --> B[Display QR Code] + B --> C[Wait for Incoming TX] + C --> D[Detect DD Output] + D --> E[Verify Ownership] + E --> F[Add to UTXO Set] + F --> G[Update Balance] + G --> H[Notify User] + + D --> I[Process Transaction] + I --> J[Extract DD Amount] + J --> K[Validate Script] + K --> F +``` + +### 5.2 Current Implementation Status + +#### **✅ Fully Working Components:** + +1. **Address Generation** (`/src/qt/digidollarreceivewidget.cpp`) + - Complete GUI with QR code generation + - Proper DD address encoding + - Address book integration + - Payment request management + +2. **Incoming Transaction Detection** (`/src/wallet/digidollarwallet.cpp`) + - `DetectIncomingDDOutputs()` scans all transactions + - Automatic processing via `SyncTransaction()` integration + - Proper ownership verification with `IsMine()` + +3. **UTXO Management** + - `AddReceivedDDUTXO()` adds to spendable set + - Database persistence via DD_OUTPUT records + - Balance calculation from UTXO aggregation + +#### **🔄 Minor Gaps Remaining:** + +1. **GUI Balance Notifications** + - Core detection works, but missing `Q_EMIT digidollarBalanceChanged()` signals + - Real-time balance updates in receive widget pending + +2. **Recent Requests Loading** + - Payment requests persist in table model + - `populateRecentRequests()` contains TODO for database loading + +3. **Enhanced Error Handling** + - Basic validation present + - Could benefit from more comprehensive edge case handling + +**Assessment**: Receive-side detection and persistence are wired end-to-end; outstanding items are GUI-side notification polish tracked in the Qt section, not in the protocol layer. + +--- + +## 6. Oracle Integration Surface + +DigiDollar consensus consumes consensus prices from the oracle subsystem; the full oracle architecture (exchange aggregation, MuSig2 ceremony, P2P relay) lives in `DIGIDOLLAR_ORACLE_ARCHITECTURE.md`. This section only catalogs how the protocol layer touches it. + +**Price format.** Micro-USD per DGB (1,000,000 = $1.00). DD amounts are stored in cents (100 = $1.00 USD). Conversions for system health use `priceMillicents = priceMicroUSD / 10` (`src/consensus/dca.cpp:243`). + +**Where DigiDollar reads the price.** +- `src/script/interpreter.cpp` — `OP_CHECKPRICE` is reserved and deterministically disabled. It consumes its operand and pushes false; it does not consult any node-local oracle cache. +- `src/digidollar/validation.cpp` — `ValidateMintTransaction()` requires `ctx.oraclePriceMicroUSD > 0` (rejects with `bad-oracle-price` otherwise) and `ShouldBlockMintingDuringERR()` calls `EmergencyRedemptionRatio::ShouldBlockMinting()` which pulls the oracle price from `MockOracleManager` on regtest and `OracleBundleManager::GetLatestPrice()` elsewhere, failing closed when the price is unavailable. +- `src/validation.cpp:185-283` — Block validation rejects coinbase oracle bundles that fail extraction with `bad-oracle-malformed` once `IsDigiDollarEnabled` is true (the canonical reason for raw v0x01/v0x02 wire payloads, since `ExtractOracleBundle` short-circuits at `src/oracle/bundle_manager.cpp:1065-1069`). The `bad-oracle-legacy` reason is kept as a defense-in-depth gate for hypothetical bundles that parse successfully but report a non-MuSig2 `version`. Mempool acceptance requires a recent valid MuSig2 oracle quote (`HasRecentValidMuSig2OracleQuote`). +- `src/digidollar/health.cpp` — `SystemHealthMonitor` caches the last oracle price (`SystemMetrics::lastOraclePrice`) and feeds DCA/ERR. + +**Mock oracle (regtest only).** `MockOracleManager` (`src/oracle/mock_oracle.cpp`) is a regtest helper used by `setmockoracleprice`/`enablemockoracle`/`simulatepricevolatility` RPCs and by `EmergencyRedemptionRatio::ShouldBlockMinting()` when running on regtest. It is *not* a production fallback for any consensus path; mainnet/testnet `ShouldBlockMinting` consults the real `OracleBundleManager`, while `OP_CHECKPRICE` is reserved and deterministically disabled. + +**Oracle quote requirement at mempool admission.** Mainnet/testnet nodes refuse to admit DigiDollar transactions when no recent valid MuSig2 oracle quote is available (`HasRecentValidMuSig2OracleQuote`, commit `81bf974f40`); reorg-resurrected DD transactions are likewise removed if no quote is available (`src/validation.cpp:601-602`). + +--- + +## 7. Protection Systems Architecture + +### 7.1 Four-Layer Protection Model + +#### **Layer 1: Higher Collateral Ratios** +**Status: ✅ Complete** +- 10-tier system from 1000% (1 hour) to 200% (10 years) +- Provides substantial buffer against price volatility +- Treasury model rewards longer commitments + +#### **Layer 2: Dynamic Collateral Adjustment (DCA)** +Implemented in `/src/consensus/dca.cpp`. + +System health is computed once per snapshot and cached on `SystemHealthMonitor`; DCA always reads the cached value (single source of truth, commit `2de69c94d9`): + +```cpp +// Cached metrics drive DCA. Inputs: +// totalCollateral — DGB satoshis from ScanUTXOSet + OnMint/OnRedeemConnected +// totalDDSupply — DD cents from the same incremental hooks +// oraclePrice — micro-USD per DGB from the consensus price (live MuSig2) +// +// CalculateSystemHealth() returns an int percentage in [0, 30000]; the math +// uses signed __int128 (commit 9cca6970ae) to avoid overflowing on large +// collateral × price products. +int health = DCA::DynamicCollateralAdjustment::CalculateSystemHealth( + totalCollateral, totalDDSupply, oraclePriceMillicents); +``` + +**DCA tiers (HEALTH_TIERS in src/consensus/dca.cpp:53-59):** + +| Health | Multiplier | Basis Points | Status | +|--------|-----------|--------------|--------| +| ≥150% | 1.00x | 10000 | healthy | +| 120–149% | 1.25x | 12500 | warning | +| 110–119% | 1.50x | 15000 | critical | +| <110% | 2.00x | 20000 | emergency | + +`ConsensusParams::dcaLevels` (in `src/consensus/digidollar.h`) carries the same tier values. `ApplyDCA(baseRatio, health)` applies `ceil(baseRatio * multiplierBps / 10000)` and fails closed (returns INT_MAX) when the caller-supplied health is stale relative to the canonical cached value. + +#### **Layer 3: Emergency Redemption Ratio (ERR)** +Implemented in `/src/consensus/err.cpp`. + +**ERR increases DD burn requirement; collateral return is always 100%.** The DGB haircut model was removed (commit `55926c372a`); `GetAdjustedRedemption` is a deprecated identity passthrough kept for ABI compatibility. + +```cpp +// src/consensus/err.cpp ERR_TIERS basis-point table: +// {95, 9500}, {90, 9000}, {85, 8500}, {0, 8000} +// +// Required burn formula (consensus-visible): +// RequiredDD = ceil(originalDDMinted * 10000 / ratioBps) +// Computed with signed __int128 to avoid overflow on large CAmount values +// (commit 55926c372a / 9cca6970ae). +CAmount EmergencyRedemptionRatio::GetRequiredDDBurn(CAmount originalDDMinted, int systemHealth) { + if (originalDDMinted <= 0) return 0; + if (systemHealth >= 100) return originalDDMinted; + int ratioBps = CalculateERRRatioBps(systemHealth); + const __int128 numerator = (__int128)originalDDMinted * 10000; + const __int128 required = (numerator + ratioBps - 1) / ratioBps; // ceil + return required > std::numeric_limits::max() + ? std::numeric_limits::max() + : static_cast(required); +} +``` + +**ERR tiers (DD burn multiplier; collateral return always 100%):** + +| Health | ratioBps | DD Burn (= 10000/ratioBps) | +|--------|----------|----------------------------| +| 95–100% | 9500 | 1.053× | +| 90–95% | 9000 | 1.111× | +| 85–90% | 8500 | 1.176× | +| <85% | 8000 | 1.250× | + +**Mint blocking.** `ShouldBlockMinting(oraclePriceOverride)` blocks new mints whenever ERR is active OR no oracle price is available; it fails closed during oracle outages so health uncertainty cannot allow new DD issuance (commit `8bbbfedf70`). Block validation enforces this independently of the local mempool sync flag (`src/digidollar/validation.cpp:2683-2685`, `ShouldBlockMintingDuringERR` at `3004-3007`). + +**Mint-time burn enforcement.** `ValidateCollateralReleaseAmount()` (`src/digidollar/validation.cpp:2316+`) requires the redeemer to burn at least `requiredDDBurn` and to release the FULL locked collateral; partial-burn releases are rejected as `bad-collateral-release-partial-burn`. Non-DD transactions that try to spend a registered collateral vault are rejected with `bad-collateral-spend-missing-dd-burn` (commit `46cf97e804`). + +#### **Layer 4: Volatility Protection** +**Status: ✅ FULLY IMPLEMENTED AND PRODUCTION-READY** (`/src/consensus/volatility.cpp`) + +```cpp +// DigiDollar::Volatility::VolatilityMonitor (src/consensus/volatility.h) +class VolatilityMonitor { + static bool ShouldFreezeMinting(); // True if 1-hour volatility > 20% + static bool ShouldFreezeAll(); // True if 24-hour volatility > 30% + static bool InCooldownPeriod(); // Post-freeze cooldown (8640 blocks) +}; +``` + +### 7.2 System Health Monitoring + +#### **Health Dashboard** (`/src/digidollar/health.cpp`) +**Status: ✅ Comprehensive Implementation** + +**Monitoring Capabilities:** +- ✅ Real-time system health calculation +- ✅ Per-tier breakdown analysis +- ✅ Alert threshold monitoring +- ✅ Historical health tracking +- ✅ Integration with all protection systems + +**Health Metrics Tracked:** +- Total DGB locked across all positions +- Total DD supply in circulation +- Overall system collateral ratio +- Per-tier health ratios +- Protection system status (DCA/ERR/Volatility) + +### 7.3 Network-Wide Tracking System + +#### **CRITICAL FEATURE: Blockchain-Wide UTXO Scanning** +**Status: ✅ FULLY IMPLEMENTED AND TESTED** (`/src/digidollar/health.cpp:307`) + +This is a **major implementation** that was completely missing from the architecture document. + +**What It Does:** +DigiDollar implements true network-wide tracking by scanning the **entire blockchain UTXO set**, not just individual wallets. This means: +- Every node sees **identical** total DD supply and collateral +- System health is calculated **network-wide**, not per-wallet +- New nodes immediately see full network state +- No wallet needs to be loaded to see system statistics + +**Implementation Details:** + +```cpp +void SystemHealthMonitor::ScanUTXOSet(CCoinsView* view, + CCoinsView* validation_view, + const node::BlockManager* blockman, + const CTxMemPool* mempool) +{ + // Create cursor to iterate ALL UTXOs (similar to gettxoutsetinfo) + std::unique_ptr pcursor(view->Cursor()); + + // Iterate through entire blockchain UTXO set + while (pcursor->Valid()) { + COutPoint key; + Coin coin; + + // Find DigiDollar vault outputs (P2TR with value > 0 at output 0) + if (key.n == 0 && coin.out.scriptPubKey[0] == OP_1 && coin.out.nValue > 0) { + + // Fetch FULL transaction from block storage + CTransactionRef tx = node::GetTransaction(nullptr, mempool, txid, + hashBlock, *blockman); + + // Validate DD mint structure: + // - Output 0: P2TR collateral vault (has DGB value) + // - Output 1: P2TR DD token (value = 0) + // - Output 2: OP_RETURN with exact DD metadata + + // Extract exact DD amount from OP_RETURN + if (DigiDollar::ExtractDDAmount(tx->vout[2].scriptPubKey, ddAmount)) { + s_currentMetrics.totalDDSupply += ddAmount; + s_currentMetrics.totalCollateral += collateral; + } + } + pcursor->Next(); + } +} +``` + +**Key Innovations:** + +1. **Full Transaction Access**: Unlike simple UTXO scans, this implementation fetches **full transaction data** from BlockManager to access OP_RETURN metadata + +2. **Exact Amount Extraction**: Reads precise DD amounts from OP_RETURN (output 2), not estimated from collateral + +3. **Network Consensus**: All nodes scan the same UTXO set → identical results everywhere + +4. **Performance**: Efficient streaming cursor, ~100ms for 1000 vaults, read-only + +**Integration Points:** + +1. **RPC Command**: `getdigidollarstats` calls `ScanUTXOSet()` with chainstate access (full re-scan; expensive). +2. **Incremental hooks**: `OnMintConnected`/`OnRedeemConnected` (`src/digidollar/health.h:222-248`) update `s_currentMetrics` in O(1) under `cs_main` whenever a DD tx is connected during normal block processing; the symmetric `OnMintDisconnected`/`OnRedeemDisconnected` reverse the update on reorg. +3. **Block-level index**: `DigiDollarStatsIndex` (`src/index/digidollarstatsindex.{h,cpp}`) persists per-height totals (`total_dd_supply`, `total_collateral`, `vault_count`) so historical lookups don't require a re-scan. +4. **Qt GUI**: Overview widget displays network totals via RPC. +5. **Protection Systems**: DCA/ERR read the cached `SystemMetrics` (commit `2de69c94d9`) so health comes from one canonical source. + +**Verification:** + +✅ **Functional Test**: `test/functional/digidollar_network_tracking.py` - PASSING +- Creates 2 nodes (Bob and Alice) +- Bob mints DD on node 0 +- **Verifies both nodes see identical network statistics** +- Proves UTXO scanning works across network + +✅ **Documented Proof**: `NETWORK_TRACKING_PROOF.md` +- Complete test output showing identical stats +- Technical implementation details +- Performance characteristics + +**Example Output:** +``` +Bob (node 0) sees: + Total DD Supply: 20043 cents ($200.43) + Total Collateral: 633.00000000 DGB + +Alice (node 1) sees: + Total DD Supply: 20043 cents ($200.43) ← IDENTICAL! + Total Collateral: 633.00000000 DGB ← IDENTICAL! +``` + +**Impact on Architecture:** + +This is a **critical differentiator** from account-based stablecoin systems. Rather than relying on contract state, DigiDollar tracks protocol state through: +- Native UTXO set integration +- Blockchain-wide visibility +- No reliance on external indexers or APIs +- Consensus-compatible read-only queries + +**Files Implementing This Feature:** +- `src/digidollar/health.h` - `ScanUTXOSet()` declaration with validation_view + BlockManager parameters +- `src/digidollar/health.cpp` - Full UTXO scanning implementation with tx data extraction +- `src/rpc/digidollar.cpp` - RPC integration with chainstate access +- `src/qt/digidollaroverviewwidget.cpp` - Qt GUI network statistics display +- `test/functional/digidollar_network_tracking.py` - Comprehensive verification test + +**Status**: ✅ **Production-Ready** - Fully implemented, tested, and documented + +--- + +## 8. GUI Implementation Architecture + +### 8.1 Complete GUI Overview + +The DigiDollar GUI implementation is **90% complete** with all major widgets functional and integrated. + +#### **DigiDollar Tab Structure** (`/src/qt/digidollartab.cpp`) +**Status: ✅ Complete Implementation** + +```cpp +class DigiDollarTab : public QWidget { + // 7 main sub-widgets, all functional: + DigiDollarOverviewWidget* m_overviewWidget; + DigiDollarReceiveWidget* m_receiveWidget; + DigiDollarSendWidget* m_sendWidget; + DigiDollarMintWidget* m_mintWidget; + DigiDollarRedeemWidget* m_redeemWidget; + DigiDollarPositionsWidget* m_positionsWidget; // Vault/Positions Manager + DigiDollarTransactionsWidget* m_transactionsWidget; // Transaction History +}; +``` + +### 8.2 Widget Implementation Status + +#### **1. Overview Widget** (`/src/qt/digidollaroverviewwidget.cpp`) +**Status: ✅ 95% Complete** +- ✅ Total DD balance display +- ✅ DGB locked collateral tracking +- ✅ Current oracle price display from the live consensus/MuSig2 price source +- ✅ System health indicators (network-wide UTXO scanning) +- ✅ Recent transaction summary +- 🔄 Real-time balance updates (minor notification gap) + +#### **2. Send Widget** (`/src/qt/digidollarsendwidget.cpp`) +**Status: ✅ 100% Complete** +- ✅ DD address validation (DD/TD/RD prefixes) +- ✅ Amount input with balance checking +- ✅ Fee estimation and preview +- ✅ Transaction confirmation and broadcasting +- ✅ Backend integration with WalletModel + +#### **3. Receive Widget** (`/src/qt/digidollarreceivewidget.cpp`) +**Status: ✅ 95% Complete** +- ✅ DD address generation +- ✅ QR code creation +- ✅ Address book integration +- ✅ Payment request management +- 🔄 Recent requests loading from database (minor gap) + +#### **4. Mint Widget** (`/src/qt/digidollarmintwidget.cpp`) +**Status: ✅ 90% Complete** +- ✅ Lock period selection (10 tiers) +- ✅ Real-time collateral calculator +- ✅ Oracle price display from the live consensus/MuSig2 price source +- ✅ Mint confirmation and execution +- ✅ Uses live oracle pricing on mainnet/testnet; `setmockoracleprice` is a regtest-only helper + +#### **5. Redeem Widget** (`/src/qt/digidollarredeemwidget.cpp`) +**Status: ✅ 85% Complete** +- ✅ Position selection interface +- ✅ Redemption paths (Normal and ERR - both require timelock expiry) +- ✅ Required DD calculation display +- ✅ Time remaining indicators +- ✅ Full normal and ERR redemption validation; both paths require timelock expiry + +#### **6. Vault Manager Widget** (`/src/qt/digidollarpositionswidget.cpp`) +**Status: ✅ 90% Complete** +- ✅ Comprehensive vault table display +- ✅ Health status indicators +- ✅ Sortable columns and context menus +- ✅ Position management interface +- 🔄 Real-time health updates (depends on oracle) + +### 8.3 GUI Integration Quality + +**Strengths:** +- ✅ Professional Qt implementation following DigiByte design standards +- ✅ Proper MVC architecture with signal/slot connections +- ✅ Real-time validation and user feedback +- ✅ Theme-aware styling and responsive design +- ✅ Comprehensive error handling and progress indicators + +**Minor Gaps:** +- 🔄 Some real-time notifications depend on oracle system completion +- 🔄 Database loading for recent requests needs completion +- 🔄 Advanced error scenarios could use better user messaging + +--- + +## 8.5 HD Key Derivation for DigiDollar + +### 8.5.1 Overview + +DigiDollar uses HD (Hierarchical Deterministic) key derivation from the wallet's seed for all DigiDollar operations. This enables wallet restore via descriptors. + +**Implementation Location**: `src/wallet/wallet.cpp:2741-2836` (`CWallet::GetHDKeyForDigiDollar`). Callers: `src/rpc/digidollar.cpp:1439` (`mintdigidollar` RPC), `src/rpc/digidollar.cpp:2845` (`getdigidollaraddress` RPC), `src/qt/walletmodel.cpp:892` (Qt mint flow). + +### 8.5.2 GetHDKeyForDigiDollar() Function + +```cpp +CKey CWallet::GetHDKeyForDigiDollar(const std::string& label) +{ + // Returns an empty/invalid CKey if: + // - WALLET_FLAG_DISABLE_PRIVATE_KEYS is set, or + // - the wallet has no HD seed / no available keypool, or + // - extraction from the produced destination fails. + // Otherwise tries BECH32M (Taproot) first, falls back to BECH32. + // Uses GetSigningProviderWithKeys() for private-key access + // (NOT GetSolvingProvider()). + // Labels used: "dd-owner", "dd-address". +} +``` + +**Key Design Decisions:** +- **Uses `GetSigningProviderWithKeys()`**: critical for Taproot — `GetSolvingProvider()` returns keys without private-key access, causing signing failures. +- **No random-key or legacy-wallet fallback in V1.** Earlier revisions of this section described a `MakeNewKey(true)` fallback for legacy wallets; current code rejects non-descriptor wallets before any legacy key extraction (`src/wallet/wallet.cpp:2757-2759`). On any failure path the helper returns an invalid `CKey` and the calling RPC throws `RPC_WALLET_ERROR "DigiDollar mint requires a descriptor/bech32m HD wallet with private keys enabled"` (`src/rpc/digidollar.cpp:1441`). The Qt mint flow surfaces the same error to the user (`src/qt/walletmodel.cpp:894-896`). DigiDollar mint therefore requires a descriptor/bech32m HD wallet with private keys; non-HD/legacy/private-keys-disabled wallets fail clearly without minting. +- **Database persistence**: keys stored via `StoreOwnerKey()` and `StoreAddressKey()` *before* the mint transaction is broadcast (commit `1e95478b7e`), so a crash between broadcast and persistence cannot lose the owner key. + +### 8.5.3 Usage in DigiDollar Operations + +| Operation | Label | Called From | +|-----------|-------|-------------| +| Mint DigiDollars | `"dd-owner"` | `mintdigidollar` RPC (`src/rpc/digidollar.cpp:1439`) and Qt mint (`src/qt/walletmodel.cpp:892`) | +| Generate DD Address | `"dd-address"` | `getdigidollaraddress` RPC (`src/rpc/digidollar.cpp:2845`) | + +**Note**: `redeemdigidollar` RPC does not call `GetHDKeyForDigiDollar()` — it uses stored owner keys from the position database. The label `"dd-redeem"` is NOT used anywhere in the codebase; only `"dd-owner"` and `"dd-address"` are used. + +### 8.5.4 Wallet Restore Implications + +Because DD keys are derived from the wallet seed (when using descriptor wallets): +- Keys can be regenerated from descriptors +- `listdescriptors true` exports HD seed +- `importdescriptors` + `rescanblockchain` restores positions +- Legacy / non-HD / private-keys-disabled wallets cannot mint at all (mint RPC and Qt mint both throw immediately); there is no V1 fallback that produces an unrecoverable random key + +--- + +## 8.6 Position Reconstruction During Rescan + +### 8.6.1 Overview + +When a wallet is restored via descriptors and rescanned, DD positions must be reconstructed from blockchain data. + +**Implementation Location**: `src/wallet/digidollarwallet.cpp` (~line 1920) + +### 8.6.2 ProcessDDTxForRescan() Function + +Called from `SyncTransaction()` in `wallet.cpp` when `rescanning_old_block=true`: + +```cpp +void DigiDollarWallet::ProcessDDTxForRescan( + const CTransactionRef& ptx, + int block_height) +{ + // Handles MINT (type=1) and REDEEM (type=3) transactions + // Reconstructs positions from OP_RETURN metadata +} +``` + +### 8.6.3 Ownership Detection (Critical Design Decision) + +**Problem**: Standard `IsMine(vout[0])` fails for DigiDollar MAST scripts because the wallet doesn't recognize complex Taproot scripts as its own. + +**Solution**: Detect ownership via **input inspection**: + +```cpp +// Check if any input belongs to this wallet +bool is_our_mint = false; +for (const CTxIn& txin : tx.vin) { + auto it = m_wallet->mapWallet.find(txin.prevout.hash); + if (it != m_wallet->mapWallet.end()) { + if (m_wallet->IsMine(it->second.tx->vout[txin.prevout.n]) != wallet::ISMINE_NO) { + is_our_mint = true; + break; + } + } +} +``` + +**Why this works**: If the wallet owns the inputs to a mint transaction, it must own the resulting position. + +### 8.6.4 Position Data Extraction + +All position data is extracted from on-chain OP_RETURN metadata: +- **`dd_minted`**: From OP_RETURN +- **`dgb_collateral`**: From `vout[0].nValue` +- **`unlock_height`**: From OP_RETURN +- **`lock_tier`**: Extracted from explicit mint OP_RETURN metadata via `ExtractTierFromOpReturn()` (required) +- **`dd_timelock_id`**: Transaction hash +- **`is_active`**: Check if vault UTXO is spent + +### 8.6.5 Explicit Tier Extraction + +**Implementation**: `ExtractTierFromOpReturn()` in `src/wallet/digidollarwallet.cpp` + +```cpp +// vout[2]: OP_RETURN ("DD" | txType=1 | dd_minted | unlock_height | lock_tier) +if (!ExtractTierFromOpReturn(tx, lock_tier)) { + return false; // Old/no-tier mint formats unsupported for V1 +} +``` + +**Note**: `DeriveLockTierFromHeight()` remains in wallet code only as a deprecated diagnostic helper. V1 position reconstruction does not use a height-derived fallback: old/no-tier mint formats are unsupported, and live restore requires `lock_tier` in OP_RETURN so all ten canonical tiers, including the 2-year tier, remain unambiguous. + +--- + +## 8.7 Wallet Restore Workflow + +### 8.7.1 Complete Restore Process + +``` +┌──────────────────────────────────────────────────────────────┐ +│ WALLET RESTORE WORKFLOW │ +└──────────────────────────────────────────────────────────────┘ + +1. EXPORT FROM ORIGINAL WALLET +═══════════════════════════════ + $ digibyte-cli listdescriptors true + Returns: { + "descriptors": [ + {"desc": "tr([fingerprint/86'/20'/0']xprv.../0/*)", ...}, + ... + ] + } + +2. CREATE NEW WALLET & IMPORT +═══════════════════════════════ + $ digibyte-cli createwallet "restored" false false "" false true + $ digibyte-cli -rpcwallet=restored importdescriptors '[...]' + +3. RESCAN BLOCKCHAIN +═══════════════════════════════ + $ digibyte-cli -rpcwallet=restored rescanblockchain + + During rescan, for each block: + └─► SyncTransaction() called + └─► if (rescanning_old_block) + └─► ProcessDDTxForRescan() + └─► Extract position from OP_RETURN + └─► Check ownership via inputs + └─► Rebuild collateral_positions map + └─► Restore dd_utxos map + +4. VERIFICATION +═══════════════════════════════ + $ digibyte-cli -rpcwallet=restored listdigidollarpositions + $ digibyte-cli -rpcwallet=restored getdigidollarbalance +``` + +### 8.7.2 What Gets Restored + +| Data | Stored In | Restoration Method | +|------|-----------|-------------------| +| HD Keys | Descriptors | Imported directly | +| DGB UTXOs | Blockchain | Standard rescan | +| DD Positions | Blockchain OP_RETURN | `ProcessDDTxForRescan()` | +| DD UTXOs | Blockchain | `ProcessDDTxForRescan()` | +| Address Labels | Descriptors | Imported directly | + +### 8.7.3 What Is NOT Exported in Descriptors + +These maps are **rebuilt during rescan**, not exported: +- `dd_owner_keys` - Rebuilt from HD derivation +- `dd_utxos` - Rebuilt from blockchain scan +- `dd_address_keys` - Rebuilt from HD derivation +- `collateral_positions` - Rebuilt from OP_RETURN data + +### 8.7.4 Test File + +**Location**: `test/functional/wallet_digidollar_restore.py` + +Tests the complete workflow: +1. Create wallet, mint DD positions +2. Export descriptors +3. Create new wallet, import descriptors +4. Rescan blockchain +5. Verify positions and balances match + +--- + +## 9. Database and Persistence Architecture + +### 9.1 Database Schema Implementation + +#### **DigiDollar-Specific Tables** (`/src/wallet/walletdb.cpp`) +**Status: ✅ 100% Complete** (tested via wallet_digidollar_persistence_restart.py) + +```cpp +// Core data structures with wallet.dat integration +// Database keys (string-based, in walletdb.cpp DBKeys namespace): +// "ddutxo" (DD_OUTPUT) - UTXO tracking +// "ddbalance" (DD_BALANCE) - Address-based balances +// "ddposition" (DD_POSITION) - Collateral positions +// "ddtx" (DD_TRANSACTION) - Transaction history +``` + +#### **Persistence Implementation** + +**✅ Working Components:** +1. **DD Output Tracking**: UTXOs with amounts persist across restarts +2. **Position Storage**: Collateral positions save to wallet.dat +3. **Address Book**: DD addresses integrate with existing address book +4. **Transaction History**: Basic DD transaction tracking + +**🔄 Gaps Remaining:** +1. **Recent Requests Loading**: `populateRecentRequests()` needs database integration +2. **Full Transaction Metadata**: Some transaction details load simplified +3. **Migration Logic**: Wallet upgrade handling for DD data could be enhanced + +### 9.2 UTXO Management Database + +#### **DD UTXO Tracking** (`/src/wallet/digidollarwallet.cpp`) +**Status: ✅ Advanced Implementation** + +```cpp +// Primary UTXO tracking map +std::map dd_utxos; + +// Database operations (integrated into wallet infrastructure) +void AddDDUTXO(const COutPoint& outpoint, CAmount dd_amount); // ✅ Working +void RemoveDDUTXO(const COutPoint& outpoint); // ✅ Working +size_t LoadFromDatabase(); // ✅ Working - loads all DD data including UTXOs +``` + +**Key Features:** +- ✅ Persistent UTXO tracking across wallet restarts +- ✅ Efficient lookup for balance calculations +- ✅ Integration with coin selection algorithms +- ✅ Automatic cleanup of spent UTXOs + +--- + +## 10. RPC Interface Architecture + +### 10.1 Complete Command Implementation + +#### **35 Total RPC Commands (18 Node-Context + 17 Wallet-Context)** (`/src/rpc/digidollar.cpp` + `/src/wallet/rpc/wallet.cpp`) +**Status: ✅ 90% Complete** + +**All RPC Commands defined in `/src/rpc/digidollar.cpp` (18 registered directly, others via wallet-layer):** + +| Category | Command | Status | Notes | +|----------|---------|--------|-------| +| **System Health** | `getdigidollarstats` | ✅ Complete | Network-wide UTXO scanning + system health | +| | `getdcamultiplier` | ✅ Complete | DCA multiplier calculations | +| | `getdigidollardeploymentinfo` | ✅ Complete | BIP9 deployment activation info | +| | `getprotectionstatus` | ✅ Complete | DCA/ERR/volatility status | +| **Collateral** | `calculatecollateralrequirement` | ✅ Complete | Real-time collateral calculation | +| | `estimatecollateral` | ✅ Complete | Quick collateral estimation | +| | `getredemptioninfo` | ✅ Complete | Redemption requirements | +| **Addresses** | `validateddaddress` | ✅ Complete | DD/TD/RD address validation | +| | `listdigidollaraddresses` | ✅ Complete | List all DD addresses | +| | `importdigidollaraddress` | ⚠️ V1 unsupported stub | Validates DD address only; returns a no-op warning and does not mutate wallet state | +| **Oracle System** | `getoracleprice` | ✅ Complete | Returns the live consensus/MuSig2 oracle price on mainnet/testnet; regtest may use mock helpers | +| | `getalloracleprices` | ✅ Complete | Returns all oracle price data | +| | `sendoracleprice` | ❌ Removed | Removed — security vulnerability (fake price injection) | +| | `getoracles` | ✅ Complete | Shows configured oracle nodes | +| | `getoraclesigners` | ✅ Complete | Lists oracle signers for a block (not activation-gated) | +| | `listoracle` | ✅ Complete | List oracle details | +| | `stoporacle` | ✅ Complete | Stop local oracle participant | +| | `getoraclepubkey` | ✅ Complete | Get oracle public key by ID | +| | `submitoracleprice` | ❌ Not present | Never implemented — no string match in `src/rpc` or `src/wallet/rpc`; oracle prices come from live exchange aggregation only | +| **Mock Oracle** | `setmockoracleprice` | ✅ Complete | Set test price (RegTest only) | +| | `getmockoracleprice` | ✅ Complete | Get current mock price | +| | `simulatepricevolatility` | ✅ Complete | Test volatility protection | +| | `enablemockoracle` | ✅ Complete | Enable/disable mock oracle | + +**Wallet-Layer Commands (17 in `/src/wallet/rpc/wallet.cpp`, require wallet context):** + +| Command | Status | Notes | +|---------|--------|-------| +| `mintdigidollar` | ✅ Complete | Create DD by locking DGB collateral | +| `senddigidollar` | ✅ Complete | Transfer DD to another address | +| `sendmanydigidollar` | ✅ Complete | Transfer DD to multiple addresses in one transaction | +| `redeemdigidollar` | ✅ Complete | Burn DD to unlock DGB collateral | +| `getdigidollaraddress` | ✅ Complete | Generate new DD address | +| `getdigidollarbalance` | ✅ Complete | Get total DD balance | +| `listdigidollarpositions` | ✅ Complete | List all collateral positions | +| `listdigidollaraddresses` | ✅ Complete | List all DD addresses in wallet | +| `getredemptioninfo` | ✅ Complete | Redemption details for a position | +| `listdigidollartxs` | ✅ Complete | List DD transaction history | +| `listdigidollarunspent` | ✅ Complete | List spendable DD UTXOs for coin control | +| `listdigidollarutxos` | ✅ Complete | Alias for DD UTXO listing | +| `validateddaddress` | ✅ Complete | Validate DD address format | +| `createoraclekey` | ✅ Complete | Generate oracle signing key pair | +| `exportoracleprivkey` | ✅ Complete | Export wallet-stored oracle private key for backup/migration | +| `importoracleprivkey` | ✅ Complete | Import wallet-stored oracle private key for recovery/migration | +| `startoracle` | ✅ Complete | Start local oracle participant from wallet key | + +**Important Notes:** +- All wallet commands are fully functional through the Qt GUI +- Oracle system uses mock prices for deterministic regtest tests; mainnet/testnet operators use live exchange aggregation and MuSig2 v0x03 bundles +- Regtest mock price defaults to $0.0065 per DGB = 6500 micro-USD and can be changed with `setmockoracleprice` +- Production oracle validation does not fall back to mock prices or legacy bundle formats + +### 10.2 RPC Implementation Quality + +**Strengths:** +- ✅ Complete parameter validation and error handling +- ✅ JSON-RPC compliance with proper response formatting +- ✅ Integration with existing Bitcoin Core RPC infrastructure +- ✅ Comprehensive help documentation for all commands +- ✅ Security considerations with access control + +**Current Limitations:** +- ✅ Oracle commands use deterministic mock prices on regtest only; mainnet/testnet use live libcurl exchange aggregation when `HAVE_LIBCURL` is defined +- ✅ Oracle daemon commands operate on wallet-managed oracle keys and live P2P/MuSig2 messages +- ✅ All system health and monitoring commands fully functional + +--- + +## 11. Detailed DigiDollar Process Flows + +### 11.1 Detailed Minting Process Flow + +``` + ┌─────────────────────────────────────┐ + │ USER WANTS TO MINT DD │ + │ (Lock DGB, Get DigiDollars) │ + └─────────────────┬───────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ UI: CHOOSE PARAMETERS │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. Lock Period (10 tiers): 1h→10y (1000%→200% collateral) │ + │ 2. DD Amount: $100 - $100,000 range │ + │ 3. Real-time collateral calculator shows required DGB │ + │ CODE: /src/qt/digidollarmintwidget.cpp │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ SAFETY CHECKS & VALIDATION │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. Volatility Check: VolatilityMonitor::ShouldFreezeMinting │ + │ → If 20%+ price swing in 1hr = REJECT MINT │ +│ 2. Oracle Price: Get current DGB/USD from oracles │ +│ → Live consensus/MuSig2 price; regtest may use mock │ + │ 3. System Health: DCA multiplier (1.0x - 2.0x) │ + │ 4. Balance Check: Ensure sufficient DGB available │ + │ CODE: /src/digidollar/validation.cpp │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ COLLATERAL CALCULATION ENGINE │ + ├─────────────────────────────────────────────────────────────┤ + │ Required DGB = (dd_cents × COIN × ratio_percent × dca_bps) │ + │ / (oracle_micro_usd × 100) │ + │ │ +│ Example: $10 DD, 1yr lock, healthy system, 6500 µUSD/DGB: │ +│ Required = (1000¢ × COIN × 300 × 10000)/(6500 × 100) │ +│ ≈ 4615.38 DGB │ + │ │ + │ CODE: /src/digidollar/txbuilder.cpp - MintTxBuilder │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ BUILD MINT TRANSACTION │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. Select DGB UTXOs (greedy algorithm for collateral+fees) │ + │ 2. Create vout[0]: Collateral vault (P2TR with timelock) │ + │ • 2 redemption paths: Normal and ERR extra-burn paths │ + │ • CLTV timelock for lock period enforcement │ + │ • CreateCollateralScript() - P2TR with timelock │ + │ 3. Create vout[1]: DD token (SIMPLE P2TR, key-path only) │ + │ • NO MAST, NO CLTV - freely transferable │ + │ • CreateDDOutputScript() - just Taproot tweak │ + │ • Witness when spending: [64-byte signature] only │ + │ 4. Create vout[2]: OP_RETURN metadata (tx type + amounts) │ + │ 5. Calculate fees and create change outputs │ + │ CODE: /src/digidollar/txbuilder.cpp lines 344-370 │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ SIGN & BROADCAST TRANSACTION │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. Sign all DGB inputs with ECDSA signatures │ + │ 2. Verify transaction structure and collateral compliance │ + │ 3. Submit to mempool via wallet.chain().broadcastTransaction│ + │ 4. Create WalletCollateralPosition database record │ + │ 5. Add DD UTXO as pending; consensus spends require │ + │ confirmed DD inputs │ + │ 6. Update GUI with new vault and DD balance │ + │ CODE: /src/wallet/digidollarwallet.cpp - MintDigiDollar │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ ✅ MINT COMPLETE │ + │ • DGB locked in time-locked vault (NO early exit possible) │ + │ • DigiDollars available for spending immediately │ + │ • Vault position tracked in database with health monitoring│ + │ • User can view in "Vault Manager" tab │ + └─────────────────────────────────────────────────────────────┘ +``` + +### 11.2 Detailed Sending/Signing Process Flow + +``` + ┌─────────────────────────────────────┐ + │ USER WANTS TO SEND DD │ + │ (Transfer DigiDollars to Someone) │ + └─────────────────┬───────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ UI: ENTER SEND DETAILS │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. Recipient DD Address: Real-time validation (DD/TD/RD) │ + │ 2. Amount: Min $1.00, real-time balance checking │ + │ 3. Review: Address confirmation, fee estimation │ + │ 4. Base58Check validation & P2TR structure verification │ + │ CODE: /src/qt/digidollarsendwidget.cpp │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ SMART UTXO SELECTION ENGINE │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. DD UTXO Scan: Query dd_utxos map (COutPoint → CAmount) │ + │ → Filter spendable, sort by amount for efficiency │ + │ 2. DD Selection: Greedy algorithm until target reached │ + │ → Example: Send $5, have [$10, $3, $2] → Select $10 │ + │ → Calculate change: $10 - $5 = $5 DD change │ + │ 3. Fee UTXO Selection: Standard wallet coin selection │ + │ → Estimate fee, select DGB UTXOs for payment │ + │ CODE: /src/wallet/digidollarwallet.cpp - SelectDDCoins │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ BUILD TRANSFER TRANSACTION │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. Transaction Version: 0x02000770 (DD_TX_TRANSFER) │ + │ 2. Add Inputs: DD UTXOs + DGB fee UTXOs │ + │ 3. Create Outputs: │ + │ • Recipient DD Output (P2TR, 0 DGB, DD in metadata) │ + │ • DD Change Output (if needed, to sender's new address) │ + │ • DGB Fee Change (if DGB UTXOs > actual fee) │ + │ 4. DD Conservation Check: Total DD In = Total DD Out │ + │ CODE: /src/digidollar/txbuilder.cpp - TransferTxBuilder │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ 🔑 TAPROOT SIGNING: KEY-PATH vs SCRIPT-PATH (Critical) │ + ├─────────────────────────────────────────────────────────────┤ + │ ⚠️ Transfer transactions set LOCKTIME = 0 (no timelock) │ + │ │ + │ SIGNING PROCESS (SignDDInputs, ~line 5098): │ + │ │ + │ 1. Sign DGB Fee Inputs FIRST: │ + │ → wallet's SignTransaction() creates ECDSA signatures │ + │ → (Taproot sighash includes witness data of other inputs)│ + │ │ + │ 2. For EACH DD Input - Check Output Index (outpoint.n): │ + │ │ + │ IF outpoint.n == 1 (DD token output): │ + │ ✅ USE KEY-PATH SIGNING: │ + │ • DD tokens are simple P2TR (no MAST tree) │ + │ • Tweak key with EMPTY merkle root │ + │ • Sign with Schnorr signature │ + │ • Witness stack: [64-byte signature] (key-path) │ + │ • This is the standard transfer case! │ + │ │ + │ ELSE (outpoint.n == 0, collateral vault): │ + │ 🔒 COLLATERAL REDEMPTION: │ + │ • Collateral uses P2TR with timelock │ + │ • 2 paths: Normal or ERR extra-DD-burn redemption │ + │ • Must wait for timelock to expire │ + │ • Sign with Taproot script-path witness │ + │ • Only used during redemption, not transfers! │ + │ │ + │ 3. Validate: Check signatures, amounts, DD conservation │ + │ │ + │ KEY INSIGHT: Transfer txs spend vout[1] (DD tokens) using │ + │ simple key-path signing. Only redemptions spend vout[0] │ + │ (collateral) which requires complex script-path signing. │ + │ │ + │ CODE: /src/wallet/digidollarwallet.cpp - SignDDInputs │ + │ ~Line 5098+ contains the vout index check logic │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ BROADCAST & UPDATE DATABASE │ + ├─────────────────────────────────────────────────────────────┤ + │ 1. Network Broadcast: │ + │ → wallet.chain().broadcastTransaction() to mempool │ + │ → Relay to network peers automatically │ + │ 2. UTXO Database Updates (CRITICAL): │ + │ → Remove spent DD UTXOs from dd_utxos map │ + │ → Add new DD UTXOs (change, self-transfers) │ + │ → NEVER touch collateral positions (they stay locked!) │ + │ 3. Transaction History & Balance Updates │ + │ CODE: /src/wallet/digidollarwallet.cpp - TransferDigiDollar │ + └─────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ ✅ TRANSFER COMPLETE │ + │ • DigiDollars sent to recipient's address │ + │ • Change DigiDollars returned to sender's new address │ + │ • All collateral vaults remain locked and untouched │ + │ • Transaction appears in both wallets' history │ + │ • Network propagation ensures global consistency │ + └─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 12. Integration Points and Dependencies + +### 12.1 External Dependencies + +#### **Oracle Price Integration** +- **Current**: 6 active exchange API fetchers (libcurl). `MockOracleManager` is a regtest helper for test scenarios; `OP_CHECKPRICE` is reserved and deterministically disabled, so no production script path can read mock or live node-local prices. +- **Exchange APIs**: Binance, KuCoin, Gate.io, HTX (Huobi), Crypto.com, CoinGecko (Coinbase, Kraken, CoinMarketCap removed: DGB not tradeable / paid-key incompatible with decentralized design) +- **Status**: ✅ Real API implementation exists (conditional on HAVE_LIBCURL); regtest mock available for scripted tests +- **Remaining**: Mainnet oracle operator deployment and end-to-end testnet verification + +#### **P2P Network Integration** +- **Current**: Uses standard Bitcoin Core transaction relay + Oracle P2P protocol +- **Status**: ✅ Working for transaction propagation and oracle message relay +- **Oracle P2P**: BroadcastMessage() sends oracle prices to all peers via ORACLEPRICE msg type +- **Message Types**: MSG_ORACLE_PRICE, MSG_ORACLE_BUNDLE, MSG_ORACLE_CONSENSUS, MSG_ORACLE_ATTESTATION + +#### **UTXO Database Integration** +- **Current**: ScanUTXOSet provides full blockchain UTXO scanning; incremental tracking via OnMintConnected/OnRedeemConnected +- **Status**: ✅ Production-ready - network-wide tracking verified across multi-node tests +- **Implementation**: `src/digidollar/health.cpp` (ScanUTXOSet) + `src/index/digidollarstatsindex.cpp` (block-level index) + +### 12.2 Internal Integration Points + +#### **Consensus Layer Integration** +- **Status**: ✅ Complete integration with DigiByte consensus rules +- **Features**: Soft fork activation, block validation, transaction validation +- **Quality**: Production-ready with comprehensive error handling + +#### **Wallet Integration** +- **Status**: ✅ 90% complete with minor notification gaps +- **Features**: UTXO management, key handling, transaction creation +- **Quality**: Well-integrated with existing Bitcoin Core wallet infrastructure + +#### **GUI Integration** +- **Status**: ✅ 90% complete with professional implementation +- **Features**: All 7 widgets functional, theme integration, real-time updates +- **Quality**: Follows Qt best practices and DigiByte design standards + +--- + +## 13. Code Quality Assessment + +### 13.1 Strengths + +**Architecture and Design:** +- ✅ **Sophisticated UTXO Management**: Advanced tracking system for DigiDollar amounts +- ✅ **Proper Taproot Integration**: Complete P2TR implementation with MAST support +- ✅ **Overflow Protection**: Consistent use of 64-bit arithmetic for financial calculations +- ✅ **Error Handling**: Comprehensive validation and error reporting throughout +- ✅ **Separation of Concerns**: Well-layered architecture with clear component boundaries + +**Implementation Quality:** +- ✅ **Bitcoin Core Compliance**: Follows Bitcoin Core coding standards and patterns +- ✅ **Test Coverage**: Extensive DD/oracle unit, Qt, functional, and fuzz coverage; the current runner registers 80 DD/oracle/wallet functional entries and the Wave 23 all-target fuzz gate enumerates 247 registered fuzz targets +- ✅ **Documentation**: Well-documented code with clear intent and usage examples +- ✅ **Security Awareness**: Proper input validation, overflow protection, and access control + +**Integration Quality:** +- ✅ **GUI Implementation**: Professional Qt implementation with proper MVC patterns +- ✅ **RPC Interface**: Complete command set with proper parameter validation +- ✅ **Database Integration**: Robust persistence layer using Bitcoin Core patterns + +### 13.2 Areas for Improvement + +**Production Readiness:** +- 🔄 **Oracle Operations**: Mainnet/testnet consensus parameters are wired; operator rollout and monitoring remain operational work. +- ✅ **UTXO Scanning**: Production-ready UTXO set scanning implemented (ScanUTXOSet + incremental tracking) +- ✅ **Collateral Witness Path**: Wallet/RPC redemption signs collateral through the Taproot script path; DD token transfers remain key-path only. + +**Performance Optimization:** +- 🔄 **Coin Selection**: Implement more sophisticated UTXO selection algorithms +- ✅ **Caching**: Oracle quote and health/state caches are wired; future work is bounded-memory and telemetry tuning. +- 🔄 **Database Indexing**: Optimize database queries for large UTXO sets + +**Feature Completion:** +- 🔄 **GUI Notifications**: Complete real-time balance update notifications +- ✅ **P2P Oracle Relay**: Oracle message broadcasting implemented (BroadcastMessage via ORACLEPRICE msg) +- 🔄 **Witness Diagnostics**: Standard Taproot script validation enforces the spend; explicit DD-aware witness-shape diagnostics could still be expanded. + +--- + +## 14. V1 Hardening Notes + +The V1 branch (`feature/digidollar-v1`) closed a series of consensus and policy gaps that materially affect protocol behavior. Listed in approximate code order, with the commit hash for traceability. + +| Area | Behavior | Reference | +|------|----------|-----------| +| OP_CHECKPRICE | Reserved and deterministically disabled; consumes one operand and pushes false. It does not read live oracle state or production mock state. | `b9ddae031e` / `3668971ab2` (`src/script/interpreter.cpp:708-735`) | +| MuSig2 V1 only | Coinbase oracle bundles in DigiDollar-active blocks must carry the V1 MuSig2 v0x03 format. Raw v0x01/v0x02 OP_RETURN payloads fail extraction (`src/oracle/bundle_manager.cpp:1065-1069`) and surface as `bad-oracle-malformed`; the `bad-oracle-legacy` branch is kept as defense-in-depth for bundles that parse but report a non-MuSig2 version. Mempool acceptance requires a recent valid MuSig2 quote. | `f2bb0a19a4`, `bbb85cf363` (`src/validation.cpp:185-283`) | +| Mainnet/testnet validator parity | The mainnet oracle-validation short-circuit was removed; both networks honor the same V1 oracle-bundle gates. | `f0d9a7b2c7` | +| DCA / health overflow | DCA and health math use signed `__int128` throughout to prevent collateral × price overflow. | `9cca6970ae` | +| ERR burn math | Required burn = `ceil(originalDD * 10000 / ratioBps)` in `__int128`; `GetAdjustedRedemption` is a deprecated identity passthrough. | `55926c372a` | +| Collateral spend rule | Non-DD spends of registered collateral vaults are rejected as `bad-collateral-spend-missing-dd-burn`. | `46cf97e804` | +| Confirmed-only DD chaining | Consensus refuses DD inputs at `MEMPOOL_HEIGHT` for transfers and redeems. | `0b4959f563` | +| Pre-mutation volatility check | `WouldCandidateFreezeMinting()` runs before any mutation so a rejected mint cannot poison volatility history. | `03f4af47a7` | +| Missing system health fail-closed | Mint validation requires deterministic system health and rejects with `bad-system-health` otherwise. | `8bbbfedf70` (`src/digidollar/validation.cpp:1581-1584`) | +| Mempool oracle quote | DD mempool acceptance requires a recent valid MuSig2 oracle quote; without one, DD txs are rejected and reorg-resurrected DD txs are removed. | `81bf974f40` | +| Mining graceful degradation | DD txs failing validation are skipped during package selection and price-dependent DD txs are removed before retrying block validity when no valid oracle bundle is ready. | `6b5ff516c3` (`src/node/miner.cpp:523-538, 561-584, 849-864`) | +| Lock tier canonical window | Custom/under-locked durations are rejected; mint OP_RETURN must record the canonical tier and the remaining lock blocks must be in `[tier_blocks, tier_blocks + 100]`. | `e1dd69f99b`, `11728a6980` (`src/digidollar/validation.cpp:1342-1397, 1603-1611`) | +| DD supply alert (not a cap) | `AlertThresholds::ALERT_DD_SUPPLY = 100M DD` is a monitoring threshold, not a hard cap; `MAX_DIGIDOLLAR` is a per-output serialization bound. | `99b1f79480` (`src/digidollar/health.h:83`) | +| Coinbase price-cache poisoning | Coinbase oracle-price extraction is gated on `DEPLOYMENT_DIGIDOLLAR`, and global `UpdatePriceCache` mutation is deferred until after block checks succeed, so a coinbase OP_ORACLE cannot poison the price cache pre-activation or from an invalid block. | rh61 (`src/validation.cpp:3077-3099, 3373-3380`) | +| Single source of system health | DCA/ERR consume `SystemHealthMonitor::GetCachedMetrics()`; stale callers fail closed in `ApplyDCA`. | `2de69c94d9` | + +## 15. Known Open Items + +- **Mainnet oracle infrastructure rollout** — The 35 active oracle slots (mainnet/testnet) require operator deployment; consensus is wired and tested. +- **Supplemental witness diagnostics** — Collateral outputs use a NUMS internal key and wallet/RPC redemption signs via Taproot script path today. `ValidateScriptPathSpending()` is only a supplemental DD helper that logs/returns true; standard Taproot validation plus NUMS output reconstruction carry consensus enforcement. +- **GUI notification polish** — Real-time balance signals and recent-requests persistence are tracked outside this protocol document. + +AUDIT NOTE (2026-05-20): Do not describe `ValidateScriptPathSpending()` as the consensus witness validator. The code constructs collateral with a NUMS internal key, reconstructs the expected 2-leaf MAST output during mint validation, and spends collateral through Taproot script path in wallet/RPC redemption; the helper remains a structural hook for future DD-specific diagnostics. + +--- + +## 16. Architectural Properties + +- **UTXO-native stablecoin.** DD amounts live in P2TR outputs; no shared global state, no smart-contract VM. The DD token output is a key-path-only P2TR; the collateral output is a 2-leaf MAST P2TR with a NUMS internal key (so key-path spending is impossible — the owner *must* take a script-path that enforces CLTV). +- **Treasury-model collateral.** 10 lock tiers (1 hour … 10 years) carrying ratios 1000% → 200% encode a soft incentive for longer commitments while preserving solvency under price shocks. +- **Defense in depth.** Four protection layers operate cooperatively: tier-based base ratio, DCA multiplier on system health, ERR DD-burn premium below 100% health, and the volatility freeze with `WouldCandidateFreezeMinting()` pre-mutation gate. +- **Address namespacing.** DD/TD/RD prefixes (mainnet/testnet/regtest) prevent cross-network errors when interacting with DigiDollar specifically. +- **No early redemption ever.** Both MAST leaves enforce CLTV expiry; there is no key-path spend, no oracle override, no liquidation. + +--- + +## 17. Test Suite Inventory (Protocol-Layer Subset) + +The full unit/fuzz/functional test inventory is maintained in `REPO_MAP_DIGIDOLLAR.md`. The tables below name the protocol-layer test files most directly relevant to the architecture above; running `./src/test/test_digibyte --list_content | grep -Ei 'digidollar|oracle|musig|^rh'` is the authoritative way to discover everything currently compiled. + +### 17.1 DigiDollar Protocol Unit Tests + +**Location**: `src/test/` + +| Test File | Coverage Area | +|-----------|---------------| +| digidollar_activation_tests.cpp | Activation height logic | +| digidollar_address_tests.cpp | DD/TD/RD address validation | +| digidollar_change_tests.cpp | DD change output creation, dust handling | +| digidollar_consensus_tests.cpp | Consensus rules | +| digidollar_dca_tests.cpp | Dynamic Collateral Adjustment | +| digidollar_err_tests.cpp | ERR activation, adjustment ratios | +| digidollar_health_tests.cpp | SystemHealthMonitor metrics | +| digidollar_key_encryption_tests.cpp | DD key encryption | +| digidollar_mint_tests.cpp | Minting process | +| digidollar_opcodes_tests.cpp | DD opcodes (OP_DIGIDOLLAR etc.) | +| digidollar_oracle_tests.cpp | Oracle integration | +| digidollar_p2p_tests.cpp | P2P networking | +| digidollar_persistence_keys_tests.cpp | Database key handling | +| digidollar_persistence_serialization_tests.cpp | Serialization | +| digidollar_persistence_walletbatch_tests.cpp | Wallet database operations | +| digidollar_redeem_tests.cpp | Redemption tx building | +| digidollar_redteam_tests.cpp | Security-focused (RED HORNET audit) | +| digidollar_restore_tests.cpp | Wallet restore from rescan | +| digidollar_rpc_tests.cpp | RPC command validation | +| digidollar_scripts_tests.cpp | P2TR script creation | +| digidollar_skip_oracle_tests.cpp | Oracle skip during IBD | +| digidollar_structures_tests.cpp | Data structure validation | +| digidollar_t2_05_tests.cpp | Task 2.05 specific tests | +| digidollar_timelock_tests.cpp | CLTV timelock logic | +| digidollar_transaction_tests.cpp | Transaction building | +| digidollar_transfer_tests.cpp | DD transfer conservation | +| digidollar_txbuilder_tests.cpp | Transaction builder | +| digidollar_utxo_lifecycle_tests.cpp | DD UTXO lifecycle tracking | +| digidollar_validation_tests.cpp | Validation functions | +| digidollar_volatility_tests.cpp | Volatility monitoring | +| digidollar_wallet_tests.cpp | Wallet operations | + +### 17.2 Oracle / MuSig2 Unit Tests (cross-reference) + +**Location**: `src/test/` — protocol layer only depends on the bundle/MuSig2 surface; full oracle test inventory lives in `DIGIDOLLAR_ORACLE_ARCHITECTURE.md` and `REPO_MAP_DIGIDOLLAR.md`. + +| Test File | Coverage Area | +|-----------|---------------| +| oracle_block_validation_tests.cpp | Block validation rules | +| oracle_bundle_manager_tests.cpp | Bundle creation/management | +| oracle_bundle_timing_tests.cpp | Bundle timing edge cases | +| oracle_config_tests.cpp | Oracle configuration | +| oracle_consensus_threshold_tests.cpp | Consensus threshold testing | +| oracle_exchange_tests.cpp | Exchange API integration | +| oracle_integration_tests.cpp | System integration | +| oracle_message_tests.cpp | Message creation/validation | +| oracle_miner_tests.cpp | Miner integration | +| oracle_p2p_tests.cpp | P2P oracle messaging | +| oracle_phase2_tests.cpp | Legacy Phase 2 / MuSig2 oracle validation regressions | +| oracle_price_feed_rh09_tests.cpp | Price feed RH-09 regression | +| oracle_price_staleness_tests.cpp | Price staleness detection | +| oracle_rpc_tests.cpp | Oracle RPC commands | +| oracle_wallet_autostart_tests.cpp | Oracle wallet auto-start | +| oracle_wallet_key_tests.cpp | Oracle key generation/storage | +| redteam_phase2_audit_tests.cpp | RED HORNET legacy Phase 2 exploit regressions | +| rh62_senddigidollar_amount_parser_tests.cpp | Send amount parser regression coverage | +| rh63_oracle_validator_escape_hatches_tests.cpp | Oracle validator escape-hatch regressions | +| rh64_dca_table_disagreement_tests.cpp | DCA table disagreement regressions | + +### 17.3 Functional Tests (Protocol-Layer Subset) + +**Location**: `test/functional/` — full DD/oracle/wallet/Qt functional inventory in `REPO_MAP_DIGIDOLLAR.md`. + +| Test File | Purpose | +|-----------|---------| +| digidollar_activation.py | Activation height testing | +| digidollar_activation_boundary.py | Activation edge cases | +| digidollar_basic.py | Basic DD functionality | +| digidollar_bug11_bug13_regression.py | Bug 11/13 regression tests | +| digidollar_collateral_spend_guards.py | Collateral vault spend guards and DD burn enforcement | +| digidollar_lock_tier_canonical.py | Canonical tier window acceptance/rejection | +| digidollar_verifychain_cache_side_effect.py | Verifychain cache side-effect regression | +| digidollar_wave14_multinode_ibd_reorg.py | Multi-node IBD/reorg DD/oracle state replay | +| digidollar_wave17_spendability.py | DD spendability/watch-only/locked-wallet regressions | +| digidollar_wave18_rpc_matrix.py | DD RPC matrix across wallet/network/activation states | +| digidollar_wave26_mixed_node_compat.py | Mixed-node activation compatibility | +| digidollar_encrypted_wallet.py | DD with encrypted wallet | +| digidollar_mint.py | End-to-end minting | +| digidollar_network_relay.py | P2P transaction relay | +| digidollar_network_tracking.py | Network-wide UTXO scanning | +| digidollar_oracle.py | Oracle integration (full cycle) | +| digidollar_oracle_consistency.py | Oracle consistency across nodes | +| digidollar_oracle_keygen.py | Oracle key generation | +| digidollar_oracle_bundle_reject_matrix.py | Oracle bundle reject matrix | +| digidollar_oracle_price.py | Oracle price feed testing | +| digidollar_persistence.py | Database save/load | +| digidollar_mempool_miner_parity.py | DD mempool/miner/ConnectBlock parity | +| digidollar_protection.py | DCA/ERR/Volatility systems | +| digidollar_protection_status.py | Protection status display | +| digidollar_redeem.py | Redemption process | +| digidollar_redeem_stats.py | Redemption statistics | +| digidollar_redemption_amounts.py | Amount calculations | +| digidollar_redemption_e2e.py | End-to-end redemption | +| digidollar_rpc.py | General RPC testing | +| digidollar_rpc_addresses.py | Address RPC commands | +| digidollar_rpc_collateral.py | Collateral RPC commands | +| digidollar_rpc_dca.py | DCA RPC commands | +| digidollar_rpc_deployment.py | Deployment status RPC | +| digidollar_rpc_display_bugs.py | RPC display bug fixes | +| digidollar_rpc_position_fields.py | Position field validation | +| digidollar_rpc_estimate.py | Collateral estimation RPC | +| digidollar_rpc_gating.py | RPC activation gating | +| digidollar_rpc_oracle.py | Oracle RPC commands | +| digidollar_rpc_protection.py | Protection status RPC | +| digidollar_rpc_redemption.py | Redemption RPC commands | +| digidollar_send.py | DD send workflow | +| digidollar_stress.py | Stress/load testing | +| digidollar_transaction_fees.py | Transaction fee handling | +| digidollar_transactions.py | Transaction handling | +| digidollar_transfer.py | Transfer operations | +| digidollar_tx_amounts_debug.py | Transaction amount debugging | +| digidollar_validate_address.py | DD address validation | +| digidollar_wallet.py | Wallet integration | +| digidollar_wallet_restore_redeem.py | Wallet restore + redeem | +| digidollar_watchonly_rescan.py | Watch-only wallet rescan | +| wallet_digidollar_backup.py | Wallet backup | +| wallet_digidollar_descriptors.py | Descriptor wallet compat | +| wallet_digidollar_encryption.py | Wallet encryption impact | +| wallet_digidollar_persistence_restart.py | Position recovery on restart | +| wallet_digidollar_rescan.py | Wallet rescan | +| wallet_digidollar_restore.py | Wallet restore testing | +| feature_oracle_p2p.py | Oracle P2P networking | +| digidollar_wave20_oracle_p2p.py | Oracle P2P pending-bundle flow | + +### 17.4 Running Tests + +```bash +# Whole DD/oracle/MuSig2/Red Hornet unit suite +./src/test/test_digibyte --list_content | grep -Ei 'digidollar|oracle|musig|^rh' | xargs -n1 ./src/test/test_digibyte --run_test= + +# Single suite +./src/test/test_digibyte --run_test=digidollar_validation_tests + +# Functional smoke test +test/functional/digidollar_basic.py +``` + +--- + +## 18. Code-to-Specification Verification + +| Specified Behavior | Code Reality | Reference | +|--------------------|--------------|-----------| +| MAST has exactly 2 leaves (Normal + ERR) | `CreateCollateralP2TR` adds only `CreateNormalRedemptionPath` and `CreateERRPath` at depth 1 | `src/digidollar/scripts.cpp:117-177` | +| `CreateEmergencyPath` removed | Function deleted; explicit comment at line 85 records the removal | `src/digidollar/scripts.cpp:85-86` | +| Both MAST leaves require CLTV expiry | Both scripts begin with ` OP_CHECKLOCKTIMEVERIFY OP_DROP` | `src/digidollar/scripts.cpp:73-99` | +| ERR increases DD burn; collateral return is full | `GetRequiredDDBurn` uses `__int128` ceiling math; `GetAdjustedRedemption` is deprecated identity passthrough | `src/consensus/err.cpp:100-149` | +| Mint blocked while ERR active or oracle missing | `EmergencyRedemptionRatio::ShouldBlockMinting` fails closed on missing oracle | `src/consensus/err.cpp:417-469` | +| Partial redemption rejected | `bad-collateral-release-partial-burn` raised when `ddBurned < requiredDDBurn` | `src/digidollar/validation.cpp:2529-2536` | +| Non-DD spends of registered collateral rejected | `bad-collateral-spend-missing-dd-burn` in `ValidateDigiDollarTransaction` | `src/digidollar/validation.cpp:2631-2655` | +| Confirmed-only DD chaining | DD inputs at `MEMPOOL_HEIGHT` rejected as `dd-input-amounts-unknown` | `src/digidollar/validation.cpp:1811, 1955` | +| Lock tier canonical window on mint | `bad-mint-lock-tier` for tier outside 0–9; `bad-mint-lock-tier-duration` if remaining lock blocks are outside `[canonical_blocks, canonical_blocks + 100]`; `bad-mint-lock-period` if not in `collateralRatios` | `src/digidollar/validation.cpp:1342-1397, 1603-1611` | +| Oracle price required | `bad-oracle-price` rejection in mint validation when `ctx.oraclePriceMicroUSD <= 0` | `src/digidollar/validation.cpp:1147-1153` | +| Pre-mutation volatility freeze | `WouldCandidateFreezeMinting` checked before `RecordPrice`; rejected mints can't poison history | `src/digidollar/validation.cpp:2688-2689, 2753` | +| Mainnet/testnet validator parity | Mainnet short-circuit removed; both networks honor identical V1 oracle-bundle gates | `src/validation.cpp:185-283` | +| `OP_CHECKPRICE` reserved/disabled | Interpreter consumes one operand and pushes false; no live or mock price lookup | `src/script/interpreter.cpp:708-735` | +| DD amount in cents (100 = $1) | Stored amounts in cents; oracle prices in micro-USD; conversion `priceMillicents = priceMicroUSD / 10` for health math | `src/consensus/digidollar.h:70-73`, `src/consensus/dca.cpp:239-243` | +| Transaction types fixed at 4 | `DD_TX_NONE=0, DD_TX_MINT=1, DD_TX_TRANSFER=2, DD_TX_REDEEM=3, DD_TX_MAX=4` | `src/primitives/transaction.h:38-44` | +| Redemption paths fixed at 2 | `RedemptionPath { PATH_NORMAL=0, PATH_ERR=1 }` | `src/digidollar/digidollar.h:70-73` | +| DD supply alert (not cap) | `AlertThresholds::ALERT_DD_SUPPLY = 100M DD` is monitoring threshold; `MAX_DIGIDOLLAR` is per-output bound | `src/digidollar/health.h:83`, `src/digidollar/digidollar.h:19` | + +--- + +*Document last validated 2026-06-25 against the source on `feature/digidollar-v1`. RPC commands: 35 registered total (18 registered in `RegisterDigiDollarRPCCommands` at `src/rpc/digidollar.cpp`, 17 in `GetWalletRPCCommands` at `src/wallet/rpc/wallet.cpp`, including `sendmanydigidollar`, `listdigidollarunspent`, `listdigidollarutxos`, `exportoracleprivkey`, and `importoracleprivkey`). DD price/position/transaction/oracle-operation RPCs are activation-gated; `getdigidollardeploymentinfo` and wallet-local oracle key-management RPCs (`createoraclekey`, `exportoracleprivkey`, `importoracleprivkey`) remain usable before activation. Oracle aggregation: 6 active exchange fetchers via libcurl (Binance, KuCoin, Gate.io, HTX, Crypto.com, CoinGecko). `MockOracleManager` is a regtest helper only. DigiDollar transfers/redeems are confirmed-only (commit `0b4959f563`). `sendoracleprice` RPC was removed as a fake-price-injection vulnerability and `submitoracleprice` does not exist anywhere in the source tree. Pre-V1 oracle bundle versions are rejected at block validation once DigiDollar is active (commit `f2bb0a19a4`).* diff --git a/DIGIDOLLAR_EXCHANGE_INTEGRATION.md b/DIGIDOLLAR_EXCHANGE_INTEGRATION.md new file mode 100644 index 00000000000..29ea4027b96 --- /dev/null +++ b/DIGIDOLLAR_EXCHANGE_INTEGRATION.md @@ -0,0 +1,422 @@ +# DigiDollar Exchange Integration Guide + +*For exchanges that already support DigiByte and want to add DigiDollar (DD) trading pairs.* + +--- + +## What Is DigiDollar? + +DigiDollar is a decentralized USD-denominated stablecoin system built natively into DigiByte Core. Each DD is designed to track $1.00 USD through over-collateralized DGB vaults, live oracle pricing, DCA, ERR, and volatility protections. It uses the same blockchain, same nodes, same infrastructure — just new transaction types and a dedicated address format. + +If you already run a DigiByte node, you're most of the way there. + +--- + +## Key Facts for Exchanges + +| Feature | Detail | +|---------|--------| +| Asset type | Native UTXO on DigiByte blockchain | +| Value | USD-denominated; designed to track $1.00 | +| Amount unit in RPC | **Integer USD cents for integration code** (10000 = $100.00) | +| Address format | `DD...` (mainnet), `TD...` (testnet), `RD...` (regtest) — Base58Check P2TR with 2-byte version prefix | +| Transaction fees | Paid in **DGB** (not DD) | +| Minimum fee | 0.1 DGB for transfer builders; mint and redeem builders enforce DGB fee floors in their txbuilder paths | +| Fee unit | DGB/kB (DigiByte uses kB, not vB) | +| Block time | 15 seconds (same as DGB) | +| Confirmations | Same security model as DGB | +| Backend required | DigiByte Core v9.26.2+ with DigiDollar built in; features remain BIP9-gated until activation | +| Wallet | Spend-capable descriptor wallet required for generated deposit addresses and withdrawals | + +--- + +## 1. Node Setup + +Upgrade your existing DigiByte node to v9.26.2+ and enable DigiDollar: + +```ini +# digibyte.conf +server=1 +digidollar=1 +txindex=1 # required for DigiDollar transaction lookups +rpcuser=youruser +rpcpassword=yourpassword + +# For testnet testing: +# testnet=1 +# [test] +# digidollar=1 +# txindex=1 +# addnode=oracle1.digibyte.io:12033 +``` + +That's it. Your existing DGB infrastructure stays the same — DD runs alongside it. + +`txindex=1` is not optional for DD chains because validation and wallet recovery need creating-transaction metadata. Before activation, `getdigidollardeploymentinfo` remains available, but DD address, balance, history, send, mint, redeem, and running-oracle RPCs are gated. + +--- + +## 2. Wallet Setup + +You'll need a wallet that holds both DGB and DD: +- **DGB** — for paying transaction fees on DD sends +- **DD** — for processing customer withdrawals + +Use a descriptor wallet with private keys enabled for hot-wallet custody. A watch-only/private-key-disabled wallet can monitor state if it already has the right descriptors, but it cannot create DD deposit addresses with `getdigidollaraddress` or sign withdrawals. `importdigidollaraddress` is only a validation/no-op stub in V1; it does not import, mutate wallet state, or rescan. + +```bash +# Create a spend-capable descriptor wallet (or use an existing one) +digibyte-cli createwallet "exchange-hot" false false "" false true + +# Verify DD is active +digibyte-cli getdigidollardeploymentinfo +# status should be "active" +``` + +--- + +## 3. Generating Customer Deposit Addresses + +Generate a unique DD address for each customer, just like you do for DGB: + +```bash +digibyte-cli getdigidollaraddress +# Returns a Base58Check DD/TD/RD address for the current network +``` + +**Important:** DD addresses are NOT the same as DGB addresses. They are Base58Check strings beginning with `DD`, `TD`, or `RD`, wrapping a 32-byte Taproot output key with a 2-byte DigiDollar version prefix. Do not treat them as Bech32/Bech32m, and do not validate by prefix alone. Use `validateddaddress` and reject wrong-network, checksum-invalid, whitespace-padded, or malformed input. + +**List DD addresses:** +```bash +digibyte-cli listdigidollaraddresses + +# Include generated but still-empty addresses: +digibyte-cli listdigidollaraddresses false 0 true +``` + +`listdigidollaraddresses` hides generated zero-balance addresses by default. Keep your own customer-to-address mapping when you allocate deposit addresses. + +--- + +## 4. Detecting Customer Deposits + +Poll for incoming DD transactions the same way you poll for DGB: + +```bash +# List recent DD transactions (last 100, receive only) +digibyte-cli listdigidollartxs 100 0 "" "receive" +``` + +**Each transaction returns:** +```json +{ + "txid": "abc123...", + "category": "receive", + "amount": 50000, + "address": "DDcustomerDepositAddr...", + "confirmations": 12, + "blockheight": 22100000, + "blockhash": "def456...", + "time": 1770934000, + "fee": 0 +} +``` + +**Match deposits to customers** by the `address` field (the unique DD address you generated for them). + +Track `txid`, `vout`, `blockhash`, `blockheight`, `confirmations`, `in_mempool`, and `wallet_state` from `listdigidollartxs`. Credit only after your confirmation threshold. If a credited transaction becomes `conflicted`/`abandoned`, loses confirmations, or reappears with a different `blockhash`, hold or reverse the credit and rescan affected customer balances. + +**Check a specific address balance:** +```bash +digibyte-cli getdigidollarbalance "DDcustomerAddr..." 6 +# Second param = minimum confirmations (recommend 6+) +``` + +### Recommended Confirmation Thresholds + +| Deposit Size | Confirmations | Wait Time | +|-------------|---------------|-----------| +| < $100 | 6 | ~90 seconds | +| $100 - $10,000 | 20 | ~5 minutes | +| > $10,000 | 60 | ~15 minutes | + +Same security model as DGB — 15-second blocks with 5 mining algorithms. + +--- + +## 5. Processing Customer Withdrawals + +Send DD to a customer's DD address: + +```bash +digibyte-cli senddigidollar "DDcustomerAddress..." 25000 +# Sends $250.00 (25000 cents) +``` + +**Response:** +```json +{ + "txid": "ghi789...", + "to_address": "DDcustomerAddress...", + "amount": 25000, + "status": "success", + "fee_paid": "0.10000000", + "inputs_used": 2, + "change_amount": 25000 +} +``` + +### Critical: You Need DGB for Fees + +Every DD send requires DGB to pay the miner fee (minimum 0.1 DGB). **Always maintain a DGB balance in your hot wallet.** If you run out of DGB, DD withdrawals will fail. + +**Check your DGB fee balance:** +```bash +digibyte-cli getbalance +``` + +### Withdrawal Limits + +- Per-output dust floor: $1 (100 cents) — see `src/consensus/digidollar.h:73` +- Maximum single transfer: **$100,000** (10,000,000 cents) per `maxMintAmount`-aligned policy in `src/consensus/digidollar.h:72` +- DD inputs must be **confirmed** (≥1 confirmation) before they can be re-spent. The wallet does not chain unconfirmed DigiDollar UTXOs, and consensus rejects DD transfer/redeem inputs that resolve from `MEMPOOL_HEIGHT` (commit `0b4959f563`). Plan withdrawal cadence around the 15-second block time, or batch with `sendmanydigidollar`. +- Integration code should pass integer cents with no decimal point. The send/redeem RPCs accept decimal-dollar input for CLI compatibility, so `25000` means $250.00 but `25000.00` means $25,000.00. +- DD transfer withdrawals do not need a fresh oracle quote for mempool admission. Mint and redeem paths require recent valid MuSig2 oracle data; transfer-only exchange withdrawals are price-independent, but still require confirmed DD and DGB fee inputs. + +### Batch withdrawals + +`sendmanydigidollar` sends DD to multiple addresses in a single transaction (one fee, one set of inputs): + +```bash +digibyte-cli sendmanydigidollar "" '{"DDcust1...":12500,"DDcust2...":7500}' +``` + +The first argument is the required `sendmany` compatibility dummy string. Use integer cents in integration code to avoid decimal display/rounding ambiguity. Large batches are limited by standard OP_RETURN relay size because one amount is committed for every DD output plus possible change; split large withdrawals and handle the RPC's "Too many DigiDollar recipients" error. + +--- + +## 6. Balance Monitoring + +### Hot Wallet Balances + +```bash +# DD balance (confirmed only by default) +digibyte-cli getdigidollarbalance +# Returns: { "confirmed": 500000, "unconfirmed": 0, "total": 500000 } +# (amounts in cents — 500000 = $5,000.00) + +# Include trusted mempool DD for monitoring only: +digibyte-cli getdigidollarbalance "" 0 + +# DGB balance (for fees) +digibyte-cli getbalance + +# BIP9 activation status (verifies DD is live) +digibyte-cli getdigidollardeploymentinfo +``` + +### Watch-Only (Cold Wallet Monitoring) + +Both `getdigidollarbalance` (third arg) and `listdigidollaraddresses` (first arg) accept `include_watchonly` for wallets that already contain watch-only DD state. DigiDollar V1 does **not** support importing a DD address for watch-only tracking: `importdigidollaraddress