Compare commits

...

10 Commits

Author SHA1 Message Date
dan_s
a2647b106f Move 15 loose scripts from contrib/ root to contrib/scripts/
Consolidate all standalone utility scripts into contrib/scripts/:
- Perl: avg_blocktime.pl, block_time.pl, gen-zaddrs.pl, sda_checkpoints.pl,
  sdl_checkpoints.pl, hush_block_subsidy_per_halving, hush_halvings,
  hush_scanner, hush_supply, hush_supply_old
- Shell: fresh_clone_compile_and_run.sh, tidy_datadir.sh, dragonx_scanner
- Python: convert_address.py
- BAT: hush-uri.bat

Update path references in contrib/README.md, doc/OLD_WALLETS.md,
doc/relnotes/README.md, and sdl_checkpoints.pl.
2026-02-27 12:00:46 -06:00
dan_s
ab6a3a05d7 Deduplicate cJSON: consolidate 4 copies into a single canonical pair
- Compile cJSON.c as a standalone C translation unit (added stdbool.h)
- Rename hush_cJSON.c → hush_cJSON.cpp and compile as standalone C++ unit
  with forward declarations for external deps (_stripwhite, clonestr, etc.)
- Remove #include "cJSON.c" unity-build from hush_cJSON
- Change hush.h from #include "hush_cJSON.c" to #include "hush_cJSON.h"
- Add both files to libbitcoin_server_a_SOURCES in Makefile.am
- Delete cc/dapps/cJSON.c (old 2009 fork, 1201 lines removed)
- Replace cc/includes/cJSON.h with thin redirect to canonical headers
- Update dapp includes to reference canonical cJSON.c
2026-02-27 09:39:48 -06:00
dan_s
f565b2920d Split wallet.cpp: extract key management into wallet_keys.cpp
Separate key management from transaction logic in wallet.cpp (5,059 lines):
- wallet.cpp: 5,059 → 4,143 lines (transaction tracking, coin selection, balances)
- wallet_keys.cpp: 975 lines (key generation, encryption, HD seed, keypool)

Extracted functions include key generation (GenerateNewKey, GenerateNewSaplingZKey),
cryptographic key storage (AddKeyPubKey, AddCryptedKey, AddCryptedSaplingSpendingKey),
wallet encryption (Unlock, ChangeWalletPassphrase, EncryptWallet), HD seed management,
keypool operations, CReserveKey methods, and shielded key visitor operators.
2026-02-27 01:51:24 -06:00
dan_s
0083cd26bb Split main.cpp (8,217 lines) into four focused translation units
- tx_validation.cpp (1,012 lines): transaction validation functions
  (IsStandardTx, CheckTransaction, ContextualCheckInputs, etc.)
- mempool_accept.cpp (524 lines): mempool acceptance and orphan management
  (AcceptToMemoryPool, AddOrphanTx, GetMinRelayFee, etc.)
- block_processing.cpp (4,064 lines): block processing, chain management,
  and disk I/O (ConnectBlock, DisconnectBlock, ActivateBestChain, CheckBlock,
  LoadBlockIndex, FlushStateToDisk, etc.)
- main_internal.h (83 lines): shared internal state declarations formerly in
  anonymous namespace (CBlockIndexWorkComparator, setBlockIndexCandidates,
  vinfoBlockFile, setDirtyBlockIndex, etc.)

main.cpp retains NET message handling (ProcessMessage, SendMessages),
peer state management, and utility functions (2,821 lines).
2026-02-27 01:51:24 -06:00
dan_s
a918136a7c Split chainparams.cpp and rpcwallet.cpp into smaller files
chainparams.cpp: 5420 -> 593 lines
  - Extract HUSH3 checkpoint data to chainparams_checkpoints_hush3.h
  - Extract DRAGONX checkpoint data to chainparams_checkpoints_dragonx.h

rpcwallet.cpp: 6392 -> 4099 lines
  - Extract z-index query RPCs to rpcwallet_zindex.cpp
  - Extract shielded async operation RPCs to rpcwallet_zops.cpp
  - Create rpcwallet_internal.h for shared declarations
2026-02-27 01:51:24 -06:00
dan_s
3d4e25e429 Split hush unity build: move ~14k lines of implementation from headers into hush_impl.cpp and hush_nSPV_impl.cpp
- Add HUSH_PRIVATE_IMPLEMENTATION guard to hush.h separating implementation from declarations
- Create hush_impl.cpp to compile all hush_*.h implementation as a separate translation unit
- Create hush_nSPV_impl.cpp to compile all hush_nSPV_*.h headers separately
- main.cpp now includes declarations only, no longer a unity build for hush code
- Add both new compilation units to Makefile.am
2026-02-26 20:55:12 -06:00
dan_s
896fa9c107 Reorganize repo: move scripts to contrib/scripts/, clean up .gitignore, untrack backup files 2026-02-26 19:42:28 -06:00
dan_s
10a1b27de1 reorganizing release ouput to cleaner directory structure 2026-02-25 23:50:14 -06:00
dan_s
3cf6c37bf6 updated dragonx checkpoints 2026-02-25 14:41:10 -06:00
dan_s
b25bd2838c fix native linux build script 2026-02-25 14:09:26 -06:00
80 changed files with 14870 additions and 32346 deletions

271
.gitignore vendored
View File

@@ -1,13 +1,43 @@
# ==========================
# Editor & IDE files
# ==========================
.*.sw?
*.*~*
*~
*.bak
*.rej
*.orig
.idea
.vscode
# ==========================
# Compiled objects & libraries
# ==========================
*.o
*.o-*
*.a
*.lo
*.la
*.so
*.dll
*.pyc
*.pb.cc
*.pb.h
*.json.h
*.raw.h
*.dSYM
# ==========================
# Archives & packages
# ==========================
*.tar.gz *.tar.gz
*.deb *.deb
src/bitcoin *.zip
src/test/test_bitcoin *.dmg
src/core
*zcashTest.pk # ==========================
*zcashTest.vk # Autotools / configure
# ==========================
# autoreconf
#Makefile.in #Makefile.in
aclocal.m4 aclocal.m4
autom4te.cache/ autom4te.cache/
@@ -28,58 +58,74 @@ config.log
config.status config.status
configure configure
libtool libtool
Makefile
Makefile.in
src/Makefile.in
doc/man/Makefile.in
src/config/bitcoin-config.h src/config/bitcoin-config.h
src/config/bitcoin-config.h.in src/config/bitcoin-config.h.in
src/config/stamp-h1 src/config/stamp-h1
libzcashconsensus.pc
cache/ # ==========================
venv-mnf/ # Build outputs & artifacts
src/univalue/gen # ==========================
src/.build_target
.deps .deps
.dirstamp .dirstamp
.idea
.libs .libs
.*.sw?
*.*~*
*.bak
*.rej
*.orig
*.pyc
*.o
*.o-*
.zcash
*.a
*.pb.cc
*.pb.h
.vscode
# Hush binaries
src/hush-cli
src/hushd
src/hush-tx
src/hush-test
src/hush-cli.exe
src/hushd.exe
src/hush-tx.exe
src/wallet-utility
src/wallet-utility.exe
# Legacy bitcoin binaries
src/bitcoin
src/test/test_bitcoin
src/core
# Shared libraries
src/libcc.so
src/libcc.dll
src/cc/customcc.so
src/cc/customcc.dll
src/cc/librogue.so
# RandomX build dirs
src/RandomX/build-linux/
src/RandomX/build-win64/
# Release directories
release/
release-win64/
release-linux/
# ==========================
# Depends build system
# ==========================
depends/built/
depends/work/
depends/x86_64-*/
# ==========================
# Zcash / Sapling test keys
# ==========================
*zcashTest.pk
*zcashTest.vk
.zcash
# ==========================
# Test & coverage
# ==========================
*.log *.log
*.trs *.trs
*.dmg
*.json.h
*.raw.h
#libtool object files
*.lo
*.la
# Compilation
Makefile
# Unit-tests
Makefile.test
src/test/buildenv.py
# Resources cpp
qrc_*.cpp
# Mac specific
.DS_Store
build
#lcov
*.gcno *.gcno
*.gcda *.gcda
/*.info /*.info
@@ -87,8 +133,8 @@ test_bitcoin.coverage/
zcash-gtest.coverage/ zcash-gtest.coverage/
total.coverage/ total.coverage/
coverage_percent.txt coverage_percent.txt
Makefile.test
#build tests src/test/buildenv.py
linux-coverage-build linux-coverage-build
linux-build linux-build
win32-build win32-build
@@ -97,84 +143,61 @@ qa/pull-tester/tests-config.sh
qa/pull-tester/cache/* qa/pull-tester/cache/*
qa/pull-tester/test.*/* qa/pull-tester/test.*/*
!src/leveldb*/Makefile # ==========================
# Generated / misc source
# ==========================
qrc_*.cpp
src/univalue/gen
src/cryptoconditions/compile
src/fiat/-usd
/doc/doxygen/ /doc/doxygen/
libzcashconsensus.pc # ==========================
# CC / games (legacy)
# ==========================
src/cc/rogue/rogue
src/cc/rogue/rogue.so
src/cc/rogue/test.zip
src/cc/rogue/config.h
src/cc/rogue/confdefs.h
src/cc/rogue/x64
src/cc/dapps/a.out
src/cc/games/prices
src/cc/games/tetris
src/ROGUE.conf
src/rogue.scr
src/rogue.*.*
src/fiat/-usd # ==========================
# Misc runtime / temp files
# ==========================
src/checkfile
src/foo.zip
src/log
src/HUSH3_7776
REGTEST_7776
src/rpcmisc~.cpp
cache/
venv-mnf/
# ==========================
# Debian packaging
# ==========================
contrib/debian/files contrib/debian/files
contrib/debian/substvars contrib/debian/substvars
src/rpcmisc~.cpp # ==========================
src/wallet-utility # Platform specific
# ==========================
.DS_Store
build
src/hush-cli # ==========================
src/hushd # Bundled repos (use separately)
src/hush-tx # ==========================
src/hush-test
src/hush-cli.exe
src/hushd.exe
src/hush-tx.exe
#output during builds, symbol tables?
*.dSYM
src/cryptoconditions/compile
src/cc/rogue/rogue
src/cc/rogue/rogue.so
src/cc/rogue/test.zip
src/cc/dapps/a.out
src/checkfile
src/foo.zip
src/log
src/rogue.530623577502174316.0
src/rogue.530623577502174316.pack
src/rogue.530623577502174316.player
src/cc/rogue/config.h
src/ROGUE.conf
src/rogue.scr
src/cc/rogue/confdefs.h
src/cc/rogue/x64
src/cc/dapps/a.out
src/Makefile.in
doc/man/Makefile.in
Makefile.in
src/libcc.so
src/libcc.dll
src/cc/customcc.so
src/cc/customcc.dll
src/HUSH3_7776
REGTEST_7776
src/cc/librogue.so
src/cc/games/prices
src/cc/games/tetris
# Build artifacts
*~
*.zip
release-win64/
release-linux/
src/RandomX/build-linux/
src/RandomX/build-win64/
src/wallet-utility.exe
src/.build_target
# other
repos/ repos/
# ==========================
# Leveldb Makefile exception
# ==========================
!src/leveldb*/Makefile

View File

@@ -11,38 +11,43 @@ make clean 2>/dev/null || true
rm -rf depends/built depends/x86_64-unknown-linux-gnu depends/work rm -rf depends/built depends/x86_64-unknown-linux-gnu depends/work
make -C depends clean 2>/dev/null || true make -C depends clean 2>/dev/null || true
# Limit parallelism to avoid OOM kills inside Docker.
# Each C++ compilation can use 1-2 GB RAM; cap at ~half of nproc.
JOBS=$(( $(nproc) / 2 ))
[ "$JOBS" -lt 1 ] && JOBS=1
# Build RandomX for Linux (clean, since host build is different arch/libc) # Build RandomX for Linux (clean, since host build is different arch/libc)
cd src/RandomX cd src/RandomX
rm -rf build-linux rm -rf build-linux
mkdir -p build-linux && cd build-linux mkdir -p build-linux && cd build-linux
cmake -DARCH=native .. cmake -DARCH=native ..
make -j$(nproc) make -j"$JOBS"
cd /hush3 cd /hush3
# Run the normal build # Run the normal build
./util/build.sh --disable-tests -j$(nproc) ./util/build.sh --disable-tests -j"$JOBS"
# Package release # Package release
echo "Creating Linux release package..." echo "Creating Linux release package..."
VERSION=$(grep -oP 'define\(_CLIENT_VERSION.*?,\s*\K[0-9]+' configure.ac | head -3 | tr '\n' '.' | sed 's/\.$//') VERSION=$(grep -oP 'define\(_CLIENT_VERSION.*?,\s*\K[0-9]+' configure.ac | head -3 | tr '\n' '.' | sed 's/\.$//')
VERSION=${VERSION:-3.10.5} VERSION=${VERSION:-3.10.5}
RELEASE_DIR="release-linux" RELEASE_DIR="release/${VERSION}-linux-amd64"
mkdir -p "$RELEASE_DIR" mkdir -p "$RELEASE_DIR"
strip -s src/hushd src/hush-cli src/hush-tx strip -s src/hushd src/hush-cli src/hush-tx
cp src/hushd src/hush-cli src/hush-tx "$RELEASE_DIR/" cp src/hushd src/hush-cli src/hush-tx "$RELEASE_DIR/"
cp asmap.dat sapling-spend.params sapling-output.params "$RELEASE_DIR/" 2>/dev/null || true cp asmap.dat sapling-spend.params sapling-output.params "$RELEASE_DIR/" 2>/dev/null || true
cp src/hush-arrakis-chain src/dragonxd src/dragonx-cli "$RELEASE_DIR/" cp contrib/scripts/hush-arrakis-chain contrib/scripts/dragonxd contrib/scripts/dragonx-cli "$RELEASE_DIR/"
cp contrib/bootstrap/bootstrap-dragonx.sh "$RELEASE_DIR/" cp contrib/bootstrap/bootstrap-dragonx.sh "$RELEASE_DIR/"
# Create ZIP inside release dir (matches --win-release layout) # Create ZIP inside release dir (matches --win-release layout)
rm -f "$RELEASE_DIR/hush-${VERSION}-linux64.zip" rm -f "$RELEASE_DIR/${VERSION}-linux-amd64.zip"
cd "$RELEASE_DIR" cd "$RELEASE_DIR"
zip -9 "hush-${VERSION}-linux64.zip" * zip -9 "${VERSION}-linux-amd64.zip" *
cd .. cd ../..
echo "Release package created: $RELEASE_DIR/hush-${VERSION}-linux64.zip" echo "Release package created: $RELEASE_DIR/${VERSION}-linux-amd64.zip"
ls -lh "$RELEASE_DIR/hush-${VERSION}-linux64.zip" ls -lh "$RELEASE_DIR/${VERSION}-linux-amd64.zip"
# Fix ownership of all files created by root so host user can access them # Fix ownership of all files created by root so host user can access them
if [ -n "${HOST_UID:-}" ] && [ -n "${HOST_GID:-}" ]; then if [ -n "${HOST_UID:-}" ] && [ -n "${HOST_GID:-}" ]; then

View File

