Commit Graph

3181 Commits

Author SHA1 Message Date
389c8c7383 fix: cap mempool memory usage (-maxmempool) to bound an OOM DoS
This fork never ported Bitcoin's fee-ordered mempool eviction: CTxMemPool has no
TrimToSize/Expire, and LimitMempoolSize's body + call site are both commented out and
reference an undefined DEFAULT_MAX_MEMPOOL_SIZE. So the mempool had no total-size
ceiling. Together with the just-restored removeExpired() and near-free tx admission, a
peer could flood transactions to exhaust every node's memory (incl. pool/payout nodes).

Add a simple admission cap in AcceptToMemoryPool: once the pool exceeds -maxmempool it
refuses new admissions with DoS(0) (no ban -- a full pool isn't the peer's fault). This
is not fee-ordered eviction (that needs the absent TrimToSize machinery) but it bounds
the footprint; removeExpired() already evicts unmineable expired txs on each block
connect. New DEFAULT_MAX_MEMPOOL_SIZE=300 (MB, Bitcoin's default) is far above DragonX's
normal mempool, so normal operation is unaffected. Reviewed: bytes-vs-bytes comparison,
read under LOCK(pool.cs) on a recursive mutex (no deadlock); only the reorg re-add path
and new sends route through it, and only at 300MB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 04:58:39 +02:00
4e3c0f8f6f fix: apply real DoS score for invalid headers (Misbehaving nDoS/nDoS was always 1)
In the HEADERS handler, an invalid header scored Misbehaving(id, nDoS/nDoS). Because
the call is guarded by `if (nDoS > 0 ...)`, nDoS/nDoS is always exactly 1, so every
invalid header cost a fixed 1 misbehavior point regardless of severity -- it took
~banscore (default 101) invalid headers to ban a peer instead of 1, effectively
disarming the ban backstop against header spam. The two sibling call sites in the
same handler (tx-accept, block-accept) already pass nDoS directly.

Pass the real nDoS so a genuinely-invalid header (e.g. bad-diffbits, DoS 100) bans in
one message. Cannot over-ban honest peers: every DoS>0 header path is genuinely
invalid consensus, and benign/racy headers (unconnectable prevblock, future block,
clock-skew) either score DoS 0 or never reach Misbehaving (double-guarded by
IsInvalid + nDoS>0 + futureblock==0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 04:29:54 +02:00
4e67e687d7 perf: verify each block's RandomX solution once, not twice, during sync
RandomX PoW verification is ~84% of block-connect wall time during network IBD, and
CheckBlock was recomputing it TWICE per block: once in CheckBlockHeader and again in
hush_checkPOW (which has no CBlockIndex, so it cannot use the fRandomXVerified dedup
the parallel pre-verify pool relies on). Skip the redundant recompute inside
hush_checkPOW: CheckBlockHeader runs first in CheckBlock and rejects an invalid
solution before hush_checkPOW is reached, so the block is already verified once.
Equihash, PoW-target and notary checks in hush_checkPOW still run.

A scoped guard (ScopedRandomXSkip) SAVES and RESTORES the thread-local
fSkipRandomXValidation, so it neither clobbers the miner's own skip
(TestBlockValidity -> ConnectBlock re-entry, which would otherwise force the ~256MB
inline RandomX alloc the miner deliberately avoids) nor leaks the flag on an exception.

Measured on an isolated RandomX test chain: RandomX verifies per block 2.0 -> 1.03
(~40% faster network sync). The 2x behavior pre-exists in v1.0.2. Consensus-neutral:
RandomXPreVerify.ConsensusEquivalence gtest passes; each block is still verified
exactly once by CheckBlockHeader.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 01:26:30 +02:00
810bd6712f fix: make nCoinCacheUsage std::atomic to close an adaptive-dbcache data race
The scheduled AdjustCoinCacheForMemoryPressure task writes nCoinCacheUsage from
the scheduler thread holding no lock, while cs_main-holding threads
(FlushStateToDisk, VerifyDB) read it -- an unsynchronized read/write of a
non-atomic size_t (C++ UB). Make it std::atomic<size_t>; correct the comment
that incorrectly described the access as lock-free/race-free.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 05:48:39 +02:00
dc45e7d904 Harden ProcessGetData: log+disconnect instead of asserting on block-read failure
The legacy getdata block-serving path asserted whenever ReadBlockFromDisk failed for a block we had advertised (BLOCK_HAVE_DATA). A single transient I/O error or on-disk corruption, triggerable by any peer getdata, crashed the whole node (observed once during bulk-serve load testing on 176). Now log the failure and disconnect that peer so it can re-fetch from another node, matching the bulk GETBLOCKSTREAM serve path which already fails gracefully. Build-verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:08:34 +02:00
84aefb5475 Remove assumeutxo / UTXO-snapshot feature
Removes the dumptxoutset RPC, -loadutxosnapshot / -loadutxosnapshotunsafe,
the CCoinsViewDB Dump/LoadSnapshot machinery + CUTXOSnapshotHeader, the
AssumeutxoData chainparams anchor, the LoadSnapshotChainstate activation +
reorg-below-H guard, the persisted assumeutxo-height flag, and the gtest.

Rationale: it duplicated the existing bootstrap (same skip-the-genesis-grind
fast-sync, no speed advantage), its only real edge was a trust model we don't
need for this chain, and it was inert anyway (no published snapshot hash in
chainparams). The -loadutxosnapshot load path adopted an external UTXO set and
bypassed genesis validation, so removing it also drops that attack surface.
Builds clean (no dangling references); the kept IBD speedups (RandomX
pre-verify, adaptive dbcache, tlsmanager) are untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:42:37 -05:00
1f2b109d95 Add opt-in bulk block streaming (-bulkblocksync)
A single getblockstrm request makes a peer stream a contiguous range of old
blocks back-to-back as ordinary BLOCK messages, amortizing the per-block
round-trip over the whole range instead of the MAX_BLOCKS_IN_TRANSIT_PER_PEER
window. This targets the bandwidth-delay-product ceiling that dominates IBD
from few/high-latency peers below the checkpoint.

Design (off by default; negotiated via a NODE_BULKBLOCKS service bit; the
default getdata IBD path is untouched when disabled):
- protocol: NODE_BULKBLOCKS service bit + getblockstrm/blockstream messages.
- requester: in SendMessages, after FindNextBlocksToDownload, when the first
  needed block is >= BULK_TIP_MARGIN (5000) below the network tip and the peer
  advertises the bit and we are in IBD, request a contiguous range (<=128
  blocks) instead of per-block getdata; mark the range in-flight.
- server: stream the range (caps 128 blocks / 8 MiB; reads outside cs_main;
  per-peer flood throttle), then a trailing blockstream header with the actual
  count sent. Self-suppresses while the server itself is in IBD.
- received blocks ride the existing BLOCK -> ProcessNewBlock path (fully
  validated; checkpoints below 2.84M still apply); the trailing header
  reconciles partial deliveries and the range is freed on a 90s timeout, so a
  partial/withheld/refused batch falls back to the normal path (no leak, no
  permanent gap, no disconnect). In-flight tracking is by literal hash, so a
  reorg cannot orphan range entries.

Hardened against the issues found in two adversarial review passes (drain vs
timeout, partial reconciliation, ownership-guarded frees, one-shot header,
reorg-proof helpers, cs_main hold). Validated end-to-end between two local
v1.0.3 nodes (128/128 and partial serves; height advanced; no errors).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:22:54 -05:00
78ea2aac5b Add -maxblocksintransit: tunable per-peer block-download window
The per-peer in-flight block window (MAX_BLOCKS_IN_TRANSIT_PER_PEER) was a
hardcoded 16. On a single, high-latency peer during IBD the transfer is
bandwidth-delay-product bound (window / RTT), so with tiny sub-checkpoint
blocks the window, not bandwidth, is the ceiling — measured ~4x throughput
going 16 -> 64 on a 350ms-RTT peer. Make it a runtime flag (default 16,
clamped 1..4096), logged at startup. No behavior change at the default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:22:32 -05:00
1673cfb6dc IBD/sync speedups: parallel RandomX pre-verify, adaptive dbcache, P2P download fixes
- Parallel RandomX PoW pre-verification pool (CCheckQueue) run ahead of the serial
  connect; consensus-neutral (inline CheckRandomXSolution fallback still verifies
  anything not pre-verified). New -randomxverifythreads (default = -par).
- Adaptive dbcache: default sizes the UTXO/coins cache to most of RAM and shrinks
  under memory pressure, always leaving a reserve free; -dbcache pins a fixed value.
- P2P block download: bounded socket recv-drain loop (tlsmanager); frontier-block
  reassignment to break head-of-line stalls (-blockreassigntimeout); ProcessGetData
  serves a bounded batch of blocks per pass instead of one (fixes the serve-side
  one-block-per-tick throttle that caps download network-wide).
- assumeutxo: dumptxoutset RPC + LoadSnapshot machinery + AssumeutxoData chainparams.
- Signed bootstrap verification (util/bootstrap-dragonx.sh, util/sign-bootstrap.md).
- gtest: RandomX pre-verify consensus-equivalence test + UTXO-snapshot round-trip;
  revived the gtest harness (Makefile.am include fix, Makefile.gtest.include).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 12:30:10 -05:00
f0cb958cac Fix fresh sync failure at diff reset height 2838976
Fresh-syncing nodes rejected the on-chain min-diff block at the
RANDOMX_VALIDATION activation height (2838976) because GetNextWorkRequired
computed the expected nBits from the preceding normal-difficulty blocks,
producing 469847994 instead of the on-chain 0x200f0f0f (HUSH_MINDIFF_NBITS).
This caused all seed nodes to be banned with "Incorrect diffbits" and the
node could never sync past that height.

Two changes:

1. GetNextWorkRequired (pow.cpp): Return nProofOfWorkLimit at the exact
   RANDOMX_VALIDATION activation height, matching the on-chain diff reset.

2. ContextualCheckBlockHeader (main.cpp): Raise DragonX daaForkHeight to
   RANDOMX_VALIDATION + 62000, covering the window where nBits was never
   validated (diff reset at 2838976 through the attack at ~2879907).

Tested by invalidating block 2838975 and reconsidering — node re-validated
through the diff reset and attack window, syncing back to tip with zero
bad-diffbits rejections.

Bump version to 1.0.1.
2026-03-12 01:25:21 -05:00
0a01ad8bba Fix nBits validation bypass and restore CheckProofOfWork rejection for HACs
Two critical vulnerabilities allowed an attacker to flood the DragonX chain
with minimum-difficulty blocks starting at height 2879907:

1. ContextualCheckBlockHeader only validated nBits for HUSH3 mainnet
   (gated behind `if (ishush3)`), never for HAC/smart chains. An attacker
   could submit blocks claiming any difficulty and the node accepted them.
   Add nBits validation for all non-HUSH3 smart chains, gated above
   daaForkHeight (default 450000) to maintain consensus with early chain
   history that was mined by a different binary.

2. The rebrand commit (85c8d7f7d) commented out the `return false` block
   in CheckProofOfWork that rejects blocks whose hash does not meet the
   claimed target. This made PoW validation a no-op — any hash passed.
   Restore the rejection block and add RANDOMX_VALIDATION height-gated
   logic so blocks after the activation height are always validated even
   during initial block loading.

Vulnerability #1 was inherited from the upstream hush3 codebase.
Vulnerability #2 was introduced by the DragonX rebrand.
2026-03-05 03:09:38 -06:00
d6ba1aed4e Fix RandomX validation exploit: verify nSolution contains valid RandomX hash
- Add CheckRandomXSolution() to validate RandomX PoW in nSolution field
- Add ASSETCHAINS_RANDOMX_VALIDATION activation height per chain
  (DRAGONX: 2838976, TUMIN: 1200, others: height 1)
- Add CRandomXInput serializer for deterministic RandomX hash input
- Fix CheckProofOfWork() to properly reject invalid PoW (was missing
  SMART_CHAIN_SYMBOL check, allowing bypass)
- Call CheckRandomXSolution() in hush_checkPOW and CheckBlockHeader

Without this fix, attackers could submit blocks with invalid RandomX
hashes that passed validation, as CheckProofOfWork returned early
during block loading and the nSolution field was never verified.
2026-03-03 17:28:49 -06:00
Duke
f8136f5839 DragonX has left the nest 2026-02-28 12:12:45 -05:00
Duke
2b3f9ed33f Add -ac_clearnet=0 option so an entire chain can disable clearnet connection, instead of -clearnet=0 which only applies to a single node 2025-08-08 16:09:32 -04:00
Duke
e748772fff Validate -ac_minopreturnfee as a consensus rule 2025-05-17 10:23:51 -04:00
Duke
080092a16d -ac_burn=1 requires a z2t tx, -ac_burn=2 does not 2025-05-06 00:31:13 -04:00
Duke
d39503c13b Add HAC option to allow sending funds to the transparent burn address when -ac_private=1 2025-04-29 14:52:25 -04:00
Duke
18e4ca070e Remove more cc stuff 2024-10-01 10:49:13 -04:00
Duke
a00ad8eeb8 Merge branch 'dev' into duke 2024-10-01 08:58:09 -04:00
Duke
93f6514d86 Disable absurd fee checks when adding to the mempool
To protect users who are not using opreturn we prevent any use of z_sendmany
with absurd fees if opreturn is not being used, so this change only affects
users who are adding opreturn data. Since there is no way to currently send
opreturn data via a GUI this still protects all GUI users from absurd fees
while allowing CLI users to decide to use higher fees.
2024-09-26 11:13:07 -04:00
Duke
01f0c34661 We do not support coin imports 2024-09-24 09:35:20 -04:00
Duke
b6bcacad20 We do not support coin imports 2024-09-22 12:16:21 -04:00
Duke
148ea35a98 Remove dead sprout code 2024-09-22 11:56:12 -04:00
Duke
380875906d Remove more CC stuff 2024-09-22 09:40:37 -04:00
Duke
d471af9ef5 IsPegsImport() is always false
Since this function always returns false and is used in many "hot"
code paths, removing it from the code should give us a performance boost.
2024-09-18 12:13:37 -04:00
Duke
ffce5edda3 Remove commented out code 2024-09-18 11:59:00 -04:00
Duke
5e30079fcd IsPegsImport() always returns false 2024-09-18 11:53:40 -04:00
Duke
27f72405b2 Also print address to stderr in hush_isnotaryvout 2024-09-17 13:11:11 -04:00
Duke
f8e7df37a1 Delete commented out code 2024-09-12 12:12:59 -04:00
Duke
ed86f2dd1d Sleep for 200us before each ActivateBestChainStep call
This should lower the main thread's likelihood to immediately reacquire
cs_main after dropping it, which should help ThreadNotifyWallets and the
RPC methods to acquire cs_main more quickly.

Ported from ZEC commit e2cd1b761fe556bc6d61849346902c3611530307
2024-09-12 00:21:56 -04:00
Duke
1e892f23e6 Remove dead nVersion code
This is very old code from the early days of Bitcoin, our mainnets have
never used peer protocol version.

Originally 150ab1d34c
2024-08-07 07:18:08 -07:00
Duke
5273f4be9e Give Hush mainnet a dedicated minimum protocol version #345
Hush and DragonX do not have the same requirements for which nodes they
should talk to because they don't necessarily have consensus changes at
the same time. For instance, 3.10.0 was a consensus change for Hush but
not DragonX. This commit changes things so that Hush nodes will no
longer talk to old nodes that are not consensus compatible but leaves
things the same for DragonX mainnet, which has never had a consensus
change.
2024-05-06 08:46:21 -07:00
onryo
58b65f9670 Update copyrights 2024-02-27 23:59:59 +01:00
Duke
a581f8fc8e Fix compile error and remove some cryptocondition dingleberries 2024-02-15 11:03:05 -05:00
Duke
b9d3c77a4c Merge branch 'duke' into dev 2024-02-15 10:41:50 -05:00
Duke
07b041fd94 Do not apply overwinter/sapling consensus rules to block 0 2024-02-15 10:40:22 -05:00
Duke
8f2350fd84 Merge branch 'dev' into duke 2024-02-15 10:11:52 -05:00
Duke
b14070d15b Overwinter+sapling consensus rules do not apply to height=0 2024-02-15 10:06:37 -05:00
Duke
c94906e011 Do not spam debug.log with 'Received addr' unless -debug 2024-02-12 09:57:52 -05:00
Duke
acee1c8cf5 Do not spam debug.log with 'Received addr' unless -debug 2024-02-12 09:57:09 -05:00
Duke
90d47ecce4 Potentially fix #382 by not checking the genesis block against sapling consensus rules 2024-02-11 06:29:29 -05:00
Duke
27db254d68 Sapling and Overwinter network upgrades are always active
These NU's are always active for Hush Arrakis Chains so this code only serves
to slow down all operations by constantly being checked. So we disable them
which will speed up syncing, mining and creating transactions.
2024-01-21 16:34:53 -05:00
Duke
b0b9565d6a Sapling and Overwinter network upgrades are always active 2024-01-21 15:32:23 -05:00
Duke
3a3c67e0fc Delete many things we do not want or need 2024-01-13 00:06:09 -05:00
Duke
90133dbc0e Also log flush mode in FlushStateToDisk() 2023-12-27 17:56:44 -05:00
Duke
20fdc0e4fe Get rid of deprecation entirely which allows current code to run past block height 5555555 2023-12-27 12:57:35 -05:00
Duke
2a2391f0f9 Log when trimming block solutions 2023-12-27 11:43:53 -05:00
duke
95b4371aa4 Merge pull request 'Reduce memory usage' (#332) from reduce_memory into dev
Reviewed-on: https://git.hush.is/hush/hush3/pulls/332
2023-10-25 15:11:51 +00:00
Duke
4256e7d835 Suppress 'Ignoring nbits' debug 2023-10-16 10:36:57 -04:00
Duke
31a6b72caf Merge branch 'dev' into reduce_memory 2023-10-16 06:04:56 -04:00