|
| 1 | +# DigiByte v8.26 Transaction Fee Analysis and Implementation Specification |
| 2 | + |
| 3 | +## Executive Summary |
| 4 | + |
| 5 | +DigiByte v8.26 currently implements a **fee-per-kilobyte** model inherited from Bitcoin, which does not enforce a minimum absolute fee of 0.1 DGB per transaction as required for spam protection. This document provides a comprehensive analysis of the current fee implementation and specifications for necessary changes. |
| 6 | + |
| 7 | +**Critical Finding**: The current implementation allows transactions as small as 250 bytes to pay only 0.025 DGB in fees (at the default 0.1 DGB/kvB rate), which is insufficient for spam protection given DigiByte's 1000x larger supply compared to Bitcoin. |
| 8 | + |
| 9 | +## Current Fee Implementation in DigiByte v8.26 |
| 10 | + |
| 11 | +### Fee Constants and Their Values |
| 12 | + |
| 13 | +| Constant | Value (satoshis) | Value (DGB) | Location | Purpose | |
| 14 | +|----------|------------------|-------------|----------|---------| |
| 15 | +| `DEFAULT_TRANSACTION_MINFEE` | 10,000,000 | 0.1 DGB/kvB | `wallet/wallet.h:117` | Wallet minimum fee rate | |
| 16 | +| `DEFAULT_MIN_RELAY_TX_FEE` | 100,000 | 0.001 DGB/kvB | `policy/policy.h:59` | Network relay minimum | |
| 17 | +| `DUST_RELAY_TX_FEE` | 30,000 | 0.0003 DGB/kvB | `policy/policy.h:57` | Dust threshold calculation | |
| 18 | +| `DEFAULT_FALLBACK_FEE` | 1,000,000 | 0.01 DGB/kvB | `wallet/wallet.h:113` | Fallback when fee estimation fails | |
| 19 | +| `WALLET_INCREMENTAL_RELAY_FEE` | 1,000,000 | 0.01 DGB/kvB | `wallet/wallet.h:131` | RBF fee increment | |
| 20 | +| `DEFAULT_DISCARD_FEE` | 10,000 | 0.0001 DGB/kvB | `wallet/wallet.h:115` | Small change discard threshold | |
| 21 | + |
| 22 | +### Fee Calculation Model |
| 23 | + |
| 24 | +The current implementation uses a **fee-per-kilobyte** model: |
| 25 | + |
| 26 | +```cpp |
| 27 | +// From policy/feerate.cpp:22-35 |
| 28 | +CAmount CFeeRate::GetFee(uint32_t num_bytes) const |
| 29 | +{ |
| 30 | + // Calculate fee as: (rate_per_kvB * size_in_bytes) / 1000 |
| 31 | + CAmount nFee = std::ceil(nSatoshisPerK * num_bytes / 1000.0); |
| 32 | + return nFee; |
| 33 | +} |
| 34 | +``` |
| 35 | +
|
| 36 | +**Problem**: This means a 250-byte transaction pays: |
| 37 | +- Fee = 10,000,000 * 250 / 1000 = 2,500,000 satoshis = **0.025 DGB** |
| 38 | +- This is 4x less than the required 0.1 DGB minimum |
| 39 | +
|
| 40 | +### Fee Enforcement Points |
| 41 | +
|
| 42 | +1. **Wallet Fee Calculation** (`wallet/fees.cpp`) |
| 43 | + - `GetMinimumFeeRate()`: Returns max of wallet minimum and relay minimum |
| 44 | + - `GetRequiredFeeRate()`: Enforces wallet.m_min_fee (0.1 DGB/kvB) |
| 45 | + - No absolute minimum enforced |
| 46 | +
|
| 47 | +2. **Mempool Acceptance** (`validation.cpp`) |
| 48 | + - Line 874-876: Checks against `m_pool.m_min_relay_feerate` (0.001 DGB/kvB) |
| 49 | + - Line 674-681: `CheckFeeRate()` validates against dynamic mempool minimum |
| 50 | + - No absolute minimum enforced |
| 51 | +
|
| 52 | +3. **Network Relay** (`net_processing.cpp`) |
| 53 | + - Uses `DEFAULT_MIN_RELAY_TX_FEE` for relay decisions |
| 54 | + - Fee filter uses same per-kilobyte rates |
| 55 | +
|
| 56 | +## Bitcoin vs DigiByte Fee Scaling Analysis |
| 57 | +
|
| 58 | +### Supply and Economic Differences |
| 59 | +
|
| 60 | +| Metric | Bitcoin | DigiByte | Ratio | |
| 61 | +|--------|---------|----------|-------| |
| 62 | +| Max Supply | 21 million | 21 billion | 1000x | |
| 63 | +| Block Time | 600 seconds | 15 seconds | 40x faster | |
| 64 | +| Typical TX Size | 250 bytes | 250 bytes | Same | |
| 65 | +| Min Relay Fee | 0.00001 BTC/kvB | 0.001 DGB/kvB | 100x | |
| 66 | +| Wallet Min Fee | 0.00001 BTC/kvB | 0.1 DGB/kvB | 10,000x | |
| 67 | +
|
| 68 | +### Current Fee Comparison for 250-byte Transaction |
| 69 | +
|
| 70 | +| Network | Fee Rate | Actual Fee | USD Value* | |
| 71 | +|---------|----------|------------|------------| |
| 72 | +| Bitcoin | 0.00001 BTC/kvB | 0.0000025 BTC | ~$0.25 | |
| 73 | +| DigiByte (current) | 0.1 DGB/kvB | 0.025 DGB | ~$0.0003 | |
| 74 | +| DigiByte (required) | 0.4 DGB/kvB OR absolute 0.1 DGB | 0.1 DGB | ~$0.001 | |
| 75 | +
|
| 76 | +*USD values are illustrative based on approximate market prices |
| 77 | +
|
| 78 | +## Required Changes for 0.1 DGB Minimum Fee |
| 79 | +
|
| 80 | +### Option 1: Absolute Minimum Fee (Recommended) |
| 81 | +
|
| 82 | +Implement an absolute minimum fee check that overrides the per-kilobyte calculation: |
| 83 | +
|
| 84 | +```cpp |
| 85 | +// New constant in policy/policy.h |
| 86 | +static constexpr CAmount ABSOLUTE_MIN_TX_FEE{10000000}; // 0.1 DGB absolute minimum |
| 87 | +
|
| 88 | +// Modified fee calculation in wallet/fees.cpp |
| 89 | +CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, |
| 90 | + const CCoinControl& coin_control, FeeCalculation* feeCalc) |
| 91 | +{ |
| 92 | + CFeeRate feerate_needed = GetMinimumFeeRate(wallet, coin_control, feeCalc); |
| 93 | + CAmount calculated_fee = feerate_needed.GetFee(nTxBytes); |
| 94 | + |
| 95 | + // Enforce absolute minimum |
| 96 | + return std::max(calculated_fee, ABSOLUTE_MIN_TX_FEE); |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +### Option 2: Increased Fee Rate |
| 101 | + |
| 102 | +Increase the minimum fee rate to ensure even small transactions meet the 0.1 DGB minimum: |
| 103 | + |
| 104 | +```cpp |
| 105 | +// For a 250-byte transaction to pay 0.1 DGB: |
| 106 | +// Required rate = 0.1 DGB * 1000 / 250 = 0.4 DGB/kvB = 40,000,000 satoshis/kvB |
| 107 | +static const CAmount DEFAULT_TRANSACTION_MINFEE = 40000000; // 0.4 DGB/kvB |
| 108 | +``` |
| 109 | + |
| 110 | +### Option 3: Hybrid Approach (Most Flexible) |
| 111 | + |
| 112 | +Combine both approaches for maximum flexibility: |
| 113 | + |
| 114 | +```cpp |
| 115 | +// Use higher of: calculated fee or absolute minimum |
| 116 | +CAmount final_fee = std::max( |
| 117 | + feerate.GetFee(tx_size), // Per-kilobyte calculation |
| 118 | + ABSOLUTE_MIN_TX_FEE // Absolute minimum of 0.1 DGB |
| 119 | +); |
| 120 | +``` |
| 121 | + |
| 122 | +## Files Requiring Modification |
| 123 | + |
| 124 | +### Core Implementation Files |
| 125 | + |
| 126 | +1. **src/policy/policy.h** |
| 127 | + - Add `ABSOLUTE_MIN_TX_FEE` constant |
| 128 | + - Update `DEFAULT_MIN_RELAY_TX_FEE` if using Option 2 |
| 129 | + |
| 130 | +2. **src/wallet/wallet.h** |
| 131 | + - Update `DEFAULT_TRANSACTION_MINFEE` if using Option 2 |
| 132 | + - Add absolute minimum fee member variable |
| 133 | + |
| 134 | +3. **src/wallet/fees.cpp** |
| 135 | + - Modify `GetMinimumFee()` to enforce absolute minimum |
| 136 | + - Update `GetRequiredFee()` similarly |
| 137 | + |
| 138 | +4. **src/validation.cpp** |
| 139 | + - Update `CheckFeeRate()` to enforce absolute minimum |
| 140 | + - Modify mempool acceptance logic (lines 874-876) |
| 141 | + |
| 142 | +5. **src/wallet/spend.cpp** |
| 143 | + - Update fee calculation in `CreateTransactionInternal()` |
| 144 | + - Ensure coin selection respects new minimums |
| 145 | + |
| 146 | +6. **src/txmempool.cpp** |
| 147 | + - Update `GetMinFee()` to respect absolute minimum |
| 148 | + |
| 149 | +### Configuration and RPC Files |
| 150 | + |
| 151 | +7. **src/init.cpp** |
| 152 | + - Update help text for `-mintxfee` and `-minrelaytxfee` |
| 153 | + - Add new `-absolutemintxfee` option if desired |
| 154 | + |
| 155 | +8. **src/rpc/mempool.cpp** |
| 156 | + - Update fee-related RPC responses |
| 157 | + |
| 158 | +9. **src/wallet/rpc/spend.cpp** |
| 159 | + - Update `sendtoaddress`, `sendmany`, etc. to respect new minimums |
| 160 | + |
| 161 | +## Test Files Requiring Updates |
| 162 | + |
| 163 | +### Primary Fee-Related Tests |
| 164 | + |
| 165 | +1. **test/functional/feature_fee_estimation.py** |
| 166 | + - Update expected fee calculations |
| 167 | + - Add tests for absolute minimum |
| 168 | + |
| 169 | +2. **test/functional/wallet_fallbackfee.py** |
| 170 | + - Verify fallback respects absolute minimum |
| 171 | + |
| 172 | +3. **test/functional/wallet_bumpfee.py** |
| 173 | + - Ensure RBF respects new minimums |
| 174 | + |
| 175 | +4. **test/functional/mempool_accept.py** |
| 176 | + - Test rejection of low-fee transactions |
| 177 | + |
| 178 | +5. **test/functional/mempool_dust.py** |
| 179 | + - Update dust threshold calculations |
| 180 | + |
| 181 | +6. **test/functional/p2p_feefilter.py** |
| 182 | + - Update fee filter expectations |
| 183 | + |
| 184 | +7. **test/functional/rpc_estimatefee.py** |
| 185 | + - Verify estimation respects minimums |
| 186 | + |
| 187 | +### Secondary Tests Affected by Fee Changes |
| 188 | + |
| 189 | +8. **test/functional/wallet_basic.py** |
| 190 | + - Transaction creation tests |
| 191 | + |
| 192 | +9. **test/functional/wallet_sendmany_chain.py** |
| 193 | + - Multi-output transaction fees |
| 194 | + |
| 195 | +10. **test/functional/wallet_fundrawtransaction.py** |
| 196 | + - Raw transaction funding |
| 197 | + |
| 198 | +11. **test/functional/mempool_limit.py** |
| 199 | + - Mempool eviction by fee |
| 200 | + |
| 201 | +12. **test/functional/mempool_packages.py** |
| 202 | + - Package fee validation |
| 203 | + |
| 204 | +13. **test/functional/feature_rbf.py** |
| 205 | + - Replace-by-fee increments |
| 206 | + |
| 207 | +14. **test/functional/wallet_create_tx.py** |
| 208 | + - Transaction creation edge cases |
| 209 | + |
| 210 | +15. **test/functional/wallet_groups.py** |
| 211 | + - Coin selection with fees |
| 212 | + |
| 213 | +## Implementation Recommendations |
| 214 | + |
| 215 | +### 1. Immediate Actions |
| 216 | + |
| 217 | +1. **Implement Option 3 (Hybrid Approach)** |
| 218 | + - Provides both per-kilobyte and absolute minimum protection |
| 219 | + - Most flexible for different transaction sizes |
| 220 | + - Easiest to roll back if issues arise |
| 221 | + |
| 222 | +2. **Add Configuration Option** |
| 223 | + ```cpp |
| 224 | + // Add to init.cpp |
| 225 | + "-absolutemintxfee=<amt> Absolute minimum fee per transaction (default: 0.1 DGB)" |
| 226 | + ``` |
| 227 | + |
| 228 | +3. **Gradual Rollout** |
| 229 | + - Start with wallet enforcement only |
| 230 | + - Monitor network acceptance |
| 231 | + - Then enforce in mempool/relay |
| 232 | + |
| 233 | +### 2. Testing Strategy |
| 234 | + |
| 235 | +1. **Unit Tests** |
| 236 | + - Test fee calculation with various transaction sizes |
| 237 | + - Verify absolute minimum enforcement |
| 238 | + - Check edge cases (very large transactions) |
| 239 | + |
| 240 | +2. **Functional Tests** |
| 241 | + - Update all fee-related tests listed above |
| 242 | + - Add new test: `test/functional/feature_absolute_min_fee.py` |
| 243 | + - Verify network propagation |
| 244 | + |
| 245 | +3. **Testnet Deployment** |
| 246 | + - Deploy to testnet first |
| 247 | + - Monitor for transaction rejection issues |
| 248 | + - Gather fee metrics |
| 249 | + |
| 250 | +### 3. Monitoring and Metrics |
| 251 | + |
| 252 | +Add logging to track: |
| 253 | +- Transactions paying exactly minimum fee |
| 254 | +- Transactions rejected for low fees |
| 255 | +- Average fee per transaction |
| 256 | +- Fee distribution histogram |
| 257 | + |
| 258 | +## Potential Issues and Mitigations |
| 259 | + |
| 260 | +### Issue 1: Large Transaction Overhead |
| 261 | +**Problem**: A 10KB transaction would pay 1.0 DGB at 0.1 DGB/kvB rate |
| 262 | +**Mitigation**: Use hybrid approach - larger transactions use per-kilobyte rate |
| 263 | + |
| 264 | +### Issue 2: Wallet Compatibility |
| 265 | +**Problem**: Older wallets may create invalid transactions |
| 266 | +**Mitigation**: |
| 267 | +- Implement grace period with warnings |
| 268 | +- Provide clear error messages |
| 269 | +- Update wallet software first |
| 270 | + |
| 271 | +### Issue 3: Exchange Integration |
| 272 | +**Problem**: Exchanges may have hardcoded fee logic |
| 273 | +**Mitigation**: |
| 274 | +- Provide advance notice |
| 275 | +- Offer integration support |
| 276 | +- Consider phased rollout |
| 277 | + |
| 278 | +### Issue 4: Smart Contract/Script Transactions |
| 279 | +**Problem**: Complex transactions may be disproportionately affected |
| 280 | +**Mitigation**: Monitor and adjust rates based on actual usage |
| 281 | + |
| 282 | +## Conclusion |
| 283 | + |
| 284 | +The current DigiByte v8.26 fee structure allows transactions to pay less than the required 0.1 DGB minimum, creating spam vulnerability. The recommended solution is a hybrid approach that enforces both: |
| 285 | + |
| 286 | +1. **Absolute minimum**: 0.1 DGB per transaction |
| 287 | +2. **Rate-based fees**: For larger transactions |
| 288 | + |
| 289 | +This approach provides spam protection while maintaining fairness for legitimate large transactions. Implementation should be gradual with extensive testing and clear communication to the ecosystem. |
| 290 | + |
| 291 | +## Appendix: Quick Reference |
| 292 | + |
| 293 | +### Current State |
| 294 | +- Small TX (250 bytes) pays: **0.025 DGB** ❌ |
| 295 | +- Medium TX (1000 bytes) pays: **0.1 DGB** ✓ |
| 296 | +- Large TX (10000 bytes) pays: **1.0 DGB** ✓ |
| 297 | + |
| 298 | +### After Implementation |
| 299 | +- Small TX (250 bytes) pays: **0.1 DGB** ✓ |
| 300 | +- Medium TX (1000 bytes) pays: **0.1 DGB** ✓ |
| 301 | +- Large TX (10000 bytes) pays: **1.0 DGB** ✓ |
| 302 | + |
| 303 | +### Key Files to Modify |
| 304 | +1. `src/policy/policy.h` - Add `ABSOLUTE_MIN_TX_FEE` |
| 305 | +2. `src/wallet/fees.cpp` - Enforce in `GetMinimumFee()` |
| 306 | +3. `src/validation.cpp` - Enforce in `CheckFeeRate()` |
| 307 | +4. 15+ test files - Update expectations |
| 308 | + |
| 309 | +### Testing Command |
| 310 | +```bash |
| 311 | +# Run all fee-related tests after changes |
| 312 | +./test/functional/test_runner.py --extended feature_fee wallet_fee mempool_fee |
| 313 | +``` |
0 commit comments