@@ -26,6 +26,26 @@ check_and_clean_target() {
if [[ -d src/leveldb ]]; then if [[ -d src/leveldb ]]; then
make -C src/leveldb clean 2>/dev/null || true make -C src/leveldb clean 2>/dev/null || true
fi fi
# Clean depends when switching between Docker and native builds,
# since Docker builds bake container paths into .la files
local TRIPLET
TRIPLET=$(./depends/config.guess 2>/dev/null || true)
if [[ -n "$TRIPLET" && -d "depends/$TRIPLET" ]]; then
echo "Cleaning depends/$TRIPLET to avoid path contamination..."
# Use sudo if files are root-owned (from Docker builds)
if [[ "$(stat -c '%u' "depends/$TRIPLET" 2>/dev/null)" == "0" ]]; then
sudo rm -rf "depends/$TRIPLET" "depends/built/$TRIPLET"
else
rm -rf "depends/$TRIPLET" "depends/built/$TRIPLET"
fi
elif [[ -n "$TRIPLET" && -d "depends/built/$TRIPLET" ]]; then
echo "Cleaning depends/built/$TRIPLET to avoid path contamination..."
if [[ "$(stat -c '%u' "depends/built/$TRIPLET" 2>/dev/null)" == "0" ]]; then
sudo rm -rf "depends/built/$TRIPLET"
else
rm -rf "depends/built/$TRIPLET"
fi
fi
echo "Clean complete." echo "Clean complete."
fi fi
@@ -48,7 +68,9 @@ if [[ "${1:-}" == "--linux-release" ]]; then
echo "Building Linux release inside Ubuntu 20.04 Docker container..." echo "Building Linux release inside Ubuntu 20.04 Docker container..."
sudo docker build -t hush-builder -f Dockerfile.build . sudo docker build -t hush-builder -f Dockerfile.build .
sudo docker run --rm -e HOST_UID=$(id -u) -e HOST_GID=$(id -g) -v "$SCRIPT_DIR:/hush3" hush-builder "$@" sudo docker run --rm -e HOST_UID=$(id -u) -e HOST_GID=$(id -g) -v "$SCRIPT_DIR:/hush3" hush-builder "$@"
echo "Docker build complete. Release is in release-linux/" VERSION=$(grep -oP 'define\(_CLIENT_VERSION.*?,\s*\K[0-9]+' configure.ac | head -3 | tr '\n' '.' | sed 's/\.$//')
VERSION=${VERSION:-3.10.5}
echo "Docker build complete. Release is in release/${VERSION}-linux-amd64/"
exit $? exit $?
fi fi

View File

@@ -14,7 +14,7 @@ Estimate when a Hush block will happen.
Example: Example:
./contrib/block_time.pl 123456 # Print out datetime of when block height 123456 happens ./contrib/scripts/block_time.pl 123456 # Print out datetime of when block height 123456 happens
## gen-zaddrs.pl ## gen-zaddrs.pl
@@ -22,8 +22,8 @@ Generate zaddrs in bulk, by default 50 at a time. Prints out a zaddr one per lin
Example: Example:
./contrib/gen-zaddrs.pl # generate 50 zaddrs ./contrib/scripts/gen-zaddrs.pl # generate 50 zaddrs
./contrib/gen-zaddrs.pl 500 # generate 500 zaddrs ./contrib/scripts/gen-zaddrs.pl 500 # generate 500 zaddrs
## Wallet Tools ## Wallet Tools

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers
set -eo pipefail
# Resolve binary directory
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
BINDIR="$SCRIPTDIR"
else
BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
hush_cli='./hush-cli'
"$SCRIPTDIR/listassetchains" | while read chain; do
$hush_cli --ac_name=$chain stop
done

15
contrib/scripts/dragonx-cli Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Copyright 2016-2024 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# Resolve binary directory
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
BINDIR="$SCRIPTDIR"
else
BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
./hush-cli -ac_name=DRAGONX "$@"

View File

@@ -3,12 +3,14 @@
# Copyright 2022 The DragonX Developers # Copyright 2022 The DragonX Developers
# Released under the GPLv3 # Released under the GPLv3
# set working directory to the location of this script # Resolve binary directory
# readlink -f does not always exist SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
cd $DIR BINDIR="$SCRIPTDIR"
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )" else
cd $DIR BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
SEEDNODE=176.126.87.241 SEEDNODE=176.126.87.241

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers
# Resolve binary directory
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
BINDIR="$SCRIPTDIR"
else
BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
DEFAULTS=""
# People can just use hushd going forward, but this script makes it
# more clear what is going on
HUSH="./hushd"
$HUSH $DEFAULTS "$@"

View File

@@ -5,8 +5,12 @@ import json
def format_param(param, value): def format_param(param, value):
return '-' + param + '=' + value return '-' + param + '=' + value
script_dir = os.path.dirname(__file__) script_dir = os.path.dirname(os.path.abspath(__file__))
with open(script_dir + '/assetchains.json') as file: # Look for assetchains.json in same dir first, then in src/
json_path = os.path.join(script_dir, 'assetchains.json')
if not os.path.exists(json_path):
json_path = os.path.join(script_dir, '..', '..', 'src', 'assetchains.json')
with open(json_path) as file:
assetchains = json.load(file) assetchains = json.load(file)
for chain in assetchains: for chain in assetchains:

14
contrib/scripts/listassetchains Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env python2
import os
import json
script_dir = os.path.dirname(os.path.abspath(__file__))
# Look for assetchains.json in same dir first, then in src/
json_path = os.path.join(script_dir, 'assetchains.json')
if not os.path.exists(json_path):
json_path = os.path.join(script_dir, '..', '..', 'src', 'assetchains.json')
with open(json_path) as file:
assetchains = json.load(file)
for chain in assetchains:
print(chain['ac_name'])

View File

@@ -10,7 +10,7 @@ use warnings;
use strict; use strict;
# call this script like this to generate checkpoints for a HAC such as DragonX: # call this script like this to generate checkpoints for a HAC such as DragonX:
# CLI=./src/dragonx-cli ./contrib/sdl_checkpoints.pl ... # CLI=./src/dragonx-cli ./contrib/scripts/sdl_checkpoints.pl ...
my $hush = $ENV{CLI} || "./src/hush-cli"; my $hush = $ENV{CLI} || "./src/hush-cli";
my $gethash = "$hush getblockhash"; my $gethash = "$hush getblockhash";

View File

@@ -2,15 +2,24 @@
# Copyright (c) 2018-2024 The Hush developers # Copyright (c) 2018-2024 The Hush developers
set -eo pipefail set -eo pipefail
# Resolve binary directory
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
BINDIR="$SCRIPTDIR"
else
BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
# You can now add delay line to pubkey.txt file # You can now add delay line to pubkey.txt file
source pubkey.txt source pubkey.txt
overide_args="$@" override_args="$@"
seed_ip=$(SEEDNODE) seed_ip=$(SEEDNODE)
hsc='./hush-arrakis-chain' hsc='./hush-arrakis-chain'
if [ -z "$delay" ]; then delay=20; fi if [ -z "$delay" ]; then delay=20; fi
./listassetchainparams | while read args; do "$SCRIPTDIR/listassetchainparams" | while read args; do
gen="" gen=""
if [ $[RANDOM % 10] == 1 ]; then if [ $[RANDOM % 10] == 1 ]; then
gen=" -gen -genproclimit=1" gen=" -gen -genproclimit=1"

15
contrib/scripts/testdragonx-cli Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Copyright 2016-2024 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# Resolve binary directory
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
BINDIR="$SCRIPTDIR"
else
BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
./hush-cli -ac_name=TESTDRAGONX $@

View File

@@ -3,12 +3,14 @@
# Copyright 2022 The DragonX Developers # Copyright 2022 The DragonX Developers
# Released under the GPLv3 # Released under the GPLv3
# set working directory to the location of this script # Resolve binary directory
# readlink -f does not always exist SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
cd $DIR BINDIR="$SCRIPTDIR"
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )" else
cd $DIR BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
BLOCKTIME=18 BLOCKTIME=18
SUPPLY=0 SUPPLY=0

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Copyright 2016-2024 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# Resolve binary directory
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
BINDIR="$SCRIPTDIR"
else
BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
./hush-cli -ac_name=TESTEQUIHASH $@

View File

@@ -3,12 +3,14 @@
# Copyright 2022 The DragonX Developers # Copyright 2022 The DragonX Developers
# Released under the GPLv3 # Released under the GPLv3
# set working directory to the location of this script # Resolve binary directory
# readlink -f does not always exist SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
cd $DIR BINDIR="$SCRIPTDIR"
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )" else
cd $DIR BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
BLOCKTIME=18 BLOCKTIME=18
SUPPLY=0 SUPPLY=0

View File

@@ -1,12 +1,14 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers # Copyright (c) 2016-2024 The Hush developers
# set working directory to the location of this script # Resolve binary directory
# readlink -f does not always exist SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
cd $DIR BINDIR="$SCRIPTDIR"
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )" else
cd $DIR BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
NAME=TUSH NAME=TUSH

View File

@@ -3,12 +3,14 @@
# Distributed under the GPLv3 software license, see the accompanying # Distributed under the GPLv3 software license, see the accompanying
# file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html # file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
# set working directory to the location of this script # Resolve binary directory
# readlink -f does not always exist SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
cd $DIR BINDIR="$SCRIPTDIR"
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )" else
cd $DIR BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
# ./hushd -ac_name=TUSH -ac_private=1 -gen=1 -testnode=1 # ./hushd -ac_name=TUSH -ac_private=1 -gen=1 -testnode=1
./hushd -ac_name=TUSH -ac_private=1 -ac_supply=55555 ./hushd -ac_name=TUSH -ac_private=1 -ac_supply=55555

18
contrib/scripts/zush Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers
# Resolve binary directory
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$SCRIPTDIR/hush-cli" ] || [ -f "$SCRIPTDIR/hushd" ]; then
BINDIR="$SCRIPTDIR"
else
BINDIR="$SCRIPTDIR/../../src"
fi
cd "$BINDIR"
NAME=ZUSH
CLI=${HUSHCLI:-./hush-cli}
if [ -f $CLI ]; then
$CLI -ac_name=$NAME "$@"
fi

View File

@@ -19,7 +19,7 @@ with `t1` and now they begin with `R`.
To see what an old HUSH v2 address looks like on the new chain, this online tool To see what an old HUSH v2 address looks like on the new chain, this online tool
can be used: https://dexstats.info/addressconverter.php can be used: https://dexstats.info/addressconverter.php
or this command line tool: https://git.hush.is/hush/hush3/src/master/contrib/convert_address.py or this command line tool: https://git.hush.is/hush/hush3/src/master/contrib/scripts/convert_address.py
### Using an old wallet.dat ### Using an old wallet.dat

137
doc/codebase-cleanup.md Normal file
View File

