Compare commits
25 Commits
compliant-
...
hd-transpa
| Author | SHA1 | Date | |
|---|---|---|---|
| 4caf2fc68f | |||
| 84aefb5475 | |||
| 1f2b109d95 | |||
| 78ea2aac5b | |||
| 2419ed7bf7 | |||
| a9b1b4085f | |||
| f763e3f1e7 | |||
| f8f13f9027 | |||
| bf1b4cffe0 | |||
| 82d77344d2 | |||
| 1673cfb6dc | |||
| 2b011d6ee2 | |||
|
|
d77088c1f2 | ||
| faa3e925cd | |||
| ddd851dc11 | |||
| 752590348b | |||
| f0cb958cac | |||
| 6d56ad8541 | |||
| 449a00434e | |||
| 5cda31b505 | |||
| ec517f86e6 | |||
| 33e5f646a7 | |||
| c1408871cc | |||
| 0a01ad8bba | |||
| 85c8d7f7dd |
27
.dockerignore
Normal file
27
.dockerignore
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
.git
|
||||||
|
release
|
||||||
|
depends/built
|
||||||
|
depends/work
|
||||||
|
depends/x86_64-unknown-linux-gnu
|
||||||
|
depends/x86_64-w64-mingw32
|
||||||
|
src/RandomX/build
|
||||||
|
src/*.o
|
||||||
|
src/*.a
|
||||||
|
src/*.la
|
||||||
|
src/*.lo
|
||||||
|
src/.libs
|
||||||
|
src/.deps
|
||||||
|
src/univalue/.libs
|
||||||
|
src/univalue/.deps
|
||||||
|
src/cc/*.o
|
||||||
|
src/cc/*.a
|
||||||
|
src/dragonxd
|
||||||
|
src/dragonx-cli
|
||||||
|
src/dragonx-tx
|
||||||
|
src/dragonxd.exe
|
||||||
|
src/dragonx-cli.exe
|
||||||
|
src/dragonx-tx.exe
|
||||||
|
sapling-output.params
|
||||||
|
sapling-spend.params
|
||||||
|
config.status
|
||||||
|
config.log
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -171,4 +171,8 @@ release-linux/
|
|||||||
release/
|
release/
|
||||||
src/dragonxd
|
src/dragonxd
|
||||||
src/dragonx-cli
|
src/dragonx-cli
|
||||||
src/dragonx-tx
|
src/dragonx-tx
|
||||||
|
src/dragonxd.exe
|
||||||
|
src/dragonx-cli.exe
|
||||||
|
src/dragonx-tx.exe
|
||||||
|
doc/relnotes/
|
||||||
4
AUTHORS
4
AUTHORS
@@ -1,7 +1,3 @@
|
|||||||
# The DragonX Developers
|
|
||||||
|
|
||||||
Dan S https://git.dragonx.is/dan
|
|
||||||
|
|
||||||
# The Hush Developers
|
# The Hush Developers
|
||||||
|
|
||||||
Duke Leto https://git.hush.is/duke https://github.com/leto
|
Duke Leto https://git.hush.is/duke https://github.com/leto
|
||||||
|
|||||||
1
COPYING
1
COPYING
@@ -1,4 +1,3 @@
|
|||||||
Copyright (c) 2024-2026 The DragonX developers
|
|
||||||
Copyright (c) 2018-2025 The Hush developers
|
Copyright (c) 2018-2025 The Hush developers
|
||||||
Copyright (c) 2009-2017 The Bitcoin Core developers
|
Copyright (c) 2009-2017 The Bitcoin Core developers
|
||||||
Copyright (c) 2009-2018 Bitcoin Developers
|
Copyright (c) 2009-2018 Bitcoin Developers
|
||||||
|
|||||||
31
Dockerfile.compat
Normal file
31
Dockerfile.compat
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool \
|
||||||
|
ncurses-dev unzip python3 zlib1g-dev wget bsdmainutils automake cmake \
|
||||||
|
libcurl4-openssl-dev curl git binutils \
|
||||||
|
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . /build/
|
||||||
|
|
||||||
|
# Clean host-built depends and src artifacts to force full rebuild inside container
|
||||||
|
RUN rm -rf /build/depends/built /build/depends/work \
|
||||||
|
/build/depends/x86_64-unknown-linux-gnu \
|
||||||
|
/build/depends/x86_64-w64-mingw32 \
|
||||||
|
/build/src/RandomX/build \
|
||||||
|
&& find /build/src -name '*.o' -o -name '*.a' -o -name '*.la' -o -name '*.lo' \
|
||||||
|
-o -name '*.lai' | xargs rm -f \
|
||||||
|
&& rm -rf /build/src/univalue/.libs /build/src/univalue/.deps \
|
||||||
|
&& rm -rf /build/src/.libs /build/src/.deps \
|
||||||
|
&& rm -rf /build/src/cc/*.o /build/src/cc/*.a \
|
||||||
|
&& rm -f /build/config.status /build/config.log
|
||||||
|
|
||||||
|
RUN cd /build && ./util/build.sh --disable-tests -j$(nproc)
|
||||||
|
|
||||||
|
# Strip binaries inside the container so extracted files are already small
|
||||||
|
RUN strip /build/src/dragonxd /build/src/dragonx-cli /build/src/dragonx-tx
|
||||||
|
|
||||||
|
CMD ["/bin/bash"]
|
||||||
26
LICENSE
26
LICENSE
@@ -1,4 +1,4 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GENERAL GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
@@ -7,15 +7,15 @@
|
|||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
The GENERAL General Public License is a free, copyleft license for
|
||||||
software and other kinds of works.
|
software and other kinds of works.
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
The licenses for most software and other practical works are designed
|
||||||
to take away your freedom to share and change the works. By contrast,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
the GENERAL General Public License is intended to guarantee your freedom to
|
||||||
share and change all versions of a program--to make sure it remains free
|
share and change all versions of a program--to make sure it remains free
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
GNU General Public License for most of our software; it applies also to
|
GENERAL General Public License for most of our software; it applies also to
|
||||||
any other work released this way by its authors. You can apply it to
|
any other work released this way by its authors. You can apply it to
|
||||||
your programs, too.
|
your programs, too.
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ freedoms that you received. You must make sure that they, too, receive
|
|||||||
or can get the source code. And you must show them these terms so they
|
or can get the source code. And you must show them these terms so they
|
||||||
know their rights.
|
know their rights.
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
Developers that use the GENERAL GPL protect your rights with two steps:
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ modification follow.
|
|||||||
|
|
||||||
0. Definitions.
|
0. Definitions.
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
"This License" refers to version 3 of the GENERAL General Public License.
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
works, such as semiconductor masks.
|
works, such as semiconductor masks.
|
||||||
@@ -549,35 +549,35 @@ to collect a royalty for further conveying from those to whom you convey
|
|||||||
the Program, the only way you could satisfy both those terms and this
|
the Program, the only way you could satisfy both those terms and this
|
||||||
License would be to refrain entirely from conveying the Program.
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
13. Use with the GENERAL Affero General Public License.
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
Notwithstanding any other provision of this License, you have
|
||||||
permission to link or combine any covered work with a work licensed
|
permission to link or combine any covered work with a work licensed
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
under version 3 of the GENERAL Affero General Public License into a single
|
||||||
combined work, and to convey the resulting work. The terms of this
|
combined work, and to convey the resulting work. The terms of this
|
||||||
License will continue to apply to the part which is the covered work,
|
License will continue to apply to the part which is the covered work,
|
||||||
but the special requirements of the GNU Affero General Public License,
|
but the special requirements of the GENERAL Affero General Public License,
|
||||||
section 13, concerning interaction through a network will apply to the
|
section 13, concerning interaction through a network will apply to the
|
||||||
combination as such.
|
combination as such.
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
the GNU General Public License from time to time. Such new versions will
|
the GENERAL General Public License from time to time. Such new versions will
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
Each version is given a distinguishing version number. If the
|
||||||
Program specifies that a certain numbered version of the GNU General
|
Program specifies that a certain numbered version of the GENERAL General
|
||||||
Public License "or any later version" applies to it, you have the
|
Public License "or any later version" applies to it, you have the
|
||||||
option of following the terms and conditions either of that numbered
|
option of following the terms and conditions either of that numbered
|
||||||
version or of any later version published by the Free Software
|
version or of any later version published by the Free Software
|
||||||
Foundation. If the Program does not specify a version number of the
|
Foundation. If the Program does not specify a version number of the
|
||||||
GNU General Public License, you may choose any version ever published
|
GENERAL General Public License, you may choose any version ever published
|
||||||
by the Free Software Foundation.
|
by the Free Software Foundation.
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
If the Program specifies that a proxy can decide which future
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
versions of the GENERAL General Public License can be used, that proxy's
|
||||||
public statement of acceptance of a version permanently authorizes you
|
public statement of acceptance of a version permanently authorizes you
|
||||||
to choose that version for the Program.
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
|||||||
233
README.md
233
README.md
@@ -1,107 +1,224 @@
|
|||||||
# DragonX
|
<p align="center">
|
||||||
|
<img src="doc/hush/hush0.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
DragonX is a privacy-focused cryptocurrency full node using RandomX proof-of-work.
|
<h3>
|
||||||
All transactions are shielded (z-to-z) by default, providing strong on-chain privacy.
|
|
||||||
|
|
||||||
| | |
|
| Introduction | Install | Compile | FAQ | Documentation |
|
||||||
|---|---|
|
| :---: | :---: | :---: | :---: | :---: |
|
||||||
| **Algorithm** | RandomX (CPU-mineable) |
|
| [What is Hush?](#what-is-hush) | [Windows 10 - Video Tutorial](#install-on-windows-10) | [Build on Debian or Ubuntu](#build-on-debian-or-ubuntu) | [Where can I buy Hush?](#where-can-i-buy-hush) | [Cross compiling Windows binaries](#windows-cross-compiled-on-linux)
|
||||||
| **Block time** | 36 seconds |
|
| [Why not GitHub?](#banned-by-github) | [Build on Mac](#build-on-mac) | [Build on Arch](#build-on-arch) | [Can I mine with CPU or GPU?](#can-i-mine-with-cpu-or-gpu) | [Hush DevOps for pools and CEXs](https://git.hush.is/hush/docs/src/branch/master/advanced/devops.md)
|
||||||
| **Block reward** | 3 DRAGONX |
|
| [What is HushChat?](#what-is-hushchat) | [Debian and Ubuntu](#installing-hush-binaries) | [Build on Fedora](#build-on-fedora) | [Claiming funds from old Hush wallets](https://git.hush.is/hush/hush3/src/branch/master/doc/OLD_WALLETS.md) | [Earn Hush bounty](#earn-hush-bounty)
|
||||||
| **Halving** | Every 3,500,000 blocks |
|
| [What is SilentDagon?](#what-is-silentdagon) | [Raspberry Pi](#install-on-arm-architecture) | [Build on Ubuntu 16.04 or older](#building-on-ubuntu-16-04-and-older-systems) | [Where can I spend Hush?](#where-can-i-spend-hush) | [Cross compiling from amd64 to arm64](https://git.hush.is/hush/docs/src/branch/master/advanced/cross-compile-hush-full-node-to-aarch64-with-docker.md)
|
||||||
| **Privacy** | All transactions shielded (`-ac_private=1`) |
|
|
||||||
| **P2P port** | 21768 |
|
|
||||||
| **RPC port** | 21769 |
|
|
||||||
|
|
||||||
## Build on Debian or Ubuntu
|
</h3>
|
||||||
|
|
||||||
|
# What is Hush?
|
||||||
|
|
||||||
|
Hush implements Extreme Privacy via blockchain tech. We have our own
|
||||||
|
genesis block. We are not a chain fork (copy) of another coin. We are based on
|
||||||
|
Bitcoin code, with sophisticated zero-knowledge mathematics added for privacy.
|
||||||
|
This keeps your transaction metadata private!
|
||||||
|
|
||||||
|
# What is this repository?
|
||||||
|
|
||||||
|
This software is the Hush node and command-line client. It downloads and stores
|
||||||
|
the entire history of Hush transactions; depending on the speed of your
|
||||||
|
computer and network connection, it will likely take a few hours at least, but
|
||||||
|
some people report full nodes syncing in less than 1.5 hours.
|
||||||
|
|
||||||
|
# Fastest way to sync (bootstrap)
|
||||||
|
|
||||||
|
The quickest way to get a fully-synced node is the signed bootstrap snapshot, which
|
||||||
|
installs a pre-built blockchain so you skip re-validating the whole chain from genesis:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Install build dependencies
|
# Stop dragonxd first if it is running, then:
|
||||||
|
./util/bootstrap-dragonx.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script preserves your `wallet.dat` and `DRAGONX.conf`, verifies the download's
|
||||||
|
checksums and (once a release key is published) its cryptographic signature, then starts
|
||||||
|
you near the chain tip. If you prefer to sync from the network instead, a larger
|
||||||
|
`-dbcache` (e.g. `-dbcache=2048`) noticeably speeds up the initial block download.
|
||||||
|
|
||||||
|
# Banned by GitHub
|
||||||
|
|
||||||
|
In working on this release, Duke Leto was suspended from Github, which gave Hush developers
|
||||||
|
the impetus to completely leave that racist and censorship-loving platform. Hush now has it's own [git.hush.is](https://git.hush.is/hush) Gitea instance,
|
||||||
|
because we will not be silenced by Microsoft. All Hush software will be released from git.hush.is and hush.is, downloads from any other
|
||||||
|
domains should be assumed to be backdoored.
|
||||||
|
|
||||||
|
**Hush is unfinished and highly experimental.** Use at your own risk! Just like Bitcoin.
|
||||||
|
|
||||||
|
# Build on Debian or Ubuntu
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# install build dependencies
|
||||||
sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib \
|
sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib \
|
||||||
autoconf libtool ncurses-dev unzip git zlib1g-dev wget \
|
autoconf libtool ncurses-dev unzip git zlib1g-dev wget \
|
||||||
bsdmainutils automake curl unzip libsodium-dev cmake
|
bsdmainutils automake curl unzip nano libsodium-dev cmake
|
||||||
|
# clone git repo
|
||||||
# Clone the repo
|
git clone https://git.hush.is/hush/hush3
|
||||||
git clone https://git.dragonx.is/DragonX/dragonx
|
cd hush3
|
||||||
cd dragonx
|
# Build
|
||||||
|
# This uses 3 build processes, you need 2GB of RAM for each.
|
||||||
# Build (uses ~2GB RAM per -j thread)
|
|
||||||
./build.sh -j3
|
./build.sh -j3
|
||||||
```
|
```
|
||||||
|
Video Tutorial: https://videos.hush.is/videos/how-to-install-on-linux
|
||||||
|
|
||||||
## Build on Arch
|
# Build on Arch
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
# install build dependencies
|
||||||
sudo pacman -S gcc libsodium lib32-zlib unzip wget git python rust curl autoconf cmake
|
sudo pacman -S gcc libsodium lib32-zlib unzip wget git python rust curl autoconf cmake
|
||||||
|
# clone git repo
|
||||||
git clone https://git.dragonx.is/DragonX/dragonx
|
git clone https://git.hush.is/hush/hush3
|
||||||
cd dragonx
|
cd hush3
|
||||||
|
# Build
|
||||||
|
# This uses 3 build processes, you need 2GB of RAM for each.
|
||||||
./build.sh -j3
|
./build.sh -j3
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build on Fedora
|
# Build on Fedora
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
# install build dependencies
|
||||||
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libtool ncurses-devel patch -y
|
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libtool ncurses-devel patch -y
|
||||||
|
# clone git repo
|
||||||
git clone https://git.dragonx.is/DragonX/dragonx
|
git clone https://git.hush.is/hush/hush3
|
||||||
cd dragonx
|
cd hush3
|
||||||
|
# Build
|
||||||
|
# This uses 3 build processes, you need 2GB of RAM for each.
|
||||||
./build.sh -j3
|
./build.sh -j3
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build on macOS
|
# Install on Windows 10
|
||||||
|
|
||||||
|
Video Tutorial: https://videos.hush.is/videos/how-to-install-on-windows
|
||||||
|
|
||||||
|
# Install on ARM Architecture
|
||||||
|
|
||||||
|
Use this if you have a Raspberry Pi or similar computer. Currently, any ARMv7 machine will not be able to build this repo, because the underlying tech (zcash and the zksnark library) do not support that instruction set. This also means that old RaspberryPi devices will not work, unless they have a newer ARMv8-based Raspberry Pi. Raspberry Pi 4 and newer are known to work.
|
||||||
|
|
||||||
|
1. [Download the latest Debian package with the AARCH64 designation from the releases page](https://git.hush.is/hush/hush3/releases).
|
||||||
|
1. Install the Debian package, substituting "VERSION-NUMBER" for the version you have downloaded: `sudo dpkg -i hush-VERSION-NUMBER-aarch64.deb`.
|
||||||
|
1. Run with: `hushd`.
|
||||||
|
|
||||||
|
If you would like to compile this for ARM yourself, then please refer to the [Cross compiling a Hush full node daemon from AMD64 to ARM64(aarch64) CPU architecture with Docker](https://git.hush.is/jahway603/hush-docs/src/branch/master/advanced/cross-compile-hush-full-node-to-aarch64-with-docker.md) documentation to do that.
|
||||||
|
|
||||||
|
# Building On Ubuntu 16.04 and older systems
|
||||||
|
|
||||||
|
Some older compilers may not be able to compile modern code, such as gcc 5.4 which comes with Ubuntu 16.04 by default. Here is how to install gcc 7 on Ubuntu 16.04. Run these commands as root:
|
||||||
|
|
||||||
|
```
|
||||||
|
add-apt-repository ppa:ubuntu-toolchain-r/test && \
|
||||||
|
apt update && \
|
||||||
|
apt-get install -y gcc-7 g++-7 && \
|
||||||
|
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 60 && \
|
||||||
|
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60
|
||||||
|
```
|
||||||
|
|
||||||
|
# Build on Mac
|
||||||
|
|
||||||
|
Install Xcode Command Line Tools and [Homebrew](https://brew.sh/), then install dependencies:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo port update && sudo port upgrade outdated
|
xcode-select --install
|
||||||
sudo port install qt5
|
brew install gcc autoconf automake pkgconf libtool cmake curl
|
||||||
|
|
||||||
git clone https://git.dragonx.is/DragonX/dragonx
|
# Install Rust (needed for librustzcash on macOS Sequoia+)
|
||||||
cd dragonx
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
source "$HOME/.cargo/env"
|
||||||
|
|
||||||
|
# clone git repo
|
||||||
|
git clone https://git.hush.is/hush/hush3
|
||||||
|
cd hush3
|
||||||
|
# Build (uses 3 build processes, you need 2GB of RAM for each)
|
||||||
|
# Make sure libtool gnubin and cargo are on PATH
|
||||||
|
export PATH="$HOME/.cargo/bin:/usr/local/opt/libtool/libexec/gnubin:$PATH"
|
||||||
./build.sh -j3
|
./build.sh -j3
|
||||||
```
|
```
|
||||||
|
|
||||||
## Cross-compile for Windows (on Linux)
|
For a release build:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
export PATH="$HOME/.cargo/bin:/usr/local/opt/libtool/libexec/gnubin:$PATH"
|
||||||
|
./build.sh --mac-release -j$(sysctl -n hw.ncpu)
|
||||||
|
```
|
||||||
|
|
||||||
|
# Installing Hush binaries
|
||||||
|
|
||||||
|
1. [Download the release](https://git.hush.is/hush/hush3/releases) with a .deb file extension.
|
||||||
|
1. Install the Debian package, substituting "VERSION-NUMBER" for the version you have downloaded: `sudo dpkg -i hush-VERSION-NUMBER-amd64.deb`.
|
||||||
|
1. Run with: `hushd`.
|
||||||
|
|
||||||
|
# Windows (cross-compiled on Linux)
|
||||||
|
Get dependencies:
|
||||||
|
```ssh
|
||||||
sudo apt-get install \
|
sudo apt-get install \
|
||||||
build-essential pkg-config libc6-dev m4 g++-multilib libdb++-dev \
|
build-essential pkg-config libc6-dev m4 g++-multilib libdb++-dev \
|
||||||
autoconf libtool ncurses-dev unzip git zip \
|
autoconf libtool ncurses-dev unzip git zip \
|
||||||
zlib1g-dev wget bsdmainutils automake mingw-w64 cmake libsodium-dev
|
zlib1g-dev wget bsdmainutils automake mingw-w64 cmake libsodium-dev
|
||||||
|
```
|
||||||
|
|
||||||
git clone https://git.dragonx.is/DragonX/dragonx
|
Downloading Git source repo, building and running Hush:
|
||||||
cd dragonx
|
|
||||||
|
```sh
|
||||||
|
# pull
|
||||||
|
git clone https://git.hush.is/hush/hush3
|
||||||
|
cd hush3
|
||||||
|
# Build
|
||||||
./util/build-win.sh -j$(nproc)
|
./util/build-win.sh -j$(nproc)
|
||||||
|
# Run a HUSH node
|
||||||
|
./src/hushd
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running
|
# Official Explorers
|
||||||
|
|
||||||
```sh
|
The links for the Official Hush explorers:
|
||||||
# Start the daemon
|
* [explorer.hush.is](https://explorer.hush.is)
|
||||||
./src/dragonxd
|
|
||||||
|
|
||||||
# In another terminal, interact via CLI
|
# What is SilentDragon?
|
||||||
./src/dragonx-cli getinfo
|
|
||||||
./src/dragonx-cli z_getnewaddress
|
|
||||||
```
|
|
||||||
|
|
||||||
Data directory: `~/.hush/DRAGONX/`
|
* [SilentDragon](https://git.hush.is/hush/SilentDragon) is a desktop wallet for HUSH full node.<br>
|
||||||
Config file: `~/.hush/DRAGONX/DRAGONX.conf`
|
* [SilentDragonLite](https://git.hush.is/hush/SilentDragonLite) is a desktop wallet that does not require you to download the full blockchain.
|
||||||
|
* [SilentDragonAndroid](https://git.hush.is/hush/SilentDragonAndroid) is a wallet for Android devices.
|
||||||
|
* [SilentDragonPaper](https://git.hush.is/hush/SilentDragonPaper) is a paper wallet generator that can be run completely offline.
|
||||||
|
|
||||||
## Mining
|
# What is HushChat?
|
||||||
|
|
||||||
DragonX uses the RandomX algorithm and is CPU-mineable. Point any RandomX-compatible
|
HushChat is a protocol inspired by the design of Signal Protocol, it uses many of the same cryptography and ideas, but does not actually use any code from Signal. Signal requires phone numbers and is a centralized service. HushChat is completely anonymous and decentralized and requires absolutely no metadata be given to any centralized third parties.
|
||||||
miner (e.g. XMRig) at a DragonX stratum pool, or solo-mine with:
|
|
||||||
|
|
||||||
```sh
|
# Can I mine with CPU or GPU?
|
||||||
./src/dragonxd -gen -genproclimit=$(nproc) -mineraddress=<your_zaddr>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Attribution
|
Hush cannot be efficiently mined with CPU or GPU, only ASIC mining is recommended. HUSH uses Equihash (200,9) algo, as does Zcash, Horizen or Komodo.
|
||||||
|
|
||||||
DragonX is a fork of the [Hush Full Node](https://hush.is).
|
# Where can I buy Hush?
|
||||||
Based on code from Zcash, Komodo, and Bitcoin Core.
|
|
||||||
Licensed under GPLv3 — see [COPYING](COPYING) and [LICENSE](LICENSE).
|
|
||||||
|
|
||||||
## License
|
1. https://nonkyc.io/market/HUSH_BTC
|
||||||
|
1. https://tradeogre.com/exchange/BTC-HUSH
|
||||||
|
|
||||||
|
# Where can I spend Hush?
|
||||||
|
|
||||||
|
AgoraX market: https://agorax.is
|
||||||
|
|
||||||
|
# Earn Hush bounty
|
||||||
|
|
||||||
|
Developers can earn bounty by fixing bugs or solving feature requests listed in `Issues->Label`:
|
||||||
|
- https://git.hush.is/hush/hush3/issues
|
||||||
|
- https://git.hush.is/hush/SilentDragon/issues
|
||||||
|
- https://git.hush.is/hush/SilentDragonLite/issues
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
# Support and Socials
|
||||||
|
|
||||||
|
* Telegram: [https://hush.is/tg](https://hush.is/tg)
|
||||||
|
* Matrix: [https://hush.is/matrix](https://hush.is/matrix)
|
||||||
|
* Twitter: [https://hush.is/twitter](https://hush.is/twitter)
|
||||||
|
* PeerTube [https://hush.is/peertube](https://hush.is/peertube)
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
For license information see the file [COPYING](COPYING).
|
For license information see the file [COPYING](COPYING).
|
||||||
|
|||||||
79
build.sh
79
build.sh
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
set -eu -o pipefail
|
set -eu -o pipefail
|
||||||
|
|
||||||
VERSION="1.0.0"
|
VERSION="1.0.3"
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
RELEASE_DIR="$SCRIPT_DIR/release"
|
RELEASE_DIR="$SCRIPT_DIR/release"
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ RELEASE_DIR="$SCRIPT_DIR/release"
|
|||||||
BUILD_LINUX_RELEASE=0
|
BUILD_LINUX_RELEASE=0
|
||||||
BUILD_WIN_RELEASE=0
|
BUILD_WIN_RELEASE=0
|
||||||
BUILD_MAC_RELEASE=0
|
BUILD_MAC_RELEASE=0
|
||||||
|
BUILD_LINUX_COMPAT=0
|
||||||
REMAINING_ARGS=()
|
REMAINING_ARGS=()
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
@@ -21,6 +22,9 @@ for arg in "$@"; do
|
|||||||
--linux-release)
|
--linux-release)
|
||||||
BUILD_LINUX_RELEASE=1
|
BUILD_LINUX_RELEASE=1
|
||||||
;;
|
;;
|
||||||
|
--linux-compat)
|
||||||
|
BUILD_LINUX_COMPAT=1
|
||||||
|
;;
|
||||||
--win-release)
|
--win-release)
|
||||||
BUILD_WIN_RELEASE=1
|
BUILD_WIN_RELEASE=1
|
||||||
;;
|
;;
|
||||||
@@ -76,8 +80,12 @@ package_release() {
|
|||||||
echo "Packaging release for $platform..."
|
echo "Packaging release for $platform..."
|
||||||
mkdir -p "$release_subdir"
|
mkdir -p "$release_subdir"
|
||||||
|
|
||||||
# Copy bootstrap script
|
# Copy bootstrap script (platform-appropriate)
|
||||||
cp "$SCRIPT_DIR/util/bootstrap-dragonx.sh" "$release_subdir/"
|
if [ "$platform" = "win64" ]; then
|
||||||
|
cp "$SCRIPT_DIR/util/bootstrap-dragonx.bat" "$release_subdir/"
|
||||||
|
else
|
||||||
|
cp "$SCRIPT_DIR/util/bootstrap-dragonx.sh" "$release_subdir/"
|
||||||
|
fi
|
||||||
|
|
||||||
# Copy common files
|
# Copy common files
|
||||||
cp "$SCRIPT_DIR/contrib/asmap/asmap.dat" "$release_subdir/" 2>/dev/null || true
|
cp "$SCRIPT_DIR/contrib/asmap/asmap.dat" "$release_subdir/" 2>/dev/null || true
|
||||||
@@ -110,27 +118,78 @@ package_release() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Handle release builds
|
# Handle release builds
|
||||||
if [ $BUILD_LINUX_RELEASE -eq 1 ] || [ $BUILD_WIN_RELEASE -eq 1 ] || [ $BUILD_MAC_RELEASE -eq 1 ]; then
|
if [ $BUILD_LINUX_COMPAT -eq 1 ] || [ $BUILD_LINUX_RELEASE -eq 1 ] || [ $BUILD_WIN_RELEASE -eq 1 ] || [ $BUILD_MAC_RELEASE -eq 1 ]; then
|
||||||
mkdir -p "$RELEASE_DIR"
|
mkdir -p "$RELEASE_DIR"
|
||||||
|
|
||||||
|
if [ $BUILD_LINUX_COMPAT -eq 1 ]; then
|
||||||
|
echo "=== Building Linux compat release (Ubuntu 20.04 via Docker) ==="
|
||||||
|
if ! command -v docker &>/dev/null; then
|
||||||
|
echo "Error: docker is required for --linux-compat builds"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use sudo for docker if the user isn't in the docker group
|
||||||
|
DOCKER_CMD="docker"
|
||||||
|
if ! docker info &>/dev/null 2>&1; then
|
||||||
|
echo "Note: Using sudo for docker (add yourself to the docker group to avoid this)"
|
||||||
|
DOCKER_CMD="sudo docker"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOCKER_IMAGE="dragonx-compat-builder"
|
||||||
|
COMPAT_PLATFORM="linux-amd64-ubuntu2004"
|
||||||
|
COMPAT_RELEASE_DIR="$RELEASE_DIR/dragonx-$VERSION-$COMPAT_PLATFORM"
|
||||||
|
|
||||||
|
echo "Building Docker image (Ubuntu 20.04 base)..."
|
||||||
|
$DOCKER_CMD build -f Dockerfile.compat -t "$DOCKER_IMAGE" .
|
||||||
|
|
||||||
|
echo "Extracting binaries from Docker image..."
|
||||||
|
CONTAINER_ID=$($DOCKER_CMD create "$DOCKER_IMAGE")
|
||||||
|
mkdir -p "$COMPAT_RELEASE_DIR"
|
||||||
|
|
||||||
|
for bin in dragonxd dragonx-cli dragonx-tx; do
|
||||||
|
$DOCKER_CMD cp "$CONTAINER_ID:/build/src/$bin" "$COMPAT_RELEASE_DIR/$bin"
|
||||||
|
done
|
||||||
|
$DOCKER_CMD rm "$CONTAINER_ID" >/dev/null
|
||||||
|
|
||||||
|
# Fix ownership (docker cp creates root-owned files)
|
||||||
|
# Binaries are already stripped inside the Docker container
|
||||||
|
if [ "$(stat -c '%U' "$COMPAT_RELEASE_DIR/dragonxd")" = "root" ]; then
|
||||||
|
sudo chown "$(id -u):$(id -g)" "$COMPAT_RELEASE_DIR"/dragonx*
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy common files
|
||||||
|
cp "$SCRIPT_DIR/util/bootstrap-dragonx.sh" "$COMPAT_RELEASE_DIR/"
|
||||||
|
cp "$SCRIPT_DIR/contrib/asmap/asmap.dat" "$COMPAT_RELEASE_DIR/" 2>/dev/null || true
|
||||||
|
cp "$SCRIPT_DIR/sapling-output.params" "$COMPAT_RELEASE_DIR/" 2>/dev/null || true
|
||||||
|
cp "$SCRIPT_DIR/sapling-spend.params" "$COMPAT_RELEASE_DIR/" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "Compat release packaged: $COMPAT_RELEASE_DIR"
|
||||||
|
ls -la "$COMPAT_RELEASE_DIR"
|
||||||
|
|
||||||
|
# Show glibc version requirement
|
||||||
|
echo ""
|
||||||
|
echo "Binary compatibility info:"
|
||||||
|
objdump -T "$COMPAT_RELEASE_DIR/dragonxd" | grep -oP 'GLIBC_\d+\.\d+' | sort -uV | tail -1 && echo "(max GLIBC version required)"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $BUILD_LINUX_RELEASE -eq 1 ]; then
|
if [ $BUILD_LINUX_RELEASE -eq 1 ]; then
|
||||||
echo "=== Building Linux release ==="
|
echo "=== Building Linux release ==="
|
||||||
clean_for_platform linux
|
clean_for_platform linux
|
||||||
./util/build.sh --disable-tests "${REMAINING_ARGS[@]}"
|
./util/build.sh --disable-tests ${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}
|
||||||
package_release linux-amd64
|
package_release linux-amd64
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $BUILD_WIN_RELEASE -eq 1 ]; then
|
if [ $BUILD_WIN_RELEASE -eq 1 ]; then
|
||||||
echo "=== Building Windows release ==="
|
echo "=== Building Windows release ==="
|
||||||
clean_for_platform windows
|
clean_for_platform windows
|
||||||
./util/build-win.sh --disable-tests "${REMAINING_ARGS[@]}"
|
./util/build-win.sh --disable-tests ${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}
|
||||||
package_release win64
|
package_release win64
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $BUILD_MAC_RELEASE -eq 1 ]; then
|
if [ $BUILD_MAC_RELEASE -eq 1 ]; then
|
||||||
echo "=== Building macOS release ==="
|
echo "=== Building macOS release ==="
|
||||||
clean_for_platform macos
|
clean_for_platform macos
|
||||||
./util/build-mac.sh --disable-tests "${REMAINING_ARGS[@]}"
|
./util/build-mac.sh --disable-tests ${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}
|
||||||
package_release macos
|
package_release macos
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -142,11 +201,11 @@ fi
|
|||||||
|
|
||||||
# Standard build (auto-detect OS)
|
# Standard build (auto-detect OS)
|
||||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||||
./util/build.sh --disable-tests "${REMAINING_ARGS[@]}"
|
./util/build.sh --disable-tests ${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}
|
||||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
./util/build-mac.sh --disable-tests "${REMAINING_ARGS[@]}"
|
./util/build-mac.sh --disable-tests ${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}
|
||||||
elif [[ "$OSTYPE" == "msys"* ]]; then
|
elif [[ "$OSTYPE" == "msys"* ]]; then
|
||||||
./util/build-win.sh --disable-tests "${REMAINING_ARGS[@]}"
|
./util/build-win.sh --disable-tests ${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}
|
||||||
else
|
else
|
||||||
echo "Unable to detect your OS. What are you using?"
|
echo "Unable to detect your OS. What are you using?"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
dnl Copyright (c) 2024-2026 The DragonX developers
|
|
||||||
dnl Copyright (c) 2016-2024 The Hush developers
|
|
||||||
dnl Distributed under the GPLv3 software license, see the accompanying
|
|
||||||
dnl file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
||||||
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
||||||
AC_PREREQ([2.60])
|
AC_PREREQ([2.60])
|
||||||
define(_CLIENT_VERSION_MAJOR, 1)
|
define(_CLIENT_VERSION_MAJOR, 1)
|
||||||
dnl Must be kept in sync with src/clientversion.h , ugh!
|
dnl Must be kept in sync with src/clientversion.h , ugh!
|
||||||
define(_CLIENT_VERSION_MINOR, 0)
|
define(_CLIENT_VERSION_MINOR, 0)
|
||||||
define(_CLIENT_VERSION_REVISION, 0)
|
define(_CLIENT_VERSION_REVISION, 3)
|
||||||
define(_CLIENT_VERSION_BUILD, 50)
|
define(_CLIENT_VERSION_BUILD, 50)
|
||||||
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
|
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
|
||||||
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
|
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
dragonx (1.0.0) stable; urgency=medium
|
|
||||||
|
|
||||||
* Initial release of DragonX, forked from Hush Full Node
|
|
||||||
* Full legal-compliant rebrand: binaries, config, documentation
|
|
||||||
* RandomX proof-of-work, 36-second block time, fully shielded transactions
|
|
||||||
* New binary names: dragonxd, dragonx-cli, dragonx-tx
|
|
||||||
|
|
||||||
-- DragonX <dan-s-dev@proton.me> Mon, 03 Mar 2026 00:00:00 +0000
|
|
||||||
|
|
||||||
hush (3.10.5) stable; urgency=medium
|
hush (3.10.5) stable; urgency=medium
|
||||||
|
|
||||||
* DragonX is no longer supported by this codebase
|
* DragonX is no longer supported by this codebase
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
Source: dragonx
|
Source: hush
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: DragonX <dan-s-dev@proton.me>
|
Maintainer: Hush <myhushteam@gmail.com>
|
||||||
Homepage: https://dragonx.is
|
Homepage: https://hush.is
|
||||||
Build-Depends: autoconf, automake, bsdmainutils, build-essential,
|
Build-Depends: autoconf, automake, bsdmainutils, build-essential,
|
||||||
cmake, curl, git, g++-multilib, libc6-dev, libsodium-dev,
|
cmake, curl, git, g++-multilib, libc6-dev, libsodium-dev,
|
||||||
libtool, m4, ncurses-dev, pkg-config, python,
|
libtool, m4, ncurses-dev, pkg-config, python,
|
||||||
unzip, wget, zlib1g-dev
|
unzip, wget, zlib1g-dev
|
||||||
Vcs-Git: https://git.dragonx.is/DragonX/dragonx.git
|
Vcs-Git: https://git.hush.is/hush/hush3.git
|
||||||
Vcs-Browser: https://git.dragonx.is/DragonX/dragonx
|
Vcs-Browser: https://git.hush.is/hush/hush3
|
||||||
|
|
||||||
Package: dragonx
|
Package: hush
|
||||||
Architecture: amd64 arm64
|
Architecture: amd64 arm64
|
||||||
Depends: ${shlibs:Depends}
|
Depends: ${shlibs:Depends}
|
||||||
Description: Privacy-focused cryptocurrency full node for DragonX
|
Description: Cryptocoin full node for Hush
|
||||||
DragonX is a privacy-focused cryptocurrency using RandomX proof-of-work.
|
Speak And Transact Freely with Hush, which inherits from Bitcoin Protocol and
|
||||||
All transactions are shielded by default. Fork of the Hush Full Node.
|
Zcash Protocol and is focused on private communications.
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
Files: *
|
Files: *
|
||||||
Copyright: 2024-2026, The DragonX developers
|
Copyright: 2016-2026, The Hush developers
|
||||||
2016-2026, The Hush developers
|
|
||||||
2009-2016, Bitcoin Core developers
|
2009-2016, Bitcoin Core developers
|
||||||
License: GPLv3
|
License: GPLv3
|
||||||
Comment: https://dragonx.is
|
Comment: https://hush.is
|
||||||
|
|
||||||
Files: depends/sources/libsodium-*.tar.gz
|
Files: depends/sources/libsodium-*.tar.gz
|
||||||
Copyright: 2013-2016 Frank Denis
|
Copyright: 2013-2016 Frank Denis
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
DEBIAN/examples/DRAGONX.conf
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
usr/bin/dragonxd
|
|
||||||
usr/bin/dragonx-cli
|
|
||||||
usr/bin/dragonx-tx
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
DEBIAN/manpages/dragonx-cli.1
|
|
||||||
DEBIAN/manpages/dragonx-tx.1
|
|
||||||
DEBIAN/manpages/dragonxd.1
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
## DRAGONX.conf configuration file. Lines beginning with # are comments.
|
|
||||||
|
|
||||||
# Network-related settings:
|
|
||||||
|
|
||||||
# Run a regression test network
|
|
||||||
#regtest=0
|
|
||||||
# Run a test node (which means you can mine with no peers)
|
|
||||||
#testnode=1
|
|
||||||
|
|
||||||
#set a custom client name/user agent
|
|
||||||
#clientName=GoldenSandtrout
|
|
||||||
|
|
||||||
# Rescan from block height
|
|
||||||
#rescan=123
|
|
||||||
|
|
||||||
# Connect via a SOCKS5 proxy
|
|
||||||
#proxy=127.0.0.1:9050
|
|
||||||
|
|
||||||
# Automatically create Tor hidden service
|
|
||||||
#listenonion=1
|
|
||||||
|
|
||||||
#Use separate SOCKS5 proxy to reach peers via Tor hidden services
|
|
||||||
#onion=1.2.3.4:9050
|
|
||||||
|
|
||||||
# Only connect to nodes in network <net> (ipv4, ipv6, onion or i2p)"));
|
|
||||||
#onlynet=<net>
|
|
||||||
|
|
||||||
#Tor control port to use if onion listening enabled
|
|
||||||
#torcontrol=127.0.0.1:9051
|
|
||||||
|
|
||||||
# Bind to given address and always listen on it. Use [host]:port notation for IPv6
|
|
||||||
#bind=<addr>
|
|
||||||
|
|
||||||
# Bind to given address and allowlist peers connecting to it. Use [host]:port notation for IPv6
|
|
||||||
#allowbind=<addr>
|
|
||||||
|
|
||||||
##############################################################
|
|
||||||
## Quick Primer on addnode vs connect ##
|
|
||||||
## Let's say for instance you use addnode=4.2.2.4 ##
|
|
||||||
## addnode will connect you to and tell you about the ##
|
|
||||||
## nodes connected to 4.2.2.4. In addition it will tell ##
|
|
||||||
## the other nodes connected to it that you exist so ##
|
|
||||||
## they can connect to you. ##
|
|
||||||
## connect will not do the above when you 'connect' to it. ##
|
|
||||||
## It will *only* connect you to 4.2.2.4 and no one else.##
|
|
||||||
## ##
|
|
||||||
## So if you're behind a firewall, or have other problems ##
|
|
||||||
## finding nodes, add some using 'addnode'. ##
|
|
||||||
## ##
|
|
||||||
## If you want to stay private, use 'connect' to only ##
|
|
||||||
## connect to "trusted" nodes. ##
|
|
||||||
## ##
|
|
||||||
## If you run multiple nodes on a LAN, there's no need for ##
|
|
||||||
## all of them to open lots of connections. Instead ##
|
|
||||||
## 'connect' them all to one node that is port forwarded ##
|
|
||||||
## and has lots of connections. ##
|
|
||||||
## Thanks goes to [Noodle] on Freenode. ##
|
|
||||||
##############################################################
|
|
||||||
|
|
||||||
# Use as many addnode= settings as you like to connect to specific peers
|
|
||||||
#addnode=69.164.218.197
|
|
||||||
#addnode=10.0.0.2:8233
|
|
||||||
|
|
||||||
# Alternatively use as many connect= settings as you like to connect ONLY to specific peers
|
|
||||||
#connect=69.164.218.197
|
|
||||||
#connect=10.0.0.1:8233
|
|
||||||
|
|
||||||
# Listening mode, enabled by default except when 'connect' is being used
|
|
||||||
#listen=1
|
|
||||||
|
|
||||||
# Maximum number of inbound+outbound connections.
|
|
||||||
#maxconnections=
|
|
||||||
|
|
||||||
#
|
|
||||||
# JSON-RPC options (for controlling a running dragonxd process)
|
|
||||||
#
|
|
||||||
|
|
||||||
# server=1 tells node to accept JSON-RPC commands (set as default if not specified)
|
|
||||||
#server=1
|
|
||||||
|
|
||||||
# Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6.
|
|
||||||
# This option can be specified multiple times (default: bind to all interfaces)
|
|
||||||
#rpcbind=<addr>
|
|
||||||
|
|
||||||
# You must set rpcuser and rpcpassword to secure the JSON-RPC api
|
|
||||||
# These will automatically be created for you
|
|
||||||
#rpcuser=user
|
|
||||||
#rpcpassword=supersecretpassword
|
|
||||||
|
|
||||||
# How many seconds node will wait for a complete RPC HTTP request.
|
|
||||||
# after the HTTP connection is established.
|
|
||||||
#rpcclienttimeout=30
|
|
||||||
|
|
||||||
# By default, only RPC connections from localhost are allowed.
|
|
||||||
# Specify as many rpcallowip= settings as you like to allow connections from other hosts,
|
|
||||||
# either as a single IPv4/IPv6 or with a subnet specification.
|
|
||||||
|
|
||||||
# NOTE: opening up the RPC port to hosts outside your local trusted network is NOT RECOMMENDED,
|
|
||||||
# because the rpcpassword is transmitted over the network unencrypted and also because anyone
|
|
||||||
# that can authenticate on the RPC port can steal your keys + take over the account running dragonxd
|
|
||||||
|
|
||||||
#rpcallowip=10.1.1.34/255.255.255.0
|
|
||||||
#rpcallowip=1.2.3.4/24
|
|
||||||
#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96
|
|
||||||
|
|
||||||
# Listen for RPC connections on this TCP port:
|
|
||||||
#rpcport=1234
|
|
||||||
|
|
||||||
# You can use dragonxd to send commands to dragonxd
|
|
||||||
# running on another host using this option:
|
|
||||||
#rpcconnect=127.0.0.1
|
|
||||||
|
|
||||||
# Transaction Fee
|
|
||||||
|
|
||||||
# Send transactions as zero-fee transactions if possible (default: 0)
|
|
||||||
#sendfreetransactions=0
|
|
||||||
|
|
||||||
# Create transactions that have enough fees (or priority) so they are likely to # begin confirmation within n blocks (default: 1).
|
|
||||||
# This setting is overridden by the -paytxfee option.
|
|
||||||
#txconfirmtarget=n
|
|
||||||
|
|
||||||
# Miscellaneous options
|
|
||||||
|
|
||||||
# Enable mining at startup
|
|
||||||
#gen=1
|
|
||||||
|
|
||||||
# Set the number of threads to be used for mining (-1 = all cores).
|
|
||||||
#genproclimit=1
|
|
||||||
|
|
||||||
# Specify a different Equihash solver (e.g. "tromp") to try to mine
|
|
||||||
# faster when gen=1.
|
|
||||||
#equihashsolver=default
|
|
||||||
|
|
||||||
# Pre-generate this many public/private key pairs, so wallet backups will be valid for
|
|
||||||
# both prior transactions and several dozen future transactions.
|
|
||||||
#keypool=100
|
|
||||||
|
|
||||||
# Pay an optional transaction fee every time you send a tx. Transactions with fees
|
|
||||||
# are more likely than free transactions to be included in generated blocks, so may
|
|
||||||
# be validated sooner. This setting does not affect private transactions created with
|
|
||||||
# 'z_sendmany'.
|
|
||||||
#paytxfee=0.00
|
|
||||||
|
|
||||||
#Rewind the chain to specific block height. This is useful for creating snapshots at a given block height.
|
|
||||||
#rewind=555
|
|
||||||
|
|
||||||
#Stop the chain a specific block height. This is useful for creating snapshots at a given block height.
|
|
||||||
#stopat=1000000
|
|
||||||
|
|
||||||
#Set an address to use as change address for all transactions. This value must be set to a 33 byte pubkey. All mined coins will also be sent to this address.
|
|
||||||
#pubkey=027dc7b5cfb5efca96674b45e9fda18df069d040b9fd9ff32c35df56005e330392
|
|
||||||
|
|
||||||
# Disable clearnet (ipv4 and ipv6) connections to this node
|
|
||||||
#clearnet=0
|
|
||||||
|
|
||||||
# Disable ipv4
|
|
||||||
#disableipv4=1
|
|
||||||
# Disable ipv6
|
|
||||||
#disableipv6=1
|
|
||||||
|
|
||||||
# Enable transaction index
|
|
||||||
#txindex=1
|
|
||||||
# Enable address index
|
|
||||||
#addressindex=1
|
|
||||||
# Enable timestamp index
|
|
||||||
#timestampindex=1
|
|
||||||
# Enable spent index
|
|
||||||
#spentindex=1
|
|
||||||
|
|
||||||
# Enable shielded stats index
|
|
||||||
#zindex=1
|
|
||||||
|
|
||||||
# Attempt to salvage a corrupt wallet
|
|
||||||
# salvagewallet=1
|
|
||||||
|
|
||||||
# Mine all blocks to this address (not good for your privacy and not recommended!)
|
|
||||||
# Disallowed if clearnet=0
|
|
||||||
# mineraddress=XXX
|
|
||||||
|
|
||||||
# Disable wallet
|
|
||||||
#disablewallet=1
|
|
||||||
|
|
||||||
# Allow mining to an address that is not in the current wallet
|
|
||||||
#minetolocalwallet=0
|
|
||||||
|
|
||||||
# Delete all wallet transactions
|
|
||||||
#zapwallettxes=1
|
|
||||||
|
|
||||||
# Enable sapling consolidation
|
|
||||||
# consolidation=1
|
|
||||||
|
|
||||||
# Enable stratum server
|
|
||||||
# stratum=1
|
|
||||||
|
|
||||||
# Run a command each time a new block is seen
|
|
||||||
# %s in command is replaced by block hash
|
|
||||||
#blocknotify=/my/awesome/script.sh %s
|
|
||||||
|
|
||||||
# Run a command when wallet gets a new tx
|
|
||||||
# %s in command is replaced with txid
|
|
||||||
#walletnotify=/my/cool/script.sh %s
|
|
||||||
|
|
||||||
# Run a command when tx expires
|
|
||||||
# %s in command is replaced with txid
|
|
||||||
#txexpirynotify=/my/elite/script.sh %s
|
|
||||||
|
|
||||||
# Execute this commend to send a tx
|
|
||||||
# %s is replaced with tx hex
|
|
||||||
#txsend=/send/it.sh %s
|
|
||||||
@@ -1 +1 @@
|
|||||||
DEBIAN/examples/DRAGONX.conf
|
DEBIAN/examples/HUSH3.conf
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
usr/bin/dragonxd
|
usr/bin/hushd
|
||||||
usr/bin/dragonx-cli
|
usr/bin/hush-cli
|
||||||
usr/bin/dragonx-tx
|
usr/bin/hush-tx
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
DEBIAN/manpages/dragonx-cli.1
|
DEBIAN/manpages/hush-cli.1
|
||||||
DEBIAN/manpages/dragonx-tx.1
|
DEBIAN/manpages/hush-tx.1
|
||||||
DEBIAN/manpages/dragonxd.1
|
DEBIAN/manpages/hushd.1
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
Sample configuration files for:
|
Sample configuration files for:
|
||||||
|
|
||||||
SystemD: dragonxd.service
|
SystemD: hushd.service
|
||||||
Upstart: dragonxd.conf
|
Upstart: hushd.conf
|
||||||
OpenRC: dragonxd.openrc
|
OpenRC: hushd.openrc
|
||||||
dragonxd.openrcconf
|
hushd.openrcconf
|
||||||
CentOS: dragonxd.init
|
CentOS: hushd.init
|
||||||
|
|
||||||
have been made available to assist packagers in creating node packages here.
|
have been made available to assist packagers in creating node packages here.
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
description "Hush Daemon"
|
|
||||||
|
|
||||||
start on runlevel [2345]
|
|
||||||
stop on starting rc RUNLEVEL=[016]
|
|
||||||
|
|
||||||
env HUSHD_BIN="/usr/bin/dragonxd"
|
|
||||||
env HUSHD_USER="hush"
|
|
||||||
env HUSHD_GROUP="hush"
|
|
||||||
env HUSHD_PIDDIR="/var/run/dragonxd"
|
|
||||||
# upstart can't handle variables constructed with other variables
|
|
||||||
env HUSHD_PIDFILE="/var/run/dragonxd/dragonxd.pid"
|
|
||||||
env HUSHD_CONFIGFILE="/etc/hush/hush.conf"
|
|
||||||
env HUSHD_DATADIR="/var/lib/dragonxd"
|
|
||||||
|
|
||||||
expect fork
|
|
||||||
|
|
||||||
respawn
|
|
||||||
respawn limit 5 120
|
|
||||||
kill timeout 60
|
|
||||||
|
|
||||||
pre-start script
|
|
||||||
# this will catch non-existent config files
|
|
||||||
# dragonxd will check and exit with this very warning, but it can do so
|
|
||||||
# long after forking, leaving upstart to think everything started fine.
|
|
||||||
# since this is a commonly encountered case on install, just check and
|
|
||||||
# warn here.
|
|
||||||
if ! grep -qs '^rpcpassword=' "$HUSHD_CONFIGFILE" ; then
|
|
||||||
echo "ERROR: You must set a secure rpcpassword to run dragonxd."
|
|
||||||
echo "The setting must appear in $HUSHD_CONFIGFILE"
|
|
||||||
echo
|
|
||||||
echo "This password is security critical to securing wallets "
|
|
||||||
echo "and must not be the same as the rpcuser setting."
|
|
||||||
echo "You can generate a suitable random password using the following"
|
|
||||||
echo "command from the shell:"
|
|
||||||
echo
|
|
||||||
echo "bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$HUSHD_PIDDIR"
|
|
||||||
chmod 0755 "$HUSHD_PIDDIR"
|
|
||||||
chown $HUSHD_USER:$HUSHD_GROUP "$HUSHD_PIDDIR"
|
|
||||||
chown $HUSHD_USER:$HUSHD_GROUP "$HUSHD_CONFIGFILE"
|
|
||||||
chmod 0660 "$HUSHD_CONFIGFILE"
|
|
||||||
end script
|
|
||||||
|
|
||||||
exec start-stop-daemon \
|
|
||||||
--start \
|
|
||||||
--pidfile "$HUSHD_PIDFILE" \
|
|
||||||
--chuid $HUSHD_USER:$HUSHD_GROUP \
|
|
||||||
--exec "$HUSHD_BIN" \
|
|
||||||
-- \
|
|
||||||
-pid="$HUSHD_PIDFILE" \
|
|
||||||
-conf="$HUSHD_CONFIGFILE" \
|
|
||||||
-datadir="$HUSHD_DATADIR" \
|
|
||||||
-disablewallet \
|
|
||||||
-daemon
|
|
||||||
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# dragonxd The hush core server.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# chkconfig: 345 80 20
|
|
||||||
# description: dragonxd
|
|
||||||
# processname: dragonxd
|
|
||||||
#
|
|
||||||
|
|
||||||
# Source function library.
|
|
||||||
. /etc/init.d/functions
|
|
||||||
|
|
||||||
# you can override defaults in /etc/sysconfig/dragonxd, see below
|
|
||||||
if [ -f /etc/sysconfig/dragonxd ]; then
|
|
||||||
. /etc/sysconfig/dragonxd
|
|
||||||
fi
|
|
||||||
|
|
||||||
RETVAL=0
|
|
||||||
|
|
||||||
prog=dragonxd
|
|
||||||
# you can override the lockfile via HUSHD_LOCKFILE in /etc/sysconfig/dragonxd
|
|
||||||
lockfile=${HUSHD_LOCKFILE-/var/lock/subsys/dragonxd}
|
|
||||||
|
|
||||||
# dragonxd defaults to /usr/bin/dragonxd, override with HUSHD_BIN
|
|
||||||
dragonxd=${HUSHD_BIN-/usr/bin/dragonxd}
|
|
||||||
|
|
||||||
# dragonxd opts default to -disablewallet, override with HUSHD_OPTS
|
|
||||||
dragonxd_opts=${HUSHD_OPTS--disablewallet}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
echo -n $"Starting $prog: "
|
|
||||||
daemon $DAEMONOPTS $dragonxd $dragonxd_opts
|
|
||||||
RETVAL=$?
|
|
||||||
echo
|
|
||||||
[ $RETVAL -eq 0 ] && touch $lockfile
|
|
||||||
return $RETVAL
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
echo -n $"Stopping $prog: "
|
|
||||||
killproc $prog
|
|
||||||
RETVAL=$?
|
|
||||||
echo
|
|
||||||
[ $RETVAL -eq 0 ] && rm -f $lockfile
|
|
||||||
return $RETVAL
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status $prog
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
stop
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: service $prog {start|stop|status|restart}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
#!/sbin/runscript
|
|
||||||
|
|
||||||
# backward compatibility for existing gentoo layout
|
|
||||||
#
|
|
||||||
if [ -d "/var/lib/hush/.hush" ]; then
|
|
||||||
HUSHD_DEFAULT_DATADIR="/var/lib/hush/.hush"
|
|
||||||
else
|
|
||||||
HUSHD_DEFAULT_DATADIR="/var/lib/dragonxd"
|
|
||||||
fi
|
|
||||||
|
|
||||||
HUSHD_CONFIGFILE=${HUSHD_CONFIGFILE:-/etc/hush/hush.conf}
|
|
||||||
HUSHD_PIDDIR=${HUSHD_PIDDIR:-/var/run/dragonxd}
|
|
||||||
HUSHD_PIDFILE=${HUSHD_PIDFILE:-${HUSHD_PIDDIR}/dragonxd.pid}
|
|
||||||
HUSHD_DATADIR=${HUSHD_DATADIR:-${HUSHD_DEFAULT_DATADIR}}
|
|
||||||
HUSHD_USER=${HUSHD_USER:-${HUSH_USER:-hush}}
|
|
||||||
HUSHD_GROUP=${HUSHD_GROUP:-hush}
|
|
||||||
HUSHD_BIN=${HUSHD_BIN:-/usr/bin/dragonxd}
|
|
||||||
HUSHD_NICE=${HUSHD_NICE:-${NICELEVEL:-0}}
|
|
||||||
HUSHD_OPTS="${HUSHD_OPTS:-${HUSH_OPTS}}"
|
|
||||||
|
|
||||||
name="Hush Full Node Daemon"
|
|
||||||
description="Hush cryptocurrency P2P network daemon"
|
|
||||||
|
|
||||||
command="/usr/bin/dragonxd"
|
|
||||||
command_args="-pid=\"${HUSHD_PIDFILE}\" \
|
|
||||||
-conf=\"${HUSHD_CONFIGFILE}\" \
|
|
||||||
-datadir=\"${HUSHD_DATADIR}\" \
|
|
||||||
-daemon \
|
|
||||||
${HUSHD_OPTS}"
|
|
||||||
|
|
||||||
required_files="${HUSHD_CONFIGFILE}"
|
|
||||||
start_stop_daemon_args="-u ${HUSHD_USER} \
|
|
||||||
-N ${HUSHD_NICE} -w 2000"
|
|
||||||
pidfile="${HUSHD_PIDFILE}"
|
|
||||||
|
|
||||||
# The retry schedule to use when stopping the daemon. Could be either
|
|
||||||
# a timeout in seconds or multiple signal/timeout pairs (like
|
|
||||||
# "SIGKILL/180 SIGTERM/300")
|
|
||||||
retry="${HUSHD_SIGTERM_TIMEOUT}"
|
|
||||||
|
|
||||||
depend() {
|
|
||||||
need localmount net
|
|
||||||
}
|
|
||||||
|
|
||||||
# verify
|
|
||||||
# 1) that the datadir exists and is writable (or create it)
|
|
||||||
# 2) that a directory for the pid exists and is writable
|
|
||||||
# 3) ownership and permissions on the config file
|
|
||||||
start_pre() {
|
|
||||||
checkpath \
|
|
||||||
-d \
|
|
||||||
--mode 0750 \
|
|
||||||
--owner "${HUSHD_USER}:${HUSHD_GROUP}" \
|
|
||||||
"${HUSHD_DATADIR}"
|
|
||||||
|
|
||||||
checkpath \
|
|
||||||
-d \
|
|
||||||
--mode 0755 \
|
|
||||||
--owner "${HUSHD_USER}:${HUSHD_GROUP}" \
|
|
||||||
"${HUSHD_PIDDIR}"
|
|
||||||
|
|
||||||
checkpath -f \
|
|
||||||
-o ${HUSHD_USER}:${HUSHD_GROUP} \
|
|
||||||
-m 0660 \
|
|
||||||
${HUSHD_CONFIGFILE}
|
|
||||||
|
|
||||||
checkconfig || return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
checkconfig()
|
|
||||||
{
|
|
||||||
if ! grep -qs '^rpcpassword=' "${HUSHD_CONFIGFILE}" ; then
|
|
||||||
eerror ""
|
|
||||||
eerror "ERROR: You must set a secure rpcpassword to run dragonxd."
|
|
||||||
eerror "The setting must appear in ${HUSHD_CONFIGFILE}"
|
|
||||||
eerror ""
|
|
||||||
eerror "This password is security critical to securing wallets "
|
|
||||||
eerror "and must not be the same as the rpcuser setting."
|
|
||||||
eerror "You can generate a suitable random password using the following"
|
|
||||||
eerror "command from the shell:"
|
|
||||||
eerror ""
|
|
||||||
eerror "bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'"
|
|
||||||
eerror ""
|
|
||||||
eerror ""
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# /etc/conf.d/dragonxd: config file for /etc/init.d/dragonxd
|
|
||||||
|
|
||||||
# Config file location
|
|
||||||
#HUSHD_CONFIGFILE="/etc/hush/hush.conf"
|
|
||||||
|
|
||||||
# What directory to write pidfile to? (created and owned by $HUSHD_USER)
|
|
||||||
#HUSHD_PIDDIR="/var/run/dragonxd"
|
|
||||||
|
|
||||||
# What filename to give the pidfile
|
|
||||||
#HUSHD_PIDFILE="${HUSHD_PIDDIR}/dragonxd.pid"
|
|
||||||
|
|
||||||
# Where to write dragonxd data (be mindful that the blockchain is large)
|
|
||||||
#HUSHD_DATADIR="/var/lib/dragonxd"
|
|
||||||
|
|
||||||
# User and group to own dragonxd process
|
|
||||||
#HUSHD_USER="hush"
|
|
||||||
#HUSHD_GROUP="hush"
|
|
||||||
|
|
||||||
# Path to dragonxd executable
|
|
||||||
#HUSHD_BIN="/usr/bin/dragonxd"
|
|
||||||
|
|
||||||
# Nice value to run dragonxd under
|
|
||||||
#HUSHD_NICE=0
|
|
||||||
|
|
||||||
# Additional options (avoid -conf and -datadir, use flags above)
|
|
||||||
HUSHD_OPTS="-disablewallet"
|
|
||||||
|
|
||||||
# The timeout in seconds OpenRC will wait for dragonxd to terminate
|
|
||||||
# after a SIGTERM has been raised.
|
|
||||||
# Note that this will be mapped as argument to start-stop-daemon's
|
|
||||||
# '--retry' option, which means you can specify a retry schedule
|
|
||||||
# here. For more information see man 8 start-stop-daemon.
|
|
||||||
HUSHD_SIGTERM_TIMEOUT=60
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Hush: Speak And Transact Freely
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=hush
|
|
||||||
Group=hush
|
|
||||||
|
|
||||||
Type=forking
|
|
||||||
PIDFile=/var/lib/dragonxd/dragonxd.pid
|
|
||||||
ExecStart=/usr/bin/dragonxd -daemon -pid=/var/lib/dragonxd/dragonxd.pid \
|
|
||||||
-conf=/etc/hush/hush.conf -datadir=/var/lib/dragonxd -disablewallet
|
|
||||||
|
|
||||||
Restart=always
|
|
||||||
PrivateTmp=true
|
|
||||||
TimeoutStopSec=60s
|
|
||||||
TimeoutStartSec=2s
|
|
||||||
StartLimitInterval=120s
|
|
||||||
StartLimitBurst=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
build_darwin_CC = gcc-8
|
build_darwin_CC = gcc-15
|
||||||
build_darwin_CXX = g++-8
|
build_darwin_CXX = g++-15
|
||||||
build_darwin_AR: = $(shell xcrun -f ar)
|
build_darwin_AR: = $(shell xcrun -f ar)
|
||||||
build_darwin_RANLIB: = $(shell xcrun -f ranlib)
|
build_darwin_RANLIB: = $(shell xcrun -f ranlib)
|
||||||
build_darwin_STRIP: = $(shell xcrun -f strip)
|
build_darwin_STRIP: = $(shell xcrun -f strip)
|
||||||
@@ -10,8 +10,8 @@ build_darwin_SHA256SUM = shasum -a 256
|
|||||||
build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -f -o
|
build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -f -o
|
||||||
|
|
||||||
#darwin host on darwin builder. overrides darwin host preferences.
|
#darwin host on darwin builder. overrides darwin host preferences.
|
||||||
darwin_CC= gcc-8
|
darwin_CC= gcc-15
|
||||||
darwin_CXX= g++-8
|
darwin_CXX= g++-15
|
||||||
darwin_AR:=$(shell xcrun -f ar)
|
darwin_AR:=$(shell xcrun -f ar)
|
||||||
darwin_RANLIB:=$(shell xcrun -f ranlib)
|
darwin_RANLIB:=$(shell xcrun -f ranlib)
|
||||||
darwin_STRIP:=$(shell xcrun -f strip)
|
darwin_STRIP:=$(shell xcrun -f strip)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ OSX_MIN_VERSION=10.12
|
|||||||
OSX_SDK_VERSION=10.12
|
OSX_SDK_VERSION=10.12
|
||||||
OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk
|
OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk
|
||||||
LD64_VERSION=253.9
|
LD64_VERSION=253.9
|
||||||
darwin_CC=gcc-8 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION)
|
darwin_CC=gcc-15 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION)
|
||||||
darwin_CXX=g++-8 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION)
|
darwin_CXX=g++-15 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION)
|
||||||
|
|
||||||
darwin_CFLAGS=-pipe
|
darwin_CFLAGS=-pipe
|
||||||
darwin_CXXFLAGS=$(darwin_CFLAGS)
|
darwin_CXXFLAGS=$(darwin_CFLAGS)
|
||||||
|
|||||||
@@ -40,9 +40,15 @@ define $(package)_preprocess_cmds
|
|||||||
cat $($(package)_patch_dir)/cargo.config | sed 's|CRATE_REGISTRY|$(host_prefix)/$(CRATE_REGISTRY)|' > .cargo/config
|
cat $($(package)_patch_dir)/cargo.config | sed 's|CRATE_REGISTRY|$(host_prefix)/$(CRATE_REGISTRY)|' > .cargo/config
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
ifeq ($(build_os),darwin)
|
||||||
|
define $(package)_build_cmds
|
||||||
|
CARGO=$(HOME)/.cargo/bin/cargo RUSTC=$(HOME)/.cargo/bin/rustc $(HOME)/.cargo/bin/cargo build --package librustzcash $($(package)_build_opts)
|
||||||
|
endef
|
||||||
|
else
|
||||||
define $(package)_build_cmds
|
define $(package)_build_cmds
|
||||||
$(host_prefix)/native/bin/cargo build --package librustzcash $($(package)_build_opts)
|
$(host_prefix)/native/bin/cargo build --package librustzcash $($(package)_build_opts)
|
||||||
endef
|
endef
|
||||||
|
endif
|
||||||
|
|
||||||
define $(package)_stage_cmds
|
define $(package)_stage_cmds
|
||||||
mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
||||||
|
|||||||
8
depends/strip-rlib-metadata.sh
Executable file
8
depends/strip-rlib-metadata.sh
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Strip rust.metadata.bin from .rlib archives for macOS linker compatibility
|
||||||
|
RLIB_DIR="$1"
|
||||||
|
if [ -d "$RLIB_DIR" ]; then
|
||||||
|
for rlib in "$RLIB_DIR"/*.rlib; do
|
||||||
|
[ -f "$rlib" ] && ar d "$rlib" rust.metadata.bin 2>/dev/null || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
rpcuser=dontuseweakusernameoryougetrobbed
|
|
||||||
rpcpassword=dontuseweakpasswordoryougetrobbed
|
|
||||||
txindex=1
|
|
||||||
server=1
|
|
||||||
rpcworkqueue=64
|
|
||||||
addnode=1.2.3.4
|
|
||||||
addnode=5.6.7.8
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# Systemd script for the DragonX daemon
|
|
||||||
|
|
||||||
## Set it up
|
|
||||||
|
|
||||||
First set it up as follows:
|
|
||||||
* Copy dragonxd.service to the systemd user directory, which is /usr/lib/systemd/user directory
|
|
||||||
|
|
||||||
## Basic Usage
|
|
||||||
|
|
||||||
How to start the script:
|
|
||||||
`systemctl start --user dragonxd.service`
|
|
||||||
|
|
||||||
How to stop the script:
|
|
||||||
`systemctl stop --user dragonxd.service`
|
|
||||||
|
|
||||||
How to restart the script:
|
|
||||||
`systemctl restart --user dragonxd.service`
|
|
||||||
|
|
||||||
## How to watch it as it starts
|
|
||||||
|
|
||||||
Use the following on most Linux distros:
|
|
||||||
`watch systemctl status --user dragonxd.service`
|
|
||||||
|
|
||||||
Or watch the log directly:
|
|
||||||
`tail -f ~/.hush/DRAGONX/debug.log`
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
* Don't run it with sudo or root, or it won't work with the wallet.
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=DragonX daemon
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
ExecStart=/usr/bin/dragonxd
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=default.target
|
|
||||||
87
doc/hd-transparent-keys.md
Normal file
87
doc/hd-transparent-keys.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# HD transparent keys
|
||||||
|
|
||||||
|
DragonX derives **transparent** (t-address) keys deterministically from the
|
||||||
|
wallet's HD seed, so they can be recovered from the seed alone — the same way
|
||||||
|
Sapling (shielded) keys already are.
|
||||||
|
|
||||||
|
## Derivation
|
||||||
|
|
||||||
|
Transparent keys are derived over secp256k1 using BIP32/BIP44:
|
||||||
|
|
||||||
|
```
|
||||||
|
m / 44' / coin_type' / 0' / 0 / i
|
||||||
|
```
|
||||||
|
|
||||||
|
* `coin_type` is `Params().BIP44CoinType()` — **141** on mainnet, **1** on
|
||||||
|
test/regtest.
|
||||||
|
* Account is fixed at `0'` and the chain at `0` (external). The internal/change
|
||||||
|
chain (`1`) is **not** used: on this `ac_private=1` chain a non-coinbase
|
||||||
|
transparent output is consensus-invalid, so transparent change can never carry
|
||||||
|
value.
|
||||||
|
* `i` is `CHDChain.transparentChildCounter`, a monotonic index persisted in the
|
||||||
|
wallet so the same addresses regenerate after a seed-only restore.
|
||||||
|
|
||||||
|
Each derived key records its `hdKeypath` and the seed fingerprint (`seedFp`) in
|
||||||
|
its `CKeyMetadata`, matching the Sapling scheme.
|
||||||
|
|
||||||
|
## Why this matters on a private chain
|
||||||
|
|
||||||
|
On DragonX (`ac_private=1` from genesis) a normal user can never *receive* to a
|
||||||
|
transparent address — inbound t-payments are rejected by consensus. The only
|
||||||
|
thing that legitimately lands spendable value on a t-address is a **mining
|
||||||
|
coinbase** (plus notary/burn special cases). There is no "coinbase must be
|
||||||
|
shielded" rule, so mature coinbase is directly spendable.
|
||||||
|
|
||||||
|
So HD transparent keys exist to let a **miner recover coinbase rewards** that
|
||||||
|
were paid to wallet-derived t-addresses, using only the seed.
|
||||||
|
|
||||||
|
## Enabling / disabling
|
||||||
|
|
||||||
|
Controlled by `-hdtransparent` (default **on**). When on and the wallet has an
|
||||||
|
HD seed, every newly generated transparent key (receive address, change,
|
||||||
|
coinbase payout drawn from the keypool) is HD-derived.
|
||||||
|
|
||||||
|
```
|
||||||
|
-hdtransparent=0 # keep the legacy behaviour (random transparent keys)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backing up and restoring
|
||||||
|
|
||||||
|
* **Back up the seed.** `z_exportwallet <file>` writes the 32-byte HD seed as a
|
||||||
|
`# HDSeed=<hex>` line. Guard this value like a private key.
|
||||||
|
* **Restore into a fresh/empty wallet** by starting the node with:
|
||||||
|
|
||||||
|
```
|
||||||
|
-hdseed=<64-hex-character seed>
|
||||||
|
-hdtransparentgaplimit=<n> # HD transparent keys to pre-derive (default 1000)
|
||||||
|
```
|
||||||
|
|
||||||
|
On restore the node injects the seed, pre-derives `n` transparent keys with a
|
||||||
|
genesis birthday, and the normal startup rescan finds any coinbase paid to
|
||||||
|
them. Raise `-hdtransparentgaplimit` if the wallet minted more than `n`
|
||||||
|
distinct coinbase addresses.
|
||||||
|
|
||||||
|
> **Warning:** passing `-hdseed` on the command line exposes the seed to your
|
||||||
|
> shell history and the process list. Prefer putting it in `DRAGONX.conf` with
|
||||||
|
> tight file permissions, and remove it after the restore completes.
|
||||||
|
|
||||||
|
## Limitations (read before relying on recovery)
|
||||||
|
|
||||||
|
* **Legacy random keys are not recoverable.** Any transparent key created before
|
||||||
|
this feature (or with `-hdtransparent=0`) came from the CSPRNG, not the seed,
|
||||||
|
and the phrase/seed will **not** regenerate it. Keep `wallet.dat` /
|
||||||
|
`dumpwallet` backups for those. A wallet that predates the feature and then
|
||||||
|
enables it becomes a *mix* of random (old) and HD (new) keys.
|
||||||
|
* **Gap limit.** A rescan only discovers keys already present in the wallet.
|
||||||
|
Restore pre-derives `-hdtransparentgaplimit` keys; coinbase paid to an index
|
||||||
|
beyond that window is not found until you derive further and rescan again.
|
||||||
|
* **Scope.** Recovers transparent **coinbase** value only, per the consensus
|
||||||
|
rules above. Shielded funds are recovered separately via the Sapling HD keys.
|
||||||
|
|
||||||
|
## On-disk compatibility
|
||||||
|
|
||||||
|
The transparent counter is stored in `CHDChain` under a new serialization
|
||||||
|
version (`VERSION_HD_TRANSPARENT = 2`). Existing v1 `wallet.dat` records load
|
||||||
|
unchanged (the counter defaults to 0); the record is rewritten as v2 the first
|
||||||
|
time an HD transparent key is derived. Downgrading a v2 wallet to an older
|
||||||
|
binary is not supported.
|
||||||
62
doc/init.md
62
doc/init.md
@@ -1,37 +1,37 @@
|
|||||||
|
*** Warning: This document has not been updated for Hush and may be inaccurate. ***
|
||||||
|
|
||||||
|
Sample init scripts and service configuration for bitcoind
|
||||||
Sample init scripts and service configuration for dragonxd
|
|
||||||
==========================================================
|
==========================================================
|
||||||
|
|
||||||
Sample scripts and configuration files for systemd, Upstart and OpenRC
|
Sample scripts and configuration files for systemd, Upstart and OpenRC
|
||||||
can be found in the contrib/init folder.
|
can be found in the contrib/init folder.
|
||||||
|
|
||||||
contrib/init/dragonxd.service: systemd service unit configuration
|
contrib/init/bitcoind.service: systemd service unit configuration
|
||||||
contrib/init/dragonxd.openrc: OpenRC compatible SysV style init script
|
contrib/init/bitcoind.openrc: OpenRC compatible SysV style init script
|
||||||
contrib/init/dragonxd.openrcconf: OpenRC conf.d file
|
contrib/init/bitcoind.openrcconf: OpenRC conf.d file
|
||||||
contrib/init/dragonxd.conf: Upstart service configuration file
|
contrib/init/bitcoind.conf: Upstart service configuration file
|
||||||
contrib/init/dragonxd.init: CentOS compatible SysV style init script
|
contrib/init/bitcoind.init: CentOS compatible SysV style init script
|
||||||
|
|
||||||
1. Service User
|
1. Service User
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
All three startup configurations assume the existence of a "dragonx" user
|
All three startup configurations assume the existence of a "bitcoin" user
|
||||||
and group. They must be created before attempting to use these scripts.
|
and group. They must be created before attempting to use these scripts.
|
||||||
|
|
||||||
2. Configuration
|
2. Configuration
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
At a bare minimum, dragonxd requires that the rpcpassword setting be set
|
At a bare minimum, bitcoind requires that the rpcpassword setting be set
|
||||||
when running as a daemon. If the configuration file does not exist or this
|
when running as a daemon. If the configuration file does not exist or this
|
||||||
setting is not set, dragonxd will shutdown promptly after startup.
|
setting is not set, bitcoind will shutdown promptly after startup.
|
||||||
|
|
||||||
This password does not have to be remembered or typed as it is mostly used
|
This password does not have to be remembered or typed as it is mostly used
|
||||||
as a fixed token that dragonxd and client programs read from the configuration
|
as a fixed token that bitcoind and client programs read from the configuration
|
||||||
file, however it is recommended that a strong and secure password be used
|
file, however it is recommended that a strong and secure password be used
|
||||||
as this password is security critical to securing the wallet should the
|
as this password is security critical to securing the wallet should the
|
||||||
wallet be enabled.
|
wallet be enabled.
|
||||||
|
|
||||||
If dragonxd is run with "-daemon" flag, and no rpcpassword is set, it will
|
If bitcoind is run with "-daemon" flag, and no rpcpassword is set, it will
|
||||||
print a randomly generated suitable password to stderr. You can also
|
print a randomly generated suitable password to stderr. You can also
|
||||||
generate one from the shell yourself like this:
|
generate one from the shell yourself like this:
|
||||||
|
|
||||||
@@ -39,24 +39,24 @@ bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'
|
|||||||
|
|
||||||
|
|
||||||
For an example configuration file that describes the configuration settings,
|
For an example configuration file that describes the configuration settings,
|
||||||
see contrib/debian/examples/DRAGONX.conf.
|
see contrib/debian/examples/bitcoin.conf.
|
||||||
|
|
||||||
3. Paths
|
3. Paths
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
All three configurations assume several paths that might need to be adjusted.
|
All three configurations assume several paths that might need to be adjusted.
|
||||||
|
|
||||||
Binary: /usr/bin/dragonxd
|
Binary: /usr/bin/bitcoind
|
||||||
Configuration file: /etc/dragonx/DRAGONX.conf
|
Configuration file: /etc/bitcoin/bitcoin.conf
|
||||||
Data directory: /var/lib/dragonxd
|
Data directory: /var/lib/bitcoind
|
||||||
PID file: /var/run/dragonxd/dragonxd.pid (OpenRC and Upstart)
|
PID file: /var/run/bitcoind/bitcoind.pid (OpenRC and Upstart)
|
||||||
/var/lib/dragonxd/dragonxd.pid (systemd)
|
/var/lib/bitcoind/bitcoind.pid (systemd)
|
||||||
Lock file: /var/lock/subsys/dragonxd (CentOS)
|
Lock file: /var/lock/subsys/bitcoind (CentOS)
|
||||||
|
|
||||||
The configuration file, PID directory (if applicable) and data directory
|
The configuration file, PID directory (if applicable) and data directory
|
||||||
should all be owned by the dragonx user and group. It is advised for security
|
should all be owned by the bitcoin user and group. It is advised for security
|
||||||
reasons to make the configuration file and data directory only readable by the
|
reasons to make the configuration file and data directory only readable by the
|
||||||
dragonx user and group. Access to dragonx-cli and other dragonxd rpc clients
|
bitcoin user and group. Access to bitcoin-cli and other bitcoind rpc clients
|
||||||
can then be controlled by group membership.
|
can then be controlled by group membership.
|
||||||
|
|
||||||
4. Installing Service Configuration
|
4. Installing Service Configuration
|
||||||
@@ -68,19 +68,19 @@ Installing this .service file consists of just copying it to
|
|||||||
/usr/lib/systemd/system directory, followed by the command
|
/usr/lib/systemd/system directory, followed by the command
|
||||||
"systemctl daemon-reload" in order to update running systemd configuration.
|
"systemctl daemon-reload" in order to update running systemd configuration.
|
||||||
|
|
||||||
To test, run "systemctl start dragonxd" and to enable for system startup run
|
To test, run "systemctl start bitcoind" and to enable for system startup run
|
||||||
"systemctl enable dragonxd"
|
"systemctl enable bitcoind"
|
||||||
|
|
||||||
4b) OpenRC
|
4b) OpenRC
|
||||||
|
|
||||||
Rename dragonxd.openrc to dragonxd and drop it in /etc/init.d. Double
|
Rename bitcoind.openrc to bitcoind and drop it in /etc/init.d. Double
|
||||||
check ownership and permissions and make it executable. Test it with
|
check ownership and permissions and make it executable. Test it with
|
||||||
"/etc/init.d/dragonxd start" and configure it to run on startup with
|
"/etc/init.d/bitcoind start" and configure it to run on startup with
|
||||||
"rc-update add dragonxd"
|
"rc-update add bitcoind"
|
||||||
|
|
||||||
4c) Upstart (for Debian/Ubuntu based distributions)
|
4c) Upstart (for Debian/Ubuntu based distributions)
|
||||||
|
|
||||||
Drop dragonxd.conf in /etc/init. Test by running "service dragonxd start"
|
Drop bitcoind.conf in /etc/init. Test by running "service bitcoind start"
|
||||||
it will automatically start on reboot.
|
it will automatically start on reboot.
|
||||||
|
|
||||||
NOTE: This script is incompatible with CentOS 5 and Amazon Linux 2014 as they
|
NOTE: This script is incompatible with CentOS 5 and Amazon Linux 2014 as they
|
||||||
@@ -88,11 +88,11 @@ use old versions of Upstart and do not supply the start-stop-daemon utility.
|
|||||||
|
|
||||||
4d) CentOS
|
4d) CentOS
|
||||||
|
|
||||||
Copy dragonxd.init to /etc/init.d/dragonxd. Test by running "service dragonxd start".
|
Copy bitcoind.init to /etc/init.d/bitcoind. Test by running "service bitcoind start".
|
||||||
|
|
||||||
Using this script, you can adjust the path and flags to the dragonxd program by
|
Using this script, you can adjust the path and flags to the bitcoind program by
|
||||||
setting the DRAGONXD and FLAGS environment variables in the file
|
setting the BITCOIND and FLAGS environment variables in the file
|
||||||
/etc/sysconfig/dragonxd. You can also use the DAEMONOPTS environment variable here.
|
/etc/sysconfig/bitcoind. You can also use the DAEMONOPTS environment variable here.
|
||||||
|
|
||||||
5. Auto-respawn
|
5. Auto-respawn
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
dist_man1_MANS=dragonxd.1 dragonx-cli.1 dragonx-tx.1
|
dist_man1_MANS=hushd.1 hush-cli.1 hush-tx.1
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
|
||||||
.TH DRAGONX-CLI "1" "March 2026" "dragonx-cli v1.0.0" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
dragonx-cli \- manual page for dragonx-cli v1.0.0
|
|
||||||
.SH DESCRIPTION
|
|
||||||
DragonX RPC client version v1.0.0\-04916cdf5
|
|
||||||
.PP
|
|
||||||
In order to ensure you are adequately protecting your privacy when using DragonX,
|
|
||||||
please see <https://dragonx.is>.
|
|
||||||
.SS "Usage:"
|
|
||||||
.TP
|
|
||||||
dragonx\-cli [options] <command> [params]
|
|
||||||
Send command to DragonX
|
|
||||||
.TP
|
|
||||||
dragonx\-cli [options] help
|
|
||||||
List commands
|
|
||||||
.TP
|
|
||||||
dragonx\-cli [options] help <command>
|
|
||||||
Get help for a command
|
|
||||||
.SH OPTIONS
|
|
||||||
.HP
|
|
||||||
\-?
|
|
||||||
.IP
|
|
||||||
This help message
|
|
||||||
.HP
|
|
||||||
\fB\-conf=\fR<file>
|
|
||||||
.IP
|
|
||||||
Specify configuration file (default: DRAGONX.conf)
|
|
||||||
.HP
|
|
||||||
\fB\-datadir=\fR<dir>
|
|
||||||
.IP
|
|
||||||
Specify data directory (this path cannot use '~')
|
|
||||||
.HP
|
|
||||||
\fB\-testnet\fR
|
|
||||||
.IP
|
|
||||||
Use the test network
|
|
||||||
.HP
|
|
||||||
\fB\-regtest\fR
|
|
||||||
.IP
|
|
||||||
Enter regression test mode, which uses a special chain in which blocks
|
|
||||||
can be solved instantly. This is intended for regression testing
|
|
||||||
tools and app development.
|
|
||||||
.HP
|
|
||||||
\fB\-rpcconnect=\fR<ip>
|
|
||||||
.IP
|
|
||||||
Send commands to node running on <ip> (default: 127.0.0.1)
|
|
||||||
.HP
|
|
||||||
\fB\-rpcport=\fR<port>
|
|
||||||
.IP
|
|
||||||
Connect to JSON\-RPC on <port> (default: 18030 )
|
|
||||||
.HP
|
|
||||||
\fB\-rpcwait\fR
|
|
||||||
.IP
|
|
||||||
Wait for RPC server to start
|
|
||||||
.HP
|
|
||||||
\fB\-rpcuser=\fR<user>
|
|
||||||
.IP
|
|
||||||
Username for JSON\-RPC connections
|
|
||||||
.HP
|
|
||||||
\fB\-rpcpassword=\fR<pw>
|
|
||||||
.IP
|
|
||||||
Password for JSON\-RPC connections
|
|
||||||
.HP
|
|
||||||
\fB\-rpcclienttimeout=\fR<n>
|
|
||||||
.IP
|
|
||||||
Timeout in seconds during HTTP requests, or 0 for no timeout. (default:
|
|
||||||
900)
|
|
||||||
.HP
|
|
||||||
\fB\-stdin\fR
|
|
||||||
.IP
|
|
||||||
Read extra arguments from standard input, one per line until EOF/Ctrl\-D
|
|
||||||
(recommended for sensitive information such as passphrases)
|
|
||||||
.SH COPYRIGHT
|
|
||||||
|
|
||||||
In order to ensure you are adequately protecting your privacy when using DragonX,
|
|
||||||
please see <https://dragonx.is>.
|
|
||||||
|
|
||||||
Copyright (C) 2024-2026 The DragonX Developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2026 Duke Leto and The Hush Developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2020 jl777 and SuperNET developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2018 The Zcash developers
|
|
||||||
|
|
||||||
Copyright (C) 2009-2014 The Bitcoin Core developers
|
|
||||||
|
|
||||||
This is experimental Free Software! Fuck Yeah!!!!!
|
|
||||||
|
|
||||||
Distributed under the GPLv3 software license, see the accompanying file COPYING
|
|
||||||
or <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
|
||||||
.TH DRAGONX-TX "1" "March 2026" "dragonx-tx v1.0.0" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
dragonx-tx \- manual page for dragonx-tx v1.0.0
|
|
||||||
.SH DESCRIPTION
|
|
||||||
DragonX TX utility version v1.0.0\-04916cdf5
|
|
||||||
.SS "Usage:"
|
|
||||||
.TP
|
|
||||||
dragonx\-tx [options] <hex\-tx> [commands]
|
|
||||||
Update hex\-encoded DragonX transaction
|
|
||||||
.TP
|
|
||||||
dragonx\-tx [options] \fB\-create\fR [commands]
|
|
||||||
Create hex\-encoded DragonX transaction
|
|
||||||
.SH OPTIONS
|
|
||||||
.HP
|
|
||||||
\-?
|
|
||||||
.IP
|
|
||||||
This help message
|
|
||||||
.HP
|
|
||||||
\fB\-create\fR
|
|
||||||
.IP
|
|
||||||
Create new, empty TX.
|
|
||||||
.HP
|
|
||||||
\fB\-json\fR
|
|
||||||
.IP
|
|
||||||
Select JSON output
|
|
||||||
.HP
|
|
||||||
\fB\-txid\fR
|
|
||||||
.IP
|
|
||||||
Output only the hex\-encoded transaction id of the resultant transaction.
|
|
||||||
.HP
|
|
||||||
\fB\-regtest\fR
|
|
||||||
.IP
|
|
||||||
Enter regression test mode, which uses a special chain in which blocks
|
|
||||||
can be solved instantly.
|
|
||||||
.HP
|
|
||||||
\fB\-testnet\fR
|
|
||||||
.IP
|
|
||||||
Use the test network
|
|
||||||
.PP
|
|
||||||
Commands:
|
|
||||||
.IP
|
|
||||||
delin=N
|
|
||||||
.IP
|
|
||||||
Delete input N from TX
|
|
||||||
.IP
|
|
||||||
delout=N
|
|
||||||
.IP
|
|
||||||
Delete output N from TX
|
|
||||||
.IP
|
|
||||||
in=TXID:VOUT(:SEQUENCE_NUMBER)
|
|
||||||
.IP
|
|
||||||
Add input to TX
|
|
||||||
.IP
|
|
||||||
locktime=N
|
|
||||||
.IP
|
|
||||||
Set TX lock time to N
|
|
||||||
.IP
|
|
||||||
nversion=N
|
|
||||||
.IP
|
|
||||||
Set TX version to N
|
|
||||||
.IP
|
|
||||||
outaddr=VALUE:ADDRESS
|
|
||||||
.IP
|
|
||||||
Add address\-based output to TX
|
|
||||||
.IP
|
|
||||||
outscript=VALUE:SCRIPT
|
|
||||||
.IP
|
|
||||||
Add raw script output to TX
|
|
||||||
.IP
|
|
||||||
sign=HEIGHT:SIGHASH\-FLAGS
|
|
||||||
.IP
|
|
||||||
Add zero or more signatures to transaction. This command requires JSON
|
|
||||||
registers:prevtxs=JSON object, privatekeys=JSON object. See
|
|
||||||
signrawtransaction docs for format of sighash flags, JSON
|
|
||||||
objects.
|
|
||||||
.PP
|
|
||||||
Register Commands:
|
|
||||||
.IP
|
|
||||||
load=NAME:FILENAME
|
|
||||||
.IP
|
|
||||||
Load JSON file FILENAME into register NAME
|
|
||||||
.IP
|
|
||||||
set=NAME:JSON\-STRING
|
|
||||||
.IP
|
|
||||||
Set register NAME to given JSON\-STRING
|
|
||||||
.SH COPYRIGHT
|
|
||||||
|
|
||||||
In order to ensure you are adequately protecting your privacy when using DragonX,
|
|
||||||
please see <https://dragonx.is>.
|
|
||||||
|
|
||||||
Copyright (C) 2024-2026 The DragonX Developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2026 Duke Leto and The Hush Developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2020 jl777 and SuperNET developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2018 The Zcash developers
|
|
||||||
|
|
||||||
Copyright (C) 2009-2014 The Bitcoin Core developers
|
|
||||||
|
|
||||||
This is experimental Free Software! Fuck Yeah!!!!!
|
|
||||||
|
|
||||||
Distributed under the GPLv3 software license, see the accompanying file COPYING
|
|
||||||
or <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
|
||||||
@@ -1,781 +0,0 @@
|
|||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
|
||||||
.TH DRAGONXD "1" "March 2026" "dragonxd v1.0.0" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
dragonxd \- manual page for dragonxd v1.0.0
|
|
||||||
.SH DESCRIPTION
|
|
||||||
DragonX Daemon version v1.0.0\-04916cdf5
|
|
||||||
.PP
|
|
||||||
In order to ensure you are adequately protecting your privacy when using DragonX,
|
|
||||||
please see <https://dragonx.is>.
|
|
||||||
.SS "Usage:"
|
|
||||||
.TP
|
|
||||||
dragonxd [options]
|
|
||||||
Start a DragonX Daemon
|
|
||||||
.SH OPTIONS
|
|
||||||
.HP
|
|
||||||
\-?
|
|
||||||
.IP
|
|
||||||
This help message
|
|
||||||
.HP
|
|
||||||
\fB\-blocknotify=\fR<cmd>
|
|
||||||
.IP
|
|
||||||
Execute command when the best block changes (%s in cmd is replaced by
|
|
||||||
block hash)
|
|
||||||
.HP
|
|
||||||
\fB\-checkblocks=\fR<n>
|
|
||||||
.IP
|
|
||||||
How many blocks to check at startup (default: 288, 0 = all)
|
|
||||||
.HP
|
|
||||||
\fB\-checklevel=\fR<n>
|
|
||||||
.IP
|
|
||||||
How thorough the block verification of \fB\-checkblocks\fR is (0\-4, default: 3)
|
|
||||||
.HP
|
|
||||||
\fB\-clientname=\fR<SomeName>
|
|
||||||
.IP
|
|
||||||
Full node client name, default 'GoldenSandtrout'
|
|
||||||
.HP
|
|
||||||
\fB\-conf=\fR<file>
|
|
||||||
.IP
|
|
||||||
Specify configuration file (default: DRAGONX.conf)
|
|
||||||
.HP
|
|
||||||
\fB\-daemon\fR
|
|
||||||
.IP
|
|
||||||
Run in the background as a daemon and accept commands
|
|
||||||
.HP
|
|
||||||
\fB\-datadir=\fR<dir>
|
|
||||||
.IP
|
|
||||||
Specify data directory (this path cannot use '~')
|
|
||||||
.HP
|
|
||||||
\fB\-exportdir=\fR<dir>
|
|
||||||
.IP
|
|
||||||
Specify directory to be used when exporting data
|
|
||||||
.HP
|
|
||||||
\fB\-dbcache=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set database cache size in megabytes (4 to 16384, default: 512)
|
|
||||||
.HP
|
|
||||||
\fB\-loadblock=\fR<file>
|
|
||||||
.IP
|
|
||||||
Imports blocks from external blk000??.dat file on startup
|
|
||||||
.HP
|
|
||||||
\fB\-maxdebugfilesize=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set the max size of the debug.log file (default: 15)
|
|
||||||
.HP
|
|
||||||
\fB\-maxorphantx=\fR<n>
|
|
||||||
.IP
|
|
||||||
Keep at most <n> unconnectable transactions in memory (default: 100)
|
|
||||||
.HP
|
|
||||||
\fB\-maxreorg=\fR<n>
|
|
||||||
.IP
|
|
||||||
Specify the maximum length of a blockchain re\-organization
|
|
||||||
.HP
|
|
||||||
\fB\-mempooltxinputlimit=\fR<n>
|
|
||||||
.IP
|
|
||||||
[DEPRECATED/IGNORED] Set the maximum number of transparent inputs in a
|
|
||||||
transaction that the mempool will accept (default: 0 = no limit
|
|
||||||
applied)
|
|
||||||
.HP
|
|
||||||
\fB\-par=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set the number of script verification threads (\fB\-32\fR to 16, 0 = auto, <0 =
|
|
||||||
leave that many cores free, default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-pid=\fR<file>
|
|
||||||
.IP
|
|
||||||
Specify pid file (default: dragonxd.pid)
|
|
||||||
.HP
|
|
||||||
\fB\-txexpirynotify=\fR<cmd>
|
|
||||||
.IP
|
|
||||||
Execute command when transaction expires (%s in cmd is replaced by
|
|
||||||
transaction id)
|
|
||||||
.HP
|
|
||||||
\fB\-prune=\fR<n>
|
|
||||||
.IP
|
|
||||||
Reduce storage requirements by pruning (deleting) old blocks. This mode
|
|
||||||
disables wallet support and is incompatible with \fB\-txindex\fR.
|
|
||||||
Warning: Reverting this setting requires re\-downloading the
|
|
||||||
entire blockchain. (default: 0 = disable pruning blocks, >550 =
|
|
||||||
target size in MiB to use for block files)
|
|
||||||
.HP
|
|
||||||
\fB\-reindex\fR
|
|
||||||
.IP
|
|
||||||
Rebuild block chain index from current blk000??.dat files on startup
|
|
||||||
.HP
|
|
||||||
\fB\-sysperms\fR
|
|
||||||
.IP
|
|
||||||
Create new files with system default permissions, instead of umask 077
|
|
||||||
(only effective with disabled wallet functionality)
|
|
||||||
.HP
|
|
||||||
\fB\-txindex\fR
|
|
||||||
.IP
|
|
||||||
Maintain a full transaction index, used by the getrawtransaction rpc
|
|
||||||
call (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-txsend=\fR<cmd>
|
|
||||||
.IP
|
|
||||||
Execute command to send a transaction instead of broadcasting (%s in cmd
|
|
||||||
is replaced by transaction hex)
|
|
||||||
.HP
|
|
||||||
\fB\-addressindex\fR
|
|
||||||
.IP
|
|
||||||
Maintain a full address index, used to query for the balance, txids and
|
|
||||||
unspent outputs for addresses (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-timestampindex\fR
|
|
||||||
.IP
|
|
||||||
Maintain a timestamp index for block hashes, used to query blocks hashes
|
|
||||||
by a range of timestamps (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-spentindex\fR
|
|
||||||
.IP
|
|
||||||
Maintain a full spent index, used to query the spending txid and input
|
|
||||||
index for an outpoint (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-zindex\fR
|
|
||||||
.IP
|
|
||||||
Maintain extra statistics about shielded transactions and payments
|
|
||||||
(default: 0)
|
|
||||||
.PP
|
|
||||||
Connection options:
|
|
||||||
.HP
|
|
||||||
\fB\-addnode=\fR<ip>
|
|
||||||
.IP
|
|
||||||
Add a node to connect to and attempt to keep the connection open
|
|
||||||
.HP
|
|
||||||
\fB\-asmap=\fR<file>
|
|
||||||
.IP
|
|
||||||
Specify ASN mapping used for bucketing of the peers (default:
|
|
||||||
asmap.dat). Relative paths will be prefixed by the net\-specific
|
|
||||||
datadir location.
|
|
||||||
.HP
|
|
||||||
\fB\-banscore=\fR<n>
|
|
||||||
.IP
|
|
||||||
Threshold for disconnecting misbehaving peers (default: 100)
|
|
||||||
.HP
|
|
||||||
\fB\-bantime=\fR<n>
|
|
||||||
.IP
|
|
||||||
Number of seconds to keep misbehaving peers from reconnecting (default:
|
|
||||||
86400)
|
|
||||||
.HP
|
|
||||||
\fB\-bind=\fR<addr>
|
|
||||||
.IP
|
|
||||||
Bind to given address and always listen on it. Use [host]:port notation
|
|
||||||
for IPv6
|
|
||||||
.HP
|
|
||||||
\fB\-connect=\fR<ip>
|
|
||||||
.IP
|
|
||||||
Connect only to the specified node(s)
|
|
||||||
.HP
|
|
||||||
\fB\-discover\fR
|
|
||||||
.IP
|
|
||||||
Discover own IP addresses (default: 1 when listening and no \fB\-externalip\fR
|
|
||||||
or \fB\-proxy\fR)
|
|
||||||
.HP
|
|
||||||
\fB\-dns\fR
|
|
||||||
.IP
|
|
||||||
Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-dnsseed\fR
|
|
||||||
.IP
|
|
||||||
Query for peer addresses via DNS lookup, if low on addresses (default: 1
|
|
||||||
unless \fB\-connect\fR)
|
|
||||||
.HP
|
|
||||||
\fB\-externalip=\fR<ip>
|
|
||||||
.IP
|
|
||||||
Specify your own public address
|
|
||||||
.HP
|
|
||||||
\fB\-forcednsseed\fR
|
|
||||||
.IP
|
|
||||||
Always query for peer addresses via DNS lookup (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-listen\fR
|
|
||||||
.IP
|
|
||||||
Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR)
|
|
||||||
.HP
|
|
||||||
\fB\-listenonion\fR
|
|
||||||
.IP
|
|
||||||
Automatically create Tor hidden service (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-maxconnections=\fR<n>
|
|
||||||
.IP
|
|
||||||
Maintain at most <n> connections to peers (default: 384)
|
|
||||||
.HP
|
|
||||||
\fB\-maxreceivebuffer=\fR<n>
|
|
||||||
.IP
|
|
||||||
Maximum per\-connection receive buffer, <n>*1000 bytes (default: 5000)
|
|
||||||
.HP
|
|
||||||
\fB\-maxsendbuffer=\fR<n>
|
|
||||||
.IP
|
|
||||||
Maximum per\-connection send buffer, <n>*1000 bytes (default: 1000)
|
|
||||||
.HP
|
|
||||||
\fB\-onion=\fR<ip:port>
|
|
||||||
.IP
|
|
||||||
Use separate SOCKS5 proxy to reach peers via Tor hidden services
|
|
||||||
(default: \fB\-proxy\fR)
|
|
||||||
.HP
|
|
||||||
\fB\-nspv_msg\fR
|
|
||||||
.IP
|
|
||||||
Enable NSPV messages processing (default: true when \fB\-ac_private\fR=\fI\,1\/\fR,
|
|
||||||
otherwise false)
|
|
||||||
.HP
|
|
||||||
\fB\-i2psam=\fR<ip:port>
|
|
||||||
.IP
|
|
||||||
I2P SAM proxy to reach I2P peers and accept I2P connections (default:
|
|
||||||
none)
|
|
||||||
.HP
|
|
||||||
\fB\-i2pacceptincoming\fR
|
|
||||||
.IP
|
|
||||||
If set and \fB\-i2psam\fR is also set then incoming I2P connections are
|
|
||||||
accepted via the SAM proxy. If this is not set but \fB\-i2psam\fR is set
|
|
||||||
then only outgoing connections will be made to the I2P network.
|
|
||||||
Ignored if \fB\-i2psam\fR is not set. Listening for incoming I2P
|
|
||||||
connections is done through the SAM proxy, not by binding to a
|
|
||||||
local address and port (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-onlynet=\fR<net>
|
|
||||||
.IP
|
|
||||||
Only connect to nodes in network <net> (ipv4, ipv6, onion or i2p)
|
|
||||||
.HP
|
|
||||||
\fB\-disableipv4\fR
|
|
||||||
.IP
|
|
||||||
Disable Ipv4 network connections (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-disableipv6\fR
|
|
||||||
.IP
|
|
||||||
Disable Ipv6 network connections (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-clearnet\fR
|
|
||||||
.IP
|
|
||||||
Enable clearnet connections. Setting to 0 will disable clearnet and use
|
|
||||||
sane defaults for Tor/i2p (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-permitbaremultisig\fR
|
|
||||||
.IP
|
|
||||||
Relay non\-P2SH multisig (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-peerbloomfilters\fR
|
|
||||||
.IP
|
|
||||||
Support filtering of blocks and transaction with Bloom filters (default:
|
|
||||||
1)
|
|
||||||
.HP
|
|
||||||
\fB\-port=\fR<port>
|
|
||||||
.IP
|
|
||||||
Listen for connections on <port> (default: 55555 or testnet: 55420)
|
|
||||||
.HP
|
|
||||||
\fB\-proxy=\fR<ip:port>
|
|
||||||
.IP
|
|
||||||
Connect through SOCKS5 proxy
|
|
||||||
.HP
|
|
||||||
\fB\-proxyrandomize\fR
|
|
||||||
.IP
|
|
||||||
Randomize credentials for every proxy connection. This enables Tor
|
|
||||||
stream isolation (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-seednode=\fR<ip>
|
|
||||||
.IP
|
|
||||||
Connect to a node to retrieve peer addresses, and disconnect
|
|
||||||
.HP
|
|
||||||
\fB\-timeout=\fR<n>
|
|
||||||
.IP
|
|
||||||
Specify connection timeout in milliseconds (minimum: 1, default: 60000)
|
|
||||||
.HP
|
|
||||||
\fB\-torcontrol=\fR<ip>:<port>
|
|
||||||
.IP
|
|
||||||
Tor control port to use if onion listening enabled (default:
|
|
||||||
127.0.0.1:9051)
|
|
||||||
.HP
|
|
||||||
\fB\-torpassword=\fR<pass>
|
|
||||||
.IP
|
|
||||||
Tor control port password (default: empty)
|
|
||||||
.HP
|
|
||||||
\fB\-tls=\fR<option>
|
|
||||||
.IP
|
|
||||||
Specify TLS usage (default: 1 => enabled and required); Cannot be turned
|
|
||||||
off.
|
|
||||||
.HP
|
|
||||||
\fB\-tlsvalidate=\fR<0 or 1>
|
|
||||||
.IP
|
|
||||||
Connect to peers only with valid certificates (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-tlskeypath=\fR<path>
|
|
||||||
.IP
|
|
||||||
Full path to a private key
|
|
||||||
.HP
|
|
||||||
\fB\-tlskeypwd=\fR<password>
|
|
||||||
.IP
|
|
||||||
Password for a private key encryption (default: not set, i.e. private
|
|
||||||
key will be stored unencrypted)
|
|
||||||
.HP
|
|
||||||
\fB\-tlscertpath=\fR<path>
|
|
||||||
.IP
|
|
||||||
Full path to a certificate
|
|
||||||
.HP
|
|
||||||
\fB\-tlstrustdir=\fR<path>
|
|
||||||
.IP
|
|
||||||
Full path to a trusted certificates directory
|
|
||||||
.HP
|
|
||||||
\fB\-allowbind=\fR<addr>
|
|
||||||
.IP
|
|
||||||
Bind to given address and allowlist peers connecting to it. Use
|
|
||||||
[host]:port notation for IPv6
|
|
||||||
.HP
|
|
||||||
\fB\-allowlist=\fR<netmask>
|
|
||||||
.IP
|
|
||||||
Allowlist peers connecting from the given netmask or IP address. Can be
|
|
||||||
specified multiple times. Allowlisted peers cannot be DoS banned
|
|
||||||
and their transactions are always relayed, even if they are
|
|
||||||
already in the mempool, useful e.g. for a gateway
|
|
||||||
.PP
|
|
||||||
Wallet options:
|
|
||||||
.HP
|
|
||||||
\fB\-disablewallet\fR
|
|
||||||
.IP
|
|
||||||
Do not load the wallet and disable wallet RPC calls
|
|
||||||
.HP
|
|
||||||
\fB\-keypool=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set key pool size to <n> (default: 100)
|
|
||||||
.HP
|
|
||||||
\fB\-consolidation\fR
|
|
||||||
.IP
|
|
||||||
Enable auto Sapling note consolidation (default: false)
|
|
||||||
.HP
|
|
||||||
\fB\-consolidationinterval\fR
|
|
||||||
.IP
|
|
||||||
Block interval between consolidations (default: 25)
|
|
||||||
.HP
|
|
||||||
\fB\-consolidatesaplingaddress=\fR<zaddr>
|
|
||||||
.IP
|
|
||||||
Specify Sapling Address to Consolidate. (default: all)
|
|
||||||
.HP
|
|
||||||
\fB\-consolidationtxfee\fR
|
|
||||||
.IP
|
|
||||||
Fee amount in Puposhis used send consolidation transactions. (default
|
|
||||||
10000)
|
|
||||||
.HP
|
|
||||||
\fB\-zsweep\fR
|
|
||||||
.IP
|
|
||||||
Enable zaddr sweeping, automatically move all shielded funds to a one
|
|
||||||
address once per X blocks
|
|
||||||
.HP
|
|
||||||
\fB\-zsweepaddress=\fR<zaddr>
|
|
||||||
.IP
|
|
||||||
Specify the shielded address where swept funds will be sent)
|
|
||||||
.HP
|
|
||||||
\fB\-zsweepfee\fR
|
|
||||||
.IP
|
|
||||||
Fee amount in puposhis used send sweep transactions. (default 10000)
|
|
||||||
.HP
|
|
||||||
\fB\-zsweepinterval\fR
|
|
||||||
.IP
|
|
||||||
Sweep shielded funds every X blocks (default 5)
|
|
||||||
.HP
|
|
||||||
\fB\-zsweepmaxinputs\fR
|
|
||||||
.IP
|
|
||||||
Maximum number of shielded inputs to sweep per transaction (default 8)
|
|
||||||
.HP
|
|
||||||
\fB\-zsweepexternal\fR
|
|
||||||
.IP
|
|
||||||
Enable sweeping to an external wallet (default false)
|
|
||||||
.HP
|
|
||||||
\fB\-zsweepexclude\fR
|
|
||||||
.IP
|
|
||||||
Addresses to exclude from sweeping (default none)
|
|
||||||
.HP
|
|
||||||
\fB\-deletetx\fR
|
|
||||||
.IP
|
|
||||||
Enable Old Transaction Deletion
|
|
||||||
.HP
|
|
||||||
\fB\-deleteinterval\fR
|
|
||||||
.IP
|
|
||||||
Delete transaction every <n> blocks during inital block download
|
|
||||||
(default: 1000)
|
|
||||||
.HP
|
|
||||||
\fB\-keeptxnum\fR
|
|
||||||
.IP
|
|
||||||
Keep the last <n> transactions (default: 200)
|
|
||||||
.HP
|
|
||||||
\fB\-keeptxfornblocks\fR
|
|
||||||
.IP
|
|
||||||
Keep transactions for at least <n> blocks (default: 10000)
|
|
||||||
.HP
|
|
||||||
\fB\-paytxfee=\fR<amt>
|
|
||||||
.IP
|
|
||||||
Fee (in HUSH/kB) to add to transactions you send (default: 0.00)
|
|
||||||
.HP
|
|
||||||
\fB\-keepnotewitnesscache\fR
|
|
||||||
.IP
|
|
||||||
Keep partial Sapling Note Witness cache. Must be used with \fB\-rescanheight\fR
|
|
||||||
to find missing cache items.
|
|
||||||
.HP
|
|
||||||
\fB\-rescan\fR
|
|
||||||
.IP
|
|
||||||
Rescan the block chain for missing wallet transactions on startup
|
|
||||||
.HP
|
|
||||||
\fB\-rescanheight\fR
|
|
||||||
.IP
|
|
||||||
Rescan from specified height when rescan=1 on startup
|
|
||||||
.HP
|
|
||||||
\fB\-salvagewallet\fR
|
|
||||||
.IP
|
|
||||||
Attempt to recover private keys from a corrupt wallet.dat on startup
|
|
||||||
.HP
|
|
||||||
\fB\-sendfreetransactions\fR
|
|
||||||
.IP
|
|
||||||
Send transactions as zero\-fee transactions if possible (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-spendzeroconfchange\fR
|
|
||||||
.IP
|
|
||||||
Spend unconfirmed change when sending transactions (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-txconfirmtarget=\fR<n>
|
|
||||||
.IP
|
|
||||||
If paytxfee is not set, include enough fee so transactions begin
|
|
||||||
confirmation on average within n blocks (default: 2)
|
|
||||||
.HP
|
|
||||||
\fB\-txexpirydelta\fR
|
|
||||||
.IP
|
|
||||||
Set the number of blocks after which a transaction that has not been
|
|
||||||
mined will become invalid (default: 200)
|
|
||||||
.HP
|
|
||||||
\fB\-maxtxfee=\fR<amt>
|
|
||||||
.IP
|
|
||||||
Maximum total fees (in HUSH) to use in a single wallet transaction;
|
|
||||||
setting this too low may abort large transactions (default: 0.10)
|
|
||||||
.HP
|
|
||||||
\fB\-upgradewallet\fR
|
|
||||||
.IP
|
|
||||||
Upgrade wallet to latest format on startup
|
|
||||||
.HP
|
|
||||||
\fB\-wallet=\fR<file>
|
|
||||||
.IP
|
|
||||||
Specify wallet file absolute path or a path relative to the data
|
|
||||||
directory (default: wallet.dat)
|
|
||||||
.HP
|
|
||||||
\fB\-walletbroadcast\fR
|
|
||||||
.IP
|
|
||||||
Make the wallet broadcast transactions (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-walletnotify=\fR<cmd>
|
|
||||||
.IP
|
|
||||||
Execute command when a wallet transaction changes (%s in cmd is replaced
|
|
||||||
by TxID)
|
|
||||||
.HP
|
|
||||||
\fB\-allowlistaddress=\fR<Raddress>
|
|
||||||
.IP
|
|
||||||
Enable the wallet filter for notary nodes and add one Raddress to the
|
|
||||||
allowlist of the wallet filter. If \fB\-allowlistaddress=\fR is used,
|
|
||||||
then the wallet filter is automatically activated. Several
|
|
||||||
Raddresses can be defined using several \fB\-allowlistaddress=\fR
|
|
||||||
(similar to \fB\-addnode\fR). The wallet filter will filter the utxo to
|
|
||||||
only ones coming from my own Raddress (derived from pubkey) and
|
|
||||||
each Raddress defined using \fB\-allowlistaddress=\fR this option is
|
|
||||||
mostly for Notary Nodes).
|
|
||||||
.HP
|
|
||||||
\fB\-zapwallettxes=\fR<mode>
|
|
||||||
.IP
|
|
||||||
Delete all wallet transactions and only recover those parts of the
|
|
||||||
blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g.
|
|
||||||
account owner and payment request information, 2 = drop tx meta
|
|
||||||
data)
|
|
||||||
.PP
|
|
||||||
Debugging/Testing options:
|
|
||||||
.HP
|
|
||||||
\fB\-debug=\fR<category>
|
|
||||||
.IP
|
|
||||||
Output debugging information (default: 0, supplying <category> is
|
|
||||||
optional). If <category> is not supplied or if <category> = 1,
|
|
||||||
output all debugging information. <category> can be: addrman,
|
|
||||||
bench, coindb, db, deletetx, estimatefee, http, libevent, lock,
|
|
||||||
mempool, net, tls, partitioncheck, pow, proxy, prune, rand,
|
|
||||||
randomx, reindex, rpc, selectcoins, stratum, tor, zrpc,
|
|
||||||
zrpcunsafe (implies zrpc).
|
|
||||||
.HP
|
|
||||||
\fB\-experimentalfeatures\fR
|
|
||||||
.IP
|
|
||||||
Enable use of experimental features
|
|
||||||
.HP
|
|
||||||
\fB\-help\-debug\fR
|
|
||||||
.IP
|
|
||||||
Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR)
|
|
||||||
.HP
|
|
||||||
\fB\-logips\fR
|
|
||||||
.IP
|
|
||||||
Include IP addresses in debug output (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-logtimestamps\fR
|
|
||||||
.IP
|
|
||||||
Prepend debug output with timestamp (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-minrelaytxfee=\fR<amt>
|
|
||||||
.IP
|
|
||||||
Fees (in HUSH/kB) smaller than this are considered zero fee for relaying
|
|
||||||
(default: 0.000001)
|
|
||||||
.HP
|
|
||||||
\fB\-printtoconsole\fR
|
|
||||||
.IP
|
|
||||||
Send trace/debug info to console instead of debug.log file
|
|
||||||
.HP
|
|
||||||
\fB\-shrinkdebugfile\fR
|
|
||||||
.IP
|
|
||||||
Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR)
|
|
||||||
.HP
|
|
||||||
\fB\-testnet\fR
|
|
||||||
.IP
|
|
||||||
Use the test network
|
|
||||||
.PP
|
|
||||||
Node relay options:
|
|
||||||
.HP
|
|
||||||
\fB\-datacarrier\fR
|
|
||||||
.IP
|
|
||||||
Relay and mine data carrier transactions (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-datacarriersize\fR
|
|
||||||
.IP
|
|
||||||
Maximum size of data in data carrier transactions we relay and mine
|
|
||||||
(default: 8192)
|
|
||||||
.PP
|
|
||||||
Block creation options:
|
|
||||||
.HP
|
|
||||||
\fB\-blockminsize=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set minimum block size in bytes (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-blockmaxsize=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set maximum block size in bytes (default: 2000000)
|
|
||||||
.HP
|
|
||||||
\fB\-blockprioritysize=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set maximum size of high\-priority/low\-fee transactions in bytes
|
|
||||||
(default: 1000000)
|
|
||||||
.PP
|
|
||||||
Mining options:
|
|
||||||
.HP
|
|
||||||
\fB\-gen\fR
|
|
||||||
.IP
|
|
||||||
Mine/generate coins (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-genproclimit=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set the number of threads for coin mining if enabled (\fB\-1\fR = all cores,
|
|
||||||
default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-equihashsolver=\fR<name>
|
|
||||||
.IP
|
|
||||||
Specify the Equihash solver to be used if enabled (default: "default")
|
|
||||||
.HP
|
|
||||||
\fB\-mineraddress=\fR<addr>
|
|
||||||
.IP
|
|
||||||
Send mined coins to a specific single address
|
|
||||||
.HP
|
|
||||||
\fB\-minetolocalwallet\fR
|
|
||||||
.IP
|
|
||||||
Require that mined blocks use a coinbase address in the local wallet
|
|
||||||
(default: 1)
|
|
||||||
.PP
|
|
||||||
RPC server options:
|
|
||||||
.HP
|
|
||||||
\fB\-server\fR
|
|
||||||
.IP
|
|
||||||
Accept command line and JSON\-RPC commands
|
|
||||||
.HP
|
|
||||||
\fB\-rest\fR
|
|
||||||
.IP
|
|
||||||
Accept public REST requests (default: 0)
|
|
||||||
.HP
|
|
||||||
\fB\-rpcbind=\fR<addr>
|
|
||||||
.IP
|
|
||||||
Bind to given address to listen for JSON\-RPC connections. Use
|
|
||||||
[host]:port notation for IPv6. This option can be specified
|
|
||||||
multiple times (default: bind to all interfaces)
|
|
||||||
.HP
|
|
||||||
\fB\-rpcuser=\fR<user>
|
|
||||||
.IP
|
|
||||||
Username for JSON\-RPC connections
|
|
||||||
.HP
|
|
||||||
\fB\-rpcpassword=\fR<pw>
|
|
||||||
.IP
|
|
||||||
Password for JSON\-RPC connections
|
|
||||||
.HP
|
|
||||||
\fB\-rpcport=\fR<port>
|
|
||||||
.IP
|
|
||||||
Listen for JSON\-RPC connections on <port> (default: 0 or testnet: 10000)
|
|
||||||
.HP
|
|
||||||
\fB\-rpcallowip=\fR<ip>
|
|
||||||
.IP
|
|
||||||
Allow JSON\-RPC connections from specified source. Valid for <ip> are a
|
|
||||||
single IP (e.g. 1.2.3.4), a network/netmask (e.g.
|
|
||||||
1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This
|
|
||||||
option can be specified multiple times
|
|
||||||
.HP
|
|
||||||
\fB\-rpcthreads=\fR<n>
|
|
||||||
.IP
|
|
||||||
Set the number of threads to service RPC calls (default: 8)
|
|
||||||
.PP
|
|
||||||
Metrics Options (only if \fB\-daemon\fR and \fB\-printtoconsole\fR are not set):
|
|
||||||
.HP
|
|
||||||
\fB\-showmetrics\fR
|
|
||||||
.IP
|
|
||||||
Show metrics on stdout (default: 1 if running in a console, 0 otherwise)
|
|
||||||
.HP
|
|
||||||
\fB\-metricsui\fR
|
|
||||||
.IP
|
|
||||||
Set to 1 for a persistent metrics screen, 0 for sequential metrics
|
|
||||||
output (default: 1 if running in a console, 0 otherwise)
|
|
||||||
.HP
|
|
||||||
\fB\-metricsrefreshtime\fR
|
|
||||||
.IP
|
|
||||||
Number of seconds between metrics refreshes (default: 1 if running in a
|
|
||||||
console, 600 otherwise)
|
|
||||||
.PP
|
|
||||||
Stratum server options:
|
|
||||||
.HP
|
|
||||||
\fB\-stratum\fR
|
|
||||||
.IP
|
|
||||||
Enable stratum server (default: off)
|
|
||||||
.HP
|
|
||||||
\fB\-stratumaddress=\fR<address>
|
|
||||||
.IP
|
|
||||||
Mining address to use when special address of 'x' is sent by miner
|
|
||||||
(default: none)
|
|
||||||
.HP
|
|
||||||
\fB\-stratumbind=\fR<ipaddr>
|
|
||||||
.IP
|
|
||||||
Bind to given address to listen for Stratum work requests. Use
|
|
||||||
[host]:port notation for IPv6. This option can be specified
|
|
||||||
multiple times (default: bind to all interfaces)
|
|
||||||
.HP
|
|
||||||
\fB\-stratumport=\fR<port>
|
|
||||||
.IP
|
|
||||||
Listen for Stratum work requests on <port> (default: 19031 or testnet:
|
|
||||||
19031)
|
|
||||||
.HP
|
|
||||||
\fB\-stratumallowip=\fR<ip>
|
|
||||||
.IP
|
|
||||||
Allow Stratum work requests from specified source. Valid for <ip> are a
|
|
||||||
single IP (e.g. 1.2.3.4), a network/netmask (e.g.
|
|
||||||
1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This
|
|
||||||
option can be specified multiple times
|
|
||||||
.PP
|
|
||||||
DragonX Chain options:
|
|
||||||
.HP
|
|
||||||
\fB\-ac_algo\fR
|
|
||||||
.IP
|
|
||||||
Choose PoW mining algorithm, either 'equihash' or 'randomx'. default is
|
|
||||||
Equihash (200,9)
|
|
||||||
.HP
|
|
||||||
\fB\-ac_blocktime\fR
|
|
||||||
.IP
|
|
||||||
Block time in seconds, default is 60
|
|
||||||
.HP
|
|
||||||
\fB\-ac_beam\fR
|
|
||||||
.IP
|
|
||||||
BEAM integration
|
|
||||||
.HP
|
|
||||||
\fB\-ac_burn\fR
|
|
||||||
.IP
|
|
||||||
Allow sending funds to the transparent burn address when \fB\-ac_private\fR=\fI\,1\/\fR
|
|
||||||
.HP
|
|
||||||
\fB\-ac_minopreturnfee\fR
|
|
||||||
.IP
|
|
||||||
OP_RETURN minimum fee per tx, regardless of tx size, default is 1 coin
|
|
||||||
.HP
|
|
||||||
\fB\-ac_coda\fR
|
|
||||||
.IP
|
|
||||||
CODA integration
|
|
||||||
.HP
|
|
||||||
\fB\-ac_clearnet\fR
|
|
||||||
.IP
|
|
||||||
Enable or disable clearnet connections for the entire blockchain.
|
|
||||||
Setting to 0 will disable clearnet and use sane defaults for
|
|
||||||
Tor/i2p and require all nodes to do the same (default: 1)
|
|
||||||
.HP
|
|
||||||
\fB\-ac_decay\fR
|
|
||||||
.IP
|
|
||||||
Percentage of block reward decrease at each halving
|
|
||||||
.HP
|
|
||||||
\fB\-ac_end\fR
|
|
||||||
.IP
|
|
||||||
Block height at which block rewards will end
|
|
||||||
.HP
|
|
||||||
\fB\-ac_eras\fR
|
|
||||||
.IP
|
|
||||||
Block reward eras
|
|
||||||
.HP
|
|
||||||
\fB\-ac_founders\fR
|
|
||||||
.IP
|
|
||||||
Number of blocks between founders reward payouts
|
|
||||||
.HP
|
|
||||||
\fB\-ac_halving\fR
|
|
||||||
.IP
|
|
||||||
Number of blocks between each block reward halving
|
|
||||||
.HP
|
|
||||||
\fB\-ac_name\fR
|
|
||||||
.IP
|
|
||||||
Name of asset chain
|
|
||||||
.HP
|
|
||||||
\fB\-ac_notarypay\fR
|
|
||||||
.IP
|
|
||||||
Pay notaries, default 0
|
|
||||||
.HP
|
|
||||||
\fB\-ac_perc\fR
|
|
||||||
.IP
|
|
||||||
Percentage of block rewards paid to the founder
|
|
||||||
.HP
|
|
||||||
\fB\-ac_private\fR
|
|
||||||
.IP
|
|
||||||
Shielded transactions only (except coinbase + notaries), default is 0
|
|
||||||
.HP
|
|
||||||
\fB\-ac_pubkey\fR
|
|
||||||
.IP
|
|
||||||
Public key for receiving payments on the network
|
|
||||||
.HP
|
|
||||||
\fB\-ac_public\fR
|
|
||||||
.IP
|
|
||||||
Transparent transactions only, default 0
|
|
||||||
.HP
|
|
||||||
\fB\-ac_randomx_interval\fR
|
|
||||||
.IP
|
|
||||||
Controls how often the RandomX key block will change, default is 1024
|
|
||||||
.HP
|
|
||||||
\fB\-ac_randomx_lag\fR
|
|
||||||
.IP
|
|
||||||
Sets the number of RandomX blocks to wait before updating the key block,
|
|
||||||
default is 64
|
|
||||||
.HP
|
|
||||||
\fB\-ac_reward\fR
|
|
||||||
.IP
|
|
||||||
Block reward in satoshis, default is 0
|
|
||||||
.HP
|
|
||||||
\fB\-ac_script\fR
|
|
||||||
.IP
|
|
||||||
P2SH/multisig address to receive founders rewards
|
|
||||||
.HP
|
|
||||||
\fB\-ac_supply\fR
|
|
||||||
.IP
|
|
||||||
Starting supply, default is 10
|
|
||||||
.HP
|
|
||||||
\fB\-ac_txpow\fR
|
|
||||||
.IP
|
|
||||||
Enforce transaction\-rate limit, default 0
|
|
||||||
.SH COPYRIGHT
|
|
||||||
|
|
||||||
In order to ensure you are adequately protecting your privacy when using DragonX,
|
|
||||||
please see <https://dragonx.is>.
|
|
||||||
|
|
||||||
Copyright (C) 2024-2026 The DragonX Developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2026 Duke Leto and The Hush Developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2020 jl777 and SuperNET developers
|
|
||||||
|
|
||||||
Copyright (C) 2016-2018 The Zcash developers
|
|
||||||
|
|
||||||
Copyright (C) 2009-2014 The Bitcoin Core developers
|
|
||||||
|
|
||||||
This is experimental Free Software! Fuck Yeah!!!!!
|
|
||||||
|
|
||||||
Distributed under the GPLv3 software license, see the accompanying file COPYING
|
|
||||||
or <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
|
||||||
90
doc/seed-phrase.md
Normal file
90
doc/seed-phrase.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# BIP39 seed phrases (SilentDragonXLite-compatible)
|
||||||
|
|
||||||
|
DragonX full-node wallets can be created from and restored to a **BIP39 24-word
|
||||||
|
seed phrase** that is **byte-for-byte compatible with SilentDragonXLite**: the
|
||||||
|
same words produce the same transparent (t-) and shielded (z-) addresses in
|
||||||
|
either wallet, so funds move between the light wallet and the full node with one
|
||||||
|
backup.
|
||||||
|
|
||||||
|
## What makes them compatible
|
||||||
|
|
||||||
|
Compatibility requires the mnemonic, the seed derivation, and every HD path to
|
||||||
|
match exactly. They do:
|
||||||
|
|
||||||
|
| Detail | Value (both wallets) |
|
||||||
|
|---|---|
|
||||||
|
| Word list | BIP39 English, 2048 words |
|
||||||
|
| Passphrase | empty (no "25th word") |
|
||||||
|
| Mnemonic → seed | PBKDF2-HMAC-SHA512, 2048 rounds, salt `"mnemonic"`, 64-byte output |
|
||||||
|
| Coin type | 141 (KMD SLIP-0044) |
|
||||||
|
| Shielded path | `m/32'/141'/i'` (ZIP-32) |
|
||||||
|
| Transparent path | `m/44'/141'/0'/0/i` (BIP44) |
|
||||||
|
|
||||||
|
The node stores the 32-byte BIP39 **entropy** (SilentDragonXLite's on-disk
|
||||||
|
convention) and expands it to the 64-byte seed on demand for derivation. The
|
||||||
|
node's vendored BIP39 library (`src/crypto/bip39`) is byte-identical to
|
||||||
|
SilentDragonXLite's `tiny-bip39` 0.6.2, and the derivation is anchored by a
|
||||||
|
known-answer test (`src/gtest/test_mnemonic_compat.cpp`).
|
||||||
|
|
||||||
|
## Restore from a phrase
|
||||||
|
|
||||||
|
Start the node once, on a **fresh/empty datadir**, with the phrase:
|
||||||
|
|
||||||
|
```
|
||||||
|
dragonxd -mnemonic="word1 word2 ... word24"
|
||||||
|
```
|
||||||
|
|
||||||
|
or, preferably (keeps the phrase out of your shell history and process list),
|
||||||
|
put it in `DRAGONX.conf` with tight permissions:
|
||||||
|
|
||||||
|
```
|
||||||
|
mnemonic=word1 word2 ... word24
|
||||||
|
```
|
||||||
|
|
||||||
|
On restore the node pre-derives keys and rescans from genesis to recover funds:
|
||||||
|
|
||||||
|
* `-hdtransparentgaplimit=<n>` — HD transparent keys to pre-derive (default 1000)
|
||||||
|
* `-mnemonicsaplinggap=<n>` — shielded addresses to pre-derive (default 100)
|
||||||
|
|
||||||
|
Raise these if the wallet used many addresses. Restore only works on a wallet
|
||||||
|
with no seed yet (a brand-new datadir); it refuses to overwrite an existing seed.
|
||||||
|
|
||||||
|
## Create a new phrase on the node
|
||||||
|
|
||||||
|
By default new node wallets use a random (non-mnemonic) seed. To create a new
|
||||||
|
wallet from a fresh 24-word phrase instead — so you can export it and use it in
|
||||||
|
SilentDragonXLite — start with:
|
||||||
|
|
||||||
|
```
|
||||||
|
dragonxd -usemnemonic
|
||||||
|
```
|
||||||
|
|
||||||
|
## Show / back up the phrase
|
||||||
|
|
||||||
|
For a mnemonic wallet (created with `-usemnemonic` or restored with `-mnemonic`):
|
||||||
|
|
||||||
|
```
|
||||||
|
dragonx-cli z_exportmnemonic
|
||||||
|
```
|
||||||
|
|
||||||
|
returns the 24 words and the seed fingerprint. The wallet must be unlocked.
|
||||||
|
Guard the phrase like a private key.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
* **English + empty passphrase only.** Any other word list or a BIP39 passphrase
|
||||||
|
would break compatibility, so they are not accepted.
|
||||||
|
* **Legacy / random-seed wallets have no phrase.** A wallet created before this
|
||||||
|
feature (or without `-usemnemonic`) has a random seed; `z_exportmnemonic`
|
||||||
|
returns an error for it — use `z_exportwallet` to back up the raw seed. Such
|
||||||
|
wallets are not SilentDragonXLite-compatible.
|
||||||
|
* **Scope.** Recovers HD-derived shielded funds and transparent coinbase (see
|
||||||
|
[hd-transparent-keys.md](hd-transparent-keys.md) for why only coinbase lands on
|
||||||
|
t-addresses on this `ac_private=1` chain). Keys imported with `z_importkey` are
|
||||||
|
not seed-derived and are not recovered by the phrase.
|
||||||
|
|
||||||
|
## On-disk compatibility
|
||||||
|
|
||||||
|
Mnemonic wallets set `CHDChain` version 3 (`VERSION_HD_MNEMONIC`). Older wallet
|
||||||
|
records load unchanged. Downgrading a mnemonic wallet to an older binary is not
|
||||||
|
supported.
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
# Copyright 2016-2024 The Hush developers
|
# Copyright 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2024-2026 The DragonX 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
|
||||||
|
|
||||||
@@ -40,15 +39,22 @@ BITCOIN_INCLUDES += -I$(srcdir)/univalue/include
|
|||||||
BITCOIN_INCLUDES += -I$(srcdir)/leveldb/include
|
BITCOIN_INCLUDES += -I$(srcdir)/leveldb/include
|
||||||
|
|
||||||
if TARGET_WINDOWS
|
if TARGET_WINDOWS
|
||||||
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
|
LIBBITCOIN_SERVER=libbitcoin_server.a
|
||||||
endif
|
endif
|
||||||
if TARGET_DARWIN
|
if TARGET_DARWIN
|
||||||
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
|
LIBBITCOIN_SERVER=libbitcoin_server.a
|
||||||
endif
|
endif
|
||||||
if TARGET_LINUX
|
if TARGET_LINUX
|
||||||
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
|
LIBBITCOIN_SERVER=libbitcoin_server.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# libcurl is a linker flag, not a buildable library file. It must NOT live inside
|
||||||
|
# LIBBITCOIN_SERVER, which is also fed into EXTRA_LIBRARIES (a list of files automake
|
||||||
|
# builds) where a -l flag is illegal and triggers a portability error. Keep it as its
|
||||||
|
# own variable, added to each binary's _LDADD after libbitcoin_server.a (whose objects
|
||||||
|
# reference curl symbols) so static link order stays correct.
|
||||||
|
LIBCURL = -lcurl
|
||||||
|
|
||||||
LIBBITCOIN_WALLET=libbitcoin_wallet.a
|
LIBBITCOIN_WALLET=libbitcoin_wallet.a
|
||||||
LIBBITCOIN_COMMON=libbitcoin_common.a
|
LIBBITCOIN_COMMON=libbitcoin_common.a
|
||||||
LIBBITCOIN_CLI=libbitcoin_cli.a
|
LIBBITCOIN_CLI=libbitcoin_cli.a
|
||||||
@@ -319,6 +325,7 @@ libbitcoin_wallet_a_SOURCES = \
|
|||||||
wallet/asyncrpcoperation_shieldcoinbase.cpp \
|
wallet/asyncrpcoperation_shieldcoinbase.cpp \
|
||||||
wallet/crypter.cpp \
|
wallet/crypter.cpp \
|
||||||
wallet/db.cpp \
|
wallet/db.cpp \
|
||||||
|
wallet/mnemonic.cpp \
|
||||||
zcash/Note.cpp \
|
zcash/Note.cpp \
|
||||||
transaction_builder.cpp \
|
transaction_builder.cpp \
|
||||||
wallet/rpcdump.cpp \
|
wallet/rpcdump.cpp \
|
||||||
@@ -355,6 +362,23 @@ crypto_libbitcoin_crypto_a_SOURCES = \
|
|||||||
crypto/sha512.cpp \
|
crypto/sha512.cpp \
|
||||||
crypto/sha512.h
|
crypto/sha512.h
|
||||||
|
|
||||||
|
# Vendored trezor-crypto BIP39 (mnemonic seed phrases). Kept self-contained so
|
||||||
|
# the same 24 words are compatible with SilentDragonXLite (tiny-bip39 0.6.2).
|
||||||
|
crypto_libbitcoin_crypto_a_SOURCES += \
|
||||||
|
crypto/bip39/bip39.c \
|
||||||
|
crypto/bip39/bip39.h \
|
||||||
|
crypto/bip39/bip39_english.h \
|
||||||
|
crypto/bip39/pbkdf2.c \
|
||||||
|
crypto/bip39/pbkdf2.h \
|
||||||
|
crypto/bip39/hmac.c \
|
||||||
|
crypto/bip39/hmac.h \
|
||||||
|
crypto/bip39/sha2.c \
|
||||||
|
crypto/bip39/sha2.h \
|
||||||
|
crypto/bip39/memzero.c \
|
||||||
|
crypto/bip39/memzero.h \
|
||||||
|
crypto/bip39/options.h \
|
||||||
|
crypto/bip39/rand.h
|
||||||
|
|
||||||
if EXPERIMENTAL_ASM
|
if EXPERIMENTAL_ASM
|
||||||
crypto_libbitcoin_crypto_a_SOURCES += crypto/sha256_sse4.cpp
|
crypto_libbitcoin_crypto_a_SOURCES += crypto/sha256_sse4.cpp
|
||||||
endif
|
endif
|
||||||
@@ -465,6 +489,7 @@ endif
|
|||||||
|
|
||||||
dragonxd_LDADD = \
|
dragonxd_LDADD = \
|
||||||
$(LIBBITCOIN_SERVER) \
|
$(LIBBITCOIN_SERVER) \
|
||||||
|
$(LIBCURL) \
|
||||||
$(LIBBITCOIN_COMMON) \
|
$(LIBBITCOIN_COMMON) \
|
||||||
$(LIBUNIVALUE) \
|
$(LIBUNIVALUE) \
|
||||||
$(LIBBITCOIN_UTIL) \
|
$(LIBBITCOIN_UTIL) \
|
||||||
@@ -595,7 +620,7 @@ libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBOOST_SPIRIT_THREADSAFE -DHAV
|
|||||||
#libzcash_a_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
#libzcash_a_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||||
#libzcash_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMONTGOMERY_OUTPUT
|
#libzcash_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMONTGOMERY_OUTPUT
|
||||||
|
|
||||||
libzcash_a_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing -std=gnu17
|
libzcash_a_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing -std=gnu++17
|
||||||
libzcash_a_LDFLAGS = $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
|
libzcash_a_LDFLAGS = $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
|
||||||
libzcash_a_CPPFLAGS += -DMONTGOMERY_OUTPUT
|
libzcash_a_CPPFLAGS += -DMONTGOMERY_OUTPUT
|
||||||
|
|
||||||
@@ -637,7 +662,7 @@ libhush_a_SOURCES = \
|
|||||||
|
|
||||||
libhush_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) -pipe -O1 -g -Wstack-protector -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
|
libhush_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) -pipe -O1 -g -Wstack-protector -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
|
||||||
|
|
||||||
libhush_a_CXXFLAGS = $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing -std=gnu17
|
libhush_a_CXXFLAGS = $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing -std=gnu++17
|
||||||
|
|
||||||
libhush_a_LDFLAGS = $(HARDENED_LDFLAGS)
|
libhush_a_LDFLAGS = $(HARDENED_LDFLAGS)
|
||||||
|
|
||||||
@@ -686,5 +711,5 @@ endif
|
|||||||
if ENABLE_TESTS
|
if ENABLE_TESTS
|
||||||
#include Makefile.test-hush.include
|
#include Makefile.test-hush.include
|
||||||
#include Makefile.test.include
|
#include Makefile.test.include
|
||||||
#include Makefile.gtest.include
|
include Makefile.gtest.include
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -4,65 +4,61 @@ TESTS += hush-gtest
|
|||||||
bin_PROGRAMS += hush-gtest
|
bin_PROGRAMS += hush-gtest
|
||||||
|
|
||||||
# tool for generating our public parameters
|
# tool for generating our public parameters
|
||||||
|
# NOTE: the original test list used an invalid automake form (comment after a trailing
|
||||||
|
# backslash, and `zcash_gtest_SOURCES +=` with no prior `=`), which is why the whole
|
||||||
|
# gtest harness was disabled via a `#include`. Minimal valid set: the harness + the
|
||||||
|
# Re-add other gtest sources here as they are revived.
|
||||||
hush_gtest_SOURCES = \
|
hush_gtest_SOURCES = \
|
||||||
gtest/main.cpp \
|
gtest/main.cpp \
|
||||||
gtest/utils.cpp \
|
gtest/utils.cpp \
|
||||||
gtest/test_checktransaction.cpp \
|
gtest/test_randomx_preverify.cpp \
|
||||||
gtest/json_test_vectors.cpp \
|
gtest/test_hdtransparent.cpp \
|
||||||
gtest/json_test_vectors.h \
|
gtest/test_mnemonic_compat.cpp
|
||||||
gtest/test_wallet_zkeys.cpp \
|
|
||||||
# These tests are order-dependent, because they
|
|
||||||
# depend on global state (see #1539)
|
|
||||||
if ENABLE_WALLET
|
|
||||||
zcash_gtest_SOURCES += \
|
|
||||||
wallet/gtest/test_wallet_zkeys.cpp
|
|
||||||
endif
|
|
||||||
zcash_gtest_SOURCES += \
|
|
||||||
gtest/test_tautology.cpp \
|
|
||||||
gtest/test_deprecation.cpp \
|
|
||||||
gtest/test_equihash.cpp \
|
|
||||||
gtest/test_httprpc.cpp \
|
|
||||||
gtest/test_keys.cpp \
|
|
||||||
gtest/test_keystore.cpp \
|
|
||||||
gtest/test_noteencryption.cpp \
|
|
||||||
gtest/test_mempool.cpp \
|
|
||||||
gtest/test_merkletree.cpp \
|
|
||||||
gtest/test_metrics.cpp \
|
|
||||||
gtest/test_miner.cpp \
|
|
||||||
gtest/test_pow.cpp \
|
|
||||||
gtest/test_random.cpp \
|
|
||||||
gtest/test_rpc.cpp \
|
|
||||||
gtest/test_sapling_note.cpp \
|
|
||||||
gtest/test_transaction.cpp \
|
|
||||||
gtest/test_transaction_builder.cpp \
|
|
||||||
gtest/test_upgrades.cpp \
|
|
||||||
gtest/test_validation.cpp \
|
|
||||||
gtest/test_circuit.cpp \
|
|
||||||
gtest/test_txid.cpp \
|
|
||||||
gtest/test_libzcash_utils.cpp \
|
|
||||||
gtest/test_proofs.cpp \
|
|
||||||
gtest/test_pedersen_hash.cpp \
|
|
||||||
gtest/test_checkblock.cpp \
|
|
||||||
gtest/test_zip32.cpp
|
|
||||||
if ENABLE_WALLET
|
|
||||||
zcash_gtest_SOURCES += \
|
|
||||||
wallet/gtest/test_wallet.cpp
|
|
||||||
endif
|
|
||||||
|
|
||||||
hush_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
|
hush_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
|
||||||
hush_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
hush_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
|
|
||||||
hush_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
|
# Mirror dragonxd_LDADD's working library set/order (the old list used a non-existent
|
||||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
|
# $(LIBBITCOIN_UNIVALUE) so univalue was never linked, and omitted LIBHUSH/LIBRANDOMX/libcc).
|
||||||
|
hush_gtest_LDADD = -lgtest -lgmock \
|
||||||
|
$(LIBBITCOIN_SERVER) \
|
||||||
|
$(LIBCURL) \
|
||||||
|
$(LIBBITCOIN_COMMON) \
|
||||||
|
$(LIBUNIVALUE) \
|
||||||
|
$(LIBBITCOIN_UTIL) \
|
||||||
|
$(LIBBITCOIN_CRYPTO) \
|
||||||
|
$(LIBZCASH) \
|
||||||
|
$(LIBHUSH) \
|
||||||
|
$(LIBLEVELDB) \
|
||||||
|
$(LIBMEMENV) \
|
||||||
|
$(LIBSECP256K1) \
|
||||||
|
$(LIBRANDOMX)
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
hush_gtest_LDADD += $(LIBBITCOIN_WALLET)
|
hush_gtest_LDADD += $(LIBBITCOIN_WALLET)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
hush_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBZCASH_LIBS)
|
hush_gtest_LDADD += \
|
||||||
|
$(BOOST_LIBS) \
|
||||||
|
$(BOOST_UNIT_TEST_FRAMEWORK_LIB) \
|
||||||
|
$(BDB_LIBS) \
|
||||||
|
$(SSL_LIBS) \
|
||||||
|
$(CRYPTO_LIBS) \
|
||||||
|
$(EVENT_PTHREADS_LIBS) \
|
||||||
|
$(EVENT_LIBS) \
|
||||||
|
$(LIBBITCOIN_CRYPTO) \
|
||||||
|
$(LIBZCASH_LIBS)
|
||||||
|
|
||||||
hush_gtest_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
|
if TARGET_DARWIN
|
||||||
|
hush_gtest_LDADD += libcc.dylib $(LIBSECP256K1)
|
||||||
|
endif
|
||||||
|
if TARGET_WINDOWS
|
||||||
|
hush_gtest_LDADD += libcc.dll $(LIBSECP256K1)
|
||||||
|
endif
|
||||||
|
if TARGET_LINUX
|
||||||
|
hush_gtest_LDADD += libcc.so $(LIBSECP256K1)
|
||||||
|
endif
|
||||||
|
|
||||||
hush_gtest_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
|
hush_gtest_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
hush-gtest-expected-failures: hush-gtest FORCE
|
hush-gtest-expected-failures: hush-gtest FORCE
|
||||||
./hush-gtest --gtest_filter=*DISABLED_* --gtest_also_run_disabled_tests
|
./hush-gtest --gtest_filter=*DISABLED_* --gtest_also_run_disabled_tests
|
||||||
|
|||||||
@@ -112,13 +112,13 @@ endif
|
|||||||
|
|
||||||
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
||||||
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
|
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
|
||||||
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
|
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBCURL) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||||
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
|
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
|
||||||
endif
|
endif
|
||||||
test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
|
test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBCURL) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
|
||||||
$(LIBLEVELDB) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
|
$(LIBLEVELDB) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
|
||||||
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2013 The Bitcoin Core developers
|
// Copyright (c) 2009-2013 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2013 The Bitcoin Core developers
|
// Copyright (c) 2009-2013 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
CC_DARWIN = g++-8
|
CC_DARWIN = g++-15
|
||||||
CC_WIN = x86_64-w64-mingw32-gcc-posix
|
CC_WIN = x86_64-w64-mingw32-gcc-posix
|
||||||
CC_AARCH64 = aarch64-linux-gnu-g++
|
CC_AARCH64 = aarch64-linux-gnu-g++
|
||||||
CFLAGS_DARWIN = -DBUILD_CUSTOMCC -std=c++11 -arch x86_64 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../leveldb/include -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib
|
CFLAGS_DARWIN = -DBUILD_CUSTOMCC -std=c++11 -arch x86_64 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../leveldb/include -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib
|
||||||
|
|||||||
BIN
src/cc/customcc.dylib
Normal file
BIN
src/cc/customcc.dylib
Normal file
Binary file not shown.
20
src/chain.h
20
src/chain.h
@@ -32,8 +32,12 @@ class CChainPower;
|
|||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
extern bool fZindex;
|
extern bool fZindex;
|
||||||
static const int SPROUT_VALUE_VERSION = 1001400;
|
// These version thresholds control whether nSproutValue/nSaplingValue are
|
||||||
static const int SAPLING_VALUE_VERSION = 1010100;
|
// serialized in the block index. They must be <= CLIENT_VERSION or the
|
||||||
|
// values will never be persisted, causing nChainSaplingValue to reset
|
||||||
|
// to 0 after node restart. DragonX CLIENT_VERSION is 1000350 (v1.0.3.50).
|
||||||
|
static const int SPROUT_VALUE_VERSION = 1000000;
|
||||||
|
static const int SAPLING_VALUE_VERSION = 1000000;
|
||||||
extern int32_t ASSETCHAINS_LWMAPOS;
|
extern int32_t ASSETCHAINS_LWMAPOS;
|
||||||
extern char SMART_CHAIN_SYMBOL[65];
|
extern char SMART_CHAIN_SYMBOL[65];
|
||||||
extern uint64_t ASSETCHAINS_NOTARY_PAY[];
|
extern uint64_t ASSETCHAINS_NOTARY_PAY[];
|
||||||
@@ -395,7 +399,16 @@ public:
|
|||||||
|
|
||||||
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
|
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
|
||||||
uint32_t nSequenceId;
|
uint32_t nSequenceId;
|
||||||
|
|
||||||
|
//! (memory only) Set true once this block's RandomX PoW has been verified by the parallel
|
||||||
|
//! pre-verification pool, letting the inline check in CheckBlockHeader skip the recompute.
|
||||||
|
//! Written by exactly one pre-verify worker (1:1 with the block) and read by the connect
|
||||||
|
//! thread only AFTER the pool barrier (CCheckQueue::Wait provides the happens-before), so a
|
||||||
|
//! plain bool is race-free here. NOT serialized — a pure optimization hint; the inline
|
||||||
|
//! CheckRandomXSolution remains the consensus authority. (Plain bool, not std::atomic, so
|
||||||
|
//! CBlockIndex stays copyable for CDiskBlockIndex's `CBlockIndex(*pindex)` construction.)
|
||||||
|
bool fRandomXVerified;
|
||||||
|
|
||||||
void SetNull()
|
void SetNull()
|
||||||
{
|
{
|
||||||
phashBlock = NULL;
|
phashBlock = NULL;
|
||||||
@@ -410,6 +423,7 @@ public:
|
|||||||
chainPower = CChainPower();
|
chainPower = CChainPower();
|
||||||
nTx = 0;
|
nTx = 0;
|
||||||
nChainTx = 0;
|
nChainTx = 0;
|
||||||
|
fRandomXVerified = false;
|
||||||
|
|
||||||
// Shieldex Index chain stats
|
// Shieldex Index chain stats
|
||||||
nChainPayments = 0;
|
nChainPayments = 0;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2010 Satoshi Nakamoto
|
// Copyright (c) 2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -519,8 +518,8 @@ void *chainparams_commandline() {
|
|||||||
//}
|
//}
|
||||||
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
||||||
{
|
{
|
||||||
if (strcmp(SMART_CHAIN_SYMBOL,"DRAGONX") == 0) {
|
if (strcmp(SMART_CHAIN_SYMBOL,"HUSH3") == 0) {
|
||||||
ASSETCHAINS_P2PPORT = 21768;
|
ASSETCHAINS_P2PPORT = 18030;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ASSETCHAINS_BLOCKTIME != 60 )
|
if ( ASSETCHAINS_BLOCKTIME != 60 )
|
||||||
@@ -551,8 +550,8 @@ void *chainparams_commandline() {
|
|||||||
pCurrentParams->consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = ASSETCHAINS_SAPLING;
|
pCurrentParams->consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = ASSETCHAINS_SAPLING;
|
||||||
pCurrentParams->consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = ASSETCHAINS_OVERWINTER;
|
pCurrentParams->consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = ASSETCHAINS_OVERWINTER;
|
||||||
// Generated at 1575831755 via hush3 util/checkpoints.pl by Duke Leto
|
// Generated at 1575831755 via hush3 util/checkpoints.pl by Duke Leto
|
||||||
if (strcmp(SMART_CHAIN_SYMBOL,"DRAGONX") == 0) {
|
if (strcmp(SMART_CHAIN_SYMBOL,"HUSH3") == 0) {
|
||||||
// DRAGONX mainnet checkpoint data
|
// HUSH mainnet checkpoint data
|
||||||
checkpointData = //(Checkpoints::CCheckpointData)
|
checkpointData = //(Checkpoints::CCheckpointData)
|
||||||
{
|
{
|
||||||
boost::assign::map_list_of
|
boost::assign::map_list_of
|
||||||
@@ -5639,18 +5638,9 @@ void *chainparams_commandline() {
|
|||||||
(2836000, uint256S("0x00000000004f1a5b9b0fad39c6751db29b99bfcb045181b6077d791ee0cf91f2"))
|
(2836000, uint256S("0x00000000004f1a5b9b0fad39c6751db29b99bfcb045181b6077d791ee0cf91f2"))
|
||||||
(2837000, uint256S("0x000000000027c61ed8745c18d6b00edec9414e30dd880d92d598a6a0ce0fc238"))
|
(2837000, uint256S("0x000000000027c61ed8745c18d6b00edec9414e30dd880d92d598a6a0ce0fc238"))
|
||||||
(2838000, uint256S("0x00000000010947813b04f02da1166a07ba213369ec83695f4d8a6270c57f1141"))
|
(2838000, uint256S("0x00000000010947813b04f02da1166a07ba213369ec83695f4d8a6270c57f1141"))
|
||||||
(2839000, uint256S("0x01aa99bfd837b9795b2f067a253792e32c5b24e5beeac52d7dc8e5772e346ec2"))
|
,(int64_t) 1770622731, // time of last checkpointed block
|
||||||
(2840000, uint256S("0x00000f097b50c4d50cf046ccc3cc3e34f189b61a1a564685cfd713fc2ffd52b6"))
|
(int64_t) 2940000, // total txs
|
||||||
(2841000, uint256S("0x00028a1d142a6cd7db7f6d6b18dd7c0ec1084bb09b03d4eda2476efc77f5d58c"))
|
(double) 4576 // txs in the last day before block 2838000
|
||||||
(2842000, uint256S("0x0005cd49b00a8afa60ce1b88d9964dae60024f2e65a071e5ca1ea1f25770014d"))
|
|
||||||
(2843000, uint256S("0x0003bff7b5424419a8eeece89b8ea9b55f7169f28890f1b70641da3ea6fd14f9"))
|
|
||||||
(2844000, uint256S("0x00001813233d048530ca6bb8f07ce51f5d77dd0f68caaab74982e6655c931315"))
|
|
||||||
(2845000, uint256S("0x000070bd390b117f5c4675a5658a58a4853c687b77553742c89bddff67565da9"))
|
|
||||||
(2846000, uint256S("0x0000c92668956d600a532e8039ac5a8c25d916ec7d66221f89813a75c4eedc41"))
|
|
||||||
(2847000, uint256S("0x0001480bacbd427672a16552928a384362742c4454e97baabe1c5a7c9e15b745"))
|
|
||||||
,(int64_t) 1772014532, // time of last checkpointed block
|
|
||||||
(int64_t) 2952051, // total txs
|
|
||||||
(double) 4576 // txs in the last day before block 2847871
|
|
||||||
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2010 Satoshi Nakamoto
|
// Copyright (c) 2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright (c) 2012-2014 The Bitcoin Core developers
|
// Copyright (c) 2012-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2017 The Zcash developers
|
// Copyright (c) 2016-2017 The Zcash developers
|
||||||
// Copyright (c) 2016-2026 The Hush developers
|
// Copyright (c) 2016-2026 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
// What happened to the SuperNET developers, who cared about privacy?
|
// What happened to the SuperNET developers, who cared about privacy?
|
||||||
@@ -31,7 +30,7 @@
|
|||||||
// Must be kept in sync with configure.ac , ugh!
|
// Must be kept in sync with configure.ac , ugh!
|
||||||
#define CLIENT_VERSION_MAJOR 1
|
#define CLIENT_VERSION_MAJOR 1
|
||||||
#define CLIENT_VERSION_MINOR 0
|
#define CLIENT_VERSION_MINOR 0
|
||||||
#define CLIENT_VERSION_REVISION 0
|
#define CLIENT_VERSION_REVISION 3
|
||||||
#define CLIENT_VERSION_BUILD 50
|
#define CLIENT_VERSION_BUILD 50
|
||||||
|
|
||||||
//! Set to true for release, false for prerelease or test build
|
//! Set to true for release, false for prerelease or test build
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ bool sanity_test_range_fmt()
|
|||||||
{
|
{
|
||||||
std::string test;
|
std::string test;
|
||||||
try {
|
try {
|
||||||
test.at(1);
|
(void)test.at(1);
|
||||||
} catch (const std::out_of_range&) {
|
} catch (const std::out_of_range&) {
|
||||||
return true;
|
return true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|||||||
@@ -40,8 +40,8 @@
|
|||||||
|
|
||||||
// XXX: There are potential crashes wherever we access chainActive without a lock,
|
// XXX: There are potential crashes wherever we access chainActive without a lock,
|
||||||
// because it might be disconnecting blocks at the same time.
|
// because it might be disconnecting blocks at the same time.
|
||||||
// TODO: this assumes a blocktime of 75 seconds for DRAGONX and 60 seconds for other chains
|
// TODO: this assumes a blocktime of 75 seconds for HUSH and 60 seconds for other chains
|
||||||
int NOTARISATION_SCAN_LIMIT_BLOCKS = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? 1152 : 1440;
|
int NOTARISATION_SCAN_LIMIT_BLOCKS = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? 1152 : 1440;
|
||||||
CBlockIndex *hush_getblockindex(uint256 hash);
|
CBlockIndex *hush_getblockindex(uint256 hash);
|
||||||
|
|
||||||
/* On HUSH */
|
/* On HUSH */
|
||||||
|
|||||||
@@ -33,10 +33,13 @@
|
|||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
#include "sha2.h"
|
#include "sha2.h"
|
||||||
|
|
||||||
#if USE_BIP39_CACHE
|
// BIP39_WORDS is used unconditionally by the wordlist helpers below, so it must
|
||||||
|
// be defined even when the BIP39 cache is disabled (upstream places it inside
|
||||||
|
// the cache block by mistake).
|
||||||
int BIP39_WORDS = 2048;
|
int BIP39_WORDS = 2048;
|
||||||
|
|
||||||
|
#if USE_BIP39_CACHE
|
||||||
|
|
||||||
static int bip39_cache_index = 0;
|
static int bip39_cache_index = 0;
|
||||||
|
|
||||||
static CONFIDENTIAL struct {
|
static CONFIDENTIAL struct {
|
||||||
|
|||||||
@@ -56,8 +56,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// implement BIP39 caching
|
// implement BIP39 caching
|
||||||
|
// Disabled: caching keeps the plaintext mnemonic/passphrase/seed in a static
|
||||||
|
// process-lifetime buffer, which we do not want in a wallet daemon.
|
||||||
#ifndef USE_BIP39_CACHE
|
#ifndef USE_BIP39_CACHE
|
||||||
#define USE_BIP39_CACHE 1
|
#define USE_BIP39_CACHE 0
|
||||||
#define BIP39_CACHE_SIZE 4
|
#define BIP39_CACHE_SIZE 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
171
src/gtest/test_hdtransparent.cpp
Normal file
171
src/gtest/test_hdtransparent.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// Tests for HD-derived transparent keys (m/44'/coin'/0'/0/i) and the
|
||||||
|
// version-gated CHDChain serialization used to persist the transparent counter.
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "key.h"
|
||||||
|
#include "chainparams.h"
|
||||||
|
#include "streams.h"
|
||||||
|
#include "uint256.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "wallet/wallet.h"
|
||||||
|
#include "wallet/walletdb.h"
|
||||||
|
#include "zcash/zip32.h"
|
||||||
|
|
||||||
|
// Build an in-memory wallet with a known seed + hdChain so that the
|
||||||
|
// HD-transparent path (IsHDTransparentEnabled) is active.
|
||||||
|
static void LoadSeedForTest(CWallet& wallet, const HDSeed& seed)
|
||||||
|
{
|
||||||
|
wallet.LoadHDSeed(seed);
|
||||||
|
CHDChain chain;
|
||||||
|
chain.nVersion = CHDChain::VERSION_HD_TRANSPARENT;
|
||||||
|
chain.seedFp = seed.Fingerprint();
|
||||||
|
chain.nCreateTime = 1;
|
||||||
|
wallet.SetHDChain(chain, true /* memonly */);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same seed must reproduce the same transparent addresses in the same order:
|
||||||
|
// this is the recovery guarantee that lets a seed-only restore find coinbase.
|
||||||
|
TEST(hdtransparent_tests, DeterministicFromSeed)
|
||||||
|
{
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
|
RawHDSeed rawSeed(HD_WALLET_SEED_LENGTH, 0x42);
|
||||||
|
HDSeed seed(rawSeed);
|
||||||
|
|
||||||
|
std::vector<CKeyID> keysA;
|
||||||
|
{
|
||||||
|
CWallet wallet;
|
||||||
|
LoadSeedForTest(wallet, seed);
|
||||||
|
ASSERT_TRUE(wallet.IsHDTransparentEnabled());
|
||||||
|
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
CPubKey pk = wallet.GenerateNewKey();
|
||||||
|
keysA.push_back(pk.GetID());
|
||||||
|
|
||||||
|
const CKeyMetadata& md = wallet.mapKeyMetadata[pk.GetID()];
|
||||||
|
EXPECT_EQ(md.seedFp, seed.Fingerprint());
|
||||||
|
EXPECT_EQ(md.hdKeypath, std::string("m/44'/141'/0'/0/") + std::to_string(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fresh wallet, same seed -> identical keys.
|
||||||
|
{
|
||||||
|
CWallet wallet;
|
||||||
|
LoadSeedForTest(wallet, seed);
|
||||||
|
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
CPubKey pk = wallet.GenerateNewKey();
|
||||||
|
EXPECT_EQ(pk.GetID(), keysA[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pin the exact derivation path so it can never silently change.
|
||||||
|
TEST(hdtransparent_tests, KnownDerivationPath)
|
||||||
|
{
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
|
RawHDSeed rawSeed(HD_WALLET_SEED_LENGTH, 0x42);
|
||||||
|
HDSeed seed(rawSeed);
|
||||||
|
|
||||||
|
// Independently derive m/44'/141'/0'/0/0.
|
||||||
|
RawHDSeed raw = seed.RawSeed();
|
||||||
|
CExtKey m, purpose, coinType, account, external, child;
|
||||||
|
m.SetMaster(raw.data(), raw.size());
|
||||||
|
m.Derive(purpose, 44 | BIP32_HARDENED_KEY_LIMIT);
|
||||||
|
purpose.Derive(coinType, 141 | BIP32_HARDENED_KEY_LIMIT);
|
||||||
|
coinType.Derive(account, 0 | BIP32_HARDENED_KEY_LIMIT);
|
||||||
|
account.Derive(external, 0);
|
||||||
|
external.Derive(child, 0);
|
||||||
|
CKeyID expected = child.key.GetPubKey().GetID();
|
||||||
|
|
||||||
|
CWallet wallet;
|
||||||
|
LoadSeedForTest(wallet, seed);
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
CPubKey pk = wallet.GenerateNewKey();
|
||||||
|
EXPECT_EQ(pk.GetID(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A pre-existing v1 CHDChain record (no transparent counter) must still
|
||||||
|
// deserialize under v2 code, leaving transparentChildCounter at 0; and a v2
|
||||||
|
// record must round-trip the counter.
|
||||||
|
TEST(hdtransparent_tests, HDChainVersionCompat)
|
||||||
|
{
|
||||||
|
CHDChain v1;
|
||||||
|
v1.nVersion = CHDChain::VERSION_HD_BASE; // 1: transparentChildCounter not serialized
|
||||||
|
v1.seedFp = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
v1.nCreateTime = 12345;
|
||||||
|
v1.saplingAccountCounter = 7;
|
||||||
|
|
||||||
|
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
|
||||||
|
ss << v1;
|
||||||
|
|
||||||
|
CHDChain out; // default-constructed: SetNull() zeroes transparentChildCounter
|
||||||
|
ss >> out;
|
||||||
|
EXPECT_EQ(out.nVersion, +CHDChain::VERSION_HD_BASE); // unary + -> rvalue, avoid ODR-use of static const
|
||||||
|
EXPECT_EQ(out.seedFp, v1.seedFp);
|
||||||
|
EXPECT_EQ(out.nCreateTime, (int64_t)12345);
|
||||||
|
EXPECT_EQ(out.saplingAccountCounter, (uint32_t)7);
|
||||||
|
EXPECT_EQ(out.transparentChildCounter, (uint32_t)0);
|
||||||
|
|
||||||
|
CHDChain v2;
|
||||||
|
v2.nVersion = CHDChain::VERSION_HD_TRANSPARENT;
|
||||||
|
v2.saplingAccountCounter = 3;
|
||||||
|
v2.transparentChildCounter = 42;
|
||||||
|
CDataStream ss2(SER_DISK, PROTOCOL_VERSION);
|
||||||
|
ss2 << v2;
|
||||||
|
|
||||||
|
CHDChain out2;
|
||||||
|
ss2 >> out2;
|
||||||
|
EXPECT_EQ(out2.nVersion, +CHDChain::VERSION_HD_TRANSPARENT);
|
||||||
|
EXPECT_EQ(out2.saplingAccountCounter, (uint32_t)3);
|
||||||
|
EXPECT_EQ(out2.transparentChildCounter, (uint32_t)42);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restoring from a 32-byte seed hex reproduces the same keys as the source
|
||||||
|
// wallet, and refuses to run when a seed already exists.
|
||||||
|
TEST(hdtransparent_tests, RestoreFromSeedHex)
|
||||||
|
{
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
|
RawHDSeed rawSeed(HD_WALLET_SEED_LENGTH, 0x7a);
|
||||||
|
HDSeed seed(rawSeed);
|
||||||
|
std::string seedHex = HexStr(seed.RawSeed());
|
||||||
|
|
||||||
|
// Source wallet: derive some keys.
|
||||||
|
std::vector<CKeyID> expected;
|
||||||
|
{
|
||||||
|
CWallet wallet;
|
||||||
|
LoadSeedForTest(wallet, seed);
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
expected.push_back(wallet.GenerateNewKey().GetID());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restored wallet: inject the seed hex, pre-derive, and compare.
|
||||||
|
{
|
||||||
|
CWallet wallet;
|
||||||
|
ASSERT_TRUE(wallet.SetHDSeedFromHex(seedHex));
|
||||||
|
// Second attempt must fail: a seed already exists.
|
||||||
|
EXPECT_FALSE(wallet.SetHDSeedFromHex(seedHex));
|
||||||
|
|
||||||
|
wallet.TopUpHDTransparentKeys(3, 1);
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
EXPECT_TRUE(wallet.HaveKey(expected[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad input is rejected.
|
||||||
|
{
|
||||||
|
CWallet wallet;
|
||||||
|
EXPECT_FALSE(wallet.SetHDSeedFromHex("nothex"));
|
||||||
|
EXPECT_FALSE(wallet.SetHDSeedFromHex("abcd")); // too short
|
||||||
|
}
|
||||||
|
}
|
||||||
141
src/gtest/test_mnemonic_compat.cpp
Normal file
141
src/gtest/test_mnemonic_compat.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// Proves that a BIP39 seed phrase produces the SAME transparent and shielded
|
||||||
|
// addresses on the DragonX full node as in SilentDragonXLite. The proof chain:
|
||||||
|
// phrase -> entropy (round-trip) -> 64-byte BIP39 seed (known-answer)
|
||||||
|
// -> z/t addresses (wallet path == direct ZIP-32/BIP44 derivation).
|
||||||
|
// The 64-byte seed is anchored to the well-known BIP39 value for the all-zero
|
||||||
|
// "abandon...art" entropy with an EMPTY passphrase, which is exactly what
|
||||||
|
// SilentDragonXLite's tiny-bip39 0.6.2 feeds into the same coin_type=141 paths.
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "chainparams.h"
|
||||||
|
#include "key.h"
|
||||||
|
#include "key_io.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "wallet/mnemonic.h"
|
||||||
|
#include "wallet/wallet.h"
|
||||||
|
#include "zcash/Address.hpp"
|
||||||
|
#include "zcash/zip32.h"
|
||||||
|
|
||||||
|
// The canonical 24-word phrase for 32 bytes of all-zero entropy.
|
||||||
|
static const char* ABANDON_ART =
|
||||||
|
"abandon abandon abandon abandon abandon abandon abandon abandon "
|
||||||
|
"abandon abandon abandon abandon abandon abandon abandon abandon "
|
||||||
|
"abandon abandon abandon abandon abandon abandon abandon art";
|
||||||
|
|
||||||
|
// The standard BIP39 seed for that phrase with an EMPTY passphrase
|
||||||
|
// (PBKDF2-HMAC-SHA512, 2048 rounds, salt "mnemonic"). Matches tiny-bip39.
|
||||||
|
static const char* SEED64_HEX =
|
||||||
|
"408b285c123836004f4b8842c89324c1f01382450c0d439af345ba7fc49acf70"
|
||||||
|
"5489c6fc77dbd4e3dc1dd8cc6bc9f043db8ada1e243c4a0eafb290d399480840";
|
||||||
|
|
||||||
|
// First shielded address for a 64-byte seed: m/32'/141'/0' default address.
|
||||||
|
static std::string DeriveZAddrFromSeed64(RawHDSeed seed64)
|
||||||
|
{
|
||||||
|
HDSeed s(seed64);
|
||||||
|
auto m = libzcash::SaplingExtendedSpendingKey::Master(s);
|
||||||
|
auto xsk = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT)
|
||||||
|
.Derive(141 | ZIP32_HARDENED_KEY_LIMIT)
|
||||||
|
.Derive(0 | ZIP32_HARDENED_KEY_LIMIT);
|
||||||
|
return EncodePaymentAddress(xsk.DefaultAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
// First transparent address for a BIP32 master over `seedBytes`:
|
||||||
|
// m/44'/141'/0'/0/0.
|
||||||
|
static std::string DeriveTAddrFromSeedBytes(RawHDSeed seedBytes)
|
||||||
|
{
|
||||||
|
CExtKey master, purpose, coinType, account, external, child;
|
||||||
|
master.SetMaster(seedBytes.data(), seedBytes.size());
|
||||||
|
master.Derive(purpose, 44 | BIP32_HARDENED_KEY_LIMIT);
|
||||||
|
purpose.Derive(coinType, 141 | BIP32_HARDENED_KEY_LIMIT);
|
||||||
|
coinType.Derive(account, 0 | BIP32_HARDENED_KEY_LIMIT);
|
||||||
|
account.Derive(external, 0);
|
||||||
|
external.Derive(child, 0);
|
||||||
|
return EncodeDestination(child.key.GetPubKey().GetID());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The 64-byte seed derived from the mnemonic must equal the known BIP39 value.
|
||||||
|
// This is the cross-wallet anchor: SilentDragonXLite feeds the identical seed.
|
||||||
|
TEST(mnemonic_compat, Bip39SeedKnownAnswer)
|
||||||
|
{
|
||||||
|
RawHDSeed entropy(32, 0);
|
||||||
|
RawHDSeed seed64;
|
||||||
|
ASSERT_TRUE(Bip39SeedFromEntropy(entropy, seed64));
|
||||||
|
ASSERT_EQ(seed64.size(), (size_t)64);
|
||||||
|
EXPECT_EQ(HexStr(seed64.begin(), seed64.end()), std::string(SEED64_HEX));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mnemonic_compat, EntropyPhraseRoundTrip)
|
||||||
|
{
|
||||||
|
RawHDSeed zeros(32, 0);
|
||||||
|
std::string phrase;
|
||||||
|
ASSERT_TRUE(EntropyToMnemonic(zeros, phrase));
|
||||||
|
EXPECT_EQ(phrase, std::string(ABANDON_ART));
|
||||||
|
|
||||||
|
EXPECT_TRUE(MnemonicIsValid(ABANDON_ART));
|
||||||
|
|
||||||
|
RawHDSeed entropy;
|
||||||
|
ASSERT_TRUE(MnemonicToEntropy(ABANDON_ART, entropy));
|
||||||
|
EXPECT_EQ(entropy.size(), (size_t)32);
|
||||||
|
EXPECT_EQ(HexStr(entropy.begin(), entropy.end()), std::string(64, '0'));
|
||||||
|
|
||||||
|
// Bad checksum / unknown words are rejected.
|
||||||
|
EXPECT_FALSE(MnemonicIsValid("abandon abandon abandon"));
|
||||||
|
EXPECT_FALSE(MnemonicIsValid("clearly not valid bip39 words at all here"));
|
||||||
|
RawHDSeed junk;
|
||||||
|
EXPECT_FALSE(MnemonicToEntropy("clearly not valid bip39 words at all here", junk));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The wallet's mnemonic derivation must reproduce the exact addresses obtained
|
||||||
|
// by driving ZIP-32 / BIP44 directly from the known 64-byte seed, and must be
|
||||||
|
// deterministic across wallets.
|
||||||
|
TEST(mnemonic_compat, WalletDerivesSdxliteAddresses)
|
||||||
|
{
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
|
RawHDSeed zeros(32, 0), seed64;
|
||||||
|
ASSERT_TRUE(Bip39SeedFromEntropy(zeros, seed64));
|
||||||
|
const std::string expZ = DeriveZAddrFromSeed64(seed64);
|
||||||
|
const std::string expT = DeriveTAddrFromSeedBytes(seed64);
|
||||||
|
EXPECT_EQ(expZ.substr(0, 2), "zs"); // sapling HRP for mainnet
|
||||||
|
|
||||||
|
CWallet wallet;
|
||||||
|
ASSERT_TRUE(wallet.SetHDSeedFromMnemonic(ABANDON_ART));
|
||||||
|
ASSERT_TRUE(wallet.IsMnemonicSeed());
|
||||||
|
{
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
EXPECT_EQ(EncodePaymentAddress(wallet.GenerateNewSaplingZKey()), expZ);
|
||||||
|
EXPECT_EQ(EncodeDestination(wallet.GenerateNewKey().GetID()), expT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same phrase, fresh wallet -> identical first addresses.
|
||||||
|
CWallet wallet2;
|
||||||
|
ASSERT_TRUE(wallet2.SetHDSeedFromMnemonic(ABANDON_ART));
|
||||||
|
{
|
||||||
|
LOCK(wallet2.cs_wallet);
|
||||||
|
EXPECT_EQ(EncodePaymentAddress(wallet2.GenerateNewSaplingZKey()), expZ);
|
||||||
|
EXPECT_EQ(EncodeDestination(wallet2.GenerateNewKey().GetID()), expT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The phrase round-trips out of the wallet.
|
||||||
|
std::string exported;
|
||||||
|
ASSERT_TRUE(wallet.GetMnemonicPhrase(exported));
|
||||||
|
EXPECT_EQ(exported, std::string(ABANDON_ART));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negative: feeding the 32-byte entropy DIRECTLY as the seed (the classic
|
||||||
|
// interop bug) must produce a different address than the 64-byte BIP39 seed.
|
||||||
|
TEST(mnemonic_compat, RawEntropyDiffersFromMnemonicSeed)
|
||||||
|
{
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
|
RawHDSeed zeros(32, 0), seed64;
|
||||||
|
ASSERT_TRUE(Bip39SeedFromEntropy(zeros, seed64));
|
||||||
|
|
||||||
|
const std::string seedT = DeriveTAddrFromSeedBytes(seed64); // correct (64-byte)
|
||||||
|
const std::string entropyT = DeriveTAddrFromSeedBytes(zeros); // wrong (32-byte)
|
||||||
|
EXPECT_NE(seedT, entropyT);
|
||||||
|
}
|
||||||
172
src/gtest/test_randomx_preverify.cpp
Normal file
172
src/gtest/test_randomx_preverify.cpp
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
// Copyright (c) 2024-2026 The DragonX developers
|
||||||
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
//
|
||||||
|
// Consensus-equivalence test for the parallel RandomX pre-verification pool. The pool is purely an
|
||||||
|
// optimization: a block's transient fRandomXVerified flag (set by CRandomXCheck on a real hash
|
||||||
|
// match) only lets CheckBlockHeader SKIP the inline recompute. So for every block the pool's
|
||||||
|
// outcome must equal the inline CheckRandomXSolution outcome — `(preVerified || inline) == inline`.
|
||||||
|
// We exercise a valid solution, a corrupted solution, and confirm the pool never "succeeds" on a
|
||||||
|
// block the inline check would reject.
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "arith_uint256.h"
|
||||||
|
#include "chain.h"
|
||||||
|
#include "chainparams.h"
|
||||||
|
#include "pow.h"
|
||||||
|
#include "primitives/block.h"
|
||||||
|
#include "RandomX/src/randomx.h"
|
||||||
|
#include "hush_defs.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
extern int32_t HUSH_LOADINGBLOCKS;
|
||||||
|
extern bool fCheckpointsEnabled;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Compute the correct RandomX solution for a header using a standalone reference light VM, via the
|
||||||
|
// SAME key + input helpers the validator uses (so the bytes/key match exactly).
|
||||||
|
void ReferenceRandomXHash(const CBlockHeader& hdr, const std::string& key, unsigned char out[RANDOMX_HASH_SIZE])
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> in = GetRandomXInput(hdr);
|
||||||
|
randomx_flags flags = randomx_get_flags();
|
||||||
|
randomx_cache* c = randomx_alloc_cache(flags);
|
||||||
|
ASSERT_NE(c, nullptr);
|
||||||
|
randomx_init_cache(c, key.data(), key.size());
|
||||||
|
randomx_vm* vm = randomx_create_vm(flags, c, nullptr);
|
||||||
|
ASSERT_NE(vm, nullptr);
|
||||||
|
randomx_calculate_hash(vm, in.data(), in.size(), out);
|
||||||
|
randomx_destroy_vm(vm);
|
||||||
|
randomx_release_cache(c);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(RandomXPreVerify, ConsensusEquivalence)
|
||||||
|
{
|
||||||
|
// Force RandomX validation to actually run at low heights in the test harness.
|
||||||
|
uint32_t savedAlgo = ASSETCHAINS_ALGO, savedRx = ASSETCHAINS_RANDOMX;
|
||||||
|
int32_t savedVal = ASSETCHAINS_RANDOMX_VALIDATION, savedLoad = HUSH_LOADINGBLOCKS;
|
||||||
|
bool savedCkpt = fCheckpointsEnabled;
|
||||||
|
ASSETCHAINS_RANDOMX = 2; // a distinct nonzero algo id
|
||||||
|
ASSETCHAINS_ALGO = ASSETCHAINS_RANDOMX;
|
||||||
|
ASSETCHAINS_RANDOMX_VALIDATION = 1; // enforce from height 1
|
||||||
|
HUSH_LOADINGBLOCKS = 0; // not in initial-load (else RandomX skipped)
|
||||||
|
fCheckpointsEnabled = false; // avoid the below-checkpoint skip
|
||||||
|
|
||||||
|
const int32_t height = 10; // < interval+lag -> the chain-params initial key (no chainActive needed)
|
||||||
|
|
||||||
|
CBlockHeader hdr;
|
||||||
|
hdr.nVersion = 4;
|
||||||
|
hdr.hashPrevBlock = uint256S("0x0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
hdr.hashMerkleRoot = uint256S("0x0000000000000000000000000000000000000000000000000000000000000002");
|
||||||
|
hdr.hashFinalSaplingRoot = uint256S("0x0000000000000000000000000000000000000000000000000000000000000003");
|
||||||
|
hdr.nTime = 1700000000;
|
||||||
|
hdr.nBits = 0x200f0f0f;
|
||||||
|
hdr.nNonce = uint256S("0x0000000000000000000000000000000000000000000000000000000000000004");
|
||||||
|
|
||||||
|
std::string key = GetRandomXKey(height);
|
||||||
|
ASSERT_FALSE(key.empty());
|
||||||
|
|
||||||
|
unsigned char good[RANDOMX_HASH_SIZE];
|
||||||
|
ReferenceRandomXHash(hdr, key, good);
|
||||||
|
|
||||||
|
// Run the pool path synchronously on this thread (CRandomXCheck creates its own thread_local VM).
|
||||||
|
auto poolVerifies = [&](const CBlockHeader& h) -> bool {
|
||||||
|
RandomXValidatorPrepareKey(key); // load the shared cache with this key
|
||||||
|
bool slot = false;
|
||||||
|
CRandomXCheck chk(key, GetRandomXInput(h), h.nSolution.data(), &slot);
|
||||||
|
chk();
|
||||||
|
return slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Case 1 — valid solution: both inline and pool accept; equivalence holds.
|
||||||
|
hdr.nSolution.assign(good, good + RANDOMX_HASH_SIZE);
|
||||||
|
EXPECT_TRUE(CheckRandomXSolution(&hdr, height));
|
||||||
|
EXPECT_TRUE(poolVerifies(hdr));
|
||||||
|
EXPECT_EQ(poolVerifies(hdr) || CheckRandomXSolution(&hdr, height), CheckRandomXSolution(&hdr, height));
|
||||||
|
|
||||||
|
// Case 2 — corrupted solution: both reject; the pool must NOT set verified.
|
||||||
|
{
|
||||||
|
CBlockHeader bad = hdr;
|
||||||
|
bad.nSolution[0] ^= 0xff;
|
||||||
|
EXPECT_FALSE(CheckRandomXSolution(&bad, height));
|
||||||
|
EXPECT_FALSE(poolVerifies(bad));
|
||||||
|
EXPECT_EQ(poolVerifies(bad) || CheckRandomXSolution(&bad, height), CheckRandomXSolution(&bad, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 3 — a verified flag on the block lets CheckBlockHeader skip, but verified is only ever set
|
||||||
|
// by a real hash match, so it can never mask an invalid block. (Pool returns false for the bad
|
||||||
|
// block above, so its fRandomXVerified stays false and the inline path rejects it at connect.)
|
||||||
|
|
||||||
|
ASSETCHAINS_ALGO = savedAlgo; ASSETCHAINS_RANDOMX = savedRx;
|
||||||
|
ASSETCHAINS_RANDOMX_VALIDATION = savedVal; HUSH_LOADINGBLOCKS = savedLoad;
|
||||||
|
fCheckpointsEnabled = savedCkpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A/B: serial inline verification (single VM) vs the parallel pool (worker threads). Directly
|
||||||
|
// measures the speedup the pool delivers. We don't care about validity here (mismatched solutions
|
||||||
|
// still cost a full hash), only wall-clock. parallel must beat serial whenever >1 core is used.
|
||||||
|
TEST(RandomXPreVerify, ParallelSpeedup)
|
||||||
|
{
|
||||||
|
uint32_t savedAlgo = ASSETCHAINS_ALGO, savedRx = ASSETCHAINS_RANDOMX;
|
||||||
|
int32_t savedVal = ASSETCHAINS_RANDOMX_VALIDATION, savedLoad = HUSH_LOADINGBLOCKS;
|
||||||
|
bool savedCkpt = fCheckpointsEnabled;
|
||||||
|
ASSETCHAINS_RANDOMX = 2; ASSETCHAINS_ALGO = ASSETCHAINS_RANDOMX;
|
||||||
|
ASSETCHAINS_RANDOMX_VALIDATION = 1; HUSH_LOADINGBLOCKS = 0; fCheckpointsEnabled = false;
|
||||||
|
|
||||||
|
const int32_t height = 10;
|
||||||
|
std::string key = GetRandomXKey(height);
|
||||||
|
ASSERT_FALSE(key.empty());
|
||||||
|
ASSERT_TRUE(RandomXValidatorPrepareKey(key));
|
||||||
|
|
||||||
|
const int M = 16; // blocks to verify in the window
|
||||||
|
std::vector<CBlockHeader> hdrs(M);
|
||||||
|
for (int i = 0; i < M; i++) {
|
||||||
|
hdrs[i].nVersion = 4;
|
||||||
|
hdrs[i].nTime = 1700000000 + i;
|
||||||
|
hdrs[i].nBits = 0x200f0f0f;
|
||||||
|
hdrs[i].nNonce = ArithToUint256(arith_uint256(i + 1)); // distinct inputs
|
||||||
|
hdrs[i].nSolution.assign(RANDOMX_HASH_SIZE, 0); // arbitrary; we time the hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serial baseline: inline single-VM verification (each call hashes, then mismatches -> false).
|
||||||
|
int64_t t0 = GetTimeMicros();
|
||||||
|
for (int i = 0; i < M; i++) CheckRandomXSolution(&hdrs[i], height);
|
||||||
|
int64_t serialUs = GetTimeMicros() - t0;
|
||||||
|
|
||||||
|
// Parallel: spawn K-1 workers + the master (this thread) joining via Wait().
|
||||||
|
int K = std::min(8, std::max(2, (int)boost::thread::hardware_concurrency()));
|
||||||
|
boost::thread_group workers;
|
||||||
|
for (int i = 0; i < K - 1; i++) workers.create_thread(&ThreadRandomXVerify);
|
||||||
|
|
||||||
|
std::unique_ptr<bool[]> slots(new bool[M]());
|
||||||
|
std::vector<CRandomXCheck> checks;
|
||||||
|
checks.reserve(M);
|
||||||
|
for (int i = 0; i < M; i++)
|
||||||
|
checks.push_back(CRandomXCheck(key, GetRandomXInput(hdrs[i]), hdrs[i].nSolution.data(), &slots[i]));
|
||||||
|
|
||||||
|
int64_t t1 = GetTimeMicros();
|
||||||
|
{
|
||||||
|
CCheckQueueControl<CRandomXCheck> control(&rxCheckQueue);
|
||||||
|
control.Add(checks);
|
||||||
|
control.Wait();
|
||||||
|
}
|
||||||
|
int64_t parallelUs = GetTimeMicros() - t1;
|
||||||
|
|
||||||
|
workers.interrupt_all();
|
||||||
|
workers.join_all();
|
||||||
|
|
||||||
|
printf("[ RandomX A/B ] %d blocks: serial(1 VM)=%ldms, parallel(%d threads)=%ldms, speedup=%.1fx\n",
|
||||||
|
M, (long)(serialUs / 1000), K, (long)(parallelUs / 1000),
|
||||||
|
(double)serialUs / (double)std::max<int64_t>(1, parallelUs));
|
||||||
|
|
||||||
|
EXPECT_LT(parallelUs, serialUs); // parallel must be faster than serial on a multi-core box
|
||||||
|
|
||||||
|
ASSETCHAINS_ALGO = savedAlgo; ASSETCHAINS_RANDOMX = savedRx;
|
||||||
|
ASSETCHAINS_RANDOMX_VALIDATION = savedVal; HUSH_LOADINGBLOCKS = savedLoad;
|
||||||
|
fCheckpointsEnabled = savedCkpt;
|
||||||
|
}
|
||||||
@@ -580,70 +580,98 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds
|
|||||||
char pchBuf[0x10000];
|
char pchBuf[0x10000];
|
||||||
bool bIsSSL = false;
|
bool bIsSSL = false;
|
||||||
int nBytes = 0, nRet = 0;
|
int nBytes = 0, nRet = 0;
|
||||||
|
// Drain the socket in a bounded loop rather than one read per select pass: a single
|
||||||
|
// 64K read per pass underfills high-bandwidth/high-latency links. Cap the reads per
|
||||||
|
// pass and honor the receive-flood back-pressure so one peer can neither exhaust
|
||||||
|
// memory nor starve other peers within this pass.
|
||||||
|
int nDrainReads = 0;
|
||||||
|
const int MAX_DRAIN_READS = 16; // up to ~1 MiB per peer per pass (fairness across peers)
|
||||||
|
// Pre-read back-pressure: gate on the flood ceiling BEFORE each read so the per-peer
|
||||||
|
// recv buffer high-water stays at ReceiveFloodSize()+one read (matching the select()
|
||||||
|
// FD_SET gate), and track bytes locally to avoid the O(n) GetTotalRecvSize() per pass.
|
||||||
|
const int64_t nRecvBase = (int64_t)pnode->GetTotalRecvSize();
|
||||||
|
int64_t nPassBytes = 0;
|
||||||
|
bool fKeepReading = true;
|
||||||
|
while (fKeepReading) {
|
||||||
|
if (nRecvBase + nPassBytes > (int64_t)ReceiveFloodSize())
|
||||||
|
break;
|
||||||
|
{
|
||||||
|
LOCK(pnode->cs_hSocket);
|
||||||
|
|
||||||
{
|
if (pnode->hSocket == INVALID_SOCKET) {
|
||||||
LOCK(pnode->cs_hSocket);
|
LogPrint("tls", "Receive: connection with %s is already closed\n", pnode->addr.ToString());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (pnode->hSocket == INVALID_SOCKET) {
|
bIsSSL = (pnode->ssl != NULL);
|
||||||
LogPrint("tls", "Receive: connection with %s is already closed\n", pnode->addr.ToString());
|
|
||||||
return -1;
|
if (bIsSSL) {
|
||||||
|
wolfSSL_ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread
|
||||||
|
nBytes = wolfSSL_read(pnode->ssl, pchBuf, sizeof(pchBuf));
|
||||||
|
nRet = wolfSSL_get_error(pnode->ssl, nBytes);
|
||||||
|
} else {
|
||||||
|
nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
||||||
|
nRet = WSAGetLastError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bIsSSL = (pnode->ssl != NULL);
|
if (nBytes > 0) {
|
||||||
|
if (!pnode->ReceiveMsgBytes(pchBuf, nBytes)) {
|
||||||
if (bIsSSL) {
|
|
||||||
wolfSSL_ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread
|
|
||||||
nBytes = wolfSSL_read(pnode->ssl, pchBuf, sizeof(pchBuf));
|
|
||||||
nRet = wolfSSL_get_error(pnode->ssl, nBytes);
|
|
||||||
} else {
|
|
||||||
nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
|
||||||
nRet = WSAGetLastError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nBytes > 0) {
|
|
||||||
if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
|
|
||||||
pnode->CloseSocketDisconnect();
|
|
||||||
pnode->nLastRecv = GetTime();
|
|
||||||
pnode->nRecvBytes += nBytes;
|
|
||||||
pnode->RecordBytesRecv(nBytes);
|
|
||||||
} else if (nBytes == 0) {
|
|
||||||
|
|
||||||
if (bIsSSL) {
|
|
||||||
unsigned long error = ERR_get_error();
|
|
||||||
const char* error_str = ERR_error_string(error, NULL);
|
|
||||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_read err: %s\n",
|
|
||||||
__FILE__, __func__, __LINE__, error_str);
|
|
||||||
}
|
|
||||||
// socket closed gracefully (peer disconnected)
|
|
||||||
if (!pnode->fDisconnect)
|
|
||||||
LogPrint("tls", "socket closed (%s)\n", pnode->addr.ToString());
|
|
||||||
pnode->CloseSocketDisconnect();
|
|
||||||
|
|
||||||
} else if (nBytes < 0) {
|
|
||||||
// error
|
|
||||||
if (bIsSSL) {
|
|
||||||
if (nRet != WOLFSSL_ERROR_WANT_READ && nRet != WOLFSSL_ERROR_WANT_WRITE)
|
|
||||||
{
|
|
||||||
if (!pnode->fDisconnect)
|
|
||||||
LogPrintf("TLS: ERROR: SSL_read %s\n", ERR_error_string(nRet, NULL));
|
|
||||||
pnode->CloseSocketDisconnect();
|
pnode->CloseSocketDisconnect();
|
||||||
|
fKeepReading = false;
|
||||||
|
}
|
||||||
|
pnode->nLastRecv = GetTime();
|
||||||
|
pnode->nRecvBytes += nBytes;
|
||||||
|
pnode->RecordBytesRecv(nBytes);
|
||||||
|
nPassBytes += nBytes;
|
||||||
|
// Keep draining only while the socket likely has more data (we filled the
|
||||||
|
// buffer, or TLS has buffered decrypted bytes) and within the per-pass cap.
|
||||||
|
// The flood ceiling is enforced pre-read at the top of the loop.
|
||||||
|
if (fKeepReading) {
|
||||||
|
bool fMore = (nBytes == (int)sizeof(pchBuf)) || (bIsSSL && wolfSSL_pending(pnode->ssl) > 0);
|
||||||
|
if (!fMore || ++nDrainReads >= MAX_DRAIN_READS)
|
||||||
|
fKeepReading = false;
|
||||||
|
}
|
||||||
|
} else if (nBytes == 0) {
|
||||||
|
|
||||||
|
if (bIsSSL) {
|
||||||
unsigned long error = ERR_get_error();
|
unsigned long error = ERR_get_error();
|
||||||
const char* error_str = ERR_error_string(error, NULL);
|
const char* error_str = ERR_error_string(error, NULL);
|
||||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_read - code[0x%x], err: %s\n",
|
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_read err: %s\n",
|
||||||
__FILE__, __func__, __LINE__, nRet, error_str);
|
__FILE__, __func__, __LINE__, error_str);
|
||||||
|
}
|
||||||
|
// socket closed gracefully (peer disconnected)
|
||||||
|
if (!pnode->fDisconnect)
|
||||||
|
LogPrint("tls", "socket closed (%s)\n", pnode->addr.ToString());
|
||||||
|
pnode->CloseSocketDisconnect();
|
||||||
|
fKeepReading = false;
|
||||||
|
|
||||||
|
} else if (nBytes < 0) {
|
||||||
|
// error
|
||||||
|
if (bIsSSL) {
|
||||||
|
if (nRet != WOLFSSL_ERROR_WANT_READ && nRet != WOLFSSL_ERROR_WANT_WRITE)
|
||||||
|
{
|
||||||
|
if (!pnode->fDisconnect)
|
||||||
|
LogPrintf("TLS: ERROR: SSL_read %s\n", ERR_error_string(nRet, NULL));
|
||||||
|
pnode->CloseSocketDisconnect();
|
||||||
|
|
||||||
|
unsigned long error = ERR_get_error();
|
||||||
|
const char* error_str = ERR_error_string(error, NULL);
|
||||||
|
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_read - code[0x%x], err: %s\n",
|
||||||
|
__FILE__, __func__, __LINE__, nRet, error_str);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// preventive measure from exhausting CPU usage
|
||||||
|
MilliSleep(1); // 1 msec
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// preventive measure from exhausting CPU usage
|
if (nRet != WSAEWOULDBLOCK && nRet != WSAEMSGSIZE && nRet != WSAEINTR && nRet != WSAEINPROGRESS) {
|
||||||
MilliSleep(1); // 1 msec
|
if (!pnode->fDisconnect)
|
||||||
}
|
LogPrintf("TLS: ERROR: socket recv %s\n", NetworkErrorString(nRet));
|
||||||
} else {
|
pnode->CloseSocketDisconnect();
|
||||||
if (nRet != WSAEWOULDBLOCK && nRet != WSAEMSGSIZE && nRet != WSAEINTR && nRet != WSAEINPROGRESS) {
|
}
|
||||||
if (!pnode->fDisconnect)
|
|
||||||
LogPrintf("TLS: ERROR: socket recv %s\n", NetworkErrorString(nRet));
|
|
||||||
pnode->CloseSocketDisconnect();
|
|
||||||
}
|
}
|
||||||
|
fKeepReading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Copyright (c) 2016-2024 The Hush Developers
|
// Copyright (c) 2016-2024 The Hush Developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@@ -489,7 +488,7 @@ int32_t hush_verifynotarization(char *symbol,char *dest,int32_t height,int32_t N
|
|||||||
sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
|
sprintf(¶ms[i*2 + 2],"%02x",((uint8_t *)&NOTARIZED_DESTTXID)[31-i]);
|
||||||
strcat(params,"\", 1]");*/
|
strcat(params,"\", 1]");*/
|
||||||
sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
|
sprintf(params,"[\"%s\", 1]",NOTARIZED_DESTTXID.ToString().c_str());
|
||||||
if ( strcmp(symbol,SMART_CHAIN_SYMBOL[0]==0?(char *)"DRAGONX":SMART_CHAIN_SYMBOL) != 0 )
|
if ( strcmp(symbol,SMART_CHAIN_SYMBOL[0]==0?(char *)"HUSH3":SMART_CHAIN_SYMBOL) != 0 )
|
||||||
return(0);
|
return(0);
|
||||||
if ( 0 && SMART_CHAIN_SYMBOL[0] != 0 )
|
if ( 0 && SMART_CHAIN_SYMBOL[0] != 0 )
|
||||||
printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",SMART_CHAIN_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
|
printf("[%s] src.%s dest.%s params.[%s] ht.%d notarized.%d\n",SMART_CHAIN_SYMBOL,symbol,dest,params,height,NOTARIZED_HEIGHT);
|
||||||
@@ -941,7 +940,7 @@ int32_t hush_nextheight()
|
|||||||
int32_t hush_isrealtime(int32_t *hushheightp)
|
int32_t hush_isrealtime(int32_t *hushheightp)
|
||||||
{
|
{
|
||||||
struct hush_state *sp; CBlockIndex *pindex;
|
struct hush_state *sp; CBlockIndex *pindex;
|
||||||
if ( (sp= hush_stateptrget((char *)"DRAGONX")) != 0 )
|
if ( (sp= hush_stateptrget((char *)"HUSH3")) != 0 )
|
||||||
*hushheightp = sp->CURRENT_HEIGHT;
|
*hushheightp = sp->CURRENT_HEIGHT;
|
||||||
else *hushheightp = 0;
|
else *hushheightp = 0;
|
||||||
if ( (pindex= chainActive.LastTip()) != 0 && pindex->GetHeight() >= (int32_t)hush_longestchain() )
|
if ( (pindex= chainActive.LastTip()) != 0 && pindex->GetHeight() >= (int32_t)hush_longestchain() )
|
||||||
@@ -1075,12 +1074,12 @@ uint64_t hush_commission(int height)
|
|||||||
uint64_t the_commission(const CBlock *pblock,int32_t height)
|
uint64_t the_commission(const CBlock *pblock,int32_t height)
|
||||||
{
|
{
|
||||||
//fprintf(stderr,"%s at height=%d\n",__func__,height);
|
//fprintf(stderr,"%s at height=%d\n",__func__,height);
|
||||||
static bool didinit = false, isdragonx = false;
|
static bool didinit = false, ishush3 = false;
|
||||||
|
|
||||||
if (!didinit) {
|
if (!didinit) {
|
||||||
isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
didinit = true;
|
didinit = true;
|
||||||
fprintf(stderr,"%s: didinit isdragonx=%d\n", __func__, isdragonx);
|
fprintf(stderr,"%s: didinit ishush3=%d\n", __func__, ishush3);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t i,j,n=0,txn_count; int64_t nSubsidy; uint64_t commission,total = 0;
|
int32_t i,j,n=0,txn_count; int64_t nSubsidy; uint64_t commission,total = 0;
|
||||||
@@ -1091,7 +1090,7 @@ uint64_t the_commission(const CBlock *pblock,int32_t height)
|
|||||||
fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION));
|
fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION));
|
||||||
commission = ((nSubsidy * ASSETCHAINS_COMMISSION) / COIN);
|
commission = ((nSubsidy * ASSETCHAINS_COMMISSION) / COIN);
|
||||||
|
|
||||||
if (isdragonx) {
|
if (ishush3) {
|
||||||
commission = hush_commission(height);
|
commission = hush_commission(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ struct hush_event *hush_eventadd(struct hush_state *sp,int32_t height,char *symb
|
|||||||
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_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)
|
||||||
{
|
{
|
||||||
static uint32_t counter; int32_t verified=0; char *coin; struct hush_event_notarized N;
|
static uint32_t counter; int32_t verified=0; char *coin; struct hush_event_notarized N;
|
||||||
coin = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"DRAGONX" : SMART_CHAIN_SYMBOL;
|
coin = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"HUSH3" : SMART_CHAIN_SYMBOL;
|
||||||
if ( IS_HUSH_NOTARY != 0 && (verified= hush_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid)) < 0 )
|
if ( IS_HUSH_NOTARY != 0 && (verified= hush_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid)) < 0 )
|
||||||
{
|
{
|
||||||
if ( counter++ < 100 )
|
if ( counter++ < 100 )
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Copyright 2016-2024 The Hush Developers
|
// Copyright 2016-2024 The Hush Developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@@ -315,20 +314,20 @@ std::string DEVTAX_DATA[DEVTAX_NUM][2] = {
|
|||||||
// this is a deterministic consensus-changing function. All miners must be able
|
// this is a deterministic consensus-changing function. All miners must be able
|
||||||
// to predict the scriptpub for the next block
|
// to predict the scriptpub for the next block
|
||||||
std::string devtax_scriptpub_for_height(uint32_t nHeight) {
|
std::string devtax_scriptpub_for_height(uint32_t nHeight) {
|
||||||
bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
bool istush3 = strncmp(SMART_CHAIN_SYMBOL, "TUSH3",5) == 0 ? true : false;
|
bool istush3 = strncmp(SMART_CHAIN_SYMBOL, "TUSH3",5) == 0 ? true : false;
|
||||||
// Fork height for DRAGONX mainnet needs to be decided just before code is merged
|
// Fork height for HUSH3 mainnet needs to be decided just before code is merged
|
||||||
// Since it requires all full nodes on the network to have enough time to update.
|
// Since it requires all full nodes on the network to have enough time to update.
|
||||||
// For testing, we choose an early blockheight so we can observe the value changing
|
// For testing, we choose an early blockheight so we can observe the value changing
|
||||||
// from the old fixed value to the new values which cycle
|
// from the old fixed value to the new values which cycle
|
||||||
const int DEVTAX_FORK_HEIGHT = isdragonx ? nHushHardforkHeight4 : 5;
|
const int DEVTAX_FORK_HEIGHT = ishush3 ? nHushHardforkHeight4 : 5;
|
||||||
|
|
||||||
// Decentralized devtax is height-activated
|
// Decentralized devtax is height-activated
|
||||||
if (nHeight >= DEVTAX_FORK_HEIGHT) {
|
if (nHeight >= DEVTAX_FORK_HEIGHT) {
|
||||||
if (isdragonx || istush3) {
|
if (ishush3 || istush3) {
|
||||||
return DEVTAX_DATA[ nHeight % DEVTAX_NUM ][1];
|
return DEVTAX_DATA[ nHeight % DEVTAX_NUM ][1];
|
||||||
} else {
|
} else {
|
||||||
// if this is not DRAGONX or a testchain for DRAGONX, return it unchanged
|
// if this is not HUSH3 or a testchain for HUSH3, return it unchanged
|
||||||
return ASSETCHAINS_SCRIPTPUB;
|
return ASSETCHAINS_SCRIPTPUB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,20 +339,20 @@ std::string devtax_scriptpub_for_height(uint32_t nHeight) {
|
|||||||
// blocks < DEVTAX_FORK_HEIGHT but it could affect consensus of later blocks
|
// blocks < DEVTAX_FORK_HEIGHT but it could affect consensus of later blocks
|
||||||
std::string devtax_address_for_height(uint32_t nHeight) {
|
std::string devtax_address_for_height(uint32_t nHeight) {
|
||||||
const std::string legacy_devtax_address = "RHushEyeDm7XwtaTWtyCbjGQumYyV8vMjn";
|
const std::string legacy_devtax_address = "RHushEyeDm7XwtaTWtyCbjGQumYyV8vMjn";
|
||||||
bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
bool istush3 = strncmp(SMART_CHAIN_SYMBOL, "TUSH3",5) == 0 ? true : false;
|
bool istush3 = strncmp(SMART_CHAIN_SYMBOL, "TUSH3",5) == 0 ? true : false;
|
||||||
// Fork height for DRAGONX mainnet needs to be decided just before code is merged
|
// Fork height for HUSH3 mainnet needs to be decided just before code is merged
|
||||||
// Since it requires all full nodes on the network to have enough time to update.
|
// Since it requires all full nodes on the network to have enough time to update.
|
||||||
// For testing, we choose an early blockheight so we can observe the value changing
|
// For testing, we choose an early blockheight so we can observe the value changing
|
||||||
// from the old fixed value to the new values which cycle
|
// from the old fixed value to the new values which cycle
|
||||||
const int DEVTAX_FORK_HEIGHT = isdragonx ? nHushHardforkHeight4 : 5;
|
const int DEVTAX_FORK_HEIGHT = ishush3 ? nHushHardforkHeight4 : 5;
|
||||||
|
|
||||||
// Decentralized devtax is height-activated
|
// Decentralized devtax is height-activated
|
||||||
if (nHeight >= DEVTAX_FORK_HEIGHT) {
|
if (nHeight >= DEVTAX_FORK_HEIGHT) {
|
||||||
if (isdragonx || istush3) {
|
if (ishush3 || istush3) {
|
||||||
return DEVTAX_DATA[ nHeight % DEVTAX_NUM ][0];
|
return DEVTAX_DATA[ nHeight % DEVTAX_NUM ][0];
|
||||||
} else {
|
} else {
|
||||||
// if this is not DRAGONX or TUSH3, return legacy
|
// if this is not HUSH3 or TUSH3, return legacy
|
||||||
return legacy_devtax_address;
|
return legacy_devtax_address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -578,7 +578,7 @@ int32_t NSPV_notarizationextract(int32_t verifyntz,int32_t *ntzheightp,uint256 *
|
|||||||
int32_t numsigs=0; uint8_t elected[64][33]; char *symbol; std::vector<uint8_t> opret; uint32_t nTime;
|
int32_t numsigs=0; uint8_t elected[64][33]; char *symbol; std::vector<uint8_t> opret; uint32_t nTime;
|
||||||
if ( tx.vout.size() >= 2 )
|
if ( tx.vout.size() >= 2 )
|
||||||
{
|
{
|
||||||
symbol = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"DRAGONX" : SMART_CHAIN_SYMBOL;
|
symbol = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"HUSH3" : SMART_CHAIN_SYMBOL;
|
||||||
GetOpReturnData(tx.vout[1].scriptPubKey,opret);
|
GetOpReturnData(tx.vout[1].scriptPubKey,opret);
|
||||||
if ( opret.size() >= 32*2+4 )
|
if ( opret.size() >= 32*2+4 )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ struct NSPV_ntzargs
|
|||||||
int32_t NSPV_notarization_find(struct NSPV_ntzargs *args,int32_t height,int32_t dir)
|
int32_t NSPV_notarization_find(struct NSPV_ntzargs *args,int32_t height,int32_t dir)
|
||||||
{
|
{
|
||||||
int32_t ntzheight = 0; uint256 hashBlock; CTransaction tx; Notarization nota; char *symbol; std::vector<uint8_t> opret;
|
int32_t ntzheight = 0; uint256 hashBlock; CTransaction tx; Notarization nota; char *symbol; std::vector<uint8_t> opret;
|
||||||
symbol = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"DRAGONX" : SMART_CHAIN_SYMBOL;
|
symbol = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"HUSH3" : SMART_CHAIN_SYMBOL;
|
||||||
memset(args,0,sizeof(*args));
|
memset(args,0,sizeof(*args));
|
||||||
if ( dir > 0 )
|
if ( dir > 0 )
|
||||||
height += 10;
|
height += 10;
|
||||||
|
|||||||
@@ -110,13 +110,13 @@ int32_t hush_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp)
|
|||||||
|
|
||||||
// Find the correct DPoW Notary pubkeys for this season
|
// Find the correct DPoW Notary pubkeys for this season
|
||||||
int32_t hush_season = 0;
|
int32_t hush_season = 0;
|
||||||
bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
bool istush = strncmp(SMART_CHAIN_SYMBOL, "TUSH",4) == 0 ? true : false;
|
bool istush = strncmp(SMART_CHAIN_SYMBOL, "TUSH",4) == 0 ? true : false;
|
||||||
// TUSH uses height activation like DRAGONX, other HACs use timestamps
|
// TUSH uses height activation like HUSH3, other HACs use timestamps
|
||||||
hush_season = (isdragonx || istush) ? gethushseason(height) : getacseason(timestamp);
|
hush_season = (ishush3 || istush) ? gethushseason(height) : getacseason(timestamp);
|
||||||
|
|
||||||
if(IS_HUSH_NOTARY) {
|
if(IS_HUSH_NOTARY) {
|
||||||
fprintf(stderr,"%s: [%s] season=%d height=%d time=%d\n", __func__, isdragonx ? "DRAGONX" : SMART_CHAIN_SYMBOL, hush_season, height, timestamp);
|
fprintf(stderr,"%s: [%s] season=%d height=%d time=%d\n", __func__, ishush3 ? "HUSH3" : SMART_CHAIN_SYMBOL, hush_season, height, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( hush_season != 0 )
|
if ( hush_season != 0 )
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@@ -1474,12 +1473,9 @@ uint32_t hush_smartmagic(char *symbol,uint64_t supply,uint8_t *extraptr,int32_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: why is this needed?
|
//TODO: why is this needed?
|
||||||
const bool isdragonx = strncmp(symbol, "DRAGONX",7) == 0 ? true : false;
|
const bool ishush3 = strncmp(symbol, "HUSH3",5) == 0 ? true : false;
|
||||||
if(isdragonx) {
|
if(ishush3) {
|
||||||
// Use the same CRC-based magic as all other chains so that the
|
return HUSH_MAGIC;
|
||||||
// network magic bytes match between old wrapper-launched nodes
|
|
||||||
// and the new standalone binary.
|
|
||||||
return(calc_crc32(crc0,buf,len));
|
|
||||||
} else {
|
} else {
|
||||||
return(calc_crc32(crc0,buf,len));
|
return(calc_crc32(crc0,buf,len));
|
||||||
}
|
}
|
||||||
@@ -1623,8 +1619,8 @@ uint64_t hush_sc_block_subsidy(int nHeight)
|
|||||||
int64_t subsidyDifference;
|
int64_t subsidyDifference;
|
||||||
int32_t numhalvings = 0, curEra = 0, sign = 1;
|
int32_t numhalvings = 0, curEra = 0, sign = 1;
|
||||||
static uint64_t cached_subsidy; static int32_t cached_numhalvings; static int cached_era;
|
static uint64_t cached_subsidy; static int32_t cached_numhalvings; static int cached_era;
|
||||||
const bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
const bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
// fprintf(stderr,"%s: ht=%d isdragonx=%d\n", __func__, nHeight, isdragonx);
|
// fprintf(stderr,"%s: ht=%d ishush3=%d\n", __func__, nHeight, ishush3);
|
||||||
|
|
||||||
// check for backwards compat, older chains with no explicit rewards had 0.0001 block reward
|
// check for backwards compat, older chains with no explicit rewards had 0.0001 block reward
|
||||||
if ( ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] == 0 ) {
|
if ( ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] == 0 ) {
|
||||||
@@ -1653,12 +1649,14 @@ uint64_t hush_sc_block_subsidy(int nHeight)
|
|||||||
if(fDebug) {
|
if(fDebug) {
|
||||||
fprintf(stderr,"%s: subsidy=%ld at height=%d with ASSETCHAINS_HALVING[curEra]=%lu\n",__func__,subsidy,nHeight, ASSETCHAINS_HALVING[curEra]);
|
fprintf(stderr,"%s: subsidy=%ld at height=%d with ASSETCHAINS_HALVING[curEra]=%lu\n",__func__,subsidy,nHeight, ASSETCHAINS_HALVING[curEra]);
|
||||||
}
|
}
|
||||||
if (ASSETCHAINS_HALVING[curEra] != 0)
|
if ( ASSETCHAINS_HALVING[curEra] != 0 )
|
||||||
{
|
{
|
||||||
// hush_block_subsidy() is HUSH3-specific with hardcoded reward schedule
|
if (ishush3) {
|
||||||
// DragonX uses generic halving logic with ASSETCHAINS_REWARD/ASSETCHAINS_HALVING
|
subsidy = hush_block_subsidy(nHeight);
|
||||||
if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) {
|
if(fDebug)
|
||||||
// The code below is not compatible with DRAGONX mainnet
|
fprintf(stderr,"%s: HUSH3 subsidy=%ld at height=%d\n",__func__,subsidy,nHeight);
|
||||||
|
} else if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) {
|
||||||
|
// The code below is not compatible with HUSH3 mainnet
|
||||||
if ( ASSETCHAINS_DECAY[curEra] == 0 ) {
|
if ( ASSETCHAINS_DECAY[curEra] == 0 ) {
|
||||||
subsidy >>= numhalvings;
|
subsidy >>= numhalvings;
|
||||||
// fprintf(stderr,"%s: no decay, numhalvings.%d curEra.%d subsidy.%ld nStart.%ld\n",__func__, numhalvings, curEra, subsidy, nStart);
|
// fprintf(stderr,"%s: no decay, numhalvings.%d curEra.%d subsidy.%ld nStart.%ld\n",__func__, numhalvings, curEra, subsidy, nStart);
|
||||||
@@ -2350,14 +2348,13 @@ void hush_args(char *argv0)
|
|||||||
fprintf(stderr,"MAX_MONEY %llu %.8f\n",(long long)MAX_MONEY,(double)MAX_MONEY/SATOSHIDEN);
|
fprintf(stderr,"MAX_MONEY %llu %.8f\n",(long long)MAX_MONEY,(double)MAX_MONEY/SATOSHIDEN);
|
||||||
//printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,SMART_CHAIN_SYMBOL,(double)MAX_MONEY/SATOSHIDEN);
|
//printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,SMART_CHAIN_SYMBOL,(double)MAX_MONEY/SATOSHIDEN);
|
||||||
uint16_t tmpport = hush_port(SMART_CHAIN_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen);
|
uint16_t tmpport = hush_port(SMART_CHAIN_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen);
|
||||||
// DragonX P2P port is 21768 (RPC=21769). The HUSH_MAGIC shortcut in
|
|
||||||
// hush_smartmagic() produces 18030 which is wrong, so override here.
|
|
||||||
if(isdragonx) {
|
|
||||||
tmpport = 21768;
|
|
||||||
}
|
|
||||||
if ( GetArg("-port",0) != 0 )
|
if ( GetArg("-port",0) != 0 )
|
||||||
{
|
{
|
||||||
ASSETCHAINS_P2PPORT = GetArg("-port",0);
|
ASSETCHAINS_P2PPORT = GetArg("-port",0);
|
||||||
|
if(ishush3) {
|
||||||
|
fprintf(stderr,"set HUSH3 p2pport.%u\n",ASSETCHAINS_P2PPORT);
|
||||||
|
ASSETCHAINS_P2PPORT = 18030;
|
||||||
|
}
|
||||||
if(fDebug)
|
if(fDebug)
|
||||||
fprintf(stderr,"set p2pport.%u\n",ASSETCHAINS_P2PPORT);
|
fprintf(stderr,"set p2pport.%u\n",ASSETCHAINS_P2PPORT);
|
||||||
} else ASSETCHAINS_P2PPORT = tmpport;
|
} else ASSETCHAINS_P2PPORT = tmpport;
|
||||||
@@ -2455,7 +2452,7 @@ void hush_args(char *argv0)
|
|||||||
//fprintf(stderr,"(%s) port.%u chain params initialized\n",SMART_CHAIN_SYMBOL,BITCOIND_RPCPORT);
|
//fprintf(stderr,"(%s) port.%u chain params initialized\n",SMART_CHAIN_SYMBOL,BITCOIND_RPCPORT);
|
||||||
|
|
||||||
// Set custom cc rulse for chains here
|
// Set custom cc rulse for chains here
|
||||||
if ( strcmp("DRAGONX",SMART_CHAIN_SYMBOL) == 0 ) {
|
if ( strcmp("HUSH3",SMART_CHAIN_SYMBOL) == 0 ) {
|
||||||
// Disable all CC's
|
// Disable all CC's
|
||||||
if(GetArg("-ac_disable_cc",false)) {
|
if(GetArg("-ac_disable_cc",false)) {
|
||||||
CCDISABLEALL;
|
CCDISABLEALL;
|
||||||
|
|||||||
231
src/init.cpp
231
src/init.cpp
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
// What happened to the SuperNET devs, who were dedicated to privacy???
|
// What happened to the SuperNET devs, who were dedicated to privacy???
|
||||||
@@ -44,6 +43,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "metrics.h"
|
#include "metrics.h"
|
||||||
|
#include "pow.h"
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "rpc/server.h"
|
#include "rpc/server.h"
|
||||||
@@ -177,7 +177,7 @@ public:
|
|||||||
// Writes do not need similar protection, as failure to write is handled by the caller.
|
// Writes do not need similar protection, as failure to write is handled by the caller.
|
||||||
};
|
};
|
||||||
|
|
||||||
static CCoinsViewDB *pcoinsdbview = NULL;
|
CCoinsViewDB *pcoinsdbview = NULL; // global (declared extern in main.h) for UTXO-snapshot dump/load
|
||||||
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
|
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
|
||||||
static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
|
static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
|
||||||
|
|
||||||
@@ -207,12 +207,12 @@ void Shutdown()
|
|||||||
/// Be sure that anything that writes files or flushes caches only does this if the respective
|
/// Be sure that anything that writes files or flushes caches only does this if the respective
|
||||||
/// module was initialized.
|
/// module was initialized.
|
||||||
static char shutoffstr[128];
|
static char shutoffstr[128];
|
||||||
sprintf(shutoffstr,"%s-shutoff","dragonx");
|
sprintf(shutoffstr,"%s-shutoff","hush");
|
||||||
RenameThread(shutoffstr);
|
RenameThread(shutoffstr);
|
||||||
mempool.AddTransactionsUpdated(1);
|
mempool.AddTransactionsUpdated(1);
|
||||||
|
|
||||||
if(fDebug) {
|
if(fDebug) {
|
||||||
fprintf(stderr,"%s: stopping DragonX HTTP/REST/RPC\n", __FUNCTION__);
|
fprintf(stderr,"%s: stopping HUSH HTTP/REST/RPC\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
StopHTTPRPC();
|
StopHTTPRPC();
|
||||||
StopREST();
|
StopREST();
|
||||||
@@ -388,7 +388,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
}
|
}
|
||||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory (this path cannot use '~')"));
|
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory (this path cannot use '~')"));
|
||||||
strUsage += HelpMessageOpt("-exportdir=<dir>", _("Specify directory to be used when exporting data"));
|
strUsage += HelpMessageOpt("-exportdir=<dir>", _("Specify directory to be used when exporting data"));
|
||||||
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
|
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d). Default: adaptive - uses most free RAM to speed up initial block download (far fewer UTXO flushes to disk) and automatically shrinks if other applications need memory, always leaving a reserve free. Setting a fixed value disables adaptive sizing."), nMinDbCache, nMaxDbCache));
|
||||||
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
|
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
|
||||||
strUsage += HelpMessageOpt("-maxdebugfilesize=<n>", strprintf(_("Set the max size of the debug.log file (default: %u)"), 15));
|
strUsage += HelpMessageOpt("-maxdebugfilesize=<n>", strprintf(_("Set the max size of the debug.log file (default: %u)"), 15));
|
||||||
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
|
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
|
||||||
@@ -396,8 +396,9 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
strUsage += HelpMessageOpt("-mempooltxinputlimit=<n>", _("[DEPRECATED/IGNORED] Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)"));
|
strUsage += HelpMessageOpt("-mempooltxinputlimit=<n>", _("[DEPRECATED/IGNORED] Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)"));
|
||||||
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
|
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
|
||||||
-(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
|
-(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
|
||||||
|
strUsage += HelpMessageOpt("-randomxverifythreads=<n>", strprintf(_("Number of threads for parallel RandomX PoW pre-verification of post-checkpoint blocks during sync (0 = inline only, max %d, default: same as -par)"), MAX_SCRIPTCHECK_THREADS));
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "dragonxd.pid"));
|
strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "hushd.pid"));
|
||||||
#endif
|
#endif
|
||||||
strUsage += HelpMessageOpt("-txexpirynotify=<cmd>", _("Execute command when transaction expires (%s in cmd is replaced by transaction id)"));
|
strUsage += HelpMessageOpt("-txexpirynotify=<cmd>", _("Execute command when transaction expires (%s in cmd is replaced by transaction id)"));
|
||||||
strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. "
|
strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. "
|
||||||
@@ -466,6 +467,12 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
strUsage += HelpMessageGroup(_("Wallet options:"));
|
strUsage += HelpMessageGroup(_("Wallet options:"));
|
||||||
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
|
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
|
||||||
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
|
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
|
||||||
|
strUsage += HelpMessageOpt("-hdtransparent", strprintf(_("Derive transparent addresses from the HD seed so they can be recovered from it (default: %u)"), 1));
|
||||||
|
strUsage += HelpMessageOpt("-hdseed=<hex>", _("Restore a fresh/empty wallet from a 32- or 64-byte HD seed hex (the value shown in z_exportwallet's '# HDSeed=' line). WARNING: exposes the seed to your shell history and process list."));
|
||||||
|
strUsage += HelpMessageOpt("-mnemonic=<words>", _("Restore/create a fresh/empty wallet from a BIP39 seed phrase, compatible with SilentDragonXLite (English, no passphrase). WARNING: exposes the phrase to your shell history and process list; prefer DRAGONX.conf with tight permissions."));
|
||||||
|
strUsage += HelpMessageOpt("-usemnemonic", strprintf(_("Create new wallets from a fresh BIP39 seed phrase so the 24 words can be exported (z_exportmnemonic) and used in SilentDragonXLite (default: %u)"), 0));
|
||||||
|
strUsage += HelpMessageOpt("-hdtransparentgaplimit=<n>", strprintf(_("On -mnemonic/-hdseed restore, pre-derive this many HD transparent keys so a rescan can find coinbase paid to them (default: %u)"), 1000));
|
||||||
|
strUsage += HelpMessageOpt("-mnemonicsaplinggap=<n>", strprintf(_("On -mnemonic/-hdseed restore, pre-derive this many shielded (Sapling) addresses so a rescan can find notes sent to them (default: %u)"), 100));
|
||||||
strUsage += HelpMessageOpt("-consolidation", _("Enable auto Sapling note consolidation (default: false)"));
|
strUsage += HelpMessageOpt("-consolidation", _("Enable auto Sapling note consolidation (default: false)"));
|
||||||
strUsage += HelpMessageOpt("-consolidationinterval", _("Block interval between consolidations (default: 25)"));
|
strUsage += HelpMessageOpt("-consolidationinterval", _("Block interval between consolidations (default: 25)"));
|
||||||
strUsage += HelpMessageOpt("-consolidatesaplingaddress=<zaddr>", _("Specify Sapling Address to Consolidate. (default: all)"));
|
strUsage += HelpMessageOpt("-consolidatesaplingaddress=<zaddr>", _("Specify Sapling Address to Consolidate. (default: all)"));
|
||||||
@@ -988,6 +995,123 @@ bool AppInitServers(boost::thread_group& threadGroup)
|
|||||||
*/
|
*/
|
||||||
extern int32_t HUSH_REWIND;
|
extern int32_t HUSH_REWIND;
|
||||||
|
|
||||||
|
// --- Adaptive coins-cache sizing -------------------------------------------------------------
|
||||||
|
// The in-memory UTXO/coins cache (nCoinCacheUsage) is the biggest lever on IBD speed: a bigger
|
||||||
|
// cache means far fewer chainstate flushes to disk. We size it to use most of RAM, but a scheduled
|
||||||
|
// background task (AdjustCoinCacheForMemoryPressure, registered in AppInit2) shrinks the target when
|
||||||
|
// free system memory runs low — e.g. the user opens other apps — and grows it back when memory frees
|
||||||
|
// up, always leaving a reserve free for the rest of the system. The existing per-block flush
|
||||||
|
// (FlushStateToDisk, FLUSH_STATE_IF_NEEDED, which fires when cacheSize > nCoinCacheUsage) enforces
|
||||||
|
// whatever target is current, so the task only moves the threshold: it never touches cs_main or the
|
||||||
|
// flush path. NOTE: the coins cache is application heap, not OS file cache — "freeing" it means an
|
||||||
|
// early flush that clears the map; on Linux the allocator returns the pages, on Windows the heap
|
||||||
|
// returns them best-effort (RSS may lag), but either way the node stops growing past the target.
|
||||||
|
// windows.h / <unistd.h> arrive via compat.h (net.h). Memory helpers return 0 if undeterminable.
|
||||||
|
static int64_t GetPhysicalMemoryMB()
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
MEMORYSTATUSEX status;
|
||||||
|
status.dwLength = sizeof(status);
|
||||||
|
if (GlobalMemoryStatusEx(&status))
|
||||||
|
return (int64_t)(status.ullTotalPhys / (1024 * 1024));
|
||||||
|
return 0;
|
||||||
|
#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
|
||||||
|
long pages = sysconf(_SC_PHYS_PAGES);
|
||||||
|
long pageSize = sysconf(_SC_PAGESIZE);
|
||||||
|
if (pages > 0 && pageSize > 0)
|
||||||
|
return (int64_t)((int64_t)pages * (int64_t)pageSize / (1024 * 1024));
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently-available (allocatable) physical RAM in MiB. On Linux uses MemAvailable (counts
|
||||||
|
// reclaimable page cache), falling back to truly-free pages.
|
||||||
|
static int64_t GetAvailableMemoryMB()
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
MEMORYSTATUSEX status;
|
||||||
|
status.dwLength = sizeof(status);
|
||||||
|
if (GlobalMemoryStatusEx(&status))
|
||||||
|
return (int64_t)(status.ullAvailPhys / (1024 * 1024));
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
FILE* f = fopen("/proc/meminfo", "r");
|
||||||
|
if (f) {
|
||||||
|
char line[256];
|
||||||
|
long long availKB = -1;
|
||||||
|
while (fgets(line, sizeof(line), f)) {
|
||||||
|
if (sscanf(line, "MemAvailable: %lld kB", &availKB) == 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
if (availKB >= 0)
|
||||||
|
return (int64_t)(availKB / 1024);
|
||||||
|
}
|
||||||
|
#if defined(_SC_AVPHYS_PAGES) && defined(_SC_PAGESIZE)
|
||||||
|
long pages = sysconf(_SC_AVPHYS_PAGES);
|
||||||
|
long pageSize = sysconf(_SC_PAGESIZE);
|
||||||
|
if (pages > 0 && pageSize > 0)
|
||||||
|
return (int64_t)((int64_t)pages * (int64_t)pageSize / (1024 * 1024));
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// RAM (MiB) to always keep free for the OS and other applications: 20% of total, at least 2 GiB.
|
||||||
|
static int64_t GetMemoryReserveMB()
|
||||||
|
{
|
||||||
|
int64_t ramMB = GetPhysicalMemoryMB();
|
||||||
|
int64_t reserve = (ramMB > 0) ? ramMB / 5 : 2048; // 20%
|
||||||
|
if (reserve < 2048) reserve = 2048;
|
||||||
|
return reserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Startup -dbcache default: use most of RAM (total minus the reserve), clamped to
|
||||||
|
// [nDefaultDbCache, nMaxDbCache] MiB. Falls back to the fixed default if RAM can't be detected.
|
||||||
|
static int64_t GetDefaultDbCacheMB()
|
||||||
|
{
|
||||||
|
int64_t ramMB = GetPhysicalMemoryMB();
|
||||||
|
if (ramMB <= 0)
|
||||||
|
return nDefaultDbCache;
|
||||||
|
int64_t cacheMB = ramMB - GetMemoryReserveMB();
|
||||||
|
if (cacheMB < nDefaultDbCache) cacheMB = nDefaultDbCache;
|
||||||
|
if (cacheMB > nMaxDbCache) cacheMB = nMaxDbCache;
|
||||||
|
return cacheMB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ceiling (bytes) the adaptive task may grow the coins cache back up to (the startup nCoinCacheUsage).
|
||||||
|
static size_t g_nMaxCoinCacheUsage = 0;
|
||||||
|
static const int64_t g_nMinCoinCacheMB = 256; // never thrash below this working set
|
||||||
|
|
||||||
|
// Scheduled task: nudge nCoinCacheUsage toward "use all RAM except the reserve". If free RAM is below
|
||||||
|
// the reserve we shrink the target (the next per-block flush releases the excess); if there is spare
|
||||||
|
// RAM we grow it back toward the startup ceiling. Lock-free: it only reads system memory and writes
|
||||||
|
// the aligned size_t threshold that the flush path reads.
|
||||||
|
static void AdjustCoinCacheForMemoryPressure()
|
||||||
|
{
|
||||||
|
if (g_nMaxCoinCacheUsage == 0)
|
||||||
|
return; // adaptive sizing disabled (user pinned -dbcache) or RAM undetectable
|
||||||
|
int64_t availMB = GetAvailableMemoryMB();
|
||||||
|
if (availMB <= 0)
|
||||||
|
return; // can't measure pressure; leave the target untouched
|
||||||
|
int64_t reserveMB = GetMemoryReserveMB();
|
||||||
|
// Error term: free RAM beyond the reserve. >0 => spare, grow; <0 => pressure, shrink.
|
||||||
|
int64_t errMB = availMB - reserveMB;
|
||||||
|
// Deadband: ignore small fluctuations so the target settles instead of oscillating.
|
||||||
|
if (errMB > -256 && errMB < 256)
|
||||||
|
return;
|
||||||
|
int64_t curTargetMB = (int64_t)(nCoinCacheUsage >> 20);
|
||||||
|
// Damped proportional step (gain 1/4) toward "free RAM == reserve"; the clamps bound it and the
|
||||||
|
// per-block flush (FLUSH_STATE_IF_NEEDED) enforces a lowered target within ~one block during IBD.
|
||||||
|
int64_t newTargetMB = curTargetMB + errMB / 4;
|
||||||
|
int64_t ceilMB = (int64_t)(g_nMaxCoinCacheUsage >> 20);
|
||||||
|
if (newTargetMB > ceilMB) newTargetMB = ceilMB;
|
||||||
|
if (newTargetMB < g_nMinCoinCacheMB) newTargetMB = g_nMinCoinCacheMB;
|
||||||
|
nCoinCacheUsage = (size_t)(newTargetMB << 20);
|
||||||
|
}
|
||||||
|
|
||||||
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||||
{
|
{
|
||||||
//fprintf(stderr,"%s start\n", __FUNCTION__);
|
//fprintf(stderr,"%s start\n", __FUNCTION__);
|
||||||
@@ -1310,6 +1434,29 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
|
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
|
||||||
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
|
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
|
||||||
|
|
||||||
|
// Parallel RandomX pre-verification threads (speeds up post-checkpoint sync). Defaults to the
|
||||||
|
// script-check thread count — RandomX pre-verify and script checks do not run simultaneously
|
||||||
|
// within a single connect, so they can share the same budget. 0 disables (inline-only).
|
||||||
|
nRandomXVerifyThreads = GetArg("-randomxverifythreads", nScriptCheckThreads);
|
||||||
|
if (nRandomXVerifyThreads < 0)
|
||||||
|
nRandomXVerifyThreads = 0;
|
||||||
|
else if (nRandomXVerifyThreads > MAX_SCRIPTCHECK_THREADS)
|
||||||
|
nRandomXVerifyThreads = MAX_SCRIPTCHECK_THREADS;
|
||||||
|
|
||||||
|
// Per-peer block-download window (see MAX_BLOCKS_IN_TRANSIT_PER_PEER). Raising this lifts
|
||||||
|
// the bandwidth-delay-product ceiling on high-latency peers during IBD. Clamp to a sane range.
|
||||||
|
MAX_BLOCKS_IN_TRANSIT_PER_PEER = GetArg("-maxblocksintransit", DEFAULT_MAX_BLOCKS_IN_TRANSIT_PER_PEER);
|
||||||
|
if (MAX_BLOCKS_IN_TRANSIT_PER_PEER < 1)
|
||||||
|
MAX_BLOCKS_IN_TRANSIT_PER_PEER = 1;
|
||||||
|
else if (MAX_BLOCKS_IN_TRANSIT_PER_PEER > 4096)
|
||||||
|
MAX_BLOCKS_IN_TRANSIT_PER_PEER = 4096;
|
||||||
|
LogPrintf("Per-peer max blocks in transit: %d\n", MAX_BLOCKS_IN_TRANSIT_PER_PEER);
|
||||||
|
|
||||||
|
// Opt-in bulk block streaming (DragonX). Drives the requester branch in SendMessages and, when
|
||||||
|
// set, also advertises NODE_BULKBLOCKS below so we serve bulk ranges to peers. OFF by default.
|
||||||
|
fBulkBlockSync = GetBoolArg("-bulkblocksync", DEFAULT_BULKBLOCKSYNC);
|
||||||
|
LogPrintf("Bulk block streaming: %s\n", fBulkBlockSync ? "enabled" : "disabled");
|
||||||
|
|
||||||
fServer = GetBoolArg("-server", false);
|
fServer = GetBoolArg("-server", false);
|
||||||
//fprintf(stderr,"%s tik6\n", __FUNCTION__);
|
//fprintf(stderr,"%s tik6\n", __FUNCTION__);
|
||||||
|
|
||||||
@@ -1546,6 +1693,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
threadGroup.create_thread(&ThreadScriptCheck);
|
threadGroup.create_thread(&ThreadScriptCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Spawn the parallel RandomX pre-verification worker pool (the connect thread joins as the Nth
|
||||||
|
// worker via CCheckQueueControl::Wait, so spawn N-1 here, mirroring ThreadScriptCheck).
|
||||||
|
if (ASSETCHAINS_ALGO == ASSETCHAINS_RANDOMX && nRandomXVerifyThreads > 0) {
|
||||||
|
LogPrintf("Using %u threads for parallel RandomX pre-verification\n", nRandomXVerifyThreads);
|
||||||
|
for (int i = 0; i < nRandomXVerifyThreads - 1; i++)
|
||||||
|
threadGroup.create_thread(&ThreadRandomXVerify);
|
||||||
|
}
|
||||||
|
|
||||||
//fprintf(stderr,"%s tik13\n", __FUNCTION__);
|
//fprintf(stderr,"%s tik13\n", __FUNCTION__);
|
||||||
|
|
||||||
// Start the lightweight task scheduler thread
|
// Start the lightweight task scheduler thread
|
||||||
@@ -1841,7 +1996,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
LogPrintf("* Compression is %s\n", dbCompression ? "enabled" : "disabled");
|
LogPrintf("* Compression is %s\n", dbCompression ? "enabled" : "disabled");
|
||||||
|
|
||||||
// cache size calculations
|
// cache size calculations
|
||||||
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
|
int64_t nTotalCache = (GetArg("-dbcache", GetDefaultDbCacheMB()) << 20);
|
||||||
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
|
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
|
||||||
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
|
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
|
||||||
int64_t nBlockTreeDBCache = nTotalCache / 8;
|
int64_t nBlockTreeDBCache = nTotalCache / 8;
|
||||||
@@ -1858,6 +2013,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
|
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
|
||||||
nTotalCache -= nCoinDBCache;
|
nTotalCache -= nCoinDBCache;
|
||||||
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
|
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
|
||||||
|
// Adaptive sizing: unless the user pinned -dbcache, grow/shrink the coins cache with free system
|
||||||
|
// memory (AdjustCoinCacheForMemoryPressure), using the startup size as the ceiling.
|
||||||
|
if (!mapArgs.count("-dbcache")) {
|
||||||
|
g_nMaxCoinCacheUsage = nCoinCacheUsage;
|
||||||
|
scheduler.scheduleEvery(&AdjustCoinCacheForMemoryPressure, 5);
|
||||||
|
LogPrintf("* Adaptive dbcache enabled: ceiling %.0fMiB, keeping >= %lldMiB RAM free for the system\n",
|
||||||
|
nCoinCacheUsage * (1.0 / 1024 / 1024), (long long)GetMemoryReserveMB());
|
||||||
|
}
|
||||||
LogPrintf("Cache configuration:\n");
|
LogPrintf("Cache configuration:\n");
|
||||||
LogPrintf("* Max cache setting possible %.1fMiB\n", nMaxDbCache);
|
LogPrintf("* Max cache setting possible %.1fMiB\n", nMaxDbCache);
|
||||||
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
|
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
|
||||||
@@ -1939,6 +2102,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
strLoadError = _("Error initializing block database");
|
strLoadError = _("Error initializing block database");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
HUSH_LOADINGBLOCKS = 0;
|
HUSH_LOADINGBLOCKS = 0;
|
||||||
// Check for changed -txindex state
|
// Check for changed -txindex state
|
||||||
if (fTxIndex != GetBoolArg("-txindex", true)) {
|
if (fTxIndex != GetBoolArg("-txindex", true)) {
|
||||||
@@ -2108,8 +2272,54 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
|
|
||||||
if (!pwalletMain->HaveHDSeed())
|
if (!pwalletMain->HaveHDSeed())
|
||||||
{
|
{
|
||||||
// generate a new HD seed
|
std::string mnemonic = GetArg("-mnemonic", "");
|
||||||
pwalletMain->GenerateNewSeed();
|
std::string hdSeedHex = GetArg("-hdseed", "");
|
||||||
|
bool restoring = false;
|
||||||
|
|
||||||
|
if (!mnemonic.empty() && !hdSeedHex.empty())
|
||||||
|
return InitError(_("Specify only one of -mnemonic or -hdseed, not both"));
|
||||||
|
|
||||||
|
if (!mnemonic.empty())
|
||||||
|
{
|
||||||
|
// Restore/create a wallet from a BIP39 seed phrase, byte-compatible
|
||||||
|
// with SilentDragonXLite. Must be a fresh/empty wallet.
|
||||||
|
if (!pwalletMain->SetHDSeedFromMnemonic(mnemonic))
|
||||||
|
return InitError(_("Invalid -mnemonic: expected a valid BIP39 English phrase on a fresh/empty wallet"));
|
||||||
|
LogPrintf("%s: restoring wallet from -mnemonic seed phrase\n", __func__);
|
||||||
|
restoring = true;
|
||||||
|
}
|
||||||
|
else if (!hdSeedHex.empty())
|
||||||
|
{
|
||||||
|
// Restore from a previously exported HD seed hex (z_exportwallet's
|
||||||
|
// "# HDSeed=" line): 32 bytes (raw) or 64 bytes (BIP39-derived).
|
||||||
|
if (!pwalletMain->SetHDSeedFromHex(hdSeedHex))
|
||||||
|
return InitError(_("Invalid -hdseed: expected a 32- or 64-hex-character seed on a fresh/empty wallet"));
|
||||||
|
LogPrintf("%s: restoring wallet from -hdseed\n", __func__);
|
||||||
|
restoring = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// generate a new HD seed
|
||||||
|
pwalletMain->GenerateNewSeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restoring)
|
||||||
|
{
|
||||||
|
// Pre-derive keys (birthday = genesis) so the startup rescan finds
|
||||||
|
// funds paid to them: transparent coinbase + shielded notes.
|
||||||
|
int64_t tGap = GetArg("-hdtransparentgaplimit", 1000);
|
||||||
|
if (tGap < 0) tGap = 0;
|
||||||
|
pwalletMain->TopUpHDTransparentKeys((unsigned int)tGap, 1);
|
||||||
|
|
||||||
|
int64_t zGap = GetArg("-mnemonicsaplinggap", 100);
|
||||||
|
if (zGap < 0) zGap = 0;
|
||||||
|
{
|
||||||
|
LOCK(pwalletMain->cs_wallet);
|
||||||
|
for (int i = 0; i < (int)zGap; i++)
|
||||||
|
pwalletMain->GenerateNewSaplingZKey();
|
||||||
|
}
|
||||||
|
LogPrintf("%s: pre-derived %d transparent and %d sapling keys for restore rescan\n", __func__, (int)tGap, (int)zGap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set Sapling Consolidation
|
//Set Sapling Consolidation
|
||||||
@@ -2381,6 +2591,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
nLocalServices |= NODE_ADDRINDEX;
|
nLocalServices |= NODE_ADDRINDEX;
|
||||||
if ( GetBoolArg("-spentindex", DEFAULT_SPENTINDEX) != 0 )
|
if ( GetBoolArg("-spentindex", DEFAULT_SPENTINDEX) != 0 )
|
||||||
nLocalServices |= NODE_SPENTINDEX;
|
nLocalServices |= NODE_SPENTINDEX;
|
||||||
|
// Advertise willingness to SERVE bulk block streams (full nodes only) when opted in.
|
||||||
|
if ( fBulkBlockSync )
|
||||||
|
nLocalServices |= NODE_BULKBLOCKS;
|
||||||
fprintf(stderr,"nLocalServices %llx %d, %d\n",(long long)nLocalServices,GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX),GetBoolArg("-spentindex", DEFAULT_SPENTINDEX));
|
fprintf(stderr,"nLocalServices %llx %d, %d\n",(long long)nLocalServices,GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX),GetBoolArg("-spentindex", DEFAULT_SPENTINDEX));
|
||||||
}
|
}
|
||||||
// ********************************************************* Step 10: import blocks
|
// ********************************************************* Step 10: import blocks
|
||||||
|
|||||||
@@ -39,6 +39,9 @@
|
|||||||
*/
|
*/
|
||||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
|
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
|
||||||
|
|
||||||
|
/** BIP32: child indices at or above this are hardened. */
|
||||||
|
const unsigned int BIP32_HARDENED_KEY_LIMIT = 0x80000000;
|
||||||
|
|
||||||
/** An encapsulated private key. */
|
/** An encapsulated private key. */
|
||||||
class CKey
|
class CKey
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ namespace port {
|
|||||||
|
|
||||||
// Mac OS
|
// Mac OS
|
||||||
#elif defined(OS_MACOSX)
|
#elif defined(OS_MACOSX)
|
||||||
|
#include <atomic>
|
||||||
inline void MemoryBarrier() {
|
inline void MemoryBarrier() {
|
||||||
OSMemoryBarrier();
|
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
#define LEVELDB_HAVE_MEMORY_BARRIER
|
#define LEVELDB_HAVE_MEMORY_BARRIER
|
||||||
|
|
||||||
|
|||||||
BIN
src/libcc.dylib
Normal file
BIN
src/libcc.dylib
Normal file
Binary file not shown.
410
src/main.cpp
410
src/main.cpp
@@ -89,6 +89,12 @@ static int64_t nTimeBestReceived = 0;
|
|||||||
CWaitableCriticalSection csBestBlock;
|
CWaitableCriticalSection csBestBlock;
|
||||||
CConditionVariable cvBlockChange;
|
CConditionVariable cvBlockChange;
|
||||||
int nScriptCheckThreads = 0;
|
int nScriptCheckThreads = 0;
|
||||||
|
int MAX_BLOCKS_IN_TRANSIT_PER_PEER = DEFAULT_MAX_BLOCKS_IN_TRANSIT_PER_PEER;
|
||||||
|
bool fBulkBlockSync = DEFAULT_BULKBLOCKSYNC;
|
||||||
|
// Server-side flood throttle: minimum interval between bulk serves to the same peer (main.cpp-local
|
||||||
|
// since only the serve handler uses it; kept out of main.h to avoid a full-tree recompile).
|
||||||
|
static const int64_t BULK_MIN_SERVE_INTERVAL_US = 50000; // 50 ms => <= 20 bulk serves/s/peer
|
||||||
|
int nRandomXVerifyThreads = 0; // parallel RandomX pre-verification worker count (0 = inline only)
|
||||||
bool fExperimentalMode = true;
|
bool fExperimentalMode = true;
|
||||||
bool fImporting = false;
|
bool fImporting = false;
|
||||||
bool fReindex = false;
|
bool fReindex = false;
|
||||||
@@ -107,7 +113,7 @@ size_t nCoinCacheUsage = 5000 * 300;
|
|||||||
uint64_t nPruneTarget = 0;
|
uint64_t nPruneTarget = 0;
|
||||||
// If the tip is older than this (in seconds), the node is considered to be in initial block download.
|
// If the tip is older than this (in seconds), the node is considered to be in initial block download.
|
||||||
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
|
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
|
||||||
const bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
const bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
int32_t nFirstHalvingHeight = 340000;
|
int32_t nFirstHalvingHeight = 340000;
|
||||||
|
|
||||||
unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA;
|
unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA;
|
||||||
@@ -247,6 +253,7 @@ namespace {
|
|||||||
int64_t nTime; //! Time of "getdata" request in microseconds.
|
int64_t nTime; //! Time of "getdata" request in microseconds.
|
||||||
bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
|
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)
|
int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer)
|
||||||
|
bool fBulk; //! Requested as part of a bulk stream range (exempt from the front() stall-disconnect).
|
||||||
};
|
};
|
||||||
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
|
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
|
||||||
|
|
||||||
@@ -306,6 +313,21 @@ namespace {
|
|||||||
int nBlocksInFlightValidHeaders;
|
int nBlocksInFlightValidHeaders;
|
||||||
//! Whether we consider this a preferred download peer.
|
//! Whether we consider this a preferred download peer.
|
||||||
bool fPreferredDownload;
|
bool fPreferredDownload;
|
||||||
|
//! Opt-in bulk block streaming (DragonX): whether a bulk range request is outstanding to this peer.
|
||||||
|
bool fBulkInFlight;
|
||||||
|
//! Time (us) the outstanding bulk request was issued, for the response timeout/fallback.
|
||||||
|
int64_t nBulkSince;
|
||||||
|
//! Height of the first block in the outstanding bulk range.
|
||||||
|
int nBulkRangeStart;
|
||||||
|
//! Number of blocks requested in the outstanding bulk range.
|
||||||
|
int nBulkRangeCount;
|
||||||
|
//! Hash of the first block of the outstanding bulk range (request identity; the server echoes it
|
||||||
|
//! in the BLOCKSTREAM header so a stale/duplicate header for an old request can be ignored).
|
||||||
|
uint256 nBulkHashStart;
|
||||||
|
//! Whether the (one-shot) trailing BLOCKSTREAM header for the outstanding request was processed.
|
||||||
|
bool fBulkHeaderSeen;
|
||||||
|
//! (server side) time (us) we last served a bulk stream to this peer, for flood throttling.
|
||||||
|
int64_t nLastBulkServeTime;
|
||||||
|
|
||||||
CNodeState() {
|
CNodeState() {
|
||||||
fCurrentlyConnected = false;
|
fCurrentlyConnected = false;
|
||||||
@@ -319,6 +341,13 @@ namespace {
|
|||||||
nBlocksInFlight = 0;
|
nBlocksInFlight = 0;
|
||||||
nBlocksInFlightValidHeaders = 0;
|
nBlocksInFlightValidHeaders = 0;
|
||||||
fPreferredDownload = false;
|
fPreferredDownload = false;
|
||||||
|
fBulkInFlight = false;
|
||||||
|
nBulkSince = 0;
|
||||||
|
nBulkRangeStart = 0;
|
||||||
|
nBulkRangeCount = 0;
|
||||||
|
nBulkHashStart.SetNull();
|
||||||
|
fBulkHeaderSeen = false;
|
||||||
|
nLastBulkServeTime = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -413,7 +442,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Requires cs_main.
|
// Requires cs_main.
|
||||||
void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) {
|
void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL, bool fBulk = false) {
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
assert(state != NULL);
|
assert(state != NULL);
|
||||||
|
|
||||||
@@ -421,7 +450,7 @@ namespace {
|
|||||||
MarkBlockAsReceived(hash);
|
MarkBlockAsReceived(hash);
|
||||||
|
|
||||||
int64_t nNow = GetTimeMicros();
|
int64_t nNow = GetTimeMicros();
|
||||||
QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)};
|
QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams), fBulk};
|
||||||
nQueuedValidatedHeaders += newentry.fValidatedHeaders;
|
nQueuedValidatedHeaders += newentry.fValidatedHeaders;
|
||||||
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
|
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
|
||||||
state->nBlocksInFlight++;
|
state->nBlocksInFlight++;
|
||||||
@@ -429,6 +458,36 @@ namespace {
|
|||||||
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
|
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opt-in bulk block streaming (DragonX): free this peer's still-in-flight bulk blocks whose height
|
||||||
|
// falls in [hStart, hEnd), so the normal per-block path re-fetches them. We scan the peer's OWN
|
||||||
|
// vBlocksInFlight by the LITERAL hash marked at request time (via the stored pindex) rather than
|
||||||
|
// re-deriving hashes from the mutable pindexBestKnownBlock - the latter would miss the real entries
|
||||||
|
// after a reorg (leaking in-flight slots) and can never touch another peer's blocks. Requires cs_main.
|
||||||
|
void FreeBulkRangeInFlight(CNodeState* state, int hStart, int hEnd) {
|
||||||
|
if (state == NULL) return;
|
||||||
|
std::vector<uint256> toFree; // collect first: MarkBlockAsReceived erases from vBlocksInFlight
|
||||||
|
BOOST_FOREACH(const QueuedBlock& q, state->vBlocksInFlight) {
|
||||||
|
if (q.fBulk && q.pindex != NULL) {
|
||||||
|
int h = q.pindex->GetHeight();
|
||||||
|
if (h >= hStart && h < hEnd) toFree.push_back(q.hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOOST_FOREACH(const uint256& hh, toFree)
|
||||||
|
MarkBlockAsReceived(hh);
|
||||||
|
}
|
||||||
|
// True if any of this peer's bulk blocks with height in [hStart, hEnd) is still in flight (range not
|
||||||
|
// fully drained). Completion is decided by the RANGE draining, not the global per-peer window count.
|
||||||
|
bool BulkRangeInFlight(CNodeState* state, int hStart, int hEnd) {
|
||||||
|
if (state == NULL) return false;
|
||||||
|
BOOST_FOREACH(const QueuedBlock& q, state->vBlocksInFlight) {
|
||||||
|
if (q.fBulk && q.pindex != NULL) {
|
||||||
|
int h = q.pindex->GetHeight();
|
||||||
|
if (h >= hStart && h < hEnd) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** Check whether the last unknown block a peer advertized is not yet known. */
|
/** Check whether the last unknown block a peer advertized is not yet known. */
|
||||||
void ProcessBlockAvailability(NodeId nodeid) {
|
void ProcessBlockAvailability(NodeId nodeid) {
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
@@ -485,7 +544,7 @@ namespace {
|
|||||||
|
|
||||||
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
|
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
|
||||||
* at most count entries. */
|
* at most count entries. */
|
||||||
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
|
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller, CBlockIndex** pFrontierStuck = NULL) {
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -562,8 +621,9 @@ namespace {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (waitingfor == -1) {
|
} else if (waitingfor == -1) {
|
||||||
// This is the first already-in-flight block.
|
// This is the first already-in-flight block (the download frontier).
|
||||||
waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first;
|
waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first;
|
||||||
|
if (pFrontierStuck) *pFrontierStuck = pindex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1414,10 +1474,10 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState
|
|||||||
|
|
||||||
// This is and hush_notaries()/gethushseason/getacseason are all consensus code
|
// This is and hush_notaries()/gethushseason/getacseason are all consensus code
|
||||||
int32_t hush_isnotaryvout(char *coinaddr,uint32_t tiptime) {
|
int32_t hush_isnotaryvout(char *coinaddr,uint32_t tiptime) {
|
||||||
bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
bool istush = strncmp(SMART_CHAIN_SYMBOL, "TUSH",4) == 0 ? true : false;
|
bool istush = strncmp(SMART_CHAIN_SYMBOL, "TUSH",4) == 0 ? true : false;
|
||||||
int32_t height = chainActive.LastTip()->GetHeight();
|
int32_t height = chainActive.LastTip()->GetHeight();
|
||||||
int32_t season = (isdragonx || istush) ? gethushseason(height) : getacseason(tiptime);
|
int32_t season = (ishush3 || istush) ? gethushseason(height) : getacseason(tiptime);
|
||||||
fprintf(stderr,"%s: coinaddr=%s season=%d, tiptime=%d\n", __func__, coinaddr, season,tiptime);
|
fprintf(stderr,"%s: coinaddr=%s season=%d, tiptime=%d\n", __func__, coinaddr, season,tiptime);
|
||||||
if ( NOTARY_ADDRESSES[season-1][0][0] == 0 ) {
|
if ( NOTARY_ADDRESSES[season-1][0][0] == 0 ) {
|
||||||
uint8_t pubkeys[64][33];
|
uint8_t pubkeys[64][33];
|
||||||
@@ -1708,8 +1768,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
const uint32_t z2zTransitionStart = 340000 - z2zTransitionWindow;
|
const uint32_t z2zTransitionStart = 340000 - z2zTransitionWindow;
|
||||||
const uint32_t nHeight = chainActive.Height();
|
const uint32_t nHeight = chainActive.Height();
|
||||||
|
|
||||||
// This only applies to DRAGONX, other chains can start off z2z via ac_private=1
|
// This only applies to HUSH3, other chains can start off z2z via ac_private=1
|
||||||
if(isdragonx) {
|
if(ishush3) {
|
||||||
if((nHeight >= z2zTransitionStart) || (nHeight <= 340000)) {
|
if((nHeight >= z2zTransitionStart) || (nHeight <= 340000)) {
|
||||||
// During the z2z transition window, only coinbase tx's as part of blocks are allowed
|
// 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
|
// Theory: We want an empty mempool at our fork block height, and the only way to assure that
|
||||||
@@ -3062,8 +3122,15 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||||||
// move best block pointer to prevout block
|
// move best block pointer to prevout block
|
||||||
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
||||||
|
|
||||||
// DragonX has a fixed 36s blocktime - no blocktime halving needed
|
// If disconnecting a block brings us back before our blocktime halving height, go back
|
||||||
|
// to our original blocktime so our DAA has the correct target for that height
|
||||||
int nHeight = pindex->pprev->GetHeight();
|
int nHeight = pindex->pprev->GetHeight();
|
||||||
|
nFirstHalvingHeight = GetArg("-z2zheight",340000);
|
||||||
|
if (ishush3 && (ASSETCHAINS_BLOCKTIME != 150) && (nHeight < nFirstHalvingHeight)) {
|
||||||
|
LogPrintf("%s: Setting blocktime to 150s at height %d!\n",__func__,nHeight);
|
||||||
|
ASSETCHAINS_BLOCKTIME = 150;
|
||||||
|
hush_changeblocktime();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pfClean) {
|
if (pfClean) {
|
||||||
@@ -3135,19 +3202,23 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
//fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->GetHeight());
|
//fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->GetHeight());
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
const bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
const bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
|
|
||||||
// At startup, DRAGONX doesn't know a block height yet and so we must wait until
|
// At startup, HUSH3 doesn't know a block height yet and so we must wait until
|
||||||
// connecting a block to set our private/blocktime flags, which are height-dependent
|
// connecting a block to set our private/blocktime flags, which are height-dependent
|
||||||
nFirstHalvingHeight = GetArg("-z2zheight",340000);
|
nFirstHalvingHeight = GetArg("-z2zheight",340000);
|
||||||
if(!ASSETCHAINS_PRIVATE && isdragonx) {
|
if(!ASSETCHAINS_PRIVATE && ishush3) {
|
||||||
unsigned int nHeight = pindex->GetHeight();
|
unsigned int nHeight = pindex->GetHeight();
|
||||||
if(nHeight >= nFirstHalvingHeight) {
|
if(nHeight >= nFirstHalvingHeight) {
|
||||||
fprintf(stderr, "%s: Going full z2z at height %d!\n",__func__,pindex->GetHeight());
|
fprintf(stderr, "%s: Going full z2z at height %d!\n",__func__,pindex->GetHeight());
|
||||||
ASSETCHAINS_PRIVATE = 1;
|
ASSETCHAINS_PRIVATE = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// DragonX has a fixed 36s blocktime - no blocktime halving needed
|
if (ishush3 && (ASSETCHAINS_BLOCKTIME != 75) && (chainActive.Height() >= nFirstHalvingHeight)) {
|
||||||
|
LogPrintf("%s: Blocktime halving to 75s at height %d!\n",__func__,pindex->GetHeight());
|
||||||
|
ASSETCHAINS_BLOCKTIME = 75;
|
||||||
|
hush_changeblocktime();
|
||||||
|
}
|
||||||
|
|
||||||
bool fExpensiveChecks = true;
|
bool fExpensiveChecks = true;
|
||||||
if (fCheckpointsEnabled) {
|
if (fCheckpointsEnabled) {
|
||||||
@@ -3743,14 +3814,21 @@ void static UpdateTip(CBlockIndex *pindexNew) {
|
|||||||
mempool.AddTransactionsUpdated(1);
|
mempool.AddTransactionsUpdated(1);
|
||||||
HUSH_NEWBLOCKS++;
|
HUSH_NEWBLOCKS++;
|
||||||
double progress;
|
double progress;
|
||||||
if ( isdragonx ) {
|
if ( ishush3 ) {
|
||||||
progress = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip());
|
progress = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip());
|
||||||
} else {
|
} else {
|
||||||
int32_t longestchain = hush_longestchain();
|
int32_t longestchain = hush_longestchain();
|
||||||
progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0;
|
progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DragonX has a fixed 36s blocktime - no blocktime halving needed
|
nFirstHalvingHeight = GetArg("-z2zheight",340000);
|
||||||
|
if(ishush3) {
|
||||||
|
if (ASSETCHAINS_BLOCKTIME != 75 && (chainActive.Height() >= nFirstHalvingHeight)) {
|
||||||
|
LogPrintf("%s: Blocktime halving to 75s at height %d!\n",__func__,chainActive.Height());
|
||||||
|
ASSETCHAINS_BLOCKTIME = 75;
|
||||||
|
hush_changeblocktime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__,
|
LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__,
|
||||||
chainActive.LastTip()->GetBlockHash().ToString(), chainActive.Height(),
|
chainActive.LastTip()->GetBlockHash().ToString(), chainActive.Height(),
|
||||||
@@ -4170,6 +4248,7 @@ static bool ActivateBestChainStep(bool fSkipdpow, CValidationState &state, CBloc
|
|||||||
return state.DoS(100, error("ActivateBestChainStep(): pindexOldTip->GetHeight().%d > notarizedht %d && pindexFork->GetHeight().%d is < notarizedht %d, so ignore it",(int32_t)pindexOldTip->GetHeight(),notarizedht,(int32_t)pindexFork->GetHeight(),notarizedht),
|
return state.DoS(100, error("ActivateBestChainStep(): pindexOldTip->GetHeight().%d > notarizedht %d && pindexFork->GetHeight().%d is < notarizedht %d, so ignore it",(int32_t)pindexOldTip->GetHeight(),notarizedht,(int32_t)pindexFork->GetHeight(),notarizedht),
|
||||||
REJECT_INVALID, "past-notarized-height");
|
REJECT_INVALID, "past-notarized-height");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks.
|
// - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks.
|
||||||
// - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain,
|
// - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain,
|
||||||
// then pindexFork will be null, and we would need to remove the entire chain including
|
// then pindexFork will be null, and we would need to remove the entire chain including
|
||||||
@@ -4240,6 +4319,36 @@ static bool ActivateBestChainStep(bool fSkipdpow, CValidationState &state, CBloc
|
|||||||
}
|
}
|
||||||
nHeight = nTargetHeight;
|
nHeight = nTargetHeight;
|
||||||
|
|
||||||
|
// Parallel RandomX pre-verification (Stage 4): verify this about-to-be-connected window's
|
||||||
|
// PoW on the worker pool BEFORE the serial connect, so ConnectBlock rarely pays the
|
||||||
|
// ~tens-of-ms light-mode hash. Pure optimization — CheckBlockHeader's inline
|
||||||
|
// CheckRandomXSolution still verifies anything not pre-verified, so consensus is unchanged.
|
||||||
|
// We hold cs_main; key derivation + the disk reads happen here on the main thread, and the
|
||||||
|
// pool workers receive only value-type work items (no cs_main, no chainstate pointers).
|
||||||
|
if (nRandomXVerifyThreads > 0 && rxCheckQueue.IsIdle()) {
|
||||||
|
std::map<std::string, std::vector<CRandomXCheck> > rxGroups; // grouped by RandomX key
|
||||||
|
BOOST_FOREACH(CBlockIndex *pidx, vpindexToConnect) {
|
||||||
|
if (pidx->fRandomXVerified || !RandomXValidationRequired(pidx->GetHeight()))
|
||||||
|
continue;
|
||||||
|
std::string rxKey = GetRandomXKey(pidx->GetHeight());
|
||||||
|
if (rxKey.empty())
|
||||||
|
continue; // can't derive key -> inline fallback
|
||||||
|
CBlock blk;
|
||||||
|
if (!ReadBlockFromDisk(blk, pidx, false))
|
||||||
|
continue; // -> inline fallback
|
||||||
|
if (blk.nSolution.size() != 32) // RANDOMX_HASH_SIZE; wrong size -> inline (will error)
|
||||||
|
continue;
|
||||||
|
rxGroups[rxKey].push_back(CRandomXCheck(rxKey, GetRandomXInput(blk), blk.nSolution.data(), &pidx->fRandomXVerified));
|
||||||
|
}
|
||||||
|
for (std::map<std::string, std::vector<CRandomXCheck> >::iterator it = rxGroups.begin(); it != rxGroups.end(); ++it) {
|
||||||
|
if (!RandomXValidatorPrepareKey(it->first))
|
||||||
|
break; // cache alloc failed -> leave the rest for the inline fallback
|
||||||
|
CCheckQueueControl<CRandomXCheck> control(&rxCheckQueue);
|
||||||
|
control.Add(it->second);
|
||||||
|
control.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Connect new blocks.
|
// Connect new blocks.
|
||||||
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
|
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
|
||||||
if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) {
|
if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) {
|
||||||
@@ -4975,7 +5084,11 @@ bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,
|
|||||||
{
|
{
|
||||||
if ( !CheckEquihashSolution(&blockhdr, Params()) )
|
if ( !CheckEquihashSolution(&blockhdr, Params()) )
|
||||||
return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution");
|
return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution");
|
||||||
if ( !CheckRandomXSolution(&blockhdr, height) )
|
// Skip the inline RandomX recompute only if the parallel pre-verify pool already verified
|
||||||
|
// THIS block (fRandomXVerified set 1:1 on a real hash match). Every other case — pool miss,
|
||||||
|
// straggler, disabled pool, or any pindex==NULL caller (TestBlockValidity/VerifyDB/header
|
||||||
|
// accept) — falls through to the inline check, so consensus is unchanged.
|
||||||
|
if ( !(pindex && pindex->fRandomXVerified) && !CheckRandomXSolution(&blockhdr, height) )
|
||||||
return state.DoS(100, error("CheckBlockHeader(): RandomX solution invalid"),REJECT_INVALID, "invalid-randomx-solution");
|
return state.DoS(100, error("CheckBlockHeader(): RandomX solution invalid"),REJECT_INVALID, "invalid-randomx-solution");
|
||||||
}
|
}
|
||||||
// Check proof of work matches claimed amount
|
// Check proof of work matches claimed amount
|
||||||
@@ -5089,13 +5202,28 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
|
|||||||
|
|
||||||
assert(pindexPrev);
|
assert(pindexPrev);
|
||||||
|
|
||||||
int daaForkHeight = GetArg("-daaforkheight", 450000);
|
// For HUSH3, nBits validation starts above the original DAA fork height (450000).
|
||||||
|
// For DragonX, nBits was never validated before the standalone binary, so the
|
||||||
|
// chain contains blocks with incorrect nBits during the vulnerable window
|
||||||
|
// (diff reset at RANDOMX_VALIDATION height through the attack at ~2879907).
|
||||||
|
// Set daaForkHeight past that window so fresh sync accepts historical blocks.
|
||||||
|
bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX", 7) == 0;
|
||||||
|
int defaultDaaForkHeight = isdragonx ? ASSETCHAINS_RANDOMX_VALIDATION + 62000 : 450000;
|
||||||
|
int daaForkHeight = GetArg("-daaforkheight", defaultDaaForkHeight);
|
||||||
int nHeight = pindexPrev->GetHeight()+1;
|
int nHeight = pindexPrev->GetHeight()+1;
|
||||||
bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
// Check Proof-of-Work difficulty
|
// Check Proof-of-Work difficulty
|
||||||
if (isdragonx) {
|
if (ishush3) {
|
||||||
|
|
||||||
// DragonX has a fixed 36s blocktime - no blocktime halving needed
|
// Difficulty (nBits) relies on the current blocktime of this block
|
||||||
|
if ((ASSETCHAINS_BLOCKTIME != 75) && (nHeight >= nFirstHalvingHeight)) {
|
||||||
|
LogPrintf("%s: Blocktime halving to 75s at height %d!\n",__func__,nHeight);
|
||||||
|
ASSETCHAINS_BLOCKTIME = 75;
|
||||||
|
hush_changeblocktime();
|
||||||
|
}
|
||||||
|
// The change of blocktime from 150s to 75s caused incorrect AWT of 34 blocks instead of 17
|
||||||
|
// caused by the fact that Difficulty Adjustment Algorithms do not take into account blocktime
|
||||||
|
// changing at run-time, from Consensus::Params being a const struct
|
||||||
unsigned int nNextWork = GetNextWorkRequired(pindexPrev, &block, consensusParams);
|
unsigned int nNextWork = GetNextWorkRequired(pindexPrev, &block, consensusParams);
|
||||||
|
|
||||||
if (fDebug) {
|
if (fDebug) {
|
||||||
@@ -5114,6 +5242,26 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check Proof-of-Work difficulty for smart chains (HACs)
|
||||||
|
// Without this check, an attacker can submit blocks with arbitrary nBits
|
||||||
|
// (e.g., powLimit / diff=1) and they will be accepted, allowing the chain
|
||||||
|
// to be flooded with minimum-difficulty blocks.
|
||||||
|
// Only enforce above daaForkHeight to avoid consensus mismatch with early
|
||||||
|
// chain blocks that were mined by a different binary version.
|
||||||
|
if (!ishush3 && SMART_CHAIN_SYMBOL[0] != 0 && nHeight > daaForkHeight) {
|
||||||
|
unsigned int nNextWork = GetNextWorkRequired(pindexPrev, &block, consensusParams);
|
||||||
|
if (fDebug) {
|
||||||
|
LogPrintf("%s: HAC nbits height=%d expected=%lu actual=%lu\n",
|
||||||
|
__func__, nHeight, (unsigned long)nNextWork, (unsigned long)block.nBits);
|
||||||
|
}
|
||||||
|
if (block.nBits != nNextWork) {
|
||||||
|
return state.DoS(100,
|
||||||
|
error("%s: Incorrect diffbits for %s at height %d: expected %lu got %lu",
|
||||||
|
__func__, SMART_CHAIN_SYMBOL, nHeight, (unsigned long)nNextWork, (unsigned long)block.nBits),
|
||||||
|
REJECT_INVALID, "bad-diffbits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check timestamp against prev
|
// Check timestamp against prev
|
||||||
if (ASSETCHAINS_ADAPTIVEPOW <= 0 || nHeight < 30) {
|
if (ASSETCHAINS_ADAPTIVEPOW <= 0 || nHeight < 30) {
|
||||||
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast() )
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast() )
|
||||||
@@ -5933,7 +6081,7 @@ bool static LoadBlockIndexDB()
|
|||||||
|
|
||||||
// Try to detect if we are z2z based on height of blocks on disk
|
// Try to detect if we are z2z based on height of blocks on disk
|
||||||
// This helps to set it correctly on startup before a new block is connected
|
// This helps to set it correctly on startup before a new block is connected
|
||||||
if(isdragonx && chainActive.Height() >= 340000) {
|
if(ishush3 && chainActive.Height() >= 340000) {
|
||||||
LogPrintf("%s: enabled ac_private=1 at height=%d\n", __func__, chainActive.Height());
|
LogPrintf("%s: enabled ac_private=1 at height=%d\n", __func__, chainActive.Height());
|
||||||
ASSETCHAINS_PRIVATE = 1;
|
ASSETCHAINS_PRIVATE = 1;
|
||||||
}
|
}
|
||||||
@@ -5946,7 +6094,7 @@ bool static LoadBlockIndexDB()
|
|||||||
PruneBlockIndexCandidates();
|
PruneBlockIndexCandidates();
|
||||||
|
|
||||||
double progress;
|
double progress;
|
||||||
if ( isdragonx ) {
|
if ( ishush3 ) {
|
||||||
progress = Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.LastTip());
|
progress = Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.LastTip());
|
||||||
} else {
|
} else {
|
||||||
int32_t longestchain = hush_longestchain();
|
int32_t longestchain = hush_longestchain();
|
||||||
@@ -6693,6 +6841,13 @@ void static ProcessGetData(CNode* pfrom)
|
|||||||
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
|
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
|
||||||
|
|
||||||
vector<CInv> vNotFound;
|
vector<CInv> vNotFound;
|
||||||
|
// Serve up to this many blocks per ProcessGetData pass. The old code broke after a SINGLE block,
|
||||||
|
// so a 16-block getdata was dribbled out one block per message-handler tick (~100ms), throttling
|
||||||
|
// block download for every peer fetching from us. Bound the per-pass work (cs_main is held while
|
||||||
|
// reading blocks from disk); any remainder is served on the next pass (the message handler keeps
|
||||||
|
// fSleep=false while vRecvGetData is non-empty, so there is no 100ms park between passes).
|
||||||
|
const unsigned int nMaxBlocksServedPerPass = 16;
|
||||||
|
unsigned int nBlocksServed = 0;
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
@@ -6810,7 +6965,10 @@ void static ProcessGetData(CNode* pfrom)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
|
// Serve a bounded batch of blocks per pass rather than one (see nMaxBlocksServedPerPass
|
||||||
|
// above). The send-buffer gate at the top of the loop still pauses us if the buffer fills;
|
||||||
|
// this counter bounds the cs_main hold for a (possibly malicious) large getdata.
|
||||||
|
if ((inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) && ++nBlocksServed >= nMaxBlocksServedPerPass)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6874,7 +7032,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
CAddress addrFrom;
|
CAddress addrFrom;
|
||||||
uint64_t nNonce = 1;
|
uint64_t nNonce = 1;
|
||||||
int nVersion; // use temporary for version, don't set version number until validated as connected
|
int nVersion; // use temporary for version, don't set version number until validated as connected
|
||||||
const int minVersion = isdragonx ? MIN_HUSH_PEER_PROTO_VERSION : MIN_PEER_PROTO_VERSION;
|
const int minVersion = ishush3 ? MIN_HUSH_PEER_PROTO_VERSION : MIN_PEER_PROTO_VERSION;
|
||||||
vRecv >> nVersion >> pfrom->nServices >> nTime >> addrMe;
|
vRecv >> nVersion >> pfrom->nServices >> nTime >> addrMe;
|
||||||
|
|
||||||
if (nVersion < minVersion)
|
if (nVersion < minVersion)
|
||||||
@@ -7635,6 +7793,118 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CheckBlockIndex();
|
CheckBlockIndex();
|
||||||
|
} else if (strCommand == NetMsgType::GETBLOCKSTREAM) {
|
||||||
|
// Opt-in bulk block streaming (DragonX): a peer asks us to stream a contiguous range of
|
||||||
|
// old blocks as back-to-back BLOCK messages. We only honor it if we advertised the bit
|
||||||
|
// (i.e. were started with -bulkblocksync) and we are not mid-import/reindex.
|
||||||
|
if ((nLocalServices & NODE_BULKBLOCKS) == 0 || fImporting || fReindex)
|
||||||
|
return true;
|
||||||
|
uint256 hashStart; int32_t nStartHeight; uint16_t nCount;
|
||||||
|
vRecv >> hashStart >> nStartHeight >> nCount;
|
||||||
|
|
||||||
|
// Resolve the range under cs_main (cheap, no disk I/O), then read + stream the blocks WITHOUT
|
||||||
|
// holding the lock, so a 128-block / 8 MiB serve never holds cs_main across disk reads (the
|
||||||
|
// analogous ProcessGetData caps per-pass work precisely because it reads under cs_main).
|
||||||
|
std::vector<CBlockIndex*> vSend;
|
||||||
|
int firstH = -1;
|
||||||
|
bool refuse = false;
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
if (nCount == 0 || nCount > BULK_MAX_BLOCKS_PER_REQUEST) {
|
||||||
|
Misbehaving(pfrom->GetId(), 20); // mirrors the getdata MAX_INV_SZ penalty
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Light flood throttle: at most one bulk serve per peer per BULK_MIN_SERVE_INTERVAL_US. On
|
||||||
|
// throttle, send a refusal header so the requester falls back immediately (not after 90s).
|
||||||
|
int64_t nNowServe = GetTimeMicros();
|
||||||
|
CNodeState* sst = State(pfrom->GetId());
|
||||||
|
if (sst != NULL && sst->nLastBulkServeTime > nNowServe - BULK_MIN_SERVE_INTERVAL_US) {
|
||||||
|
pfrom->PushMessage(NetMsgType::BLOCKSTREAM, hashStart, (int32_t)-1, (uint16_t)0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (sst != NULL) sst->nLastBulkServeTime = nNowServe;
|
||||||
|
|
||||||
|
BlockMap::iterator mi = mapBlockIndex.find(hashStart);
|
||||||
|
// Don't flood old blocks while WE are still syncing (unless allowlisted); only serve blocks
|
||||||
|
// on our active chain at the height the requester expects (nStartHeight, tamper-checked).
|
||||||
|
if ((IsInitialBlockDownload() && !pfrom->fAllowlisted) ||
|
||||||
|
mi == mapBlockIndex.end() || !chainActive.Contains(mi->second) ||
|
||||||
|
mi->second->GetHeight() != nStartHeight) {
|
||||||
|
refuse = true;
|
||||||
|
} else {
|
||||||
|
CBlockIndex* pindex = mi->second;
|
||||||
|
firstH = pindex->GetHeight();
|
||||||
|
for (uint16_t i = 0; i < nCount && pindex != NULL; i++, pindex = chainActive.Next(pindex)) {
|
||||||
|
if ((pindex->nStatus & BLOCK_HAVE_DATA) == 0) break; // pruned/missing
|
||||||
|
vSend.push_back(pindex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refuse) {
|
||||||
|
pfrom->PushMessage(NetMsgType::BLOCKSTREAM, hashStart, (int32_t)-1, (uint16_t)0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Read from disk + stream OUTSIDE cs_main. CBlockIndex pointers are stable and block files are
|
||||||
|
// append-only, so reading by pindex without the lock is safe (a concurrent reorg cannot delete
|
||||||
|
// block data, and the requester validates every block against its own headers regardless).
|
||||||
|
uint16_t nSent = 0;
|
||||||
|
size_t cumBytes = 0;
|
||||||
|
BOOST_FOREACH(CBlockIndex* pb, vSend) {
|
||||||
|
if (pfrom->nSendSize >= SendBufferSize()) break; // send-buffer backpressure
|
||||||
|
boost::this_thread::interruption_point();
|
||||||
|
CBlock block;
|
||||||
|
if (!ReadBlockFromDisk(block, pb, 1)) break; // graceful, never assert
|
||||||
|
size_t sz = GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
if (nSent > 0 && cumBytes + sz > BULK_MAX_RESPONSE_BYTES) break; // total byte cap
|
||||||
|
cumBytes += sz;
|
||||||
|
pfrom->PushMessage(NetMsgType::BLOCK, block);
|
||||||
|
nSent++;
|
||||||
|
}
|
||||||
|
// Trailing control header carries the ACTUAL count sent (authoritative), so the requester can
|
||||||
|
// free any undelivered tail immediately rather than waiting for the bulk response timeout.
|
||||||
|
pfrom->PushMessage(NetMsgType::BLOCKSTREAM, hashStart, (int32_t)firstH, nSent);
|
||||||
|
LogPrint("net", "Bulk stream serve: %u/%u blocks from height %d (%lu bytes) peer=%d\n",
|
||||||
|
(unsigned)nSent, (unsigned)nCount, firstH, (unsigned long)cumBytes, pfrom->id);
|
||||||
|
return true;
|
||||||
|
} else if (strCommand == NetMsgType::BLOCKSTREAM) {
|
||||||
|
// Opt-in bulk block streaming (DragonX): the trailing control header for a streamed range. The
|
||||||
|
// blocks themselves arrive as ordinary BLOCK messages (handled below); this reconciles what the
|
||||||
|
// peer actually delivered so the undelivered tail (or a refusal) falls back at once instead of
|
||||||
|
// waiting for the bulk timeout. Service bits are unauthenticated, so we ignore anything that
|
||||||
|
// doesn't match our exact outstanding request.
|
||||||
|
uint256 hashStart; int32_t nFirstHeight; uint16_t nBlocks;
|
||||||
|
vRecv >> hashStart >> nFirstHeight >> nBlocks;
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
CNodeState* state = State(pfrom->GetId());
|
||||||
|
if (state == NULL || !state->fBulkInFlight)
|
||||||
|
return true; // nothing outstanding
|
||||||
|
if (hashStart != state->nBulkHashStart)
|
||||||
|
return true; // header for a different/stale request; ignore
|
||||||
|
if (state->fBulkHeaderSeen)
|
||||||
|
return true; // one-shot: already reconciled this request
|
||||||
|
state->fBulkHeaderSeen = true;
|
||||||
|
|
||||||
|
// nBlocks==0 (refusal) or an over-count => free our whole outstanding range and fall back.
|
||||||
|
// 0 < nBlocks <= count => the peer commits to that many; free only the undelivered tail now.
|
||||||
|
// FreeBulkRangeInFlight scans THIS peer's vBlocksInFlight by literal hash, so it only ever frees
|
||||||
|
// heights still genuinely in flight to this peer (no cross-peer effect, reorg-proof).
|
||||||
|
bool refuse = (nBlocks == 0 || nBlocks > state->nBulkRangeCount);
|
||||||
|
int deliver = refuse ? 0 : (int)nBlocks;
|
||||||
|
FreeBulkRangeInFlight(state, state->nBulkRangeStart + deliver,
|
||||||
|
state->nBulkRangeStart + state->nBulkRangeCount);
|
||||||
|
if (refuse) {
|
||||||
|
state->fBulkInFlight = false;
|
||||||
|
pfrom->nServices &= ~(uint64_t)NODE_BULKBLOCKS; // local hint: don't retry bulk on this peer
|
||||||
|
LogPrint("net", "Bulk stream refused by peer=%d (nBlocks=%u), falling back\n", pfrom->id, (unsigned)nBlocks);
|
||||||
|
} else {
|
||||||
|
// Track only what was promised; fBulkInFlight clears once that prefix fully drains
|
||||||
|
// (range-drain check in SendMessages) or via the timeout fallback.
|
||||||
|
state->nBulkRangeCount = deliver;
|
||||||
|
if (deliver == 0)
|
||||||
|
state->fBulkInFlight = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
} else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
|
} else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
|
||||||
{
|
{
|
||||||
CBlock block;
|
CBlock block;
|
||||||
@@ -8080,24 +8350,108 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|||||||
LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow);
|
LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow);
|
||||||
queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow;
|
queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow;
|
||||||
}
|
}
|
||||||
if (queuedBlock.nTimeDisconnect < nNow) {
|
if (queuedBlock.nTimeDisconnect < nNow && !queuedBlock.fBulk) {
|
||||||
|
// Bulk-stream blocks are exempt: a 128-block batch shares one request time, so the
|
||||||
|
// front() entry could expire before the tail streams in. The bulk response timeout
|
||||||
|
// below frees the range without disconnecting instead.
|
||||||
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id);
|
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id);
|
||||||
pto->fDisconnect = true;
|
pto->fDisconnect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opt-in bulk block streaming (DragonX): manage the outstanding bulk range, then (below)
|
||||||
|
// possibly issue a new one. Clearing fBulkInFlight once the batch has drained below the
|
||||||
|
// normal window re-enables the next bulk request; a never-fully-delivered batch is freed
|
||||||
|
// after BULK_RESPONSE_TIMEOUT_US so the normal per-block path re-fetches it (no disconnect).
|
||||||
|
if (state.fBulkInFlight) {
|
||||||
|
int hEnd = state.nBulkRangeStart + state.nBulkRangeCount;
|
||||||
|
if (!BulkRangeInFlight(&state, state.nBulkRangeStart, hEnd)) {
|
||||||
|
// Whole (possibly shrunk) range received -> done. Completion is keyed on the RANGE
|
||||||
|
// draining, NOT on the global in-flight count crossing the window, so a partially
|
||||||
|
// delivered batch can never leave undelivered heights stuck in-flight.
|
||||||
|
state.fBulkInFlight = false;
|
||||||
|
} else if (state.nBulkSince > 0 && state.nBulkSince < nNow - BULK_RESPONSE_TIMEOUT_US) {
|
||||||
|
// Promised blocks never fully arrived: free the still-in-flight remainder (the normal
|
||||||
|
// per-block path re-fetches it), give up bulk on this unresponsive peer. No disconnect.
|
||||||
|
FreeBulkRangeInFlight(&state, state.nBulkRangeStart, hEnd);
|
||||||
|
state.fBulkInFlight = false;
|
||||||
|
pto->nServices &= ~(uint64_t)NODE_BULKBLOCKS;
|
||||||
|
LogPrint("net", "Bulk stream timeout peer=%d, freed range [%d,%d)\n",
|
||||||
|
pto->id, state.nBulkRangeStart, hEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Message: getdata (blocks)
|
// Message: getdata (blocks)
|
||||||
static uint256 zero;
|
static uint256 zero;
|
||||||
vector<CInv> vGetData;
|
vector<CInv> vGetData;
|
||||||
if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER && !state.fBulkInFlight) {
|
||||||
vector<CBlockIndex*> vToDownload;
|
vector<CBlockIndex*> vToDownload;
|
||||||
NodeId staller = -1;
|
NodeId staller = -1;
|
||||||
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
|
CBlockIndex *pFrontierStuck = NULL;
|
||||||
|
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, &pFrontierStuck);
|
||||||
|
|
||||||
|
// Opt-in bulk block streaming (DragonX): if the first block we need is in the deep,
|
||||||
|
// stable region (>= BULK_TIP_MARGIN below the NETWORK tip) and the peer advertised the
|
||||||
|
// capability, request a whole contiguous range in one shot instead of per-block getdata.
|
||||||
|
// FindNextBlocksToDownload already advanced the cursor past what we have, so
|
||||||
|
// vToDownload.front() is the correct, cursor-managed starting point.
|
||||||
|
bool didBulk = false;
|
||||||
|
if (fBulkBlockSync && (pto->nServices & NODE_BULKBLOCKS) && IsInitialBlockDownload()
|
||||||
|
&& !vToDownload.empty() && state.pindexBestKnownBlock != NULL) {
|
||||||
|
CBlockIndex* pfirst = vToDownload.front();
|
||||||
|
int cursorH = pfirst->GetHeight();
|
||||||
|
int maxH = state.pindexBestKnownBlock->GetHeight() - BULK_TIP_MARGIN;
|
||||||
|
if (cursorH <= maxH) {
|
||||||
|
int want = std::min(maxH - cursorH + 1, (int)BULK_MAX_BLOCKS_PER_REQUEST);
|
||||||
|
uint16_t n = 0;
|
||||||
|
for (int i = 0; i < want; i++) {
|
||||||
|
CBlockIndex* pb = state.pindexBestKnownBlock->GetAncestor(cursorH + i);
|
||||||
|
if (pb == NULL || mapBlocksInFlight.count(pb->GetBlockHash())) break;
|
||||||
|
MarkBlockAsInFlight(pto->GetId(), pb->GetBlockHash(), consensusParams, pb, true);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (n > 0) {
|
||||||
|
pto->PushMessage(NetMsgType::GETBLOCKSTREAM, pfirst->GetBlockHash(), (int32_t)cursorH, n);
|
||||||
|
state.fBulkInFlight = true;
|
||||||
|
state.nBulkSince = nNow;
|
||||||
|
state.nBulkRangeStart = cursorH;
|
||||||
|
state.nBulkRangeCount = n;
|
||||||
|
state.nBulkHashStart = pfirst->GetBlockHash(); // request identity (matched in BLOCKSTREAM)
|
||||||
|
state.fBulkHeaderSeen = false; // arm the one-shot header reconciliation
|
||||||
|
didBulk = true;
|
||||||
|
LogPrint("net", "Requesting bulk stream [%d..%d] (%u blocks) peer=%d\n",
|
||||||
|
cursorH, cursorH + n - 1, (unsigned)n, pto->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!didBulk) {
|
||||||
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
|
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
|
||||||
vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash()));
|
vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash()));
|
||||||
MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
|
MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
|
||||||
LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), pindex->GetHeight(), pto->id);
|
LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), pindex->GetHeight(), pto->id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Frontier reassignment: when this peer has nothing new to fetch because the next-needed
|
||||||
|
// (frontier) block is in flight from another, slow peer and has been stuck beyond a short
|
||||||
|
// threshold, re-request it from THIS (responsive) peer instead of waiting out the long
|
||||||
|
// (~72s) timeout or disconnecting the slow peer. This breaks the head-of-line stall that
|
||||||
|
// throttles IBD when downloading from few, distant peers. Trustless: the block is still
|
||||||
|
// fully validated on arrival - we only change which peer serves it. -blockreassigntimeout
|
||||||
|
// = seconds (0 disables; default 5).
|
||||||
|
static const int64_t nReassignUs = GetArg("-blockreassigntimeout", 5) * 1000000LL;
|
||||||
|
if (nReassignUs > 0 && vToDownload.empty() && pFrontierStuck != NULL &&
|
||||||
|
staller != -1 && staller != pto->GetId()) {
|
||||||
|
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itF =
|
||||||
|
mapBlocksInFlight.find(pFrontierStuck->GetBlockHash());
|
||||||
|
if (itF != mapBlocksInFlight.end() && itF->second.first == staller &&
|
||||||
|
itF->second.second->nTime < nNow - nReassignUs) {
|
||||||
|
uint256 hReassign = pFrontierStuck->GetBlockHash();
|
||||||
|
LogPrint("net", "Reassigning stalled frontier block %s (%d) from peer=%d to peer=%d\n",
|
||||||
|
hReassign.ToString(), pFrontierStuck->GetHeight(), staller, pto->id);
|
||||||
|
MarkBlockAsReceived(hReassign); // free from slow peer (no disconnect)
|
||||||
|
vGetData.push_back(CInv(MSG_BLOCK, hReassign));
|
||||||
|
MarkBlockAsInFlight(pto->GetId(), hReassign, consensusParams, pFrontierStuck); // re-request from this peer
|
||||||
|
}
|
||||||
|
}
|
||||||
if (state.nBlocksInFlight == 0 && staller != -1) {
|
if (state.nBlocksInFlight == 0 && staller != -1) {
|
||||||
if (State(staller)->nStallingSince == 0) {
|
if (State(staller)->nStallingSince == 0) {
|
||||||
State(staller)->nStallingSince = nNow;
|
State(staller)->nStallingSince = nNow;
|
||||||
|
|||||||
36
src/main.h
36
src/main.h
@@ -95,12 +95,37 @@ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
|
|||||||
static const int MAX_SCRIPTCHECK_THREADS = 16;
|
static const int MAX_SCRIPTCHECK_THREADS = 16;
|
||||||
/** -par default (number of script-checking threads, 0 = auto) */
|
/** -par default (number of script-checking threads, 0 = auto) */
|
||||||
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
|
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
|
||||||
/** Number of blocks that can be requested at any given time from a single peer. */
|
/** Number of blocks that can be requested at any given time from a single peer.
|
||||||
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
|
* Runtime-tunable via -maxblocksintransit. The default of 16 caps single-peer IBD
|
||||||
|
* throughput at (window / RTT): on a high-latency peer with tiny (sub-checkpoint)
|
||||||
|
* blocks the transfer is bandwidth-delay-product bound, so a larger window lifts the
|
||||||
|
* ceiling at negligible bandwidth cost. */
|
||||||
|
static const int DEFAULT_MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
|
||||||
|
extern int MAX_BLOCKS_IN_TRANSIT_PER_PEER;
|
||||||
|
/** Opt-in bulk block streaming (DragonX, -bulkblocksync). A single GETBLOCKSTREAM request makes a
|
||||||
|
* peer stream a contiguous range of old blocks as back-to-back BLOCK messages, amortizing the
|
||||||
|
* per-block round-trip over the whole range instead of the MAX_BLOCKS_IN_TRANSIT_PER_PEER window.
|
||||||
|
* OFF by default; negotiated via NODE_BULKBLOCKS; only used during IBD for blocks more than
|
||||||
|
* BULK_TIP_MARGIN below the active tip; never alters the default getdata path. */
|
||||||
|
static const bool DEFAULT_BULKBLOCKSYNC = false;
|
||||||
|
extern bool fBulkBlockSync;
|
||||||
|
/** Only bulk-stream blocks at least this far below the active tip (near-tip uses the normal path). */
|
||||||
|
static const int BULK_TIP_MARGIN = 5000;
|
||||||
|
/** Hard DoS cap: max blocks a single GETBLOCKSTREAM may request/serve. */
|
||||||
|
static const uint16_t BULK_MAX_BLOCKS_PER_REQUEST = 128;
|
||||||
|
/** Hard DoS cap: max total bytes streamed in response to one GETBLOCKSTREAM. */
|
||||||
|
static const size_t BULK_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
||||||
|
/** Requester fallback: if a promised bulk range doesn't fully arrive within this many microseconds,
|
||||||
|
* free the in-flight range so the normal per-block path re-fetches it. */
|
||||||
|
static const int64_t BULK_RESPONSE_TIMEOUT_US = 90 * 1000000LL;
|
||||||
/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */
|
/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */
|
||||||
static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
|
static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
|
||||||
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
|
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
|
||||||
* less than this number, we reached its tip. Changing this value is a protocol upgrade. */
|
* less than this number, we reached its tip. Changing this value is a protocol upgrade: the
|
||||||
|
* continuation logic (main.cpp, "nCount == MAX_HEADERS_RESULTS") and the serve-side limit must
|
||||||
|
* match across the network, so a single node raising it unilaterally would mis-detect a stock
|
||||||
|
* peer's 160-header reply as "tip reached" and stall header sync. Raise only as a coordinated
|
||||||
|
* network upgrade (with a protocol-version bump). */
|
||||||
static const unsigned int MAX_HEADERS_RESULTS = 160;
|
static const unsigned int MAX_HEADERS_RESULTS = 160;
|
||||||
/** Size of the "block download window": how far ahead of our current height do we fetch?
|
/** Size of the "block download window": how far ahead of our current height do we fetch?
|
||||||
* Larger windows tolerate larger download speed differences between peer, but increase the potential
|
* Larger windows tolerate larger download speed differences between peer, but increase the potential
|
||||||
@@ -155,6 +180,7 @@ extern bool fExperimentalMode;
|
|||||||
extern bool fImporting;
|
extern bool fImporting;
|
||||||
extern bool fReindex;
|
extern bool fReindex;
|
||||||
extern int nScriptCheckThreads;
|
extern int nScriptCheckThreads;
|
||||||
|
extern int nRandomXVerifyThreads;
|
||||||
extern bool fTxIndex;
|
extern bool fTxIndex;
|
||||||
extern bool fZindex;
|
extern bool fZindex;
|
||||||
extern bool fIsBareMultisigStd;
|
extern bool fIsBareMultisigStd;
|
||||||
@@ -930,6 +956,10 @@ extern CChain chainActive;
|
|||||||
/** Global variable that points to the active CCoinsView (protected by cs_main) */
|
/** Global variable that points to the active CCoinsView (protected by cs_main) */
|
||||||
extern CCoinsViewCache *pcoinsTip;
|
extern CCoinsViewCache *pcoinsTip;
|
||||||
|
|
||||||
|
/** Global variable that points to the coins database (chainstate/, protected by cs_main). */
|
||||||
|
class CCoinsViewDB;
|
||||||
|
extern CCoinsViewDB *pcoinsdbview;
|
||||||
|
|
||||||
/** Global variable that points to the active block tree (protected by cs_main) */
|
/** Global variable that points to the active block tree (protected by cs_main) */
|
||||||
extern CBlockTreeDB *pblocktree;
|
extern CBlockTreeDB *pblocktree;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX developers
|
|
||||||
// Copyright (c) 2016 The Zcash developers
|
// Copyright (c) 2016 The Zcash 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
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
#include "crypto/common.h"
|
#include "crypto/common.h"
|
||||||
#include "hush/utiltls.h"
|
#include "hush/utiltls.h"
|
||||||
#include <random.h>
|
#include <random.h>
|
||||||
|
#include <random>
|
||||||
|
#include <limits>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#else
|
#else
|
||||||
@@ -2004,7 +2006,7 @@ void ThreadMessageHandler()
|
|||||||
// Randomize the order in which we process messages from/to our peers.
|
// Randomize the order in which we process messages from/to our peers.
|
||||||
// This prevents attacks in which an attacker exploits having multiple
|
// This prevents attacks in which an attacker exploits having multiple
|
||||||
// consecutive connections in the vNodes list.
|
// consecutive connections in the vNodes list.
|
||||||
random_shuffle(vNodesCopy.begin(), vNodesCopy.end(), GetRandInt);
|
std::shuffle(vNodesCopy.begin(), vNodesCopy.end(), std::mt19937(GetRand(std::numeric_limits<uint32_t>::max())));
|
||||||
|
|
||||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||||
{
|
{
|
||||||
@@ -2516,7 +2518,7 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
|||||||
// We always round down, except when we have only 1 connection
|
// We always round down, except when we have only 1 connection
|
||||||
auto newSize = (vNodes.size() / 2) == 0 ? 1 : (vNodes.size() / 2);
|
auto newSize = (vNodes.size() / 2) == 0 ? 1 : (vNodes.size() / 2);
|
||||||
|
|
||||||
random_shuffle( vRelayNodes.begin(), vRelayNodes.end(), GetRandInt );
|
std::shuffle( vRelayNodes.begin(), vRelayNodes.end(), std::mt19937(GetRand(std::numeric_limits<uint32_t>::max())) );
|
||||||
|
|
||||||
vRelayNodes.resize(newSize);
|
vRelayNodes.resize(newSize);
|
||||||
if (HUSH_TESTNODE==1 && vNodes.size() == 0) {
|
if (HUSH_TESTNODE==1 && vNodes.size() == 0) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
constexpr uint64_t CNetAddr::V1_SERIALIZATION_SIZE;
|
constexpr uint64_t CNetAddr::V1_SERIALIZATION_SIZE;
|
||||||
|
constexpr uint64_t CNetAddr::MAX_ADDRV2_SIZE;
|
||||||
|
|
||||||
/** check whether a given address is in a network we can probably connect to */
|
/** check whether a given address is in a network we can probably connect to */
|
||||||
bool CNetAddr::IsReachableNetwork() {
|
bool CNetAddr::IsReachableNetwork() {
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ NotarizationsInBlock ScanBlockNotarizations(const CBlock &block, int nHeight) {
|
|||||||
EvalRef eval;
|
EvalRef eval;
|
||||||
NotarizationsInBlock vNotarizations;
|
NotarizationsInBlock vNotarizations;
|
||||||
int timestamp = block.nTime;
|
int timestamp = block.nTime;
|
||||||
bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX",7) == 0 ? true : false;
|
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
|
|
||||||
// No valid ntz's before this height
|
// No valid ntz's before this height
|
||||||
int minheight = isdragonx ? 365420 : 1;
|
int minheight = ishush3 ? 365420 : 1;
|
||||||
if(isdragonx && (nHeight <= GetArg("-dpow-start-height",minheight))) {
|
if(ishush3 && (nHeight <= GetArg("-dpow-start-height",minheight))) {
|
||||||
return vNotarizations;
|
return vNotarizations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
248
src/pow.cpp
248
src/pow.cpp
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@@ -19,6 +18,7 @@
|
|||||||
* *
|
* *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
|
#include "checkpoints.h"
|
||||||
#include "consensus/upgrades.h"
|
#include "consensus/upgrades.h"
|
||||||
#include "arith_uint256.h"
|
#include "arith_uint256.h"
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
@@ -31,6 +31,8 @@
|
|||||||
#include "sodium.h"
|
#include "sodium.h"
|
||||||
#include "RandomX/src/randomx.h"
|
#include "RandomX/src/randomx.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <boost/thread/shared_mutex.hpp>
|
||||||
|
#include <boost/thread/locks.hpp>
|
||||||
|
|
||||||
#ifdef ENABLE_RUST
|
#ifdef ENABLE_RUST
|
||||||
#include "librustzcash.h"
|
#include "librustzcash.h"
|
||||||
@@ -316,6 +318,16 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
|||||||
if (pindexLast == NULL )
|
if (pindexLast == NULL )
|
||||||
return nProofOfWorkLimit;
|
return nProofOfWorkLimit;
|
||||||
|
|
||||||
|
// DragonX difficulty reset at the RANDOMX_VALIDATION activation height.
|
||||||
|
// The chain transitioned to a new binary at this height and difficulty was
|
||||||
|
// reset to minimum (powLimit). Without this, fresh-syncing nodes compute
|
||||||
|
// a different nBits from GetNextWorkRequired (based on pre-reset blocks)
|
||||||
|
// and reject the on-chain min-diff block, banning all seed nodes.
|
||||||
|
if (ASSETCHAINS_RANDOMX_VALIDATION > 0 && pindexLast->GetHeight() + 1 == ASSETCHAINS_RANDOMX_VALIDATION) {
|
||||||
|
LogPrintf("%s: difficulty reset to powLimit at height %d\n", __func__, ASSETCHAINS_RANDOMX_VALIDATION);
|
||||||
|
return nProofOfWorkLimit;
|
||||||
|
}
|
||||||
|
|
||||||
//{
|
//{
|
||||||
// Comparing to pindexLast->nHeight with >= because this function
|
// Comparing to pindexLast->nHeight with >= because this function
|
||||||
// returns the work required for the block after pindexLast.
|
// returns the work required for the block after pindexLast.
|
||||||
@@ -533,9 +545,9 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
|||||||
int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime;
|
int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime;
|
||||||
LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan);
|
LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan);
|
||||||
|
|
||||||
// DragonX uses params.AveragingWindowTimespan() = nPowAveragingWindow * nPowTargetSpacing = 17 * 36 = 612
|
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||||
// The standalone AveragingWindowTimespan() returns 1275 which is HUSH3-specific (17 * 75s)
|
// If this is HUSH3, use AWT function defined above, else use the one in params
|
||||||
int64_t AWT = params.AveragingWindowTimespan();
|
int64_t AWT = ishush3 ? AveragingWindowTimespan() : params.AveragingWindowTimespan();
|
||||||
|
|
||||||
nActualTimespan = AWT + (nActualTimespan - AWT)/4;
|
nActualTimespan = AWT + (nActualTimespan - AWT)/4;
|
||||||
LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan);
|
LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan);
|
||||||
@@ -695,6 +707,7 @@ static std::mutex cs_randomx_validator;
|
|||||||
static randomx_cache *s_rxCache = nullptr;
|
static randomx_cache *s_rxCache = nullptr;
|
||||||
static randomx_vm *s_rxVM = nullptr;
|
static randomx_vm *s_rxVM = nullptr;
|
||||||
static std::string s_rxCurrentKey; // tracks current key to avoid re-init
|
static std::string s_rxCurrentKey; // tracks current key to avoid re-init
|
||||||
|
static int64_t nTimeRandomX = 0; // cumulative RandomX validation time (us), reported under -debug=bench
|
||||||
|
|
||||||
// Thread-local flag: skip CheckRandomXSolution when the miner is validating its own block
|
// Thread-local flag: skip CheckRandomXSolution when the miner is validating its own block
|
||||||
// The miner already computed the correct RandomX hash — re-verifying with a separate
|
// The miner already computed the correct RandomX hash — re-verifying with a separate
|
||||||
@@ -705,26 +718,70 @@ void SetSkipRandomXValidation(bool skip) { fSkipRandomXValidation = skip; }
|
|||||||
|
|
||||||
CBlockIndex *hush_chainactive(int32_t height);
|
CBlockIndex *hush_chainactive(int32_t height);
|
||||||
|
|
||||||
bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
// Centralized predicate: does a block at this height actually require a RandomX hash check?
|
||||||
|
// Shared by CheckRandomXSolution (inline path) and the parallel pre-verify pool so the two can
|
||||||
|
// never drift. Returns false when the recompute is unnecessary:
|
||||||
|
// - non-RandomX chain, or RandomX validation disabled (activation height < 0)
|
||||||
|
// - below the RandomX activation height (those blocks used Equihash, validated elsewhere)
|
||||||
|
// - during initial on-disk block loading / reindex (HUSH_LOADINGBLOCKS)
|
||||||
|
// - below the last hardcoded checkpoint (chain pinned by checkpoint hash + linkage + work)
|
||||||
|
// Deliberately does NOT consider the thread-local fSkipRandomXValidation (miner self-check) — that
|
||||||
|
// is a property of the calling thread, handled only in the inline CheckRandomXSolution below.
|
||||||
|
bool RandomXValidationRequired(int32_t height)
|
||||||
{
|
{
|
||||||
// Only applies to RandomX chains
|
|
||||||
if (ASSETCHAINS_ALGO != ASSETCHAINS_RANDOMX)
|
if (ASSETCHAINS_ALGO != ASSETCHAINS_RANDOMX)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
// Disabled if activation height is negative
|
|
||||||
if (ASSETCHAINS_RANDOMX_VALIDATION < 0)
|
if (ASSETCHAINS_RANDOMX_VALIDATION < 0)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
// Not yet at activation height
|
|
||||||
if (height < ASSETCHAINS_RANDOMX_VALIDATION)
|
if (height < ASSETCHAINS_RANDOMX_VALIDATION)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
// Do not affect initial block loading
|
|
||||||
extern int32_t HUSH_LOADINGBLOCKS;
|
extern int32_t HUSH_LOADINGBLOCKS;
|
||||||
if (HUSH_LOADINGBLOCKS != 0)
|
if (HUSH_LOADINGBLOCKS != 0)
|
||||||
|
return false;
|
||||||
|
extern bool fCheckpointsEnabled;
|
||||||
|
if (fCheckpointsEnabled && height < Checkpoints::GetTotalBlocksEstimate(Params().Checkpoints()))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize the RandomX hash input: the block header without nSolution (but with nNonce). Used by
|
||||||
|
// both the inline CheckRandomXSolution and the parallel pre-verify pool, so the bytes are identical.
|
||||||
|
std::vector<unsigned char> GetRandomXInput(const CBlockHeader& block)
|
||||||
|
{
|
||||||
|
CRandomXInput rxInput(block);
|
||||||
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss << rxInput;
|
||||||
|
return std::vector<unsigned char>(ss.begin(), ss.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derive the RandomX key string for a block at `height`. Below interval+lag it is the chain-params
|
||||||
|
// initial key; otherwise the block hash at the key-rotation height. MUST be called under cs_main
|
||||||
|
// (reads chainActive via hush_chainactive). Returns empty if the key-height block is unavailable.
|
||||||
|
std::string GetRandomXKey(int32_t height)
|
||||||
|
{
|
||||||
|
static int randomxInterval = GetRandomXInterval();
|
||||||
|
static int randomxBlockLag = GetRandomXBlockLag();
|
||||||
|
if (height < randomxInterval + randomxBlockLag) {
|
||||||
|
char initialKey[82];
|
||||||
|
snprintf(initialKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT);
|
||||||
|
return std::string(initialKey, strlen(initialKey));
|
||||||
|
}
|
||||||
|
int keyHeight = ((height - randomxBlockLag) / randomxInterval) * randomxInterval;
|
||||||
|
CBlockIndex *pKeyIndex = hush_chainactive(keyHeight);
|
||||||
|
if (pKeyIndex == nullptr)
|
||||||
|
return std::string();
|
||||||
|
uint256 blockKey = pKeyIndex->GetBlockHash();
|
||||||
|
return std::string((const char*)&blockKey, sizeof(blockKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
||||||
|
{
|
||||||
|
// Centralized height gate (shared with the parallel pre-verify pool, Stage 0).
|
||||||
|
if (!RandomXValidationRequired(height))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Skip when miner is validating its own block via TestBlockValidity
|
// Skip when the miner is validating its own freshly-mined block via TestBlockValidity
|
||||||
|
// (thread-local; never set on the connect thread or the pre-verify worker threads).
|
||||||
if (fSkipRandomXValidation)
|
if (fSkipRandomXValidation)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -734,47 +791,44 @@ bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
|||||||
pblock->nSolution.size(), RANDOMX_HASH_SIZE, height);
|
pblock->nSolution.size(), RANDOMX_HASH_SIZE, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int randomxInterval = GetRandomXInterval();
|
// Derive the key (shared helper) and serialize the input (identical bytes to the pool path).
|
||||||
static int randomxBlockLag = GetRandomXBlockLag();
|
std::string rxKey = GetRandomXKey(height);
|
||||||
|
if (rxKey.empty())
|
||||||
// Determine the correct RandomX key for this height
|
return error("CheckRandomXSolution(): cannot derive RandomX key for height %d", height);
|
||||||
char initialKey[82];
|
std::vector<unsigned char> ssInput = GetRandomXInput(*pblock);
|
||||||
snprintf(initialKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT);
|
|
||||||
|
|
||||||
std::string rxKey;
|
|
||||||
if (height < randomxInterval + randomxBlockLag) {
|
|
||||||
// Use initial key derived from chain params
|
|
||||||
rxKey = std::string(initialKey, strlen(initialKey));
|
|
||||||
} else {
|
|
||||||
// Use block hash at the key height
|
|
||||||
int keyHeight = ((height - randomxBlockLag) / randomxInterval) * randomxInterval;
|
|
||||||
CBlockIndex *pKeyIndex = hush_chainactive(keyHeight);
|
|
||||||
if (pKeyIndex == nullptr) {
|
|
||||||
return error("CheckRandomXSolution(): cannot get block index at key height %d for block %d", keyHeight, height);
|
|
||||||
}
|
|
||||||
uint256 blockKey = pKeyIndex->GetBlockHash();
|
|
||||||
rxKey = std::string((const char*)&blockKey, sizeof(blockKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize the block header without nSolution (but with nNonce) as RandomX input
|
|
||||||
CRandomXInput rxInput(*pblock);
|
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
|
||||||
ss << rxInput;
|
|
||||||
|
|
||||||
char computedHash[RANDOMX_HASH_SIZE];
|
char computedHash[RANDOMX_HASH_SIZE];
|
||||||
|
|
||||||
|
// Measurement (Track 1): isolate RandomX verification cost during IBD. The
|
||||||
|
// expensive parts are the per-key cache (re)init (~every GetRandomXInterval()
|
||||||
|
// blocks) and the hash computation itself; both happen under the lock below.
|
||||||
|
int64_t nTimeRxStart = GetTimeMicros();
|
||||||
|
bool fKeyInit = false;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(cs_randomx_validator);
|
std::lock_guard<std::mutex> lock(cs_randomx_validator);
|
||||||
|
|
||||||
// Initialize cache + VM if needed, or re-init if key changed
|
// Initialize cache + VM if needed, or re-init if key changed
|
||||||
if (s_rxCache == nullptr) {
|
if (s_rxCache == nullptr) {
|
||||||
randomx_flags flags = randomx_get_flags();
|
randomx_flags flags = randomx_get_flags();
|
||||||
s_rxCache = randomx_alloc_cache(flags);
|
// Try large pages for the 256MB validator cache: fewer TLB misses → ~15-30% faster
|
||||||
|
// light-mode validation where the OS has hugepages configured. Falls back transparently
|
||||||
|
// when unavailable, exactly as the miner does (miner.cpp:1097). Page size does not affect
|
||||||
|
// the computed hash, so this is consensus-neutral.
|
||||||
|
bool fLargePages = true;
|
||||||
|
s_rxCache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES);
|
||||||
|
if (s_rxCache == nullptr) {
|
||||||
|
fLargePages = false;
|
||||||
|
s_rxCache = randomx_alloc_cache(flags);
|
||||||
|
}
|
||||||
if (s_rxCache == nullptr) {
|
if (s_rxCache == nullptr) {
|
||||||
return error("CheckRandomXSolution(): failed to allocate RandomX cache");
|
return error("CheckRandomXSolution(): failed to allocate RandomX cache");
|
||||||
}
|
}
|
||||||
|
// Confirm the fast paths are active (JIT off would be ~9x slower; see randomx-benchmark).
|
||||||
|
LogPrint("bench", "CheckRandomXSolution: RandomX flags=0x%x JIT=%d HARD_AES=%d largePages=%d\n",
|
||||||
|
(unsigned int)flags, !!(flags & RANDOMX_FLAG_JIT), !!(flags & RANDOMX_FLAG_HARD_AES), (int)fLargePages);
|
||||||
randomx_init_cache(s_rxCache, rxKey.data(), rxKey.size());
|
randomx_init_cache(s_rxCache, rxKey.data(), rxKey.size());
|
||||||
s_rxCurrentKey = rxKey;
|
s_rxCurrentKey = rxKey;
|
||||||
|
fKeyInit = true;
|
||||||
s_rxVM = randomx_create_vm(flags, s_rxCache, nullptr);
|
s_rxVM = randomx_create_vm(flags, s_rxCache, nullptr);
|
||||||
if (s_rxVM == nullptr) {
|
if (s_rxVM == nullptr) {
|
||||||
randomx_release_cache(s_rxCache);
|
randomx_release_cache(s_rxCache);
|
||||||
@@ -784,11 +838,17 @@ bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
|||||||
} else if (s_rxCurrentKey != rxKey) {
|
} else if (s_rxCurrentKey != rxKey) {
|
||||||
randomx_init_cache(s_rxCache, rxKey.data(), rxKey.size());
|
randomx_init_cache(s_rxCache, rxKey.data(), rxKey.size());
|
||||||
s_rxCurrentKey = rxKey;
|
s_rxCurrentKey = rxKey;
|
||||||
|
fKeyInit = true;
|
||||||
randomx_vm_set_cache(s_rxVM, s_rxCache);
|
randomx_vm_set_cache(s_rxVM, s_rxCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
randomx_calculate_hash(s_rxVM, &ss[0], ss.size(), computedHash);
|
randomx_calculate_hash(s_rxVM, ssInput.data(), ssInput.size(), computedHash);
|
||||||
}
|
}
|
||||||
|
int64_t nTimeRxEnd = GetTimeMicros();
|
||||||
|
nTimeRandomX += nTimeRxEnd - nTimeRxStart;
|
||||||
|
LogPrint("bench", " - RandomX verify ht=%d: %.2fms%s [%.2fs]\n",
|
||||||
|
height, (nTimeRxEnd - nTimeRxStart) * 0.001,
|
||||||
|
fKeyInit ? " (key-init)" : "", nTimeRandomX * 0.000001);
|
||||||
|
|
||||||
// Compare computed hash against nSolution
|
// Compare computed hash against nSolution
|
||||||
if (memcmp(computedHash, pblock->nSolution.data(), RANDOMX_HASH_SIZE) != 0) {
|
if (memcmp(computedHash, pblock->nSolution.data(), RANDOMX_HASH_SIZE) != 0) {
|
||||||
@@ -805,7 +865,7 @@ bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
|||||||
fprintf(stderr, " computed : %s\n", computedHex.c_str());
|
fprintf(stderr, " computed : %s\n", computedHex.c_str());
|
||||||
fprintf(stderr, " nSolution: %s\n", solutionHex.c_str());
|
fprintf(stderr, " nSolution: %s\n", solutionHex.c_str());
|
||||||
fprintf(stderr, " rxKey size=%lu, input size=%lu, nNonce=%s\n",
|
fprintf(stderr, " rxKey size=%lu, input size=%lu, nNonce=%s\n",
|
||||||
rxKey.size(), ss.size(), pblock->nNonce.ToString().c_str());
|
rxKey.size(), ssInput.size(), pblock->nNonce.ToString().c_str());
|
||||||
fprintf(stderr, " nSolution.size()=%lu, RANDOMX_HASH_SIZE=%d\n",
|
fprintf(stderr, " nSolution.size()=%lu, RANDOMX_HASH_SIZE=%d\n",
|
||||||
pblock->nSolution.size(), RANDOMX_HASH_SIZE);
|
pblock->nSolution.size(), RANDOMX_HASH_SIZE);
|
||||||
// Also log to debug.log
|
// Also log to debug.log
|
||||||
@@ -813,7 +873,7 @@ bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
|||||||
LogPrintf(" computed : %s\n", computedHex);
|
LogPrintf(" computed : %s\n", computedHex);
|
||||||
LogPrintf(" nSolution: %s\n", solutionHex);
|
LogPrintf(" nSolution: %s\n", solutionHex);
|
||||||
LogPrintf(" rxKey size=%lu, input size=%lu, nNonce=%s\n",
|
LogPrintf(" rxKey size=%lu, input size=%lu, nNonce=%s\n",
|
||||||
rxKey.size(), ss.size(), pblock->nNonce.ToString());
|
rxKey.size(), ssInput.size(), pblock->nNonce.ToString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,6 +881,88 @@ bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================================
|
||||||
|
// Parallel RandomX pre-verification pool (Stage 2).
|
||||||
|
// One shared light-mode cache (holding a single key at a time) + per-thread VMs, mirroring the
|
||||||
|
// miner's RandomXDatasetManager pattern (miner.cpp). The connect thread (ActivateBestChainStep)
|
||||||
|
// loads the cache key for a same-key group of about-to-be-connected blocks, dispatches them to
|
||||||
|
// this pool, and barrier-waits; each worker hashes on its own VM (sharing the read-only cache)
|
||||||
|
// and, on a match, sets the block's transient fRandomXVerified flag so the inline check in
|
||||||
|
// CheckBlockHeader can be skipped. The inline path remains the consensus authority for anything
|
||||||
|
// not pre-verified, so the pool can only ever flip false->true on a real hash match.
|
||||||
|
static boost::shared_mutex g_rxvMutex; // shared = hashing; exclusive = cache (re)init
|
||||||
|
static randomx_cache* g_rxvCache = nullptr; // shared, read-only during hashing
|
||||||
|
static std::string g_rxvKey; // key currently loaded into g_rxvCache
|
||||||
|
static randomx_flags g_rxvFlags;
|
||||||
|
static thread_local randomx_vm* tls_rxvVM = nullptr;
|
||||||
|
static thread_local std::string tls_rxvVMKey;
|
||||||
|
|
||||||
|
CCheckQueue<CRandomXCheck> rxCheckQueue(1); // batch size 1: each item is ~tens of ms
|
||||||
|
|
||||||
|
bool RandomXValidatorPrepareKey(const std::string& rxKey)
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::shared_mutex> lock(g_rxvMutex);
|
||||||
|
if (g_rxvCache == nullptr) {
|
||||||
|
g_rxvFlags = randomx_get_flags();
|
||||||
|
g_rxvCache = randomx_alloc_cache(g_rxvFlags | RANDOMX_FLAG_LARGE_PAGES);
|
||||||
|
if (g_rxvCache == nullptr)
|
||||||
|
g_rxvCache = randomx_alloc_cache(g_rxvFlags);
|
||||||
|
if (g_rxvCache == nullptr) {
|
||||||
|
LogPrintf("RandomXValidatorPrepareKey: cache alloc failed; parallel pre-verify disabled\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
randomx_init_cache(g_rxvCache, rxKey.data(), rxKey.size());
|
||||||
|
g_rxvKey = rxKey;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (g_rxvKey != rxKey) {
|
||||||
|
randomx_init_cache(g_rxvCache, rxKey.data(), rxKey.size());
|
||||||
|
g_rxvKey = rxKey;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CRandomXCheck::operator()()
|
||||||
|
{
|
||||||
|
boost::shared_lock<boost::shared_mutex> lock(g_rxvMutex);
|
||||||
|
// The connect thread set the shared cache to one key before dispatching this group. If this
|
||||||
|
// item's key doesn't match (e.g. a key-rotation straggler) or the cache is unavailable, skip it
|
||||||
|
// and leave *presult false — the inline CheckRandomXSolution will verify it.
|
||||||
|
if (g_rxvCache == nullptr || g_rxvKey != rxKey)
|
||||||
|
return true;
|
||||||
|
if (tls_rxvVM == nullptr) {
|
||||||
|
tls_rxvVM = randomx_create_vm(g_rxvFlags, g_rxvCache, nullptr);
|
||||||
|
if (tls_rxvVM == nullptr)
|
||||||
|
return true; // cannot verify here -> inline fallback
|
||||||
|
tls_rxvVMKey = g_rxvKey;
|
||||||
|
} else if (tls_rxvVMKey != g_rxvKey) {
|
||||||
|
// Cache was re-initialized to a new key since this VM last ran; rebind.
|
||||||
|
randomx_vm_set_cache(tls_rxvVM, g_rxvCache);
|
||||||
|
tls_rxvVMKey = g_rxvKey;
|
||||||
|
}
|
||||||
|
unsigned char h[RANDOMX_HASH_SIZE];
|
||||||
|
randomx_calculate_hash(tls_rxvVM, input.data(), input.size(), h);
|
||||||
|
if (memcmp(h, expected, RANDOMX_HASH_SIZE) == 0 && presult != nullptr)
|
||||||
|
*presult = true;
|
||||||
|
return true; // ALWAYS true: never short-circuit the queue; per-block result is in *presult
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadRandomXVerify()
|
||||||
|
{
|
||||||
|
RenameThread("hush-rxverify");
|
||||||
|
rxCheckQueue.Thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomXValidatorShutdown()
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::shared_mutex> lock(g_rxvMutex);
|
||||||
|
// Per-thread VMs are intentionally leaked (process exiting); release the shared cache.
|
||||||
|
if (g_rxvCache != nullptr) {
|
||||||
|
randomx_release_cache(g_rxvCache);
|
||||||
|
g_rxvCache = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int32_t hush_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
|
int32_t hush_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
|
||||||
int32_t hush_currentheight();
|
int32_t hush_currentheight();
|
||||||
void hush_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height);
|
void hush_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height);
|
||||||
@@ -864,10 +1006,17 @@ bool CheckProofOfWork(const CBlockHeader &blkHeader, uint8_t *pubkey33, int32_t
|
|||||||
// Check proof of work matches claimed amount
|
// Check proof of work matches claimed amount
|
||||||
if ( UintToArith256(hash = blkHeader.GetHash()) > bnTarget )
|
if ( UintToArith256(hash = blkHeader.GetHash()) > bnTarget )
|
||||||
{
|
{
|
||||||
if ( HUSH_LOADINGBLOCKS != 0 )
|
// During initial block loading/sync, skip PoW validation for blocks
|
||||||
return true;
|
// before RandomX validation height. After activation, always validate
|
||||||
|
// to prevent injection of blocks with fake PoW.
|
||||||
|
if ( HUSH_LOADINGBLOCKS != 0 ) {
|
||||||
|
if (ASSETCHAINS_ALGO == ASSETCHAINS_RANDOMX && ASSETCHAINS_RANDOMX_VALIDATION > 0 && height >= ASSETCHAINS_RANDOMX_VALIDATION) {
|
||||||
|
// Fall through to reject the block — do NOT skip validation after activation
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if ( SMART_CHAIN_SYMBOL[0] != 0 || height > 792000 )
|
if ( SMART_CHAIN_SYMBOL[0] != 0 || height > 792000 )
|
||||||
{
|
{
|
||||||
if ( Params().NetworkIDString() != "regtest" )
|
if ( Params().NetworkIDString() != "regtest" )
|
||||||
@@ -887,7 +1036,6 @@ bool CheckProofOfWork(const CBlockHeader &blkHeader, uint8_t *pubkey33, int32_t
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
/*for (i=31; i>=0; i--)
|
/*for (i=31; i>=0; i--)
|
||||||
fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
|
fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
|
||||||
|
|||||||
54
src/pow.h
54
src/pow.h
@@ -21,8 +21,13 @@
|
|||||||
#define HUSH_POW_H
|
#define HUSH_POW_H
|
||||||
|
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
|
#include "checkqueue.h"
|
||||||
#include "consensus/params.h"
|
#include "consensus/params.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CBlockHeader;
|
class CBlockHeader;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
@@ -41,6 +46,55 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams&);
|
|||||||
/** Check whether a block header contains a valid RandomX solution */
|
/** Check whether a block header contains a valid RandomX solution */
|
||||||
bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height);
|
bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height);
|
||||||
|
|
||||||
|
/** Whether a block at this height requires a RandomX hash check (shared gate used by both the
|
||||||
|
* inline CheckRandomXSolution and the parallel pre-verification pool). */
|
||||||
|
bool RandomXValidationRequired(int32_t height);
|
||||||
|
|
||||||
|
/** Serialize the RandomX hash input (block header without nSolution) — identical bytes to the
|
||||||
|
* inline CheckRandomXSolution path, so the parallel pool computes the same hash. */
|
||||||
|
std::vector<unsigned char> GetRandomXInput(const CBlockHeader& block);
|
||||||
|
|
||||||
|
/** Derive the RandomX key string for a block at `height`. MUST be called under cs_main (reads
|
||||||
|
* chainActive). Returns empty string if the key-height block is unavailable. */
|
||||||
|
std::string GetRandomXKey(int32_t height);
|
||||||
|
|
||||||
|
/** A single RandomX pre-verification work item for the parallel validator pool. Pure value type
|
||||||
|
* (no chainstate pointers) so workers need no cs_main. On a hash match it sets *presult=true; on
|
||||||
|
* any failure it leaves *presult untouched — the inline CheckRandomXSolution remains the
|
||||||
|
* consensus authority and re-verifies anything not pre-verified. operator() ALWAYS returns true,
|
||||||
|
* so one block's failure never short-circuits the rest of the CCheckQueue batch. */
|
||||||
|
class CRandomXCheck
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string rxKey; // RandomX key for this block's height
|
||||||
|
std::vector<unsigned char> input; // serialized CRandomXInput(header)
|
||||||
|
unsigned char expected[32]; // block.nSolution (claimed RandomX hash)
|
||||||
|
bool* presult; // -> pindex->fRandomXVerified (set true only on a hash match)
|
||||||
|
public:
|
||||||
|
CRandomXCheck() : presult(nullptr) { memset(expected, 0, sizeof(expected)); }
|
||||||
|
CRandomXCheck(const std::string& keyIn, std::vector<unsigned char> inputIn,
|
||||||
|
const unsigned char* expectedIn, bool* presultIn)
|
||||||
|
: rxKey(keyIn), input(std::move(inputIn)), presult(presultIn)
|
||||||
|
{ memcpy(expected, expectedIn, sizeof(expected)); }
|
||||||
|
bool operator()();
|
||||||
|
void swap(CRandomXCheck& c) {
|
||||||
|
rxKey.swap(c.rxKey);
|
||||||
|
input.swap(c.input);
|
||||||
|
std::swap(presult, c.presult);
|
||||||
|
for (int i = 0; i < 32; i++) std::swap(expected[i], c.expected[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The RandomX pre-verification check queue (parallel pool). */
|
||||||
|
extern CCheckQueue<CRandomXCheck> rxCheckQueue;
|
||||||
|
/** Worker entry point (spawn N at startup, mirrors ThreadScriptCheck). */
|
||||||
|
void ThreadRandomXVerify();
|
||||||
|
/** Load `rxKey` into the shared validator cache (alloc on first use); call before dispatching a
|
||||||
|
* same-key group of checks. Returns false on allocation failure. */
|
||||||
|
bool RandomXValidatorPrepareKey(const std::string& rxKey);
|
||||||
|
/** Release the shared validator cache at shutdown. */
|
||||||
|
void RandomXValidatorShutdown();
|
||||||
|
|
||||||
/** Set thread-local flag to skip RandomX validation (used by miner during TestBlockValidity) */
|
/** Set thread-local flag to skip RandomX validation (used by miner during TestBlockValidity) */
|
||||||
void SetSkipRandomXValidation(bool skip);
|
void SetSkipRandomXValidation(bool skip);
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ const char *GETNSPV="getnSPV"; //used
|
|||||||
const char *NSPV="nSPV"; //used
|
const char *NSPV="nSPV"; //used
|
||||||
const char *ALERT="alert"; //used
|
const char *ALERT="alert"; //used
|
||||||
const char *REJECT="reject"; //used
|
const char *REJECT="reject"; //used
|
||||||
|
const char *GETBLOCKSTREAM="getblockstrm"; // 12 chars (COMMAND_SIZE max); "getblockstream" would truncate
|
||||||
|
const char *BLOCKSTREAM="blockstream";
|
||||||
} // namespace NetMsgType
|
} // namespace NetMsgType
|
||||||
|
|
||||||
/** All known message types. Keep this in the same order as the list of
|
/** All known message types. Keep this in the same order as the list of
|
||||||
@@ -119,6 +121,8 @@ const static std::string allNetMessageTypes[] = {
|
|||||||
NetMsgType::NSPV,
|
NetMsgType::NSPV,
|
||||||
NetMsgType::ALERT,
|
NetMsgType::ALERT,
|
||||||
NetMsgType::REJECT,
|
NetMsgType::REJECT,
|
||||||
|
NetMsgType::GETBLOCKSTREAM,
|
||||||
|
NetMsgType::BLOCKSTREAM,
|
||||||
};
|
};
|
||||||
|
|
||||||
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
|
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
|
||||||
|
|||||||
@@ -285,6 +285,10 @@ extern const char* GETNSPV;
|
|||||||
extern const char* NSPV;
|
extern const char* NSPV;
|
||||||
extern const char* ALERT;
|
extern const char* ALERT;
|
||||||
extern const char* REJECT;
|
extern const char* REJECT;
|
||||||
|
/** Opt-in bulk block streaming (DragonX): request a contiguous range of old blocks. */
|
||||||
|
extern const char* GETBLOCKSTREAM;
|
||||||
|
/** Opt-in bulk block streaming (DragonX): control header preceding a streamed block range. */
|
||||||
|
extern const char* BLOCKSTREAM;
|
||||||
}; // namespace NetMsgType
|
}; // namespace NetMsgType
|
||||||
|
|
||||||
/* Get a vector of all valid message types (see above) */
|
/* Get a vector of all valid message types (see above) */
|
||||||
@@ -304,6 +308,9 @@ enum ServiceFlags : uint64_t {
|
|||||||
NODE_NSPV = (1 << 30),
|
NODE_NSPV = (1 << 30),
|
||||||
NODE_ADDRINDEX = (1 << 29),
|
NODE_ADDRINDEX = (1 << 29),
|
||||||
NODE_SPENTINDEX = (1 << 28),
|
NODE_SPENTINDEX = (1 << 28),
|
||||||
|
// Opt-in bulk block streaming (DragonX). Unauthenticated advertisement; serve/request
|
||||||
|
// handlers validate every block regardless, so robustness against false advertisement holds.
|
||||||
|
NODE_BULKBLOCKS = (1 << 27),
|
||||||
|
|
||||||
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
|
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
|
||||||
// isn't getting used, or one not being used much, and notify the
|
// isn't getting used, or one not being used much, and notify the
|
||||||
|
|||||||
@@ -30,7 +30,9 @@
|
|||||||
#include "rpc/server.h"
|
#include "rpc/server.h"
|
||||||
#include "streams.h"
|
#include "streams.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
|
#include "txdb.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/script_error.h"
|
#include "script/script_error.h"
|
||||||
#include "script/sign.h"
|
#include "script/sign.h"
|
||||||
@@ -322,6 +324,15 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
|
|||||||
result.push_back(Pair("anchor", blockindex->hashFinalSproutRoot.GetHex()));
|
result.push_back(Pair("anchor", blockindex->hashFinalSproutRoot.GetHex()));
|
||||||
result.push_back(Pair("blocktype", "mined"));
|
result.push_back(Pair("blocktype", "mined"));
|
||||||
|
|
||||||
|
// Report block subsidy and fees separately so explorers don't have to
|
||||||
|
// reimplement the reward schedule to display them.
|
||||||
|
CAmount nSubsidy = GetBlockSubsidy(blockindex->GetHeight(), Params().GetConsensus());
|
||||||
|
CAmount nCoinbase = block.vtx[0].GetValueOut();
|
||||||
|
CAmount nFees = nCoinbase - nSubsidy;
|
||||||
|
if (nFees < 0) nFees = 0; // block 1 has premine, avoid negative
|
||||||
|
result.push_back(Pair("subsidy", ValueFromAmount(nSubsidy)));
|
||||||
|
result.push_back(Pair("fees", ValueFromAmount(nFees)));
|
||||||
|
|
||||||
UniValue valuePools(UniValue::VARR);
|
UniValue valuePools(UniValue::VARR);
|
||||||
valuePools.push_back(ValuePoolDesc("sapling", blockindex->nChainSaplingValue, blockindex->nSaplingValue));
|
valuePools.push_back(ValuePoolDesc("sapling", blockindex->nChainSaplingValue, blockindex->nSaplingValue));
|
||||||
result.push_back(Pair("valuePools", valuePools));
|
result.push_back(Pair("valuePools", valuePools));
|
||||||
@@ -851,6 +862,7 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp, const CPubKey& mypk
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UniValue getblockmerkletree(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
UniValue getblockmerkletree(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() != 1 )
|
if (fHelp || params.size() != 1 )
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2010 Satoshi Nakamoto
|
// Copyright (c) 2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -253,12 +253,12 @@ UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString()));
|
obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString()));
|
||||||
if ( HUSH_NSPV_FULLNODE )
|
if ( HUSH_NSPV_FULLNODE )
|
||||||
{
|
{
|
||||||
txid_height = notarizedtxid_height( (char *)"DRAGONX" ,(char *)notarized_desttxid.ToString().c_str(),&hushnotarized_height);
|
txid_height = notarizedtxid_height( (char *)"HUSH3" ,(char *)notarized_desttxid.ToString().c_str(),&hushnotarized_height);
|
||||||
if ( txid_height > 0 )
|
if ( txid_height > 0 )
|
||||||
obj.push_back(Pair("notarizedtxid_height", txid_height));
|
obj.push_back(Pair("notarizedtxid_height", txid_height));
|
||||||
else obj.push_back(Pair("notarizedtxid_height", "mempool"));
|
else obj.push_back(Pair("notarizedtxid_height", "mempool"));
|
||||||
if ( SMART_CHAIN_SYMBOL[0] != 0 ) {
|
if ( SMART_CHAIN_SYMBOL[0] != 0 ) {
|
||||||
obj.push_back(Pair("DRAGONXnotarized_height", hushnotarized_height));
|
obj.push_back(Pair("HUSHnotarized_height", hushnotarized_height));
|
||||||
}
|
}
|
||||||
obj.push_back(Pair("notarized_confirms", txid_height < hushnotarized_height ? (hushnotarized_height - txid_height + 1) : 0));
|
obj.push_back(Pair("notarized_confirms", txid_height < hushnotarized_height ? (hushnotarized_height - txid_height + 1) : 0));
|
||||||
//fprintf(stderr,"after notarized_confirms %u\n",(uint32_t)time(NULL));
|
//fprintf(stderr,"after notarized_confirms %u\n",(uint32_t)time(NULL));
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -276,8 +276,8 @@ UniValue stop(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
// Shutdown will take long enough that the response should get back
|
// Shutdown will take long enough that the response should get back
|
||||||
StartShutdown();
|
StartShutdown();
|
||||||
|
|
||||||
if ((strncmp(SMART_CHAIN_SYMBOL, "DRAGONX", 7) == 0) ) {
|
if ((strncmp(SMART_CHAIN_SYMBOL, "HUSH3", 5) == 0) ) {
|
||||||
sprintf(buf,"DragonX server stopping, for now...");
|
sprintf(buf,"Hush server stopping, for now...");
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf,"%s server stopping...",SMART_CHAIN_SYMBOL);
|
sprintf(buf,"%s server stopping...",SMART_CHAIN_SYMBOL);
|
||||||
}
|
}
|
||||||
@@ -474,6 +474,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "wallet", "z_listaddresses", &z_listaddresses, true },
|
{ "wallet", "z_listaddresses", &z_listaddresses, true },
|
||||||
{ "wallet", "z_listnullifiers", &z_listnullifiers, true },
|
{ "wallet", "z_listnullifiers", &z_listnullifiers, true },
|
||||||
{ "wallet", "z_exportkey", &z_exportkey, true },
|
{ "wallet", "z_exportkey", &z_exportkey, true },
|
||||||
|
{ "wallet", "z_exportmnemonic", &z_exportmnemonic, true },
|
||||||
{ "wallet", "z_importkey", &z_importkey, true },
|
{ "wallet", "z_importkey", &z_importkey, true },
|
||||||
{ "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
|
{ "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
|
||||||
{ "wallet", "z_importviewingkey", &z_importviewingkey, true },
|
{ "wallet", "z_importviewingkey", &z_importviewingkey, true },
|
||||||
@@ -694,10 +695,10 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms
|
|||||||
|
|
||||||
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
|
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
|
||||||
{
|
{
|
||||||
if ((strncmp(SMART_CHAIN_SYMBOL, "DRAGONX", 7) == 0) ) {
|
if ((strncmp(SMART_CHAIN_SYMBOL, "HUSH3", 5) == 0) ) {
|
||||||
return "> dragonx-cli " + methodname + " " + args + "\n";
|
return "> hush-cli " + methodname + " " + args + "\n";
|
||||||
} else {
|
} else {
|
||||||
return "> dragonx-cli -ac_name=" + strprintf("%s", SMART_CHAIN_SYMBOL) + " " + methodname + " " + args + "\n";
|
return "> hush-cli -ac_name=" + strprintf("%s", SMART_CHAIN_SYMBOL) + " " + methodname + " " + args + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -353,6 +353,7 @@ extern UniValue nspv_listccmoduleunspent(const UniValue& params, bool fHelp, con
|
|||||||
extern UniValue getblocksubsidy(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
extern UniValue getblocksubsidy(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
|
|
||||||
extern UniValue z_exportkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
extern UniValue z_exportkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
||||||
|
extern UniValue z_exportmnemonic(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
||||||
extern UniValue z_importkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
extern UniValue z_importkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
||||||
extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
||||||
extern UniValue z_importviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
extern UniValue z_importviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
#include <boost/optional/optional_io.hpp>
|
#include <boost/optional/optional_io.hpp>
|
||||||
#include <librustzcash.h>
|
#include <librustzcash.h>
|
||||||
#include "zcash/Note.hpp"
|
#include "zcash/Note.hpp"
|
||||||
|
#include <random>
|
||||||
|
#include <limits>
|
||||||
extern bool fZDebug;
|
extern bool fZDebug;
|
||||||
|
|
||||||
SpendDescriptionInfo::SpendDescriptionInfo(
|
SpendDescriptionInfo::SpendDescriptionInfo(
|
||||||
@@ -66,7 +68,7 @@ void TransactionBuilder::AddSaplingOutput(
|
|||||||
void TransactionBuilder::ShuffleOutputs()
|
void TransactionBuilder::ShuffleOutputs()
|
||||||
{
|
{
|
||||||
LogPrintf("%s: Shuffling %d zouts\n", __func__, outputs.size() );
|
LogPrintf("%s: Shuffling %d zouts\n", __func__, outputs.size() );
|
||||||
random_shuffle( outputs.begin(), outputs.end(), GetRandInt );
|
std::shuffle( outputs.begin(), outputs.end(), std::mt19937(GetRand(std::numeric_limits<uint32_t>::max())) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransactionBuilder::AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value, uint32_t _nSequence)
|
void TransactionBuilder::AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value, uint32_t _nSequence)
|
||||||
|
|||||||
@@ -21,9 +21,11 @@
|
|||||||
|
|
||||||
#include "txdb.h"
|
#include "txdb.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
|
#include "clientversion.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
|
#include "streams.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2025 The Hush developers
|
// Copyright (c) 2016-2025 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
|
|
||||||
@@ -751,7 +750,7 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
boost::filesystem::path GetPidFile()
|
boost::filesystem::path GetPidFile()
|
||||||
{
|
{
|
||||||
boost::filesystem::path pathPidFile(GetArg("-pid", "dragonxd.pid"));
|
boost::filesystem::path pathPidFile(GetArg("-pid", "hushd.pid"));
|
||||||
if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
|
if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
|
||||||
return pathPidFile;
|
return pathPidFile;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright (c) 2012-2014 The Bitcoin Core developers
|
// Copyright (c) 2012-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2016-2026 The Hush developers
|
// Copyright (c) 2016-2026 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Copyright (c) 2016-2024 The Hush developers
|
// Copyright (c) 2016-2024 The Hush developers
|
||||||
// Copyright (c) 2024-2026 The DragonX 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
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||||||
// recoverable, while keeping it logically separate from the ZIP 32
|
// recoverable, while keeping it logically separate from the ZIP 32
|
||||||
// Sapling key hierarchy, which the user might not be using.
|
// Sapling key hierarchy, which the user might not be using.
|
||||||
HDSeed seed;
|
HDSeed seed;
|
||||||
if (!pwalletMain->GetHDSeed(seed)) {
|
if (!pwalletMain->GetHDSeedForDerivation(seed)) {
|
||||||
throw JSONRPCError(
|
throw JSONRPCError(
|
||||||
RPC_WALLET_ERROR,
|
RPC_WALLET_ERROR,
|
||||||
"AsyncRPCOperation_sendmany: HD seed not found");
|
"AsyncRPCOperation_sendmany: HD seed not found");
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||||||
// recoverable, while keeping it logically separate from the ZIP 32
|
// recoverable, while keeping it logically separate from the ZIP 32
|
||||||
// Sapling key hierarchy, which the user might not be using.
|
// Sapling key hierarchy, which the user might not be using.
|
||||||
HDSeed seed;
|
HDSeed seed;
|
||||||
if (!pwalletMain->GetHDSeed(seed)) {
|
if (!pwalletMain->GetHDSeedForDerivation(seed)) {
|
||||||
throw JSONRPCError(
|
throw JSONRPCError(
|
||||||
RPC_WALLET_ERROR,
|
RPC_WALLET_ERROR,
|
||||||
"AsyncRPCOperation_sendmany::main_impl(): HD seed not found");
|
"AsyncRPCOperation_sendmany::main_impl(): HD seed not found");
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ bool ShieldToAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) c
|
|||||||
// recoverable, while keeping it logically separate from the ZIP 32
|
// recoverable, while keeping it logically separate from the ZIP 32
|
||||||
// Sapling key hierarchy, which the user might not be using.
|
// Sapling key hierarchy, which the user might not be using.
|
||||||
HDSeed seed;
|
HDSeed seed;
|
||||||
if (!pwalletMain->GetHDSeed(seed)) {
|
if (!pwalletMain->GetHDSeedForDerivation(seed)) {
|
||||||
throw JSONRPCError(
|
throw JSONRPCError(
|
||||||
RPC_WALLET_ERROR,
|
RPC_WALLET_ERROR,
|
||||||
"CWallet::GenerateNewSaplingZKey(): HD seed not found");
|
"CWallet::GenerateNewSaplingZKey(): HD seed not found");
|
||||||
|
|||||||
99
src/wallet/mnemonic.cpp
Normal file
99
src/wallet/mnemonic.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// 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
|
||||||
|
#include "wallet/mnemonic.h"
|
||||||
|
|
||||||
|
#include "random.h"
|
||||||
|
#include "support/cleanse.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "crypto/bip39/bip39.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
// The vendored BIP39 library references random_buffer() (used by its
|
||||||
|
// mnemonic_generate()). We do not compile trezor's insecure rand.c; instead we
|
||||||
|
// route it to the node CSPRNG so any BIP39 randomness is cryptographically
|
||||||
|
// sound. random_buffer is declared weak in rand.c, so this strong definition
|
||||||
|
// is the one that links.
|
||||||
|
extern "C" void random_buffer(uint8_t* buf, size_t len)
|
||||||
|
{
|
||||||
|
GetRandBytes(buf, (int)len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mnemonic_from_data()/mnemonic_to_seed() use process-static scratch buffers,
|
||||||
|
// so serialize all access behind one lock and copy results out immediately.
|
||||||
|
static std::mutex cs_bip39;
|
||||||
|
|
||||||
|
bool MnemonicIsValid(const std::string& phrase)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cs_bip39);
|
||||||
|
return mnemonic_check(phrase.c_str()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MnemonicToEntropy(const std::string& phrase, RawHDSeed& entropyOut)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cs_bip39);
|
||||||
|
// Reject bad checksum / unknown words first.
|
||||||
|
if (mnemonic_check(phrase.c_str()) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// mnemonic_to_entropy() writes 33 bytes (entropy || 1 checksum byte) and
|
||||||
|
// returns the total bit count (words * 11).
|
||||||
|
uint8_t buf[33];
|
||||||
|
int totalBits = mnemonic_to_entropy(phrase.c_str(), buf);
|
||||||
|
if (totalBits <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int words = totalBits / 11;
|
||||||
|
if (words != 12 && words != 18 && words != 24) {
|
||||||
|
memory_cleanse(buf, sizeof(buf));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int entropyBytes = words * 4 / 3; // 12->16, 18->24, 24->32
|
||||||
|
entropyOut.assign(buf, buf + entropyBytes);
|
||||||
|
memory_cleanse(buf, sizeof(buf));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntropyToMnemonic(const RawHDSeed& entropy, std::string& phraseOut)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cs_bip39);
|
||||||
|
const char* phrase = mnemonic_from_data(entropy.data(), (int)entropy.size());
|
||||||
|
if (phrase == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
phraseOut.assign(phrase);
|
||||||
|
mnemonic_clear(); // wipe the static buffer
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bip39SeedFromEntropy(const RawHDSeed& entropy, RawHDSeed& seed64Out)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cs_bip39);
|
||||||
|
// Regenerate the canonical phrase from entropy (matches SDXLite's
|
||||||
|
// Mnemonic::from_entropy(entropy).phrase()), then PBKDF2 with an EMPTY
|
||||||
|
// passphrase to get the standard 64-byte BIP39 seed.
|
||||||
|
const char* phrase = mnemonic_from_data(entropy.data(), (int)entropy.size());
|
||||||
|
if (phrase == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t seed[64];
|
||||||
|
mnemonic_to_seed(phrase, "", seed, nullptr);
|
||||||
|
mnemonic_clear();
|
||||||
|
seed64Out.assign(seed, seed + 64);
|
||||||
|
memory_cleanse(seed, sizeof(seed));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GenerateMnemonicEntropy(int bits, RawHDSeed& entropyOut)
|
||||||
|
{
|
||||||
|
if (bits != 128 && bits != 160 && bits != 192 && bits != 224 && bits != 256) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entropyOut.resize(bits / 8);
|
||||||
|
GetRandBytes(entropyOut.data(), (int)entropyOut.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
39
src/wallet/mnemonic.h
Normal file
39
src/wallet/mnemonic.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// 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
|
||||||
|
#ifndef HUSH_WALLET_MNEMONIC_H
|
||||||
|
#define HUSH_WALLET_MNEMONIC_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "zcash/zip32.h" // RawHDSeed
|
||||||
|
|
||||||
|
// Thin, thread-safe C++ wrapper over the vendored BIP39 (trezor-crypto) library.
|
||||||
|
// It reproduces SilentDragonXLite's tiny-bip39 0.6.2 conventions EXACTLY so the
|
||||||
|
// same 24 words yield the same addresses in both wallets:
|
||||||
|
// - English wordlist only (byte-identical to tiny-bip39's english.txt)
|
||||||
|
// - empty BIP39 passphrase (no "25th word")
|
||||||
|
// - PBKDF2-HMAC-SHA512, 2048 rounds, 64-byte seed
|
||||||
|
// - the seed is derived from the CANONICAL phrase regenerated from entropy,
|
||||||
|
// matching SDXLite's Mnemonic::from_entropy(entropy).phrase() round-trip.
|
||||||
|
|
||||||
|
//! True if `phrase` is a valid BIP39 mnemonic (word list + checksum).
|
||||||
|
bool MnemonicIsValid(const std::string& phrase);
|
||||||
|
|
||||||
|
//! Parse `phrase` into its BIP39 entropy (16/20/24/28/32 bytes). Validates the
|
||||||
|
//! checksum first. Returns false on any invalid input.
|
||||||
|
bool MnemonicToEntropy(const std::string& phrase, RawHDSeed& entropyOut);
|
||||||
|
|
||||||
|
//! Regenerate the canonical English mnemonic phrase from `entropy`.
|
||||||
|
bool EntropyToMnemonic(const RawHDSeed& entropy, std::string& phraseOut);
|
||||||
|
|
||||||
|
//! Derive the 64-byte BIP39 seed used for HD derivation from `entropy`, exactly
|
||||||
|
//! as SilentDragonXLite does: canonical phrase from entropy, then PBKDF2 with an
|
||||||
|
//! empty passphrase.
|
||||||
|
bool Bip39SeedFromEntropy(const RawHDSeed& entropy, RawHDSeed& seed64Out);
|
||||||
|
|
||||||
|
//! Generate fresh BIP39 entropy of `bits` (128/160/192/224/256) from the node
|
||||||
|
//! CSPRNG, for creating a new mnemonic wallet.
|
||||||
|
bool GenerateMnemonicEntropy(int bits, RawHDSeed& entropyOut);
|
||||||
|
|
||||||
|
#endif // HUSH_WALLET_MNEMONIC_H
|
||||||
@@ -742,7 +742,9 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
|
|||||||
file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
|
file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
|
||||||
{
|
{
|
||||||
HDSeed hdSeed;
|
HDSeed hdSeed;
|
||||||
pwalletMain->GetHDSeed(hdSeed);
|
// Dump the 64-byte derivation seed (for mnemonic wallets this is the
|
||||||
|
// expanded BIP39 seed), so re-importing the hex reproduces the same keys.
|
||||||
|
pwalletMain->GetHDSeedForDerivation(hdSeed);
|
||||||
auto rawSeed = hdSeed.RawSeed();
|
auto rawSeed = hdSeed.RawSeed();
|
||||||
file << strprintf("# HDSeed=%s fingerprint=%s", HexStr(rawSeed.begin(), rawSeed.end()), hdSeed.Fingerprint().GetHex());
|
file << strprintf("# HDSeed=%s fingerprint=%s", HexStr(rawSeed.begin(), rawSeed.end()), hdSeed.Fingerprint().GetHex());
|
||||||
file << "\n";
|
file << "\n";
|
||||||
@@ -1026,6 +1028,50 @@ UniValue z_exportkey(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
return EncodeSpendingKey(sk.get());
|
return EncodeSpendingKey(sk.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue z_exportmnemonic(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (fHelp || params.size() != 0)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_exportmnemonic\n"
|
||||||
|
"\nReveal the wallet's BIP39 seed phrase (24 words).\n"
|
||||||
|
"The phrase is byte-compatible with SilentDragonXLite: the same words\n"
|
||||||
|
"restore the same transparent and shielded addresses in either wallet.\n"
|
||||||
|
"Only works for wallets created or restored from a mnemonic (see the\n"
|
||||||
|
"-mnemonic and -usemnemonic options). Requires the wallet be unlocked.\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"{\n"
|
||||||
|
" \"mnemonic\" : \"word1 ... word24\", (string) the BIP39 seed phrase\n"
|
||||||
|
" \"seedfp\" : \"hex\" (string) the HD seed fingerprint\n"
|
||||||
|
"}\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_exportmnemonic", "")
|
||||||
|
+ HelpExampleRpc("z_exportmnemonic", "")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
if (!pwalletMain->IsMnemonicSeed()) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR,
|
||||||
|
"This wallet's seed was not derived from a mnemonic, so no seed phrase is available. "
|
||||||
|
"Use z_exportwallet to back up the raw HD seed instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string phrase;
|
||||||
|
if (!pwalletMain->GetMnemonicPhrase(phrase)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Could not retrieve the seed phrase (is the wallet unlocked?)");
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue ret(UniValue::VOBJ);
|
||||||
|
ret.push_back(Pair("mnemonic", phrase));
|
||||||
|
ret.push_back(Pair("seedfp", pwalletMain->GetHDChain().seedFp.GetHex()));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ void zsTxSendsToJSON(const CWalletTx& wtx, UniValue& sends, CAmount& totalSends,
|
|||||||
//Decrypt sapling outgoing t to z transaction using HDseed
|
//Decrypt sapling outgoing t to z transaction using HDseed
|
||||||
if (wtx.vShieldedSpend.size()==0) {
|
if (wtx.vShieldedSpend.size()==0) {
|
||||||
HDSeed seed;
|
HDSeed seed;
|
||||||
if (pwalletMain->GetHDSeed(seed)) {
|
if (pwalletMain->GetHDSeedForDerivation(seed)) {
|
||||||
auto opt = libzcash::SaplingOutgoingPlaintext::decrypt(
|
auto opt = libzcash::SaplingOutgoingPlaintext::decrypt(
|
||||||
outputDesc.outCiphertext,ovkForShieldingFromTaddr(seed),outputDesc.cv,outputDesc.cm,outputDesc.ephemeralKey);
|
outputDesc.outCiphertext,ovkForShieldingFromTaddr(seed),outputDesc.cv,outputDesc.cm,outputDesc.ephemeralKey);
|
||||||
|
|
||||||
|
|||||||
@@ -712,7 +712,7 @@ UniValue kvupdate(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
//for (i=0; i<32; i++)
|
//for (i=0; i<32; i++)
|
||||||
// printf("%02x",((uint8_t *)&sig)[i]);
|
// printf("%02x",((uint8_t *)&sig)[i]);
|
||||||
//printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
|
//printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
|
||||||
ret.push_back(Pair("coin",(char *)(SMART_CHAIN_SYMBOL[0] == 0 ? "DRAGONX" : SMART_CHAIN_SYMBOL)));
|
ret.push_back(Pair("coin",(char *)(SMART_CHAIN_SYMBOL[0] == 0 ? "HUSH3" : SMART_CHAIN_SYMBOL)));
|
||||||
height = chainActive.LastTip()->GetHeight();
|
height = chainActive.LastTip()->GetHeight();
|
||||||
if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
|
if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
|
||||||
ret.push_back(Pair("owner",refpubkey.GetHex()));
|
ret.push_back(Pair("owner",refpubkey.GetHex()));
|
||||||
@@ -6272,6 +6272,7 @@ extern UniValue importaddress(const UniValue& params, bool fHelp, const CPubKey&
|
|||||||
extern UniValue dumpwallet(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
extern UniValue dumpwallet(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue importwallet(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
extern UniValue importwallet(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue z_exportkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
extern UniValue z_exportkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
|
extern UniValue z_exportmnemonic(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue z_importkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
extern UniValue z_importkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue z_importviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
extern UniValue z_importviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
@@ -6351,6 +6352,7 @@ static const CRPCCommand commands[] =
|
|||||||
{ "wallet", "z_getnewaddress", &z_getnewaddress, true },
|
{ "wallet", "z_getnewaddress", &z_getnewaddress, true },
|
||||||
{ "wallet", "z_listaddresses", &z_listaddresses, true },
|
{ "wallet", "z_listaddresses", &z_listaddresses, true },
|
||||||
{ "wallet", "z_exportkey", &z_exportkey, true },
|
{ "wallet", "z_exportkey", &z_exportkey, true },
|
||||||
|
{ "wallet", "z_exportmnemonic", &z_exportmnemonic, true },
|
||||||
{ "wallet", "z_importkey", &z_importkey, true },
|
{ "wallet", "z_importkey", &z_importkey, true },
|
||||||
{ "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
|
{ "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
|
||||||
{ "wallet", "z_importviewingkey", &z_importviewingkey, true },
|
{ "wallet", "z_importviewingkey", &z_importviewingkey, true },
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user