@@ -0,0 +1,137 @@
# Codebase Cleanup & Organization Options
## 1. Remove Build Artifacts from the Working Tree
The `depends/` directory alone is **1.8 GB**, with 479M in `depends/sources/`, 302M in `depends/built/`. The `release/` dir is 395M, and `repos/` is 164M. While `release/` and `repos/` are already in `.gitignore`, the `depends/built/` and `depends/work/` outputs are not explicitly ignored.
**Actions:**
- [x] Add `depends/built/`, `depends/work/`, `depends/x86_64-w64-mingw32/` to `.gitignore`
- [ ] Run `git clean -fdx` on build output directories periodically
- [ ] The `.o` and `.a` files in `src/` (e.g., 22M `libbitcoin_server.a`) are build outputs cluttering the source tree
## 2. Move Large Binary Params Out of Git History
`sapling-spend.params` (46M) and `sapling-output.params` (3.5M) are committed directly. These are cryptographic proving keys from the Zcash Sapling trusted setup ceremony and **cannot be regenerated**. The node shuts down without them.
**Options:**
- [ ] Use **Git LFS** to track them instead
- [ ] Download them at build/install time via a script (like Zcash's `fetch-params.sh`)
- [x] Keep as-is (current deliberate design choice — guarantees out-of-box operation)
## 3. Clean Up Tracked Editor/Autoconf Backup Files
`src/univalue/configure~` is a tracked backup file. The root `configure~` also exists. These should be removed from tracking and the `.gitignore` pattern `*~` should catch them going forward.
- [x] Remove `src/univalue/configure~` from git tracking
## 4. Split Monolithic Source Files
Several files are extremely large and would benefit from decomposition:
| File | Lines | Suggestion |
|------|-------|------------|
| `src/main.cpp` | 8,217 | Split validation, block processing, mempool logic into separate files |
| `src/wallet/rpcwallet.cpp` | 6,392 | Group RPC methods by category (send, receive, list, z-operations) |
| `src/chainparams.cpp` | 5,420 | Extract checkpoint data and chain-specific params to separate files |
| `src/wallet/wallet.cpp` | 5,059 | Split wallet transaction logic from key management |
- [x] Split `src/main.cpp`
- 8,217 → 2,821 lines in `main.cpp`
- Created `tx_validation.cpp` (1,012 lines) — transaction validation (IsStandardTx, CheckTransaction, ContextualCheckInputs, etc.)
- Created `mempool_accept.cpp` (524 lines) — mempool acceptance and orphan management (AcceptToMemoryPool, AddOrphanTx, etc.)
- Created `block_processing.cpp` (4,064 lines) — block processing, chain management, and disk I/O (ConnectBlock, DisconnectBlock, ActivateBestChain, CheckBlock, LoadBlockIndex, etc.)
- Created `main_internal.h` (83 lines) — shared internal state (block index candidates, file info, dirty sets, etc.)
- [x] Split `src/wallet/rpcwallet.cpp`
- 6,392 → 4,099 lines in `rpcwallet.cpp`
- Created `wallet/rpcwallet_zindex.cpp` (1,193 lines) — z-index query RPCs (`getalldata`, `z_getinfo`, `z_getstats`, etc.)
- Created `wallet/rpcwallet_zops.cpp` (1,194 lines) — shielded async operation RPCs (`z_sendmany`, `z_shieldcoinbase`, `z_mergetoaddress`, etc.)
- Created `wallet/rpcwallet_internal.h` (45 lines) — shared declarations and `THROW_IF_SYNCING` macro
- [x] Split `src/chainparams.cpp`
- 5,420 → 593 lines in `chainparams.cpp`
- Created `chainparams_checkpoints_hush3.h` (1,986 lines) — HUSH3 checkpoint data
- Created `chainparams_checkpoints_dragonx.h` (2,853 lines) — DRAGONX checkpoint data
- [x] Split `src/wallet/wallet.cpp`
- 5,059 → 4,143 lines in `wallet.cpp`
- Created `wallet_keys.cpp` (975 lines) — key management, encryption, HD seed, keypool
## 5. Move Implementation Out of Header Files
There are **13,652 lines** of implementation code in `hush_*.h` headers:
| Header | Lines |
|--------|-------|
| `src/hush_utils.h` | 2,549 |
| `src/hush_gateway.h` | 2,531 |
| `src/hush_bitcoind.h` | 1,867 |
| `src/hush_curve25519.h` | 1,017 |
| `src/hush_nSPV_superlite.h` | 977 |
| `src/hush_nSPV_fullnode.h` | 914 |
| `src/hush_defs.h` | 656 |
| `src/hush_nSPV.h` | 603 |
| `src/hush_nSPV_wallet.h` | 505 |
| `src/hush_notary.h` | 469 |
| `src/hush_globals.h` | 360 |
| `src/hush_ccdata.h` | 272 |
| `src/hush_kv.h` | 204 |
| `src/hush_nSPV_defs.h` | 193 |
- [x] Move implementations from `hush_*.h` headers to `.cpp` files
- Created `src/hush_impl.cpp` — compiles all hush_*.h implementation via `HUSH_PRIVATE_IMPLEMENTATION` guard
- Created `src/hush_nSPV_impl.cpp` — compiles all hush_nSPV_*.h implementation
- Modified `src/hush.h` with `#ifdef HUSH_PRIVATE_IMPLEMENTATION` to separate implementation from declarations
- `main.cpp` now includes declarations only (no longer a unity build for hush code)
## 6. Deduplicate Vendored Code
`cJSON` has been consolidated:
- `src/cJSON.c` + `src/cJSON.h` — canonical implementation, compiled as a standalone C translation unit
- `src/hush_cJSON.cpp` + `src/hush_cJSON.h` — helper/wrapper functions, compiled as a standalone C++ translation unit
- `src/cc/includes/cJSON.h` — thin redirect to the canonical headers above
- `src/cc/dapps/cJSON.c` — deleted (old 2009 fork); dapp includes updated to use canonical copy
- [x] Consolidate to a single copy and have other modules link against it
## 7. Relocate Shell Scripts Out of `src/`
There are **15+ shell scripts and .bat files** tracked inside `src/`:
- `dragonx-cli`, `dragonxd`, `tush-cli`, `tushd`, `zush`
- `smartchains`, `purge`, `listassetchains`, `listassetchainparams`
- `testdragonx-cli`, `testdragonxd`, `testequihash-cli`, `testequihashd`
- `assetchains_stop`, `hush-arrakis-chain`
- `.bat` variants: `dragonx-cli.bat`, `dragonxd.bat`, `hush-arrakis-chain.bat`
- [x] Move shell scripts to `contrib/scripts/` directory
## 8. ~~Organize the `repos/` Directory~~ (N/A — `repos/` is gitignored)
## 9. Improve `.gitignore` Coverage
The current `.gitignore` has redundant and scattered entries (e.g., `src/cc/dapps/a.out` listed twice, many game-related paths for a rogue game that appears obsolete).
- [x] Group entries by category (build outputs, editor files, platform-specific)
- [x] Remove stale entries for files/features that no longer exist
- [x] Add `depends/built/`, `depends/work/`, `depends/x86_64-*/`
## 10. Consolidate Documentation
Docs are split across `doc/`, `contrib/README.md`, and the root.
- [ ] Create a `doc/architecture.md` describing the module structure
---
## Recommended Priority
**Highest-impact, lowest-risk changes** (don't touch compiled code):
1. Items **1, 3, 9**`.gitignore` cleanup and removing tracked backup files
2. Item **7** — relocate scripts out of `src/`
**Higher-impact, higher-risk changes** (affect build system and code):
4. Item **5** — move implementation out of headers
5. Item **4** — split monolithic source files
6. Item **6** — deduplicate cJSON
7. Item **2**~~Move shell scripts to `contrib/scripts/` directory~~ Done — moved 15 loose scripts from `contrib/` root into `contrib/scripts/`

View File

@@ -96,7 +96,7 @@ For this repo, it's likely this is the command you need:
gdb src/hushd core gdb src/hushd core
``` ```
NOTE: Even if you are debugging a coredump on a HAC, such as DragonX, the file `src/dragonxd` NOTE: Even if you are debugging a coredump on a HAC, such as DragonX, the file `contrib/scripts/dragonxd`
is just a shell script that calls `src/hushd` and you always want to give an actual executable is just a shell script that calls `src/hushd` and you always want to give an actual executable
file as the first argument to `gdb`, not a bash script. file as the first argument to `gdb`, not a bash script.

View File

@@ -13,11 +13,11 @@ The following command can be used to launch an HSC on a single computer. Each op
HSC CLI arguments that start with `-ac_` means they *Affect Consensus*. HSC CLI arguments that start with `-ac_` means they *Affect Consensus*.
``` ```
./src/hush-arrakis-chain -ac_halving=100 -ac_algo=randomx -ac_name=RANDOMX -ac_private=1 -ac_blocktime=15 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 -testnode=1 ./contrib/scripts/hush-arrakis-chain -ac_halving=100 -ac_algo=randomx -ac_name=RANDOMX -ac_private=1 -ac_blocktime=15 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 -testnode=1
``` ```
* `hush-arrakis-chain` is the script used to launch or connect to HSCs * `hush-arrakis-chain` is the script used to launch or connect to HSCs
* It lives in the `./src` directory, next to `hushd` and `hush-cli` * It lives in the `./contrib/scripts` directory
* It is called `hush-arrakis-chain.bat` on Windows * It is called `hush-arrakis-chain.bat` on Windows
* `-ac_halving=100` means "the block reward halves every 100 blocks" * `-ac_halving=100` means "the block reward halves every 100 blocks"
* `-ac_algo=randomx` means "use RandomX for Proof-Of-Work * `-ac_algo=randomx` means "use RandomX for Proof-Of-Work
@@ -41,12 +41,12 @@ HSC CLI arguments that start with `-ac_` means they *Affect Consensus*.
* One node would use * One node would use
``` ```
# first node # first node
./src/hush-arrakis-chain -ac_halving=100 -ac_algo=randomx -ac_name=RANDOMX -ac_private=1 -ac_blocktime=15 -ac_reward=500000000 -ac_supply=55555 ./contrib/scripts/hush-arrakis-chain -ac_halving=100 -ac_algo=randomx -ac_name=RANDOMX -ac_private=1 -ac_blocktime=15 -ac_reward=500000000 -ac_supply=55555
``` ```
* And the second node would use: * And the second node would use:
``` ```
# mining node. NOTE: This node will mine the genesis block and pre-mine, if any # mining node. NOTE: This node will mine the genesis block and pre-mine, if any
./src/hush-arrakis-chain -ac_halving=100 -ac_algo=randomx -ac_name=RANDOMX -ac_private=1 -ac_blocktime=15 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 ./contrib/scripts/hush-arrakis-chain -ac_halving=100 -ac_algo=randomx -ac_name=RANDOMX -ac_private=1 -ac_blocktime=15 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1
``` ```
# Advanced Options # Advanced Options

View File

@@ -231,8 +231,8 @@ since it contains various bugfixes and improvements that will benefit busy walle
* sendmany RPC will now reject transactions that send to taddrs immediately, instead of them being rejected in mempool * sendmany RPC will now reject transactions that send to taddrs immediately, instead of them being rejected in mempool
* Preliminary support for FreeBSD has been added to the Hush build system * Preliminary support for FreeBSD has been added to the Hush build system
* New contrib scripts: * New contrib scripts:
* `contrib/gen-zaddrs.pl` - Generate zaddrs in bulk, defaults to 50 * `contrib/scripts/gen-zaddrs.pl` - Generate zaddrs in bulk, defaults to 50
* `contrib/sdl_checkpoints.pl` - Generate SDL checkpoints using `getblockmerkletree` * `contrib/scripts/sdl_checkpoints.pl` - Generate SDL checkpoints using `getblockmerkletree`
* ZeroMQ support has been removed from Hush * ZeroMQ support has been removed from Hush
# Hush 3.9.1 "Luciferous Locust" # Hush 3.9.1 "Luciferous Locust"

View File

@@ -240,6 +240,7 @@ BITCOIN_CORE_H = \
wallet/crypter.h \ wallet/crypter.h \
wallet/db.h \ wallet/db.h \
wallet/rpcwallet.h \ wallet/rpcwallet.h \
wallet/rpcwallet_internal.h \
wallet/rpchushwallet.h \ wallet/rpchushwallet.h \
wallet/wallet.h \ wallet/wallet.h \
wallet/wallet_ismine.h \ wallet/wallet_ismine.h \
@@ -277,7 +278,14 @@ libbitcoin_server_a_SOURCES = \
i2p.cpp \ i2p.cpp \
init.cpp \ init.cpp \
dbwrapper.cpp \ dbwrapper.cpp \
cJSON.c \
hush_cJSON.cpp \
hush_impl.cpp \
hush_nSPV_impl.cpp \
main.cpp \ main.cpp \
tx_validation.cpp \
mempool_accept.cpp \
block_processing.cpp \
merkleblock.cpp \ merkleblock.cpp \
metrics.h \ metrics.h \
miner.cpp \ miner.cpp \
@@ -322,8 +330,11 @@ libbitcoin_wallet_a_SOURCES = \
wallet/rpcdump.cpp \ wallet/rpcdump.cpp \
cc/CCtx.cpp \ cc/CCtx.cpp \
wallet/rpcwallet.cpp \ wallet/rpcwallet.cpp \
wallet/rpcwallet_zindex.cpp \
wallet/rpcwallet_zops.cpp \
wallet/rpchushwallet.cpp \ wallet/rpchushwallet.cpp \
wallet/wallet.cpp \ wallet/wallet.cpp \
wallet/wallet_keys.cpp \
wallet/wallet_ismine.cpp \ wallet/wallet_ismine.cpp \
wallet/walletdb.cpp \ wallet/walletdb.cpp \
zcash/zip32.cpp \ zcash/zip32.cpp \

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers
set -eo pipefail
hush_cli='./hush-cli'
./listassetchains | while read chain; do
$hush_cli --ac_name=$chain stop
done

4064
src/block_processing.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -50,6 +50,7 @@
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
#include <locale.h> #include <locale.h>
#include <stdbool.h>
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC visibility pop #pragma GCC visibility pop

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <memory.h> #include <memory.h>
#include "cJSON.c" #include "../../cJSON.c"
bits256 zeroid; bits256 zeroid;

View File

@@ -248,7 +248,7 @@ int32_t safecopy(char *dest,char *src,long len)
//#ifdef STANDALONE //#ifdef STANDALONE
//#include "../hush3/src/hush_cJSON.c" //#include "../hush3/src/hush_cJSON.c"
//#else //#else
#include "../hush_cJSON.c" #include "../../hush_cJSON.cpp"
//#endif //#endif
int32_t games_replay(uint64_t seed,int32_t sleeptime); int32_t games_replay(uint64_t seed,int32_t sleeptime);

View File

@@ -20,7 +20,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <memory.h> #include <memory.h>
#include "cJSON.c" #include "../../cJSON.c"
/* /*
NOTE: HUSH nor any Hush Arrakis Chain has any sprout outputs. This code is kept for historical and educational purposes. NOTE: HUSH nor any Hush Arrakis Chain has any sprout outputs. This code is kept for historical and educational purposes.

View File

@@ -1,255 +1,19 @@
// Copyright (c) 2016-2024 The Hush developers // Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying // Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
/* //
Copyright (c) 2009 Dave Gamble // This header now redirects to the canonical cJSON at src/cJSON.h + src/hush_cJSON.h.
// The old duplicate (2009 Dave Gamble fork) has been removed as part of cJSON deduplication.
Permission is hereby granted, free of charge, to any person obtaining a copy //
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#ifndef cJSON__ccih #ifndef cJSON__ccih
#define cJSON__ccih #define cJSON__ccih
#include <stdio.h> #include "../../cJSON.h"
#include <stdlib.h> #include "../../hush_cJSON.h"
#include <stdint.h>
#include <math.h>
#include <ctype.h>
#include <float.h>
#include <memory.h>
#include "../crypto777/OS_portable.h"
#ifndef SATOSHIDEN
#define SATOSHIDEN ((uint64_t)100000000L) #define SATOSHIDEN ((uint64_t)100000000L)
#define dstr(x) ((double)(x) / SATOSHIDEN) #define dstr(x) ((double)(x) / SATOSHIDEN)
#define MAX_JSON_FIELD 4096 // on the big side
#ifdef __cplusplus
extern "C"
{
#endif
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define is_cJSON_Null(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_NULL)
#define is_cJSON_Array(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Array)
#define is_cJSON_String(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_String)
#define is_cJSON_Number(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Number)
#define is_cJSON_Object(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Object)
#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True)
#define is_cJSON_False(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_False)
#define cJSON_IsReference 256
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int32_t type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int64_t valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
uint32_t cjsonid;
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(cJSON *item);
/* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int32_t item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int32_t b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(int64_t *numbers,int32_t count);
extern cJSON *cJSON_CreateFloatArray(float *numbers,int32_t count);
extern cJSON *cJSON_CreateDoubleArray(double *numbers,int32_t count);
extern cJSON *cJSON_CreateStringArray(char **strings,int32_t count);
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int32_t which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int32_t which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* Update array items. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int32_t which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int32_t recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int32_t require_null_terminated);
extern void cJSON_Minify(char *json);
/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
struct destbuf { char buf[MAX_JSON_FIELD]; };
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define jfieldstr get_cJSON_fieldname
char *cJSON_str(cJSON *json);
char *jstr(cJSON *json,char *field);
char *jprint(cJSON *json,int32_t freeflag);
int32_t jint(cJSON *json,char *field);
uint32_t juint(cJSON *json,char *field);
char *jstri(cJSON *json,int32_t i);
int32_t jinti(cJSON *json,int32_t i);
uint32_t juinti(cJSON *json,int32_t i);
uint64_t j64bitsi(cJSON *json,int32_t i);
double jdoublei(cJSON *json,int32_t i);
double jdouble(cJSON *json,char *field);
cJSON *jobj(cJSON *json,char *field);
cJSON *jarray(int32_t *nump,cJSON *json,char *field);
cJSON *jitem(cJSON *array,int32_t i);
uint64_t j64bits(cJSON *json,char *field);
void jadd(cJSON *json,char *field,cJSON *item);
void jaddstr(cJSON *json,char *field,char *str);
void jaddnum(cJSON *json,char *field,double num);
void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits);
void jaddi(cJSON *json,cJSON *item);
void jaddistr(cJSON *json,char *str);
void jaddinum(cJSON *json,double num);
void jaddi64bits(cJSON *json,uint64_t nxt64bits);
void jdelete(cJSON *object,char *string);
cJSON *jduplicate(cJSON *json);
int32_t jnum(cJSON *obj,char *field);
bits256 jbits256(cJSON *json,char *field);
bits256 jbits256i(cJSON *json,int32_t i);
void jaddbits256(cJSON *json,char *field,bits256 hash);
void jaddibits256(cJSON *json,bits256 hash);
void copy_cJSON(struct destbuf *dest,cJSON *obj);
void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj);
cJSON *gen_list_json(char **list);
int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field);
void free_json(cJSON *json);
int64_t _conv_cJSON_float(cJSON *json);
int64_t conv_cJSON_float(cJSON *json,char *field);
int64_t get_cJSON_int(cJSON *json,char *field);
void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis);
uint64_t get_satoshi_obj(cJSON *json,char *field);
int32_t get_API_int(cJSON *obj,int32_t val);
uint32_t get_API_uint(cJSON *obj,uint32_t val);
uint64_t get_API_nxt64bits(cJSON *obj);
double get_API_float(cJSON *obj);
char *get_cJSON_fieldname(cJSON *obj);
void ensure_jsonitem(cJSON *json,char *field,char *value);
int32_t in_jsonarray(cJSON *array,char *value);
char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params,int32_t timeout);
uint64_t calc_nxt64bits(const char *str);
int32_t expand_nxt64bits(char *str,uint64_t nxt64bits);
char *nxt64str(uint64_t nxt64bits);
char *nxt64str2(uint64_t nxt64bits);
cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num);
int32_t myatoi(char *str,int32_t range);
void cJSON_register(cJSON *item);
void cJSON_unregister(cJSON *item);
char *stringifyM(char *str);
#define replace_backslashquotes unstringify
char *unstringify(char *str);
#define jtrue cJSON_CreateTrue
#define jfalse cJSON_CreateFalse
#define jfieldname get_cJSON_fieldname
#ifdef __cplusplus
}
#endif #endif
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env bash
# Copyright 2016-2024 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
./hush-cli -ac_name=DRAGONX "$@"

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
DEFAULTS=""
# People can just use hushd going forward, but this script makes it
# more clear what is going on
HUSH="./hushd"
$HUSH $DEFAULTS "$@"

View File

@@ -27,6 +27,12 @@
#define HUSH_SMART_CHAINS_WAITNOTARIZE #define HUSH_SMART_CHAINS_WAITNOTARIZE
#define HUSH_PAXMAX (10000 * COIN) #define HUSH_PAXMAX (10000 * COIN)
extern int32_t NOTARIZED_HEIGHT; extern int32_t NOTARIZED_HEIGHT;
#ifdef HUSH_PRIVATE_IMPLEMENTATION
// ===================================================================
// Full implementation mode — only compiled via hush_impl.cpp
// ===================================================================
uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID; uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID;
#include <stdint.h> #include <stdint.h>
@@ -45,7 +51,7 @@ bool check_pprevnotarizedht();
#include "hush_globals.h" #include "hush_globals.h"
#include "hush_utils.h" #include "hush_utils.h"
#include "hush_curve25519.h" #include "hush_curve25519.h"
#include "hush_cJSON.c" #include "hush_cJSON.h"
#include "hush_bitcoind.h" #include "hush_bitcoind.h"
#include "hush_pax.h" #include "hush_pax.h"
#include "hush_notary.h" #include "hush_notary.h"
@@ -56,6 +62,9 @@ int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *de
#include "hush_events.h" #include "hush_events.h"
#include "hush_ccdata.h" #include "hush_ccdata.h"
// Need NSPV struct definitions for hush_currentheight() below
#include "hush_nSPV_defs.h"
void hush_currentheight_set(int32_t height) void hush_currentheight_set(int32_t height)
{ {
char symbol[HUSH_SMART_CHAIN_MAXLEN],dest[HUSH_SMART_CHAIN_MAXLEN]; struct hush_state *sp; char symbol[HUSH_SMART_CHAIN_MAXLEN],dest[HUSH_SMART_CHAIN_MAXLEN]; struct hush_state *sp;
@@ -980,4 +989,162 @@ int32_t hush_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block)
} }
} }
#else
// ===================================================================
// Declarations-only mode — for files that call hush functions
// This provides type info and function declarations without pulling
// in 14,000+ lines of implementation code.
// ===================================================================
extern uint256 NOTARIZED_HASH, NOTARIZED_DESTTXID;
#include <stdint.h>
#include <stdio.h>
#include <pthread.h>
// Struct/type declarations from hush_structs.h
#include "hush_structs.h"
// nSPV type definitions and forward declarations
#include "hush_nSPV_defs.h"
// Extern globals defined in hush_globals.h but missing from hush_defs.h
extern uint8_t ASSETCHAINS_BURN;
extern uint32_t ASSETCHAINS_MINOPRETURNFEE;
extern uint32_t HUSH_STOPAT;
extern int32_t HUSH_REWIND;
// Macros from implementation headers needed by callers
#define BURN_ADDRESS "RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY"
#ifndef SATOSHIDEN
#define SATOSHIDEN ((uint64_t)100000000L)
#endif
#ifndef dstr
#define dstr(x) ((double)(x) / SATOSHIDEN)
#endif
#define HUSH_NOTARIES_HEIGHT1 814000
// Forward declarations — hush.h implementation functions
void hush_currentheight_set(int32_t height);
int32_t hush_currentheight();
int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *dest);
int32_t hush_parsestatefiledata(struct hush_state *sp,uint8_t *filedata,long *fposp,long datalen,char *symbol,char *dest);
int32_t memread(void *dest,int32_t size,uint8_t *filedata,long *fposp,long datalen);
void hush_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t HUSHheight,uint32_t HUSHtimestamp,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout,uint256 MoM,int32_t MoMdepth);
int32_t hush_validate_chain(uint256 srchash,int32_t notarized_height);
int32_t hush_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen,int32_t height,uint256 txhash,int32_t i,int32_t j,uint64_t *voutmaskp,int32_t *specialtxp,int32_t *notarizedheightp,uint64_t value,int32_t notarized,uint64_t signedmask,uint32_t timestamp);
int32_t hush_notarycmp(uint8_t *scriptPubKey,int32_t scriptlen,uint8_t pubkeys[64][33],int32_t numnotaries,uint8_t rmd160[20]);
int32_t hush_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block);
// Forward declarations — hush_globals.h functions
int32_t hush_baseid(char *origbase);
uint64_t hush_current_supply(uint32_t nHeight);
std::string devtax_scriptpub_for_height(uint32_t nHeight);
std::string devtax_address_for_height(uint32_t nHeight);
// Forward declarations — hush_utils.h functions
void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen);
void calc_rmd160(char deprecated[41],uint8_t buf[20],uint8_t *msg,int32_t len);
uint32_t calc_crc32(uint32_t crc,const void *buf,size_t size);
void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen);
int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr);
char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
int32_t hush_is_issuer();
int32_t bitweight(uint64_t x);
int32_t _unhex(char c);
int32_t is_hexstr(char *str,int32_t n);
int32_t unhex(char c);
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
char hexbyte(int32_t c);
int32_t init_hexbytes_noT(char *hexbytes,unsigned char *message,long len);
char *bits256_str(char hexstr[65],bits256 x);
int32_t dragon_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
int32_t dragon_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp);
int32_t hush_scriptitemlen(int32_t *opretlenp,uint8_t *script);
uint64_t hush_block_prg(uint32_t nHeight);
int64_t hush_block_unlocktime(uint32_t nHeight);
long _stripwhite(char *buf,int accept);
char *clonestr(char *str);
int32_t safecopy(char *dest,char *src,long len);
char *parse_conf_line(char *line,char *field);
double OS_milliseconds();
void OS_randombytes(unsigned char *x,long xlen);
uint16_t _hush_userpass(char *username,char *password,FILE *fp);
void hush_statefname(char *fname,char *symbol,char *str);
void hush_configfile(char *symbol,uint16_t rpcport);
uint16_t hush_userpass(char *userpass,char *symbol);
uint32_t hush_smartmagic(char *symbol,uint64_t supply,uint8_t *extraptr,int32_t extralen);
uint16_t hush_smartport(uint32_t magic,int32_t extralen);
uint16_t hush_port(char *symbol,uint64_t supply,uint32_t *magicp,uint8_t *extraptr,int32_t extralen);
int32_t hush_whoami(char *pubkeystr,int32_t height,uint32_t timestamp);
uint64_t hush_max_money();
uint64_t hush_block_subsidy(int height);
uint64_t hush_sc_block_subsidy(int nHeight);
int8_t equihash_params_possible(uint64_t n, uint64_t k);
void hush_args(char *argv0);
void hush_nameset(char *symbol,char *dest,char *source);
void hush_prefetch(FILE *fp);
// Forward declarations — hush_bitcoind.h functions
struct hush_state *hush_stateptr(char *symbol,char *dest);
void hush_init(int32_t height);
int32_t hush_faststateinit(struct hush_state *sp,char *fname,char *symbol,char *dest);
int32_t hush_isrealtime(int32_t *hushheightp);
int32_t hush_longestchain();
uint64_t hush_paxtotal();
int32_t hush_block2height(CBlock *block);
int32_t hush_block2pubkey33(uint8_t *pubkey33,CBlock *block);
int32_t hush_blockload(CBlock& block, CBlockIndex *pindex);
CBlockIndex *hush_chainactive(int32_t height);
CBlockIndex *hush_getblockindex(uint256 hash);
uint32_t hush_chainactive_timestamp();
char *hush_issuemethod(char *userpass,char *method,char *params,uint16_t port);
int32_t hush_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
int32_t hush_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
bool hush_hardfork_active(uint32_t time);
// Forward declarations — hush_pax.h functions
void hush_paxpricefeed(int32_t height,uint8_t *pricefeed,int32_t len);
// Forward declarations — hush_notary.h functions
int32_t hush_notarized_height(int32_t *prevMoMheightp,uint256 *hashp,uint256 *txidp);
int32_t hush_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *hushtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *hushstartip,int32_t *hushendip);
int32_t hush_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp);
// Forward declarations — hush_gateway.h functions
int32_t hush_isPoS(CBlock *pblock,int32_t height,bool fJustCheck);
int32_t hush_checkPOW(int64_t stakeTxValue, int32_t slowflag, CBlock *pblock, int32_t height);
void hush_passport_iteration();
int32_t hush_opretvalidate(const CBlock *block,CBlockIndex *previndex,int32_t height,CScript scriptPubKey);
int32_t hush_scpublic(uint32_t tiptime);
int32_t hush_checknotarypay(CBlock *pblock,int32_t height);
int32_t hush_checkpoint(int32_t *notarized_heightp, int32_t nHeight, uint256 hash);
// Forward declarations — hush_bitcoind.h additional functions
uint64_t the_commission(const CBlock *pblock, int32_t height);
// Forward declarations — hush_events.h functions
void hush_eventadd_pubkeys(struct hush_state *sp,char *symbol,int32_t height,uint8_t num,uint8_t pubkeys[64][33]);
void hush_eventadd_pricefeed(struct hush_state *sp,char *symbol,int32_t height,uint32_t *prices,uint8_t num);
void hush_eventadd_opreturn(struct hush_state *sp,char *symbol,int32_t height,uint256 txid,uint64_t value,uint16_t vout,uint8_t *buf,uint16_t len);
void hush_eventadd_notarized(struct hush_state *sp,char *symbol,int32_t height,char *dest,uint256 notarized_hash,uint256 notarized_desttxid,int32_t notarizedheight,uint256 MoM,int32_t MoMdepth);
void hush_eventadd_hushheight(struct hush_state *sp,char *symbol,int32_t height,int32_t hushheight,uint32_t timestamp);
void hush_event_rewind(struct hush_state *sp,char *symbol,int32_t height);
// Forward declarations — hush_ccdata.h functions
void hush_rwccdata(char *symbol,int32_t rwflag,struct hush_ccdata *ccdata,struct hush_ccdataMoMoM *MoMoMdata);
void hush_purge_ccdata(int32_t height);
// Forward declarations — hush_kv.h / other
int32_t gettxout_scriptPubKey(uint8_t *scriptPubkey,int32_t maxsize,uint256 txid,int32_t n);
bool check_pprevnotarizedht();
// Forward declarations — nSPV functions (defined in hush_nSPV_*.h, compiled in hush_nSPV_impl.cpp)
void hush_nSPVreq(CNode *pfrom,std::vector<uint8_t> request);
void hush_nSPVresp(CNode *pfrom,std::vector<uint8_t> response);
void hush_nSPV(CNode *pto);
#endif // HUSH_PRIVATE_IMPLEMENTATION
#endif #endif

View File

@@ -25,10 +25,21 @@
/* cJSON */ /* cJSON */
/* JSON parser in C. */ /* JSON parser in C. */
#include <math.h> #include <math.h>
#include <string.h>
#include "cJSON.h" #include "cJSON.h"
#include "hush_cJSON.h" #include "hush_cJSON.h"
#include "cJSON.c"
// External dependencies (defined in hush_utils.h, compiled in hush_impl.cpp)
#ifndef SATOSHIDEN
#define SATOSHIDEN ((uint64_t)100000000L)
#define dstr(x) ((double)(x) / SATOSHIDEN)
#endif
long _stripwhite(char *buf, int accept);
char *clonestr(char *str);
int32_t decode_hex(uint8_t *bytes, int32_t n, char *hex);
char *bits256_str(char hexstr[65], bits256 x);
int32_t safecopy(char *dest, char *src, long len);
#ifndef DBL_EPSILON #ifndef DBL_EPSILON
#define DBL_EPSILON 2.2204460492503131E-16 #define DBL_EPSILON 2.2204460492503131E-16

29
src/hush_impl.cpp Normal file
View File

@@ -0,0 +1,29 @@
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
//
// hush_impl.cpp — Compilation unit for all hush_*.h implementation code.
//
// Previously, the hush implementation headers were #included directly
// into main.cpp (a "unity build" pattern), making main.o enormous and
// coupling everything into one translation unit. This file replaces
// that pattern: it includes hush.h with HUSH_PRIVATE_IMPLEMENTATION
// defined, which pulls in all the implementation headers and compiles
// them as a separate object file (hush_impl.o).
//
// main.cpp now includes hush.h WITHOUT HUSH_PRIVATE_IMPLEMENTATION,
// receiving only forward declarations.
// Standard project headers needed by hush implementation code
#include "main.h"
#include "notarizationdb.h"
#include "init.h"
#include "txdb.h"
#include "hush_nSPV_defs.h"
#include "wallet/asyncrpcoperation_sendmany.h"
#include "wallet/asyncrpcoperation_shieldcoinbase.h"
// Enable full implementation mode and HUSH_ZCASH compatibility flag
#define HUSH_PRIVATE_IMPLEMENTATION
#define HUSH_ZCASH
#include "hush.h"

38
src/hush_nSPV_impl.cpp Normal file
View File

@@ -0,0 +1,38 @@
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
//
// hush_nSPV_impl.cpp — Compilation unit for nSPV (simplified payment
// verification) implementation headers.
//
// Previously, the nSPV implementation headers were #included directly
// into main.cpp after hush.h. This file replaces that pattern by
// compiling them as a separate object (hush_nSPV_impl.o).
// Standard project headers needed by nSPV code
#include "main.h"
#include "notarizationdb.h"
#include "rpc/server.h"
#include "init.h"
#include "txdb.h"
#include "core_io.h"
#include "key_io.h"
#include "merkleblock.h"
#include "script/sign.h"
#include "cc/CCinclude.h"
#include "wallet/asyncrpcoperation_sendmany.h"
#include "wallet/asyncrpcoperation_shieldcoinbase.h"
// Forward declare functions defined in other compilation units
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
// hush.h in declarations-only mode gives us hush function declarations
// that nSPV code calls (dragon_rwnum, dragon_rwbignum, hush_notarized_height, etc.)
#include "hush.h"
// nSPV implementation headers — defines, structs, serialization, then fullnode/superlite/wallet
#include "hush_nSPV_defs.h"
#include "hush_nSPV.h"
#include "hush_nSPV_fullnode.h"
#include "hush_nSPV_superlite.h"
#include "hush_nSPV_wallet.h"

View File

@@ -1,10 +0,0 @@
#!/usr/bin/env python2
import os
import json
script_dir = os.path.dirname(__file__)
with open(script_dir + '/assetchains.json') as file:
assetchains = json.load(file)
for chain in assetchains:
print(chain['ac_name'])

File diff suppressed because it is too large Load Diff

View File

@@ -289,6 +289,14 @@ void PruneAndFlush();
/** (try to) add transaction to memory pool **/ /** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee=false, int dosLevel=-1); bool* pfMissingInputs, bool fRejectAbsurdFee=false, int dosLevel=-1);
bool CCTxFixAcceptToMemPoolUnchecked(CTxMemPool& pool, const CTransaction &tx);
bool myAddtomempool(CTransaction &tx, CValidationState *pstate, bool fSkipExpiry);
/** Orphan transaction management */
bool AddOrphanTx(const CTransaction& tx, NodeId peer);
void EraseOrphanTx(uint256 hash);
void EraseOrphansFor(NodeId peer);
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
struct CNodeStateStats { struct CNodeStateStats {
@@ -708,6 +716,8 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde
bool (*isInitBlockDownload)() = IsInitialBlockDownload,int32_t validateprices=1); bool (*isInitBlockDownload)() = IsInitialBlockDownload,int32_t validateprices=1);
/** Apply the effects of this transaction on the UTXO set represented by view */ /** Apply the effects of this transaction on the UTXO set represented by view */
class CTxUndo;
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Transaction validation functions */ /** Transaction validation functions */

83
src/main_internal.h Normal file
View File

@@ -0,0 +1,83 @@
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
//
// Internal shared state for main.cpp and block_processing.cpp
// These variables were previously in an anonymous namespace in main.cpp
// but need to be shared across translation units after splitting.
#ifndef HUSH_MAIN_INTERNAL_H
#define HUSH_MAIN_INTERNAL_H
#include "chain.h"
#include "sync.h"
#include "bloom.h"
#include "primitives/block.h"
#include "chainparams.h"
#include <set>
#include <map>
#include <list>
#include <vector>
#include <boost/smart_ptr/scoped_ptr.hpp>
struct CBlockIndexWorkComparator
{
bool operator()(CBlockIndex *pa, const CBlockIndex *pb) const {
// First sort by most total work, ...
if (pa->chainPower.chainWork > pb->chainPower.chainWork) return false;
if (pa->chainPower.chainWork < pb->chainPower.chainWork) return true;
// ... then by earliest time received, ...
if (pa->nSequenceId < pb->nSequenceId) return false;
if (pa->nSequenceId > pb->nSequenceId) return true;
// Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if (pa < pb) return false;
if (pa > pb) return true;
// Identical blocks.
return false;
}
};
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
CBlockIndex *pindex; //! Optional.
int64_t nTime; //! Time of "getdata" request in microseconds.
bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer)
};
// Shared block-processing state — defined in main.cpp
extern CBlockIndex *pindexBestInvalid;
extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
extern int nSyncStarted;
extern std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
extern CCriticalSection cs_LastBlockFile;
extern std::vector<CBlockFileInfo> vinfoBlockFile, tmpBlockFiles;
extern int nLastBlockFile;
extern int nLastTmpFile;
extern unsigned int maxTempFileSize0;
extern unsigned int maxTempFileSize1;
extern bool fCheckForPruning;
extern CCriticalSection cs_nBlockSequenceId;
extern uint32_t nBlockSequenceId;
extern std::map<uint256, NodeId> mapBlockSource;
extern boost::scoped_ptr<CRollingBloomFilter> recentRejects;
extern uint256 hashRecentRejectsChainTip;
extern std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight;
extern int nQueuedValidatedHeaders;
extern int nPreferredDownload;
extern std::set<CBlockIndex*> setDirtyBlockIndex;
extern std::set<int> setDirtyFileInfo;
#endif // HUSH_MAIN_INTERNAL_H

524
src/mempool_accept.cpp Normal file
View File

@@ -0,0 +1,524 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
//
// Mempool acceptance and orphan transaction management — extracted from main.cpp
// Functions: AddOrphanTx, EraseOrphanTx, EraseOrphansFor, LimitOrphanTxSize,
// GetMinRelayFee, AcceptToMemoryPool, CCTxFixAcceptToMemPoolUnchecked, myAddtomempool
#include "main.h"
#include "sodium.h"
#include "arith_uint256.h"
#include "chainparams.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
#include "key_io.h"
#include "metrics.h"
#include "net.h"
#include "script/interpreter.h"
#include "timedata.h"
#include "txdb.h"
#include "txmempool.h"
#include "undo.h"
#include "util.h"
#include "utilmoneystr.h"
#include "validationinterface.h"
#include "hush_defs.h"
#include "hush.h"
#include "librustzcash.h"
#include <cstring>
#include <algorithm>
#include <atomic>
#include <sstream>
#include <map>
#include <unordered_map>
#include <vector>
using namespace std;
extern int32_t HUSH_LOADINGBLOCKS,HUSH_LONGESTCHAIN,HUSH_INSYNC,HUSH_CONNECTING,HUSH_EXTRASATOSHI;
extern unsigned int expiryDelta;
extern CFeeRate minRelayTxFee;
extern bool fAddressIndex;
extern bool fSpentIndex;
extern const bool ishush3;
#define ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE 10000
// Orphan transaction data — defined in main.cpp
struct COrphanTx {
CTransaction tx;
NodeId fromPeer;
};
extern map<uint256, COrphanTx> mapOrphanTransactions;
extern map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
return false;
// Ignore big transactions, to avoid a
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// large transaction with a missing parent then we assume
// it will rebroadcast it later, after the parent transaction(s)
// have been mined or received.
// 10,000 orphans, each of which is at most 5,000 bytes big is
// at most 500 megabytes of orphans:
unsigned int sz = GetSerializeSize(tx, SER_NETWORK, tx.nVersion);
if (sz > 5000)
{
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
return false;
}
mapOrphanTransactions[hash].tx = tx;
mapOrphanTransactions[hash].fromPeer = peer;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(),
mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size());
return true;
}
void EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
return;
BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin)
{
map<uint256, set<uint256> >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash);
if (itPrev == mapOrphanTransactionsByPrev.end())
continue;
itPrev->second.erase(hash);
if (itPrev->second.empty())
mapOrphanTransactionsByPrev.erase(itPrev);
}
mapOrphanTransactions.erase(it);
}
void EraseOrphansFor(NodeId peer)
{
int nErased = 0;
map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
while (iter != mapOrphanTransactions.end())
{
map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer)
{
EraseOrphanTx(maybeErase->second.tx.GetHash());
++nErased;
}
}
if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer);
}
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans)
{
// Evict a random orphan:
uint256 randomhash = GetRandHash();
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
EraseOrphanTx(it->first);
++nEvicted;
}
return nEvicted;
}
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
{
{
LOCK(mempool.cs);
uint256 hash = tx.GetHash();
double dPriorityDelta = 0;
CAmount nFeeDelta = 0;
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
if (dPriorityDelta > 0 || nFeeDelta > 0)
return 0;
}
CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);
if (fAllowFree)
{
// There is a free transaction area in blocks created by most miners,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
nMinFee = 0;
}
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, int dosLevel)
{
AssertLockHeld(cs_main);
const uint32_t z2zTransitionWindow = 10;
const uint32_t z2zTransitionStart = 340000 - z2zTransitionWindow;
const uint32_t nHeight = chainActive.Height();
// This only applies to HUSH3, other chains can start off z2z via ac_private=1
if(ishush3) {
if((nHeight >= z2zTransitionStart) || (nHeight <= 340000)) {
// During the z2z transition window, only coinbase tx's as part of blocks are allowed
// Theory: We want an empty mempool at our fork block height, and the only way to assure that
// is to have an empty mempool for a few previous blocks, to take care of potential re-orgs
// and edge cases. This empty mempool assures there will be no transactions involving taddrs
// stuck in the mempool, when the z2z rule takes effect.
// Thanks to jl777 for helping design this
fprintf(stderr,"%s: rejecting all tx's during z2z transition window. Please retry after Block %d !!!\n", __func__,nHeight);
return false;
}
}
if (pfMissingInputs)
*pfMissingInputs = false;
uint32_t tiptime;
int flag=0,nextBlockHeight = chainActive.Height() + 1;
auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus());
if ( nextBlockHeight <= 1 || chainActive.LastTip() == 0 )
tiptime = (uint32_t)time(NULL);
else tiptime = (uint32_t)chainActive.LastTip()->nTime;
auto verifier = libzcash::ProofVerifier::Strict();
if (!CheckTransaction(tiptime,tx, state, verifier, 0, 0))
{
return error("AcceptToMemoryPool: CheckTransaction failed");
}
// Reject duplicate output proofs in a single ztx in mempool
// Migrate this to CheckTransaction() to make it a consensus requirement
{
set<libzcash::GrothProof> vSaplingOutputProof;
BOOST_FOREACH(const OutputDescription& output, tx.vShieldedOutput)
{
if (vSaplingOutputProof.count(output.zkproof))
return state.Invalid(error("AcceptToMemoryPool: duplicate output proof"),REJECT_DUPLICATE_OUTPUT_PROOF, "bad-txns-duplicate-output-proof");
vSaplingOutputProof.insert(output.zkproof);
}
}
// Reject duplicate spend proofs in a single ztx in mempool
// Migrate this to CheckTransaction() to make it a consensus requirement
{
set<libzcash::GrothProof> vSaplingSpendProof;
BOOST_FOREACH(const SpendDescription& spend, tx.vShieldedSpend)
{
if (vSaplingSpendProof.count(spend.zkproof))
return state.Invalid(error("AcceptToMemoryPool: duplicate spend proof"),REJECT_DUPLICATE_SPEND_PROOF, "bad-txns-duplicate-spend-proof");
vSaplingSpendProof.insert(spend.zkproof);
}
}
// DoS level set to 10 to be more forgiving.
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
if (!ContextualCheckTransaction(0,0,0,tx, state, nextBlockHeight, (dosLevel == -1) ? 10 : dosLevel))
{
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
}
//fprintf(stderr,"addmempool 2\n");
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
{
fprintf(stderr,"AcceptToMemoryPool coinbase as individual tx\n");
return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"),REJECT_INVALID, "coinbase");
}
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason;
if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight))
{
//
//fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\nscriptPubKey: %s\n",reason.c_str(),tx.vout[0].scriptPubKey.ToString().c_str());
return state.DoS(0,error("AcceptToMemoryPool: nonstandard transaction: %s", reason),REJECT_NONSTANDARD, reason);
}
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
{
//fprintf(stderr,"AcceptToMemoryPool reject non-final\n");
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
}
// is it already in the memory pool?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
{
//fprintf(stderr,"already in mempool\n");
return state.Invalid(false, REJECT_DUPLICATE, "already in mempool");
}
// Check for conflicts with in-memory transactions
{
LOCK(pool.cs); // protect pool.mapNextTx
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
COutPoint outpoint = tx.vin[i].prevout;
if (pool.mapNextTx.count(outpoint))
{
// Disable replacement feature for now
return false;
}
}
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
if (pool.nullifierExists(spendDescription.nullifier, SAPLING)) {
return false;
}
}
}
{
CCoinsView dummy;
CCoinsViewCache view(&dummy);
int64_t interest;
CAmount nValueIn = 0;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
// do we already have it?
if (view.HaveCoins(hash)) {
//fprintf(stderr,"view.HaveCoins(hash) error\n");
return state.Invalid(false, REJECT_DUPLICATE, "already have coins");
}
{
// do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
// and only helps with filling in pfMissingInputs (to determine missing vs spent).
BOOST_FOREACH(const CTxIn txin, tx.vin)
{
if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs)
*pfMissingInputs = true;
//fprintf(stderr,"missing inputs\n");
return false;
// https://github.com/zcash/zcash/blob/master/src/main.cpp#L1490
// state.DoS(0, error("AcceptToMemoryPool: tx inputs not found"),REJECT_INVALID, "bad-txns-inputs-missing");
}
}
// are the actual inputs available?
if (!view.HaveInputs(tx)) {
//fprintf(stderr,"accept failure. inputs-spent\n");
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),REJECT_DUPLICATE, "bad-txns-inputs-spent");
}
}
// are the zaddr requirements met?
if (!view.HaveShieldedRequirements(tx)) {
//fprintf(stderr,"accept failure. ztx reqs not met\n");
return state.Invalid(error("AcceptToMemoryPool: shielded requirements not met"),REJECT_DUPLICATE, "bad-txns-shielded-requirements-not-met");
}
// Bring the best block into scope
view.GetBestBlock();
nValueIn = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime);
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
}
// Check for non-standard pay-to-script-hash in inputs
if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId))
return error("AcceptToMemoryPool: reject nonstandard transaction input");
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
{
fprintf(stderr,"accept failure.4\n");
return state.DoS(1, error("AcceptToMemoryPool: too many sigops %s, %d > %d", hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
}
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
double dPriority = view.GetPriority(tx, chainActive.Height());
if ( nValueOut > 777777*COIN && HUSH_VALUETOOBIG(nValueOut - 777777*COIN) != 0 ) // some room for blockreward and txfees
return state.DoS(100, error("AcceptToMemoryPool: GetValueOut too big"),REJECT_INVALID,"tx valueout is too big");
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false;
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
const CCoins *coins = view.AccessCoins(txin.prevout.hash);
if (coins->IsCoinBase()) {
fSpendsCoinbase = true;
break;
}
}
// Grab the branch ID we expect this transaction to commit to. We don't
// yet know if it does, but if the entry gets added to the mempool, then
// it has passed ContextualCheckInputs and therefore this is correct.
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase, consensusBranchId);
unsigned int nSize = entry.GetTxSize();
// Accept a tx if it contains zspends and has at least the default fee specified by z_sendmany.
if (tx.vShieldedSpend.size() > 0 && nFees >= ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE) {
// In future we will we have more accurate and dynamic computation of fees, derpz
} else {
// Don't accept it if it can't get into a block, yallz
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee) {
//fprintf(stderr,"accept failure.5\n");
return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",hash.ToString(), nFees, txMinFee),REJECT_INSUFFICIENTFEE, "insufficient fee");
}
}
// Require that free transactions have sufficient priority to be mined in the next block.
if (GetBoolArg("-relaypriority", false) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
fprintf(stderr,"accept failure.6\n");
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) )
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();
LOCK(csFreeLimiter);
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
{
fprintf(stderr,"accept failure.7\n");
return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction");
}
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
fRejectAbsurdFee = false;
if ( fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000 && nFees > nValueOut/19)
// Disable checks for absurd fees when adding to the mempool. Instead, this check is done
// when a user attempts to make a transaction with an absurd fee and only rejects absurd
// fees when OP_RETURN data is NOT being used. This means users making normal financial
// transactions (z2z) are protected from absurd fees, it is only users who are storing
// arbitrary data via a z2t transaction are allowed to (or potentially required) to pay high fees
// It would be nice to detect the use of OP_RETURN right here but it seems to only be known
// inside of IsStandard() inside of IsStandardTx() and we want to avoid doing expensive checks
// multiple times.
{
string errmsg = strprintf("absurdly high fees %s, %d > %d",
hash.ToString(),
nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
LogPrint("mempool", errmsg.c_str());
return state.Error("AcceptToMemoryPool: " + errmsg);
}
//fprintf(stderr,"addmempool 6\n");
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata(tx);
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{
//fprintf(stderr,"accept failure.9\n");
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
}
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
// transactions to pass as valid when they're actually invalid. For
// instance the STRICTENC flag was incorrectly allowing certain
// CHECKSIG NOT scripts to pass, even though they were invalid.
//
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
// XXX: is this neccesary for CryptoConditions?
if ( HUSH_CONNECTING <= 0 && chainActive.LastTip() != 0 )
{
flag = 1;
HUSH_CONNECTING = (1<<30) + (int32_t)chainActive.LastTip()->GetHeight() + 1;
}
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{
if ( flag != 0 )
HUSH_CONNECTING = -1;
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
}
if ( flag != 0 )
HUSH_CONNECTING = -1;
{
LOCK(pool.cs);
// Store transaction in memory
pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
// Add memory address index
if (fAddressIndex) {
pool.addAddressIndex(entry, view);
}
// Add memory spent index
if (fSpentIndex) {
pool.addSpentIndex(entry, view);
}
}
}
return true;
}
bool CCTxFixAcceptToMemPoolUnchecked(CTxMemPool& pool, const CTransaction &tx)
{
// called from CheckBlock which is in cs_main and mempool.cs locks already.
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTxMemPoolEntry entry(tx, 0, GetTime(), 0, chainActive.Height(), mempool.HasNoInputsOf(tx), false, consensusBranchId);
//fprintf(stderr, "adding %s to mempool from block %d\n",tx.GetHash().ToString().c_str(),chainActive.GetHeight());
pool.addUnchecked(tx.GetHash(), entry, false);
return true;
}
bool myAddtomempool(CTransaction &tx, CValidationState *pstate, bool fSkipExpiry)
{
CValidationState state;
if (!pstate)
pstate = &state;
CTransaction Ltx; bool fMissingInputs,fOverrideFees = false;
if ( mempool.lookup(tx.GetHash(),Ltx) == 0 )
{
if ( !fSkipExpiry )
return(AcceptToMemoryPool(mempool, *pstate, tx, false, &fMissingInputs, !fOverrideFees, -1));
else
return(CCTxFixAcceptToMemPoolUnchecked(mempool,tx));
}
else return(true);
}

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env bash
# Copyright 2016-2024 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
./hush-cli -ac_name=TESTDRAGONX $@

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env bash
# Copyright 2016-2024 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
./hush-cli -ac_name=TESTEQUIHASH $@

1012
src/tx_validation.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
//
// Shared declarations for rpcwallet_*.cpp split files.
// These helper functions are defined in rpcwallet.cpp but called from other rpcwallet_*.cpp files.
#ifndef HUSH_WALLET_RPCWALLET_INTERNAL_H
#define HUSH_WALLET_RPCWALLET_INTERNAL_H
#include <string>
class UniValue;
class CPubKey;
// Macro used by multiple rpcwallet files — call-site must include main.h and hush_globals.h
#define THROW_IF_SYNCING(INSYNC) if (HUSH_TESTNODE == 0 && INSYNC == 0) { throw runtime_error(strprintf("%s: Extreme Privacy! Chain still syncing at height %d, aborting to prevent linkability analysis. Please wait until FULLY SYNCED and try again.",__FUNCTION__,chainActive.Tip()->GetHeight())); }
// Helper functions defined in rpcwallet.cpp
bool EnsureWalletIsAvailable(bool avoidException);
void EnsureWalletIsUnlocked();
std::string HelpRequiringPassphrase();
// Functions defined in rpcwallet_zops.cpp
UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
UniValue z_getoperationresult(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_getoperationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_shieldcoinbase(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_listoperationids(const UniValue& params, bool fHelp, const CPubKey& mypk);
// Functions defined in rpcwallet_zindex.cpp
UniValue getalldata(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_consolidationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_sweepstatus(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_listreceivedaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_listsentbyaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_anonsetblockdelta(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_anonsettxdelta(const UniValue& params, bool fHelp, const CPubKey& mypk);
UniValue z_getbalances(const UniValue& params, bool fHelp, const CPubKey& mypk);
#endif // HUSH_WALLET_RPCWALLET_INTERNAL_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -115,359 +115,6 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
return &(it->second); return &(it->second);
} }
// Generate a new Sapling spending key and return its public payment address
SaplingPaymentAddress CWallet::GenerateNewSaplingZKey(bool addToWallet)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
// Create new metadata
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
// Try to get the seed
HDSeed seed;
if (!GetHDSeed(seed))
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): HD seed not found");
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
uint32_t bip44CoinType = Params().BIP44CoinType();
// We use a fixed keypath scheme of m/32'/coin_type'/account'
// Derive m/32'
auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
// Derive m/32'/coin_type'
auto m_32h_cth = m_32h.Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT);
// Derive account key at next index, skip keys already known to the wallet
libzcash::SaplingExtendedSpendingKey xsk;
do
{
xsk = m_32h_cth.Derive(hdChain.saplingAccountCounter | ZIP32_HARDENED_KEY_LIMIT);
metadata.hdKeypath = "m/32'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(hdChain.saplingAccountCounter) + "'";
metadata.seedFp = hdChain.seedFp;
// Increment childkey index
hdChain.saplingAccountCounter++;
} while (HaveSaplingSpendingKey(xsk.expsk.full_viewing_key()));
// Update the chain model in the database
if (fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(hdChain))
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): Writing HD chain model failed");
auto ivk = xsk.expsk.full_viewing_key().in_viewing_key();
mapSaplingZKeyMetadata[ivk] = metadata;
auto addr = xsk.DefaultAddress();
if (addToWallet && !AddSaplingZKey(xsk, addr)) {
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): AddSaplingZKey failed");
}
// return default sapling payment address.
return addr;
}
// Add spending key to keystore
bool CWallet::AddSaplingZKey(
const libzcash::SaplingExtendedSpendingKey &sk,
const libzcash::SaplingPaymentAddress &defaultAddr)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
if (!CCryptoKeyStore::AddSaplingSpendingKey(sk, defaultAddr)) {
return false;
}
nTimeFirstKey = 1; // No birthday information for viewing keys.
if (!fFileBacked) {
return true;
}
if (!IsCrypted()) {
auto ivk = sk.expsk.full_viewing_key().in_viewing_key();
return CWalletDB(strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]);
}
return true;
}
// Add payment address -> incoming viewing key map entry
bool CWallet::AddSaplingIncomingViewingKey(
const libzcash::SaplingIncomingViewingKey &ivk,
const libzcash::SaplingPaymentAddress &addr)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
if (!CCryptoKeyStore::AddSaplingIncomingViewingKey(ivk, addr)) {
return false;
}
if (!fFileBacked) {
return true;
}
if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteSaplingPaymentAddress(addr, ivk);
}
return true;
}
CPubKey CWallet::GenerateNewKey()
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
CKey secret;
secret.MakeNewKey(fCompressed);
// Compressed public keys were introduced in version 0.6.0
if (fCompressed)
SetMinVersion(FEATURE_COMPRPUBKEY);
CPubKey pubkey = secret.GetPubKey();
assert(secret.VerifyPubKey(pubkey));
// Create new metadata
int64_t nCreationTime = GetTime();
mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
nTimeFirstKey = nCreationTime;
if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
return pubkey;
}
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false;
// check if we need to remove from watch-only
CScript script;
script = GetScriptForDestination(pubkey.GetID());
if (HaveWatchOnly(script))
RemoveWatchOnly(script);
if (!fFileBacked)
return true;
if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteKey(pubkey,
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
return true;
}
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
if (!fFileBacked)
return true;
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
}
return false;
}
bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::vector<unsigned char> &vchCryptedSecret,
const libzcash::SaplingPaymentAddress &defaultAddr)
{
if (!CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr))
return false;
if (!fFileBacked)
return true;
{
LOCK(cs_wallet);
if (pwalletdbEncryption) {
return pwalletdbEncryption->WriteCryptedSaplingZKey(extfvk,
vchCryptedSecret,
mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
} else {
return CWalletDB(strWalletFile).WriteCryptedSaplingZKey(extfvk,
vchCryptedSecret,
mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
}
}
return false;
}
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
nTimeFirstKey = meta.nCreateTime;
mapKeyMetadata[pubkey.GetID()] = meta;
return true;
}
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
bool CWallet::LoadCryptedSaplingZKey(
const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, extfvk.DefaultAddress());
}
bool CWallet::LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
mapSaplingZKeyMetadata[ivk] = meta;
return true;
}
bool CWallet::LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key)
{
return CCryptoKeyStore::AddSaplingSpendingKey(key, key.DefaultAddress());
}
bool CWallet::LoadSaplingPaymentAddress(
const libzcash::SaplingPaymentAddress &addr,
const libzcash::SaplingIncomingViewingKey &ivk)
{
return CCryptoKeyStore::AddSaplingIncomingViewingKey(ivk, addr);
}
bool CWallet::AddCScript(const CScript& redeemScript)
{
if (!CCryptoKeyStore::AddCScript(redeemScript))
return false;
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
}
bool CWallet::LoadCScript(const CScript& redeemScript)
{
/* A sanity check was added in pull #3843 to avoid adding redeemScripts
* that never can be redeemed. However, old wallets may still contain
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
std::string strAddr = EncodeDestination(CScriptID(redeemScript));
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
}
return CCryptoKeyStore::AddCScript(redeemScript);
}
bool CWallet::AddWatchOnly(const CScript &dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
nTimeFirstKey = 1; // No birthday information for watch-only keys.
NotifyWatchonlyChanged(true);
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteWatchOnly(dest);
}
bool CWallet::RemoveWatchOnly(const CScript &dest)
{
AssertLockHeld(cs_wallet);
if (!CCryptoKeyStore::RemoveWatchOnly(dest))
return false;
if (!HaveWatchOnly())
NotifyWatchonlyChanged(false);
if (fFileBacked)
if (!CWalletDB(strWalletFile).EraseWatchOnly(dest))
return false;
return true;
}
bool CWallet::LoadWatchOnly(const CScript &dest)
{
return CCryptoKeyStore::AddWatchOnly(dest);
}
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
CKeyingMaterial vMasterKey;
{
LOCK(cs_wallet);
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
continue; // try another master key
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
}
return false;
}
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
{
bool fWasLocked = IsLocked();
{
LOCK(cs_wallet);
Lock();
CCrypter crypter;
CKeyingMaterial vMasterKey;
BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
{
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000;
LogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
return false;
CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked)
Lock();
return true;
}
}
}
return false;
}
void CWallet::ChainTip(const CBlockIndex *pindex, void CWallet::ChainTip(const CBlockIndex *pindex,
const CBlock *pblock, const CBlock *pblock,
boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added) boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added)
@@ -1216,97 +863,6 @@ void CWallet::BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly)
} }
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
return false;
CKeyingMaterial vMasterKey;
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000;
LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
return false;
{
LOCK(cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
assert(!pwalletdbEncryption);
pwalletdbEncryption = new CWalletDB(strWalletFile);
if (!pwalletdbEncryption->TxnBegin()) {
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
return false;
}
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
{
if (fFileBacked) {
pwalletdbEncryption->TxnAbort();
delete pwalletdbEncryption;
}
// We now probably have half of our keys encrypted in memory, and half not...
// die and let the user reload the unencrypted wallet.
assert(false);
}
// Encryption was introduced in version 0.4.0
SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
if (fFileBacked)
{
if (!pwalletdbEncryption->TxnCommit()) {
delete pwalletdbEncryption;
// We now have keys encrypted in memory, but not on disk...
// die to avoid confusion and let the user reload the unencrypted wallet.
assert(false);
}
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
}
Lock();
Unlock(strWalletPassphrase);
NewKeyPool();
Lock();
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
CDB::Rewrite(strWalletFile);
}
NotifyStatusChanged(this);
return true;
}
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{ {
AssertLockHeld(cs_wallet); // nOrderPosNext AssertLockHeld(cs_wallet); // nOrderPosNext
@@ -2110,92 +1666,6 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
return nChange; return nChange;
} }
bool CWallet::IsHDFullyEnabled() const
{
// Only Sapling addresses are HD for now
return false;
}
void CWallet::GenerateNewSeed()
{
LOCK(cs_wallet);
auto seed = HDSeed::Random(HD_WALLET_SEED_LENGTH);
int64_t nCreationTime = GetTime();
// If the wallet is encrypted and locked, this will fail.
if (!SetHDSeed(seed))
throw std::runtime_error(std::string(__func__) + ": SetHDSeed failed");
// store the key creation time together with
// the child index counter in the database
// as a hdchain object
CHDChain newHdChain;
newHdChain.nVersion = CHDChain::VERSION_HD_BASE;
newHdChain.seedFp = seed.Fingerprint();
newHdChain.nCreateTime = nCreationTime;
SetHDChain(newHdChain, false);
}
bool CWallet::SetHDSeed(const HDSeed& seed)
{
if (!CCryptoKeyStore::SetHDSeed(seed)) {
return false;
}
if (!fFileBacked) {
return true;
}
{
LOCK(cs_wallet);
if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteHDSeed(seed);
}
}
return true;
}
bool CWallet::SetCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::SetCryptedHDSeed(seedFp, vchCryptedSecret)) {
return false;
}
if (!fFileBacked) {
return true;
}
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedHDSeed(seedFp, vchCryptedSecret);
else
return CWalletDB(strWalletFile).WriteCryptedHDSeed(seedFp, vchCryptedSecret);
}
return false;
}
void CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
if (!memonly && fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(chain))
throw std::runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain;
}
bool CWallet::LoadHDSeed(const HDSeed& seed)
{
return CBasicKeyStore::SetHDSeed(seed);
}
bool CWallet::LoadCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& seed)
{
return CCryptoKeyStore::SetCryptedHDSeed(seedFp, seed);
}
void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t &noteData) void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t &noteData)
{ {
mapSaplingNoteData.clear(); mapSaplingNoteData.clear();
@@ -4196,143 +3666,6 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
return true; return true;
} }
/**
* Mark old keypool keys as used,
* and generate all new keys
*/
bool CWallet::NewKeyPool()
{
{
LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile);
BOOST_FOREACH(int64_t nIndex, setKeyPool)
walletdb.ErasePool(nIndex);
setKeyPool.clear();
if (IsLocked())
return false;
int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0);
for (int i = 0; i < nKeys; i++)
{
int64_t nIndex = i+1;
walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
setKeyPool.insert(nIndex);
}
LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
}
return true;
}
bool CWallet::TopUpKeyPool(unsigned int kpSize)
{
{
LOCK(cs_wallet);
if (IsLocked())
return false;
CWalletDB walletdb(strWalletFile);
// Top up key pool
unsigned int nTargetSize;
if (kpSize > 0)
nTargetSize = kpSize;
else
nTargetSize = max(GetArg("-keypool", 100), (int64_t) 0);
while (setKeyPool.size() < (nTargetSize + 1))
{
int64_t nEnd = 1;
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
throw runtime_error("TopUpKeyPool(): writing generated key failed");
setKeyPool.insert(nEnd);
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
}
}
return true;
}
void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
{
LOCK(cs_wallet);
if (!IsLocked())
TopUpKeyPool();
// Get the oldest key
if(setKeyPool.empty())
return;
CWalletDB walletdb(strWalletFile);
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool(): read failed");
if (!HaveKey(keypool.vchPubKey.GetID()))
throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
assert(keypool.vchPubKey.IsValid());
//LogPrintf("keypool reserve %d\n", nIndex);
}
}
void CWallet::KeepKey(int64_t nIndex)
{
// Remove from key pool
if (fFileBacked)
{
CWalletDB walletdb(strWalletFile);
walletdb.ErasePool(nIndex);
}
LogPrintf("keypool keep %d\n", nIndex);
}
void CWallet::ReturnKey(int64_t nIndex)
{
// Return to key pool
{
LOCK(cs_wallet);
setKeyPool.insert(nIndex);
}
//LogPrintf("keypool return %d\n", nIndex);
}
bool CWallet::GetKeyFromPool(CPubKey& result)
{
int64_t nIndex = 0;
CKeyPool keypool;
{
LOCK(cs_wallet);
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
{
if (IsLocked()) return false;
result = GenerateNewKey();
return true;
}
KeepKey(nIndex);
result = keypool.vchPubKey;
}
return true;
}
int64_t CWallet::GetOldestKeyPoolTime()
{
int64_t nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
return GetTime();
ReturnKey(nIndex);
return keypool.nTime;
}
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{ {
map<CTxDestination, CAmount> balances; map<CTxDestination, CAmount> balances;
@@ -4480,59 +3813,6 @@ std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAcco
return result; return result;
} }
bool CReserveKey::GetReservedKey(CPubKey& pubkey)
{
if (nIndex == -1)
{
CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex != -1)
vchPubKey = keypool.vchPubKey;
else {
return false;
}
}
assert(vchPubKey.IsValid());
pubkey = vchPubKey;
return true;
}
void CReserveKey::KeepKey()
{
if (nIndex != -1)
pwallet->KeepKey(nIndex);
nIndex = -1;
vchPubKey = CPubKey();
}
void CReserveKey::ReturnKey()
{
if (nIndex != -1)
pwallet->ReturnKey(nIndex);
nIndex = -1;
vchPubKey = CPubKey();
}
void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
setAddress.clear();
CWalletDB walletdb(strWalletFile);
LOCK2(cs_main, cs_wallet);
BOOST_FOREACH(const int64_t& id, setKeyPool)
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
throw runtime_error("GetAllReserveKeyHashes(): read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID))
throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
setAddress.insert(keyID);
}
}
void CWallet::UpdatedTransaction(const uint256 &hashTx) void CWallet::UpdatedTransaction(const uint256 &hashTx)
{ {
{ {
@@ -4616,96 +3896,6 @@ std::vector<SaplingOutPoint> CWallet::ListLockedSaplingNotes()
/** @} */ // end of Actions /** @} */ // end of Actions
class CAffectedKeysVisitor : public boost::static_visitor<void> {
private:
const CKeyStore &keystore;
std::vector<CKeyID> &vKeys;
public:
CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
void Process(const CScript &script) {
txnouttype type;
std::vector<CTxDestination> vDest;
int nRequired;
if (ExtractDestinations(script, type, vDest, nRequired)) {
BOOST_FOREACH(const CTxDestination &dest, vDest)
boost::apply_visitor(*this, dest);
}
}
void operator()(const CKeyID &keyId) {
if (keystore.HaveKey(keyId))
vKeys.push_back(keyId);
}
void operator()(const CPubKey &key) {
CKeyID keyId = key.GetID();
if (keystore.HaveKey(keyId))
vKeys.push_back(keyId);
}
void operator()(const CScriptID &scriptId) {
CScript script;
if (keystore.GetCScript(scriptId, script))
Process(script);
}
void operator()(const CNoDestination &none) {}
};
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
AssertLockHeld(cs_wallet); // mapKeyMetadata
mapKeyBirth.clear();
// get birth times for keys with metadata
for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
if (it->second.nCreateTime)
mapKeyBirth[it->first] = it->second.nCreateTime;
// map in which we'll infer heights of other keys
CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
std::set<CKeyID> setKeys;
GetKeys(setKeys);
BOOST_FOREACH(const CKeyID &keyid, setKeys) {
if (mapKeyBirth.count(keyid) == 0)
mapKeyFirstBlock[keyid] = pindexMax;
}
setKeys.clear();
// if there are no such keys, we're done
if (mapKeyFirstBlock.empty())
return;
// find first block that affects those keys, if there are any left
std::vector<CKeyID> vAffected;
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
// iterate over all wallet transactions...
const CWalletTx &wtx = (*it).second;
BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
int nHeight = blit->second->GetHeight();
BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
// iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
BOOST_FOREACH(const CKeyID &keyid, vAffected) {
// ... and all their affected keys
std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->GetHeight())
rit->second = blit->second;
}
vAffected.clear();
}
}
}
// Extract block timestamps for those keys
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
}
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value) bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
{ {
if (boost::get<CNoDestination>(&dest)) if (boost::get<CNoDestination>(&dest))
@@ -4951,109 +4141,3 @@ void CWallet::GetFilteredNotes(
} }
} }
} }
//
// Shielded key and address generalizations
//
bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingIncomingViewingKey ivk;
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk);
}
bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
{
return false;
}
bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingIncomingViewingKey ivk;
// If we have a SaplingExtendedSpendingKey in the wallet, then we will
// also have the corresponding SaplingFullViewingKey.
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
m_wallet->HaveSaplingFullViewingKey(ivk);
}
bool PaymentAddressBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
{
return false;
}
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingIncomingViewingKey ivk;
libzcash::SaplingFullViewingKey fvk;
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
m_wallet->GetSaplingFullViewingKey(ivk, fvk) &&
m_wallet->HaveSaplingSpendingKey(fvk);
}
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::InvalidEncoding& no) const
{
return false;
}
boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingExtendedSpendingKey extsk;
if (m_wallet->GetSaplingExtendedSpendingKey(zaddr, extsk)) {
return libzcash::SpendingKey(extsk);
} else {
return boost::none;
}
}
boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
const libzcash::InvalidEncoding& no) const
{
// Defaults to InvalidEncoding
return libzcash::SpendingKey();
}
SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
auto fvk = sk.expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto addr = sk.DefaultAddress();
{
if (log){
LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
}
// Don't throw error in case a key is already there
if (m_wallet->HaveSaplingSpendingKey(fvk)) {
return KeyAlreadyExists;
} else {
if (!m_wallet-> AddSaplingZKey(sk, addr)) {
return KeyNotAdded;
}
// Sapling addresses can't have been used in transactions prior to activation.
if (params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight == Consensus::NetworkUpgrade::ALWAYS_ACTIVE) {
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = nTime;
} else {
// TODO: set a better time for HUSH+DRAGONX
// 154051200 seconds from epoch is Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = std::max((int64_t) 154051200, nTime);
}
if (hdKeypath) {
m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.get();
}
if (seedFpStr) {
uint256 seedFp;
seedFp.SetHex(seedFpStr.get());
m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp;
}
return KeyAdded;
}
}
}
SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
}

975
src/wallet/wallet_keys.cpp Normal file
View File

@@ -0,0 +1,975 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
// Key management, encryption, HD wallet, and keypool operations
// Split from wallet.cpp to separate key management from transaction logic
#include "wallet/wallet.h"
#include "key_io.h"
#include "main.h"
#include "rpc/protocol.h"
#include "script/script.h"
#include "script/sign.h"
#include "crypter.h"
#include "consensus/upgrades.h"
#include "zcash/zip32.h"
#include <assert.h>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
using namespace std;
using namespace libzcash;
//
// Key generation and management
//
// Generate a new Sapling spending key and return its public payment address
SaplingPaymentAddress CWallet::GenerateNewSaplingZKey(bool addToWallet)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
// Create new metadata
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
// Try to get the seed
HDSeed seed;
if (!GetHDSeed(seed))
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): HD seed not found");
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
uint32_t bip44CoinType = Params().BIP44CoinType();
// We use a fixed keypath scheme of m/32'/coin_type'/account'
// Derive m/32'
auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
// Derive m/32'/coin_type'
auto m_32h_cth = m_32h.Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT);
// Derive account key at next index, skip keys already known to the wallet
libzcash::SaplingExtendedSpendingKey xsk;
do
{
xsk = m_32h_cth.Derive(hdChain.saplingAccountCounter | ZIP32_HARDENED_KEY_LIMIT);
metadata.hdKeypath = "m/32'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(hdChain.saplingAccountCounter) + "'";
metadata.seedFp = hdChain.seedFp;
// Increment childkey index
hdChain.saplingAccountCounter++;
} while (HaveSaplingSpendingKey(xsk.expsk.full_viewing_key()));
// Update the chain model in the database
if (fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(hdChain))
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): Writing HD chain model failed");
auto ivk = xsk.expsk.full_viewing_key().in_viewing_key();
mapSaplingZKeyMetadata[ivk] = metadata;
auto addr = xsk.DefaultAddress();
if (addToWallet && !AddSaplingZKey(xsk, addr)) {
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): AddSaplingZKey failed");
}
// return default sapling payment address.
return addr;
}
// Add spending key to keystore
bool CWallet::AddSaplingZKey(
const libzcash::SaplingExtendedSpendingKey &sk,
const libzcash::SaplingPaymentAddress &defaultAddr)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
if (!CCryptoKeyStore::AddSaplingSpendingKey(sk, defaultAddr)) {
return false;
}
nTimeFirstKey = 1; // No birthday information for viewing keys.
if (!fFileBacked) {
return true;
}
if (!IsCrypted()) {
auto ivk = sk.expsk.full_viewing_key().in_viewing_key();
return CWalletDB(strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]);
}
return true;
}
// Add payment address -> incoming viewing key map entry
bool CWallet::AddSaplingIncomingViewingKey(
const libzcash::SaplingIncomingViewingKey &ivk,
const libzcash::SaplingPaymentAddress &addr)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
if (!CCryptoKeyStore::AddSaplingIncomingViewingKey(ivk, addr)) {
return false;
}
if (!fFileBacked) {
return true;
}
if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteSaplingPaymentAddress(addr, ivk);
}
return true;
}
CPubKey CWallet::GenerateNewKey()
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
CKey secret;
secret.MakeNewKey(fCompressed);
// Compressed public keys were introduced in version 0.6.0
if (fCompressed)
SetMinVersion(FEATURE_COMPRPUBKEY);
CPubKey pubkey = secret.GetPubKey();
assert(secret.VerifyPubKey(pubkey));
// Create new metadata
int64_t nCreationTime = GetTime();
mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
nTimeFirstKey = nCreationTime;
if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
return pubkey;
}
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false;
// check if we need to remove from watch-only
CScript script;
script = GetScriptForDestination(pubkey.GetID());
if (HaveWatchOnly(script))
RemoveWatchOnly(script);
if (!fFileBacked)
return true;
if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteKey(pubkey,
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
return true;
}
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
if (!fFileBacked)
return true;
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
}
return false;
}
bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::vector<unsigned char> &vchCryptedSecret,
const libzcash::SaplingPaymentAddress &defaultAddr)
{
if (!CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr))
return false;
if (!fFileBacked)
return true;
{
LOCK(cs_wallet);
if (pwalletdbEncryption) {
return pwalletdbEncryption->WriteCryptedSaplingZKey(extfvk,
vchCryptedSecret,
mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
} else {
return CWalletDB(strWalletFile).WriteCryptedSaplingZKey(extfvk,
vchCryptedSecret,
mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
}
}
return false;
}
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
nTimeFirstKey = meta.nCreateTime;
mapKeyMetadata[pubkey.GetID()] = meta;
return true;
}
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
bool CWallet::LoadCryptedSaplingZKey(
const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, extfvk.DefaultAddress());
}
bool CWallet::LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
mapSaplingZKeyMetadata[ivk] = meta;
return true;
}
bool CWallet::LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key)
{
return CCryptoKeyStore::AddSaplingSpendingKey(key, key.DefaultAddress());
}
bool CWallet::LoadSaplingPaymentAddress(
const libzcash::SaplingPaymentAddress &addr,
const libzcash::SaplingIncomingViewingKey &ivk)
{
return CCryptoKeyStore::AddSaplingIncomingViewingKey(ivk, addr);
}
bool CWallet::AddCScript(const CScript& redeemScript)
{
if (!CCryptoKeyStore::AddCScript(redeemScript))
return false;
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
}
bool CWallet::LoadCScript(const CScript& redeemScript)
{
/* A sanity check was added in pull #3843 to avoid adding redeemScripts
* that never can be redeemed. However, old wallets may still contain
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
std::string strAddr = EncodeDestination(CScriptID(redeemScript));
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
}
return CCryptoKeyStore::AddCScript(redeemScript);
}
bool CWallet::AddWatchOnly(const CScript &dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
nTimeFirstKey = 1; // No birthday information for watch-only keys.
NotifyWatchonlyChanged(true);
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteWatchOnly(dest);
}
bool CWallet::RemoveWatchOnly(const CScript &dest)
{
AssertLockHeld(cs_wallet);
if (!CCryptoKeyStore::RemoveWatchOnly(dest))
return false;
if (!HaveWatchOnly())
NotifyWatchonlyChanged(false);
if (fFileBacked)
if (!CWalletDB(strWalletFile).EraseWatchOnly(dest))
return false;
return true;
}
bool CWallet::LoadWatchOnly(const CScript &dest)
{
return CCryptoKeyStore::AddWatchOnly(dest);
}
//
// Wallet encryption and passphrase management
//
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
CKeyingMaterial vMasterKey;
{
LOCK(cs_wallet);
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
continue; // try another master key
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
}
return false;
}
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
{
bool fWasLocked = IsLocked();
{
LOCK(cs_wallet);
Lock();
CCrypter crypter;
CKeyingMaterial vMasterKey;
BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
{
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000;
LogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
return false;
CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked)
Lock();
return true;
}
}
}
return false;
}
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
return false;
CKeyingMaterial vMasterKey;
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000;
LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
return false;
{
LOCK(cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
assert(!pwalletdbEncryption);
pwalletdbEncryption = new CWalletDB(strWalletFile);
if (!pwalletdbEncryption->TxnBegin()) {
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
return false;
}
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
{
if (fFileBacked) {
pwalletdbEncryption->TxnAbort();
delete pwalletdbEncryption;
}
// We now probably have half of our keys encrypted in memory, and half not...
// die and let the user reload the unencrypted wallet.
assert(false);
}
// Encryption was introduced in version 0.4.0
SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
if (fFileBacked)
{
if (!pwalletdbEncryption->TxnCommit()) {
delete pwalletdbEncryption;
// We now have keys encrypted in memory, but not on disk...
// die to avoid confusion and let the user reload the unencrypted wallet.
assert(false);
}
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
}
Lock();
Unlock(strWalletPassphrase);
NewKeyPool();
Lock();
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
CDB::Rewrite(strWalletFile);
}
NotifyStatusChanged(this);
return true;
}
//
// HD wallet seed management
//
bool CWallet::IsHDFullyEnabled() const
{
// Only Sapling addresses are HD for now
return false;
}
void CWallet::GenerateNewSeed()
{
LOCK(cs_wallet);
auto seed = HDSeed::Random(HD_WALLET_SEED_LENGTH);
int64_t nCreationTime = GetTime();
// If the wallet is encrypted and locked, this will fail.
if (!SetHDSeed(seed))
throw std::runtime_error(std::string(__func__) + ": SetHDSeed failed");
// store the key creation time together with
// the child index counter in the database
// as a hdchain object
CHDChain newHdChain;
newHdChain.nVersion = CHDChain::VERSION_HD_BASE;
newHdChain.seedFp = seed.Fingerprint();
newHdChain.nCreateTime = nCreationTime;
SetHDChain(newHdChain, false);
}
bool CWallet::SetHDSeed(const HDSeed& seed)
{
if (!CCryptoKeyStore::SetHDSeed(seed)) {
return false;
}
if (!fFileBacked) {
return true;
}
{
LOCK(cs_wallet);
if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteHDSeed(seed);
}
}
return true;
}
bool CWallet::SetCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::SetCryptedHDSeed(seedFp, vchCryptedSecret)) {
return false;
}
if (!fFileBacked) {
return true;
}
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedHDSeed(seedFp, vchCryptedSecret);
else
return CWalletDB(strWalletFile).WriteCryptedHDSeed(seedFp, vchCryptedSecret);
}
return false;
}
void CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
if (!memonly && fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(chain))
throw std::runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain;
}
bool CWallet::LoadHDSeed(const HDSeed& seed)
{
return CBasicKeyStore::SetHDSeed(seed);
}
bool CWallet::LoadCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& seed)
{
return CCryptoKeyStore::SetCryptedHDSeed(seedFp, seed);
}
//
// Key pool management
//
bool CWallet::NewKeyPool()
{
{
LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile);
BOOST_FOREACH(int64_t nIndex, setKeyPool)
walletdb.ErasePool(nIndex);
setKeyPool.clear();
if (IsLocked())
return false;
int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0);
for (int i = 0; i < nKeys; i++)
{
int64_t nIndex = i+1;
walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
setKeyPool.insert(nIndex);
}
LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
}
return true;
}
bool CWallet::TopUpKeyPool(unsigned int kpSize)
{
{
LOCK(cs_wallet);
if (IsLocked())
return false;
CWalletDB walletdb(strWalletFile);
// Top up key pool
unsigned int nTargetSize;
if (kpSize > 0)
nTargetSize = kpSize;
else
nTargetSize = max(GetArg("-keypool", 100), (int64_t) 0);
while (setKeyPool.size() < (nTargetSize + 1))
{
int64_t nEnd = 1;
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
throw runtime_error("TopUpKeyPool(): writing generated key failed");
setKeyPool.insert(nEnd);
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
}
}
return true;
}
void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
{
LOCK(cs_wallet);
if (!IsLocked())
TopUpKeyPool();
// Get the oldest key
if(setKeyPool.empty())
return;
CWalletDB walletdb(strWalletFile);
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool(): read failed");
if (!HaveKey(keypool.vchPubKey.GetID()))
throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
assert(keypool.vchPubKey.IsValid());
//LogPrintf("keypool reserve %d\n", nIndex);
}
}
void CWallet::KeepKey(int64_t nIndex)
{
// Remove from key pool
if (fFileBacked)
{
CWalletDB walletdb(strWalletFile);
walletdb.ErasePool(nIndex);
}
LogPrintf("keypool keep %d\n", nIndex);
}
void CWallet::ReturnKey(int64_t nIndex)
{
// Return to key pool
{
LOCK(cs_wallet);
setKeyPool.insert(nIndex);
}
//LogPrintf("keypool return %d\n", nIndex);
}
bool CWallet::GetKeyFromPool(CPubKey& result)
{
int64_t nIndex = 0;
CKeyPool keypool;
{
LOCK(cs_wallet);
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
{
if (IsLocked()) return false;
result = GenerateNewKey();
return true;
}
KeepKey(nIndex);
result = keypool.vchPubKey;
}
return true;
}
int64_t CWallet::GetOldestKeyPoolTime()
{
int64_t nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
return GetTime();
ReturnKey(nIndex);
return keypool.nTime;
}
//
// CReserveKey
//
bool CReserveKey::GetReservedKey(CPubKey& pubkey)
{
if (nIndex == -1)
{
CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex != -1)
vchPubKey = keypool.vchPubKey;
else {
return false;
}
}
assert(vchPubKey.IsValid());
pubkey = vchPubKey;
return true;
}
void CReserveKey::KeepKey()
{
if (nIndex != -1)
pwallet->KeepKey(nIndex);
nIndex = -1;
vchPubKey = CPubKey();
}
void CReserveKey::ReturnKey()
{
if (nIndex != -1)
pwallet->ReturnKey(nIndex);
nIndex = -1;
vchPubKey = CPubKey();
}
void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
setAddress.clear();
CWalletDB walletdb(strWalletFile);
LOCK2(cs_main, cs_wallet);
BOOST_FOREACH(const int64_t& id, setKeyPool)
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
throw runtime_error("GetAllReserveKeyHashes(): read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID))
throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
setAddress.insert(keyID);
}
}
//
// Key birth times
//
class CAffectedKeysVisitor : public boost::static_visitor<void> {
private:
const CKeyStore &keystore;
std::vector<CKeyID> &vKeys;
public:
CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
void Process(const CScript &script) {
txnouttype type;
std::vector<CTxDestination> vDest;
int nRequired;
if (ExtractDestinations(script, type, vDest, nRequired)) {
BOOST_FOREACH(const CTxDestination &dest, vDest)
boost::apply_visitor(*this, dest);
}
}
void operator()(const CKeyID &keyId) {
if (keystore.HaveKey(keyId))
vKeys.push_back(keyId);
}
void operator()(const CPubKey &key) {
CKeyID keyId = key.GetID();
if (keystore.HaveKey(keyId))
vKeys.push_back(keyId);
}
void operator()(const CScriptID &scriptId) {
CScript script;
if (keystore.GetCScript(scriptId, script))
Process(script);
}
void operator()(const CNoDestination &none) {}
};
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
AssertLockHeld(cs_wallet); // mapKeyMetadata
mapKeyBirth.clear();
// get birth times for keys with metadata
for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
if (it->second.nCreateTime)
mapKeyBirth[it->first] = it->second.nCreateTime;
// map in which we'll infer heights of other keys
CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
std::set<CKeyID> setKeys;
GetKeys(setKeys);
BOOST_FOREACH(const CKeyID &keyid, setKeys) {
if (mapKeyBirth.count(keyid) == 0)
mapKeyFirstBlock[keyid] = pindexMax;
}
setKeys.clear();
// if there are no such keys, we're done
if (mapKeyFirstBlock.empty())
return;
// find first block that affects those keys, if there are any left
std::vector<CKeyID> vAffected;
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
// iterate over all wallet transactions...
const CWalletTx &wtx = (*it).second;
BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
int nHeight = blit->second->GetHeight();
BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
// iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
BOOST_FOREACH(const CKeyID &keyid, vAffected) {
// ... and all their affected keys
std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->GetHeight())
rit->second = blit->second;
}
vAffected.clear();
}
}
}
// Extract block timestamps for those keys
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
}
//
// Shielded key and address generalizations
//
bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingIncomingViewingKey ivk;
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk);
}
bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
{
return false;
}
bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingIncomingViewingKey ivk;
// If we have a SaplingExtendedSpendingKey in the wallet, then we will
// also have the corresponding SaplingFullViewingKey.
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
m_wallet->HaveSaplingFullViewingKey(ivk);
}
bool PaymentAddressBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
{
return false;
}
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingIncomingViewingKey ivk;
libzcash::SaplingFullViewingKey fvk;
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
m_wallet->GetSaplingFullViewingKey(ivk, fvk) &&
m_wallet->HaveSaplingSpendingKey(fvk);
}
bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::InvalidEncoding& no) const
{
return false;
}
boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingExtendedSpendingKey extsk;
if (m_wallet->GetSaplingExtendedSpendingKey(zaddr, extsk)) {
return libzcash::SpendingKey(extsk);
} else {
return boost::none;
}
}
boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
const libzcash::InvalidEncoding& no) const
{
// Defaults to InvalidEncoding
return libzcash::SpendingKey();
}
SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
auto fvk = sk.expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto addr = sk.DefaultAddress();
{
if (log){
LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
}
// Don't throw error in case a key is already there
if (m_wallet->HaveSaplingSpendingKey(fvk)) {
return KeyAlreadyExists;
} else {
if (!m_wallet-> AddSaplingZKey(sk, addr)) {
return KeyNotAdded;
}
// Sapling addresses can't have been used in transactions prior to activation.
if (params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight == Consensus::NetworkUpgrade::ALWAYS_ACTIVE) {
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = nTime;
} else {
// TODO: set a better time for HUSH+DRAGONX
// 154051200 seconds from epoch is Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = std::max((int64_t) 154051200, nTime);
}
if (hdKeypath) {
m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.get();
}
if (seedFpStr) {
uint256 seedFp;
seedFp.SetHex(seedFpStr.get());
m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp;
}
return KeyAdded;
}
}
}
SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
}

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
NAME=ZUSH
CLI=${HUSHCLI:-./hush-cli}
if [ -f $CLI ]; then
$CLI -ac_name=$NAME "$@"
fi

View File

@@ -82,10 +82,10 @@ cp $SRC_PATH/src/hush-tx $DEB_BIN
strip $DEB_BIN/hush-tx strip $DEB_BIN/hush-tx
# these are scripts and don't require a strip # these are scripts and don't require a strip
cp $SRC_PATH/src/dragonx-cli $DEB_BIN cp $SRC_PATH/contrib/scripts/dragonx-cli $DEB_BIN
cp $SRC_PATH/src/dragonxd $DEB_BIN cp $SRC_PATH/contrib/scripts/dragonxd $DEB_BIN
cp $SRC_PATH/src/hush-arrakis-chain $DEB_BIN cp $SRC_PATH/contrib/scripts/hush-arrakis-chain $DEB_BIN
cp $SRC_DEB/changelog $DEB_DOC cp $SRC_DEB/changelog $DEB_DOC
cp $SRC_DEB/copyright $DEB_DOC cp $SRC_DEB/copyright $DEB_DOC
cp -r $SRC_DEB/examples $DEB_DOC cp -r $SRC_DEB/examples $DEB_DOC

View File

@@ -97,3 +97,34 @@ CXXFLAGS="${EXTRA_CXXFLAGS} -I$PREFIX/include" \
./configure --prefix="${PREFIX}" --with-gui=no "$HARDENING_ARG" "$LCOV_ARG" ./configure --prefix="${PREFIX}" --with-gui=no "$HARDENING_ARG" "$LCOV_ARG"
make "$@" V=1 NO_GTEST=1 STATIC=1 make "$@" V=1 NO_GTEST=1 STATIC=1
# Package release
echo "Creating macOS release package..."
VERSION=$(grep -oP 'define\(_CLIENT_VERSION.*?,\s*\K[0-9]+' configure.ac | head -3 | tr '\n' '.' | sed 's/\.$//')
VERSION=${VERSION:-3.10.5}
RELEASE_DIR="release/${VERSION}-mac"
mkdir -p "$RELEASE_DIR"
# Strip binaries
strip src/hushd src/hush-cli src/hush-tx 2>/dev/null || true
# Copy binaries
cp src/hushd src/hush-cli src/hush-tx "$RELEASE_DIR/"
# Copy wrapper scripts
cp contrib/scripts/hush-arrakis-chain contrib/scripts/dragonxd contrib/scripts/dragonx-cli "$RELEASE_DIR/" 2>/dev/null || true
# Copy required data files
cp asmap.dat sapling-spend.params sapling-output.params "$RELEASE_DIR/" 2>/dev/null || true
# Copy bootstrap script
cp contrib/bootstrap/bootstrap-dragonx.sh "$RELEASE_DIR/" 2>/dev/null || true
# Create ZIP
rm -f "$RELEASE_DIR/${VERSION}-mac.zip"
cd "$RELEASE_DIR"
zip -9 "${VERSION}-mac.zip" *
cd ../..
echo "Release package created: $RELEASE_DIR/${VERSION}-mac.zip"
ls -lh "$RELEASE_DIR/${VERSION}-mac.zip"

View File

@@ -39,6 +39,15 @@ fi
cd $WD cd $WD
sed -i 's/-lboost_system-mt /-lboost_system-mt-s /' configure sed -i 's/-lboost_system-mt /-lboost_system-mt-s /' configure
# Clean any stale native-compiled objects before cross-compiling.
# If objects were previously built with the native Linux compiler (ELF format),
# make won't recompile them for Windows (COFF format), causing link failures.
if [ -f src/libbitcoin_server.a ]; then
echo "Cleaning previous build objects to ensure Windows cross-compilation..."
cd src/ && make clean 2>/dev/null || true && cd ..
fi
cd src/ cd src/
CC="${CC} -g " CXX="${CXX} -g " make V=1 hushd.exe hush-cli.exe hush-tx.exe CC="${CC} -g " CXX="${CXX} -g " make V=1 hushd.exe hush-cli.exe hush-tx.exe
@@ -47,7 +56,7 @@ cd $WD
echo "Creating Windows release package..." echo "Creating Windows release package..."
VERSION=$(grep -oP 'define\(_CLIENT_VERSION.*?,\s*\K[0-9]+' configure.ac | head -3 | tr '\n' '.' | sed 's/\.$//') VERSION=$(grep -oP 'define\(_CLIENT_VERSION.*?,\s*\K[0-9]+' configure.ac | head -3 | tr '\n' '.' | sed 's/\.$//')
VERSION=${VERSION:-3.10.5} VERSION=${VERSION:-3.10.5}
RELEASE_DIR="release-win64" RELEASE_DIR="release/${VERSION}-win"
mkdir -p "$RELEASE_DIR" mkdir -p "$RELEASE_DIR"
# Strip binaries # Strip binaries
@@ -89,10 +98,10 @@ EOF
cp contrib/bootstrap/bootstrap-dragonx.bat "$RELEASE_DIR/" cp contrib/bootstrap/bootstrap-dragonx.bat "$RELEASE_DIR/"
# Create ZIP # Create ZIP
rm -f "$RELEASE_DIR/hush-${VERSION}-win64.zip" rm -f "$RELEASE_DIR/${VERSION}-win.zip"
cd "$RELEASE_DIR" cd "$RELEASE_DIR"
zip -9 "hush-${VERSION}-win64.zip" *.exe *.bat *.dat *.params zip -9 "${VERSION}-win.zip" *.exe *.bat *.dat *.params
cd .. cd ../..
echo "Release package created: $RELEASE_DIR/hush-${VERSION}-win64.zip" echo "Release package created: $RELEASE_DIR/${VERSION}-win.zip"
ls -lh "$RELEASE_DIR/hush-${VERSION}-win64.zip" ls -lh "$RELEASE_DIR/${VERSION}-win.zip"

View File

@@ -8,7 +8,7 @@ set -x
#hardcode and uncomment if hushd is not running on this machine #hardcode and uncomment if hushd is not running on this machine
#VERSION=3.6.3 #VERSION=3.6.3
VERSION=$(./src/hushd --version|grep version|cut -d' ' -f4|cut -d- -f1|sed 's/v//g') VERSION=$(./src/hushd --version|grep version|cut -d' ' -f4|cut -d- -f1|sed 's/v//g')
DIR="hush-$VERSION-linux-amd64" DIR="$VERSION-linux-amd64"
FILE="$DIR.tar" FILE="$DIR.tar"
TIME=$(perl -e 'print time') TIME=$(perl -e 'print time')
@@ -28,7 +28,7 @@ cp hushd hush-cli hush-tx hush-arrakis-chain dragonx-cli dragonxd ../$BUILD
cd ../$BUILD cd ../$BUILD
strip hushd hush-cli hush-tx strip hushd hush-cli hush-tx
cd .. cd ..
tar -f $FILE -c hush-$VERSION-linux-amd64/* tar -f $FILE -c $VERSION-linux-amd64/*
gzip -9 $FILE gzip -9 $FILE
sha256sum *.gz sha256sum *.gz
du -sh *.gz du -sh *.gz