Compare commits
37 Commits
autoshield
...
d05302d450
| Author | SHA1 | Date | |
|---|---|---|---|
| d05302d450 | |||
| 2232868d9f | |||
| 1745ee4e63 | |||
| 11766ec61b | |||
| 004808403f | |||
| e55c67b0eb | |||
| 4a2e531cb6 | |||
| c92e69a13f | |||
| 81f803948c | |||
| 817c6b2d0e | |||
| cf15b0a399 | |||
| 267e6f7ad5 | |||
| 0de30bbbd1 | |||
| b7060c7de0 | |||
| f76382f8e7 | |||
| aff6101987 | |||
| 798eccc624 | |||
| ac95106abe | |||
| 02b4d03fc6 | |||
| fad05d3ab4 | |||
| 5d3f7e520c | |||
| 092a608fd9 | |||
| 3dd667b127 | |||
| dde6cd810f | |||
| 499f02a905 | |||
| 4dc57e80b1 | |||
| 04ac7c1186 | |||
| 65130c3120 | |||
| 698bcf9574 | |||
| a0ccb4be1d | |||
| 358011bd54 | |||
| 7a62fc4877 | |||
| 9a8f17b2c8 | |||
| 1ec6590fb7 | |||
| 92e6c7008d | |||
| 733df964ec | |||
| d12e7dc99d |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -131,7 +131,6 @@ src/cc/rogue/rogue
|
||||
src/cc/rogue/rogue.so
|
||||
|
||||
src/cc/rogue/test.zip
|
||||
src/cc/dapps/a.out
|
||||
src/checkfile
|
||||
|
||||
src/foo.zip
|
||||
@@ -154,14 +153,15 @@ src/rogue.scr
|
||||
src/cc/rogue/confdefs.h
|
||||
src/cc/rogue/x64
|
||||
|
||||
src/cc/dapps/a.out
|
||||
src/Makefile.in
|
||||
doc/man/Makefile.in
|
||||
Makefile.in
|
||||
src/libcc.so
|
||||
src/libcc.dll
|
||||
src/libcc.dylib
|
||||
src/cc/customcc.so
|
||||
src/cc/customcc.dll
|
||||
src/cc/customcc.dylib
|
||||
src/HUSH3_7776
|
||||
REGTEST_7776
|
||||
src/cc/librogue.so
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
FROM ubuntu:20.04
|
||||
# Base image is parameterised so one Dockerfile can produce binaries for several
|
||||
# glibc floors: docker build --build-arg BASE_IMAGE=ubuntu:18.04 ...
|
||||
# The default is unchanged, so `./build.sh --linux-compat` behaves exactly as before.
|
||||
ARG BASE_IMAGE=ubuntu:20.04
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@@ -23,6 +27,17 @@ RUN rm -rf /build/depends/built /build/depends/work \
|
||||
&& rm -rf /build/src/cc/*.o /build/src/cc/*.a \
|
||||
&& rm -f /build/config.status /build/config.log
|
||||
|
||||
# The build context excludes .git (see .dockerignore), so genbuild.sh cannot derive
|
||||
# a version and would stamp the binaries "-unk". build.sh computes the real one
|
||||
# on the host and passes it in here.
|
||||
ARG BUILD_DESC=
|
||||
ENV DRAGONX_BUILD_DESC=${BUILD_DESC}
|
||||
|
||||
RUN if [ -z "$DRAGONX_BUILD_DESC" ]; then \
|
||||
echo "WARNING: no BUILD_DESC build-arg -- binaries will be stamped -unk." >&2; \
|
||||
echo " Prefer ./build.sh --linux-compat, or pass --build-arg BUILD_DESC=..." >&2; \
|
||||
fi
|
||||
|
||||
RUN cd /build && ./util/build.sh --disable-tests -j$(nproc)
|
||||
|
||||
# Strip binaries inside the container so extracted files are already small
|
||||
|
||||
55
build.sh
55
build.sh
@@ -6,10 +6,34 @@
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
VERSION="1.0.3"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
RELEASE_DIR="$SCRIPT_DIR/release"
|
||||
|
||||
# Derive the release version from configure.ac instead of hardcoding it here.
|
||||
# A stale literal names the release directories after the wrong version while the
|
||||
# binaries inside report the real one: this said 1.0.3 while the tree was already
|
||||
# 1.1.0, so `./build.sh --all-release` would have produced
|
||||
# release/dragonx-1.0.3-<platform>/ full of binaries announcing 1.1.0.
|
||||
# Mirrors configure.ac's _CLIENT_VERSION_SUFFIX m4 exactly:
|
||||
# build < 25 -> beta(build+1) build < 50 -> rc(build-24)
|
||||
# build == 50 -> plain release build > 50 -> point release (build-50)
|
||||
_acdef() { sed -n "s/^define(_CLIENT_VERSION_$1, *\([0-9]\{1,\}\))/\1/p" "$SCRIPT_DIR/configure.ac"; }
|
||||
_V_MAJOR="$(_acdef MAJOR)"
|
||||
_V_MINOR="$(_acdef MINOR)"
|
||||
_V_REVISION="$(_acdef REVISION)"
|
||||
_V_BUILD="$(_acdef BUILD)"
|
||||
if [ -z "$_V_MAJOR" ] || [ -z "$_V_MINOR" ] || [ -z "$_V_REVISION" ] || [ -z "$_V_BUILD" ]; then
|
||||
echo "ERROR: could not read the version from $SCRIPT_DIR/configure.ac" >&2
|
||||
echo " refusing to build a release whose directory name would be wrong." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$_V_BUILD" -lt 25 ]; then _V_SUFFIX="$_V_REVISION-beta$((_V_BUILD + 1))"
|
||||
elif [ "$_V_BUILD" -lt 50 ]; then _V_SUFFIX="$_V_REVISION-rc$((_V_BUILD - 24))"
|
||||
elif [ "$_V_BUILD" -eq 50 ]; then _V_SUFFIX="$_V_REVISION"
|
||||
else _V_SUFFIX="$_V_REVISION-$((_V_BUILD - 50))"
|
||||
fi
|
||||
VERSION="$_V_MAJOR.$_V_MINOR.$_V_SUFFIX"
|
||||
|
||||
# Parse release flags
|
||||
BUILD_LINUX_RELEASE=0
|
||||
BUILD_WIN_RELEASE=0
|
||||
@@ -140,7 +164,34 @@ if [ $BUILD_LINUX_COMPAT -eq 1 ] || [ $BUILD_LINUX_RELEASE -eq 1 ] || [ $BUILD_W
|
||||
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" .
|
||||
# .dockerignore excludes .git, so genbuild.sh inside the container cannot
|
||||
# derive the version and would stamp the binaries "-unk". Compute it on the
|
||||
# host, mirroring util/genbuild.sh exactly, and pass it in via --build-arg.
|
||||
# NB: build.sh runs under `set -eu -o pipefail`, so every git call here must be
|
||||
# non-fatal -- a source tarball, a machine without git, or a branch whose only
|
||||
# reachable tags are lightweight (v1.0.1-v1.0.3) would otherwise abort the build.
|
||||
git diff >/dev/null 2>&1 || true # refresh index: touched-but-unmodified are not dirty
|
||||
COMPAT_BUILD_DESC=""
|
||||
COMPAT_RAWDESC=$(git describe --abbrev=0 2>/dev/null || true)
|
||||
if [ -n "$COMPAT_RAWDESC" ] \
|
||||
&& [ "$(git rev-parse HEAD 2>/dev/null)" = "$(git rev-list -1 "$COMPAT_RAWDESC" 2>/dev/null)" ] \
|
||||
&& git diff-index --quiet HEAD -- 2>/dev/null; then
|
||||
COMPAT_BUILD_DESC="$COMPAT_RAWDESC"
|
||||
else
|
||||
COMPAT_SUFFIX=$(git rev-parse --short HEAD 2>/dev/null || true)
|
||||
if [ -n "$COMPAT_SUFFIX" ]; then
|
||||
git diff-index --quiet HEAD -- 2>/dev/null || COMPAT_SUFFIX="$COMPAT_SUFFIX-dirty"
|
||||
COMPAT_BUILD_DESC="v$VERSION-$COMPAT_SUFFIX"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$COMPAT_BUILD_DESC" ]; then
|
||||
echo "Stamping container build as: $COMPAT_BUILD_DESC"
|
||||
else
|
||||
echo "Warning: no usable git metadata; container binaries will be stamped -unk"
|
||||
fi
|
||||
$DOCKER_CMD build -f Dockerfile.compat \
|
||||
--build-arg BUILD_DESC="$COMPAT_BUILD_DESC" \
|
||||
-t "$DOCKER_IMAGE" .
|
||||
|
||||
echo "Extracting binaries from Docker image..."
|
||||
CONTAINER_ID=$($DOCKER_CMD create "$DOCKER_IMAGE")
|
||||
|
||||
18
configure.ac
18
configure.ac
@@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
||||
AC_PREREQ([2.60])
|
||||
define(_CLIENT_VERSION_MAJOR, 1)
|
||||
dnl Must be kept in sync with src/clientversion.h , ugh!
|
||||
define(_CLIENT_VERSION_MINOR, 1)
|
||||
define(_CLIENT_VERSION_MINOR, 2)
|
||||
define(_CLIENT_VERSION_REVISION, 0)
|
||||
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)))
|
||||
@@ -833,6 +833,22 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin])
|
||||
AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin])
|
||||
AM_CONDITIONAL([TARGET_LINUX], [test x$TARGET_OS = xlinux])
|
||||
AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
|
||||
|
||||
dnl mingw ld is single-pass: bracket the internal static archives in a link group
|
||||
dnl so it re-scans and resolves the cross-references DragonX added between them
|
||||
dnl (libbitcoin_util/common objects using UniValue; util<->common mutual deps).
|
||||
dnl Delivered via AC_SUBST (not an automake conditional) so automake does not
|
||||
dnl reject the linker flags inside _LDADD. Empty elsewhere (macOS ld64 rejects the
|
||||
dnl flag; GNU ld on Linux re-scans archives already).
|
||||
if test "x$TARGET_OS" = "xwindows"; then
|
||||
LINK_GROUP_START="-Wl,--start-group"
|
||||
LINK_GROUP_END="-Wl,--end-group"
|
||||
else
|
||||
LINK_GROUP_START=""
|
||||
LINK_GROUP_END=""
|
||||
fi
|
||||
AC_SUBST(LINK_GROUP_START)
|
||||
AC_SUBST(LINK_GROUP_END)
|
||||
AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
|
||||
AM_CONDITIONAL([ENABLE_MINING],[test x$enable_mining = xyes])
|
||||
AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes])
|
||||
|
||||
@@ -1,3 +1,40 @@
|
||||
dragonx (1.2.0) stable; urgency=medium
|
||||
|
||||
* Auto-shield matured coinbase into a wallet-owned Sapling address on a block
|
||||
interval. The destination is derived from the HD seed at m/32'/coin'/i' and
|
||||
is the lowest index inside -mnemonicsaplinggap, so a bare seed-phrase restore
|
||||
re-derives it; auto-shielding refuses to run rather than send anywhere a
|
||||
restore would not find. Enabled only when the seed's provenance is known to be
|
||||
recoverable, so upgraded wallets stay opted out until the operator says
|
||||
otherwise.
|
||||
* Create new wallets from a BIP39 seed phrase by default, byte-compatible with
|
||||
SilentDragonXLite. z_exportmnemonic returns the phrase; -mnemonic restores
|
||||
from it.
|
||||
* New RPC z_autoshieldstatus reports whether auto-shielding is on, the resolved
|
||||
destination, the HD seed's provenance, and why it is off when it is off.
|
||||
* Bound each auto-shield round to 400 inputs and correct the transaction size
|
||||
estimate to account for all three Sapling output descriptions, and lock the
|
||||
selected coins for the duration of proof building so a concurrent
|
||||
z_shieldcoinbase or z_sendmany cannot select them too.
|
||||
* Repair, rather than reject, an hdchain record truncated by an older wallet
|
||||
build. Previously one address generated under a pre-1.1.0 binary left the
|
||||
wallet unopenable with "Wallet corrupted"; the record is now completed and
|
||||
rewritten, and the error text names the seed-phrase remedy when it genuinely
|
||||
cannot be recovered.
|
||||
* Clear a stale sweep flag that could otherwise leave sweeping, consolidation
|
||||
and auto-shielding permanently disabled together, and stop the async queue
|
||||
silently discarding operations at shutdown while reporting success.
|
||||
* Peer discovery: seed from the round-robin DNS record seed.dragonx.is rather
|
||||
than three hostnames that no longer resolve, count DNS-seeded addresses so
|
||||
the fixed-seed fallback is no longer triggered spuriously, give every entry
|
||||
in the compiled-in seed list its P2P port, and stop non-DRAGONX smart chains
|
||||
inheriting DragonX's seeds. Adds two seed nodes in new regions.
|
||||
* Derive the release version from configure.ac in build.sh instead of a
|
||||
hardcoded literal, and document container-based release builds in
|
||||
doc/build-containers.md.
|
||||
|
||||
-- DragonX Developers <dev@dragonx.is> Tue, 25 Aug 2026 19:45:00 +0000
|
||||
|
||||
dragonx (1.1.0) stable; urgency=medium
|
||||
|
||||
* Extend DRAGONX checkpoints to height 3,226,000, enabling the existing
|
||||
@@ -17,7 +54,7 @@ dragonx (1.1.0) stable; urgency=medium
|
||||
pre-verification, adaptive -dbcache, Sapling witness desync fix, BIP39
|
||||
seed phrases, chain-level Sapling turnstile, and the audit fixes.
|
||||
|
||||
-- DragonX Developers <dev@dragonx.is> Thu, 21 Aug 2026 22:00:00 +0000
|
||||
-- DragonX Developers <dev@dragonx.is> Sun, 23 Aug 2026 10:41:53 -0500
|
||||
|
||||
dragonx (1.0.3) stable; urgency=medium
|
||||
|
||||
@@ -29,6 +66,22 @@ dragonx (1.0.3) stable; urgency=medium
|
||||
|
||||
-- DragonX <dan-s-dev@proton.me> Tue, 07 Jul 2026 05:49:59 +0200
|
||||
|
||||
dragonx (1.0.2) stable; urgency=medium
|
||||
|
||||
* Fix Sapling pool persistence, and report the block subsidy and total fees
|
||||
in the getblock RPC
|
||||
* Fix the Windows bootstrap script and add a mirror fallback
|
||||
* Fix the Windows build
|
||||
* Fix the macOS Sequoia build with GCC 15
|
||||
|
||||
-- DragonX <dan-s-dev@proton.me> Thu, 19 Mar 2026 10:09:18 -0500
|
||||
|
||||
dragonx (1.0.1) stable; urgency=medium
|
||||
|
||||
* Fix a fresh-sync failure at the difficulty reset height 2838976
|
||||
|
||||
-- DragonX <dan-s-dev@proton.me> Thu, 12 Mar 2026 01:25:21 -0500
|
||||
|
||||
dragonx (1.0.0) stable; urgency=medium
|
||||
|
||||
* Initial release of DragonX, forked from Hush Full Node
|
||||
@@ -36,7 +89,7 @@ dragonx (1.0.0) stable; urgency=medium
|
||||
* 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
|
||||
-- DragonX <dan-s-dev@proton.me> Tue, 10 Mar 2026 19:39:55 -0500
|
||||
|
||||
hush (3.10.5) stable; urgency=medium
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
DEBIAN/manpages/dragonx-cli.1
|
||||
DEBIAN/manpages/dragonx-tx.1
|
||||
DEBIAN/manpages/dragonxd.1
|
||||
doc/man/dragonxd.1
|
||||
doc/man/dragonx-cli.1
|
||||
doc/man/dragonx-tx.1
|
||||
|
||||
@@ -177,7 +177,7 @@ def main():
|
||||
g.write('\n')
|
||||
with open(os.path.join(indir,'nodes_test.txt'), 'r', encoding="utf8") as f:
|
||||
process_nodes(g, f, 'chainparams_seed_test')
|
||||
g.write('#endif // HUSH_CHAINPARAMSSEEDS_H\n')
|
||||
g.write('#endif // DRAGONX_CHAINPARAMSSEEDS_H\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
# generate-seeds.py expects <ip>:<port> (see its docstring). Without the port it
|
||||
# emits 0, and every fixed seed becomes unconnectable -- which is what shipped:
|
||||
# the whole chainparams_seed_main array carried 0x00,0x00 as the port.
|
||||
# node1.dragonx.is
|
||||
212.56.41.63
|
||||
212.56.41.63:21768
|
||||
|
||||
# node2.dragonx.is
|
||||
194.140.198.176
|
||||
194.140.198.176:21768
|
||||
|
||||
# node3.dragonx.is
|
||||
212.56.41.47
|
||||
212.56.41.47:21768
|
||||
|
||||
# node4.dragonx.is
|
||||
144.126.147.165
|
||||
144.126.147.165:21768
|
||||
|
||||
# node5.dragonx.is
|
||||
176.126.87.241
|
||||
176.126.87.241:21768
|
||||
|
||||
# node6.dragonx.is
|
||||
13.140.58.251:21768
|
||||
|
||||
# node7.dragonx.is
|
||||
5.104.83.100:21768
|
||||
|
||||
@@ -53,6 +53,6 @@ endif
|
||||
define $(package)_stage_cmds
|
||||
mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
||||
mkdir $($(package)_staging_dir)$(host_prefix)/include/ && \
|
||||
cp $($(package)_library_file) $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
||||
cp $($(package)_library_file) $($(package)_staging_dir)$(host_prefix)/lib/librustzcash.a && \
|
||||
cp librustzcash/include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/
|
||||
endef
|
||||
|
||||
223
doc/build-containers.md
Normal file
223
doc/build-containers.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# Building release binaries in containers
|
||||
|
||||
Release binaries must be built in a container based on an **old** Linux distribution.
|
||||
This document is written to be executed, by a person or an agent, on a machine that
|
||||
has nothing set up yet.
|
||||
|
||||
---
|
||||
|
||||
## 1. Why this exists
|
||||
|
||||
glibc compatibility runs one way only. A binary linked against glibc 2.35 demands
|
||||
symbol versions that glibc 2.31 does not have, and refuses to start. A binary linked
|
||||
against glibc 2.29 runs on 2.29, 2.31 and 2.35 alike.
|
||||
|
||||
Measured on the actual fleet, 2026-08-25:
|
||||
|
||||
| binary | max GLIBC required | runs on |
|
||||
|---|---|---|
|
||||
| what all four 20.04 seeds run today (`v1.0.3-d159e7208`) | `GLIBC_2.29` | 18.04, 20.04, 22.04 |
|
||||
| anything built on seed 176 today (Ubuntu 22.04) | `GLIBC_2.34` | 22.04 only |
|
||||
|
||||
The second binary will not start on four of our own five seeds. The loader reports:
|
||||
|
||||
```
|
||||
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found
|
||||
/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.30' not found
|
||||
```
|
||||
|
||||
Nothing new is being *called*. glibc 2.34 merged libpthread and libdl into libc and
|
||||
re-versioned every `pthread_*`, `dlsym` and `dladdr` symbol; 2.33 replaced the old
|
||||
`__xstat` inlines with real `stat`/`fstat`/`lstat64`. All of those functions exist in
|
||||
2.31 under older tags. Building against older headers is the entire fix.
|
||||
|
||||
**Do not try to solve this with full static linking.** The daemon calls `getaddrinfo`,
|
||||
`gethostbyname` and `getnameinfo`, and it must resolve `node1..node5.dragonx.is`, which
|
||||
are hard-coded and injected into `-addnode` on every node. Under a fully static glibc
|
||||
binary those go through NSS, which `dlopen`s `libnss_dns.so.2` at run time — it either
|
||||
fails or silently requires the target to have the same glibc you linked against, which
|
||||
defeats the purpose.
|
||||
|
||||
---
|
||||
|
||||
## 2. What already exists in this repo
|
||||
|
||||
Do not write a new build system. Two pieces are already here:
|
||||
|
||||
- **`Dockerfile.compat`** — an Ubuntu base image that installs the toolchain, copies the
|
||||
tree, **deletes any host-built `depends/` and object files**, runs `./util/build.sh`,
|
||||
and strips the three binaries.
|
||||
- **`./build.sh --linux-compat`** — builds that image, creates a throwaway container,
|
||||
copies `dragonxd`, `dragonx-cli` and `dragonx-tx` out into
|
||||
`release/dragonx-<version>-linux-amd64-ubuntu2004/`, adds `bootstrap-dragonx.sh`,
|
||||
`asmap.dat` and the two sapling params, fixes ownership, and prints the binary's
|
||||
maximum required GLIBC version.
|
||||
|
||||
The base image is parameterised via `ARG BASE_IMAGE` (default `ubuntu:20.04`), so the
|
||||
same Dockerfile can target several glibc floors.
|
||||
|
||||
---
|
||||
|
||||
## 3. Prerequisites
|
||||
|
||||
Docker (the scripted path uses `docker` specifically; podman works for the manual path
|
||||
if you alias or substitute it).
|
||||
|
||||
```sh
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker.io git
|
||||
sudo usermod -aG docker "$USER" # then log out and back in, or every command needs sudo
|
||||
```
|
||||
|
||||
Budget, measured on a 4-core box:
|
||||
|
||||
| resource | needs |
|
||||
|---|---|
|
||||
| disk | ~15 GB free (the `depends/` tree alone is ~1.6 GB per target, plus image layers) |
|
||||
| RAM | 4 GB minimum, 8 GB comfortable — the link step is the peak |
|
||||
| time | **1–2 hours per base image on first build.** `depends/` builds boost, BDB, wolfssl, libevent, libsodium, libcurl and rust from source. Later builds reuse Docker layer cache unless the tree changed. |
|
||||
|
||||
`depends/` downloads and builds its own rust toolchain, so the host's rust (or absence
|
||||
of it) is irrelevant.
|
||||
|
||||
---
|
||||
|
||||
## 4. Build one target
|
||||
|
||||
```sh
|
||||
git clone https://git.dragonx.is/DragonX/dragonx
|
||||
cd dragonx
|
||||
git checkout <the tag or branch you are releasing>
|
||||
|
||||
./build.sh --linux-compat
|
||||
```
|
||||
|
||||
Output lands in `release/dragonx-<version>-linux-amd64-ubuntu2004/` and the script
|
||||
prints the max GLIBC at the end. `<version>` is read from `configure.ac`, not
|
||||
hardcoded, so it always matches what the binaries report.
|
||||
|
||||
---
|
||||
|
||||
## 5. Build several targets
|
||||
|
||||
```sh
|
||||
for BASE in ubuntu:18.04 ubuntu:20.04 ubuntu:22.04; do
|
||||
TAG="dragonx-compat-${BASE#ubuntu:}"
|
||||
TAG="${TAG//./}"
|
||||
docker build --build-arg "BASE_IMAGE=$BASE" -f Dockerfile.compat -t "$TAG" .
|
||||
|
||||
OUT="release/dragonx-$(grep -oP 'define\(_CLIENT_VERSION_MAJOR, \K[0-9]+' configure.ac).$(grep -oP 'define\(_CLIENT_VERSION_MINOR, \K[0-9]+' configure.ac).$(grep -oP 'define\(_CLIENT_VERSION_REVISION, \K[0-9]+' configure.ac)-linux-amd64-${BASE#ubuntu:}"
|
||||
mkdir -p "$OUT"
|
||||
CID=$(docker create "$TAG")
|
||||
for b in dragonxd dragonx-cli dragonx-tx; do docker cp "$CID:/build/src/$b" "$OUT/$b"; done
|
||||
docker rm "$CID" >/dev/null
|
||||
cp util/bootstrap-dragonx.sh contrib/asmap/asmap.dat sapling-output.params sapling-spend.params "$OUT/" 2>/dev/null || true
|
||||
done
|
||||
```
|
||||
|
||||
### Which base to choose
|
||||
|
||||
| base | glibc it provides | default GCC | verdict |
|
||||
|---|---|---|---|
|
||||
| `ubuntu:18.04` | 2.27 | 7 | **Verify before relying on it.** The tree is built with `-std=c++17`; GCC 7's C++17 support is incomplete and its cmake (3.10) may be too old for RandomX. Attempt only if you need to reach 18.04 users, and treat a successful build as the proof. |
|
||||
| `ubuntu:20.04` | 2.31 | 9 | **Recommended floor.** GCC 9 covers C++17 fully. Evidence it works: the binary the fleet runs today requires only `GLIBC_2.29`, i.e. the code touches nothing newer, so a 20.04 build reaches 18.04 machines anyway. |
|
||||
| `ubuntu:22.04` | 2.35 | 11 | **Do not ship this.** It is what we already have and what excludes four of our own seeds. Useful only for development. |
|
||||
|
||||
Ubuntu 20.04 left standard support in April 2025, which is precisely why it belongs in
|
||||
a container on a patched host rather than on a build box someone has to maintain.
|
||||
|
||||
---
|
||||
|
||||
## 6. Verify — this step is not optional
|
||||
|
||||
A build that silently targets the wrong glibc looks completely normal until a user
|
||||
reports that nothing starts.
|
||||
|
||||
```sh
|
||||
BIN=release/dragonx-<version>-linux-amd64-ubuntu2004/dragonxd
|
||||
|
||||
# The ceiling. Must be <= the glibc of the OLDEST system you intend to support.
|
||||
objdump -p "$BIN" | grep -oE 'GLIBC_2\.[0-9]+' | sort -t. -k2 -n | tail -1
|
||||
objdump -p "$BIN" | grep -oE 'GLIBCXX_3\.4\.[0-9]+' | sort -t. -k3 -n | tail -1
|
||||
|
||||
# If the ceiling is too high, this names the symbols responsible.
|
||||
readelf --dyn-syms --wide "$BIN" | grep -E '@GLIBC_2\.(3[2-9])'
|
||||
```
|
||||
|
||||
Expected for a 20.04 build: `GLIBC_2.29` or lower, `GLIBCXX_3.4.26` or lower.
|
||||
|
||||
Then actually run it somewhere old. A ceiling check proves the loader will resolve the
|
||||
symbols; it does not prove the binary works. `./dragonxd --version` on a real 20.04 box
|
||||
is a ten-second confirmation.
|
||||
|
||||
---
|
||||
|
||||
## 7. Traps
|
||||
|
||||
Each of these has cost real time.
|
||||
|
||||
**`ETXTBSY` when installing over a running daemon.** `cp` onto the binary fails with
|
||||
"Text file busy" *even after the process has exited* — `pgrep` returning nothing is not
|
||||
sufficient, the kernel still holds the text mapping. Stage into the same directory and
|
||||
`mv` (rename is not blocked), allow ~10 s to settle, and **sha256-verify the installed
|
||||
file before starting it**. A failed copy that goes unnoticed leaves the old binary
|
||||
running and looks like a successful deploy.
|
||||
|
||||
**Never touch `configure.ac` in a configured tree.** Even `cp`-ing back a byte-identical
|
||||
copy updates its mtime, which makes `make` regenerate `aclocal.m4` and `configure` and
|
||||
then re-run `configure`, which fails with `libdb_cxx headers missing` because the
|
||||
depends prefix is not on the command line. If it happens: confirm
|
||||
`git diff --quiet HEAD -- configure.ac`, then restore mtime order oldest-to-newest with
|
||||
one-second gaps — `configure.ac`/`Makefile.am`, then `aclocal.m4`, then
|
||||
`configure`/`Makefile.in`, then `config.status`, then `Makefile`. Inside a container
|
||||
this cannot happen, which is one more reason to build there.
|
||||
|
||||
**Never blind-`touch` a path that might not exist.** `touch src/config/hush-config.h`
|
||||
silently *creates* an empty stray file; the real header is `bitcoin-config.h`. Check
|
||||
`git status` after any timestamp surgery.
|
||||
|
||||
**RandomX must be built with `ARCH=default`.** `util/build.sh` already passes it and the
|
||||
comment there explains why: `ARCH=native` tunes to the build machine, and a build on an
|
||||
AVX-512 host emitted 746 `zmm` instructions into `librandomx.a`, which `SIGILL`s on the
|
||||
entire fleet. If you ever invoke cmake by hand, pass `-DARCH=default`.
|
||||
|
||||
**Strip before distributing.** Unstripped is ~220 MB, stripped ~16 MB. `Dockerfile.compat`
|
||||
already strips inside the container.
|
||||
|
||||
**`util/build-win.sh` discards every argument.** There is no `"$@"` handling in it, so
|
||||
`-j$(nproc)` and `--disable-tests` are dropped on the floor and the Windows build is
|
||||
single-threaded. Expect it to be far slower than you planned.
|
||||
|
||||
**Windows also needs `-Wa,-mbig-obj` and `-DARCH=default`.** Both are in
|
||||
`util/build-win.sh` today. The mingw flag was missing from `dev` for a month; without it
|
||||
the cross-compile fails at link because boost-heavy translation units exceed the
|
||||
PE/COFF section limit. Do not lose it on a re-branch.
|
||||
|
||||
**macOS cannot be containerised.** `util/build-mac.sh` is a native-Mac script, and there
|
||||
is no darwin cross-compile path in `depends/` at all: `hosts/darwin.mk` wants
|
||||
`native_cctools`, which has no package definition, and there is no SDK in the tree. It
|
||||
also hardcodes an Intel Homebrew GCC path, so it produces x86_64 only — no arm64, no
|
||||
universal binary. macOS needs a real Mac.
|
||||
|
||||
**The `contrib/gitian-descriptors/` files are not a build path.** They are unmodified
|
||||
upstream Bitcoin files (`name: "bitcoin-win-0.11"`, suite `trusty`) with zero DragonX
|
||||
content. Ignore them.
|
||||
|
||||
---
|
||||
|
||||
## 8. Handoff checklist
|
||||
|
||||
- [ ] Docker installed, user in the `docker` group, ~15 GB free
|
||||
- [ ] Correct tag or branch checked out, tree clean (`git status`)
|
||||
- [ ] Version in `configure.ac` is the one you intend to release
|
||||
- [ ] `./build.sh --linux-compat` completes
|
||||
- [ ] GLIBC ceiling is **2.31 or lower** (2.29 expected)
|
||||
- [ ] GLIBCXX ceiling is **3.4.28 or lower** (3.4.26 expected)
|
||||
- [ ] `dragonxd --version` runs on a real machine of the oldest supported distro
|
||||
- [ ] Binaries stripped, `release/` contains the bootstrap script, `asmap.dat` and both sapling params
|
||||
- [ ] sha256 recorded for each artifact
|
||||
|
||||
One more thing that is not a build step but belongs in the same conversation: the
|
||||
in-app daemon updater refuses any release without a detached signature
|
||||
(`kDaemonRequireSignature = true`). Publishing checksums alone means no existing user
|
||||
can update in place.
|
||||
@@ -1,9 +1,9 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.1.
|
||||
.TH DRAGONX "1" "July 2026" "DragonX RPC client version v1.0.3-95aeaed0c-dirty" "User Commands"
|
||||
.TH DRAGONX-CLI "1" "August 2026" "dragonx-cli v1.2.0" "User Commands"
|
||||
.SH NAME
|
||||
DragonX \- manual page for DragonX RPC client version v1.0.3-95aeaed0c-dirty
|
||||
dragonx-cli \- manual page for dragonx-cli v1.2.0
|
||||
.SH DESCRIPTION
|
||||
DragonX RPC client version v1.0.3\-95aeaed0c\-dirty
|
||||
DragonX RPC client version v1.2.0
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
DragonX, please see <https://dragonx.is/security/>.
|
||||
@@ -70,25 +70,22 @@ Timeout in seconds during HTTP requests, or 0 for no timeout. (default:
|
||||
.IP
|
||||
Read extra arguments from standard input, one per line until EOF/Ctrl\-D
|
||||
(recommended for sensitive information such as passphrases)
|
||||
.PP
|
||||
.SH COPYRIGHT
|
||||
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
DragonX, please see <https://dragonx.is/security/>.
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2024\-2026 The DragonX Developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2016\-2024 Duke Leto and The Hush Developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2016\-2020 jl777 and SuperNET developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2016\-2018 The Zcash developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2009\-2014 The Bitcoin Core developers
|
||||
.PP
|
||||
|
||||
Copyright (C) 2024-2026 The DragonX Developers
|
||||
|
||||
Copyright (C) 2016-2024 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!!!!!
|
||||
.PP
|
||||
|
||||
Distributed under the GPLv3 software license, see the accompanying file COPYING
|
||||
or <https://www.gnu.org/licenses/gpl\-3.0.en.html>.
|
||||
or <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.1.
|
||||
.TH DRAGONX-TX "1" "July 2026" "dragonx-tx v1.0.3-4caf2fc68" "User Commands"
|
||||
.TH DRAGONX-TX "1" "August 2026" "dragonx-tx v1.2.0" "User Commands"
|
||||
.SH NAME
|
||||
dragonx-tx \- DragonX transaction utility
|
||||
dragonx-tx \- manual page for dragonx-tx v1.2.0
|
||||
.SH DESCRIPTION
|
||||
hush\-tx utility version v1.0.3\-4caf2fc68
|
||||
hush\-tx utility version v1.2.0
|
||||
.SS "Usage:"
|
||||
.TP
|
||||
hush\-tx [options] <hex\-tx> [commands]
|
||||
@@ -84,3 +84,22 @@ Load JSON file FILENAME into register NAME
|
||||
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/security/>.
|
||||
|
||||
Copyright (C) 2024-2026 The DragonX Developers
|
||||
|
||||
Copyright (C) 2016-2024 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,9 +1,9 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.1.
|
||||
.TH DRAGONX "1" "July 2026" "DragonX Daemon version v1.0.3-4caf2fc68" "User Commands"
|
||||
.TH DRAGONXD "1" "August 2026" "dragonxd v1.2.0" "User Commands"
|
||||
.SH NAME
|
||||
DragonX \- manual page for DragonX Daemon version v1.0.3-4caf2fc68
|
||||
dragonxd \- manual page for dragonxd v1.2.0
|
||||
.SH DESCRIPTION
|
||||
DragonX Daemon version v1.0.3\-4caf2fc68
|
||||
DragonX Daemon version v1.2.0
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
DragonX, please see <https://dragonx.is/security/>.
|
||||
@@ -52,7 +52,7 @@ Specify directory to be used when exporting data
|
||||
.HP
|
||||
\fB\-dbcache=\fR<n>
|
||||
.IP
|
||||
Set database cache size in megabytes (4 to 16384). Default: adaptive \-
|
||||
Set database cache size in megabytes (4 to 65536). 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
|
||||
@@ -88,8 +88,8 @@ leave that many cores free, default: 0)
|
||||
\fB\-randomxverifythreads=\fR<n>
|
||||
.IP
|
||||
Number of threads for parallel RandomX PoW pre\-verification of
|
||||
post\-checkpoint blocks during sync (0 = inline only, max 16,
|
||||
default: same as \fB\-par\fR)
|
||||
post\-checkpoint blocks during network sync; no effect on reindex
|
||||
(0 = inline only, max 16, default: same as \fB\-par\fR)
|
||||
.HP
|
||||
\fB\-pid=\fR<file>
|
||||
.IP
|
||||
@@ -361,15 +361,18 @@ exposes the seed to your shell history and process list.
|
||||
\fB\-mnemonic=\fR<words>
|
||||
.IP
|
||||
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.
|
||||
with SilentDragonXLite (English, no passphrase; cross\-wallet
|
||||
restore parity is mainnet\-only \fB\-\-\fR testnet/regtest derive a
|
||||
different HD coin_type). WARNING: exposes the phrase to your
|
||||
shell history and process list; prefer DRAGONX.conf with tight
|
||||
permissions.
|
||||
.HP
|
||||
\fB\-usemnemonic\fR
|
||||
.IP
|
||||
Create new wallets from a fresh BIP39 seed phrase so the 24 words can be
|
||||
exported (z_exportmnemonic) and used in SilentDragonXLite
|
||||
(default: 0)
|
||||
exported (z_exportmnemonic) and used in SilentDragonXLite. Set to
|
||||
0 for a raw random seed with no recovery phrase; existing wallets
|
||||
are never changed (default: 1)
|
||||
.HP
|
||||
\fB\-hdtransparentgaplimit=\fR<n>
|
||||
.IP
|
||||
@@ -427,6 +430,33 @@ Enable sweeping to an external wallet (default false)
|
||||
.IP
|
||||
Addresses to exclude from sweeping (default none)
|
||||
.HP
|
||||
\fB\-autoshield\fR
|
||||
.IP
|
||||
Automatically shield matured coinbase (mining rewards) into a
|
||||
seed\-derived wallet z\-address (default: true for wallets created
|
||||
or restored by this software, false when the HD seed provenance
|
||||
is unknown). No\-op when not mining or wallet is locked.
|
||||
.HP
|
||||
\fB\-autoshieldinterval\fR
|
||||
.IP
|
||||
Block interval between automatic coinbase\-shielding rounds (default: 25,
|
||||
min 5)
|
||||
.HP
|
||||
\fB\-autoshieldaddress=\fR<zaddr>
|
||||
.IP
|
||||
Destination Sapling z\-address for auto\-shielded coinbase (default: reuse
|
||||
or create a wallet z\-address). Must be spendable by this wallet.
|
||||
.HP
|
||||
\fB\-autoshieldfee\fR
|
||||
.IP
|
||||
Fee in puposhis for automatic coinbase\-shielding transactions (default:
|
||||
10000)
|
||||
.HP
|
||||
\fB\-autoshieldminutxos\fR
|
||||
.IP
|
||||
Only auto\-shield once at least this many matured coinbase UTXOs exist
|
||||
(default: 1)
|
||||
.HP
|
||||
\fB\-deletetx\fR
|
||||
.IP
|
||||
Enable Old Transaction Deletion
|
||||
@@ -446,7 +476,7 @@ 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)
|
||||
Fee (in DRAGONX/kB) to add to transactions you send (default: 0.00)
|
||||
.HP
|
||||
\fB\-keepnotewitnesscache\fR
|
||||
.IP
|
||||
@@ -485,7 +515,7 @@ mined will become invalid (default: 200)
|
||||
.HP
|
||||
\fB\-maxtxfee=\fR<amt>
|
||||
.IP
|
||||
Maximum total fees (in HUSH) to use in a single wallet transaction;
|
||||
Maximum total fees (in DRAGONX) to use in a single wallet transaction;
|
||||
setting this too low may abort large transactions (default: 0.10)
|
||||
.HP
|
||||
\fB\-upgradewallet\fR
|
||||
@@ -554,8 +584,8 @@ 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)
|
||||
Fees (in DRAGONX/kB) smaller than this are considered zero fee for
|
||||
relaying (default: 0.000001)
|
||||
.HP
|
||||
\fB\-printtoconsole\fR
|
||||
.IP
|
||||
@@ -804,25 +834,22 @@ Starting supply, default is 10
|
||||
\fB\-ac_txpow\fR
|
||||
.IP
|
||||
Enforce transaction\-rate limit, default 0
|
||||
.PP
|
||||
.SH COPYRIGHT
|
||||
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
DragonX, please see <https://dragonx.is/security/>.
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2024\-2026 The DragonX Developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2016\-2024 Duke Leto and The Hush Developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2016\-2020 jl777 and SuperNET developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2016\-2018 The Zcash developers
|
||||
.PP
|
||||
.br
|
||||
Copyright \(co 2009\-2014 The Bitcoin Core developers
|
||||
.PP
|
||||
|
||||
Copyright (C) 2024-2026 The DragonX Developers
|
||||
|
||||
Copyright (C) 2016-2024 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!!!!!
|
||||
.PP
|
||||
|
||||
Distributed under the GPLv3 software license, see the accompanying file COPYING
|
||||
or <https://www.gnu.org/licenses/gpl\-3.0.en.html>.
|
||||
or <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
||||
|
||||
@@ -1,296 +0,0 @@
|
||||
<!-- Creator : groff version 1.23.0 -->
|
||||
<!-- CreationDate: Mon Jan 5 14:12:33 2026 -->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content="groff -Thtml, see www.gnu.org">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
<meta name="Content-Style" content="text/css">
|
||||
<style type="text/css">
|
||||
p { margin-top: 0; margin-bottom: 0; vertical-align: top }
|
||||
pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
|
||||
table { margin-top: 0; margin-bottom: 0; vertical-align: top }
|
||||
h1 { text-align: center }
|
||||
</style>
|
||||
<title>HUSH-CLI</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1 align="center">HUSH-CLI</h1>
|
||||
|
||||
<a href="#NAME">NAME</a><br>
|
||||
<a href="#DESCRIPTION">DESCRIPTION</a><br>
|
||||
<a href="#Usage:">Usage:</a><br>
|
||||
<a href="#OPTIONS">OPTIONS</a><br>
|
||||
<a href="#COPYRIGHT">COPYRIGHT</a><br>
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
<h2>NAME
|
||||
<a name="NAME"></a>
|
||||
</h2>
|
||||
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">hush-cli -
|
||||
manual page for hush-cli v3.10.4</p>
|
||||
|
||||
<h2>DESCRIPTION
|
||||
<a name="DESCRIPTION"></a>
|
||||
</h2>
|
||||
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">Hush RPC client
|
||||
version v3.10.4-7e63e2f01-dirty</p>
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">In order to
|
||||
ensure you are adequately protecting your privacy when using
|
||||
Hush, please see <https://hush.is/security/>.</p>
|
||||
|
||||
<h3>Usage:
|
||||
<a name="Usage:"></a>
|
||||
</h3>
|
||||
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">hush-cli
|
||||
[options] <command> [params]</p>
|
||||
|
||||
<p style="margin-left:18%;">Send command to Hush</p>
|
||||
|
||||
<p style="margin-left:9%;">hush-cli [options] help</p>
|
||||
|
||||
<p style="margin-left:18%;">List commands</p>
|
||||
|
||||
<p style="margin-left:9%;">hush-cli [options] help
|
||||
<command></p>
|
||||
|
||||
<p style="margin-left:18%;">Get help for a command</p>
|
||||
|
||||
<h2>OPTIONS
|
||||
<a name="OPTIONS"></a>
|
||||
</h2>
|
||||
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="3%">
|
||||
|
||||
|
||||
<p style="margin-top: 1em">-?</p></td>
|
||||
<td width="88%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">This help
|
||||
message</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="15%">
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-conf=</b><file></p></td>
|
||||
<td width="76%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Specify
|
||||
configuration file (default: HUSH3.conf)</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="18%">
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-datadir=</b><dir></p></td>
|
||||
<td width="73%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Specify data
|
||||
directory (this path cannot use ’˜’)</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="10%">
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-testnet</b></p></td>
|
||||
<td width="81%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Use the test
|
||||
network</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="10%">
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-regtest</b></p></td>
|
||||
<td width="81%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">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.</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="20%">
|
||||
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-rpcconnect=</b><ip></p> </td>
|
||||
<td width="71%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Send commands
|
||||
to node running on <ip> (default: 127.0.0.1)</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="19%">
|
||||
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-rpcport=</b><port></p> </td>
|
||||
<td width="72%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Connect to
|
||||
JSON-RPC on <port> (default: 18030 )</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="10%">
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-rpcwait</b></p></td>
|
||||
<td width="81%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Wait for RPC
|
||||
server to start</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="19%">
|
||||
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-rpcuser=</b><user></p> </td>
|
||||
<td width="72%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Username for
|
||||
JSON-RPC connections</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="22%">
|
||||
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-rpcpassword=</b><pw></p> </td>
|
||||
<td width="69%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Password for
|
||||
JSON-RPC connections</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="27%">
|
||||
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-rpcclienttimeout=</b><n></p> </td>
|
||||
<td width="64%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Timeout in
|
||||
seconds during HTTP requests, or 0 for no timeout. (default:
|
||||
900)</p>
|
||||
|
||||
<table width="100%" border="0" rules="none" frame="void"
|
||||
cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="9%"></td>
|
||||
<td width="8%">
|
||||
|
||||
|
||||
<p style="margin-top: 1em"><b>-stdin</b></p></td>
|
||||
<td width="83%">
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-left:18%; margin-top: 1em">Read extra
|
||||
arguments from standard input, one per line until EOF/Ctrl-D
|
||||
(recommended for sensitive information such as
|
||||
passphrases)</p>
|
||||
|
||||
<h2>COPYRIGHT
|
||||
<a name="COPYRIGHT"></a>
|
||||
</h2>
|
||||
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">In order to
|
||||
ensure you are adequately protecting your privacy when using
|
||||
Hush, please see <https://hush.is/security/>.</p>
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">Copyright (C)
|
||||
2016-2025 Duke Leto and The Hush Developers</p>
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">Copyright (C)
|
||||
2016-2020 jl777 and SuperNET developers</p>
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">Copyright (C)
|
||||
2016-2018 The Zcash developers</p>
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">Copyright (C)
|
||||
2009-2014 The Bitcoin Core developers</p>
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">This is
|
||||
experimental Free Software! Fuck Yeah!!!!!</p>
|
||||
|
||||
<p style="margin-left:9%; margin-top: 1em">Distributed
|
||||
under the GPLv3 software license, see the accompanying file
|
||||
COPYING or
|
||||
<https://www.gnu.org/licenses/gpl-3.0.en.html>.</p>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
2681
doc/man/hushd.html
2681
doc/man/hushd.html
File diff suppressed because it is too large
Load Diff
@@ -489,7 +489,7 @@ if TARGET_WINDOWS
|
||||
dragonxd_SOURCES += bitcoind-res.rc
|
||||
endif
|
||||
|
||||
dragonxd_LDADD = \
|
||||
dragonxd_LDADD = $(LINK_GROUP_START) \
|
||||
$(LIBBITCOIN_SERVER) \
|
||||
$(LIBCURL) \
|
||||
$(LIBBITCOIN_COMMON) \
|
||||
@@ -527,6 +527,8 @@ if TARGET_LINUX
|
||||
dragonxd_LDADD += libcc.so $(LIBSECP256K1)
|
||||
endif
|
||||
|
||||
dragonxd_LDADD += $(LINK_GROUP_END)
|
||||
|
||||
# [+] Decker: use static linking for libstdc++.6.dylib, libgomp.1.dylib, libgcc_s.1.dylib
|
||||
if TARGET_DARWIN
|
||||
dragonxd_LDFLAGS += -static-libgcc
|
||||
@@ -553,7 +555,7 @@ if TARGET_WINDOWS
|
||||
dragonx_cli_SOURCES += bitcoin-cli-res.rc
|
||||
endif
|
||||
|
||||
dragonx_cli_LDADD = \
|
||||
dragonx_cli_LDADD = $(LINK_GROUP_START) \
|
||||
$(LIBBITCOIN_CLI) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
@@ -566,8 +568,10 @@ dragonx_cli_LDADD = \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
dragonx_cli_LDADD += $(LINK_GROUP_END)
|
||||
|
||||
if ENABLE_WALLET
|
||||
wallet_utility_LDADD = \
|
||||
wallet_utility_LDADD = $(LINK_GROUP_START) \
|
||||
libbitcoin_wallet.a \
|
||||
$(LIBBITCOIN_COMMON) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
@@ -579,6 +583,7 @@ wallet_utility_LDADD = \
|
||||
$(LIBZCASH) \
|
||||
$(LIBZCASH_LIBS)\
|
||||
$(LIBRANDOMX)
|
||||
wallet_utility_LDADD += $(LINK_GROUP_END)
|
||||
endif
|
||||
|
||||
# hush-tx binary #
|
||||
@@ -591,7 +596,7 @@ if TARGET_WINDOWS
|
||||
dragonx_tx_SOURCES += bitcoin-tx-res.rc
|
||||
endif
|
||||
|
||||
dragonx_tx_LDADD = \
|
||||
dragonx_tx_LDADD = $(LINK_GROUP_START) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBBITCOIN_COMMON) \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
@@ -602,7 +607,7 @@ dragonx_tx_LDADD = \
|
||||
$(LIBZCASH_LIBS) \
|
||||
$(LIBRANDOMX)
|
||||
|
||||
dragonx_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
|
||||
dragonx_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) $(LINK_GROUP_END)
|
||||
|
||||
# Zcash Protocol Primitives
|
||||
libzcash_a_SOURCES = \
|
||||
|
||||
140
src/addrman.cpp
140
src/addrman.cpp
@@ -473,11 +473,6 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
|
||||
if (size() == 0)
|
||||
return CAddrInfo();
|
||||
|
||||
// Track number of attempts to find a table entry, before giving up to avoid infinite loop
|
||||
const int kMaxRetries = 200000; // magic number so unit tests can pass
|
||||
const int kRetriesBetweenSleep = 1000;
|
||||
const int kRetrySleepInterval = 100; // milliseconds
|
||||
|
||||
if (newOnly && nNew == 0)
|
||||
return CAddrInfo();
|
||||
|
||||
@@ -485,89 +480,72 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
|
||||
if (!newOnly &&
|
||||
(nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) {
|
||||
// use a tried node
|
||||
double fChanceFactor = 1.0;
|
||||
double fReachableFactor = 1.0;
|
||||
double fJustTried = 1.0;
|
||||
while (1) {
|
||||
if (ShutdownRequested()) //break loop on shutdown request
|
||||
return CAddrInfo();
|
||||
|
||||
int i = 0;
|
||||
int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT);
|
||||
int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
|
||||
while (vvTried[nKBucket][nKBucketPos] == -1) {
|
||||
nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT;
|
||||
nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE;
|
||||
if (i++ > kMaxRetries)
|
||||
return CAddrInfo();
|
||||
if (i % kRetriesBetweenSleep == 0 && !nKey.IsNull())
|
||||
MilliSleep(kRetrySleepInterval);
|
||||
}
|
||||
int nId = vvTried[nKBucket][nKBucketPos];
|
||||
// assert(mapInfo.count(nId) == 1);
|
||||
if(mapInfo.count(nId) != 1) {
|
||||
fprintf(stderr,"%s: Could not find tried node with nId=%d=vvTried[%d][%d], mapInfo.count(%d)=%lu\n", __func__, nId, nKBucket, nKBucketPos, nId, mapInfo.count(nId) );
|
||||
continue;
|
||||
}
|
||||
|
||||
CAddrInfo& info = mapInfo[nId];
|
||||
if (info.IsReachableNetwork()) {
|
||||
//deprioritize unreachable networks
|
||||
fReachableFactor = 0.25;
|
||||
}
|
||||
if (info.IsJustTried()) {
|
||||
//deprioritize entries just tried
|
||||
fJustTried = 0.10;
|
||||
}
|
||||
if (RandomInt(1 << 30) < fChanceFactor * fReachableFactor * fJustTried * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
return SelectFromTable_(vvTried, ADDRMAN_TRIED_BUCKET_COUNT, "tried");
|
||||
} else {
|
||||
// use a new node
|
||||
double fChanceFactor = 1.0;
|
||||
double fReachableFactor = 1.0;
|
||||
double fJustTried = 1.0;
|
||||
while (1) {
|
||||
if (ShutdownRequested()) //break loop on shutdown request
|
||||
return CAddrInfo();
|
||||
|
||||
int i = 0;
|
||||
int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);
|
||||
int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
|
||||
while (vvNew[nUBucket][nUBucketPos] == -1) {
|
||||
nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT;
|
||||
nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE;
|
||||
if (i++ > kMaxRetries)
|
||||
return CAddrInfo();
|
||||
if (i % kRetriesBetweenSleep == 0 && !nKey.IsNull())
|
||||
MilliSleep(kRetrySleepInterval);
|
||||
}
|
||||
int nId = vvNew[nUBucket][nUBucketPos];
|
||||
|
||||
if(mapInfo.count(nId) != 1) {
|
||||
fprintf(stderr,"%s: Could not find new node with nId=%d=vvNew[%d][%d], mapInfo.count(%d)=%lu\n", __func__, nId, nUBucket, nUBucketPos, nId, mapInfo.count(nId) );
|
||||
continue;
|
||||
}
|
||||
// assert(mapInfo.count(nId) == 1);
|
||||
CAddrInfo& info = mapInfo[nId];
|
||||
if (info.IsReachableNetwork()) {
|
||||
//deprioritize unreachable networks
|
||||
fReachableFactor = 0.25;
|
||||
}
|
||||
if (info.IsJustTried()) {
|
||||
//deprioritize entries just tried
|
||||
fJustTried = 0.10;
|
||||
}
|
||||
if (RandomInt(1 << 30) < fChanceFactor * fReachableFactor * fJustTried * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
return SelectFromTable_(vvNew, ADDRMAN_NEW_BUCKET_COUNT, "new");
|
||||
}
|
||||
|
||||
return CAddrInfo();
|
||||
}
|
||||
|
||||
// Random-walk one addrman bucket table (tried or new) and return an accepted peer,
|
||||
// applying the reachable/just-tried deprioritization and the growing chance factor.
|
||||
// Extracted verbatim from Select_'s two previously copy-pasted branches; the only
|
||||
// differences were the table (vvTried/vvNew), its bucket count, and the log label.
|
||||
CAddrInfo CAddrMan::SelectFromTable_(int (*vvTable)[ADDRMAN_BUCKET_SIZE], int nBucketCount, const char *tableName)
|
||||
{
|
||||
// Track number of attempts to find a table entry, before giving up to avoid infinite loop
|
||||
const int kMaxRetries = 200000; // magic number so unit tests can pass
|
||||
const int kRetriesBetweenSleep = 1000;
|
||||
const int kRetrySleepInterval = 100; // milliseconds
|
||||
|
||||
// Peer-selection tuning factors (networking heuristics, not consensus).
|
||||
const double kChanceFactorGrowth = 1.2;
|
||||
const double kUnreachableDeprioritize = 0.25;
|
||||
const double kJustTriedDeprioritize = 0.10;
|
||||
const int kChanceScale = 1 << 30;
|
||||
|
||||
double fChanceFactor = 1.0;
|
||||
double fReachableFactor = 1.0;
|
||||
double fJustTried = 1.0;
|
||||
while (1) {
|
||||
if (ShutdownRequested()) //break loop on shutdown request
|
||||
return CAddrInfo();
|
||||
|
||||
int i = 0;
|
||||
int nKBucket = RandomInt(nBucketCount);
|
||||
int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
|
||||
while (vvTable[nKBucket][nKBucketPos] == -1) {
|
||||
nKBucket = (nKBucket + insecure_rand()) % nBucketCount;
|
||||
nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE;
|
||||
if (i++ > kMaxRetries)
|
||||
return CAddrInfo();
|
||||
if (i % kRetriesBetweenSleep == 0 && !nKey.IsNull())
|
||||
MilliSleep(kRetrySleepInterval);
|
||||
}
|
||||
int nId = vvTable[nKBucket][nKBucketPos];
|
||||
// assert(mapInfo.count(nId) == 1);
|
||||
if(mapInfo.count(nId) != 1) {
|
||||
fprintf(stderr,"%s: Could not find %s node with nId=%d=vvTable[%d][%d], mapInfo.count(%d)=%lu\n", __func__, tableName, nId, nKBucket, nKBucketPos, nId, mapInfo.count(nId) );
|
||||
continue;
|
||||
}
|
||||
|
||||
CAddrInfo& info = mapInfo[nId];
|
||||
if (info.IsReachableNetwork()) {
|
||||
//deprioritize unreachable networks
|
||||
fReachableFactor = kUnreachableDeprioritize;
|
||||
}
|
||||
if (info.IsJustTried()) {
|
||||
//deprioritize entries just tried
|
||||
fJustTried = kJustTriedDeprioritize;
|
||||
}
|
||||
if (RandomInt(kChanceScale) < fChanceFactor * fReachableFactor * fJustTried * info.GetChance() * kChanceScale)
|
||||
return info;
|
||||
fChanceFactor *= kChanceFactorGrowth;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ADDRMAN
|
||||
int CAddrMan::Check_()
|
||||
{
|
||||
|
||||
@@ -300,6 +300,10 @@ protected:
|
||||
//! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
|
||||
CAddrInfo Select_(bool newOnly);
|
||||
|
||||
//! Random-walk one bucket table (tried or new) and return an accepted peer.
|
||||
//! Shared implementation for Select_'s two (previously copy-pasted) branches.
|
||||
CAddrInfo SelectFromTable_(int (*vvTable)[ADDRMAN_BUCKET_SIZE], int nBucketCount, const char *tableName);
|
||||
|
||||
//! Wraps GetRandInt to allow tests to override RandomInt and make it deterministic.
|
||||
virtual int RandomInt(int nMax);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "asyncrpcoperation.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
@@ -58,6 +59,31 @@ AsyncRPCOperation::AsyncRPCOperation(const AsyncRPCOperation& o) :
|
||||
{
|
||||
}
|
||||
|
||||
// Shared error mapping for every async op's main(): rethrow the in-flight
|
||||
// exception and translate it to this operation's error code/message. Keeping
|
||||
// it here means the mapping is edited in one place, not copy-pasted into six.
|
||||
void AsyncRPCOperation::set_error_from_current_exception()
|
||||
{
|
||||
try {
|
||||
throw;
|
||||
} catch (const UniValue& objError) {
|
||||
set_error_code(find_value(objError, "code").get_int());
|
||||
set_error_message(find_value(objError, "message").get_str());
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
AsyncRPCOperation& AsyncRPCOperation::operator=( const AsyncRPCOperation& other ) {
|
||||
this->id_ = other.id_;
|
||||
this->creation_time_ = other.creation_time_;
|
||||
|
||||
@@ -147,6 +147,11 @@ protected:
|
||||
std::lock_guard<std::mutex> guard(lock_);
|
||||
this->error_message_ = errorMessage;
|
||||
}
|
||||
|
||||
// Map the in-flight (rethrown) exception to error_code_/error_message_. Called from
|
||||
// every async op's main() catch(...) so the UniValue/runtime/logic/exception mapping
|
||||
// lives in one place instead of being copy-pasted into all six operations.
|
||||
void set_error_from_current_exception();
|
||||
|
||||
void set_result(UniValue v) {
|
||||
std::lock_guard<std::mutex> guard(lock_);
|
||||
|
||||
@@ -96,18 +96,21 @@ void AsyncRPCQueue::run(size_t workerId) {
|
||||
*
|
||||
* Don't use std::make_shared<AsyncRPCOperation>().
|
||||
*/
|
||||
void AsyncRPCQueue::addOperation(const std::shared_ptr<AsyncRPCOperation> &ptrOperation) {
|
||||
bool AsyncRPCQueue::addOperation(const std::shared_ptr<AsyncRPCOperation> &ptrOperation) {
|
||||
std::lock_guard<std::mutex> guard(lock_);
|
||||
|
||||
// Don't add if queue is closed or finishing
|
||||
// Don't add if queue is closed or finishing. Report it: silently dropping the
|
||||
// operation made callers announce work that would never run.
|
||||
// (isClosed/isFinishing read atomics, so calling them under the guard is safe.)
|
||||
if (isClosed() || isFinishing()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncRPCOperationId id = ptrOperation->getId();
|
||||
operation_map_.emplace(id, ptrOperation);
|
||||
operation_id_queue_.push(id);
|
||||
this->condition_.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,7 +63,12 @@ public:
|
||||
size_t getOperationCount() const;
|
||||
std::shared_ptr<AsyncRPCOperation> getOperationForId(AsyncRPCOperationId) const;
|
||||
std::shared_ptr<AsyncRPCOperation> popOperationForId(AsyncRPCOperationId);
|
||||
void addOperation(const std::shared_ptr<AsyncRPCOperation> &ptrOperation);
|
||||
// Returns false if the queue is closed or finishing, in which case the
|
||||
// operation was NOT queued and will never run. Callers must react: a caller
|
||||
// that ignores this both reports success for work that will not happen and
|
||||
// leaves any state it set for the operation (running flags, coin locks)
|
||||
// stranded for the life of the process.
|
||||
bool addOperation(const std::shared_ptr<AsyncRPCOperation> &ptrOperation);
|
||||
std::vector<AsyncRPCOperationId> getAllOperationIds() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -41,7 +41,11 @@
|
||||
|
||||
/// \cond INTERNAL
|
||||
#define CC_MAXVINS 1024
|
||||
#define CC_REQUIREMENTS_MSG (HUSH_NSPV_SUPERLITE?"to use CC contracts you need to nspv_login first\n":"to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n")
|
||||
// NOTE: CryptoConditions (CC) contracts are inherited from the Komodo/Hush lineage and are
|
||||
// largely vestigial on DragonX (ac_private=1 fully-shielded chain). This user-facing message
|
||||
// still describes the legacy prerequisites for using CC contracts (nspv_login in superlite
|
||||
// mode, or launching dragonxd with a valid -pubkey=).
|
||||
#define CC_REQUIREMENTS_MSG (HUSH_NSPV_SUPERLITE?"to use CC contracts you need to nspv_login first\n":"to use CC contracts, you need to launch dragonxd with valid -pubkey= for an address in your wallet\n")
|
||||
|
||||
#define SMALLVAL 0.000000000000001
|
||||
#define SATOSHIDEN ((uint64_t)100000000L)
|
||||
@@ -58,7 +62,8 @@ struct CC_utxo
|
||||
/// \endcond
|
||||
|
||||
|
||||
/// CC contract (Antara module) info structure that contains data used for signing and validation of cc contract transactions
|
||||
/// CC (CryptoConditions) contract info structure that contains data used for signing and validation of cc contract transactions.
|
||||
/// NOTE: the CC framework (historically called "Antara modules" in the Komodo/Hush lineage) is largely vestigial on DragonX.
|
||||
struct CCcontract_info
|
||||
{
|
||||
uint8_t evalcode; //!< cc contract eval code, set by CCinit function
|
||||
@@ -101,7 +106,7 @@ struct CCcontract_info
|
||||
bool(*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
/// checks if the value of evalcode in cp object is present in the scriptSig parameter,
|
||||
/// that is, the vin for this scriptSig will be validated by the cc contract (Antara module) defined by the eval code in this CCcontract_info object
|
||||
/// that is, the vin for this scriptSig will be validated by the cc contract defined by the eval code in this CCcontract_info object
|
||||
/// @param scriptSig scriptSig to check\n
|
||||
/// Example:
|
||||
/// \code
|
||||
@@ -283,7 +288,7 @@ bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector<CPubKey> &vin
|
||||
/// cp = CCinit(&C, EVAL_ASSETS);
|
||||
/// CPubKey ccAssetsPk = GetUnspendable(cp, ccAssetsPriv);
|
||||
/// \endcode
|
||||
/// Now ccAssetsPk has Antara 'Assets' module global pubkey and ccAssetsPriv has its publicly available private key
|
||||
/// Now ccAssetsPk has the 'Assets' CC module global pubkey and ccAssetsPriv has its publicly available private key
|
||||
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
|
||||
|
||||
// CCutils
|
||||
@@ -373,7 +378,7 @@ int64_t CCfullsupply(uint256 tokenid);
|
||||
/// @returns true if success
|
||||
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
|
||||
|
||||
/// Returns my pubkey, that is set by -pubkey hushd parameter
|
||||
/// Returns my pubkey, that is set by the -pubkey dragonxd parameter
|
||||
/// @returns public key as byte array
|
||||
std::vector<uint8_t> Mypubkey();
|
||||
|
||||
@@ -404,8 +409,8 @@ extern std::vector<CPubKey> NULL_pubkeys; //!< constant value for use in functio
|
||||
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret,std::vector<CPubKey> pubkeys = NULL_pubkeys);
|
||||
|
||||
/// FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and might add an opreturn output.
|
||||
/// This allows for Antara module transaction creation rpc functions to create an CMutableTransaction object, add the appropriate vins and vouts to it and use FinalizeCCTx to properly sign the transaction.
|
||||
/// By using -addressindex=1 of hushd daemon, it allows tracking of all the CC addresses.
|
||||
/// This allows for CC module transaction creation rpc functions to create an CMutableTransaction object, add the appropriate vins and vouts to it and use FinalizeCCTx to properly sign the transaction.
|
||||
/// By using -addressindex=1 of the dragonxd daemon, it allows tracking of all the CC addresses.
|
||||
///
|
||||
/// For signing the vins the function builds several default probe scriptPubKeys and checks them against the referred previous transactions (vintx) vouts.
|
||||
/// For cryptocondition vins the function creates a basic set of probe cryptconditions with mypk and module global pubkey, both for coins and tokens cases.
|
||||
@@ -473,7 +478,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
|
||||
int64_t AddNormalinputsLocal(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs);
|
||||
|
||||
/// AddNormalinputs2 adds normal (not cc) inputs to the transaction object vin array for the specified total amount using utxos on my pubkey's TX_PUBKEY address (my pubkey is set by -pubkey command line parameter), to fund the transaction.
|
||||
/// 'My pubkey' is the -pubkey parameter of hushd.
|
||||
/// 'My pubkey' is the -pubkey parameter of dragonxd.
|
||||
/// @param mtx mutable transaction object
|
||||
/// @param total amount of inputs to add. If total equals to 0 the function does not add inputs but returns amount of all available normal inputs in the wallet
|
||||
/// @param maxinputs maximum number of inputs to add
|
||||
|
||||
@@ -72,11 +72,6 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *
|
||||
abovei = belowi = -1;
|
||||
for (above=below=i=0; i<numunspents; i++)
|
||||
{
|
||||
// Filter to randomly pick utxo to avoid conflicts, and having multiple CC choose the same ones.
|
||||
//if ( numunspents > 200 ) {
|
||||
// if ( (rand() % 100) < 90 )
|
||||
// continue;
|
||||
//}
|
||||
if ( (atx_value= utxos[i].nValue) <= 0 )
|
||||
continue;
|
||||
if ( atx_value == value )
|
||||
@@ -103,13 +98,11 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *
|
||||
belowi = i;
|
||||
}
|
||||
}
|
||||
//printf("value %.8f gap %.8f abovei.%d %.8f belowi.%d %.8f\n",dstr(value),dstr(gap),abovei,dstr(above),belowi,dstr(below));
|
||||
}
|
||||
*aboveip = abovei;
|
||||
*abovep = above;
|
||||
*belowip = belowi;
|
||||
*belowp = below;
|
||||
//printf("above.%d below.%d\n",abovei,belowi);
|
||||
if ( abovei >= 0 && belowi >= 0 )
|
||||
{
|
||||
if ( above < (below >> 1) )
|
||||
@@ -127,8 +120,6 @@ int64_t AddNormalinputsLocal(CMutableTransaction &mtx,CPubKey mypk,int64_t total
|
||||
if ( HUSH_NSPV_SUPERLITE )
|
||||
return(NSPV_AddNormalinputs(mtx,mypk,total,maxinputs,&NSPV_U));
|
||||
|
||||
// if (mypk != pubkey2pk(Mypubkey())) //remote superlite mypk, do not use wallet since it is not locked for non-equal pks (see rpcs with nspv support)!
|
||||
// return(AddNormalinputs3(mtx, mypk, total, maxinputs));
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
assert(pwalletMain != NULL);
|
||||
@@ -150,7 +141,6 @@ int64_t AddNormalinputsLocal(CMutableTransaction &mtx,CPubKey mypk,int64_t total
|
||||
vout = out.i;
|
||||
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
{
|
||||
//fprintf(stderr,"check %.8f to vins array.%d of %d %s/v%d\n",(double)out.tx->vout[out.i].nValue/COIN,n,maxutxos,txid.GetHex().c_str(),(int32_t)vout);
|
||||
if ( mtx.vin.size() > 0 )
|
||||
{
|
||||
for (i=0; i<mtx.vin.size(); i++)
|
||||
@@ -174,7 +164,6 @@ int64_t AddNormalinputsLocal(CMutableTransaction &mtx,CPubKey mypk,int64_t total
|
||||
up->nValue = out.tx->vout[out.i].nValue;
|
||||
up->vout = vout;
|
||||
sum += up->nValue;
|
||||
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
|
||||
if ( n >= maxinputs || sum >= total )
|
||||
break;
|
||||
}
|
||||
@@ -207,14 +196,12 @@ int64_t AddNormalinputsLocal(CMutableTransaction &mtx,CPubKey mypk,int64_t total
|
||||
remains -= up->nValue;
|
||||
utxos[ind] = utxos[--n];
|
||||
memset(&utxos[n],0,sizeof(utxos[n]));
|
||||
//fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs);
|
||||
if ( totalinputs >= total || (i+1) >= maxinputs )
|
||||
break;
|
||||
}
|
||||
free(utxos);
|
||||
if ( totalinputs >= total )
|
||||
{
|
||||
//fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN);
|
||||
return(totalinputs);
|
||||
}
|
||||
#endif
|
||||
@@ -252,7 +239,6 @@ int64_t AddNormalinputsRemote(CMutableTransaction &mtx, CPubKey mypk, int64_t to
|
||||
continue;
|
||||
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
{
|
||||
//fprintf(stderr,"check %.8f to vins array.%d of %d %s/v%d\n",(double)out.tx->vout[out.i].nValue/COIN,n,maxutxos,txid.GetHex().c_str(),(int32_t)vout);
|
||||
if ( mtx.vin.size() > 0 )
|
||||
{
|
||||
for (i=0; i<mtx.vin.size(); i++)
|
||||
@@ -276,7 +262,6 @@ int64_t AddNormalinputsRemote(CMutableTransaction &mtx, CPubKey mypk, int64_t to
|
||||
up->nValue = it->second.satoshis;
|
||||
up->vout = vout;
|
||||
sum += up->nValue;
|
||||
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
|
||||
if ( n >= maxinputs || sum >= total )
|
||||
break;
|
||||
}
|
||||
@@ -308,14 +293,12 @@ int64_t AddNormalinputsRemote(CMutableTransaction &mtx, CPubKey mypk, int64_t to
|
||||
remains -= up->nValue;
|
||||
utxos[ind] = utxos[--n];
|
||||
memset(&utxos[n],0,sizeof(utxos[n]));
|
||||
//fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs);
|
||||
if ( totalinputs >= total || (i+1) >= maxinputs )
|
||||
break;
|
||||
}
|
||||
free(utxos);
|
||||
if ( totalinputs >= total )
|
||||
{
|
||||
//fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN);
|
||||
return(totalinputs);
|
||||
}
|
||||
return(0);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "CCinclude.h"
|
||||
#include "hush_structs.h"
|
||||
#include "key_io.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef TESTMODE
|
||||
#define MIN_NON_NOTARIZED_CONFIRMS 2
|
||||
@@ -46,7 +47,6 @@ int32_t has_opret(const CTransaction &tx, uint8_t evalcode)
|
||||
int i = 0;
|
||||
for ( auto vout : tx.vout )
|
||||
{
|
||||
//fprintf(stderr, "[txid.%s] 1.%i 2.%i 3.%i 4.%i\n",tx.GetHash().GetHex().c_str(), vout.scriptPubKey[0], vout.scriptPubKey[1], vout.scriptPubKey[2], vout.scriptPubKey[3]);
|
||||
if ( vout.scriptPubKey.size() > 3 && vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[2] == evalcode )
|
||||
return i;
|
||||
i++;
|
||||
@@ -88,7 +88,6 @@ bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_
|
||||
actualtxfee = valuein-tx.GetValueOut();
|
||||
if ( actualtxfee > txfee )
|
||||
{
|
||||
//fprintf(stderr, "actualtxfee.%li vs txfee.%li\n", actualtxfee, txfee);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -112,7 +111,6 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"ExtractDestination failed\n");
|
||||
return(false);
|
||||
}
|
||||
|
||||
@@ -202,17 +200,17 @@ bool hush_txnotarizedconfirmed(uint256 txid)
|
||||
{
|
||||
if ( NSPV_myGetTransaction(txid,tx,hashBlock,txheight,currentheight) == 0 )
|
||||
{
|
||||
fprintf(stderr,"hush_txnotarizedconfirmed cant find txid %s\n",txid.ToString().c_str());
|
||||
LogPrintf("hush_txnotarizedconfirmed cant find txid %s\n",txid.ToString().c_str());
|
||||
return(0);
|
||||
}
|
||||
else if (txheight<=0)
|
||||
{
|
||||
fprintf(stderr,"hush_txnotarizedconfirmed no txheight.%d for txid %s\n",txheight,txid.ToString().c_str());
|
||||
LogPrintf("hush_txnotarizedconfirmed no txheight.%d for txid %s\n",txheight,txid.ToString().c_str());
|
||||
return(0);
|
||||
}
|
||||
else if (txheight>currentheight)
|
||||
{
|
||||
fprintf(stderr,"hush_txnotarizedconfirmed backwards heights for txid %s hts.(%d %d)\n",txid.ToString().c_str(),txheight,currentheight);
|
||||
LogPrintf("hush_txnotarizedconfirmed backwards heights for txid %s hts.(%d %d)\n",txid.ToString().c_str(),txheight,currentheight);
|
||||
return(0);
|
||||
}
|
||||
confirms=1 + currentheight - txheight;
|
||||
@@ -221,24 +219,24 @@ bool hush_txnotarizedconfirmed(uint256 txid)
|
||||
{
|
||||
if ( myGetTransaction(txid,tx,hashBlock) == 0 )
|
||||
{
|
||||
fprintf(stderr,"hush_txnotarizedconfirmed cant find txid %s\n",txid.ToString().c_str());
|
||||
LogPrintf("hush_txnotarizedconfirmed cant find txid %s\n",txid.ToString().c_str());
|
||||
return(0);
|
||||
}
|
||||
else if ( hashBlock == zeroid )
|
||||
{
|
||||
fprintf(stderr,"hush_txnotarizedconfirmed no hashBlock for txid %s\n",txid.ToString().c_str());
|
||||
LogPrintf("hush_txnotarizedconfirmed no hashBlock for txid %s\n",txid.ToString().c_str());
|
||||
return(0);
|
||||
}
|
||||
else if ( (pindex= hush_blockindex(hashBlock)) == 0 || (txheight= pindex->GetHeight()) <= 0 )
|
||||
{
|
||||
fprintf(stderr,"hush_txnotarizedconfirmed no txheight.%d %p for txid %s\n",txheight,pindex,txid.ToString().c_str());
|
||||
LogPrintf("hush_txnotarizedconfirmed no txheight.%d %p for txid %s\n",txheight,pindex,txid.ToString().c_str());
|
||||
return(0);
|
||||
}
|
||||
else if ( (pindex= chainActive.LastTip()) == 0 || pindex->GetHeight() < txheight )
|
||||
{
|
||||
fprintf(stderr,"hush_txnotarizedconfirmed backwards heights for txid %s hts.(%d %d)\n",txid.ToString().c_str(),txheight,(int32_t)pindex->GetHeight());
|
||||
LogPrintf("hush_txnotarizedconfirmed backwards heights for txid %s hts.(%d %d)\n",txid.ToString().c_str(),txheight,(int32_t)pindex->GetHeight());
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
confirms=1 + pindex->GetHeight() - txheight;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "main.h"
|
||||
#include "chain.h"
|
||||
#include "core_io.h"
|
||||
#define FAUCET2SIZE COIN
|
||||
#define EVAL_FAUCET2 EVAL_FIRSTUSER
|
||||
|
||||
#ifdef BUILD_CUSTOMCC
|
||||
|
||||
Binary file not shown.
@@ -1,20 +0,0 @@
|
||||
# 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
|
||||
# Just type make to compile all dat dapp code, fellow cypherpunkz
|
||||
|
||||
# we no longer build zmigrate by default, nobody uses that fucking code
|
||||
all: hushdex
|
||||
|
||||
hushdex:
|
||||
$(CC) hushdex.c -o hushdex -lm
|
||||
|
||||
# Just for historical knowledge, to study how fucking stupid
|
||||
# ZEC+KMD were to still support sprout, to this day!!!!!!!!
|
||||
# Hush leads the entire world into the future, sans Sprout turdz
|
||||
zmigrate:
|
||||
$(CC) zmigrate.c -o zmigrate -lm
|
||||
|
||||
clean:
|
||||
rm zmigrate
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
# CryptoCondition dApps
|
||||
|
||||
## Compiling
|
||||
|
||||
To compile all dapps in this directory:
|
||||
|
||||
make
|
||||
|
||||
## zmigrate - Sprout to Sapling Migration dApp
|
||||
|
||||
This tool converts Sprout zaddress funds into Sapling funds in a new Sapling address.
|
||||
This is not applicable to HUSH3, since we have no Sprout funds, but left for historical
|
||||
purposes.
|
||||
|
||||
### Usage
|
||||
|
||||
./zmigrate COIN zsaplingaddr
|
||||
|
||||
The above command may need to be run multiple times to complete the process.
|
||||
|
||||
This CLI implementation will be called by GUI wallets, average users do not
|
||||
need to worry about using this low-level tool.
|
||||
|
||||
## HushDEX
|
||||
|
||||
HushDEX forked from the Subatomic Decentralized App (dapp) and we focus purely
|
||||
on privacy coin swaps, and specifically, shielded swaps between Zcash Protocol
|
||||
coins. These are called z-swaps.
|
||||
|
||||
### Z-swap example
|
||||
|
||||
Alice has 1 ZEC and wants to trade it for 5 HUSH, since she hears HushChat is
|
||||
pretty awesome and ZEC just goes down in price, always. We represent this in
|
||||
a diagram like this
|
||||
|
||||
Alice (ZEC) <> Bob (HUSH)
|
||||
|
||||
HushDEX is only concerns with Sapling shielded addresses (zaddrs) which start
|
||||
with `zs1`. Even though ZEC supports Sprout addresses (which start with `zc`),
|
||||
they cannot be used on HushDEX. Sprout is unsupported on HushDEX.
|
||||
|
||||
So Alice must make sure her ZEC is in a Sapling zaddr, and then she can use
|
||||
HushDEX on her computer, to z-swap with Bob, in a decentralized way, with
|
||||
no centralized service. The system is not completely trustless, users must
|
||||
trust the developers and miners on the relevant chains to not do nefarious
|
||||
things. There is no central authority to decide who gets to do what, it's
|
||||
peer-to-peer like BitTorrent or Tor.
|
||||
|
||||
### Privacy Features of Z-Swaps
|
||||
|
||||
* No KYC
|
||||
* We will not feed the identity theft industry any more free data
|
||||
* No IP address limiting
|
||||
* It is trivial to pay for an IP address from any country in the world
|
||||
* Alice's address never appears in public data
|
||||
* Bob's address never appears in public data
|
||||
* Consequently, Alice and Bob's address cannot be searched for on an explorer
|
||||
* Since you can't see the address of any transaction, you cannot infer if
|
||||
the same address appears as sender or receiver in many transactions.
|
||||
* The amount of the transaction, how much ZEC and how much HUSH, is unknown
|
||||
* It could be pennies or millions
|
||||
* The exchange rate of the transaction never appears on the blockchain
|
||||
* The exchange rate will be leaked to the network p2p layer, but it is never
|
||||
recorded in blockchain history. If you are not there to record it, it is gone.
|
||||
* Realistically, it's simple to run a malicious node which records all exchange rates
|
||||
and so we assume an adversary does this
|
||||
* Since the exchange rate of ZEC/HUSH is already public data, this is not considered valuable
|
||||
information leakage. We are leaking the differential of CEX ZEC/HUSH exchange ratio to
|
||||
this DEX's ratio.
|
||||
* Adversaries watching all possible public data can infer exchange ratios but no amounts
|
||||
or addresses, which is considered a massive blow against blockchain analysis.
|
||||
|
||||
1201
src/cc/dapps/cJSON.c
1201
src/cc/dapps/cJSON.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"authorized": [
|
||||
{"dukeleto":"030554bffcf6dfcb34a20c486ff0a5be5546b9cc16fba969216527263f8e98c4af" },
|
||||
{"gilardh":"020554bffcf6dfcb34a20c486ff5a5be5546b9cc06fba9692165272b3f8e98c448" },
|
||||
{"nhdigitalcash":"030554bffcf6dfcb34a20c086ff5a5be5546b9cc16fba9692105272b3f8e98c4a0" },
|
||||
{"miodrag":"02b25de3ee5335518b06f69f4fbabb029cfc737603b100996841d5532b324a5a61" }
|
||||
],
|
||||
"tokens":[
|
||||
],
|
||||
"files":[
|
||||
{"filename":"hushd","prices":[{"HUSH":0.1}, {"ZEC":1}]}
|
||||
],
|
||||
"externalcoins":[
|
||||
{ "BTC":"bitcoin-cli" },
|
||||
{ "HUSH":"hush-cli" },
|
||||
{ "ZEC":"zcash-cli" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
gcc -o oraclefeed cc/dapps/oraclefeed.c -lm
|
||||
gcc -o zmigrate cc/dapps/zmigrate.c -lm
|
||||
File diff suppressed because it is too large
Load Diff
@@ -80,21 +80,6 @@ public:
|
||||
bool Error(std::string s) { return state.Error(s); }
|
||||
bool Valid() { return true; }
|
||||
|
||||
/*
|
||||
* Dispute a payout using a VM
|
||||
*/
|
||||
bool DisputePayout(AppVM &vm, std::vector<uint8_t> params, const CTransaction &disputeTx, unsigned int nIn);
|
||||
|
||||
/*
|
||||
* Test an ImportPayout CC Eval condition
|
||||
*/
|
||||
bool ImportPayout(std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn);
|
||||
|
||||
/*
|
||||
* Import coin from another chain with same symbol
|
||||
*/
|
||||
bool ImportCoin(std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn);
|
||||
|
||||
/*
|
||||
* IO functions
|
||||
*/
|
||||
@@ -281,7 +266,6 @@ typedef std::pair<uint256,MerkleBranch> TxProof;
|
||||
|
||||
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves);
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode);
|
||||
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull, const CTransaction &tx, unsigned int nIn);
|
||||
|
||||
|
||||
#endif /* CC_EVAL_H */
|
||||
|
||||
@@ -148,6 +148,12 @@ public:
|
||||
nMinerThreads = 0;
|
||||
nMaxTipAge = 24 * 60 * 60;
|
||||
nPruneAfterHeight = 100000;
|
||||
// NOTE: These Equihash parameters and the literal Bitcoin genesis block below are
|
||||
// inherited from the upstream (Zcash/Komodo) CMainParams and are NOT what DragonX
|
||||
// mines under. DragonX is a RandomX CPU-mining chain whose real PoW and chain
|
||||
// parameters are set for its SMART_CHAIN_SYMBOL at runtime (see hush_utils.h and
|
||||
// chainparams_commandline()). They are retained here for upstream-diff hygiene and
|
||||
// genesis fixity; do not "fix" them to RandomX values.
|
||||
const size_t N = 200, K = 9;
|
||||
BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K));
|
||||
nEquihashN = N;
|
||||
@@ -181,11 +187,29 @@ public:
|
||||
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
|
||||
vFixedSeeds.clear();
|
||||
vSeeds.clear();
|
||||
// Hush Official DNS Seeds
|
||||
vSeeds.push_back(CDNSSeedData("node1", "seed1.hush.is"));
|
||||
vSeeds.push_back(CDNSSeedData("node2", "seed2.hush.is"));
|
||||
// Community run DNS Seeds
|
||||
vSeeds.push_back(CDNSSeedData("node3", "dns.leto.net"));
|
||||
// DragonX DNS seeds. These must be names that actually resolve.
|
||||
//
|
||||
// An assetchain INHERITS these: chainparams_commandline() sets the port, magic,
|
||||
// blocktime, upgrade heights and checkpoints, but never touches vSeeds or
|
||||
// vFixedSeeds. DRAGONX therefore ran on Hush's seeds -- seed1.hush.is,
|
||||
// seed2.hush.is and dns.leto.net -- and all three have no A records left, so DNS
|
||||
// seeding silently returned zero addresses on every start. The only bootstrap
|
||||
// path that worked was the node1..node5.dragonx.is -addnode injection in
|
||||
// hush_utils.h, which is almost certainly why that injection exists.
|
||||
//
|
||||
// seed.dragonx.is is a round-robin A record over the seed set, so ONE lookup
|
||||
// returns all of them and the set can be changed -- a node added, a node retired
|
||||
// -- with a DNS edit instead of a release. That is the point of it: the previous
|
||||
// arrangement hardcoded the seed list into the binary twice over (here and in the
|
||||
// -addnode injection in hush_utils.h), so the network's entry points could only
|
||||
// change by shipping a new version.
|
||||
//
|
||||
// node1/node5 stay as static fallbacks in case the round-robin record is ever
|
||||
// mistyped or removed. They are the same hosts, so this is insurance against a
|
||||
// DNS mistake rather than genuine redundancy.
|
||||
vSeeds.push_back(CDNSSeedData("seed", "seed.dragonx.is"));
|
||||
vSeeds.push_back(CDNSSeedData("node1", "node1.dragonx.is"));
|
||||
vSeeds.push_back(CDNSSeedData("node5", "node5.dragonx.is"));
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,60);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,85);
|
||||
@@ -515,15 +539,27 @@ void hush_setactivation(int32_t height)
|
||||
|
||||
void *chainparams_commandline() {
|
||||
CChainParams::CCheckpointData checkpointData;
|
||||
//if(fDebug) {
|
||||
fprintf(stderr,"chainparams_commandline called with port=%u\n", ASSETCHAINS_P2PPORT);
|
||||
//}
|
||||
LogPrint("net", "chainparams_commandline called with port=%u\n", ASSETCHAINS_P2PPORT);
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
||||
{
|
||||
// A smart chain inherits vSeeds/vFixedSeeds from the base network params,
|
||||
// and nothing below ever touched them. That is how DRAGONX came to run on
|
||||
// Hush's seeds -- seed1.hush.is and friends, long since removed from DNS --
|
||||
// for as long as it did. Seeds are per-chain by nature: an address that
|
||||
// serves one chain is useless to another, and dialling it is at best wasted
|
||||
// effort and at worst a peer that speaks a different protocol.
|
||||
//
|
||||
// DRAGONX keeps the seeds configured in CMainParams (which are its own).
|
||||
// Every other chain starts empty and relies on -addnode/-connect, which is
|
||||
// what an assetchain operator has to configure anyway.
|
||||
if (strcmp(SMART_CHAIN_SYMBOL,"HUSH3") == 0) {
|
||||
ASSETCHAINS_P2PPORT = 18030;
|
||||
}
|
||||
|
||||
if (strcmp(SMART_CHAIN_SYMBOL, "DRAGONX") != 0) {
|
||||
pCurrentParams->ClearSeeds();
|
||||
}
|
||||
|
||||
if ( ASSETCHAINS_BLOCKTIME != 60 )
|
||||
{
|
||||
pCurrentParams->consensus.nMaxFutureBlockTime = 7 * ASSETCHAINS_BLOCKTIME; // 7 blocks
|
||||
@@ -547,7 +583,7 @@ void *chainparams_commandline() {
|
||||
pCurrentParams->pchMessageStart[1] = (ASSETCHAINS_MAGIC >> 8) & 0xff;
|
||||
pCurrentParams->pchMessageStart[2] = (ASSETCHAINS_MAGIC >> 16) & 0xff;
|
||||
pCurrentParams->pchMessageStart[3] = (ASSETCHAINS_MAGIC >> 24) & 0xff;
|
||||
fprintf(stderr,">>>>>>>>>> %s: p2p.%u rpc.%u magic.%08x %u %u coins\n",SMART_CHAIN_SYMBOL,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_MAGIC,ASSETCHAINS_MAGIC,(uint32_t)ASSETCHAINS_SUPPLY);
|
||||
LogPrintf("%s: p2p port %u, rpc port %u, magic %08x, supply %u coins\n",SMART_CHAIN_SYMBOL,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_MAGIC,(uint32_t)ASSETCHAINS_SUPPLY);
|
||||
|
||||
pCurrentParams->consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = ASSETCHAINS_SAPLING;
|
||||
pCurrentParams->consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = ASSETCHAINS_OVERWINTER;
|
||||
|
||||
@@ -117,6 +117,10 @@ public:
|
||||
void SetNValue(uint64_t n) { nEquihashN = n; }
|
||||
void SetKValue(uint64_t k) { nEquihashK = k; }
|
||||
void SetMiningRequiresPeers(bool flag) { fMiningRequiresPeers = flag; }
|
||||
//! Drop any inherited peer seeds. An assetchain gets its params by copying a
|
||||
//! base network and overriding pieces; without this it silently keeps the base
|
||||
//! chain's DNS and fixed seeds, which are wrong for it by definition.
|
||||
void ClearSeeds() { vSeeds.clear(); vFixedSeeds.clear(); }
|
||||
|
||||
CMessageHeader::MessageStartChars pchMessageStart;
|
||||
Consensus::Params consensus;
|
||||
|
||||
@@ -11,14 +11,16 @@
|
||||
// Each line contains a BIP155 serialized address.
|
||||
//
|
||||
static const uint8_t chainparams_seed_main[] = {
|
||||
0x01,0x04,0xd4,0x38,0x29,0x3f,0x00,0x00, // 212.56.41.63
|
||||
0x01,0x04,0xc2,0x8c,0xc6,0xb0,0x00,0x00, // 194.140.198.176
|
||||
0x01,0x04,0xd4,0x38,0x29,0x2f,0x00,0x00, // 212.56.41.47
|
||||
0x01,0x04,0x90,0x7e,0x93,0xa5,0x00,0x00, // 144.126.147.165
|
||||
0x01,0x04,0xb0,0x7e,0x57,0xf1,0x00,0x00, // 176.126.87.241
|
||||
0x01,0x04,0xd4,0x38,0x29,0x3f,0x55,0x08, // 212.56.41.63:21768
|
||||
0x01,0x04,0xc2,0x8c,0xc6,0xb0,0x55,0x08, // 194.140.198.176:21768
|
||||
0x01,0x04,0xd4,0x38,0x29,0x2f,0x55,0x08, // 212.56.41.47:21768
|
||||
0x01,0x04,0x90,0x7e,0x93,0xa5,0x55,0x08, // 144.126.147.165:21768
|
||||
0x01,0x04,0xb0,0x7e,0x57,0xf1,0x55,0x08, // 176.126.87.241:21768
|
||||
0x01,0x04,0x0d,0x8c,0x3a,0xfb,0x55,0x08, // 13.140.58.251:21768
|
||||
0x01,0x04,0x05,0x68,0x53,0x64,0x55,0x08, // 5.104.83.100:21768
|
||||
};
|
||||
|
||||
static const uint8_t chainparams_seed_test[] = {
|
||||
0x01,0x04,0x01,0x02,0x03,0x04,0x00,0x00, // 1.2.3.4
|
||||
};
|
||||
#endif // HUSH_CHAINPARAMSSEEDS_H
|
||||
#endif // DRAGONX_CHAINPARAMSSEEDS_H
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
|
||||
// Must be kept in sync with configure.ac , ugh!
|
||||
#define CLIENT_VERSION_MAJOR 1
|
||||
#define CLIENT_VERSION_MINOR 1
|
||||
#define CLIENT_VERSION_MINOR 2
|
||||
#define CLIENT_VERSION_REVISION 0
|
||||
#define CLIENT_VERSION_BUILD 50
|
||||
|
||||
|
||||
@@ -214,19 +214,6 @@ void CCoinsViewCache::AbstractPushAnchor(
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: delete
|
||||
/*
|
||||
template<> void CCoinsViewCache::PushAnchor(const SproutMerkleTree &tree)
|
||||
{
|
||||
AbstractPushAnchor<SproutMerkleTree, CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(
|
||||
tree,
|
||||
SPROUT,
|
||||
cacheSproutAnchors,
|
||||
hashSproutAnchor
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
|
||||
{
|
||||
AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
|
||||
@@ -406,8 +393,6 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
|
||||
|
||||
void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
|
||||
{
|
||||
//if(fZdebug)
|
||||
// LogPrintf("%s\n", __FUNCTION__);
|
||||
for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
|
||||
if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
|
||||
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
|
||||
@@ -531,10 +516,7 @@ unsigned int CCoinsViewCache::GetCacheSize() const {
|
||||
const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
|
||||
{
|
||||
const CCoins* coins = AccessCoins(input.prevout.hash);
|
||||
//fprintf(stderr, "GetOutputFor: input=%s", input.ToString().c_str());
|
||||
//fprintf(stderr, "GetOutputFor: prevout n=%d,txid=%s\n", input.prevout.n, input.prevout.hash.ToString().c_str());
|
||||
assert(coins && coins->IsAvailable(input.prevout.n));
|
||||
//fprintf(stderr, "GetOutputFor: IsAvailable\n");
|
||||
return coins->vout[input.prevout.n];
|
||||
}
|
||||
|
||||
@@ -596,7 +578,6 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const CCoins* coins = AccessCoins(prevout.hash);
|
||||
if (!coins || !coins->IsAvailable(prevout.n)) {
|
||||
//fprintf(stderr,"HaveInputs missing input %s/v%d\n",prevout.hash.ToString().c_str(),prevout.n);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,10 +63,6 @@ UpgradeState NetworkUpgradeState(
|
||||
const Consensus::Params& params,
|
||||
Consensus::UpgradeIndex idx)
|
||||
{
|
||||
if (nHeight < 0)
|
||||
{
|
||||
printf("height: %d", nHeight);
|
||||
}
|
||||
assert(nHeight >= 0);
|
||||
assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES);
|
||||
auto nActivationHeight = params.vUpgrades[idx].nActivationHeight;
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
// XXX: There are potential crashes wherever we access chainActive without a lock,
|
||||
// because it might be disconnecting blocks at the same time.
|
||||
// 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, "HUSH3",5) == 0 ? 1152 : 1440;
|
||||
// DragonX: the HUSH3 (1152) branch is dead — SMART_CHAIN_SYMBOL is always "DRAGONX", and at
|
||||
// static-init time it is empty, so this already always resolved to 1440. Pinned to 1440.
|
||||
int NOTARISATION_SCAN_LIMIT_BLOCKS = 1440;
|
||||
CBlockIndex *hush_getblockindex(uint256 hash);
|
||||
|
||||
/* On HUSH */
|
||||
|
||||
33
src/hush.h
33
src/hush.h
@@ -95,7 +95,6 @@ int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *de
|
||||
errs++;
|
||||
else
|
||||
{
|
||||
//printf("updated %d pubkeys at %s ht.%d\n",num,symbol,ht);
|
||||
if ( (HUSH_EXTERNAL_NOTARIES != 0 && matched != 0) )
|
||||
hush_eventadd_pubkeys(sp,symbol,ht,num,pubkeys);
|
||||
}
|
||||
@@ -131,7 +130,6 @@ int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *de
|
||||
uint8_t n,nid; uint256 hash; uint64_t mask;
|
||||
n = fgetc(fp);
|
||||
nid = fgetc(fp);
|
||||
//printf("U %d %d\n",n,nid);
|
||||
if ( fread(&mask,1,sizeof(mask),fp) != sizeof(mask) )
|
||||
errs++;
|
||||
if ( fread(&hash,1,sizeof(hash),fp) != sizeof(hash) )
|
||||
@@ -145,7 +143,6 @@ int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *de
|
||||
if ( fread(&kheight,1,sizeof(kheight),fp) != sizeof(kheight) )
|
||||
errs++;
|
||||
//if ( matched != 0 ) global independent states -> inside *sp
|
||||
//printf("%s.%d load[%s] ht.%d\n",SMART_CHAIN_SYMBOL,ht,symbol,kheight);
|
||||
hush_eventadd_hushheight(sp,symbol,ht,kheight,0);
|
||||
}
|
||||
else if ( func == 'T' )
|
||||
@@ -156,7 +153,6 @@ int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *de
|
||||
if ( fread(&ktimestamp,1,sizeof(ktimestamp),fp) != sizeof(ktimestamp) )
|
||||
errs++;
|
||||
//if ( matched != 0 ) global independent states -> inside *sp
|
||||
//printf("%s.%d load[%s] ht.%d t.%u\n",SMART_CHAIN_SYMBOL,ht,symbol,kheight,ktimestamp);
|
||||
hush_eventadd_hushheight(sp,symbol,ht,kheight,ktimestamp);
|
||||
}
|
||||
else if ( func == 'R' )
|
||||
@@ -186,7 +182,6 @@ int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *de
|
||||
int32_t i;
|
||||
for (i=0; i<olen; i++)
|
||||
fgetc(fp);
|
||||
//printf("illegal olen.%u\n",olen);
|
||||
}
|
||||
}
|
||||
else if ( func == 'D' )
|
||||
@@ -200,9 +195,7 @@ int32_t hush_parsestatefile(struct hush_state *sp,FILE *fp,char *symbol,char *de
|
||||
if ( numpvals*sizeof(uint32_t) <= sizeof(pvals) && fread(pvals,sizeof(uint32_t),numpvals,fp) == numpvals )
|
||||
{
|
||||
//if ( matched != 0 ) global shared state -> global PVALS
|
||||
//printf("%s load[%s] prices %d\n",SMART_CHAIN_SYMBOL,symbol,ht);
|
||||
hush_eventadd_pricefeed(sp,symbol,ht,pvals,numpvals);
|
||||
//printf("load pvals ht.%d numpvals.%d\n",ht,numpvals);
|
||||
} else printf("error loading pvals[%d]\n",numpvals);
|
||||
} // else printf("[%s] %s illegal func.(%d %c)\n",SMART_CHAIN_SYMBOL,symbol,func,func);
|
||||
return(func);
|
||||
@@ -239,7 +232,6 @@ int32_t hush_parsestatefiledata(struct hush_state *sp,uint8_t *filedata,long *fp
|
||||
errs++;
|
||||
else
|
||||
{
|
||||
//printf("updated %d pubkeys at %s ht.%d\n",num,symbol,ht);
|
||||
if ( (HUSH_EXTERNAL_NOTARIES != 0 && matched != 0) )
|
||||
hush_eventadd_pubkeys(sp,symbol,ht,num,pubkeys);
|
||||
}
|
||||
@@ -274,7 +266,6 @@ int32_t hush_parsestatefiledata(struct hush_state *sp,uint8_t *filedata,long *fp
|
||||
uint8_t n,nid; uint256 hash; uint64_t mask;
|
||||
n = filedata[fpos++];
|
||||
nid = filedata[fpos++];
|
||||
//printf("U %d %d\n",n,nid);
|
||||
if ( memread(&mask,sizeof(mask),filedata,&fpos,datalen) != sizeof(mask) )
|
||||
errs++;
|
||||
if ( memread(&hash,sizeof(hash),filedata,&fpos,datalen) != sizeof(hash) )
|
||||
@@ -295,7 +286,6 @@ int32_t hush_parsestatefiledata(struct hush_state *sp,uint8_t *filedata,long *fp
|
||||
if ( memread(&ktimestamp,sizeof(ktimestamp),filedata,&fpos,datalen) != sizeof(ktimestamp) )
|
||||
errs++;
|
||||
//if ( matched != 0 ) global independent states -> inside *sp
|
||||
//printf("%s.%d load[%s] ht.%d t.%u\n",SMART_CHAIN_SYMBOL,ht,symbol,kheight,ktimestamp);
|
||||
hush_eventadd_hushheight(sp,symbol,ht,kheight,ktimestamp);
|
||||
}
|
||||
else if ( func == 'R' )
|
||||
@@ -325,7 +315,6 @@ int32_t hush_parsestatefiledata(struct hush_state *sp,uint8_t *filedata,long *fp
|
||||
int32_t i;
|
||||
for (i=0; i<olen; i++)
|
||||
filedata[fpos++];
|
||||
//printf("illegal olen.%u\n",olen);
|
||||
}
|
||||
}
|
||||
else if ( func == 'D' )
|
||||
@@ -339,9 +328,7 @@ int32_t hush_parsestatefiledata(struct hush_state *sp,uint8_t *filedata,long *fp
|
||||
if ( numpvals*sizeof(uint32_t) <= sizeof(pvals) && memread(pvals,(int32_t)(sizeof(uint32_t)*numpvals),filedata,&fpos,datalen) == numpvals*sizeof(uint32_t) )
|
||||
{
|
||||
//if ( matched != 0 ) global shared state -> global PVALS
|
||||
//printf("%s load[%s] prices %d\n",SMART_CHAIN_SYMBOL,symbol,ht);
|
||||
hush_eventadd_pricefeed(sp,symbol,ht,pvals,numpvals);
|
||||
//printf("load pvals ht.%d numpvals.%d\n",ht,numpvals);
|
||||
} else printf("error loading pvals[%d]\n",numpvals);
|
||||
} // else printf("[%s] %s illegal func.(%d %c)\n",SMART_CHAIN_SYMBOL,symbol,func,func);
|
||||
*fposp = fpos;
|
||||
@@ -366,7 +353,6 @@ void hush_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotarie
|
||||
printf("[%s] no hush_stateptr\n",SMART_CHAIN_SYMBOL);
|
||||
return;
|
||||
}
|
||||
//printf("[%s] (%s) -> (%s)\n",SMART_CHAIN_SYMBOL,symbol,dest);
|
||||
if ( fp == 0 )
|
||||
{
|
||||
hush_statefname(fname,SMART_CHAIN_SYMBOL,(char *)"hushstate");
|
||||
@@ -385,12 +371,10 @@ void hush_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotarie
|
||||
}
|
||||
if ( height <= 0 )
|
||||
{
|
||||
//printf("early return: stateupdate height.%d\n",height);
|
||||
return;
|
||||
}
|
||||
if ( fp != 0 ) // write out funcid, height, other fields, call side effect function
|
||||
{
|
||||
//printf("fpos.%ld ",ftell(fp));
|
||||
if ( HUSHheight != 0 )
|
||||
{
|
||||
if ( HUSHtimestamp != 0 )
|
||||
@@ -425,7 +409,6 @@ void hush_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotarie
|
||||
errs++;
|
||||
if ( fwrite(opretbuf,1,olen,fp) != olen )
|
||||
errs++;
|
||||
//printf("create ht.%d R opret[%d] sp.%p\n",height,olen,sp);
|
||||
hush_eventadd_opreturn(sp,symbol,height,txhash,opretvalue,vout,opretbuf,olen);
|
||||
}
|
||||
else if ( notarypubs != 0 && numnotaries > 0 )
|
||||
@@ -441,7 +424,6 @@ void hush_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotarie
|
||||
}
|
||||
else if ( voutmask != 0 && numvouts > 0 )
|
||||
{
|
||||
//printf("ht.%d func U %d %d errs.%d hashsize.%ld\n",height,numvouts,notaryid,errs,sizeof(txhash));
|
||||
fputc('U',fp);
|
||||
if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) )
|
||||
errs++;
|
||||
@@ -468,13 +450,10 @@ void hush_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotarie
|
||||
if ( fwrite(pvals,sizeof(uint32_t),numpvals,fp) != numpvals )
|
||||
errs++;
|
||||
hush_eventadd_pricefeed(sp,symbol,height,pvals,numpvals);
|
||||
//printf("ht.%d V numpvals[%d]\n",height,numpvals);
|
||||
}
|
||||
//printf("save pvals height.%d numpvals.%d\n",height,numpvals);
|
||||
}
|
||||
else if ( height != 0 )
|
||||
{
|
||||
//printf("ht.%d func N ht.%d errs.%d\n",height,NOTARIZED_HEIGHT,errs);
|
||||
if ( sp != 0 )
|
||||
{
|
||||
if ( sp->MoMdepth != 0 && sp->MoM != zero )
|
||||
@@ -504,7 +483,6 @@ void hush_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotarie
|
||||
|
||||
int32_t hush_validate_chain(uint256 srchash,int32_t notarized_height)
|
||||
{
|
||||
//fprintf(stderr,"%s\n", __func__);
|
||||
static int32_t last_rewind; int32_t rewindtarget; CBlockIndex *pindex; struct hush_state *sp; char symbol[HUSH_SMART_CHAIN_MAXLEN],dest[HUSH_SMART_CHAIN_MAXLEN];
|
||||
if ( (sp= hush_stateptr(symbol,dest)) == 0 )
|
||||
return(0);
|
||||
@@ -555,11 +533,9 @@ int32_t hush_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notaryi
|
||||
if ( memcmp(crypto555,scriptbuf+1,33) == 0 )
|
||||
{
|
||||
*specialtxp = 1;
|
||||
//printf(">>>>>>>> ");
|
||||
}
|
||||
else if ( hush_chosennotary(&nid,height,scriptbuf + 1,timestamp) >= 0 )
|
||||
{
|
||||
//printf("found notary.k%d\n",k);
|
||||
if ( notaryid < 64 )
|
||||
{
|
||||
if ( notaryid < 0 )
|
||||
@@ -569,9 +545,6 @@ int32_t hush_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notaryi
|
||||
}
|
||||
else if ( notaryid != nid )
|
||||
{
|
||||
//for (i=0; i<33; i++)
|
||||
// printf("%02x",scriptbuf[i+1]);
|
||||
//printf(" %s mismatch notaryid.%d k.%d\n",SMART_CHAIN_SYMBOL,notaryid,nid);
|
||||
notaryid = 64;
|
||||
*voutmaskp = 0;
|
||||
}
|
||||
@@ -605,7 +578,6 @@ int32_t hush_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notaryi
|
||||
} else {
|
||||
if ( scriptbuf[len] == 'K' )
|
||||
{
|
||||
//fprintf(stderr,"i.%d j.%d KV OPRET len.%d %.8f\n",i,j,opretlen,dstr(value));
|
||||
hush_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen,j,zero,0);
|
||||
return(-1);
|
||||
}
|
||||
@@ -727,9 +699,6 @@ int32_t hush_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notaryi
|
||||
}
|
||||
else if ( matched != 0 )
|
||||
{
|
||||
//int32_t k; for (k=0; k<scriptlen; k++)
|
||||
// printf("%02x",scriptbuf[k]);
|
||||
//printf(" <- script ht.%d i.%d j.%d value %.8f %s\n",height,i,j,dstr(value),SMART_CHAIN_SYMBOL);
|
||||
if ( opretlen >= 32*2+4 && strcmp(SMART_CHAIN_SYMBOL,(char *)&scriptbuf[len+32*2+4]) == 0 )
|
||||
{
|
||||
for (k=0; k<32; k++)
|
||||
@@ -793,7 +762,6 @@ int32_t hush_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block)
|
||||
fprintf(stderr,"unexpected null stateptr.[%s]\n",SMART_CHAIN_SYMBOL);
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr,"%s connect.%d\n",SMART_CHAIN_SYMBOL,pindex->nHeight);
|
||||
// Wallet Filter. Disabled here. Cant be activated by notaries or pools with some changes.
|
||||
numnotaries = hush_notaries(pubkeys,pindex->GetHeight(),pindex->GetBlockTime());
|
||||
calc_rmd160_sha256(rmd160,pubkeys[0],33);
|
||||
@@ -970,7 +938,6 @@ int32_t hush_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block)
|
||||
else
|
||||
{ fprintf(stderr,"hush_connectblock: unexpected null pindex\n"); return(0); }
|
||||
//HUSH_INITDONE = (uint32_t)time(NULL);
|
||||
//fprintf(stderr,"%s end connect.%d\n",SMART_CHAIN_SYMBOL,pindex->GetHeight());
|
||||
if (fJustCheck)
|
||||
{
|
||||
if ( notarizations.size() == 0 )
|
||||
|
||||
@@ -975,8 +975,9 @@ uint64_t hush_commission(int height)
|
||||
INTERVAL = GetArg("-ac_halving1",840000), TRANSITION = 129;
|
||||
uint64_t commission = 0;
|
||||
|
||||
//TODO: Likely a bug hiding here or at the next halving :)
|
||||
//if( height >= HALVING1) {
|
||||
// NB: INTERVAL is consumed only by the debug fprintf at the end of this function;
|
||||
// the commission schedule below uses hardcoded height thresholds, not INTERVAL. So
|
||||
// the > vs >= boundary at HALVING1 has no consensus effect. Left as > for stability.
|
||||
if( height > HALVING1) {
|
||||
// Block time going from 150s to 75s (half) means the interval between halvings
|
||||
// must be twice as often, i.e. 840000*2=1680000
|
||||
@@ -1019,14 +1020,14 @@ uint64_t hush_commission(int height)
|
||||
commission = 61035;
|
||||
} else if (height < 23860000) {
|
||||
commission = 30517;
|
||||
} else if (height < 23860000) {
|
||||
commission = 15258;
|
||||
// removed unreachable duplicate `height < 23860000` (=> 15258); the schedule
|
||||
// intentionally drops straight to 7629 next — this is the deployed behavior.
|
||||
} else if (height < 25540000) {
|
||||
commission = 7629;
|
||||
} else if (height < 27220000) {
|
||||
commission = 3814;
|
||||
} else if (height < 27220000) {
|
||||
commission = 1907;
|
||||
// removed unreachable duplicate `height < 27220000` (=> 1907); the schedule
|
||||
// intentionally drops straight to 953 next — this is the deployed behavior.
|
||||
} else if (height < 28900000) {
|
||||
commission = 953;
|
||||
} else if (height < 30580000) {
|
||||
|
||||
@@ -597,7 +597,7 @@ void hush_netevent(std::vector<uint8_t> payload);
|
||||
int32_t getacseason(uint32_t timestamp);
|
||||
int32_t gethushseason(int32_t height);
|
||||
|
||||
#define DRAGON_MAXSCRIPTSIZE 10001
|
||||
// DRAGON_MAXSCRIPTSIZE is defined once near the top of this header; the duplicate here was removed.
|
||||
#define HUSH_KVDURATION 1440
|
||||
#define HUSH_KVBINARY 2
|
||||
#define PRICES_SMOOTHWIDTH 1
|
||||
|
||||
@@ -568,8 +568,6 @@ uint256 NSPV_opretextract(int32_t *heightp,uint256 *blockhashp,char *symbol,std:
|
||||
((uint8_t *)blockhashp)[i] = opret[i];
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)&desttxid)[i] = opret[4 + 32 + i];
|
||||
if ( 0 && *heightp != 2690 )
|
||||
fprintf(stderr," ntzht.%d %s <- txid.%s size.%d\n",*heightp,(*blockhashp).GetHex().c_str(),(txid).GetHex().c_str(),(int32_t)opret.size());
|
||||
return(desttxid);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ struct NSPV_ntzargs
|
||||
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;
|
||||
symbol = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"HUSH3" : SMART_CHAIN_SYMBOL;
|
||||
// Notarization symbol; the empty-symbol fallback is dead on DragonX (SMART_CHAIN_SYMBOL is always "DRAGONX", never empty)
|
||||
symbol = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"DRAGONX" : SMART_CHAIN_SYMBOL;
|
||||
memset(args,0,sizeof(*args));
|
||||
if ( dir > 0 )
|
||||
height += 10;
|
||||
@@ -659,7 +660,7 @@ void hush_nSPVreq(CNode *pfrom,std::vector<uint8_t> request) // received a reque
|
||||
struct NSPV_utxosresp U;
|
||||
if ( len >= 2 && len < 64+5 && request[1] < 64 && (request[1] == len-3 || request[1] == len-7 || request[1] == len-11) )
|
||||
{
|
||||
int32_t skipcount = 0; char coinaddr[64]; uint8_t filter; uint8_t isCC = 0;
|
||||
int32_t skipcount = 0; char coinaddr[64]; uint32_t filter; uint8_t isCC = 0;
|
||||
memcpy(coinaddr,&request[2],request[1]); // request[1] < 64 bounds the copy + the terminator write
|
||||
coinaddr[request[1]] = 0;
|
||||
if ( request[1] == len-3 )
|
||||
@@ -675,8 +676,6 @@ void hush_nSPVreq(CNode *pfrom,std::vector<uint8_t> request) // received a reque
|
||||
dragon_rwnum(0,&request[len-8],sizeof(skipcount),&skipcount);
|
||||
dragon_rwnum(0,&request[len-4],sizeof(filter),&filter);
|
||||
}
|
||||
if ( 0 && isCC != 0 )
|
||||
fprintf(stderr,"utxos %s isCC.%d skipcount.%d filter.%x\n",coinaddr,isCC,skipcount,filter);
|
||||
memset(&U,0,sizeof(U));
|
||||
if ( (slen= NSPV_getaddressutxos(&U,coinaddr,isCC,skipcount,filter)) > 0 )
|
||||
{
|
||||
@@ -715,8 +714,6 @@ void hush_nSPVreq(CNode *pfrom,std::vector<uint8_t> request) // received a reque
|
||||
dragon_rwnum(0,&request[len-8],sizeof(skipcount),&skipcount);
|
||||
dragon_rwnum(0,&request[len-4],sizeof(filter),&filter);
|
||||
}
|
||||
if ( 0 && isCC != 0 )
|
||||
fprintf(stderr,"txids %s isCC.%d skipcount.%d filter.%d\n",coinaddr,isCC,skipcount,filter);
|
||||
memset(&T,0,sizeof(T));
|
||||
if ( (slen= NSPV_getaddresstxids(&T,coinaddr,isCC,skipcount,filter)) > 0 )
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ struct NSPV_ntzsresp *NSPV_ntzsresp_add(struct NSPV_ntzsresp *ptr)
|
||||
i = (rand() % (sizeof(NSPV_ntzsresp_cache)/sizeof(*NSPV_ntzsresp_cache)));
|
||||
NSPV_ntzsresp_purge(&NSPV_ntzsresp_cache[i]);
|
||||
NSPV_ntzsresp_copy(&NSPV_ntzsresp_cache[i],ptr);
|
||||
fprintf(stderr,"ADD CACHE ntzsresp req.%d\n",ptr->reqheight);
|
||||
LogPrint("nspv","ADD CACHE ntzsresp req.%d\n",ptr->reqheight);
|
||||
return(&NSPV_ntzsresp_cache[i]);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ struct NSPV_txproof *NSPV_txproof_add(struct NSPV_txproof *ptr)
|
||||
i = (rand() % (sizeof(NSPV_txproof_cache)/sizeof(*NSPV_txproof_cache)));
|
||||
NSPV_txproof_purge(&NSPV_txproof_cache[i]);
|
||||
NSPV_txproof_copy(&NSPV_txproof_cache[i],ptr);
|
||||
fprintf(stderr,"ADD CACHE txproof %s\n",ptr->txid.GetHex().c_str());
|
||||
LogPrint("nspv","ADD CACHE txproof %s\n",ptr->txid.GetHex().c_str());
|
||||
return(&NSPV_txproof_cache[i]);
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ struct NSPV_ntzsproofresp *NSPV_ntzsproof_add(struct NSPV_ntzsproofresp *ptr)
|
||||
i = (rand() % (sizeof(NSPV_ntzsproofresp_cache)/sizeof(*NSPV_ntzsproofresp_cache)));
|
||||
NSPV_ntzsproofresp_purge(&NSPV_ntzsproofresp_cache[i]);
|
||||
NSPV_ntzsproofresp_copy(&NSPV_ntzsproofresp_cache[i],ptr);
|
||||
fprintf(stderr,"ADD CACHE ntzsproof %s %s\n",ptr->prevtxid.GetHex().c_str(),ptr->nexttxid.GetHex().c_str());
|
||||
LogPrint("nspv","ADD CACHE ntzsproof %s %s\n",ptr->prevtxid.GetHex().c_str(),ptr->nexttxid.GetHex().c_str());
|
||||
return(&NSPV_ntzsproofresp_cache[i]);
|
||||
}
|
||||
|
||||
@@ -139,13 +139,13 @@ void hush_nSPVresp(CNode *pfrom,std::vector<uint8_t> response) // received a res
|
||||
switch ( response[0] )
|
||||
{
|
||||
case NSPV_INFORESP:
|
||||
fprintf(stderr,"got version.%d info response %u size.%d height.%d\n",NSPV_inforesult.version,timestamp,(int32_t)response.size(),NSPV_inforesult.height); // update current height and ntrz status
|
||||
LogPrint("nspv","got version.%d info response %u size.%d height.%d\n",NSPV_inforesult.version,timestamp,(int32_t)response.size(),NSPV_inforesult.height); // update current height and ntrz status
|
||||
I = NSPV_inforesult;
|
||||
NSPV_inforesp_purge(&NSPV_inforesult);
|
||||
NSPV_rwinforesp(0,&response[1],&NSPV_inforesult);
|
||||
if ( NSPV_inforesult.height < I.height )
|
||||
{
|
||||
fprintf(stderr,"got old info response %u size.%d height.%d\n",timestamp,(int32_t)response.size(),NSPV_inforesult.height); // update current height and ntrz status
|
||||
LogPrint("nspv","got old info response %u size.%d height.%d\n",timestamp,(int32_t)response.size(),NSPV_inforesult.height); // update current height and ntrz status
|
||||
NSPV_inforesp_purge(&NSPV_inforesult);
|
||||
NSPV_inforesult = I;
|
||||
}
|
||||
@@ -160,56 +160,56 @@ void hush_nSPVresp(CNode *pfrom,std::vector<uint8_t> response) // received a res
|
||||
case NSPV_UTXOSRESP:
|
||||
NSPV_utxosresp_purge(&NSPV_utxosresult);
|
||||
NSPV_rwutxosresp(0,&response[1],&NSPV_utxosresult);
|
||||
fprintf(stderr,"got utxos response %u size.%d\n",timestamp,(int32_t)response.size());
|
||||
LogPrint("nspv","got utxos response %u size.%d\n",timestamp,(int32_t)response.size());
|
||||
break;
|
||||
case NSPV_TXIDSRESP:
|
||||
NSPV_txidsresp_purge(&NSPV_txidsresult);
|
||||
NSPV_rwtxidsresp(0,&response[1],&NSPV_txidsresult);
|
||||
fprintf(stderr,"got txids response %u size.%d %s CC.%d num.%d\n",timestamp,(int32_t)response.size(),NSPV_txidsresult.coinaddr,NSPV_txidsresult.CCflag,NSPV_txidsresult.numtxids);
|
||||
LogPrint("nspv","got txids response %u size.%d %s CC.%d num.%d\n",timestamp,(int32_t)response.size(),NSPV_txidsresult.coinaddr,NSPV_txidsresult.CCflag,NSPV_txidsresult.numtxids);
|
||||
break;
|
||||
case NSPV_MEMPOOLRESP:
|
||||
NSPV_mempoolresp_purge(&NSPV_mempoolresult);
|
||||
NSPV_rwmempoolresp(0,&response[1],&NSPV_mempoolresult);
|
||||
fprintf(stderr,"got mempool response %u size.%d %s CC.%d num.%d funcid.%d %s/v%d\n",timestamp,(int32_t)response.size(),NSPV_mempoolresult.coinaddr,NSPV_mempoolresult.CCflag,NSPV_mempoolresult.numtxids,NSPV_mempoolresult.funcid,NSPV_mempoolresult.txid.GetHex().c_str(),NSPV_mempoolresult.vout);
|
||||
LogPrint("nspv","got mempool response %u size.%d %s CC.%d num.%d funcid.%d %s/v%d\n",timestamp,(int32_t)response.size(),NSPV_mempoolresult.coinaddr,NSPV_mempoolresult.CCflag,NSPV_mempoolresult.numtxids,NSPV_mempoolresult.funcid,NSPV_mempoolresult.txid.GetHex().c_str(),NSPV_mempoolresult.vout);
|
||||
break;
|
||||
case NSPV_NTZSRESP:
|
||||
NSPV_ntzsresp_purge(&NSPV_ntzsresult);
|
||||
NSPV_rwntzsresp(0,&response[1],&NSPV_ntzsresult);
|
||||
if ( NSPV_ntzsresp_find(NSPV_ntzsresult.reqheight) == 0 )
|
||||
NSPV_ntzsresp_add(&NSPV_ntzsresult);
|
||||
fprintf(stderr,"got ntzs response %u size.%d %s prev.%d, %s next.%d\n",timestamp,(int32_t)response.size(),NSPV_ntzsresult.prevntz.txid.GetHex().c_str(),NSPV_ntzsresult.prevntz.height,NSPV_ntzsresult.nextntz.txid.GetHex().c_str(),NSPV_ntzsresult.nextntz.height);
|
||||
LogPrint("nspv","got ntzs response %u size.%d %s prev.%d, %s next.%d\n",timestamp,(int32_t)response.size(),NSPV_ntzsresult.prevntz.txid.GetHex().c_str(),NSPV_ntzsresult.prevntz.height,NSPV_ntzsresult.nextntz.txid.GetHex().c_str(),NSPV_ntzsresult.nextntz.height);
|
||||
break;
|
||||
case NSPV_NTZSPROOFRESP:
|
||||
NSPV_ntzsproofresp_purge(&NSPV_ntzsproofresult);
|
||||
NSPV_rwntzsproofresp(0,&response[1],&NSPV_ntzsproofresult);
|
||||
if ( NSPV_ntzsproof_find(NSPV_ntzsproofresult.prevtxid,NSPV_ntzsproofresult.nexttxid) == 0 )
|
||||
NSPV_ntzsproof_add(&NSPV_ntzsproofresult);
|
||||
fprintf(stderr,"got ntzproof response %u size.%d prev.%d next.%d\n",timestamp,(int32_t)response.size(),NSPV_ntzsproofresult.common.prevht,NSPV_ntzsproofresult.common.nextht);
|
||||
LogPrint("nspv","got ntzproof response %u size.%d prev.%d next.%d\n",timestamp,(int32_t)response.size(),NSPV_ntzsproofresult.common.prevht,NSPV_ntzsproofresult.common.nextht);
|
||||
break;
|
||||
case NSPV_TXPROOFRESP:
|
||||
NSPV_txproof_purge(&NSPV_txproofresult);
|
||||
NSPV_rwtxproof(0,&response[1],&NSPV_txproofresult);
|
||||
if ( NSPV_txproof_find(NSPV_txproofresult.txid) == 0 )
|
||||
NSPV_txproof_add(&NSPV_txproofresult);
|
||||
fprintf(stderr,"got txproof response %u size.%d %s ht.%d\n",timestamp,(int32_t)response.size(),NSPV_txproofresult.txid.GetHex().c_str(),NSPV_txproofresult.height);
|
||||
LogPrint("nspv","got txproof response %u size.%d %s ht.%d\n",timestamp,(int32_t)response.size(),NSPV_txproofresult.txid.GetHex().c_str(),NSPV_txproofresult.height);
|
||||
break;
|
||||
case NSPV_SPENTINFORESP:
|
||||
NSPV_spentinfo_purge(&NSPV_spentresult);
|
||||
NSPV_rwspentinfo(0,&response[1],&NSPV_spentresult);
|
||||
fprintf(stderr,"got spentinfo response %u size.%d\n",timestamp,(int32_t)response.size());
|
||||
LogPrint("nspv","got spentinfo response %u size.%d\n",timestamp,(int32_t)response.size());
|
||||
break;
|
||||
case NSPV_BROADCASTRESP:
|
||||
NSPV_broadcast_purge(&NSPV_broadcastresult);
|
||||
NSPV_rwbroadcastresp(0,&response[1],&NSPV_broadcastresult);
|
||||
fprintf(stderr,"got broadcast response %u size.%d %s retcode.%d\n",timestamp,(int32_t)response.size(),NSPV_broadcastresult.txid.GetHex().c_str(),NSPV_broadcastresult.retcode);
|
||||
LogPrint("nspv","got broadcast response %u size.%d %s retcode.%d\n",timestamp,(int32_t)response.size(),NSPV_broadcastresult.txid.GetHex().c_str(),NSPV_broadcastresult.retcode);
|
||||
break;
|
||||
case NSPV_CCMODULEUTXOSRESP:
|
||||
NSPV_utxosresp_purge(&NSPV_utxosresult);
|
||||
NSPV_rwutxosresp(0, &response[1], &NSPV_utxosresult);
|
||||
fprintf(stderr, "got cc module utxos response %u size.%d\n", timestamp, (int32_t)response.size());
|
||||
LogPrint("nspv", "got cc module utxos response %u size.%d\n", timestamp, (int32_t)response.size());
|
||||
break;
|
||||
|
||||
default: fprintf(stderr,"unexpected response %02x size.%d at %u\n",response[0],(int32_t)response.size(),timestamp);
|
||||
default: LogPrint("nspv","unexpected response %02x size.%d at %u\n",response[0],(int32_t)response.size(),timestamp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -254,7 +254,7 @@ CNode *NSPV_req(CNode *pnode,uint8_t *msg,int32_t len,uint64_t mask,int32_t ind)
|
||||
pnode->PushMessage("getnSPV",request);
|
||||
pnode->prevtimes[ind] = timestamp;
|
||||
return(pnode);
|
||||
} else fprintf(stderr,"no pnodes\n");
|
||||
} else LogPrint("nspv","no pnodes\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ UniValue NSPV_logout()
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("result","success"));
|
||||
if ( NSPV_logintime != 0 )
|
||||
fprintf(stderr,"scrub wif and privkey from NSPV memory\n");
|
||||
LogPrint("nspv","scrub wif and privkey from NSPV memory\n");
|
||||
else result.push_back(Pair("status","wasnt logged in"));
|
||||
memset(NSPV_ntzsproofresp_cache,0,sizeof(NSPV_ntzsproofresp_cache));
|
||||
memset(NSPV_txproof_cache,0,sizeof(NSPV_txproof_cache));
|
||||
@@ -294,7 +294,6 @@ void hush_nSPV(CNode *pto) // polling loop from SendMessages
|
||||
len = 0;
|
||||
msg[len++] = NSPV_INFO;
|
||||
len += dragon_rwnum(1,&msg[len],sizeof(reqht),&reqht);
|
||||
//fprintf(stderr,"issue getinfo\n");
|
||||
NSPV_req(pto,msg,len,NODE_NSPV,NSPV_INFO>>1);
|
||||
}
|
||||
}
|
||||
@@ -485,7 +484,6 @@ UniValue NSPV_ntzsproof_json(struct NSPV_ntzsproofresp *ptr)
|
||||
result.push_back(Pair("numhdrs",(int64_t)ptr->common.numhdrs));
|
||||
result.push_back(Pair("headers",NSPV_headers_json(ptr->common.hdrs,ptr->common.numhdrs,ptr->common.prevht)));
|
||||
result.push_back(Pair("lastpeer",NSPV_lastpeer));
|
||||
//fprintf(stderr,"ntzs_proof %s %d, %s %d\n",ptr->prevtxid.GetHex().c_str(),ptr->common.prevht,ptr->nexttxid.GetHex().c_str(),ptr->common.nextht);
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -577,7 +575,7 @@ uint32_t NSPV_blocktime(int32_t hdrheight)
|
||||
{
|
||||
timestamp = NSPV_inforesult.H.nTime;
|
||||
NSPV_inforesult = old;
|
||||
fprintf(stderr,"NSPV_blocktime ht.%d -> t%u\n",hdrheight,timestamp);
|
||||
LogPrint("nspv","NSPV_blocktime ht.%d -> t%u\n",hdrheight,timestamp);
|
||||
return(timestamp);
|
||||
}
|
||||
}
|
||||
@@ -588,7 +586,6 @@ uint32_t NSPV_blocktime(int32_t hdrheight)
|
||||
UniValue NSPV_addressutxos(char *coinaddr,int32_t CCflag,int32_t skipcount,int32_t filter)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint8_t msg[512]; int32_t i,iter,slen,len = 0;
|
||||
//fprintf(stderr,"utxos %s NSPV addr %s\n",coinaddr,NSPV_address.c_str());
|
||||
//if ( NSPV_utxosresult.nodeheight >= NSPV_inforesult.height && strcmp(coinaddr,NSPV_utxosresult.coinaddr) == 0 && CCflag == NSPV_utxosresult.CCflag && skipcount == NSPV_utxosresult.skipcount && filter == NSPV_utxosresult.filter )
|
||||
// return(NSPV_utxosresp_json(&NSPV_utxosresult));
|
||||
if ( skipcount < 0 )
|
||||
@@ -644,7 +641,6 @@ UniValue NSPV_addresstxids(char *coinaddr,int32_t CCflag,int32_t skipcount,int32
|
||||
msg[len++] = (CCflag != 0);
|
||||
len += dragon_rwnum(1,&msg[len],sizeof(skipcount),&skipcount);
|
||||
len += dragon_rwnum(1,&msg[len],sizeof(filter),&filter);
|
||||
//fprintf(stderr,"skipcount.%d\n",skipcount);
|
||||
for (iter=0; iter<3; iter++)
|
||||
if ( NSPV_req(0,msg,len,NODE_ADDRINDEX,msg[0]>>1) != 0 )
|
||||
{
|
||||
@@ -683,7 +679,7 @@ UniValue NSPV_ccaddresstxids(char *coinaddr,int32_t CCflag,int32_t skipcount,uin
|
||||
slen = (int32_t)strlen(coinaddr);
|
||||
msg[len++] = slen;
|
||||
memcpy(&msg[len],coinaddr,slen), len += slen;
|
||||
fprintf(stderr,"(%s) func.%d CC.%d %s skipcount.%d len.%d\n",coinaddr,NSPV_CC_TXIDS,CCflag,filtertxid.GetHex().c_str(),skipcount,len);
|
||||
LogPrint("nspv","(%s) func.%d CC.%d %s skipcount.%d len.%d\n",coinaddr,NSPV_CC_TXIDS,CCflag,filtertxid.GetHex().c_str(),skipcount,len);
|
||||
for (iter=0; iter<3; iter++)
|
||||
if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 )
|
||||
{
|
||||
@@ -721,7 +717,7 @@ UniValue NSPV_mempooltxids(char *coinaddr,int32_t CCflag,uint8_t funcid,uint256
|
||||
slen = (int32_t)strlen(coinaddr);
|
||||
msg[len++] = slen;
|
||||
memcpy(&msg[len],coinaddr,slen), len += slen;
|
||||
fprintf(stderr,"(%s) func.%d CC.%d %s/v%d len.%d\n",coinaddr,funcid,CCflag,txid.GetHex().c_str(),vout,len);
|
||||
LogPrint("nspv","(%s) func.%d CC.%d %s/v%d len.%d\n",coinaddr,funcid,CCflag,txid.GetHex().c_str(),vout,len);
|
||||
for (iter=0; iter<3; iter++)
|
||||
if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 )
|
||||
{
|
||||
@@ -782,7 +778,7 @@ UniValue NSPV_notarizations(int32_t reqheight)
|
||||
uint8_t msg[512]; int32_t i,iter,len = 0; struct NSPV_ntzsresp N,*ptr;
|
||||
if ( (ptr= NSPV_ntzsresp_find(reqheight)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"FROM CACHE NSPV_notarizations.%d\n",reqheight);
|
||||
LogPrint("nspv","FROM CACHE NSPV_notarizations.%d\n",reqheight);
|
||||
NSPV_ntzsresp_purge(&NSPV_ntzsresult);
|
||||
NSPV_ntzsresp_copy(&NSPV_ntzsresult,ptr);
|
||||
return(NSPV_ntzsresp_json(ptr));
|
||||
@@ -808,7 +804,7 @@ UniValue NSPV_txidhdrsproof(uint256 prevtxid,uint256 nexttxid)
|
||||
uint8_t msg[512]; int32_t i,iter,len = 0; struct NSPV_ntzsproofresp P,*ptr;
|
||||
if ( (ptr= NSPV_ntzsproof_find(prevtxid,nexttxid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"FROM CACHE NSPV_txidhdrsproof %s %s\n",ptr->prevtxid.GetHex().c_str(),ptr->nexttxid.GetHex().c_str());
|
||||
LogPrint("nspv","FROM CACHE NSPV_txidhdrsproof %s %s\n",ptr->prevtxid.GetHex().c_str(),ptr->nexttxid.GetHex().c_str());
|
||||
NSPV_ntzsproofresp_purge(&NSPV_ntzsproofresult);
|
||||
NSPV_ntzsproofresp_copy(&NSPV_ntzsproofresult,ptr);
|
||||
return(NSPV_ntzsproof_json(ptr));
|
||||
@@ -846,7 +842,7 @@ UniValue NSPV_txproof(int32_t vout,uint256 txid,int32_t height)
|
||||
uint8_t msg[512]; int32_t i,iter,len = 0; struct NSPV_txproof P,*ptr;
|
||||
if ( (ptr= NSPV_txproof_find(txid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"FROM CACHE NSPV_txproof %s\n",txid.GetHex().c_str());
|
||||
LogPrint("nspv","FROM CACHE NSPV_txproof %s\n",txid.GetHex().c_str());
|
||||
NSPV_txproof_purge(&NSPV_txproofresult);
|
||||
NSPV_txproof_copy(&NSPV_txproofresult,ptr);
|
||||
return(NSPV_txproof_json(ptr));
|
||||
@@ -856,7 +852,7 @@ UniValue NSPV_txproof(int32_t vout,uint256 txid,int32_t height)
|
||||
len += dragon_rwnum(1,&msg[len],sizeof(height),&height);
|
||||
len += dragon_rwnum(1,&msg[len],sizeof(vout),&vout);
|
||||
len += dragon_rwbignum(1,&msg[len],sizeof(txid),(uint8_t *)&txid);
|
||||
fprintf(stderr,"req txproof %s/v%d at height.%d\n",txid.GetHex().c_str(),vout,height);
|
||||
LogPrint("nspv","req txproof %s/v%d at height.%d\n",txid.GetHex().c_str(),vout,height);
|
||||
for (iter=0; iter<3; iter++)
|
||||
if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 )
|
||||
{
|
||||
@@ -867,7 +863,7 @@ UniValue NSPV_txproof(int32_t vout,uint256 txid,int32_t height)
|
||||
return(NSPV_txproof_json(&NSPV_txproofresult));
|
||||
}
|
||||
} else sleep(1);
|
||||
fprintf(stderr,"txproof timeout\n");
|
||||
LogPrint("nspv","txproof timeout\n");
|
||||
memset(&P,0,sizeof(P));
|
||||
return(NSPV_txproof_json(&P));
|
||||
}
|
||||
@@ -907,7 +903,6 @@ UniValue NSPV_broadcast(char *hex)
|
||||
len += dragon_rwnum(1,&msg[len],sizeof(n),&n);
|
||||
memcpy(&msg[len],data,n), len += n;
|
||||
free(data);
|
||||
//fprintf(stderr,"send txid.%s\n",txid.GetHex().c_str());
|
||||
for (iter=0; iter<3; iter++)
|
||||
if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 )
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@ int32_t NSPV_validatehdrs(struct NSPV_ntzsproofresp *ptr)
|
||||
int32_t i,height,txidht; CTransaction tx; uint256 blockhash,txid,desttxid;
|
||||
if ( (ptr->common.nextht-ptr->common.prevht+1) != ptr->common.numhdrs )
|
||||
{
|
||||
fprintf(stderr,"next.%d prev.%d -> %d vs %d\n",ptr->common.nextht,ptr->common.prevht,ptr->common.nextht-ptr->common.prevht+1,ptr->common.numhdrs);
|
||||
LogPrintf("next.%d prev.%d -> %d vs %d\n",ptr->common.nextht,ptr->common.prevht,ptr->common.nextht-ptr->common.prevht+1,ptr->common.numhdrs);
|
||||
return(-2);
|
||||
}
|
||||
else if ( NSPV_txextract(tx,ptr->nextntz,ptr->nexttxlen) < 0 )
|
||||
@@ -64,7 +64,6 @@ int32_t NSPV_gettransaction(int32_t skipvalidation,int32_t vout,uint256 txid,int
|
||||
struct NSPV_txproof *ptr; int32_t i,offset,retval; int64_t rewards = 0; uint32_t nLockTime; std::vector<uint8_t> proof;
|
||||
retval = skipvalidation != 0 ? 0 : -1;
|
||||
|
||||
//fprintf(stderr,"NSPV_gettx %s/v%d ht.%d\n",txid.GetHex().c_str(),vout,height);
|
||||
if ( (ptr= NSPV_txproof_find(txid)) == 0 )
|
||||
{
|
||||
NSPV_txproof(vout,txid,height);
|
||||
@@ -75,7 +74,7 @@ int32_t NSPV_gettransaction(int32_t skipvalidation,int32_t vout,uint256 txid,int
|
||||
currentheight=NSPV_inforesult.height;
|
||||
if ( ptr->txid != txid )
|
||||
{
|
||||
fprintf(stderr,"txproof error %s != %s\n",ptr->txid.GetHex().c_str(),txid.GetHex().c_str());
|
||||
LogPrintf("txproof error %s != %s\n",ptr->txid.GetHex().c_str(),txid.GetHex().c_str());
|
||||
return(-1);
|
||||
}
|
||||
else if ( NSPV_txextract(tx,ptr->tx,ptr->txlen) < 0 || ptr->txlen <= 0 )
|
||||
@@ -87,8 +86,7 @@ int32_t NSPV_gettransaction(int32_t skipvalidation,int32_t vout,uint256 txid,int
|
||||
|
||||
//char coinaddr[64];
|
||||
//Getscriptaddress(coinaddr,tx.vout[0].scriptPubKey); causes crash??
|
||||
//fprintf(stderr,"%s txid.%s vs hash.%s\n",coinaddr,txid.GetHex().c_str(),tx.GetHash().GetHex().c_str());
|
||||
|
||||
|
||||
if ( skipvalidation == 0 )
|
||||
{
|
||||
if ( ptr->txprooflen > 0 )
|
||||
@@ -99,18 +97,17 @@ int32_t NSPV_gettransaction(int32_t skipvalidation,int32_t vout,uint256 txid,int
|
||||
NSPV_notarizations(height); // gets the prev and next notarizations
|
||||
if ( NSPV_inforesult.notarization.height >= height && (NSPV_ntzsresult.prevntz.height == 0 || NSPV_ntzsresult.prevntz.height >= NSPV_ntzsresult.nextntz.height) )
|
||||
{
|
||||
fprintf(stderr,"issue manual bracket\n");
|
||||
LogPrintf("issue manual bracket\n");
|
||||
NSPV_notarizations(height-1);
|
||||
NSPV_notarizations(height+1);
|
||||
NSPV_notarizations(height); // gets the prev and next notarizations
|
||||
}
|
||||
if ( NSPV_ntzsresult.prevntz.height != 0 && NSPV_ntzsresult.prevntz.height <= NSPV_ntzsresult.nextntz.height )
|
||||
{
|
||||
fprintf(stderr,">>>>> gettx ht.%d prev.%d next.%d\n",height,NSPV_ntzsresult.prevntz.height, NSPV_ntzsresult.nextntz.height);
|
||||
LogPrintf(">>>>> gettx ht.%d prev.%d next.%d\n",height,NSPV_ntzsresult.prevntz.height, NSPV_ntzsresult.nextntz.height);
|
||||
offset = (height - NSPV_ntzsresult.prevntz.height);
|
||||
if ( offset >= 0 && height <= NSPV_ntzsresult.nextntz.height )
|
||||
{
|
||||
//fprintf(stderr,"call NSPV_txidhdrsproof %s %s\n",NSPV_ntzsresult.prevntz.txid.GetHex().c_str(),NSPV_ntzsresult.nextntz.txid.GetHex().c_str());
|
||||
NSPV_txidhdrsproof(NSPV_ntzsresult.prevntz.txid,NSPV_ntzsresult.nextntz.txid);
|
||||
usleep(10000);
|
||||
if ( (retval= NSPV_validatehdrs(&NSPV_ntzsproofresult)) == 0 )
|
||||
@@ -119,8 +116,8 @@ int32_t NSPV_gettransaction(int32_t skipvalidation,int32_t vout,uint256 txid,int
|
||||
proofroot = BitcoinGetProofMerkleRoot(proof,txids);
|
||||
if ( proofroot != NSPV_ntzsproofresult.common.hdrs[offset].hashMerkleRoot || txids[0] != txid )
|
||||
{
|
||||
fprintf(stderr,"txid.%s vs txids[0] %s\n",txid.GetHex().c_str(),txids[0].GetHex().c_str());
|
||||
fprintf(stderr,"prooflen.%d proofroot.%s vs %s\n",(int32_t)proof.size(),proofroot.GetHex().c_str(),NSPV_ntzsproofresult.common.hdrs[offset].hashMerkleRoot.GetHex().c_str());
|
||||
LogPrintf("txid.%s vs txids[0] %s\n",txid.GetHex().c_str(),txids[0].GetHex().c_str());
|
||||
LogPrintf("prooflen.%d proofroot.%s vs %s\n",(int32_t)proof.size(),proofroot.GetHex().c_str(),NSPV_ntzsproofresult.common.hdrs[offset].hashMerkleRoot.GetHex().c_str());
|
||||
retval = -2003;
|
||||
} else retval = 0;
|
||||
}
|
||||
@@ -162,13 +159,11 @@ int32_t NSPV_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t
|
||||
belowi = i;
|
||||
}
|
||||
}
|
||||
//printf("value %.8f gap %.8f abovei.%d %.8f belowi.%d %.8f\n",dstr(value),dstr(gap),abovei,dstr(above),belowi,dstr(below));
|
||||
}
|
||||
*aboveip = abovei;
|
||||
*abovep = above;
|
||||
*belowip = belowi;
|
||||
*belowp = below;
|
||||
//printf("above.%d below.%d\n",abovei,belowi);
|
||||
if ( abovei >= 0 && belowi >= 0 )
|
||||
{
|
||||
if ( above < (below >> 1) )
|
||||
@@ -195,14 +190,13 @@ int64_t NSPV_addinputs(struct NSPV_utxoresp *used,CMutableTransaction &mtx,int64
|
||||
utxos[n++] = ptr[i];
|
||||
}
|
||||
remains = total;
|
||||
//fprintf(stderr,"threshold %.8f n.%d for total %.8f\n",(double)threshold/COIN,n,(double)total/COIN);
|
||||
for (i=0; i<maxinputs && n>0; i++)
|
||||
{
|
||||
below = above = 0;
|
||||
abovei = belowi = -1;
|
||||
if ( NSPV_vinselect(&abovei,&above,&belowi,&below,utxos,n,remains) < 0 )
|
||||
{
|
||||
fprintf(stderr,"error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN);
|
||||
LogPrintf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN);
|
||||
return(0);
|
||||
}
|
||||
if ( belowi < 0 || abovei >= 0 )
|
||||
@@ -210,10 +204,9 @@ int64_t NSPV_addinputs(struct NSPV_utxoresp *used,CMutableTransaction &mtx,int64
|
||||
else ind = belowi;
|
||||
if ( ind < 0 )
|
||||
{
|
||||
fprintf(stderr,"error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,n,(double)remains/COIN,(double)total/COIN,abovei,belowi,ind);
|
||||
LogPrintf("error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,n,(double)remains/COIN,(double)total/COIN,abovei,belowi,ind);
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr,"i.%d ind.%d abovei.%d belowi.%d n.%d\n",i,ind,abovei,belowi,n);
|
||||
up = &utxos[ind];
|
||||
mtx.vin.push_back(CTxIn(up->txid,up->vout,CScript()));
|
||||
used[i] = *up;
|
||||
@@ -221,11 +214,9 @@ int64_t NSPV_addinputs(struct NSPV_utxoresp *used,CMutableTransaction &mtx,int64
|
||||
remains -= up->satoshis;
|
||||
utxos[ind] = utxos[--n];
|
||||
memset(&utxos[n],0,sizeof(utxos[n]));
|
||||
//fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs);
|
||||
if ( totalinputs >= total || (i+1) >= maxinputs )
|
||||
break;
|
||||
}
|
||||
//fprintf(stderr,"totalinputs %.8f vs total %.8f\n",(double)totalinputs/COIN,(double)total/COIN);
|
||||
if ( totalinputs >= total )
|
||||
return(totalinputs);
|
||||
return(0);
|
||||
@@ -236,21 +227,20 @@ bool NSPV_SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const C
|
||||
CTransaction txNewConst(mtx); SignatureData sigdata; CBasicKeyStore keystore; int64_t branchid = NSPV_BRANCHID;
|
||||
if ( NSPV_logintime == 0 || time(NULL) > NSPV_logintime+NSPV_AUTOLOGOUT )
|
||||
{
|
||||
fprintf(stderr,"need to be logged in to get myprivkey\n");
|
||||
LogPrintf("need to be logged in to get myprivkey\n");
|
||||
return false;
|
||||
}
|
||||
keystore.AddKey(NSPV_key);
|
||||
if ( nTime != 0 && nTime < HUSH_SAPING_ACTIVATION )
|
||||
{
|
||||
fprintf(stderr,"use legacy sig validation\n");
|
||||
LogPrintf("use legacy sig validation\n");
|
||||
branchid = 0;
|
||||
}
|
||||
if ( ProduceSignature(TransactionSignatureCreator(&keystore,&txNewConst,vini,utxovalue,SIGHASH_ALL),scriptPubKey,sigdata,branchid) != 0 )
|
||||
{
|
||||
UpdateTransaction(mtx,vini,sigdata);
|
||||
fprintf(stderr,"SIG_TXHASH %s vini.%d %.8f\n",SIG_TXHASH.GetHex().c_str(),vini,(double)utxovalue/COIN);
|
||||
return(true);
|
||||
} //else fprintf(stderr,"sigerr SIG_TXHASH %s vini.%d %.8f\n",SIG_TXHASH.GetHex().c_str(),vini,(double)utxovalue/COIN);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
@@ -285,22 +275,21 @@ std::string NSPV_signtx(int64_t &rewardsum,int64_t &interestsum,UniValue &retcod
|
||||
{
|
||||
if ( vintx.vout[utxovout].nValue != used[i].satoshis )
|
||||
{
|
||||
fprintf(stderr,"vintx mismatch %.8f != %.8f\n",(double)vintx.vout[utxovout].nValue/COIN,(double)used[i].satoshis/COIN);
|
||||
LogPrintf("vintx mismatch %.8f != %.8f\n",(double)vintx.vout[utxovout].nValue/COIN,(double)used[i].satoshis/COIN);
|
||||
return("");
|
||||
}
|
||||
else if ( utxovout != used[i].vout )
|
||||
{
|
||||
fprintf(stderr,"vintx vout mismatch %d != %d\n",utxovout,used[i].vout);
|
||||
LogPrintf("vintx vout mismatch %d != %d\n",utxovout,used[i].vout);
|
||||
return("");
|
||||
}
|
||||
else if ( NSPV_SignTx(mtx,i,vintx.vout[utxovout].nValue,vintx.vout[utxovout].scriptPubKey,0) == 0 )
|
||||
{
|
||||
fprintf(stderr,"signing error for vini.%d\n",i);
|
||||
LogPrintf("signing error for vini.%d\n",i);
|
||||
return("");
|
||||
}
|
||||
} else fprintf(stderr,"couldnt find txid.%s/v%d or it was spent\n",mtx.vin[i].prevout.hash.GetHex().c_str(),utxovout); // of course much better handling is needed
|
||||
} else LogPrintf("couldnt find txid.%s/v%d or it was spent\n",mtx.vin[i].prevout.hash.GetHex().c_str(),utxovout); // of course much better handling is needed
|
||||
}
|
||||
fprintf(stderr,"sign %d inputs %.8f + interest %.8f -> %d outputs %.8f change %.8f\n",(int32_t)mtx.vin.size(),(double)totalinputs/COIN,(double)interest/COIN,(int32_t)mtx.vout.size(),(double)totaloutputs/COIN,(double)change/COIN);
|
||||
return(EncodeHexTx(mtx));
|
||||
}
|
||||
|
||||
@@ -360,7 +349,6 @@ UniValue NSPV_spend(char *srcaddr,char *destaddr,int64_t satoshis) // what its a
|
||||
result.push_back(Pair("amount",(double)satoshis/COIN));
|
||||
return(result);
|
||||
}
|
||||
printf("%s numutxos.%d balance %.8f\n",NSPV_utxosresult.coinaddr,NSPV_utxosresult.numutxos,(double)NSPV_utxosresult.total/COIN);
|
||||
CScript opret; std::string hex; struct NSPV_utxoresp used[NSPV_MAXVINS]; CMutableTransaction mtx; CTransaction tx; int64_t rewardsum=0,interestsum=0;
|
||||
mtx.fOverwintered = true;
|
||||
mtx.nExpiryHeight = 0;
|
||||
@@ -428,7 +416,7 @@ int64_t NSPV_AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total
|
||||
NSPV_utxosresp_purge(&ptr->U);
|
||||
NSPV_utxosresp_copy(&ptr->U,&NSPV_utxosresult);
|
||||
// }
|
||||
fprintf(stderr,"%s numutxos.%d\n",ptr->U.coinaddr,ptr->U.numutxos);
|
||||
LogPrintf("%s numutxos.%d\n",ptr->U.coinaddr,ptr->U.numutxos);
|
||||
memset(ptr->used,0,sizeof(ptr->used));
|
||||
return(NSPV_addinputs(ptr->used,mtx,total,maxinputs,ptr->U.utxos,ptr->U.numutxos));
|
||||
} else return(0);
|
||||
@@ -442,7 +430,7 @@ void NSPV_utxos2CCunspents(struct NSPV_utxosresp *ptr,std::vector<std::pair<CAdd
|
||||
CBitcoinAddress address(addrstr);
|
||||
if ( address.GetIndexKey(hashBytes, type, ptr->CCflag) == 0 )
|
||||
{
|
||||
fprintf(stderr,"couldnt get indexkey\n");
|
||||
LogPrintf("couldnt get indexkey\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < ptr->numutxos; i ++)
|
||||
@@ -466,7 +454,7 @@ void NSPV_txids2CCtxids(struct NSPV_txidsresp *ptr,std::vector<std::pair<CAddres
|
||||
CBitcoinAddress address(addrstr);
|
||||
if ( address.GetIndexKey(hashBytes, type, ptr->CCflag) == 0 )
|
||||
{
|
||||
fprintf(stderr,"couldnt get indexkey\n");
|
||||
LogPrintf("couldnt get indexkey\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < ptr->numtxids; i ++)
|
||||
|
||||
199
src/hush_utils.h
199
src/hush_utils.h
@@ -770,19 +770,15 @@ int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr
|
||||
memcpy(rmd160,buf+1,20);
|
||||
if ( (buf[21]&0xff) == hash.bytes[31] && (buf[22]&0xff) == hash.bytes[30] &&(buf[23]&0xff) == hash.bytes[29] && (buf[24]&0xff) == hash.bytes[28] )
|
||||
{
|
||||
//printf("coinaddr.(%s) valid checksum addrtype.%02x\n",coinaddr,*addrtypep);
|
||||
return(20);
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t i;
|
||||
if ( len > 20 )
|
||||
{
|
||||
hash = bits256_doublesha256(0,buf,len);
|
||||
}
|
||||
for (i=0; i<len; i++)
|
||||
printf("%02x ",buf[i]);
|
||||
printf("\nhex checkhash.(%s) len.%d mismatch %02x %02x %02x %02x vs %02x %02x %02x %02x\n",coinaddr,len,buf[len-1]&0xff,buf[len-2]&0xff,buf[len-3]&0xff,buf[len-4]&0xff,hash.bytes[31],hash.bytes[30],hash.bytes[29],hash.bytes[28]);
|
||||
LogPrintf("\nhex checkhash.(%s) len.%d mismatch %02x %02x %02x %02x vs %02x %02x %02x %02x\n",coinaddr,len,buf[len-1]&0xff,buf[len-2]&0xff,buf[len-3]&0xff,buf[len-4]&0xff,hash.bytes[31],hash.bytes[30],hash.bytes[29],hash.bytes[28]);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
@@ -801,10 +797,6 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,
|
||||
data[21+i] = hash.bytes[31-i];
|
||||
if ( (coinaddr= bitcoin_base58encode(coinaddr,data,25)) != 0 )
|
||||
{
|
||||
//uint8_t checktype,rmd160[20];
|
||||
//bitcoin_addr2rmd160(&checktype,rmd160,coinaddr);
|
||||
//if ( strcmp(checkaddr,coinaddr) != 0 )
|
||||
// printf("checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20));
|
||||
}
|
||||
return(coinaddr);
|
||||
}
|
||||
@@ -858,7 +850,7 @@ int32_t unhex(char c)
|
||||
int32_t hex;
|
||||
if ( (hex= _unhex(c)) < 0 )
|
||||
{
|
||||
fprintf(stderr,"unhex: illegal hexchar.(%c)\n",c);
|
||||
LogPrintf("unhex: illegal hexchar.(%c)\n",c);
|
||||
}
|
||||
return(hex);
|
||||
}
|
||||
@@ -868,7 +860,6 @@ unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])
|
||||
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex)
|
||||
{
|
||||
int32_t adjust,i = 0;
|
||||
//printf("decode.(%s)\n",hex);
|
||||
if ( is_hexstr(hex,n) <= 0 )
|
||||
{
|
||||
memset(bytes,0,n);
|
||||
@@ -881,7 +872,7 @@ int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex)
|
||||
if ( n > 0 )
|
||||
{
|
||||
bytes[0] = unhex(hex[0]);
|
||||
printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex));
|
||||
LogPrintf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex));
|
||||
}
|
||||
bytes++;
|
||||
hex++;
|
||||
@@ -918,10 +909,8 @@ int32_t init_hexbytes_noT(char *hexbytes,unsigned char *message,long len)
|
||||
{
|
||||
hexbytes[i*2] = hexbyte((message[i]>>4) & 0xf);
|
||||
hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf);
|
||||
//printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]);
|
||||
}
|
||||
hexbytes[len*2] = 0;
|
||||
//printf("len.%ld\n",len*2+1);
|
||||
return((int32_t)len*2+1);
|
||||
}
|
||||
|
||||
@@ -1087,7 +1076,7 @@ char *clonestr(char *str)
|
||||
char *clone;
|
||||
if ( str == 0 || str[0] == 0 )
|
||||
{
|
||||
printf("warning cloning nullstr.%p\n",str);
|
||||
LogPrintf("warning cloning nullstr.%p\n",str);
|
||||
#ifdef __APPLE__
|
||||
while ( 1 ) sleep(1);
|
||||
#endif
|
||||
@@ -1109,7 +1098,7 @@ int32_t safecopy(char *dest,char *src,long len)
|
||||
dest[i] = src[i];
|
||||
if ( i == len )
|
||||
{
|
||||
printf("safecopy: %s too long %ld\n",src,len);
|
||||
LogPrintf("safecopy: %s too long %ld\n",src,len);
|
||||
#ifdef __APPLE__
|
||||
//getchar();
|
||||
#endif
|
||||
@@ -1131,7 +1120,6 @@ char *parse_conf_line(char *line,char *field)
|
||||
line++;
|
||||
while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' )
|
||||
line[strlen(line)-1] = 0;
|
||||
//printf("LINE.(%s)\n",line);
|
||||
_stripwhite(line,0);
|
||||
return(clonestr(line));
|
||||
}
|
||||
@@ -1141,7 +1129,6 @@ double OS_milliseconds()
|
||||
struct timeval tv; double millis;
|
||||
gettimeofday(&tv,NULL);
|
||||
millis = ((double)tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.);
|
||||
//printf("tv_sec.%ld usec.%d %f\n",tv.tv_sec,tv.tv_usec,millis);
|
||||
return(millis);
|
||||
}
|
||||
|
||||
@@ -1193,7 +1180,7 @@ void queue_enqueue(char *name,queue_t *queue,struct queueitem *item)
|
||||
strcpy(queue->name,name);
|
||||
if ( item == 0 )
|
||||
{
|
||||
printf("FATAL type error: queueing empty value\n");
|
||||
LogPrintf("FATAL type error: queueing empty value\n");
|
||||
return;
|
||||
}
|
||||
lock_queue(queue);
|
||||
@@ -1230,7 +1217,7 @@ void *queue_delete(queue_t *queue,struct queueitem *copy,int32_t copysize)
|
||||
{
|
||||
DL_DELETE(queue->list,item);
|
||||
portable_mutex_unlock(&queue->mutex);
|
||||
printf("name.(%s) deleted item.%p list.%p\n",queue->name,item,queue->list);
|
||||
LogPrintf("name.(%s) deleted item.%p list.%p\n",queue->name,item,queue->list);
|
||||
return(item);
|
||||
}
|
||||
}
|
||||
@@ -1250,7 +1237,6 @@ void *queue_free(queue_t *queue)
|
||||
DL_DELETE(queue->list,item);
|
||||
free(item);
|
||||
}
|
||||
//printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list);
|
||||
}
|
||||
portable_mutex_unlock(&queue->mutex);
|
||||
return(0);
|
||||
@@ -1268,7 +1254,6 @@ void *queue_clone(queue_t *clone,queue_t *queue,int32_t size)
|
||||
memcpy(ptr,item,size);
|
||||
queue_enqueue(queue->name,clone,ptr);
|
||||
}
|
||||
//printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list);
|
||||
}
|
||||
portable_mutex_unlock(&queue->mutex);
|
||||
return(0);
|
||||
@@ -1304,7 +1289,6 @@ uint16_t _hush_userpass(char *username,char *password,FILE *fp)
|
||||
{
|
||||
if ( line[0] == '#' )
|
||||
continue;
|
||||
//printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword"));
|
||||
if ( (str= strstr(line,(char *)"rpcuser")) != 0 )
|
||||
rpcuser = parse_conf_line(str,(char *)"rpcuser");
|
||||
else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 )
|
||||
@@ -1312,7 +1296,6 @@ uint16_t _hush_userpass(char *username,char *password,FILE *fp)
|
||||
else if ( (str= strstr(line,(char *)"rpcport")) != 0 )
|
||||
{
|
||||
port = atoi(parse_conf_line(str,(char *)"rpcport"));
|
||||
//fprintf(stderr,"rpcport.%u in file\n",port);
|
||||
}
|
||||
}
|
||||
if ( rpcuser != 0 && rpcpassword != 0 )
|
||||
@@ -1320,7 +1303,6 @@ uint16_t _hush_userpass(char *username,char *password,FILE *fp)
|
||||
strcpy(username,rpcuser);
|
||||
strcpy(password,rpcpassword);
|
||||
}
|
||||
//printf("rpcuser.(%s) rpcpassword.(%s) HUSHUSERPASS.(%s) %u\n",rpcuser,rpcpassword,HUSHUSERPASS,port);
|
||||
if ( rpcuser != 0 )
|
||||
free(rpcuser);
|
||||
if ( rpcpassword != 0 )
|
||||
@@ -1340,7 +1322,7 @@ void hush_statefname(char *fname,char *symbol,char *str)
|
||||
else
|
||||
{
|
||||
if ( strcmp(symbol,"ZZZ") != 0 )
|
||||
printf("unexpected fname.(%s) vs %s [%s] n.%d len.%d (%s)\n",fname,symbol,SMART_CHAIN_SYMBOL,n,len,&fname[len - n]);
|
||||
LogPrintf("unexpected fname.(%s) vs %s [%s] n.%d len.%d (%s)\n",fname,symbol,SMART_CHAIN_SYMBOL,n,len,&fname[len - n]);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -1353,7 +1335,6 @@ void hush_statefname(char *fname,char *symbol,char *str)
|
||||
if ( symbol != 0 && symbol[0] != 0)
|
||||
{
|
||||
strcat(fname,symbol);
|
||||
//printf("statefname.(%s) -> (%s)\n",symbol,fname);
|
||||
#ifdef _WIN32
|
||||
strcat(fname,"\\");
|
||||
#else
|
||||
@@ -1361,7 +1342,6 @@ void hush_statefname(char *fname,char *symbol,char *str)
|
||||
#endif
|
||||
}
|
||||
strcat(fname,str);
|
||||
//printf("test.(%s) -> [%s] statename.(%s) %s\n",test,SMART_CHAIN_SYMBOL,symbol,fname);
|
||||
}
|
||||
|
||||
void hush_configfile(char *symbol,uint16_t rpcport)
|
||||
@@ -1398,14 +1378,13 @@ void hush_configfile(char *symbol,uint16_t rpcport)
|
||||
{
|
||||
fprintf(fp,"rpcuser=user%u\nrpcpassword=pass%s\nrpcport=%u\nserver=1\ntxindex=1\nrpcworkqueue=4096\nrpcallowip=127.0.0.1\nrpcbind=127.0.0.1\n",crc,password,rpcport);
|
||||
fclose(fp);
|
||||
printf("Created (%s)\n",fname);
|
||||
} else printf("Couldnt create (%s)\n",fname);
|
||||
LogPrintf("Created (%s)\n",fname);
|
||||
} else LogPrintf("Couldnt create (%s)\n",fname);
|
||||
#endif
|
||||
} else {
|
||||
_hush_userpass(myusername,mypassword,fp);
|
||||
mapArgs["-rpcpassword"] = mypassword;
|
||||
mapArgs["-rpcusername"] = myusername;
|
||||
//fprintf(stderr,"myusername.(%s)\n",myusername);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
@@ -1429,9 +1408,8 @@ void hush_configfile(char *symbol,uint16_t rpcport)
|
||||
DRAGONX_PORT = hushport;
|
||||
sprintf(HUSHUSERPASS,"%s:%s",username,password);
|
||||
fclose(fp);
|
||||
//printf("HUSH.(%s) -> userpass.(%s)\n",fname,HUSHUSERPASS);
|
||||
} else {
|
||||
printf("could not open.(%s)\n",fname);
|
||||
LogPrintf("could not open.(%s)\n",fname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1466,13 +1444,13 @@ uint32_t hush_smartmagic(char *symbol,uint64_t supply,uint8_t *extraptr,int32_t
|
||||
{
|
||||
vcalc_sha256(0,hash.bytes,extraptr,extralen);
|
||||
crc0 = hash.uints[0];
|
||||
fprintf(stderr,"DragonX raw magic=");
|
||||
int32_t i; for (i=0; i<extralen; i++)
|
||||
fprintf(stderr,"%02x",extraptr[i]);
|
||||
fprintf(stderr," extralen=%d crc0=%x\n",extralen,crc0);
|
||||
LogPrintf("DragonX raw magic extralen=%d crc0=%x\n",extralen,crc0);
|
||||
}
|
||||
|
||||
//TODO: why is this needed?
|
||||
// Legacy special case: HUSH3 mainnet had a hardcoded network magic (HUSH_MAGIC)
|
||||
// rather than the crc32-derived value used by every other chain. This branch is
|
||||
// dead on DragonX (SMART_CHAIN_SYMBOL is "DRAGONX", never "HUSH3"); it is kept only
|
||||
// so the function still reproduces HUSH3's magic if ever run with that symbol.
|
||||
const bool ishush3 = strncmp(symbol, "HUSH3",5) == 0 ? true : false;
|
||||
if(ishush3) {
|
||||
return HUSH_MAGIC;
|
||||
@@ -1497,8 +1475,7 @@ uint16_t hush_port(char *symbol,uint64_t supply,uint32_t *magicp,uint8_t *extrap
|
||||
fprintf(stderr,"%s: extralen=%d\n",__func__,extralen);
|
||||
|
||||
*magicp = hush_smartmagic(symbol,supply,extraptr,extralen);
|
||||
//if(fDebug)
|
||||
fprintf(stderr,"%s: extralen=%d, supply=%lu\n",__func__,extralen, supply);
|
||||
LogPrintf("%s: extralen=%d, supply=%lu\n",__func__,extralen, supply);
|
||||
|
||||
return(hush_smartport(*magicp,extralen));
|
||||
}
|
||||
@@ -1519,16 +1496,19 @@ uint64_t hush_max_money()
|
||||
return hush_current_supply(10000000);
|
||||
}
|
||||
|
||||
// This implements the Hush Emission Curve, the miner subsidy part,
|
||||
// and must be kept in sync with hush_commision() in hush_bitcoind.h!
|
||||
// Changing these functions are consensus changes!
|
||||
// Here Be Dragons! -- Duke Leto
|
||||
// This implements the emission curve (miner subsidy part) and must be kept in
|
||||
// sync with hush_commission() in hush_bitcoind.h! Changing these functions,
|
||||
// including the height literals below, is a CONSENSUS change.
|
||||
// NOTE: this TRANSITION boundary is 128 here, while hush_commission() uses 129.
|
||||
// This off-by-one between the two curves is a historical consensus quirk and is
|
||||
// deliberately left as-is: changing either value would be a consensus change.
|
||||
uint64_t hush_block_subsidy(int height)
|
||||
{
|
||||
uint64_t subsidy = 0;
|
||||
int32_t HALVING1 = GetArg("-z2zheight",340000);
|
||||
//TODO: support INTERVAL :(
|
||||
//int32_t INTERVAL = GetArg("-ac_halving1",840000);
|
||||
// Consensus: TRANSITION is 128 here vs 129 in hush_commission(); do not change (see note above).
|
||||
int32_t TRANSITION = 128;
|
||||
|
||||
if (height < TRANSITION) {
|
||||
@@ -1564,14 +1544,14 @@ uint64_t hush_block_subsidy(int height)
|
||||
subsidy = 549316;
|
||||
} else if (height < 23860000) {
|
||||
subsidy = 274658;
|
||||
} else if (height < 23860000) {
|
||||
subsidy = 137329;
|
||||
// removed unreachable duplicate `height < 23860000` (=> 137329); kept in sync
|
||||
// with hush_commission() — the schedule drops straight to 68664 next.
|
||||
} else if (height < 25540000) {
|
||||
subsidy = 68664;
|
||||
} else if (height < 27220000) {
|
||||
subsidy = 34332;
|
||||
} else if (height < 27220000) {
|
||||
subsidy = 17166;
|
||||
// removed unreachable duplicate `height < 27220000` (=> 17166); kept in sync
|
||||
// with hush_commission() — the schedule drops straight to 8583 next.
|
||||
} else if (height < 28900000) {
|
||||
subsidy = 8583;
|
||||
} else if (height < 30580000) {
|
||||
@@ -1611,7 +1591,9 @@ uint64_t hush_block_subsidy(int height)
|
||||
return subsidy;
|
||||
}
|
||||
|
||||
// wrapper for more general supply curves of Hush Arrakis Chains
|
||||
// Wrapper for the more general supply curves used by assetchains (era/halving/decay driven).
|
||||
// On DragonX the reward comes from the -ac_reward/-ac_halving parameters set in hush_args();
|
||||
// the ishush3 branch below is a legacy special case that is dead on DragonX.
|
||||
uint64_t hush_sc_block_subsidy(int nHeight)
|
||||
{
|
||||
// Find current era, start from beginning reward, and determine current subsidy
|
||||
@@ -1619,12 +1601,13 @@ uint64_t hush_sc_block_subsidy(int nHeight)
|
||||
int64_t subsidyDifference;
|
||||
int32_t numhalvings = 0, curEra = 0, sign = 1;
|
||||
static uint64_t cached_subsidy; static int32_t cached_numhalvings; static int cached_era;
|
||||
// Legacy-HUSH3 detection: dead on DragonX (SMART_CHAIN_SYMBOL is "DRAGONX"), used only
|
||||
// to route HUSH3 mainnet through its bespoke hush_block_subsidy() emission curve below.
|
||||
const bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||
// 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
|
||||
if ( ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] == 0 ) {
|
||||
fprintf(stderr,"%s: defaulting to 0.0001 subsidy\n",__func__);
|
||||
LogPrintf("%s: defaulting to 0.0001 subsidy\n",__func__);
|
||||
subsidy = 10000;
|
||||
} else if ( (ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] != 0) || ASSETCHAINS_ENDSUBSIDY[0] != 0 ) {
|
||||
// if we have an end block in the first era, find our current era
|
||||
@@ -1656,10 +1639,11 @@ uint64_t hush_sc_block_subsidy(int nHeight)
|
||||
if(fDebug)
|
||||
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
|
||||
// Generic halving/decay path used by DragonX and other assetchains.
|
||||
// (Legacy HUSH3 mainnet did NOT use this path; it took the ishush3
|
||||
// branch above, which reproduces its bespoke emission curve.)
|
||||
if ( ASSETCHAINS_DECAY[curEra] == 0 ) {
|
||||
subsidy >>= numhalvings;
|
||||
// fprintf(stderr,"%s: no decay, numhalvings.%d curEra.%d subsidy.%ld nStart.%ld\n",__func__, numhalvings, curEra, subsidy, nStart);
|
||||
} else if ( ASSETCHAINS_DECAY[curEra] == 100000000 && ASSETCHAINS_ENDSUBSIDY[curEra] != 0 ) {
|
||||
if ( curEra == ASSETCHAINS_LASTERA )
|
||||
{
|
||||
@@ -1675,12 +1659,11 @@ uint64_t hush_sc_block_subsidy(int nHeight)
|
||||
}
|
||||
denominator = ASSETCHAINS_ENDSUBSIDY[curEra] - nStart;
|
||||
numerator = denominator - ((ASSETCHAINS_ENDSUBSIDY[curEra] - nHeight) + ((nHeight - nStart) % ASSETCHAINS_HALVING[curEra]));
|
||||
// fprintf(stderr,"%s: numerator=%ld , denominator=%ld at height=%d\n",__func__,numerator, denominator,nHeight);
|
||||
if( denominator ) {
|
||||
subsidy = subsidy - sign * ((subsidyDifference * numerator) / denominator);
|
||||
} else {
|
||||
fprintf(stderr,"%s: invalid denominator=%ld !\n", __func__, denominator);
|
||||
fprintf(stderr,"%s: defaulting to 0.0001 subsidy\n",__func__);
|
||||
LogPrintf("%s: invalid denominator=%ld !\n", __func__, denominator);
|
||||
LogPrintf("%s: defaulting to 0.0001 subsidy\n",__func__);
|
||||
subsidy = 10000;
|
||||
}
|
||||
} else {
|
||||
@@ -1698,13 +1681,13 @@ uint64_t hush_sc_block_subsidy(int nHeight)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"%s: curEra.%d > lastEra.%lu\n", __func__, curEra, ASSETCHAINS_LASTERA);
|
||||
LogPrintf("%s: curEra.%d > lastEra.%lu\n", __func__, curEra, ASSETCHAINS_LASTERA);
|
||||
}
|
||||
}
|
||||
uint32_t magicExtra = ASSETCHAINS_STAKED ? ASSETCHAINS_MAGIC : (ASSETCHAINS_MAGIC & 0xffffff);
|
||||
if ( ASSETCHAINS_SUPPLY > 10000000000 ) // over 10 billion?
|
||||
{
|
||||
fprintf(stderr,"%s: Detected supply over 10 billion, danger zone!\n",__func__);
|
||||
LogPrintf("%s: Detected supply over 10 billion, danger zone!\n",__func__);
|
||||
if ( nHeight <= ASSETCHAINS_SUPPLY/1000000000 )
|
||||
{
|
||||
subsidy += (uint64_t)1000000000 * COIN;
|
||||
@@ -1782,7 +1765,7 @@ void hush_args(char *argv0)
|
||||
IS_HUSH_NOTARY = 1;
|
||||
HUSH_MININGTHREADS = 1;
|
||||
mapArgs ["-genproclimit"] = itostr(HUSH_MININGTHREADS);
|
||||
fprintf(stderr,"running as notary.%d %s\n",i,notaries_list[hush_season-1][i][0]);
|
||||
LogPrintf("running as notary.%d %s\n",i,notaries_list[hush_season-1][i][0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1799,14 +1782,23 @@ void hush_args(char *argv0)
|
||||
|
||||
LogPrint("net", "%s: isdragonx=%d\n", __func__, isdragonx);
|
||||
if (isdragonx) {
|
||||
// node8-node10 are PLACEHOLDERS with no DNS records yet. A hostname that
|
||||
// does not resolve is harmless here: ThreadOpenAddedConnections just fails
|
||||
// to open the connection and retries on its 2-minute cycle. Reserving the
|
||||
// names in the binary means a future seed can be brought into the -addnode
|
||||
// set by creating one DNS record, with no release and no waiting for users
|
||||
// to upgrade. (seed.dragonx.is already provides that for the DNS-seed path;
|
||||
// this extends the same property to the addnode path.)
|
||||
DRAGONX_nodes = {"node1.dragonx.is","node2.dragonx.is","node3.dragonx.is",
|
||||
"node4.dragonx.is","node5.dragonx.is"
|
||||
"node4.dragonx.is","node5.dragonx.is","node6.dragonx.is",
|
||||
"node7.dragonx.is","node8.dragonx.is","node9.dragonx.is",
|
||||
"node10.dragonx.is"
|
||||
};
|
||||
}
|
||||
|
||||
vector<string> more_nodes = mapMultiArgs["-addnode"];
|
||||
if (more_nodes.size() > 0) {
|
||||
fprintf(stderr,"%s: Adding %lu more nodes via custom -addnode arguments\n", __func__, more_nodes.size() );
|
||||
LogPrint("net", "%s: Adding %lu more nodes via custom -addnode arguments\n", __func__, more_nodes.size() );
|
||||
}
|
||||
// Add default DRAGONX nodes after custom addnodes, if applicable
|
||||
if(DRAGONX_nodes.size() > 0) {
|
||||
@@ -1848,19 +1840,19 @@ void hush_args(char *argv0)
|
||||
if ( i > 1 && ccEnablesHeight[i-2] == ecode )
|
||||
break;
|
||||
if ( ecode > 255 || ecode < 0 )
|
||||
fprintf(stderr, "ac_ccactivateht: invalid evalcode.%i must be between 0 and 256.\n", ecode);
|
||||
LogPrintf("ac_ccactivateht: invalid evalcode.%i must be between 0 and 256.\n", ecode);
|
||||
else if ( ht > 0 )
|
||||
{
|
||||
// update global map.
|
||||
mapHeightEvalActivate[ecode] = ht;
|
||||
fprintf(stderr, "ac_ccactivateht: ecode.%i activates at height.%i\n", ecode, mapHeightEvalActivate[ecode]);
|
||||
LogPrintf("ac_ccactivateht: ecode.%i activates at height.%i\n", ecode, mapHeightEvalActivate[ecode]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( (HUSH_REWIND= GetArg("-rewind",0)) != 0 )
|
||||
{
|
||||
printf("HUSH_REWIND %d\n",HUSH_REWIND);
|
||||
LogPrintf("HUSH_REWIND %d\n",HUSH_REWIND);
|
||||
}
|
||||
HUSH_EARLYTXID = Parseuint256(GetArg("-earlytxid","0").c_str());
|
||||
ASSETCHAINS_EARLYTXIDCONTRACT = GetArg("-ac_earlytxidcontract",0);
|
||||
@@ -1878,7 +1870,7 @@ void hush_args(char *argv0)
|
||||
STAKING_MIN_DIFF = ASSETCHAINS_MINDIFF[i];
|
||||
// only worth mentioning if it's not equihash
|
||||
if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
|
||||
printf("ASSETCHAINS_ALGO, algorithm set to %s\n", selectedAlgo.c_str());
|
||||
LogPrintf("ASSETCHAINS_ALGO, algorithm set to %s\n", selectedAlgo.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1888,11 +1880,11 @@ void hush_args(char *argv0)
|
||||
{
|
||||
printf("equihash values N.%li and K.%li are not currently available\n", ASSETCHAINS_NK[0], ASSETCHAINS_NK[1]);
|
||||
exit(0);
|
||||
} else printf("ASSETCHAINS_ALGO, algorithm set to equihash with N.%li and K.%li\n", ASSETCHAINS_NK[0], ASSETCHAINS_NK[1]);
|
||||
} else LogPrintf("ASSETCHAINS_ALGO, algorithm set to equihash with N.%li and K.%li\n", ASSETCHAINS_NK[0], ASSETCHAINS_NK[1]);
|
||||
}
|
||||
if (i == ASSETCHAINS_NUMALGOS)
|
||||
{
|
||||
printf("ASSETCHAINS_ALGO, %s not supported. using equihash\n", selectedAlgo.c_str());
|
||||
LogPrintf("ASSETCHAINS_ALGO, %s not supported. using equihash\n", selectedAlgo.c_str());
|
||||
}
|
||||
|
||||
// Set our symbol from -ac_name value
|
||||
@@ -1907,14 +1899,14 @@ void hush_args(char *argv0)
|
||||
} else {
|
||||
ASSETCHAINS_RANDOMX_VALIDATION = 1; // all other RandomX HACs: enforce from height 1
|
||||
}
|
||||
printf("ASSETCHAINS_RANDOMX_VALIDATION set to %d for %s\n", ASSETCHAINS_RANDOMX_VALIDATION, SMART_CHAIN_SYMBOL);
|
||||
LogPrintf("ASSETCHAINS_RANDOMX_VALIDATION set to %d for %s\n", ASSETCHAINS_RANDOMX_VALIDATION, SMART_CHAIN_SYMBOL);
|
||||
}
|
||||
|
||||
ASSETCHAINS_LASTERA = GetArg("-ac_eras", 1);
|
||||
if ( ASSETCHAINS_LASTERA < 1 || ASSETCHAINS_LASTERA > ASSETCHAINS_MAX_ERAS )
|
||||
{
|
||||
ASSETCHAINS_LASTERA = 1;
|
||||
printf("ASSETCHAINS_LASTERA, if specified, must be between 1 and %u. ASSETCHAINS_LASTERA set to %lu\n", ASSETCHAINS_MAX_ERAS, ASSETCHAINS_LASTERA);
|
||||
LogPrintf("ASSETCHAINS_LASTERA, if specified, must be between 1 and %u. ASSETCHAINS_LASTERA set to %lu\n", ASSETCHAINS_MAX_ERAS, ASSETCHAINS_LASTERA);
|
||||
}
|
||||
ASSETCHAINS_LASTERA -= 1;
|
||||
if(fDebug)
|
||||
@@ -1925,7 +1917,7 @@ void hush_args(char *argv0)
|
||||
ASSETCHAINS_TIMEUNLOCKTO = GetArg("-ac_timeunlockto", 0);
|
||||
if ( ASSETCHAINS_TIMEUNLOCKFROM > ASSETCHAINS_TIMEUNLOCKTO )
|
||||
{
|
||||
printf("ASSETCHAINS_TIMELOCKGTE - must specify valid ac_timeunlockfrom and ac_timeunlockto\n");
|
||||
LogPrintf("ASSETCHAINS_TIMELOCKGTE - must specify valid ac_timeunlockfrom and ac_timeunlockto\n");
|
||||
ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
|
||||
ASSETCHAINS_TIMEUNLOCKFROM = ASSETCHAINS_TIMEUNLOCKTO = 0;
|
||||
}
|
||||
@@ -1944,7 +1936,7 @@ void hush_args(char *argv0)
|
||||
ASSETCHAINS_SCRIPTPUB = GetArg("-ac_script","");
|
||||
|
||||
|
||||
fprintf(stderr,"%s: Setting custom %s reward isdragonx=%d reward,halving,subsidy chain values...\n",__func__, SMART_CHAIN_SYMBOL, isdragonx);
|
||||
LogPrintf("%s: Setting custom %s reward isdragonx=%d reward,halving,subsidy chain values...\n",__func__, SMART_CHAIN_SYMBOL, isdragonx);
|
||||
if(isdragonx) {
|
||||
// DragonX chain parameters (previously set via wrapper script)
|
||||
// -ac_name=DRAGONX -ac_algo=randomx -ac_halving=3500000 -ac_reward=300000000 -ac_blocktime=36 -ac_private=1
|
||||
@@ -1960,12 +1952,12 @@ void hush_args(char *argv0)
|
||||
if ( ASSETCHAINS_DECAY[i] == 100000000 && ASSETCHAINS_ENDSUBSIDY == 0 )
|
||||
{
|
||||
ASSETCHAINS_DECAY[i] = 0;
|
||||
printf("ERA%u: ASSETCHAINS_DECAY of 100000000 means linear and that needs ASSETCHAINS_ENDSUBSIDY\n", i);
|
||||
LogPrintf("ERA%u: ASSETCHAINS_DECAY of 100000000 means linear and that needs ASSETCHAINS_ENDSUBSIDY\n", i);
|
||||
}
|
||||
else if ( ASSETCHAINS_DECAY[i] > 100000000 )
|
||||
{
|
||||
ASSETCHAINS_DECAY[i] = 0;
|
||||
printf("ERA%u: ASSETCHAINS_DECAY cant be more than 100000000\n", i);
|
||||
LogPrintf("ERA%u: ASSETCHAINS_DECAY cant be more than 100000000\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1991,21 +1983,15 @@ void hush_args(char *argv0)
|
||||
SplitStr(GetArg("-ac_stocks",""), ASSETCHAINS_STOCKS);
|
||||
if ( ASSETCHAINS_STOCKS.size() > 0 )
|
||||
ASSETCHAINS_CBOPRET |= 8;
|
||||
for (i=0; i<ASSETCHAINS_PRICES.size(); i++)
|
||||
fprintf(stderr,"%s ",ASSETCHAINS_PRICES[i].c_str());
|
||||
fprintf(stderr,"%d -ac_prices\n",(int32_t)ASSETCHAINS_PRICES.size());
|
||||
for (i=0; i<ASSETCHAINS_STOCKS.size(); i++)
|
||||
fprintf(stderr,"%s ",ASSETCHAINS_STOCKS[i].c_str());
|
||||
fprintf(stderr,"%d -ac_stocks\n",(int32_t)ASSETCHAINS_STOCKS.size());
|
||||
LogPrintf("%d -ac_prices\n",(int32_t)ASSETCHAINS_PRICES.size());
|
||||
LogPrintf("%d -ac_stocks\n",(int32_t)ASSETCHAINS_STOCKS.size());
|
||||
}
|
||||
hexstr = GetArg("-ac_mineropret","");
|
||||
if ( hexstr.size() != 0 )
|
||||
{
|
||||
Mineropret.resize(hexstr.size()/2);
|
||||
decode_hex(Mineropret.data(),hexstr.size()/2,(char *)hexstr.c_str());
|
||||
for (i=0; i<Mineropret.size(); i++)
|
||||
fprintf(stderr,"%02x",Mineropret[i]);
|
||||
fprintf(stderr," Mineropret\n");
|
||||
LogPrintf(" Mineropret\n");
|
||||
}
|
||||
if ( ASSETCHAINS_COMMISSION != 0 && ASSETCHAINS_FOUNDERS_REWARD != 0 )
|
||||
{
|
||||
@@ -2017,7 +2003,8 @@ void hush_args(char *argv0)
|
||||
uint8_t prevCCi = 0;
|
||||
ASSETCHAINS_CCLIB = GetArg("-ac_cclib","hush3");
|
||||
|
||||
// these are the enabled CCs on HUSH3 mainnet
|
||||
// Default CC set inherited from legacy HUSH3 mainnet; only used when a chain
|
||||
// enables CryptoConditions and does not override -ac_ccenable.
|
||||
Split(GetArg("-ac_ccenable","228,234,235,236,241"), sizeof(ccenables)/sizeof(*ccenables), ccenables, 0);
|
||||
for (i=nonz=0; i<0x100; i++)
|
||||
{
|
||||
@@ -2025,10 +2012,9 @@ void hush_args(char *argv0)
|
||||
{
|
||||
nonz++;
|
||||
prevCCi = ccenables[i];
|
||||
fprintf(stderr,"%d ",(uint8_t)(ccenables[i] & 0xff));
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"nonz.%d ccenables[]\n",nonz);
|
||||
LogPrintf("nonz.%d ccenables[]\n",nonz);
|
||||
if ( nonz > 0 )
|
||||
{
|
||||
for (i=0; i<256; i++)
|
||||
@@ -2128,9 +2114,9 @@ void hush_args(char *argv0)
|
||||
if ( ASSETCHAINS_FOUNDERS_REWARD == 0 )
|
||||
{
|
||||
ASSETCHAINS_COMMISSION = 53846154; // maps to 35%
|
||||
printf("ASSETCHAINS_COMMISSION defaulted to 35%% when founders reward active\n");
|
||||
LogPrintf("ASSETCHAINS_COMMISSION defaulted to 35%% when founders reward active\n");
|
||||
} else {
|
||||
printf("ASSETCHAINS_FOUNDERS_REWARD set to %ld\n", ASSETCHAINS_FOUNDERS_REWARD);
|
||||
LogPrintf("ASSETCHAINS_FOUNDERS_REWARD set to %ld\n", ASSETCHAINS_FOUNDERS_REWARD);
|
||||
}
|
||||
/*else if ( ASSETCHAINS_SELFIMPORT.size() == 0 )
|
||||
{
|
||||
@@ -2142,12 +2128,12 @@ void hush_args(char *argv0)
|
||||
if ( ASSETCHAINS_COMMISSION != 0 )
|
||||
{
|
||||
ASSETCHAINS_COMMISSION = 0;
|
||||
printf("ASSETCHAINS_COMMISSION needs an ASSETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n");
|
||||
LogPrintf("ASSETCHAINS_COMMISSION needs an ASSETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n");
|
||||
}
|
||||
if ( ASSETCHAINS_FOUNDERS != 0 )
|
||||
{
|
||||
ASSETCHAINS_FOUNDERS = 0;
|
||||
printf("ASSETCHAINS_FOUNDERS needs an ASSETCHAINS_OVERRIDE_PUBKEY or ASSETCHAINS_SCRIPTPUB\n");
|
||||
LogPrintf("ASSETCHAINS_FOUNDERS needs an ASSETCHAINS_OVERRIDE_PUBKEY or ASSETCHAINS_SCRIPTPUB\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2215,7 +2201,7 @@ void hush_args(char *argv0)
|
||||
// NOTE: Hush does not use this, we use -ac_script to implement our FR -- Duke
|
||||
if ( ASSETCHAINS_FOUNDERS_REWARD != 0 )
|
||||
{
|
||||
fprintf(stderr, "set founders reward.%lld\n",(long long)ASSETCHAINS_FOUNDERS_REWARD);
|
||||
LogPrintf("set founders reward.%lld\n",(long long)ASSETCHAINS_FOUNDERS_REWARD);
|
||||
extralen += dragon_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_FOUNDERS_REWARD),(void *)&ASSETCHAINS_FOUNDERS_REWARD);
|
||||
}
|
||||
}
|
||||
@@ -2224,14 +2210,12 @@ void hush_args(char *argv0)
|
||||
decode_hex(&extraptr[extralen],ASSETCHAINS_SCRIPTPUB.size()/2,(char *)ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
extralen += ASSETCHAINS_SCRIPTPUB.size()/2;
|
||||
//extralen += dragon_rwnum(1,&extraptr[extralen],(int32_t)ASSETCHAINS_SCRIPTPUB.size(),(void *)ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
fprintf(stderr,"append ac_script %s\n",ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
LogPrintf("append ac_script %s\n",ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
}
|
||||
if ( ASSETCHAINS_SELFIMPORT.size() > 0 )
|
||||
{
|
||||
memcpy(&extraptr[extralen],(char *)ASSETCHAINS_SELFIMPORT.c_str(),ASSETCHAINS_SELFIMPORT.size());
|
||||
for (i=0; i<ASSETCHAINS_SELFIMPORT.size(); i++)
|
||||
fprintf(stderr,"%c",extraptr[extralen+i]);
|
||||
fprintf(stderr," selfimport\n");
|
||||
LogPrintf(" selfimport\n");
|
||||
extralen += ASSETCHAINS_SELFIMPORT.size();
|
||||
}
|
||||
if ( ASSETCHAINS_BEAMPORT != 0 )
|
||||
@@ -2241,7 +2225,7 @@ void hush_args(char *argv0)
|
||||
if ( ASSETCHAINS_MARMARA != 0 )
|
||||
extraptr[extralen++] = ASSETCHAINS_MARMARA;
|
||||
|
||||
fprintf(stderr,"extralen.%d before disable bits\n",extralen);
|
||||
LogPrintf("extralen.%d before disable bits\n",extralen);
|
||||
|
||||
if ( nonz > 0 ) {
|
||||
memcpy(&extraptr[extralen],disablebits,sizeof(disablebits));
|
||||
@@ -2252,14 +2236,13 @@ void hush_args(char *argv0)
|
||||
for (i=0; i<ASSETCHAINS_CCLIB.size(); i++)
|
||||
{
|
||||
extraptr[extralen++] = ASSETCHAINS_CCLIB[i];
|
||||
fprintf(stderr,"%c",ASSETCHAINS_CCLIB[i]);
|
||||
}
|
||||
fprintf(stderr," <- CCLIB name\n");
|
||||
LogPrintf(" <- CCLIB name\n");
|
||||
}
|
||||
|
||||
if ( ASSETCHAINS_BLOCKTIME != 60 ) {
|
||||
extralen += dragon_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_BLOCKTIME),(void *)&ASSETCHAINS_BLOCKTIME);
|
||||
fprintf(stderr,"%s: ASSETCHAINS_BLOCKTIME=%d, extralen=%d\n", __func__, ASSETCHAINS_BLOCKTIME, extralen);
|
||||
LogPrintf("%s: ASSETCHAINS_BLOCKTIME=%d, extralen=%d\n", __func__, ASSETCHAINS_BLOCKTIME, extralen);
|
||||
}
|
||||
|
||||
if ( Mineropret.size() != 0 )
|
||||
@@ -2290,7 +2273,7 @@ void hush_args(char *argv0)
|
||||
}
|
||||
//hush_pricesinit();
|
||||
hush_cbopretupdate(1); // will set Mineropret
|
||||
fprintf(stderr,"This blockchain uses data produced from CoinDesk Bitcoin Price Index\n");
|
||||
LogPrintf("This blockchain uses data produced from CoinDesk Bitcoin Price Index\n");
|
||||
}
|
||||
if ( ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0 )
|
||||
{
|
||||
@@ -2346,13 +2329,12 @@ void hush_args(char *argv0)
|
||||
MAX_MONEY = HUSH_MAXNVALUE;
|
||||
if(fDebug)
|
||||
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);
|
||||
uint16_t tmpport = hush_port(SMART_CHAIN_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen);
|
||||
if ( GetArg("-port",0) != 0 )
|
||||
{
|
||||
ASSETCHAINS_P2PPORT = GetArg("-port",0);
|
||||
if(ishush3) {
|
||||
fprintf(stderr,"set HUSH3 p2pport.%u\n",ASSETCHAINS_P2PPORT);
|
||||
LogPrintf("set HUSH3 p2pport.%u\n",ASSETCHAINS_P2PPORT);
|
||||
ASSETCHAINS_P2PPORT = 18030;
|
||||
}
|
||||
if(fDebug)
|
||||
@@ -2368,7 +2350,6 @@ void hush_args(char *argv0)
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
|
||||
#endif
|
||||
}
|
||||
//fprintf(stderr,"Got datadir.(%s)\n",dirname);
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
||||
{
|
||||
int32_t hush_baseid(char *origbase);
|
||||
@@ -2386,7 +2367,6 @@ void hush_args(char *argv0)
|
||||
fprintf(stderr,"ac_cbmaturity must be >0, shutting down\n");
|
||||
StartShutdown();
|
||||
}
|
||||
//fprintf(stderr,"ASSETCHAINS_RPCPORT (%s) %u\n",SMART_CHAIN_SYMBOL,ASSETCHAINS_RPCPORT);
|
||||
}
|
||||
if ( ASSETCHAINS_RPCPORT == 0 )
|
||||
ASSETCHAINS_RPCPORT = ASSETCHAINS_P2PPORT + 1;
|
||||
@@ -2402,13 +2382,16 @@ void hush_args(char *argv0)
|
||||
if ( HUSH_CCACTIVATE != 0 )
|
||||
{
|
||||
ASSETCHAINS_CC = 2;
|
||||
fprintf(stderr,"smart utxo CC contracts will activate at height.%d\n",HUSH_CCACTIVATE);
|
||||
LogPrintf("smart utxo CC contracts will activate at height.%d\n",HUSH_CCACTIVATE);
|
||||
} else if ( ccEnablesHeight[0] != 0 ) {
|
||||
ASSETCHAINS_CC = 2;
|
||||
fprintf(stderr,"smart utxo CC contract %d will activate at height.%d\n",(int32_t)ccEnablesHeight[0],(int32_t)ccEnablesHeight[1]);
|
||||
LogPrintf("smart utxo CC contract %d will activate at height.%d\n",(int32_t)ccEnablesHeight[0],(int32_t)ccEnablesHeight[1]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Legacy fallback path taken only when no -ac_name is set (SMART_CHAIN_SYMBOL empty).
|
||||
// Dead on DragonX, which always runs with -ac_name=DRAGONX. The HUSH3/Bitcoin conf
|
||||
// paths and default ports below are historical and left as-is for backwards compat.
|
||||
char fname[512],username[512],password[4096]; int32_t iter; FILE *fp;
|
||||
ASSETCHAINS_P2PPORT = 7770;
|
||||
ASSETCHAINS_RPCPORT = 7771;
|
||||
@@ -2439,8 +2422,7 @@ void hush_args(char *argv0)
|
||||
_hush_userpass(username,password,fp);
|
||||
sprintf(iter == 0 ? HUSHUSERPASS : BTCUSERPASS,"%s:%s",username,password);
|
||||
fclose(fp);
|
||||
//printf("HUSH.(%s) -> userpass.(%s)\n",fname,HUSHUSERPASS);
|
||||
} //else printf("couldnt open.(%s)\n",fname);
|
||||
}
|
||||
if ( IS_HUSH_NOTARY == 0 )
|
||||
break;
|
||||
}
|
||||
@@ -2449,7 +2431,6 @@ void hush_args(char *argv0)
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
||||
{
|
||||
BITCOIND_RPCPORT = GetArg("-rpcport", ASSETCHAINS_RPCPORT);
|
||||
//fprintf(stderr,"(%s) port.%u chain params initialized\n",SMART_CHAIN_SYMBOL,BITCOIND_RPCPORT);
|
||||
|
||||
// Set custom cc rulse for chains here
|
||||
if ( strcmp("HUSH3",SMART_CHAIN_SYMBOL) == 0 ) {
|
||||
@@ -2505,7 +2486,7 @@ void hush_prefetch(FILE *fp)
|
||||
{
|
||||
rewind(fp);
|
||||
while ( fread(ignore,1,incr,fp) == incr ) // prefetch
|
||||
fprintf(stderr,".");
|
||||
;
|
||||
free(ignore);
|
||||
}
|
||||
}
|
||||
|
||||
187
src/init.cpp
187
src/init.cpp
@@ -60,6 +60,7 @@
|
||||
#include "wallet/wallet.h"
|
||||
#include "wallet/walletdb.h"
|
||||
#include "wallet/asyncrpcoperation_saplingconsolidation.h"
|
||||
#include "wallet/asyncrpcoperation_autoshieldcoinbase.h"
|
||||
#include "wallet/asyncrpcoperation_sweep.h"
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
@@ -120,7 +121,11 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
|
||||
|
||||
static const char* DEFAULT_ASMAP_FILENAME="asmap.dat";
|
||||
|
||||
CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h
|
||||
// LevelDB read-cache size (bytes) for the notarizations (dPoW) DB. Non-consensus: just the
|
||||
// in-memory cache the DB is opened with; the value here does not affect validation.
|
||||
static const size_t NOTARIZATION_DB_CACHE_BYTES = 100 * 1024 * 1024; // 100 MiB
|
||||
|
||||
CClientUIInterface uiInterface; // global UI callback dispatcher (declared extern in ui_interface.h)
|
||||
|
||||
// Shutdown
|
||||
//
|
||||
@@ -148,7 +153,7 @@ std::atomic<bool> fRequestShutdown(false);
|
||||
void StartShutdown()
|
||||
{
|
||||
if(fDebug) {
|
||||
fprintf(stderr,"%s: fRequestShudown=true\n", __FUNCTION__);
|
||||
fprintf(stderr,"%s: fRequestShutdown=true\n", __FUNCTION__);
|
||||
}
|
||||
fRequestShutdown = true;
|
||||
}
|
||||
@@ -490,9 +495,11 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-zsweepexclude", _("Addresses to exclude from sweeping (default none)"));
|
||||
|
||||
strUsage += HelpMessageOpt("-autoshield", _("Automatically shield matured coinbase (mining rewards) into a seed-derived wallet z-address (default: true for wallets created or restored by this software, false when the HD seed provenance is unknown). No-op when not mining or wallet is locked."));
|
||||
strUsage += HelpMessageOpt("-autoshieldinterval", strprintf(_("Block interval between automatic coinbase-shielding rounds (default: %i, min 5)"), 25));
|
||||
strUsage += HelpMessageOpt("-autoshieldinterval", strprintf(_("Block interval between automatic coinbase-shielding rounds (default: %i, min %i)"), DEFAULT_AUTOSHIELD_INTERVAL, MIN_AUTOSHIELD_INTERVAL));
|
||||
strUsage += HelpMessageOpt("-autoshieldaddress=<zaddr>", _("Destination Sapling z-address for auto-shielded coinbase (default: reuse or create a wallet z-address). Must be spendable by this wallet."));
|
||||
strUsage += HelpMessageOpt("-autoshieldfee", strprintf(_("Fee in puposhis for automatic coinbase-shielding transactions (default: %i)"), 10000));
|
||||
strUsage += HelpMessageOpt("-autoshieldfee", strprintf(_("Fee in puposhis for automatic coinbase-shielding transactions (default: %i)"), DEFAULT_AUTOSHIELD_FEE));
|
||||
|
||||
strUsage += HelpMessageOpt("-sietch-min-zouts=<n>", strprintf(_("Minimum number of shielded (Sapling) outputs Sietch adds to each z_sendmany transaction as decoys, strengthening amount/linkability privacy. Higher values add privacy at the cost of larger transactions (default: %u, clamped to the range 3-50)"), 7));
|
||||
strUsage += HelpMessageOpt("-autoshieldminutxos", strprintf(_("Only auto-shield once at least this many matured coinbase UTXOs exist (default: %i)"), 1));
|
||||
|
||||
strUsage += HelpMessageOpt("-deletetx", _("Enable Old Transaction Deletion"));
|
||||
@@ -614,12 +621,13 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
|
||||
strUsage += HelpMessageGroup(_("Stratum server options:"));
|
||||
strUsage += HelpMessageOpt("-stratum", _("Enable stratum server (default: off)"));
|
||||
strUsage += HelpMessageOpt("-stratumtarget=<hex>", _("Pool share target (64-hex, big-endian; larger = easier). Default is the diff-1 target. Useful for solo/low-difficulty mining."));
|
||||
strUsage += HelpMessageOpt("-stratumaddress=<address>", _("Mining address to use when special address of 'x' is sent by miner (default: none)"));
|
||||
strUsage += HelpMessageOpt("-stratumbind=<ipaddr>", _("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)"));
|
||||
strUsage += HelpMessageOpt("-stratumport=<port>", strprintf(_("Listen for Stratum work requests on <port> (default: %u or testnet: %u)"), BaseParams().StratumPort(), BaseParams().StratumPort()));
|
||||
strUsage += HelpMessageOpt("-stratumallowip=<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"));
|
||||
|
||||
// "ac" stands for "affects consensus" or Arrakis Chain
|
||||
// "ac" prefix is inherited from the Komodo asset-chain lineage ("asset chain"/"affects consensus")
|
||||
strUsage += HelpMessageGroup(_("DragonX Chain options:"));
|
||||
strUsage += HelpMessageOpt("-ac_algo", _("Choose PoW mining algorithm, either 'equihash' or 'randomx'. default is Equihash (200,9)"));
|
||||
strUsage += HelpMessageOpt("-ac_blocktime", _("Block time in seconds, default is 60"));
|
||||
@@ -786,7 +794,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
|
||||
}
|
||||
|
||||
/** Sanity checks
|
||||
* Ensure that Hush is running in a usable environment with all
|
||||
* Ensure that DragonX is running in a usable environment with all
|
||||
* necessary library support.
|
||||
*/
|
||||
bool InitSanityCheck(void)
|
||||
@@ -907,7 +915,7 @@ static void ZC_LoadParams(const CChainParams& chainparams)
|
||||
|
||||
if (!found) {
|
||||
// The traditional place Zcash params are stored, should not hit this case in normal circumstances,
|
||||
// as Hush packages sapling params now
|
||||
// as DragonX packages sapling params now
|
||||
sapling_spend = ZC_GetParamsDir() / "sapling-spend.params";
|
||||
sapling_output = ZC_GetParamsDir() / "sapling-output.params";
|
||||
if (files_exist(sapling_spend, sapling_output)) {
|
||||
@@ -926,7 +934,7 @@ static void ZC_LoadParams(const CChainParams& chainparams)
|
||||
boost::system::error_code ec1, ec2;
|
||||
boost::uintmax_t spend_size = file_size(sapling_spend, ec1);
|
||||
boost::uintmax_t output_size = file_size(sapling_output, ec2);
|
||||
fprintf(stderr,"Sapling spend: %d bytes, output: %d bytes\n", (int)spend_size, (int)output_size);
|
||||
LogPrintf("Sapling spend: %d bytes, output: %d bytes\n", (int)spend_size, (int)output_size);
|
||||
|
||||
// We could check sha hashes, but we mostly want to detect on-disk file corruption
|
||||
// or people having a full harddrive. Full validation happens in librustzcash_init_zksnark_params
|
||||
@@ -979,11 +987,15 @@ static void ZC_LoadParams(const CChainParams& chainparams)
|
||||
|
||||
bool AppInitServers(boost::thread_group& threadGroup)
|
||||
{
|
||||
fprintf(stderr,"%s: start\n",__func__);
|
||||
LogPrintf("%s: start\n",__func__);
|
||||
RPCServer::OnStopped(&OnRPCStopped);
|
||||
RPCServer::OnPreCommand(&OnRPCPreCommand);
|
||||
if (!InitHTTPServer())
|
||||
return false;
|
||||
// Stratum server (stratum.cpp) supports DragonX's RandomX PoW (32-byte solution + per-height
|
||||
// RandomX key conveyed to the miner) as well as legacy Equihash, branched on ASSETCHAINS_ALGO.
|
||||
// Off by default (DEFAULT_STRATUM_ENABLE=false); only -stratum turns it on. Needs a RandomX-aware
|
||||
// stratum miner (see contrib/ reference miner) — stock Equihash/Monero miners won't work.
|
||||
if (GetBoolArg("-stratum", DEFAULT_STRATUM_ENABLE) && !InitStratumServer())
|
||||
return false;
|
||||
if (!StartRPC())
|
||||
@@ -997,7 +1009,7 @@ bool AppInitServers(boost::thread_group& threadGroup)
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Initialize Hush.
|
||||
/** Initialize DragonX.
|
||||
* @pre Parameters should be parsed and config file should be read.
|
||||
*/
|
||||
extern int32_t HUSH_REWIND;
|
||||
@@ -1121,7 +1133,6 @@ static void AdjustCoinCacheForMemoryPressure()
|
||||
|
||||
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
{
|
||||
//fprintf(stderr,"%s start\n", __FUNCTION__);
|
||||
// ********************************************************* Step 1: setup
|
||||
#ifdef _MSC_VER
|
||||
// Turn off Microsoft heap dump noise
|
||||
@@ -1158,7 +1169,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
return InitError("Error: -sysperms is not allowed in combination with enabled wallet functionality");
|
||||
#endif
|
||||
} else {
|
||||
//fprintf(stderr,"%s setting umask\n", __FUNCTION__);
|
||||
umask(077);
|
||||
}
|
||||
|
||||
@@ -1176,12 +1186,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
std::set_new_handler(new_handler_terminate);
|
||||
|
||||
//fprintf(stderr,"%s: set signal handlers\n", __FUNCTION__);
|
||||
|
||||
// ********************************************************* Step 2: parameter interactions
|
||||
const CChainParams& chainparams = Params();
|
||||
|
||||
//fprintf(stderr,"%s: got chain params\n", __FUNCTION__);
|
||||
|
||||
// Set this early so that experimental features are correctly enabled/disabled
|
||||
fExperimentalMode = GetBoolArg("-experimentalfeatures", true);
|
||||
@@ -1192,11 +1200,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
// Fail early if user has set experimental options without the global flag
|
||||
if (!fExperimentalMode) {
|
||||
if (mapArgs.count("-developerencryptwallet")) {
|
||||
fprintf(stderr,"%s wallet encryption error\n", __FUNCTION__);
|
||||
LogPrintf("%s wallet encryption error\n", __FUNCTION__);
|
||||
return InitError(_("Wallet encryption requires -experimentalfeatures."));
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"%s tik2\n", __FUNCTION__);
|
||||
|
||||
// Set this early so that parameter interactions go to console
|
||||
fPrintToConsole = GetBoolArg("-printtoconsole", false);
|
||||
@@ -1205,7 +1212,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
|
||||
LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
LogPrintf("Hush version %s (%s)\n", FormatFullVersion());
|
||||
LogPrintf("DragonX version %s (%s)\n", FormatFullVersion());
|
||||
|
||||
|
||||
#ifdef DEBUG_LOCKORDER
|
||||
@@ -1225,7 +1232,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
LogPrintf("%s: parameter interaction: -allowbind set -> setting -listen=1\n", __func__);
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s tik3\n", __FUNCTION__);
|
||||
if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) {
|
||||
// when only connecting to trusted nodes, do not seed via DNS, or listen by default
|
||||
if (SoftSetBoolArg("-dnsseed", false))
|
||||
@@ -1257,7 +1263,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__);
|
||||
}
|
||||
|
||||
// Read asmap file by default for HUSH3 and all Hush Arrakis Chains
|
||||
// Read asmap file by default on DragonX
|
||||
if (GetArg("-asmap",1)) {
|
||||
fs::path asmap_path = fs::path(GetArg("-asmap", ""));
|
||||
|
||||
@@ -1275,36 +1281,36 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (asmap_path.empty()) {
|
||||
// Most binaries will have it in PWD
|
||||
asmap_path = pwd / DEFAULT_ASMAP_FILENAME;
|
||||
printf("%s: looking for asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: looking for asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
if(fs::exists(asmap_path)) {
|
||||
printf("%s: found asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: found asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
} else {
|
||||
// Debian Packages
|
||||
asmap_path = fs::path("/usr/share/hush") / DEFAULT_ASMAP_FILENAME;
|
||||
printf("%s: looking for asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: looking for asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
if(fs::exists(asmap_path)) {
|
||||
printf("%s: found asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: found asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
} else {
|
||||
// Source code
|
||||
asmap_path = contrib / DEFAULT_ASMAP_FILENAME;
|
||||
printf("%s: looking for asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: looking for asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
if(fs::exists(asmap_path)) {
|
||||
printf("%s: found asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: found asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
} else {
|
||||
// Last Resort: Check the parent directory
|
||||
asmap_path = pwd / ".." / DEFAULT_ASMAP_FILENAME;
|
||||
printf("%s: looking for asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: looking for asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
if(fs::exists(asmap_path)) {
|
||||
printf("%s: found asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: found asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
} else {
|
||||
// Mac SD
|
||||
asmap_path = fs::path("/Applications/SilentDragon.app/Contents/MacOS/") / DEFAULT_ASMAP_FILENAME;
|
||||
printf("%s: looking for asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: looking for asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
if(fs::exists(asmap_path)) {
|
||||
printf("%s: found asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: found asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
} else {
|
||||
// Shit is fucked up, die an honorable death
|
||||
InitError(strprintf(_("Could not find any asmap file! Please report this bug to Hush Developers")));
|
||||
// No asmap file found in any known location; abort startup.
|
||||
InitError(strprintf(_("Could not find any asmap file! Please report this bug to DragonX Developers")));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1315,7 +1321,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (!asmap_path.is_absolute()) {
|
||||
asmap_path = GetDataDir() / asmap_path;
|
||||
}
|
||||
printf("%s: looking for custom asmap file at %s\n", __func__, asmap_path.c_str() );
|
||||
LogPrint("net", "%s: looking for custom asmap file at %s\n", __func__, asmap_path.string().c_str() );
|
||||
}
|
||||
|
||||
//TODO: verify asmap_path is not a directory
|
||||
@@ -1329,7 +1335,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
return false;
|
||||
}
|
||||
const uint256 asmap_version = SerializeHash(asmap);
|
||||
printf("%s: asmap version=%s with %lu mappings\n", __func__, asmap_version.ToString().c_str(), asmap.size());
|
||||
LogPrint("net", "%s: asmap version=%s with %lu mappings\n", __func__, asmap_version.ToString().c_str(), asmap.size());
|
||||
LogPrintf("Using asmap version %s for IP bucketing with %lu mappings\n", asmap_version.ToString(), asmap.size());
|
||||
addrman.m_asmap = std::move(asmap); // //node.connman->SetAsmap(std::move(asmap));
|
||||
|
||||
@@ -1348,20 +1354,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (SoftSetBoolArg("-rescan", true))
|
||||
LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
|
||||
}
|
||||
//fprintf(stderr,"%s tik4\n", __FUNCTION__);
|
||||
|
||||
// Make sure enough file descriptors are available
|
||||
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-allowbind"), 1);
|
||||
nMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
|
||||
//fprintf(stderr,"nMaxConnections %d\n",nMaxConnections);
|
||||
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
|
||||
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
|
||||
fprintf(stderr,"nMaxConnections %d FD_SETSIZE.%d nBind.%d expr.%d \n",nMaxConnections,FD_SETSIZE,nBind,(int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS));
|
||||
LogPrintf("nMaxConnections %d FD_SETSIZE.%d nBind.%d expr.%d \n",nMaxConnections,FD_SETSIZE,nBind,(int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS));
|
||||
if (nFD < MIN_CORE_FILEDESCRIPTORS)
|
||||
return InitError(_("Not enough file descriptors available."));
|
||||
if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections)
|
||||
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
|
||||
//fprintf(stderr,"nMaxConnections %d\n",nMaxConnections);
|
||||
// if using block pruning, then disable txindex
|
||||
// also disable the wallet (for now, until SPV support is implemented in wallet)
|
||||
if (GetArg("-prune", 0)) {
|
||||
@@ -1407,10 +1410,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
}
|
||||
if (find(categories.begin(), categories.end(), string("randomx")) != categories.end()) {
|
||||
fRandomXDebug = true;
|
||||
fprintf(stderr,"%s: enabled randomx debug\n", __func__);
|
||||
LogPrintf("%s: enabled randomx debug\n", __func__);
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s tik5\n", __FUNCTION__);
|
||||
// Check for -debugnet
|
||||
if (GetBoolArg("-debugnet", false))
|
||||
InitWarning(_("Warning: Unsupported argument -debugnet ignored, use -debug=net."));
|
||||
@@ -1469,7 +1471,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
LogPrintf("Bulk block streaming: %s\n", fBulkBlockSync ? "enabled" : "disabled");
|
||||
|
||||
fServer = GetBoolArg("-server", false);
|
||||
//fprintf(stderr,"%s tik6\n", __FUNCTION__);
|
||||
|
||||
// block pruning; get the amount of disk space (in MB) to allot for block & undo files
|
||||
int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024;
|
||||
@@ -1557,7 +1558,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
expiryDelta = GetArg("-txexpirydelta", DEFAULT_TX_EXPIRY_DELTA);
|
||||
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true);
|
||||
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false);
|
||||
//fprintf(stderr,"%s tik7\n", __FUNCTION__);
|
||||
|
||||
std::string strWalletFile = GetArg("-wallet", "wallet.dat");
|
||||
#endif // ENABLE_WALLET
|
||||
@@ -1574,7 +1574,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
nLocalServices |= NODE_BLOOM;
|
||||
}
|
||||
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
|
||||
//fprintf(stderr,"%s tik8\n", __FUNCTION__);
|
||||
|
||||
#ifdef ENABLE_MINING
|
||||
if (mapArgs.count("-mineraddress")) {
|
||||
@@ -1597,7 +1596,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
}
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s tik9\n", __FUNCTION__);
|
||||
if (!mapMultiArgs["-nuparams"].empty()) {
|
||||
// Allow overriding network upgrade parameters for testing
|
||||
if (Params().NetworkIDString() != "regtest") {
|
||||
@@ -1646,10 +1644,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
std::string sha256_algo = SHA256AutoDetect();
|
||||
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
|
||||
|
||||
//fprintf(stderr,"%s tik10\n", __FUNCTION__);
|
||||
// Sanity check
|
||||
if (!InitSanityCheck())
|
||||
return InitError(_("Initialization sanity check failed. Please check for insanity. Hush is shutting down!"));
|
||||
return InitError(_("Initialization sanity check failed. Please check for insanity. DragonX is shutting down!"));
|
||||
|
||||
std::string strDataDir = GetDataDir().string();
|
||||
#ifdef ENABLE_WALLET
|
||||
@@ -1657,14 +1654,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile))
|
||||
return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir));
|
||||
#endif
|
||||
// Make sure only a single Hush process is using the data directory.
|
||||
// Make sure only a single DragonX process is using the data directory.
|
||||
boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
|
||||
FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
|
||||
if (file) fclose(file);
|
||||
|
||||
|
||||
//fprintf(stderr,"%s tik11\n", __FUNCTION__);
|
||||
fprintf(stderr,"Attempting to obtain lock %s\n", pathLockFile.string().c_str());
|
||||
LogPrintf("Attempting to obtain lock %s\n", pathLockFile.string().c_str());
|
||||
try {
|
||||
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
|
||||
if (!lock.try_lock())
|
||||
@@ -1679,10 +1675,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (GetBoolArg("-shrinkdebugfile", !fDebug))
|
||||
ShrinkDebugFile();
|
||||
|
||||
//fprintf(stderr,"%s tik12\n", __FUNCTION__);
|
||||
|
||||
LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
LogPrintf("Hush version %s\n", FormatFullVersion());
|
||||
LogPrintf("DragonX version %s\n", FormatFullVersion());
|
||||
|
||||
if (fPrintToDebugLog)
|
||||
OpenDebugLog();
|
||||
@@ -1712,7 +1707,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
threadGroup.create_thread(&ThreadRandomXVerify);
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s tik13\n", __FUNCTION__);
|
||||
|
||||
// Start the lightweight task scheduler thread
|
||||
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
|
||||
@@ -1720,7 +1714,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
// Count uptime
|
||||
MarkStartTime();
|
||||
//fprintf(stderr,"%s tik14\n", __FUNCTION__);
|
||||
|
||||
if ((chainparams.NetworkIDString() != "regtest") &&
|
||||
GetBoolArg("-showmetrics", 0) &&
|
||||
@@ -1730,7 +1723,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
threadGroup.create_thread(&ThreadShowMetricsScreen);
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s tik15\n", __FUNCTION__);
|
||||
|
||||
if ( HUSH_NSPV_FULLNODE )
|
||||
{
|
||||
@@ -1748,7 +1740,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (!AppInitServers(threadGroup))
|
||||
return InitError(_("Unable to start HTTP server. See debug log for details."));
|
||||
}
|
||||
//fprintf(stderr,"%s tik16\n", __FUNCTION__);
|
||||
|
||||
int64_t nStart;
|
||||
|
||||
@@ -1775,7 +1766,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
#endif // ENABLE_WALLET
|
||||
// ********************************************************* Step 6: network initialization
|
||||
|
||||
//fprintf(stderr,"%s tik17\n", __FUNCTION__);
|
||||
RegisterNodeSignals(GetNodeSignals());
|
||||
|
||||
// sanitize comments per BIP-0014, format user agent and check total size
|
||||
@@ -1791,7 +1781,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.",
|
||||
strSubVersion.size(), MAX_SUBVERSION_LENGTH));
|
||||
}
|
||||
//fprintf(stderr,"%s tik18\n", __FUNCTION__);
|
||||
|
||||
// Disable clearnet peers if -clearnet=0 for this node or -ac_clearnet=0 for this chain
|
||||
if (ASSETCHAINS_CLEARNET == 0 || !GetBoolArg("-clearnet", DEFAULT_CLEARNET)) {
|
||||
@@ -1850,7 +1839,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
SetReachable(NET_IPV4, false);
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s tik19\n", __FUNCTION__);
|
||||
if (mapArgs.count("-allowlist")) {
|
||||
BOOST_FOREACH(const std::string& net, mapMultiArgs["-allowlist"]) {
|
||||
CSubNet subnet;
|
||||
@@ -1913,7 +1901,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
fDiscover = GetBoolArg("-discover", true);
|
||||
fNameLookup = GetBoolArg("-dns", true);
|
||||
|
||||
//fprintf(stderr,"%s tik22\n", __FUNCTION__);
|
||||
bool fBound = false;
|
||||
if (fListen) {
|
||||
if (mapArgs.count("-bind") || mapArgs.count("-allowbind")) {
|
||||
@@ -1952,7 +1939,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
}
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s tik23\n", __FUNCTION__);
|
||||
|
||||
BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"])
|
||||
AddOneShot(strDest);
|
||||
@@ -1988,7 +1974,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
return !fRequestShutdown;
|
||||
}
|
||||
// ********************************************************* Step 7: load block chain
|
||||
//fprintf(stderr,"%s tik24\n", __FUNCTION__);
|
||||
|
||||
fReindex = GetBoolArg("-reindex", false);
|
||||
|
||||
@@ -2053,7 +2038,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if ( checkval != fAddressIndex && fAddressIndex != 0 )
|
||||
{
|
||||
pblocktree->WriteFlag("addressindex", fAddressIndex);
|
||||
fprintf(stderr,"set addressindex, will reindex. could take a while.\n");
|
||||
LogPrintf("set addressindex, will reindex. could take a while.\n");
|
||||
fReindex = true;
|
||||
}
|
||||
fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX);
|
||||
@@ -2061,7 +2046,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if ( checkval != fSpentIndex && fSpentIndex != 0 )
|
||||
{
|
||||
pblocktree->WriteFlag("spentindex", fSpentIndex);
|
||||
fprintf(stderr,"set spentindex, will reindex. could take a while.\n");
|
||||
LogPrintf("set spentindex, will reindex. could take a while.\n");
|
||||
fReindex = true;
|
||||
}
|
||||
}
|
||||
@@ -2090,7 +2075,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
|
||||
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
|
||||
try {
|
||||
pnotarizations = new NotarizationDB(100*1024*1024, false, fReindex);
|
||||
pnotarizations = new NotarizationDB(NOTARIZATION_DB_CACHE_BYTES, false, fReindex);
|
||||
} catch (const std::exception& e) {
|
||||
// The notarizations (dPoW) DB is non-essential and node-regenerable. It has been seen to
|
||||
// snapshot/flush torn (0-byte log -> leveldb "Database I/O error" on reopen), which
|
||||
@@ -2106,7 +2091,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
boost::filesystem::remove_all(ndir.string() + ".corrupt");
|
||||
boost::filesystem::rename(ndir, ndir.string() + ".corrupt");
|
||||
}
|
||||
pnotarizations = new NotarizationDB(100*1024*1024, false, true);
|
||||
pnotarizations = new NotarizationDB(NOTARIZATION_DB_CACHE_BYTES, false, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -2114,14 +2099,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
boost::filesystem::remove(GetDataDir() / "hushstate");
|
||||
boost::filesystem::remove(GetDataDir() / "hushsignedmasks");
|
||||
pblocktree->WriteReindexing(true);
|
||||
fprintf(stderr, "%s: Deleted hushstate and hushsignedmasks...\n", __FUNCTION__);
|
||||
LogPrintf("%s: Deleted hushstate and hushsignedmasks...\n", __FUNCTION__);
|
||||
|
||||
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
|
||||
if (fPruneMode)
|
||||
CleanupBlockRevFiles();
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: Loading block index...\n", __FUNCTION__);
|
||||
LogPrintf("%s: Loading block index...\n", __FUNCTION__);
|
||||
if (!LoadBlockIndex()) {
|
||||
strLoadError = _("Error loading block database");
|
||||
break;
|
||||
@@ -2145,7 +2130,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "zindex=%s in block index\n", fZindex ? "enabled" : "disabled");
|
||||
LogPrintf("zindex=%s in block index\n", fZindex ? "enabled" : "disabled");
|
||||
if (fZindex != GetBoolArg("-zindex", false)) {
|
||||
strLoadError = _("You need to rebuild the database using -reindex to change -zindex");
|
||||
break;
|
||||
@@ -2200,7 +2185,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (!fLoaded) {
|
||||
// first suggest a reindex
|
||||
if (!fReset) {
|
||||
fprintf(stderr,"%s: error in hd data\n", __FUNCTION__);
|
||||
LogPrintf("%s: error in hd data\n", __FUNCTION__);
|
||||
bool fRet = uiInterface.ThreadSafeMessageBox(
|
||||
strLoadError + ".\n\n" + _("error in HDD data, might just need to update to latest, if that doesnt work, then you need to resync"),
|
||||
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
|
||||
@@ -2235,7 +2220,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
mempool.ReadFeeEstimates(est_filein);
|
||||
fFeeEstimatesInitialized = true;
|
||||
|
||||
//fprintf(stderr,"%s tik25\n", __FUNCTION__);
|
||||
|
||||
// ********************************************************* Step 8: load wallet
|
||||
#ifdef ENABLE_WALLET
|
||||
@@ -2270,7 +2254,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (nLoadWalletRet != DB_LOAD_OK)
|
||||
{
|
||||
if (nLoadWalletRet == DB_CORRUPT)
|
||||
strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
|
||||
strErrors << _("Error loading wallet.dat: Wallet corrupted. If this wallet was last opened "
|
||||
"by an older version, move wallet.dat aside and restore from your seed "
|
||||
"phrase with -mnemonic=\"<your seed phrase>\" -rescan (see debug.log for "
|
||||
"the specific record at fault).") << "\n";
|
||||
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
|
||||
{
|
||||
string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data"
|
||||
@@ -2278,10 +2265,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
InitWarning(msg);
|
||||
}
|
||||
else if (nLoadWalletRet == DB_TOO_NEW)
|
||||
strErrors << _("Error loading wallet.dat: Wallet requires newer version of Hush") << "\n";
|
||||
strErrors << _("Error loading wallet.dat: Wallet requires newer version of DragonX") << "\n";
|
||||
else if (nLoadWalletRet == DB_NEED_REWRITE)
|
||||
{
|
||||
strErrors << _("Wallet needed to be rewritten: restart Hush to complete") << "\n";
|
||||
strErrors << _("Wallet needed to be rewritten: restart DragonX to complete") << "\n";
|
||||
LogPrintf("%s", strErrors.str());
|
||||
return InitError(strErrors.str());
|
||||
}
|
||||
@@ -2404,7 +2391,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
int consolidationInterval = GetArg("-consolidationinterval", 25);
|
||||
if (consolidationInterval < 5) {
|
||||
fprintf(stderr,"%s: Invalid consolidation interval of %d < 5, setting to default of 25\n", __func__, consolidationInterval);
|
||||
LogPrintf("%s: Invalid consolidation interval of %d < 5, setting to default of 25\n", __func__, consolidationInterval);
|
||||
consolidationInterval = 25;
|
||||
}
|
||||
|
||||
@@ -2429,7 +2416,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if (pwalletMain->fSweepEnabled) {
|
||||
int sweepInterval = GetArg("-zsweepinterval", 10);
|
||||
if (sweepInterval < 5) {
|
||||
fprintf(stderr,"%s: Invalid sweep interval of %d, setting to default of 10\n", __func__, sweepInterval);
|
||||
LogPrintf("%s: Invalid sweep interval of %d, setting to default of 10\n", __func__, sweepInterval);
|
||||
sweepInterval = 10;
|
||||
}
|
||||
pwalletMain->sweepInterval = sweepInterval;
|
||||
@@ -2446,7 +2433,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
}
|
||||
|
||||
for (int i = 0; i < vSweep.size(); i++) {
|
||||
// LogPrintf("Sweep Address: %s\n", vSweep[i]);
|
||||
auto zSweep = DecodePaymentAddress(vSweep[i]);
|
||||
if (!IsValidPaymentAddress(zSweep)) {
|
||||
return InitError("Invalid zsweep address");
|
||||
@@ -2515,10 +2501,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
"pass -autoshield=1 to enable.\n", __func__, pwalletMain->hdSeedOrigin);
|
||||
}
|
||||
if (pwalletMain->fAutoShieldEnabled) {
|
||||
int autoShieldInterval = GetArg("-autoshieldinterval", 25);
|
||||
if (autoShieldInterval < 5) {
|
||||
fprintf(stderr,"%s: Invalid autoshield interval of %d < 5, setting to default of 25\n", __func__, autoShieldInterval);
|
||||
autoShieldInterval = 25;
|
||||
int autoShieldInterval = GetArg("-autoshieldinterval", DEFAULT_AUTOSHIELD_INTERVAL);
|
||||
if (autoShieldInterval < MIN_AUTOSHIELD_INTERVAL) {
|
||||
InitWarning(strprintf(_("autoshield interval %d below the minimum, clamping to %d"),
|
||||
autoShieldInterval, MIN_AUTOSHIELD_INTERVAL));
|
||||
autoShieldInterval = MIN_AUTOSHIELD_INTERVAL;
|
||||
}
|
||||
pwalletMain->autoShieldInterval = autoShieldInterval;
|
||||
pwalletMain->nextAutoShield = pwalletMain->autoShieldInterval + chainActive.Height();
|
||||
@@ -2527,16 +2514,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
// guard against a fat-finger (e.g. -autoshieldfee=5000000000) that
|
||||
// would otherwise build an over-fee or malformed shield tx that
|
||||
// fails mempool admission every round.
|
||||
CAmount autoShieldFee = GetArg("-autoshieldfee", 10000);
|
||||
const CAmount AUTOSHIELD_MIN_FEE = 1000; // comfortably above minRelayTxFee for a small tx
|
||||
const CAmount AUTOSHIELD_MAX_FEE = 10000000; // 0.1 DRGX; no sane autoshield fee exceeds this
|
||||
CAmount autoShieldFee = GetArg("-autoshieldfee", DEFAULT_AUTOSHIELD_FEE);
|
||||
if (autoShieldFee < AUTOSHIELD_MIN_FEE || autoShieldFee > AUTOSHIELD_MAX_FEE) {
|
||||
fprintf(stderr,"%s: -autoshieldfee=%lld out of range [%lld,%lld], using default 10000\n",
|
||||
__func__, (long long)autoShieldFee, (long long)AUTOSHIELD_MIN_FEE, (long long)AUTOSHIELD_MAX_FEE);
|
||||
autoShieldFee = 10000;
|
||||
InitWarning(strprintf(_("-autoshieldfee=%lld out of range [%lld,%lld], using default %lld"),
|
||||
(long long)autoShieldFee, (long long)AUTOSHIELD_MIN_FEE, (long long)AUTOSHIELD_MAX_FEE, (long long)DEFAULT_AUTOSHIELD_FEE));
|
||||
autoShieldFee = DEFAULT_AUTOSHIELD_FEE;
|
||||
}
|
||||
pwalletMain->autoShieldFee = autoShieldFee;
|
||||
pwalletMain->autoShieldMinUtxos = GetArg("-autoshieldminutxos", 1);
|
||||
pwalletMain->autoShieldMinUtxos = GetArg("-autoshieldminutxos", DEFAULT_AUTOSHIELD_MIN_UTXOS);
|
||||
if (pwalletMain->autoShieldMinUtxos < 1) {
|
||||
pwalletMain->autoShieldMinUtxos = 1;
|
||||
}
|
||||
@@ -2556,6 +2541,25 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
return InitError("Wallet must hold the spending key of -autoshieldaddress (else shielded coinbase would be unrecoverable)");
|
||||
}
|
||||
pwalletMain->autoShieldAddress = autoShieldAddress;
|
||||
} else {
|
||||
// No explicit destination. Resolve the seed-derived one now, read-only,
|
||||
// so z_autoshieldstatus can say where coinbase will go BEFORE the first
|
||||
// round rather than reporting an empty string until one fires. This
|
||||
// never generates a key: a fresh account must not be a side effect of
|
||||
// populating a status field. A brand-new wallet holds nothing in-gap
|
||||
// yet, so the field stays empty and the RPC explains why.
|
||||
LOCK(pwalletMain->cs_wallet);
|
||||
if (!pwalletMain->IsLocked()) {
|
||||
libzcash::SaplingPaymentAddress destAddr;
|
||||
std::string destStr;
|
||||
uint32_t destAccount = AUTOSHIELD_ACCOUNT_NONE;
|
||||
if (ResolveAutoShieldDestinationReadOnly(destAddr, destStr, destAccount)
|
||||
== AutoShieldDestStatus::Resolved) {
|
||||
pwalletMain->autoShieldAddress = destStr;
|
||||
LogPrintf("%s: autoshield destination %s (seed-derived sapling account %u)\n",
|
||||
__func__, destStr, (unsigned)destAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2669,10 +2673,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
#ifdef ENABLE_MINING
|
||||
#ifndef ENABLE_WALLET
|
||||
if (GetBoolArg("-minetolocalwallet", false)) {
|
||||
return InitError(_("Hush was not built with wallet support. Set -minetolocalwallet=0 to use -mineraddress, or rebuild Hush with wallet support."));
|
||||
return InitError(_("DragonX was not built with wallet support. Set -minetolocalwallet=0 to use -mineraddress, or rebuild DragonX with wallet support."));
|
||||
}
|
||||
if (GetArg("-mineraddress", "").empty() && GetBoolArg("-gen", false)) {
|
||||
return InitError(_("Hush was not built with wallet support. Set -mineraddress, or rebuild Hush with wallet support."));
|
||||
return InitError(_("DragonX was not built with wallet support. Set -mineraddress, or rebuild DragonX with wallet support."));
|
||||
}
|
||||
#endif // !ENABLE_WALLET
|
||||
|
||||
@@ -2731,7 +2735,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
// 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));
|
||||
LogPrintf("nLocalServices %llx %d, %d\n",(long long)nLocalServices,GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX),GetBoolArg("-spentindex", DEFAULT_SPENTINDEX));
|
||||
}
|
||||
// ********************************************************* Step 10: import blocks
|
||||
|
||||
@@ -2747,7 +2751,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
if ( !ActivateBestChain(true,state))
|
||||
strErrors << "Failed to connect best block";
|
||||
} else {
|
||||
fprintf(stderr,"HUSH_REWIND < 0\n");
|
||||
LogPrintf("HUSH_REWIND < 0\n");
|
||||
}
|
||||
std::vector<boost::filesystem::path> vImportFiles;
|
||||
if (mapArgs.count("-loadblock"))
|
||||
@@ -2776,7 +2780,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
// ********************************************************* Step 11: start node
|
||||
|
||||
//fprintf(stderr,"Checking disk space...\n");
|
||||
if (!CheckDiskSpace())
|
||||
return false;
|
||||
|
||||
@@ -2814,7 +2817,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
SetRPCWarmupFinished();
|
||||
if(fDebug)
|
||||
fprintf(stderr,"RPC warmump finished\n");
|
||||
fprintf(stderr,"RPC warmup finished\n");
|
||||
uiInterface.InitMessage(_("Full Node Done Loading! :)"));
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
|
||||
BIN
src/libcc.dylib
BIN
src/libcc.dylib
Binary file not shown.
@@ -1259,11 +1259,10 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||
// Ensure that a coinbase transaction is structured according to the consensus rules of the chain
|
||||
bool ContextualCheckCoinbaseTransaction(int32_t slowflag,const CBlock *block,CBlockIndex * const previndex,const CTransaction& tx, const int nHeight,int32_t validateprices)
|
||||
{
|
||||
if ( slowflag != 0 && ASSETCHAINS_CBOPRET != 0 && validateprices != 0 && nHeight > 0 && tx.vout.size() > 0 )
|
||||
{
|
||||
if ( hush_opretvalidate(block,previndex,nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 )
|
||||
return(false);
|
||||
}
|
||||
// The only coinbase-specific contextual check here was CBOPRET price-oracle
|
||||
// validation (hush_opretvalidate), gated on ASSETCHAINS_CBOPRET, which is always
|
||||
// 0 on DragonX (no -ac_cbopret). With that dead path removed there is nothing left
|
||||
// to validate, so a DragonX coinbase is unconditionally valid at this stage.
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
203
src/miner.cpp
203
src/miner.cpp
@@ -160,7 +160,6 @@ bool hush_appendACscriptpub();
|
||||
|
||||
CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake)
|
||||
{
|
||||
//fprintf(stderr,"%s\n", __func__);
|
||||
CScript scriptPubKeyIn(_scriptPubKeyIn);
|
||||
|
||||
CPubKey pk;
|
||||
@@ -179,15 +178,13 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
uint32_t blocktime; const CChainParams& chainparams = Params();
|
||||
bool fNotarizationBlock = false; std::vector<int8_t> NotarizationNotaries;
|
||||
|
||||
//fprintf(stderr,"%s: create new block with pubkey=%s\n", __func__, HexStr(pk).c_str());
|
||||
// Create new block
|
||||
if ( gpucount < 0 )
|
||||
gpucount = HUSH_MAXGPUCOUNT;
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
|
||||
//fprintf(stderr,"%s: created new block template\n", __func__);
|
||||
if(!pblocktemplate.get())
|
||||
{
|
||||
fprintf(stderr,"%s: pblocktemplate.get() failure\n", __func__);
|
||||
LogPrintf("%s: pblocktemplate.get() failure\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
||||
@@ -200,7 +197,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
pblock->vtx.push_back(CTransaction());
|
||||
pblocktemplate->vTxFees.push_back(-1); // updated at end
|
||||
pblocktemplate->vTxSigOps.push_back(-1); // updated at end
|
||||
//fprintf(stderr,"%s: added dummy coinbase\n", __func__);
|
||||
|
||||
// Largest block you're willing to create:
|
||||
unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE(1)); // MAX_BLOCK_SIZE(chainActive.LastTip()->GetHeight()+1));
|
||||
@@ -217,7 +213,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
// until there are no more or the block reaches this size:
|
||||
const unsigned int nBlockMinSize = std::min(nBlockMaxSize, (unsigned int) GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE));
|
||||
// nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
|
||||
//fprintf(stderr,"%s: nBlockMaxSize=%u, nBlockPrioritySize=%u, nBlockMinSize=%u\n", __func__, nBlockMaxSize, nBlockPrioritySize, nBlockMinSize);
|
||||
|
||||
|
||||
// Collect memory pool transactions into the block
|
||||
@@ -243,17 +238,18 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
|
||||
uint32_t proposedTime = GetTime();
|
||||
|
||||
//fprintf(stderr,"%s: nHeight=%d, consensusBranchId=%u, proposedTime=%u\n", __func__, nHeight, consensusBranchId, proposedTime);
|
||||
|
||||
if (proposedTime == nMedianTimePast)
|
||||
{
|
||||
// too fast or stuck, this addresses the too fast issue, while moving
|
||||
// forward as quickly as possible
|
||||
for (int i; i < 100; i++)
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
proposedTime = GetTime();
|
||||
if (proposedTime == nMedianTimePast)
|
||||
MilliSleep(10);
|
||||
else
|
||||
break; // time advanced past the median; stop waiting
|
||||
}
|
||||
}
|
||||
pblock->nTime = GetTime();
|
||||
@@ -280,7 +276,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
vector<TxPriority> vecPriority;
|
||||
vecPriority.reserve(mempool.mapTx.size() + 1);
|
||||
|
||||
//fprintf(stderr,"%s: going to add txs from mempool\n", __func__);
|
||||
// now add transactions from the mempool
|
||||
int32_t Notarizations = 0; uint64_t txvalue;
|
||||
uint32_t large_zins = 0; // number of ztxs with large number of inputs in block
|
||||
@@ -299,7 +294,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
|
||||
if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight))
|
||||
{
|
||||
fprintf(stderr,"%s: coinbase.%d finaltx.%d expired.%d\n",__func__, tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight));
|
||||
LogPrint("mempool", "%s: coinbase.%d finaltx.%d expired.%d\n",__func__, tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight));
|
||||
continue;
|
||||
}
|
||||
txvalue = tx.GetValueOut();
|
||||
@@ -378,9 +373,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
{
|
||||
// check a notary didnt sign twice (this would be an invalid notarization later on and cause problems)
|
||||
std::set<int> checkdupes( TMP_NotarizationNotaries.begin(), TMP_NotarizationNotaries.end() );
|
||||
if ( checkdupes.size() != TMP_NotarizationNotaries.size() )
|
||||
if ( checkdupes.size() != TMP_NotarizationNotaries.size() )
|
||||
{
|
||||
fprintf(stderr, "%s: WTFBBQ! possible notarization is signed multiple times by same notary, passed as normal transaction.\n", __func__);
|
||||
} else fNotarization = true;
|
||||
}
|
||||
nTotalIn += tx.GetShieldedValueIn();
|
||||
@@ -390,7 +384,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
|
||||
// Priority is sum(valuein * age) / modified_txsize
|
||||
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
// fprintf(stderr,"%s: computing priority with nTxSize=%u\n", __func__, nTxSize);
|
||||
dPriority = tx.ComputePriority(dPriority, nTxSize);
|
||||
|
||||
uint256 hash = tx.GetHash();
|
||||
@@ -410,7 +403,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
Notarizations++;
|
||||
if ( Notarizations > 1 )
|
||||
{
|
||||
fprintf(stderr, "%s: skipping notarization.%d\n",__func__, Notarizations);
|
||||
LogPrint("mempool", "%s: skipping notarization.%d\n",__func__, Notarizations);
|
||||
// Any attempted notarization needs to be in its own block!
|
||||
continue;
|
||||
}
|
||||
@@ -421,7 +414,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
NotarizationNotaries = TMP_NotarizationNotaries;
|
||||
dPriority = 1e16;
|
||||
fNotarizationBlock = true;
|
||||
//fprintf(stderr, "Notarization %s set to maximum priority\n",hash.ToString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,7 +428,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
|
||||
}
|
||||
}
|
||||
// fprintf(stderr,"%s: done adding txs from mempool\n", __func__);
|
||||
|
||||
// Collect transactions into block
|
||||
int64_t interest;
|
||||
@@ -448,7 +439,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
TxPriorityCompare comparer(fSortedByFee);
|
||||
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
|
||||
// fprintf(stderr,"%s: compared txs with fSortedByFee=%d\n", __func__, fSortedByFee);
|
||||
|
||||
while (!vecPriority.empty()) {
|
||||
// Take highest priority transaction off the priority queue:
|
||||
@@ -456,10 +446,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
CFeeRate feeRate = vecPriority.front().get<1>();
|
||||
const CTransaction& tx = *(vecPriority.front().get<2>());
|
||||
|
||||
// fprintf(stderr,"%s: grabbed first tx from priority queue\n", __func__);
|
||||
|
||||
std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
// fprintf(stderr,"%s: compared first tx from priority queue\n", __func__);
|
||||
vecPriority.pop_back();
|
||||
|
||||
if(tx.vShieldedSpend.size() >= LARGE_ZINS_THRESHOLD && large_zins >= LARGE_ZINS_MAX) {
|
||||
@@ -476,12 +464,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
|
||||
// Size limits
|
||||
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
// fprintf(stderr,"%s: nTxSize = %u\n", __func__, nTxSize);
|
||||
|
||||
|
||||
if (nBlockSize + nTxSize >= nBlockMaxSize-512) // room for extra autotx
|
||||
{
|
||||
fprintf(stderr,"%s: nBlockSize %d + %d nTxSize >= %d nBlockMaxSize\n",__func__, (int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)nBlockMaxSize);
|
||||
LogPrint("mempool", "%s: nBlockSize %d + %d nTxSize >= %d nBlockMaxSize\n",__func__, (int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)nBlockMaxSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -489,11 +476,9 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
unsigned int nTxSigOps = GetLegacySigOpCount(tx);
|
||||
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
|
||||
{
|
||||
//fprintf(stderr,"A nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
|
||||
continue;
|
||||
}
|
||||
|
||||
// fprintf(stderr,"%s: looking to see if we need to skip any fee=0 txs\n", __func__);
|
||||
|
||||
// Skip free transactions if we're past the minimum block size:
|
||||
const uint256& hash = tx.GetHash();
|
||||
@@ -502,7 +487,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
|
||||
if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
|
||||
{
|
||||
fprintf(stderr,"%s: fee rate skip\n", __func__);
|
||||
LogPrint("mempool", "%s: fee rate skip\n", __func__);
|
||||
continue;
|
||||
}
|
||||
// Prioritize by fee once past the priority size or we run out of high-priority transactions
|
||||
@@ -516,7 +501,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
|
||||
if (!view.HaveInputs(tx))
|
||||
{
|
||||
//fprintf(stderr,"dont have inputs\n");
|
||||
continue;
|
||||
}
|
||||
CAmount nTxFees = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime)-tx.GetValueOut();
|
||||
@@ -541,7 +525,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
opcodetype op;
|
||||
std::vector<uint8_t> opretData;
|
||||
if (txout.scriptPubKey.GetOp(it, op, opretData)) {
|
||||
//std::cerr << HexStr(opretData.begin(), opretData.end()) << std::endl;
|
||||
nTxOpretSize += opretData.size();
|
||||
}
|
||||
}
|
||||
@@ -552,13 +535,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
std::cerr << __func__ << ": " << tx.GetHash().ToString() << " nTxSize=" << nTxSize << " nTxOpretSize=" << nTxOpretSize << " feeRate=" << feeRate.ToString() << " opretMinFee=" << opretMinFee << " nTxFees=" << nTxFees <<" fSpamTx=" << fSpamTx << std::endl;
|
||||
continue;
|
||||
}
|
||||
// std::cerr << tx.GetHash().ToString() << " vecPriority.size() = " << vecPriority.size() << std::endl;
|
||||
}
|
||||
|
||||
nTxSigOps += GetP2SHSigOpCount(tx, view);
|
||||
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
|
||||
{
|
||||
//fprintf(stderr,"B nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
|
||||
continue;
|
||||
}
|
||||
// Note that flags: we don't want to set mempool/IsStandard()
|
||||
@@ -568,7 +549,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||
{
|
||||
fprintf(stderr,"%s: ContextualCheckInputs failure\n",__func__);
|
||||
LogPrint("mempool", "%s: ContextualCheckInputs failure\n",__func__);
|
||||
continue;
|
||||
}
|
||||
UpdateCoins(tx, view, nHeight);
|
||||
@@ -623,13 +604,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
|
||||
nLastBlockTx = nBlockTx;
|
||||
nLastBlockSize = nBlockSize;
|
||||
// fprintf(stderr,"%s: nLastBlockTx=%lu , nLastBlockSize=%lu\n", __func__, nLastBlockTx, nLastBlockSize);
|
||||
|
||||
if ( ASSETCHAINS_ADAPTIVEPOW <= 0 )
|
||||
blocktime = 1 + std::max(pindexPrev->GetMedianTimePast()+1, GetTime());
|
||||
else blocktime = 1 + std::max((int64_t)(pindexPrev->nTime+1), GetTime());
|
||||
//pblock->nTime = blocktime + 1;
|
||||
// fprintf(stderr,"%s: calling GetNextWorkRequired\n", __func__);
|
||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||
|
||||
LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits);
|
||||
@@ -643,7 +622,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
txNew.vout.resize(1);
|
||||
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
|
||||
txNew.vout[0].nValue = GetBlockSubsidy(nHeight,consensusParams) + nFees;
|
||||
// fprintf(stderr,"%s: mine ht.%d with %.8f\n",__func__,nHeight,(double)txNew.vout[0].nValue/COIN);
|
||||
txNew.nExpiryHeight = 0;
|
||||
if ( ASSETCHAINS_ADAPTIVEPOW <= 0 )
|
||||
txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetTime());
|
||||
@@ -665,10 +643,9 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
static bool didinit = false;
|
||||
if ( !didinit && nHeight > HUSH_EARLYTXID_HEIGHT && HUSH_EARLYTXID != zeroid && hush_appendACscriptpub() )
|
||||
{
|
||||
fprintf(stderr, "appended ccopreturn to assetchains_scriptpub.%s\n", assetchains_scriptpub.c_str());
|
||||
LogPrintf("appended ccopreturn to assetchains_scriptpub.%s\n", assetchains_scriptpub.c_str());
|
||||
didinit = true;
|
||||
}
|
||||
//fprintf(stderr,"mine to -ac_script\n");
|
||||
//txNew.vout[1].scriptPubKey = CScript() << ParseHex();
|
||||
int32_t len = strlen(assetchains_scriptpub.c_str());
|
||||
len >>= 1;
|
||||
@@ -682,14 +659,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
for (i=0; i<33; i++)
|
||||
{
|
||||
ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i];
|
||||
//fprintf(stderr,"%02x",ptr[i+1]);
|
||||
}
|
||||
ptr[34] = OP_CHECKSIG;
|
||||
//fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n");
|
||||
}
|
||||
//printf("autocreate commision vout\n");
|
||||
} else if ( (uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE) {
|
||||
fprintf(stderr,"timelocked chains not supported in this code!\n");
|
||||
LogPrintf("timelocked chains not supported in this code!\n");
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
return(0);
|
||||
@@ -702,16 +676,15 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
uint64_t totalsats = hush_notarypay(txNew, NotarizationNotaries, pblock->nTime, nHeight, script, scriptlen);
|
||||
if ( totalsats == 0 )
|
||||
{
|
||||
fprintf(stderr, "Could not create notary payment, trying again.\n");
|
||||
if ( !isStake )
|
||||
{
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
}
|
||||
LogPrintf("Could not create notary payment, trying again.\n");
|
||||
// Release unconditionally to match the unconditional ENTER above. The old
|
||||
// `if(!isStake)` guard leaked cs_main/mempool.cs on the isStake path (this
|
||||
// still return(0)s), while the success and timelock paths always release.
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr, "Created notary payment coinbase totalsat.%lu\n",totalsats);
|
||||
} else fprintf(stderr, "vout 2 of notarization is not OP_RETURN scriptlen.%i\n", scriptlen);
|
||||
} else LogPrintf("vout 2 of notarization is not OP_RETURN scriptlen.%i\n", scriptlen);
|
||||
}
|
||||
if ( ASSETCHAINS_CBOPRET != 0 )
|
||||
{
|
||||
@@ -719,7 +692,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
txNew.vout.resize(numv+1);
|
||||
txNew.vout[numv].nValue = 0;
|
||||
txNew.vout[numv].scriptPubKey = hush_mineropret(nHeight);
|
||||
//printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size());
|
||||
}
|
||||
pblock->vtx[0] = txNew;
|
||||
pblocktemplate->vTxFees[0] = -nFees;
|
||||
@@ -752,26 +724,23 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
if ( ASSETCHAINS_CC == 0 && pindexPrev != 0 && (IS_HUSH_NOTARY == 0 || My_notaryid < 0) )
|
||||
{
|
||||
CValidationState state;
|
||||
//fprintf(stderr,"%s: check validity\n", __func__);
|
||||
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) // invokes CC checks
|
||||
{
|
||||
if ( !isStake )
|
||||
{
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
}
|
||||
fprintf(stderr,"%s: TestBlockValidity failed!\n", __func__);
|
||||
// Release unconditionally to match the unconditional ENTER above. The old
|
||||
// `if(!isStake)` guard leaked cs_main/mempool.cs on the isStake path (this
|
||||
// still return(0)s), while the success and timelock paths always release.
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
LogPrintf("%s: TestBlockValidity failed!\n", __func__);
|
||||
//throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed"); // crashes the node, moved to GetBlockTemplate and issue return.
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr,"valid\n");
|
||||
}
|
||||
}
|
||||
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
|
||||
// fprintf(stderr,"%s: done\n", __func__);
|
||||
return pblocktemplate.release();
|
||||
}
|
||||
|
||||
@@ -781,7 +750,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
|
||||
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
|
||||
{
|
||||
//fprintf(stderr,"RandomXMiner: %s with nExtraNonce=%u\n", __func__, nExtraNonce);
|
||||
// Update nExtraNonce
|
||||
static uint256 hashPrevBlock;
|
||||
if (hashPrevBlock != pblock->hashPrevBlock)
|
||||
@@ -805,7 +773,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
|
||||
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, int32_t gpucount, bool isStake)
|
||||
{
|
||||
CPubKey pubkey; CScript scriptPubKey; uint8_t *script,*ptr; int32_t i,len;
|
||||
// fprintf(stderr,"%s: with nHeight=%d\n", __func__, nHeight);
|
||||
|
||||
// Create a local variable instead of modifying the global assetchains_scriptpub
|
||||
auto assetchains_scriptpub = devtax_scriptpub_for_height(nHeight);
|
||||
@@ -815,7 +782,6 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
|
||||
{
|
||||
pubkey = ParseHex(ASSETCHAINS_OVERRIDE_PUBKEY);
|
||||
scriptPubKey = CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG;
|
||||
// fprintf(stderr,"%s: with pubkey=%s\n", __func__, HexStr(pubkey).c_str() );
|
||||
} else {
|
||||
len = strlen(assetchains_scriptpub.c_str());
|
||||
len >>= 1;
|
||||
@@ -824,7 +790,6 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
|
||||
decode_hex(ptr,len,(char *)assetchains_scriptpub.c_str());
|
||||
}
|
||||
} else if ( USE_EXTERNAL_PUBKEY != 0 ) {
|
||||
//fprintf(stderr,"use notary pubkey\n");
|
||||
pubkey = ParseHex(NOTARY_PUBKEY);
|
||||
scriptPubKey = CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG;
|
||||
} else {
|
||||
@@ -845,14 +810,13 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
|
||||
// scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
scriptPubKey = GetScriptForDestination(dest);
|
||||
Getscriptaddress(destaddr,scriptPubKey);
|
||||
fprintf(stderr,"%s: wallet disabled with mineraddress=%s\n", __func__, destaddr);
|
||||
LogPrintf("%s: wallet disabled with mineraddress=%s\n", __func__, destaddr);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// fprintf(stderr,"%s: calling CreateNewBlock\n", __func__);
|
||||
return CreateNewBlock(pubkey, scriptPubKey, gpucount, isStake);
|
||||
}
|
||||
|
||||
@@ -866,7 +830,6 @@ void hush_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std:
|
||||
continue;
|
||||
if ( numsent < minpeers || (rand() % 10) == 0 )
|
||||
{
|
||||
//fprintf(stderr,"pushmessage\n");
|
||||
pnode->PushMessage(message,payload);
|
||||
if ( numsent++ > maxpeers )
|
||||
break;
|
||||
@@ -887,16 +850,6 @@ static bool ProcessBlockFound(CBlock* pblock)
|
||||
LOCK(cs_main);
|
||||
if (pblock->hashPrevBlock != chainActive.LastTip()->GetBlockHash())
|
||||
{
|
||||
uint256 hash; int32_t i;
|
||||
hash = pblock->hashPrevBlock;
|
||||
for (i=31; i>=0; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
|
||||
fprintf(stderr," <- prev (stale)\n");
|
||||
hash = chainActive.LastTip()->GetBlockHash();
|
||||
for (i=31; i>=0; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
|
||||
fprintf(stderr," <- chainTip (stale)\n");
|
||||
|
||||
return error("HushMiner: generated block is stale");
|
||||
}
|
||||
}
|
||||
@@ -914,7 +867,6 @@ static bool ProcessBlockFound(CBlock* pblock)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//fprintf(stderr,"process new block\n");
|
||||
|
||||
// Process this block the same as if we had received it from another node
|
||||
CValidationState state;
|
||||
@@ -989,9 +941,7 @@ CBlockIndex *get_chainactive(int32_t height)
|
||||
LOCK(cs_main);
|
||||
return(chainActive[height]);
|
||||
}
|
||||
// else fprintf(stderr,"get_chainactive height %d > active.%d\n",height,chainActive.Tip()->GetHeight());
|
||||
}
|
||||
//fprintf(stderr,"get_chainactive null chainActive.Tip() height %d\n",height);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1040,7 +990,7 @@ static void LogProcessMemory(const char* label) {
|
||||
PMC_EX pmc = {};
|
||||
pmc.cb = sizeof(pmc);
|
||||
if (pfn(GetCurrentProcess(), &pmc, sizeof(pmc))) {
|
||||
LogPrintf("MemDiag [%s]: WorkingSet=%.1fMB, PrivateUsage=%.1fMB, PagefileUsage=%.1fMB\n",
|
||||
LogPrint("randomx", "MemDiag [%s]: WorkingSet=%.1fMB, PrivateUsage=%.1fMB, PagefileUsage=%.1fMB\n",
|
||||
label,
|
||||
pmc.WorkingSetSize / (1024.0 * 1024.0),
|
||||
pmc.PrivateUsage / (1024.0 * 1024.0),
|
||||
@@ -1058,7 +1008,7 @@ static void LogProcessMemory(const char* label) {
|
||||
if (strncmp(line, "VmRSS:", 6) == 0 || strncmp(line, "VmSize:", 7) == 0) {
|
||||
// Remove newline
|
||||
line[strlen(line)-1] = '\0';
|
||||
LogPrintf("MemDiag [%s]: %s\n", label, line);
|
||||
LogPrint("randomx", "MemDiag [%s]: %s\n", label, line);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
@@ -1087,7 +1037,7 @@ struct RandomXDatasetManager {
|
||||
if (initialized) return true;
|
||||
|
||||
flags |= RANDOMX_FLAG_FULL_MEM;
|
||||
LogPrintf("RandomXDatasetManager: flags=0x%x (JIT=%d, HARD_AES=%d, FULL_MEM=%d, LARGE_PAGES=%d)\n",
|
||||
LogPrint("randomx", "RandomXDatasetManager: flags=0x%x (JIT=%d, HARD_AES=%d, FULL_MEM=%d, LARGE_PAGES=%d)\n",
|
||||
(int)flags,
|
||||
!!(flags & RANDOMX_FLAG_JIT), !!(flags & RANDOMX_FLAG_HARD_AES),
|
||||
!!(flags & RANDOMX_FLAG_FULL_MEM), !!(flags & RANDOMX_FLAG_LARGE_PAGES));
|
||||
@@ -1128,11 +1078,11 @@ struct RandomXDatasetManager {
|
||||
// Log the actual memory addresses to help diagnose sharing issues
|
||||
uint8_t *datasetMemory = (uint8_t*)randomx_get_dataset_memory(dataset);
|
||||
size_t datasetSize = datasetItemCount * RANDOMX_DATASET_ITEM_SIZE;
|
||||
LogPrintf("RandomXDatasetManager: allocated shared dataset:\n");
|
||||
LogPrintf(" - Dataset struct at: %p\n", (void*)dataset);
|
||||
LogPrintf(" - Dataset memory at: %p (size: %.2f GB)\n", (void*)datasetMemory, datasetSize / (1024.0 * 1024.0 * 1024.0));
|
||||
LogPrintf(" - Items: %lu, Item size: %d bytes\n", datasetItemCount, RANDOMX_DATASET_ITEM_SIZE);
|
||||
LogPrintf(" - Expected total process memory: ~%.2f GB + ~2MB per mining thread\n", datasetSize / (1024.0 * 1024.0 * 1024.0));
|
||||
LogPrintf("RandomXDatasetManager: allocated shared dataset (%.2f GB, %lu items)\n",
|
||||
datasetSize / (1024.0 * 1024.0 * 1024.0), datasetItemCount);
|
||||
LogPrint("randomx", " - Dataset struct at: %p, memory at: %p\n", (void*)dataset, (void*)datasetMemory);
|
||||
LogPrint("randomx", " - Item size: %d bytes; expected ~%.2f GB + ~2MB per mining thread\n",
|
||||
RANDOMX_DATASET_ITEM_SIZE, datasetSize / (1024.0 * 1024.0 * 1024.0));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1190,9 +1140,9 @@ struct RandomXDatasetManager {
|
||||
if (vm != nullptr) {
|
||||
int id = ++vmCount;
|
||||
uint8_t *datasetMemory = (uint8_t*)randomx_get_dataset_memory(dataset);
|
||||
LogPrintf("RandomXDatasetManager: VM #%d created — VM at %p, shared dataset at %p\n",
|
||||
LogPrint("randomx", "RandomXDatasetManager: VM #%d created — VM at %p, shared dataset at %p\n",
|
||||
id, (void*)vm, (void*)datasetMemory);
|
||||
LogPrintf(" Per-thread overhead: ~2MB scratchpad + ~84KB JIT (dataset NOT copied)\n");
|
||||
LogPrint("randomx", " Per-thread overhead: ~2MB scratchpad + ~84KB JIT (dataset NOT copied)\n");
|
||||
LogProcessMemory("after CreateVM");
|
||||
}
|
||||
return vm;
|
||||
@@ -1279,13 +1229,11 @@ void static RandomXMiner()
|
||||
randomx_vm *myVM = nullptr;
|
||||
|
||||
try {
|
||||
// fprintf(stderr,"RandomXMiner: mining %s with randomx\n",SMART_CHAIN_SYMBOL);
|
||||
|
||||
rxdebug("%s: mining %s with randomx\n", SMART_CHAIN_SYMBOL);
|
||||
|
||||
while (true)
|
||||
{
|
||||
// fprintf(stderr,"RandomXMiner: beginning mining loop on %s with nExtraNonce=%u\n",SMART_CHAIN_SYMBOL, nExtraNonce);
|
||||
rxdebug("%s: start mining loop on %s with nExtraNonce=%u\n", SMART_CHAIN_SYMBOL, nExtraNonce);
|
||||
|
||||
if (chainparams.MiningRequiresPeers()) {
|
||||
@@ -1303,10 +1251,8 @@ void static RandomXMiner()
|
||||
if (!fvNodesEmpty )//&& !IsInitialBlockDownload())
|
||||
break;
|
||||
MilliSleep(15000);
|
||||
//fprintf(stderr,"fvNodesEmpty %d IsInitialBlockDownload(%s) %d\n",(int32_t)fvNodesEmpty,SMART_CHAIN_SYMBOL,(int32_t)IsInitialBlockDownload());
|
||||
|
||||
} while (true);
|
||||
//fprintf(stderr,"%s Found peers\n",SMART_CHAIN_SYMBOL);
|
||||
miningTimer.start();
|
||||
}
|
||||
|
||||
@@ -1320,7 +1266,7 @@ void static RandomXMiner()
|
||||
|
||||
// If we don't have a valid chain tip to work from, wait and try again.
|
||||
if (pindexPrev == nullptr) {
|
||||
fprintf(stderr,"%s: null pindexPrev, trying again...\n",__func__);
|
||||
LogPrint("randomx", "%s: null pindexPrev, trying again...\n",__func__);
|
||||
MilliSleep(1000);
|
||||
continue;
|
||||
}
|
||||
@@ -1331,7 +1277,6 @@ void static RandomXMiner()
|
||||
Mining_start = (uint32_t)time(NULL);
|
||||
}
|
||||
|
||||
// fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag);
|
||||
rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height);
|
||||
// Update the shared dataset key — only one thread will actually rebuild,
|
||||
// others will see the key is already current and skip.
|
||||
@@ -1364,14 +1309,12 @@ void static RandomXMiner()
|
||||
|
||||
// Acquire shared lock to prevent dataset rebuild while we're hashing
|
||||
boost::shared_lock<boost::shared_mutex> datasetLock(g_rxDatasetManager->datasetMtx);
|
||||
//fprintf(stderr,"RandomXMiner: Mining_start=%u\n", Mining_start);
|
||||
#ifdef ENABLE_WALLET
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, pindexPrev->GetHeight()+1, gpucount, 0);
|
||||
#else
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey();
|
||||
#endif
|
||||
|
||||
// fprintf(stderr,"RandomXMiner: created new block with Mining_start=%u\n",Mining_start);
|
||||
rxdebug("%s: created new block with Mining_start=%u\n",Mining_start);
|
||||
if ( ptr == 0 )
|
||||
{
|
||||
@@ -1384,11 +1327,10 @@ void static RandomXMiner()
|
||||
}
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 10 )
|
||||
fprintf(stderr,"RandomXMiner: created illegal blockB, retry with counter=%u\n", counter);
|
||||
LogPrint("randomx", "RandomXMiner: created illegal blockB, retry with counter=%u\n", counter);
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
// fprintf(stderr,"RandomXMiner: getting block template\n");
|
||||
rxdebug("%s: getting block template\n");
|
||||
|
||||
unique_ptr<CBlockTemplate> pblocktemplate(ptr);
|
||||
@@ -1410,14 +1352,13 @@ void static RandomXMiner()
|
||||
{
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 10 )
|
||||
fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",SMART_CHAIN_SYMBOL);
|
||||
LogPrint("randomx", "skip generating %s on-demand block, no tx avail\n",SMART_CHAIN_SYMBOL);
|
||||
sleep(10);
|
||||
continue;
|
||||
} else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",SMART_CHAIN_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
|
||||
} else LogPrint("randomx", "%s vouts.%d mining.%d vs %d\n",SMART_CHAIN_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
|
||||
}
|
||||
rxdebug("%s: incrementing extra nonce\n");
|
||||
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
||||
// fprintf(stderr,"RandomXMiner: %u transactions in block\n",(int32_t)pblock->vtx.size());
|
||||
LogPrintf("Running HushRandomXMiner with %u transactions in block (%u bytes)\n",pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
|
||||
|
||||
// Search
|
||||
@@ -1433,12 +1374,11 @@ void static RandomXMiner()
|
||||
while (true)
|
||||
{
|
||||
if ( gotinvalid != 0 ) {
|
||||
fprintf(stderr,"RandomXMiner: gotinvalid=%d\n",gotinvalid);
|
||||
LogPrint("randomx", "RandomXMiner: gotinvalid=%d\n",gotinvalid);
|
||||
break;
|
||||
}
|
||||
hush_longestchain();
|
||||
|
||||
// fprintf(stderr,"RandomXMiner: solving with nNonce = %s\n",pblock->nNonce.ToString().c_str());
|
||||
rxdebug("%s: solving with nNonce = %s\n",pblock->nNonce.ToString().c_str());
|
||||
arith_uint256 hashTarget;
|
||||
hashTarget = HASHTarget;
|
||||
@@ -1448,8 +1388,6 @@ void static RandomXMiner()
|
||||
// Serialize block header without nSolution but with nNonce for deterministic RandomX input
|
||||
randomxInput << rxInput;
|
||||
|
||||
// std::cerr << "RandomXMiner: randomxInput=" << HexStr(randomxInput) << "\n";
|
||||
// fprintf(stderr,"RandomXMiner: created randomxKey=%s , randomxInput.size=%lu\n", randomxKey, randomxInput.size() ); //randomxInput);
|
||||
rxdebug("%s: randomxKey=%s randomxInput=%s\n", randomxKey, HexStr(randomxInput).c_str());
|
||||
|
||||
rxdebug("%s: calculating randomx hash\n");
|
||||
@@ -1478,7 +1416,6 @@ void static RandomXMiner()
|
||||
rxdebug("%s: Checking solution against target\n");
|
||||
pblock->nSolution = soln;
|
||||
solutionTargetChecks.increment();
|
||||
// fprintf(stderr,"%s: solutionTargetChecks=%lu\n", __func__, solutionTargetChecks.get());
|
||||
B = *pblock;
|
||||
h = UintToArith256(B.GetHash());
|
||||
|
||||
@@ -1508,17 +1445,6 @@ void static RandomXMiner()
|
||||
SetSkipRandomXValidation(false);
|
||||
if ( !fValid )
|
||||
{
|
||||
h = UintToArith256(B.GetHash());
|
||||
fprintf(stderr,"RandomXMiner: TestBlockValidity FAILED at ht.%d nNonce=%s hash=",
|
||||
Mining_height, pblock->nNonce.ToString().c_str());
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&h)[z]);
|
||||
fprintf(stderr," nSolution.size=%lu\n", B.nSolution.size());
|
||||
// Dump nSolution hex for comparison with validator
|
||||
fprintf(stderr,"RandomXMiner: nSolution=");
|
||||
for (unsigned i = 0; i < B.nSolution.size(); i++)
|
||||
fprintf(stderr,"%02x", B.nSolution[i]);
|
||||
fprintf(stderr,"\n");
|
||||
LogPrintf("RandomXMiner: TestBlockValidity FAILED at ht.%d, gotinvalid=1, state=%s\n",
|
||||
Mining_height, state.GetRejectReason());
|
||||
gotinvalid = 1;
|
||||
@@ -1575,13 +1501,13 @@ void static RandomXMiner()
|
||||
{
|
||||
if ( Mining_height > ASSETCHAINS_MINHEIGHT )
|
||||
{
|
||||
fprintf(stderr,"%s: no nodes, break\n", __func__);
|
||||
LogPrint("randomx", "%s: no nodes, break\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff)
|
||||
{
|
||||
fprintf(stderr,"%s: nonce & 0xffff == 0xffff, break\n", __func__);
|
||||
LogPrint("randomx", "%s: nonce & 0xffff == 0xffff, break\n", __func__);
|
||||
break;
|
||||
}
|
||||
// Update nNonce and nTime
|
||||
@@ -1604,7 +1530,6 @@ void static RandomXMiner()
|
||||
LogPrintf("%s: destroyed vm via thread interrupt\n", __func__);
|
||||
} else {
|
||||
LogPrintf("%s: WARNING myVM already null in thread interrupt handler, skipping destroy (would double-free)\n", __func__);
|
||||
fprintf(stderr, "%s: WARNING myVM already null in thread interrupt, would have double-freed!\n", __func__);
|
||||
}
|
||||
// Dataset and cache are owned by g_rxDatasetManager — do NOT release here
|
||||
|
||||
@@ -1613,7 +1538,7 @@ void static RandomXMiner()
|
||||
} catch (const std::runtime_error &e) {
|
||||
miningTimer.stop();
|
||||
c.disconnect();
|
||||
fprintf(stderr,"RandomXMiner: runtime error: %s\n", e.what());
|
||||
LogPrintf("RandomXMiner: runtime error: %s\n", e.what());
|
||||
|
||||
if (myVM != nullptr) {
|
||||
randomx_destroy_vm(myVM);
|
||||
@@ -1672,7 +1597,7 @@ void static BitcoinMiner()
|
||||
assert(solver == "tromp" || solver == "default");
|
||||
LogPrint("pow", "Using Equihash solver \"%s\" with n = %u, k = %u\n", solver, n, k);
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
||||
fprintf(stderr,"notaryid.%d Mining.%s with %s\n",notaryid,SMART_CHAIN_SYMBOL,solver.c_str());
|
||||
LogPrintf("notaryid.%d Mining.%s with %s\n",notaryid,SMART_CHAIN_SYMBOL,solver.c_str());
|
||||
std::mutex m_cs;
|
||||
bool cancelSolver = false;
|
||||
boost::signals2::connection c = uiInterface.NotifyBlockTip.connect(
|
||||
@@ -1685,7 +1610,7 @@ void static BitcoinMiner()
|
||||
|
||||
try {
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
||||
fprintf(stderr,"try %s Mining with %s\n",SMART_CHAIN_SYMBOL,solver.c_str());
|
||||
LogPrintf("try %s Mining with %s\n",SMART_CHAIN_SYMBOL,solver.c_str());
|
||||
while (true)
|
||||
{
|
||||
if (chainparams.MiningRequiresPeers()) {
|
||||
@@ -1703,10 +1628,8 @@ void static BitcoinMiner()
|
||||
if (!fvNodesEmpty )//&& !IsInitialBlockDownload())
|
||||
break;
|
||||
MilliSleep(15000);
|
||||
//fprintf(stderr,"fvNodesEmpty %d IsInitialBlockDownload(%s) %d\n",(int32_t)fvNodesEmpty,SMART_CHAIN_SYMBOL,(int32_t)IsInitialBlockDownload());
|
||||
|
||||
} while (true);
|
||||
//fprintf(stderr,"%s Found peers\n",SMART_CHAIN_SYMBOL);
|
||||
miningTimer.start();
|
||||
}
|
||||
//
|
||||
@@ -1717,7 +1640,7 @@ void static BitcoinMiner()
|
||||
|
||||
// If we don't have a valid chain tip to work from, wait and try again.
|
||||
if (pindexPrev == nullptr) {
|
||||
fprintf(stderr,"%s: null pindexPrev, trying again...\n",__func__);
|
||||
LogPrint("pow", "%s: null pindexPrev, trying again...\n",__func__);
|
||||
MilliSleep(1000);
|
||||
continue;
|
||||
}
|
||||
@@ -1729,7 +1652,6 @@ void static BitcoinMiner()
|
||||
}
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 && ASSETCHAINS_STAKED == 0 )
|
||||
{
|
||||
//fprintf(stderr,"%s create new block ht.%d\n",SMART_CHAIN_SYMBOL,Mining_height);
|
||||
//sleep(3);
|
||||
}
|
||||
|
||||
@@ -1750,11 +1672,10 @@ void static BitcoinMiner()
|
||||
}
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 10 && ASSETCHAINS_STAKED == 0 )
|
||||
fprintf(stderr,"created illegal blockB, retry\n");
|
||||
LogPrint("pow", "created illegal blockB, retry\n");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
//fprintf(stderr,"get template\n");
|
||||
unique_ptr<CBlockTemplate> pblocktemplate(ptr);
|
||||
if (!pblocktemplate.get())
|
||||
{
|
||||
@@ -1775,14 +1696,13 @@ void static BitcoinMiner()
|
||||
{
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 10 )
|
||||
fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",SMART_CHAIN_SYMBOL);
|
||||
LogPrint("pow", "skip generating %s on-demand block, no tx avail\n",SMART_CHAIN_SYMBOL);
|
||||
sleep(10);
|
||||
continue;
|
||||
} else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",SMART_CHAIN_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
|
||||
} else LogPrint("pow", "%s vouts.%d mining.%d vs %d\n",SMART_CHAIN_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
|
||||
}
|
||||
}
|
||||
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
||||
//fprintf(stderr,"Running HushMiner.%s with %u transactions in block\n",solver.c_str(),(int32_t)pblock->vtx.size());
|
||||
LogPrintf("Running HushMiner.%s with %u transactions in block (%u bytes)\n",solver.c_str(),pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
|
||||
|
||||
// Search
|
||||
@@ -1798,7 +1718,6 @@ void static BitcoinMiner()
|
||||
gotinvalid = 0;
|
||||
while (true)
|
||||
{
|
||||
//fprintf(stderr,"gotinvalid.%d\n",gotinvalid);
|
||||
if ( gotinvalid != 0 )
|
||||
break;
|
||||
hush_longestchain();
|
||||
@@ -1823,7 +1742,6 @@ void static BitcoinMiner()
|
||||
if ( HUSH_MININGTHREADS > 0 && ASSETCHAINS_STAKED > 0 && ASSETCHAINS_STAKED < 100 && Mining_height > 10 )
|
||||
hashTarget = HASHTarget_POW;
|
||||
//else if ( ASSETCHAINS_ADAPTIVEPOW > 0 )
|
||||
// hashTarget = HASHTarget_POW;
|
||||
else hashTarget = HASHTarget;
|
||||
std::function<bool(std::vector<unsigned char>)> validBlock =
|
||||
#ifdef ENABLE_WALLET
|
||||
@@ -1837,7 +1755,6 @@ void static BitcoinMiner()
|
||||
LogPrint("pow", "- Checking solution against target\n");
|
||||
pblock->nSolution = soln;
|
||||
solutionTargetChecks.increment();
|
||||
// fprintf(stderr, "%s: solutionTargetChecks=%lu\n", __func__, solutionTargetChecks.get());
|
||||
B = *pblock;
|
||||
h = UintToArith256(B.GetHash());
|
||||
/*for (z=31; z>=16; z--)
|
||||
@@ -1857,13 +1774,12 @@ void static BitcoinMiner()
|
||||
}
|
||||
if ( IS_HUSH_NOTARY != 0 && B.nTime > GetTime() )
|
||||
{
|
||||
//fprintf(stderr,"need to wait %d seconds to submit block\n",(int32_t)(B.nTime - GetTime()));
|
||||
while ( GetTime() < B.nTime-2 )
|
||||
{
|
||||
sleep(1);
|
||||
if ( chainActive.LastTip()->GetHeight() >= Mining_height )
|
||||
{
|
||||
fprintf(stderr,"new block arrived\n");
|
||||
LogPrint("pow", "new block arrived\n");
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
@@ -1877,13 +1793,6 @@ void static BitcoinMiner()
|
||||
MilliSleep((rand() % (r * 1000)) + 1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint256 tmp = B.GetHash();
|
||||
int32_t z; for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&tmp)[z]);
|
||||
fprintf(stderr," mined %s block %d!\n",SMART_CHAIN_SYMBOL,Mining_height);
|
||||
}
|
||||
CValidationState state;
|
||||
|
||||
//{ LOCK(cs_main);
|
||||
@@ -1891,8 +1800,6 @@ void static BitcoinMiner()
|
||||
{
|
||||
h = UintToArith256(B.GetHash());
|
||||
//for (z=31; z>=0; z--)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&h)[z]);
|
||||
//fprintf(stderr," Invalid block mined, try again\n");
|
||||
gotinvalid = 1;
|
||||
return(false);
|
||||
}
|
||||
@@ -1967,8 +1874,6 @@ void static BitcoinMiner()
|
||||
if (found) {
|
||||
int32_t i; uint256 hash = pblock->GetHash();
|
||||
//for (i=0; i<32; i++)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
|
||||
//fprintf(stderr," <- %s Block found %d\n",SMART_CHAIN_SYMBOL,Mining_height);
|
||||
//FOUND_BLOCK = 1;
|
||||
//HUSH_MAYBEMINED = Mining_height;
|
||||
break;
|
||||
@@ -1993,14 +1898,14 @@ void static BitcoinMiner()
|
||||
{
|
||||
if ( SMART_CHAIN_SYMBOL[0] == 0 || Mining_height > ASSETCHAINS_MINHEIGHT )
|
||||
{
|
||||
fprintf(stderr,"no nodes, break\n");
|
||||
LogPrint("pow", "no nodes, break\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff)
|
||||
{
|
||||
//if ( 0 && SMART_CHAIN_SYMBOL[0] != 0 )
|
||||
fprintf(stderr,"0xffff, break\n");
|
||||
LogPrint("pow", "0xffff, break\n");
|
||||
break;
|
||||
}
|
||||
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
|
||||
@@ -2024,7 +1929,6 @@ void static BitcoinMiner()
|
||||
HASHTarget.SetCompact(pblock->nBits);
|
||||
hashTarget = HASHTarget;
|
||||
savebits = pblock->nBits;
|
||||
//hashTarget = HASHTarget_POW = hush_adaptivepow_target(Mining_height,HASHTarget,pblock->nTime);
|
||||
}
|
||||
/*if ( NOTARY_PUBKEY33[0] == 0 )
|
||||
{
|
||||
@@ -2104,7 +2008,6 @@ void static BitcoinMiner()
|
||||
g_rxDatasetManager = new RandomXDatasetManager();
|
||||
if (!g_rxDatasetManager->Init()) {
|
||||
LogPrintf("%s: FATAL - Failed to initialize shared RandomX dataset manager\n", __func__);
|
||||
fprintf(stderr, "%s: FATAL - Failed to initialize shared RandomX dataset manager\n", __func__);
|
||||
delete g_rxDatasetManager;
|
||||
g_rxDatasetManager = nullptr;
|
||||
delete minerThreads;
|
||||
|
||||
54
src/net.cpp
54
src/net.cpp
@@ -56,7 +56,7 @@ extern uint8_t ASSETCHAINS_CLEARNET;
|
||||
// Run asmap health check every 24hr by default
|
||||
#define ASMAP_HEALTHCHECK_INTERVAL 24*60*60
|
||||
|
||||
// This is every 2 blocks, on avg, on HUSH3
|
||||
// Interval (seconds) between zindex stat dumps when -zindex is enabled.
|
||||
#define DUMP_ZINDEX_INTERVAL 150
|
||||
|
||||
#define CHECK_PLZ_STOP_INTERVAL 120
|
||||
@@ -79,7 +79,9 @@ extern uint8_t ASSETCHAINS_CLEARNET;
|
||||
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
|
||||
#define FEELER_SLEEP_WINDOW 1
|
||||
|
||||
#define USE_TLS "encrypted as fuck"
|
||||
// Marker macro that enables the TLS p2p transport. Only its definedness is
|
||||
// ever tested (via defined()/#ifdef); the string value itself is never used.
|
||||
#define USE_TLS "enabled"
|
||||
|
||||
#if defined(USE_TLS) && !defined(TLS1_3_VERSION)
|
||||
// minimum secure protocol is 1.3
|
||||
@@ -468,12 +470,20 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) {
|
||||
bool connected = false;
|
||||
std::unique_ptr<Sock> sock;
|
||||
|
||||
if (!addrConnect.IsValid()) {
|
||||
return NULL;
|
||||
}
|
||||
// When connecting by name (pszDest is set, e.g. -connect / -addnode host:port
|
||||
// or "addnode <host> onetry"), addrConnect is an empty placeholder — the real
|
||||
// target is resolved from pszDest by ConnectSocketByName() below. Only validate
|
||||
// addrConnect when we are dialing it directly (pszDest == NULL); otherwise
|
||||
// IsValid()/IsReachable() on the empty address abort the connection before it is
|
||||
// ever attempted, which silently breaks -connect.
|
||||
if (!pszDest) {
|
||||
if (!addrConnect.IsValid()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!IsReachable(addrConnect)) {
|
||||
return NULL;
|
||||
if (!IsReachable(addrConnect)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (addrConnect.GetNetwork() == NET_I2P && m_i2p_sam_session.get() != nullptr) {
|
||||
@@ -614,7 +624,7 @@ void DumpBanlist()
|
||||
if (bandb.Write(banmap)) {
|
||||
SetBannedSetDirty(false);
|
||||
}
|
||||
fprintf(stderr,"%s: Dumping banlist with %lu items\n", __func__, banmap.size());
|
||||
LogPrint("net", "%s: Dumping banlist with %lu items\n", __func__, banmap.size());
|
||||
|
||||
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
|
||||
banmap.size(), GetTimeMillis() - nStart);
|
||||
@@ -642,7 +652,7 @@ bool CNode::IsBanned(CNetAddr ip)
|
||||
CBanEntry banEntry = (*it).second;
|
||||
|
||||
if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil) {
|
||||
fprintf(stderr,"%s: found banned subnet %s\n", __func__, subNet.ToString().c_str());
|
||||
LogPrint("net", "%s: found banned subnet %s\n", __func__, subNet.ToString().c_str());
|
||||
fResult = true;
|
||||
}
|
||||
}
|
||||
@@ -676,7 +686,7 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
|
||||
if (bantimeoffset > 0)
|
||||
banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
|
||||
|
||||
fprintf(stderr, "%s: banning %s until %ld with bantimeoffset=%ld sinceUnixEpoch=%d\n", __func__, subNet.ToString().c_str(), banEntry.nBanUntil, bantimeoffset, sinceUnixEpoch);
|
||||
LogPrint("net", "%s: banning %s until %ld with bantimeoffset=%ld sinceUnixEpoch=%d\n", __func__, subNet.ToString().c_str(), banEntry.nBanUntil, bantimeoffset, sinceUnixEpoch);
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
|
||||
@@ -689,14 +699,15 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (CNode* pnode : vNodes) {
|
||||
if (subNet.Match(static_cast<CNetAddr>(pnode->addr)))
|
||||
fprintf(stderr, "%s: disconnecting from banned node %s\n", __func__, pnode->addr.ToString().c_str() );
|
||||
if (subNet.Match(static_cast<CNetAddr>(pnode->addr))) {
|
||||
LogPrint("net", "%s: disconnecting from banned node %s\n", __func__, pnode->addr.ToString().c_str() );
|
||||
pnode->fDisconnect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(banReason == BanReasonManuallyAdded) {
|
||||
fprintf(stderr,"%s: dumping banlist after manual ban\n", __func__);
|
||||
LogPrint("net", "%s: dumping banlist after manual ban\n", __func__);
|
||||
DumpBanlist(); //store banlist to disk immediately if user requested ban
|
||||
}
|
||||
}
|
||||
@@ -815,7 +826,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
|
||||
nPingUsecWait = GetTimeMicros() - nPingUsecStart;
|
||||
}
|
||||
|
||||
// Raw ping time is in microseconds, but show it to user as whole seconds (Hush users should be well used to small numbers with many decimal places by now :)
|
||||
// Raw ping time is in microseconds; convert to seconds for display to the user.
|
||||
stats.dPingTime = (((double)nPingUsecTime) / 1e6);
|
||||
stats.dMinPing = (((double)nMinPingUsecTime) / 1e6);
|
||||
stats.dPingWait = (((double)nPingUsecWait) / 1e6);
|
||||
@@ -1581,6 +1592,7 @@ void ThreadDNSAddressSeed()
|
||||
CAddress addr = CAddress(CService(ip, ASSETCHAINS_P2PPORT));
|
||||
addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
|
||||
vAdd.push_back(addr);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
// TODO: The seed name resolve may fail, yielding an IP of [::], which results in
|
||||
@@ -1721,7 +1733,6 @@ void ThreadOpenConnections()
|
||||
boost::this_thread::interruption_point();
|
||||
|
||||
// Add seed nodes if DNS seeds are all down (an infrastructure attack?).
|
||||
// if (addrman.size() == 0 && (GetTime() - nStart > 60)) {
|
||||
if (GetTime() - nStart > 60) {
|
||||
static bool done = false;
|
||||
if (!done) {
|
||||
@@ -1851,7 +1862,6 @@ void ThreadOpenConnections()
|
||||
int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
|
||||
MilliSleep(randsleep);
|
||||
LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString().c_str());
|
||||
printf("%s: Making feeler connection to %s\n", __func__, addrConnect.ToString().c_str());
|
||||
}
|
||||
|
||||
//int failures = setConnected.size() >= std::min(nMaxConnections - 1, 2);
|
||||
@@ -2510,22 +2520,24 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
||||
// If we have no nodes to relay to, there is nothing to do
|
||||
if(vNodes.size() == 0) {
|
||||
if (HUSH_TESTNODE==0) {
|
||||
fprintf(stderr, "%s: No nodes to relay to!\n", __func__ );
|
||||
LogPrint("net", "%s: No nodes to relay to!\n", __func__ );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We always round down, except when we have only 1 connection
|
||||
// Relay to half of our peers, rounding down, but never fewer than 1.
|
||||
// Equivalent to max(1, vNodes.size()/2): the ternary picks 1 only when the
|
||||
// integer division vNodes.size()/2 is 0 (i.e. exactly 1 connection).
|
||||
auto newSize = (vNodes.size() / 2) == 0 ? 1 : (vNodes.size() / 2);
|
||||
|
||||
std::shuffle( vRelayNodes.begin(), vRelayNodes.end(), std::mt19937(GetRand(std::numeric_limits<uint32_t>::max())) );
|
||||
|
||||
vRelayNodes.resize(newSize);
|
||||
if (HUSH_TESTNODE==1 && vNodes.size() == 0) {
|
||||
fprintf(stderr, "%s: -testnode=1, no peers, not relaying\n", __func__ );
|
||||
LogPrint("net", "%s: -testnode=1, no peers, not relaying\n", __func__ );
|
||||
return;
|
||||
} else {
|
||||
fprintf(stderr, "%s: Relaying %s to %lu of %lu peers\n", __func__, tx.GetHash().GetHex().c_str(), newSize, vNodes.size() );
|
||||
LogPrint("net", "%s: Relaying %s to %lu of %lu peers\n", __func__, tx.GetHash().GetHex().c_str(), newSize, vNodes.size() );
|
||||
}
|
||||
|
||||
// Only relay to randomly chosen 50% of peers
|
||||
@@ -2774,7 +2786,7 @@ bool CNode::GetTlsValidate()
|
||||
{
|
||||
if (tlsValidate == eTlsOption::FALLBACK_UNSET)
|
||||
{
|
||||
// This is useful for private Hush Arrakis Chains, that want to exist
|
||||
// This is useful for private DragonX-based chains that want to exist
|
||||
// on a closed VPN with an internal CA or trusted cert system, or
|
||||
// various other use cases
|
||||
if ( GetBoolArg("-tlsvalidate", false)) {
|
||||
|
||||
@@ -44,9 +44,12 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/signals2/signal.hpp>
|
||||
// Enable WolfSSL Support for Hush
|
||||
// Enable WolfSSL support for DragonX
|
||||
#include <wolfssl/options.h>
|
||||
// TODO: these are not set correctly by wolfssl for some reason. Ja bless.
|
||||
// Force-enable wolfSSL's constant-time (timing-resistant) ECC and TFM code paths.
|
||||
// These are feature-enable macros that wolfSSL checks with #ifdef, so the numeric
|
||||
// value is immaterial to behavior; the value 420 is arbitrary and must simply be
|
||||
// non-empty. Redefined here because wolfssl/options.h does not reliably set them.
|
||||
#undef ECC_TIMING_RESISTANT
|
||||
#undef TFM_TIMING_RESISTANT
|
||||
#define ECC_TIMING_RESISTANT 420
|
||||
|
||||
162
src/pow.cpp
162
src/pow.cpp
@@ -97,75 +97,13 @@ bnTarget = RT_CST_RST (bnTarget, ts, cw, numerator, denominator, W, T, past);
|
||||
#define T ASSETCHAINS_BLOCKTIME
|
||||
#define K ((int64_t)1000000)
|
||||
|
||||
#ifdef original_algo
|
||||
arith_uint256 oldRT_CST_RST(int32_t height,uint32_t nTime,arith_uint256 bnTarget,uint32_t *ts,arith_uint256 *ct,int32_t numerator,int32_t denominator,int32_t W,int32_t past)
|
||||
// The proof-of-work limit for the active algorithm: Equihash chains use params.powLimit,
|
||||
// everything else (DragonX = RandomX) uses params.powAlternate. Shared by the retarget
|
||||
// functions below, where this selection was previously copy-pasted as an if/else.
|
||||
static arith_uint256 PowLimitForAlgo(const Consensus::Params& params)
|
||||
{
|
||||
//if (ts.size() < 2*W || ct.size() < 2*W ) { exit; } // error. a vector was too small
|
||||
//if (ts.size() < past+W || ct.size() < past+W ) { past = min(ct.size(), ts.size()) - W; } // past was too small, adjust
|
||||
int64_t altK; int32_t i,j,k,ii=0; // K is a scaling factor for integer divisions
|
||||
if ( height < 64 )
|
||||
return(bnTarget);
|
||||
//if ( ((ts[0]-ts[W]) * W * 100)/(W-1) < (T * numerator * 100)/denominator )
|
||||
if ( (ts[0] - ts[W]) < (T * numerator)/denominator )
|
||||
{
|
||||
//bnTarget = ((ct[0]-ct[1])/K) * max(K,(K*(nTime-ts[0])*(ts[0]-ts[W])*denominator/numerator)/T/T);
|
||||
bnTarget = ct[0] / arith_uint256(K);
|
||||
//altK = (K * (nTime-ts[0]) * (ts[0]-ts[W]) * denominator * W) / (numerator * (W-1) * (T * T));
|
||||
altK = (K * (nTime-ts[0]) * (ts[0]-ts[W]) * denominator) / (numerator * (T * T));
|
||||
fprintf(stderr,"ht.%d initial altK.%lld %d * %d * %d / %d\n",height,(long long)altK,(nTime-ts[0]),(ts[0]-ts[W]),denominator,numerator);
|
||||
if ( altK > K )
|
||||
altK = K;
|
||||
bnTarget *= arith_uint256(altK);
|
||||
if ( altK < K )
|
||||
return(bnTarget);
|
||||
}
|
||||
/* Check past 24 blocks for any sum of 3 STs < T/2 triggers. This is messy
|
||||
because the blockchain does not allow us to store a variable to know
|
||||
if we are currently in a triggered state that is making a sequence of
|
||||
adjustments to prevTargets, so we have to look for them.
|
||||
Nested loops do this: if block emission has not slowed to be back on track at
|
||||
any time since most recent trigger and we are at current block, aggressively
|
||||
adust prevTarget. */
|
||||
|
||||
for (j=past-1; j>=2; j--)
|
||||
{
|
||||
if ( ts[j]-ts[j+W] < T*numerator/denominator )
|
||||
{
|
||||
ii = 0;
|
||||
for (i=j-2; i>=0; i--)
|
||||
{
|
||||
ii++;
|
||||
// Check if emission caught up. If yes, "trigger stopped at i".
|
||||
// Break loop to try more recent j's to see if trigger activates again.
|
||||
if ( (ts[i] - ts[j+W]) > (ii+W)*T )
|
||||
break;
|
||||
|
||||
// We're here, so there was a TS[j]-TS[j-3] < T/2 trigger in the past and emission rate has not yet slowed up to be back on track so the "trigger is still active", aggressively adjusting target here at block "i"
|
||||
if ( i == 0 )
|
||||
{
|
||||
/* We made it all the way to current block. Emission rate since
|
||||
last trigger never slowed enough to get back on track, so adjust again.
|
||||
If avg last 3 STs = T, this increases target to prevTarget as ST increases to T.
|
||||
This biases it towards ST=~1.75*T to get emission back on track.
|
||||
If avg last 3 STs = T/2, target increases to prevTarget at 2*T.
|
||||
Rarely, last 3 STs can be 1/2 speed => target = prevTarget at T/2, & 1/2 at T.*/
|
||||
|
||||
//bnTarget = ((ct[0]-ct[W])/W/K) * (K*(nTime-ts[0])*(ts[0]-ts[W]))/W/T/T;
|
||||
bnTarget = ct[0];
|
||||
for (k=1; k<W; k++)
|
||||
bnTarget += ct[k];
|
||||
bnTarget /= arith_uint256(W * K);
|
||||
altK = (K * (nTime-ts[0]) * (ts[0]-ts[W])) / (W * T * T);
|
||||
fprintf(stderr,"ht.%d made it to i == 0, j.%d ii.%d altK %lld (%d * %d) %u - %u W.%d\n",height,j,ii,(long long)altK,(nTime-ts[0]),(ts[0]-ts[W]),ts[0],ts[W],W);
|
||||
bnTarget *= arith_uint256(altK);
|
||||
j = 0; // It needed adjusting, we adjusted it, we're finished, so break out of j loop.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(bnTarget);
|
||||
return UintToArith256(ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH ? params.powLimit : params.powAlternate);
|
||||
}
|
||||
#endif
|
||||
|
||||
arith_uint256 RT_CST_RST_outer(int32_t height,uint32_t nTime,arith_uint256 bnTarget,uint32_t *ts,arith_uint256 *ct,int32_t numerator,int32_t denominator,int32_t W,int32_t past)
|
||||
{
|
||||
@@ -183,13 +121,7 @@ arith_uint256 RT_CST_RST_outer(int32_t height,uint32_t nTime,arith_uint256 bnTar
|
||||
}
|
||||
if ( bnTarget > mintarget )
|
||||
bnTarget = mintarget;
|
||||
{
|
||||
int32_t z;
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[z]);
|
||||
}
|
||||
fprintf(stderr," ht.%d initial W.%d outerK.%lld %d * %d * %d / %d\n",height,W,(long long)outerK,(nTime-ts[0]),(ts[0]-ts[W]),denominator,numerator);
|
||||
} //else fprintf(stderr,"ht.%d no outer trigger %d >= %d\n",height,(ts[0] - ts[W]),(T * numerator)/denominator);
|
||||
}
|
||||
return(bnTarget);
|
||||
}
|
||||
|
||||
@@ -202,13 +134,6 @@ arith_uint256 RT_CST_RST_target(int32_t height,uint32_t nTime,arith_uint256 bnTa
|
||||
bnTarget /= arith_uint256(width * K);
|
||||
innerK = (K * (nTime-ts[0]) * (ts[0]-ts[width])) / (width * T * T);
|
||||
bnTarget *= arith_uint256(innerK);
|
||||
if ( 0 )
|
||||
{
|
||||
int32_t z;
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[z]);
|
||||
fprintf(stderr," ht.%d innerK %lld (%d * %d) %u - %u width.%d\n",height,(long long)innerK,(nTime-ts[0]),(ts[0]-ts[width]),ts[0],ts[width],width);
|
||||
}
|
||||
return(bnTarget);
|
||||
}
|
||||
|
||||
@@ -223,12 +148,6 @@ arith_uint256 RT_CST_RST_inner(int32_t height,uint32_t nTime,arith_uint256 bnTar
|
||||
bnTarget = RT_CST_RST_target(height,nTime,bnTarget,ts,ct,W);
|
||||
if ( bnTarget == origtarget ) // force zawyflag to 1
|
||||
bnTarget = mintarget;
|
||||
{
|
||||
int32_t z;
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[z]);
|
||||
}
|
||||
fprintf(stderr," height.%d O.%-2d, W.%-2d width.%-2d %4d vs %-4d, deficit %4d tip.%d\n",height,outeri,W,width,(ts[0] - ts[width]),expected,expected - (ts[0] - ts[width]),nTime-ts[0]);
|
||||
}
|
||||
return(bnTarget);
|
||||
}
|
||||
@@ -288,31 +207,19 @@ arith_uint256 zawy_TSA_EMA(int32_t height,int32_t tipdiff,arith_uint256 prevTarg
|
||||
B = (bnTarget / arith_uint256(360000)) * arith_uint256(tipdiff * zawy_exponential_val360000(tipdiff/2));
|
||||
C = (bnTarget / arith_uint256(360000)) * arith_uint256(T * zawy_exponential_val360000(tipdiff/2));
|
||||
bnTarget = ((A + B - C) / arith_uint256(tipdiff)) * arith_uint256(K*T);
|
||||
{
|
||||
int32_t z;
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[z]);
|
||||
}
|
||||
fprintf(stderr," ht.%d TSA bnTarget tipdiff.%d\n",height,tipdiff);
|
||||
return(bnTarget);
|
||||
}
|
||||
|
||||
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
|
||||
{
|
||||
if (pindexLast->GetHeight() == 340000) {
|
||||
LogPrintf("%s: Using blocktime=%d\n",__func__,ASSETCHAINS_BLOCKTIME);
|
||||
}
|
||||
//if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH && ASSETCHAINS_STAKED == 0)
|
||||
if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH && ASSETCHAINS_ALGO != ASSETCHAINS_RANDOMX) {
|
||||
fprintf(stderr,"%s: using lwma for next work\n",__func__);
|
||||
LogPrint("pow","%s: using lwma for next work\n",__func__);
|
||||
return lwmaGetNextWorkRequired(pindexLast, pblock, params);
|
||||
}
|
||||
|
||||
arith_uint256 bnLimit;
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
|
||||
bnLimit = UintToArith256(params.powLimit);
|
||||
else
|
||||
bnLimit = UintToArith256(params.powAlternate);
|
||||
bnLimit = PowLimitForAlgo(params);
|
||||
unsigned int nProofOfWorkLimit = bnLimit.GetCompact();
|
||||
// Genesis block
|
||||
if (pindexLast == NULL )
|
||||
@@ -386,13 +293,11 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||
{
|
||||
blocktime = pindexFirst->nTime;
|
||||
diff = (pblock->nTime - blocktime);
|
||||
//fprintf(stderr,"%d ",diff);
|
||||
if ( i < 6 )
|
||||
{
|
||||
diff -= (8+i)*ASSETCHAINS_BLOCKTIME;
|
||||
if ( diff > mult )
|
||||
{
|
||||
//fprintf(stderr,"i.%d diff.%d (%u - %u - %dx)\n",i,(int32_t)diff,pblock->nTime,pindexFirst->nTime,(8+i));
|
||||
mult = diff;
|
||||
}
|
||||
}
|
||||
@@ -402,7 +307,6 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||
bnTot += bnTmp;
|
||||
pindexFirst = pindexFirst->pprev;
|
||||
}
|
||||
//fprintf(stderr,"diffs %d\n",height);
|
||||
// Check we have enough blocks
|
||||
if (pindexFirst == NULL)
|
||||
return nProofOfWorkLimit;
|
||||
@@ -499,21 +403,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||
if ( bnTarget < origtarget || bnTarget > easy )
|
||||
{
|
||||
bnTarget = easy;
|
||||
fprintf(stderr,"cmp.%d mult.%d ht.%d -> easy target\n",mult>1,(int32_t)mult,height);
|
||||
LogPrint("pow","cmp.%d mult.%d ht.%d -> easy target\n",mult>1,(int32_t)mult,height);
|
||||
return(HUSH_MINDIFF_NBITS & (~3));
|
||||
}
|
||||
{
|
||||
int32_t z;
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[z]);
|
||||
}
|
||||
fprintf(stderr," exp() to the rescue cmp.%d mult.%d for ht.%d\n",mult>1,(int32_t)mult,height);
|
||||
}
|
||||
if ( 0 && zflags[0] == 0 && zawyflag == 0 && mult <= 1 )
|
||||
{
|
||||
bnTarget = zawy_TSA_EMA(height,tipdiff,(bnTarget+ct[0]+ct[1])/arith_uint256(3),ts[0] - ts[1]);
|
||||
if ( bnTarget < origtarget )
|
||||
zawyflag = 3;
|
||||
}
|
||||
}
|
||||
nbits = bnTarget.GetCompact();
|
||||
@@ -527,7 +419,10 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||
|
||||
// Changing this requires changing many other things and
|
||||
// might change consensus. Have fun -- Duke
|
||||
// NOTE: Ony HUSH3 mainnet should use this function, all HAC's should use params.AveragigWindowTimespan()
|
||||
// NOTE: This hardcoded AWT is legacy from the original HUSH3 mainnet. On DragonX the
|
||||
// CalculateNextWorkRequired strncmp(SMART_CHAIN_SYMBOL,"HUSH3",...) check is never true
|
||||
// (SMART_CHAIN_SYMBOL is "DRAGONX"), so this function is dead here and the params-derived
|
||||
// AveragingWindowTimespan() is used instead. Kept as-is to avoid a consensus change.
|
||||
int64_t AveragingWindowTimespan() {
|
||||
// used in const methods, beware!
|
||||
// This is the correct AWT for 75s blocktime, before block 340k
|
||||
@@ -545,8 +440,11 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||
int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime;
|
||||
LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan);
|
||||
|
||||
// Legacy branch: the original HUSH3 mainnet used the hardcoded AveragingWindowTimespan()
|
||||
// above; every other chain uses the params-derived value. On DragonX the symbol is
|
||||
// "DRAGONX", so this comparison is always false and the params value is used. The check is
|
||||
// kept (rather than removed) because it is part of consensus difficulty calculation.
|
||||
bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||
// If this is HUSH3, use AWT function defined above, else use the one in params
|
||||
int64_t AWT = ishush3 ? AveragingWindowTimespan() : params.AveragingWindowTimespan();
|
||||
|
||||
nActualTimespan = AWT + (nActualTimespan - AWT)/4;
|
||||
@@ -568,10 +466,7 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||
}
|
||||
// Retarget
|
||||
arith_uint256 bnLimit;
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
|
||||
bnLimit = UintToArith256(params.powLimit);
|
||||
else
|
||||
bnLimit = UintToArith256(params.powAlternate);
|
||||
bnLimit = PowLimitForAlgo(params);
|
||||
|
||||
const arith_uint256 bnPowLimit = bnLimit; //UintToArith256(params.powLimit);
|
||||
arith_uint256 bnNew {bnAvg};
|
||||
@@ -594,8 +489,9 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||
return bnNew.GetCompact();
|
||||
}
|
||||
|
||||
// HUSH does not use these functions but Hush Arrakis Chains can opt-in to using more bleeding edge DAA's
|
||||
// ASIC chains do not need these protections as much -- Duke Leto
|
||||
// These LWMA difficulty functions are inherited from the Hush lineage and are only used when
|
||||
// ASSETCHAINS_ALGO is neither Equihash nor RandomX (see the dispatch in GetNextWorkRequired).
|
||||
// DragonX uses RandomX, so this LWMA path is not on DragonX's active difficulty codepath.
|
||||
unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
|
||||
{
|
||||
return lwmaCalculateNextWorkRequired(pindexLast, params);
|
||||
@@ -604,14 +500,10 @@ unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock
|
||||
unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params)
|
||||
{
|
||||
arith_uint256 nextTarget {0}, sumTarget {0}, bnTmp, bnLimit;
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
|
||||
bnLimit = UintToArith256(params.powLimit);
|
||||
else
|
||||
bnLimit = UintToArith256(params.powAlternate);
|
||||
bnLimit = PowLimitForAlgo(params);
|
||||
|
||||
unsigned int nProofOfWorkLimit = bnLimit.GetCompact();
|
||||
|
||||
//printf("PoWLimit: %u\n", nProofOfWorkLimit);
|
||||
|
||||
// Find the first block in the averaging interval as we total the linearly weighted average
|
||||
const CBlockIndex* pindexFirst = pindexLast;
|
||||
const CBlockIndex* pindexNext;
|
||||
@@ -872,14 +764,6 @@ bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)
|
||||
snprintf(buf, sizeof(buf), "%02x", pblock->nSolution[i]);
|
||||
solutionHex += buf;
|
||||
}
|
||||
fprintf(stderr, "CheckRandomXSolution(): HASH MISMATCH at height %d\n", height);
|
||||
fprintf(stderr, " computed : %s\n", computedHex.c_str());
|
||||
fprintf(stderr, " nSolution: %s\n", solutionHex.c_str());
|
||||
fprintf(stderr, " rxKey size=%lu, input size=%lu, nNonce=%s\n",
|
||||
rxKey.size(), ssInput.size(), pblock->nNonce.ToString().c_str());
|
||||
fprintf(stderr, " nSolution.size()=%lu, RANDOMX_HASH_SIZE=%d\n",
|
||||
pblock->nSolution.size(), RANDOMX_HASH_SIZE);
|
||||
// Also log to debug.log
|
||||
LogPrintf("CheckRandomXSolution(): HASH MISMATCH at height %d\n", height);
|
||||
LogPrintf(" computed : %s\n", computedHex);
|
||||
LogPrintf(" nSolution: %s\n", solutionHex);
|
||||
|
||||
@@ -42,6 +42,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "getaddednodeinfo", 0 },
|
||||
{ "setgenerate", 0 },
|
||||
{ "setgenerate", 1 },
|
||||
{ "stratummine", 1 }, // port
|
||||
{ "stratummine", 3 }, // timeout
|
||||
{ "generate", 0 },
|
||||
{ "getnetworkhashps", 0 },
|
||||
{ "getnetworkhashps", 1 },
|
||||
@@ -50,8 +52,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "sendtoaddress", 1 },
|
||||
{ "sendtoaddress", 4 },
|
||||
{ "settxfee", 0 },
|
||||
{ "getnotarysendmany", 0 },
|
||||
{ "getnotarysendmany", 1 },
|
||||
{ "getreceivedbyaddress", 1 },
|
||||
{ "getreceivedbyaccount", 1 },
|
||||
{ "listreceivedbyaddress", 0 },
|
||||
@@ -171,7 +171,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
|
||||
// crosschain
|
||||
{ "assetchainproof", 1},
|
||||
{ "crosschainproof", 1},
|
||||
{ "getproofroot", 2},
|
||||
{ "getNotarizationsForBlock", 0},
|
||||
{ "height_MoM", 1},
|
||||
|
||||
@@ -78,14 +78,6 @@ UniValue assetchainproof(const UniValue& params, bool fHelp, const CPubKey& mypk
|
||||
}
|
||||
|
||||
|
||||
UniValue crosschainproof(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
//fprintf(stderr,"crosschainproof needs to be implemented\n");
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
UniValue height_MoM(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
int32_t height,depth,notarized_height,MoMoMdepth,MoMoMoffset,hushstarti,hushendi; uint256 MoM,MoMoM,hushtxid; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
|
||||
|
||||
@@ -45,6 +45,21 @@
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
#include "compat/byteswap.h" // bswap_32 for the stratum wire fields (version/time/bits)
|
||||
#ifndef WIN32
|
||||
// stratummine (below) is a POSIX-only reference RandomX stratum miner used to exercise the pool
|
||||
// path end-to-end. It reuses DragonX's own RandomX + GetRandomXInput so its hash is byte-identical
|
||||
// to CheckRandomXSolution. Not built on Windows (raw POSIX sockets).
|
||||
#include "RandomX/src/randomx.h"
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "hush_defs.h"
|
||||
@@ -363,7 +378,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
}
|
||||
|
||||
HUSH_MININGTHREADS = (int32_t)nGenProcLimit;
|
||||
fprintf(stderr,"%s:HUSH_MININGTHREADS=%d\n", __FUNCTION__, HUSH_MININGTHREADS);
|
||||
LogPrint("mining","%s:HUSH_MININGTHREADS=%d\n", __FUNCTION__, HUSH_MININGTHREADS);
|
||||
|
||||
mapArgs["-gen"] = (fGenerate ? "1" : "0");
|
||||
mapArgs ["-genproclimit"] = itostr(HUSH_MININGTHREADS);
|
||||
@@ -460,15 +475,8 @@ UniValue getmininginfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty()));
|
||||
obj.push_back(Pair("errors", GetWarnings("statusbar")));
|
||||
obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
|
||||
{
|
||||
obj.push_back(Pair("localsolps" , getlocalsolps(params, false, mypk)));
|
||||
obj.push_back(Pair("networksolps", getnetworksolps(params, false, mypk)));
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.push_back(Pair("localhashps" , GetBoolArg("-gen", false) ? getlocalsolps(params, false, mypk) : (double)0.0));
|
||||
}
|
||||
// DragonX is RandomX-only; the Equihash sol/s reporting path was removed.
|
||||
obj.push_back(Pair("localhashps" , GetBoolArg("-gen", false) ? getlocalsolps(params, false, mypk) : (double)0.0));
|
||||
obj.push_back(Pair("networkhashps", getnetworksolps(params, false, mypk)));
|
||||
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
|
||||
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
|
||||
@@ -854,7 +862,6 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
|
||||
result.push_back(Pair("height", (int64_t)(pindexPrev->GetHeight()+1)));
|
||||
|
||||
//fprintf(stderr,"return complete template\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -905,7 +912,6 @@ UniValue submitblock(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
);
|
||||
|
||||
CBlock block;
|
||||
//LogPrintStr("Hex block submission: " + params[0].get_str());
|
||||
if (!DecodeHexBlk(block, params[0].get_str()))
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
|
||||
|
||||
@@ -931,7 +937,6 @@ UniValue submitblock(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
CValidationState state;
|
||||
submitblock_StateCatcher sc(block.GetHash());
|
||||
RegisterValidationInterface(&sc);
|
||||
//printf("submitblock, height=%d, coinbase sequence: %d, scriptSig: %s\n", chainActive.LastTip()->GetHeight()+1, block.vtx[0].vin[0].nSequence, block.vtx[0].vin[0].scriptSig.ToString().c_str());
|
||||
bool fAccepted = ProcessNewBlock(1,chainActive.LastTip()->GetHeight()+1,state, NULL, &block, true, NULL);
|
||||
UnregisterValidationInterface(&sc);
|
||||
if (fBlockPresent)
|
||||
@@ -1063,9 +1068,242 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp, const CPubKey& mypk
|
||||
}
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_RANDOMX; // hush_defs.h — active PoW algorithm
|
||||
|
||||
// Send one newline-terminated JSON line on a blocking socket.
|
||||
static bool StratumMinerSend(int fd, const std::string& s)
|
||||
{
|
||||
std::string line = s;
|
||||
if (line.empty() || line.back() != '\n') line += '\n';
|
||||
size_t off = 0;
|
||||
while (off < line.size()) {
|
||||
ssize_t n = send(fd, line.data() + off, line.size() - off, 0);
|
||||
if (n <= 0) return false;
|
||||
off += (size_t)n;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wait up to timeout_ms for data, then split all completed lines out of buf into out.
|
||||
// Returns false only on socket error/close (a timeout with no data is success with out empty).
|
||||
static bool StratumMinerRecvLines(int fd, std::string& buf, int timeout_ms, std::vector<std::string>& out)
|
||||
{
|
||||
fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds);
|
||||
struct timeval tv; tv.tv_sec = timeout_ms / 1000; tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
int r = select(fd + 1, &rfds, NULL, NULL, &tv);
|
||||
if (r < 0) return false;
|
||||
if (r == 0) return true;
|
||||
char tmp[8192];
|
||||
ssize_t n = recv(fd, tmp, sizeof(tmp), 0);
|
||||
if (n <= 0) return false;
|
||||
buf.append(tmp, tmp + n);
|
||||
size_t pos;
|
||||
while ((pos = buf.find('\n')) != std::string::npos) {
|
||||
std::string line = buf.substr(0, pos);
|
||||
buf.erase(0, pos + 1);
|
||||
if (!line.empty() && line.back() == '\r') line.pop_back();
|
||||
if (!line.empty()) out.push_back(line);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reference RandomX stratum miner (test utility): connect to a DragonX stratum server, subscribe +
|
||||
// authorize, receive work + the per-height RandomX key, then vary the block nNonce, hash with
|
||||
// RandomX (byte-identical to CheckRandomXSolution via GetRandomXInput), and submit a 32-byte
|
||||
// solution when the block hash meets target. Exists to validate the -stratum RandomX pool path.
|
||||
UniValue stratummine(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
if (fHelp || params.size() < 2 || params.size() > 4)
|
||||
throw runtime_error(
|
||||
"stratummine \"host\" port ( \"address\" timeout )\n"
|
||||
"\nReference RandomX stratum miner: connect to a DragonX stratum server, solve RandomX,\n"
|
||||
"and submit until one share/block is accepted or the timeout elapses. For testing -stratum.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"host\" (string, required) stratum server host or IP\n"
|
||||
"2. port (numeric, required) stratum server port\n"
|
||||
"3. \"address\" (string, optional, default=\"x\") payout R-address, or \"x\" for the server default\n"
|
||||
"4. timeout (numeric, optional, default=120) seconds to mine before giving up\n"
|
||||
"\nResult: {\"found\":bool,\"accepted\":bool,\"hash\":\"..\",\"hashes\":n,\"seconds\":n}\n");
|
||||
|
||||
if (ASSETCHAINS_ALGO != ASSETCHAINS_RANDOMX)
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "stratummine only supports RandomX chains");
|
||||
|
||||
const std::string host = params[0].get_str();
|
||||
const int port = params[1].get_int();
|
||||
const std::string addr = params.size() > 2 ? params[2].get_str() : "x";
|
||||
const int64_t timeout = params.size() > 3 ? params[3].get_int64() : 120;
|
||||
const int64_t deadline = GetTime() + timeout;
|
||||
|
||||
// connect (blocking TCP)
|
||||
struct addrinfo hints; memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM;
|
||||
struct addrinfo* ai = NULL;
|
||||
if (getaddrinfo(host.c_str(), strprintf("%d", port).c_str(), &hints, &ai) != 0 || !ai)
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, strprintf("cannot resolve %s:%d", host, port));
|
||||
int fd = -1;
|
||||
for (struct addrinfo* p = ai; p; p = p->ai_next) {
|
||||
fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if (fd < 0) continue;
|
||||
if (connect(fd, p->ai_addr, p->ai_addrlen) == 0) break;
|
||||
close(fd); fd = -1;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if (fd < 0)
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, strprintf("cannot connect to %s:%d", host, port));
|
||||
{ int one = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)); }
|
||||
|
||||
StratumMinerSend(fd, "{\"id\":1,\"method\":\"mining.subscribe\",\"params\":[\"dragonx-refminer/1.0\"]}");
|
||||
StratumMinerSend(fd, strprintf("{\"id\":2,\"method\":\"mining.authorize\",\"params\":[\"%s\",\"x\"]}", addr));
|
||||
|
||||
// state accumulated from the server
|
||||
std::vector<unsigned char> extranonce1;
|
||||
std::string rxKey;
|
||||
bool haveKey = false, haveTarget = false, haveJob = false;
|
||||
arith_uint256 poolTarget;
|
||||
std::string jobId, timeHex;
|
||||
uint32_t nVersion = 4, nTime = 0, nBits = 0;
|
||||
uint256 hashPrevBlock, hashMerkleRoot, hashReserved;
|
||||
|
||||
auto processLine = [&](const std::string& line) {
|
||||
UniValue v;
|
||||
if (!v.read(line)) return;
|
||||
const UniValue& id = find_value(v, "id");
|
||||
const UniValue& result = find_value(v, "result");
|
||||
if (id.isNum() && id.get_int() == 1 && result.isArray() && result.size() >= 2 && result[1].isStr())
|
||||
extranonce1 = ParseHex(result[1].get_str());
|
||||
const UniValue& method = find_value(v, "method");
|
||||
if (!method.isStr()) return;
|
||||
const UniValue& p = find_value(v, "params");
|
||||
if (!p.isArray()) return;
|
||||
const std::string m = method.get_str();
|
||||
if (m == "mining.set_randomx_key" && p.size() >= 1) {
|
||||
std::vector<unsigned char> kb = ParseHex(p[0].get_str());
|
||||
rxKey.assign(kb.begin(), kb.end());
|
||||
haveKey = true;
|
||||
} else if (m == "mining.set_target" && p.size() >= 1) {
|
||||
poolTarget = UintToArith256(uint256S(p[0].get_str()));
|
||||
haveTarget = true;
|
||||
} else if (m == "mining.notify" && p.size() >= 7) {
|
||||
jobId = p[0].get_str();
|
||||
nVersion = bswap_32((uint32_t)strtoul(p[1].get_str().c_str(), NULL, 16));
|
||||
hashPrevBlock = uint256(ParseHex(p[2].get_str()));
|
||||
hashMerkleRoot = uint256(ParseHex(p[3].get_str()));
|
||||
hashReserved = uint256(ParseHex(p[4].get_str()));
|
||||
timeHex = p[5].get_str();
|
||||
nTime = bswap_32((uint32_t)strtoul(timeHex.c_str(), NULL, 16));
|
||||
nBits = bswap_32((uint32_t)strtoul(p[6].get_str().c_str(), NULL, 16));
|
||||
haveJob = true;
|
||||
}
|
||||
};
|
||||
|
||||
std::string buf;
|
||||
for (int i = 0; i < 120 && !(haveJob && haveTarget && haveKey && !extranonce1.empty()); i++) {
|
||||
std::vector<std::string> lines;
|
||||
if (!StratumMinerRecvLines(fd, buf, 250, lines)) { close(fd); throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "stratum connection closed during handshake"); }
|
||||
for (const std::string& l : lines) processLine(l);
|
||||
if (GetTime() > deadline) break;
|
||||
}
|
||||
if (!(haveJob && haveTarget && haveKey && !extranonce1.empty())) {
|
||||
close(fd);
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "did not receive complete RandomX work (need job + target + randomx key + extranonce)");
|
||||
}
|
||||
|
||||
randomx_flags flags = randomx_get_flags();
|
||||
randomx_cache* cache = randomx_alloc_cache(flags);
|
||||
if (!cache) { close(fd); throw JSONRPCError(RPC_MISC_ERROR, "randomx_alloc_cache failed"); }
|
||||
randomx_init_cache(cache, rxKey.data(), rxKey.size());
|
||||
std::string vmKey = rxKey;
|
||||
randomx_vm* vm = randomx_create_vm(flags, cache, NULL);
|
||||
if (!vm) { randomx_release_cache(cache); close(fd); throw JSONRPCError(RPC_MISC_ERROR, "randomx_create_vm failed"); }
|
||||
|
||||
UniValue res(UniValue::VOBJ);
|
||||
bool found = false, accepted = false, submitted = false;
|
||||
uint64_t hashes = 0, en2ctr = 0;
|
||||
std::string foundHash;
|
||||
const int64_t started = GetTime();
|
||||
|
||||
while (GetTime() <= deadline && !found) {
|
||||
std::string prevJob = jobId;
|
||||
std::vector<std::string> lines;
|
||||
if (!StratumMinerRecvLines(fd, buf, 0, lines)) break;
|
||||
for (const std::string& l : lines) processLine(l);
|
||||
if (jobId != prevJob) en2ctr = 0; // new tip -> restart the nonce search
|
||||
if (rxKey != vmKey) { randomx_init_cache(cache, rxKey.data(), rxKey.size()); randomx_vm_set_cache(vm, cache); vmKey = rxKey; }
|
||||
|
||||
arith_uint256 blockTarget; bool fNeg, fOver;
|
||||
blockTarget.SetCompact(nBits, &fNeg, &fOver);
|
||||
// Mine to the harder of (block target, pool share target) so a solution is a real block AND
|
||||
// passes the server's low-diff share check.
|
||||
arith_uint256 tgt = (haveTarget && poolTarget < blockTarget) ? poolTarget : blockTarget;
|
||||
|
||||
CBlockHeader hdr;
|
||||
hdr.nVersion = nVersion;
|
||||
hdr.hashPrevBlock = hashPrevBlock;
|
||||
hdr.hashMerkleRoot = hashMerkleRoot;
|
||||
hdr.hashFinalSaplingRoot = hashReserved;
|
||||
hdr.nTime = nTime;
|
||||
hdr.nBits = nBits;
|
||||
|
||||
for (int i = 0; i < 2000 && GetTime() <= deadline; i++) {
|
||||
std::vector<unsigned char> nonce = extranonce1;
|
||||
nonce.resize(32, 0);
|
||||
for (int b = 0; b < 8; b++) nonce[8 + b] = (unsigned char)((en2ctr >> (8 * b)) & 0xff);
|
||||
en2ctr++; hashes++;
|
||||
hdr.nNonce = uint256(nonce);
|
||||
std::vector<unsigned char> input = GetRandomXInput(hdr);
|
||||
unsigned char h[RANDOMX_HASH_SIZE];
|
||||
randomx_calculate_hash(vm, input.data(), input.size(), h);
|
||||
hdr.nSolution.assign(h, h + RANDOMX_HASH_SIZE);
|
||||
if (UintToArith256(hdr.GetHash()) <= tgt) {
|
||||
std::vector<unsigned char> en2(nonce.begin() + 8, nonce.end());
|
||||
std::string submit = strprintf(
|
||||
"{\"id\":4,\"method\":\"mining.submit\",\"params\":[\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"]}",
|
||||
addr, jobId, timeHex, HexStr(en2), HexStr(hdr.nSolution));
|
||||
StratumMinerSend(fd, submit);
|
||||
submitted = true;
|
||||
foundHash = hdr.GetHash().ToString();
|
||||
bool sawResult = false;
|
||||
for (int k = 0; k < 40 && !sawResult; k++) {
|
||||
std::vector<std::string> rl;
|
||||
if (!StratumMinerRecvLines(fd, buf, 250, rl)) break;
|
||||
for (const std::string& l : rl) {
|
||||
processLine(l);
|
||||
UniValue rv; if (!rv.read(l)) continue;
|
||||
const UniValue& rid = find_value(rv, "id");
|
||||
if (rid.isNum() && rid.get_int() == 4) {
|
||||
sawResult = true;
|
||||
const UniValue& r = find_value(rv, "result");
|
||||
accepted = r.isBool() ? r.get_bool() : find_value(rv, "error").isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
randomx_destroy_vm(vm);
|
||||
randomx_release_cache(cache);
|
||||
close(fd);
|
||||
|
||||
res.push_back(Pair("found", found));
|
||||
res.push_back(Pair("submitted", submitted));
|
||||
res.push_back(Pair("accepted", accepted));
|
||||
res.push_back(Pair("hashes", (uint64_t)hashes));
|
||||
res.push_back(Pair("seconds", (int64_t)(GetTime() - started)));
|
||||
if (!foundHash.empty()) res.push_back(Pair("hash", foundHash));
|
||||
return res;
|
||||
}
|
||||
#endif // !WIN32
|
||||
|
||||
static const CRPCCommand commands[] =
|
||||
{ // category name actor (function) okSafeMode
|
||||
// --------------------- ------------------------ ----------------------- ----------
|
||||
#ifndef WIN32
|
||||
{ "mining", "stratummine", &stratummine, true },
|
||||
#endif
|
||||
{ "mining", "getlocalsolps", &getlocalsolps, true },
|
||||
{ "mining", "getnetworksolps", &getnetworksolps, true },
|
||||
{ "mining", "getnetworkhashps", &getnetworkhashps, true },
|
||||
|
||||
127
src/rpc/misc.cpp
127
src/rpc/misc.cpp
@@ -78,106 +78,6 @@ extern int32_t ASSETCHAINS_SAPLING;
|
||||
extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[],ASSETCHAINS_NOTARY_PAY[];
|
||||
extern std::string NOTARY_PUBKEY,NOTARY_ADDRESS; extern uint8_t NOTARY_PUBKEY33[];
|
||||
|
||||
//TODO: use non-staked eras
|
||||
// Currently HUSH only uses block heights to define eras
|
||||
int32_t getera(int timestamp)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
UniValue getdragonjson(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
if (fHelp || params.size() != 0)
|
||||
throw runtime_error("getdragonjson\nreturns json for dragon, for the current ERA.");
|
||||
|
||||
UniValue json(UniValue::VOBJ);
|
||||
UniValue seeds(UniValue::VARR);
|
||||
UniValue notaries(UniValue::VARR);
|
||||
// get the current era, use local time for now.
|
||||
// should ideally take blocktime of last known block?
|
||||
int now = time(NULL);
|
||||
int32_t era = getera(now);
|
||||
|
||||
// loop over seeds array and push back to json array for seeds
|
||||
for (int8_t i = 0; i < 8; i++) {
|
||||
//seeds.push_back(dragonSeeds[i][0]);
|
||||
}
|
||||
|
||||
// get all current notaries
|
||||
for (int8_t i = 0; i < NUM_HUSH_NOTARIES; i++) {
|
||||
UniValue notary(UniValue::VOBJ);
|
||||
notary.push_back(notaries_list[era][i][0]);
|
||||
notaries.push_back(notary);
|
||||
}
|
||||
|
||||
// TODO: should be a config param
|
||||
int minsigs = 13;
|
||||
int BTCminsigs = 13;
|
||||
|
||||
int dragonPort = 5555;
|
||||
json.push_back(Pair("port",dragonPort));
|
||||
json.push_back(Pair("BTCminsigs",BTCminsigs));
|
||||
json.push_back(Pair("minsigs",minsigs));
|
||||
json.push_back(Pair("seeds",seeds));
|
||||
json.push_back(Pair("notaries",notaries));
|
||||
return json;
|
||||
}
|
||||
|
||||
UniValue getnotarysendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error(
|
||||
"getnotarysendmany\n"
|
||||
"Returns a sendmany JSON array with all current notaries Raddress's.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getnotarysendmany", "10")
|
||||
+ HelpExampleRpc("getnotarysendmany", "10")
|
||||
);
|
||||
int amount = 0;
|
||||
if ( params.size() == 1 ) {
|
||||
amount = params[0].get_int();
|
||||
}
|
||||
|
||||
//TODO: this is broke
|
||||
int era = getera(time(NULL));
|
||||
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
for (int i = 0; i<NUM_HUSH_NOTARIES; i++)
|
||||
{
|
||||
char Raddress[18]; uint8_t pubkey33[33];
|
||||
decode_hex(pubkey33,33,(char *)notaries_list[era][i][1]);
|
||||
pubkey2addr((char *)Raddress,(uint8_t *)pubkey33);
|
||||
ret.push_back(Pair(Raddress,amount));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniValue geterablockheights(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
if (fHelp || params.size() != 0)
|
||||
throw runtime_error(
|
||||
"geterablockheights\n"
|
||||
"Returns a JSON object with the first block in each era.\n"
|
||||
);
|
||||
|
||||
CBlockIndex *pindex; int8_t lastera,era = 0; UniValue ret(UniValue::VOBJ);
|
||||
|
||||
for (size_t i = 1; i < chainActive.LastTip()->GetHeight(); i++)
|
||||
{
|
||||
pindex = chainActive[i];
|
||||
era = getera(pindex->nTime)+1;
|
||||
if ( era > lastera )
|
||||
{
|
||||
char str[16];
|
||||
sprintf(str, "%d", era);
|
||||
ret.push_back(Pair(str,(int64_t)i));
|
||||
lastera = era;
|
||||
}
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
extern int getWorkQueueDepth();
|
||||
extern int getWorkQueueMaxDepth();
|
||||
extern int getWorkQueueNumThreads();
|
||||
@@ -202,7 +102,7 @@ UniValue rpcinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,longestchain,hushnotarized_height,txid_height;
|
||||
int32_t longestchain;
|
||||
if (fHelp || params.size() != 0)
|
||||
throw runtime_error(
|
||||
"getinfo\n"
|
||||
@@ -240,28 +140,13 @@ UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
proxyType proxy;
|
||||
GetProxy(NET_IPV4, proxy);
|
||||
notarized_height = hush_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid);
|
||||
//fprintf(stderr,"after notarized_height %u\n",(uint32_t)time(NULL));
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("version", CLIENT_VERSION));
|
||||
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
|
||||
obj.push_back(Pair("synced", HUSH_INSYNC!=0));
|
||||
obj.push_back(Pair("notarized", notarized_height));
|
||||
obj.push_back(Pair("prevMoMheight", prevMoMheight));
|
||||
obj.push_back(Pair("notarizedhash", notarized_hash.ToString()));
|
||||
obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString()));
|
||||
if ( HUSH_NSPV_FULLNODE )
|
||||
{
|
||||
txid_height = notarizedtxid_height( (char *)"HUSH3" ,(char *)notarized_desttxid.ToString().c_str(),&hushnotarized_height);
|
||||
if ( txid_height > 0 )
|
||||
obj.push_back(Pair("notarizedtxid_height", txid_height));
|
||||
else obj.push_back(Pair("notarizedtxid_height", "mempool"));
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 ) {
|
||||
obj.push_back(Pair("HUSHnotarized_height", hushnotarized_height));
|
||||
}
|
||||
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));
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain) {
|
||||
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
|
||||
@@ -348,14 +233,8 @@ UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
if ( ASSETCHAINS_COMMISSION != 0 )
|
||||
obj.push_back(Pair("commission", ASSETCHAINS_COMMISSION));
|
||||
if ( ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH ) {
|
||||
uint64_t N = ASSETCHAINS_NK[0] ? ASSETCHAINS_NK[0] : 200;
|
||||
uint64_t K = ASSETCHAINS_NK[1] ? ASSETCHAINS_NK[1] : 9;
|
||||
std::string equihash_algo = "equihash (" + std::to_string(N) + "," + std::to_string(K) + ")";
|
||||
obj.push_back(Pair("algo",equihash_algo));
|
||||
} else {
|
||||
obj.push_back(Pair("algo", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]));
|
||||
}
|
||||
// DragonX is RandomX-only; the Equihash (N,K) reporting path was removed.
|
||||
obj.push_back(Pair("algo", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ int32_t HUSH_LONGESTCHAIN;
|
||||
static int32_t hush_longest_depth = 0;
|
||||
int32_t hush_longestchain()
|
||||
{
|
||||
int32_t ht,n=0,num=0,maxheight=0,height = 0;
|
||||
int32_t ht,num=0,maxheight=0,height = 0;
|
||||
if ( hush_longest_depth < 0 )
|
||||
hush_longest_depth = 0;
|
||||
if ( hush_longest_depth == 0 )
|
||||
@@ -231,7 +231,6 @@ int32_t hush_longestchain()
|
||||
}
|
||||
BOOST_FOREACH(const CNodeStats& stats, vstats)
|
||||
{
|
||||
//fprintf(stderr,"hush_longestchain iter.%d\n",n);
|
||||
CNodeStateStats statestats;
|
||||
bool fStateStats = GetNodeStateStats(stats.nodeid,statestats);
|
||||
if ( statestats.nSyncHeight < 0 )
|
||||
@@ -251,10 +250,8 @@ int32_t hush_longestchain()
|
||||
height = ht;
|
||||
}
|
||||
hush_longest_depth--;
|
||||
if ( num > (n >> 1) )
|
||||
if ( num > 0 )
|
||||
{
|
||||
if ( 0 && height != HUSH_LONGESTCHAIN )
|
||||
fprintf(stderr,"set %s HUSH_LONGESTCHAIN <- %d\n",SMART_CHAIN_SYMBOL,height);
|
||||
HUSH_LONGESTCHAIN = height;
|
||||
return(height);
|
||||
}
|
||||
|
||||
@@ -1168,7 +1168,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp, const CPubKey& m
|
||||
numiters++;
|
||||
}
|
||||
if ( numiters > 0 )
|
||||
fprintf(stderr,"ASSETCHAINS_TXPOW.%d txpow.%d numiters.%d for signature\n",ASSETCHAINS_TXPOW,txpow,numiters);
|
||||
LogPrintf("ASSETCHAINS_TXPOW.%d txpow.%d numiters.%d for signature\n",ASSETCHAINS_TXPOW,txpow,numiters);
|
||||
bool fComplete = vErrors.empty();
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
|
||||
@@ -276,11 +276,7 @@ UniValue stop(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
// Shutdown will take long enough that the response should get back
|
||||
StartShutdown();
|
||||
|
||||
if ((strncmp(SMART_CHAIN_SYMBOL, "HUSH3", 5) == 0) ) {
|
||||
sprintf(buf,"Hush server stopping, for now...");
|
||||
} else {
|
||||
sprintf(buf,"%s server stopping...",SMART_CHAIN_SYMBOL);
|
||||
}
|
||||
sprintf(buf,"%s server stopping...",SMART_CHAIN_SYMBOL);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -292,9 +288,6 @@ static const CRPCCommand vRPCCommands[] =
|
||||
// --------------------- ------------------------ ----------------------- ----------
|
||||
/* Overall control/query calls */
|
||||
{ "control", "help", &help, true },
|
||||
{ "control", "getdragonjson", &getdragonjson, true },
|
||||
{ "control", "getnotarysendmany", &getnotarysendmany, true },
|
||||
{ "control", "geterablockheights", &geterablockheights, true },
|
||||
{ "control", "stop", &stop, true },
|
||||
|
||||
/* P2P networking */
|
||||
@@ -342,7 +335,6 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "crosschain", "calc_MoM", &calc_MoM, true },
|
||||
{ "crosschain", "height_MoM", &height_MoM, true },
|
||||
{ "crosschain", "assetchainproof", &assetchainproof, true },
|
||||
{ "crosschain", "crosschainproof", &crosschainproof, true },
|
||||
{ "crosschain", "getNotarizationsForBlock", &getNotarizationsForBlock, true },
|
||||
{ "crosschain", "scanNotarizationsDB", &scanNotarizationsDB, true },
|
||||
|
||||
@@ -666,7 +658,6 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms
|
||||
// while a very long wallet rescan is happening and do other read-only devopz
|
||||
if (pcmd->name != "stop" && pcmd->name != "help" && pcmd->name != "z_listaddresses" && pcmd->name != "z_exportkey" &&
|
||||
pcmd->name != "getNotarizationsForBlock" && pcmd->name != "scanNotarizationsDB" &&
|
||||
pcmd->name != "getnotarysendmany" && pcmd->name != "geterablockheights" &&
|
||||
pcmd->name != "getaddressesbyaccount" && pcmd->name != "listaddresses" && pcmd->name != "z_exportwallet" &&
|
||||
pcmd->name != "notaries" && pcmd->name != "signmessage" && pcmd->name != "decoderawtransaction" &&
|
||||
pcmd->name != "dumpprivkey" && pcmd->name != "getpeerinfo" && pcmd->name != "getnetworkinfo" &&
|
||||
@@ -695,11 +686,7 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms
|
||||
|
||||
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
|
||||
{
|
||||
if ((strncmp(SMART_CHAIN_SYMBOL, "HUSH3", 5) == 0) ) {
|
||||
return "> hush-cli " + methodname + " " + args + "\n";
|
||||
} else {
|
||||
return "> hush-cli -ac_name=" + strprintf("%s", SMART_CHAIN_SYMBOL) + " " + methodname + " " + args + "\n";
|
||||
}
|
||||
return "> dragonx-cli " + methodname + " " + args + "\n";
|
||||
}
|
||||
|
||||
std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
|
||||
|
||||
@@ -280,9 +280,6 @@ extern UniValue encryptwallet(const UniValue& params, bool fHelp, const CPubKey&
|
||||
extern UniValue validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue txnotarizedconfirmed(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue getdragonjson(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue getnotarysendmany(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue geterablockheights(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue setpubkey(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue getwalletinfo(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue getblockchaininfo(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
@@ -369,6 +366,7 @@ extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPub
|
||||
extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||
extern UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||
extern UniValue z_sweepstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||
extern UniValue z_autoshieldstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||
extern UniValue z_consolidationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||
extern UniValue z_shieldcoinbase(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||
extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||
@@ -382,7 +380,6 @@ extern UniValue MoMoMdata(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
extern UniValue calc_MoM(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue height_MoM(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue assetchainproof(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue crosschainproof(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue getNotarizationsForBlock(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue scanNotarizationsDB(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
extern UniValue getimports(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||
|
||||
182
src/stratum.cpp
182
src/stratum.cpp
@@ -16,6 +16,7 @@
|
||||
#include "httpserver.h"
|
||||
#include "miner.h"
|
||||
#include "netbase.h"
|
||||
#include "pow.h" // RandomX PoW: CheckRandomXSolution / GetRandomXKey / GetRandomXInput; and CheckEquihashSolution
|
||||
#include "net.h"
|
||||
#include "rpc/server.h"
|
||||
#include "serialize.h"
|
||||
@@ -637,9 +638,6 @@ void CustomizeWork(const StratumClient& client, const StratumWork& current_work,
|
||||
nonce.insert(nonce.end(), extranonce2.begin(), extranonce2.end());
|
||||
|
||||
// nonce = extranonce1 + extranonce2
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput) {
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " nonce = " << HexStr(nonce) << std::endl;
|
||||
// }
|
||||
|
||||
if (cb.vin.empty()) {
|
||||
const std::string msg = strprintf("%s: first transaction is missing coinbase input; unable to customize work to miner", __func__);
|
||||
@@ -666,6 +664,15 @@ void CustomizeWork(const StratumClient& client, const StratumWork& current_work,
|
||||
// cb_branch = current_work.m_cb_branch;
|
||||
}
|
||||
|
||||
// DragonX PoW is RandomX (32-byte solution); Equihash is legacy (1347-byte solution). The stratum
|
||||
// work and submit paths branch on this: RandomX hands the miner the per-height RandomX key (which it
|
||||
// cannot derive without the chain) and validates a 32-byte solution via CheckRandomXSolution();
|
||||
// Equihash keeps the legacy path (1347-byte solution + the 3-byte prefix + CheckEquihashSolution).
|
||||
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_RANDOMX; // hush_defs.h — active PoW algorithm selector
|
||||
extern int32_t HUSH_TESTNODE; // hush_globals.h — -testnode: relax IBD/sync guards for isolated test nodes
|
||||
static inline bool StratumIsRandomX() { return ASSETCHAINS_ALGO == ASSETCHAINS_RANDOMX; }
|
||||
static const size_t RX_STRATUM_SOLUTION_SIZE = 32; // == RANDOMX_HASH_SIZE (kept local to avoid pulling randomx.h into stratum)
|
||||
|
||||
std::string GetWorkUnit(StratumClient& client)
|
||||
{
|
||||
// LOCK(cs_main);
|
||||
@@ -675,7 +682,7 @@ std::string GetWorkUnit(StratumClient& client)
|
||||
} */
|
||||
|
||||
/* if (!Params().MineBlocksOnDemand() && g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) {
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Hush is not connected!");
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "DragonX is not connected!");
|
||||
} */
|
||||
|
||||
bool fvNodesEmpty;
|
||||
@@ -686,21 +693,21 @@ std::string GetWorkUnit(StratumClient& client)
|
||||
|
||||
if (Params().MiningRequiresPeers() && fvNodesEmpty)
|
||||
{
|
||||
const std::string msg = strprintf("%s: Unable to get work unit, Hush is not connected!", __func__);
|
||||
const std::string msg = strprintf("%s: Unable to get work unit, DragonX is not connected!", __func__);
|
||||
LogPrint("stratum", "%s\n", msg);
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Hush is not connected!");
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "DragonX is not connected!");
|
||||
}
|
||||
|
||||
if (IsInitialBlockDownload()) {
|
||||
const std::string msg = strprintf("%s: Unable to get work unit, Hush is still downloading blocks!", __func__);
|
||||
if (IsInitialBlockDownload() && HUSH_TESTNODE == 0) {
|
||||
const std::string msg = strprintf("%s: Unable to get work unit, DragonX is still downloading blocks!", __func__);
|
||||
LogPrint("stratum", "%s\n", msg);
|
||||
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Hush is downloading blocks...");
|
||||
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "DragonX is downloading blocks...");
|
||||
}
|
||||
|
||||
if (!client.m_authorized && client.m_aux_addr.empty()) {
|
||||
const std::string msg = strprintf("%s: Unable to get work unit, client not authorized! Use address 'x' to mine to the default address", __func__);
|
||||
LogPrint("stratum", "%s\n", msg);
|
||||
throw JSONRPCError(RPC_INVALID_REQUEST, "Stratum client not authorized. Use mining.authorize first, with a Hush R.. address as the username or 'x' to mine to the default address.");
|
||||
throw JSONRPCError(RPC_INVALID_REQUEST, "Stratum client not authorized. Use mining.authorize first, with a DragonX R.. address as the username or 'x' to mine to the default address.");
|
||||
}
|
||||
|
||||
static CBlockIndex* tip = NULL; // pindexPrev
|
||||
@@ -737,18 +744,18 @@ std::string GetWorkUnit(StratumClient& client)
|
||||
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
|
||||
}
|
||||
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput) std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << "hashMerkleRoot = " << new_work->block.hashMerkleRoot.ToString() << std::endl;
|
||||
|
||||
// So that block.GetHash() is correct
|
||||
//new_work->block.hashMerkleRoot = BlockMerkleRoot(new_work->block);
|
||||
new_work->block.hashMerkleRoot = new_work->block.BuildMerkleTree();
|
||||
|
||||
// NB! here we have merkle with scriptDummy script in coinbase, after CustomizeWork we should recalculate it (!)
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput) std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << "hashMerkleRoot = " << new_work->block.hashMerkleRoot.ToString() << std::endl;
|
||||
|
||||
job_id = new_work->block.GetHash();
|
||||
//work_templates[job_id] = StratumWork(*new_work, new_work->block.vtx[0]->HasWitness());
|
||||
work_templates[job_id] = StratumWork(*new_work, false);
|
||||
// Height of the block being mined — used for RandomX key derivation (GetRandomXKey) and
|
||||
// CheckRandomXSolution/CheckProofOfWork on submit. Previously left 0 (Equihash didn't need it).
|
||||
work_templates[job_id].nHeight = tip_new->GetHeight() + 1;
|
||||
|
||||
tip = tip_new;
|
||||
|
||||
@@ -851,12 +858,6 @@ std::string GetWorkUnit(StratumClient& client)
|
||||
CMutableTransaction cb, bf;
|
||||
std::vector<uint256> cb_branch;
|
||||
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput)
|
||||
// {
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " [1] cb = " << CTransaction(cb).ToString() << std::endl;
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " [1] current_work.GetBlock().vtx[0] = " << current_work.GetBlock().vtx[0].ToString() << std::endl;
|
||||
// }
|
||||
|
||||
{
|
||||
std::vector<unsigned char> extranonce1 = client.ExtraNonce1(job_id);
|
||||
|
||||
@@ -873,12 +874,6 @@ std::string GetWorkUnit(StratumClient& client)
|
||||
|
||||
}
|
||||
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput)
|
||||
// {
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " [2] cb = " << CTransaction(cb).ToString() << std::endl;
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " [2] current_work.GetBlock().vtx[0] = " << current_work.GetBlock().vtx[0].ToString() << std::endl;
|
||||
// }
|
||||
|
||||
CBlockHeader blkhdr;
|
||||
// Setup native proof-of-work
|
||||
|
||||
@@ -934,7 +929,25 @@ std::string GetWorkUnit(StratumClient& client)
|
||||
mining_notify.push_back(Pair("method", "mining.notify"));
|
||||
mining_notify.push_back(Pair("params", params));
|
||||
|
||||
// RandomX: the miner cannot derive the per-height RandomX key on its own (it depends on a block
|
||||
// hash deep in the chain), so hand it the key bytes + height explicitly. Sent as its own
|
||||
// mining.set_randomx_key message so the equihash-format mining.notify above stays byte-compatible
|
||||
// with legacy miners; a RandomX miner reads this before hashing.
|
||||
std::string randomx_key_msg;
|
||||
if (StratumIsRandomX()) {
|
||||
const std::string rxKey = GetRandomXKey(current_work.nHeight);
|
||||
UniValue set_rxkey(UniValue::VOBJ);
|
||||
set_rxkey.push_back(Pair("id", client.m_nextid++));
|
||||
set_rxkey.push_back(Pair("method", "mining.set_randomx_key"));
|
||||
UniValue rxparams(UniValue::VARR);
|
||||
rxparams.push_back(HexStr(rxKey.begin(), rxKey.end())); // RandomX key bytes (hex)
|
||||
rxparams.push_back(current_work.nHeight); // block height (sanity/logging)
|
||||
set_rxkey.push_back(Pair("params", rxparams));
|
||||
randomx_key_msg = set_rxkey.write() + "\n";
|
||||
}
|
||||
|
||||
return GetExtraNonceRequest(client, job_id)
|
||||
+ randomx_key_msg
|
||||
+ set_target.write() + "\n"
|
||||
+ mining_notify.write() + "\n";
|
||||
}
|
||||
@@ -942,8 +955,15 @@ bool SubmitBlock(StratumClient& client, const uint256& job_id, const StratumWork
|
||||
const std::vector<unsigned char>& extranonce1, const std::vector<unsigned char>& extranonce2,
|
||||
boost::optional<uint32_t> nVersion, uint32_t nTime, const std::vector<unsigned char>& sol)
|
||||
{
|
||||
// Submit path handles BOTH proof-of-works, branched on StratumIsRandomX():
|
||||
// * RandomX (DragonX): `sol` is the 32-byte RandomX hash and IS nSolution verbatim; validated
|
||||
// via CheckRandomXSolution(&blkhdr, height). The target check (GetHash() < target) and the
|
||||
// nNonce = extranonce1||extranonce2 assembly are identical to the equihash path.
|
||||
// * Equihash (legacy): `sol` is the 1347-byte solution; the 3-byte zcash prefix is stripped
|
||||
// and CheckEquihashSolution() validates it.
|
||||
//
|
||||
// called from stratum_mining_submit and uses following data, came from client:
|
||||
// ["WORKER_NAME", "JOB_ID", "TIME", "NONCE_2", "EQUIHASH_SOLUTION"]
|
||||
// ["WORKER_NAME", "JOB_ID", "TIME", "NONCE_2", "SOLUTION"]
|
||||
// all other params we have saved in other places
|
||||
|
||||
if (extranonce1.size() + extranonce2.size() != 32) {
|
||||
@@ -952,9 +972,9 @@ bool SubmitBlock(StratumClient& client, const uint256& job_id, const StratumWork
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, msg);
|
||||
}
|
||||
|
||||
// TODO: change hardcoded constants on actual determine of solution size, depends on equihash algo type: 200.9, etc.
|
||||
if (sol.size() != 1347) {
|
||||
std::string msg = strprintf("%s: solution is wrong length (received %d bytes; expected %d bytes", __func__, extranonce2.size(), 1347);
|
||||
const size_t expected_sol_size = StratumIsRandomX() ? RX_STRATUM_SOLUTION_SIZE : 1347;
|
||||
if (sol.size() != expected_sol_size) {
|
||||
std::string msg = strprintf("%s: solution is wrong length (received %d bytes; expected %d bytes)", __func__, sol.size(), (int)expected_sol_size);
|
||||
LogPrint("stratum", "%s\n", msg);
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, msg);
|
||||
}
|
||||
@@ -986,24 +1006,27 @@ bool SubmitBlock(StratumClient& client, const uint256& job_id, const StratumWork
|
||||
std::vector<unsigned char> nonce(extranonce1);
|
||||
nonce.insert(nonce.end(), extranonce2.begin(), extranonce2.end());
|
||||
|
||||
blkhdr.nSolution = std::vector<unsigned char>(sol.begin() + 3, sol.end());
|
||||
// RandomX: nSolution IS the 32-byte RandomX hash (verbatim). Equihash: strip the 3-byte
|
||||
// zcash solution-size prefix.
|
||||
blkhdr.nSolution = StratumIsRandomX() ? sol
|
||||
: std::vector<unsigned char>(sol.begin() + 3, sol.end());
|
||||
|
||||
blkhdr.hashFinalSaplingRoot = current_work.GetBlock().hashFinalSaplingRoot;
|
||||
blkhdr.hashMerkleRoot = current_work.GetBlock().hashMerkleRoot;
|
||||
blkhdr.nNonce = (uint256) nonce;
|
||||
|
||||
// example how to display constructed block
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput) {
|
||||
// CBlockIndex index {blkhdr};
|
||||
// index.SetHeight(current_work.nHeight);
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " blkhdr.hashPrevBlock = " << blkhdr.hashPrevBlock.GetHex() << std::endl;
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " blkhdr = " << blockToJSON(blkhdr, &index).write() << std::endl;
|
||||
// }
|
||||
|
||||
// block is constructed, now it's time to VerifyEH
|
||||
|
||||
if (instance_of_cstratumparams.fCheckEquihashSolution && !CheckEquihashSolution(&blkhdr, Params()))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid equihash solution");
|
||||
if (StratumIsRandomX()) {
|
||||
// Verify the submitted 32-byte solution really is the RandomX hash of this header
|
||||
// (nSolution == randomx_hash(GetRandomXInput(blkhdr), GetRandomXKey(height))). This is the
|
||||
// consensus authority for the solution; without it a miner could submit a low-GetHash()
|
||||
// block with a bogus nSolution. Rejects fake shares before we count/relay them.
|
||||
if (!CheckRandomXSolution(&blkhdr, current_work.nHeight))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid RandomX solution");
|
||||
} else if (instance_of_cstratumparams.fCheckEquihashSolution && !CheckEquihashSolution(&blkhdr, Params())) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid equihash solution");
|
||||
}
|
||||
|
||||
arith_uint256 bnTarget; bool fNegative, fOverflow;
|
||||
bnTarget.SetCompact(blkhdr.nBits, &fNegative, &fOverflow);
|
||||
@@ -1018,7 +1041,6 @@ bool SubmitBlock(StratumClient& client, const uint256& job_id, const StratumWork
|
||||
uint8_t pubkey33[33]; int32_t height = current_work.nHeight;
|
||||
res = CheckProofOfWork(blkhdr, pubkey33, height, Params().GetConsensus());
|
||||
}
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput) std::cerr << DateTimeStrPrecise() << "res[1] = " << res << std::endl;
|
||||
|
||||
uint256 hash = blkhdr.GetHash();
|
||||
|
||||
@@ -1061,27 +1083,8 @@ bool SubmitBlock(StratumClient& client, const uint256& job_id, const StratumWork
|
||||
shares_accepted_since_last = counter_TotalShares - counter_prev;
|
||||
start = finish;
|
||||
counter_prev = counter_TotalShares;
|
||||
// std::cerr << strprintf("%f ms - %" PRIu64 "", elapsed.count(), shares_accepted_since_last) << std::endl;
|
||||
}
|
||||
|
||||
bool fDisplayDiffHUSH = true; // otherwise it will display ccminer diff
|
||||
|
||||
std::cerr << DateTimeStrPrecise() <<
|
||||
strprintf("%saccepted: %" PRIu64 "/%" PRIu64 "%s ", ColorTypeNames[cl_WHT], counter_TotalBlocks, counter_TotalShares, ColorTypeNames[cl_N] );
|
||||
if (fDisplayDiffHUSH) {
|
||||
/* hushd diff display */
|
||||
std::cerr << strprintf("%slocal %g%s ", "\x1B[90m", hush_local_diff, ColorTypeNames[cl_N]) <<
|
||||
strprintf("%s(diff %g, target %g) %s ", ColorTypeNames[cl_WHT], hush_real_diff, hush_target_diff, ColorTypeNames[cl_N]);
|
||||
} else { /* ccminer diff display */
|
||||
std::cerr << strprintf("%slocal %.3f%s ", "\x1B[90m", ccminer_local_diff, ColorTypeNames[cl_N]) <<
|
||||
strprintf("%s(diff %.3f, target %.3f) %s", ColorTypeNames[cl_WHT], ccminer_real_diff, ccminer_target_diff, ColorTypeNames[cl_N]); // ccminer diff
|
||||
}
|
||||
|
||||
std::cerr << "" <<
|
||||
strprintf("%f ms ", elapsed.count()) << // 1 share took elapsed ms
|
||||
strprintf("%s%s%s ", ColorTypeNames[cl_LGR], (res ? "yay!!!": "yes!"), ColorTypeNames[cl_N]) <<
|
||||
std::endl;
|
||||
|
||||
// (diff %g, target %g), %
|
||||
if (res) {
|
||||
|
||||
@@ -1097,22 +1100,14 @@ bool SubmitBlock(StratumClient& client, const uint256& job_id, const StratumWork
|
||||
block.nVersion = version;
|
||||
// block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
block.hashMerkleRoot = block.BuildMerkleTree();
|
||||
//if (instance_of_cstratumparams.fstdErrDebugOutput) std::cerr << "hashMerkleRoot = " << block.hashMerkleRoot.GetHex() << std::endl;
|
||||
|
||||
block.nTime = nTime;
|
||||
// block.nNonce = nNonce;
|
||||
// nNonce <<= 32; nNonce >>= 16; // clear the top and bottom 16 bits (for local use as thread flags and counters)
|
||||
|
||||
block.nNonce = (uint256) nonce;
|
||||
block.nSolution = std::vector<unsigned char>(sol.begin() + 3, sol.end());
|
||||
|
||||
// example how to pre-check the equihash solution
|
||||
// if(instance_of_cstratumparams.fstdErrDebugOutput) {
|
||||
// CBlockIndex index {blkhdr};
|
||||
// index.SetHeight(-1);
|
||||
// std::cerr << "block = " << blockToJSON(block, &index, true).write(1) << std::endl;
|
||||
// std::cerr << "CheckEquihashSolution = " << CheckEquihashSolution(&block, Params()) << std::endl;
|
||||
// }
|
||||
block.nSolution = StratumIsRandomX() ? sol
|
||||
: std::vector<unsigned char>(sol.begin() + 3, sol.end());
|
||||
|
||||
// std::shared_ptr<const CBlock> pblock = std::make_shared<const CBlock>(block);
|
||||
// res = ProcessNewBlock(Params(), pblock, true, NULL);
|
||||
@@ -1120,8 +1115,6 @@ bool SubmitBlock(StratumClient& client, const uint256& job_id, const StratumWork
|
||||
CValidationState state;
|
||||
res = ProcessNewBlock(0,0,state, NULL, &block, true /* forceProcessing */ , NULL);
|
||||
|
||||
//if (instance_of_cstratumparams.fstdErrDebugOutput) std::cerr << DateTimeStrPrecise() << "res[2] = " << res << std::endl;
|
||||
|
||||
// we haven't PreciousBlock, so we can't prioritize the block this way for now
|
||||
/*
|
||||
if (res) {
|
||||
@@ -1207,14 +1200,6 @@ UniValue stratum_mining_subscribe(StratumClient& client, const UniValue& params)
|
||||
* sExtraNonce1 for a given client based on m_secret.
|
||||
*/
|
||||
|
||||
// if (instance_of_cstratumparams.fstdErrDebugOutput && vExtraNonce1.size() > 3) {
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " " << strprintf("client.m_supports_extranonce = %d, [%d, %d, %d, %d], %s", client.m_supports_extranonce, vExtraNonce1[0], vExtraNonce1[1], vExtraNonce1[2], vExtraNonce1[3], sExtraNonce1) << std::endl;
|
||||
// // recalc from client.m_secret example
|
||||
// uint256 sha256;
|
||||
// CSHA256().Write(client.m_secret.begin(), 32).Finalize(sha256.begin());
|
||||
// std::cerr << __func__ << ": " << __FILE__ << "," << __LINE__ << " " << HexStr(std::vector<unsigned char>(sha256.begin(), sha256.begin() + 4)) << std::endl;
|
||||
// }
|
||||
|
||||
ret.push_back(NullUniValue);
|
||||
ret.push_back(sExtraNonce1);
|
||||
|
||||
@@ -1261,7 +1246,7 @@ UniValue stratum_mining_authorize(StratumClient& client, const UniValue& params)
|
||||
// This means a miner can run a private pool without TLS and not
|
||||
// worry about MITM attacks that change addresses, and leaks less metadata.
|
||||
// It also means many miners can be used and updating their mining address does not
|
||||
// require any changes on each miner, just restart hushd with a new -stratumaddress
|
||||
// require any changes on each miner, just restart dragonxd with a new -stratumaddress
|
||||
if(addr.ToString() == "x") {
|
||||
addr = CBitcoinAddress(GetArg("-stratumaddress", ""));
|
||||
const std::string msg = strprintf("%s: Authorized client with default stratum address=%s", __func__, addr.ToString());
|
||||
@@ -1269,9 +1254,9 @@ UniValue stratum_mining_authorize(StratumClient& client, const UniValue& params)
|
||||
}
|
||||
|
||||
if (!addr.IsValid()) {
|
||||
const std::string msg = strprintf("%s: Invalid Hush address=%s", __func__, addr.ToString());
|
||||
const std::string msg = strprintf("%s: Invalid DragonX address=%s", __func__, addr.ToString());
|
||||
LogPrint("stratum", "%s\n", msg);
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid Hush address: %s", username));
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid DragonX address: %s", username));
|
||||
}
|
||||
|
||||
client.m_addr = addr;
|
||||
@@ -1315,7 +1300,11 @@ UniValue stratum_mining_configure(StratumClient& client, const UniValue& params)
|
||||
|
||||
UniValue stratum_mining_submit(StratumClient& client, const UniValue& params)
|
||||
{
|
||||
// {"id": 4, "method": "mining.submit", "params": ["WORKER_NAME", "JOB_ID", "TIME", "NONCE_2", "EQUIHASH_SOLUTION"]}\n
|
||||
// Share submission. On RandomX (DragonX) the SOLUTION param is the 32-byte RandomX hash; on
|
||||
// Equihash (legacy) it is the 1347-byte solution. The size is validated below and the branch is
|
||||
// handled in SubmitBlock(). NONCE_2 is the miner-chosen tail of the 32-byte block nNonce.
|
||||
//
|
||||
// {"id": 4, "method": "mining.submit", "params": ["WORKER_NAME", "JOB_ID", "TIME", "NONCE_2", "SOLUTION"]}\n
|
||||
|
||||
// NONCE_1 is first part of the block header nonce (in hex).
|
||||
// By protocol, Zcash's nonce is 32 bytes long. The miner will pick NONCE_2 such that len(NONCE_2) = 32 - len(NONCE_1). Please note that Stratum use hex encoding, so you have to convert NONCE_1 from hex to binary before.
|
||||
@@ -1340,10 +1329,8 @@ UniValue stratum_mining_submit(StratumClient& client, const UniValue& params)
|
||||
bool fEWBFJobIDFixNeeded = false;
|
||||
uint256 ret;
|
||||
if (params[1].isStr()) {
|
||||
//std::cerr << "\"" << params[1].get_str() << "\"" << std::endl;
|
||||
const std::string job_id_str = params[1].get_str();
|
||||
const std::string hexDigits = "0123456789abcdef";
|
||||
// std::cerr << strprintf("\"%s\" (%d)", job_id_str, job_id_str.length()) << std::endl;
|
||||
if (job_id_str.length() == 63) {
|
||||
fEWBFJobIDFixNeeded = true;
|
||||
for(const auto& hexDigit : hexDigits) {
|
||||
@@ -1370,8 +1357,9 @@ UniValue stratum_mining_submit(StratumClient& client, const UniValue& params)
|
||||
uint32_t nTime = bswap_32(ParseHexInt4(params[2], "nTime"));
|
||||
|
||||
std::vector<unsigned char> sol = ParseHexV(params[4], "solution");
|
||||
if (sol.size() != 1347) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("solution is wrong length (received %d bytes; expected %d bytes", sol.size(), 1347));
|
||||
const size_t expected_sol_size = StratumIsRandomX() ? RX_STRATUM_SOLUTION_SIZE : 1347;
|
||||
if (sol.size() != expected_sol_size) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("solution is wrong length (received %d bytes; expected %d bytes)", sol.size(), (int)expected_sol_size));
|
||||
}
|
||||
|
||||
std::vector<unsigned char> extranonce1 = client.ExtraNonce1(job_id);
|
||||
@@ -1816,7 +1804,7 @@ void SendKeepAlivePackets()
|
||||
if ( (client.m_last_tip && client.m_last_tip->GetHeight() == chainActive.Tip()->GetHeight()) || (!client.m_last_tip) )
|
||||
{
|
||||
LOCK(cs_stratum);
|
||||
std::cerr << DateTimeStrPrecise() << "\033[31m" << client.m_from.ToString() << "\033[0m seems stucked (ccminer issue), need to emulate new block incoming to unstuck!" << std::endl;
|
||||
LogPrint("stratum", "%s seems stucked (ccminer issue), need to emulate new block incoming to unstuck!\n", client.m_from.ToString());
|
||||
mempool.AddTransactionsUpdated(1);
|
||||
client.m_last_tip = (client.m_last_tip ? nullptr : chainActive.Tip());
|
||||
client.m_nextid++;
|
||||
@@ -1829,15 +1817,25 @@ void SendKeepAlivePackets()
|
||||
|
||||
}
|
||||
|
||||
/** Configure the Hush stratum server */
|
||||
/** Configure the DragonX stratum server */
|
||||
bool InitStratumServer()
|
||||
{
|
||||
LOCK(cs_stratum);
|
||||
|
||||
int stratumPort = BaseParams().StratumPort();
|
||||
int defaultPort = GetArg("-stratumport", stratumPort);
|
||||
fprintf(stderr,"%s: Starting built-in stratum server on port %d\n",__func__, defaultPort );
|
||||
LogPrintf("%s: Starting built-in stratum server on port %d\n",__func__, defaultPort );
|
||||
|
||||
// Optional pool share-target override (64-hex, big-endian like getblocktemplate's "target").
|
||||
// Loosens/tightens the accepted share difficulty; also lets a solo/test miner accept easy shares
|
||||
// on a low-difficulty chain (default is the diff-1 target 00ffff00..). Larger value = easier.
|
||||
if (mapArgs.count("-stratumtarget")) {
|
||||
const std::string t = GetArg("-stratumtarget", "");
|
||||
if (!t.empty()) {
|
||||
instance_of_cstratumparams.setTarget(arith_uint256(t));
|
||||
LogPrintf("%s: stratum pool share target overridden to %s\n", __func__, t);
|
||||
}
|
||||
}
|
||||
|
||||
if (!InitStratumAllowList(stratum_allow_subnets)) {
|
||||
LogPrint("stratum", "Unable to bind stratum server to an endpoint.\n");
|
||||
@@ -1959,7 +1957,7 @@ UniValue rpc_stratum_updatework(const UniValue& params, bool fHelp, const CPubKe
|
||||
|
||||
// Ignore clients that aren't authorized yet.
|
||||
if (!client.m_authorized && client.m_aux_addr.empty()) {
|
||||
fprintf(stderr,"%s: Ignoring unauthorized client\n", __func__);
|
||||
LogPrint("stratum", "%s: Ignoring unauthorized client\n", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
31
src/txdb.cpp
31
src/txdb.cpp
@@ -285,8 +285,9 @@ bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockF
|
||||
std::pair<char, uint256> key = make_pair(DB_BLOCK_INDEX, it->GetBlockHash());
|
||||
try {
|
||||
CDiskBlockIndex dbindex {it, [this, &key]() {
|
||||
// It can happen that the index entry is written, then the Equihash solution is cleared from memory,
|
||||
// It can happen that the index entry is written, then the solution is cleared from memory,
|
||||
// then the index entry is rewritten. In that case we must read the solution from the old entry.
|
||||
// (GetSolution() returns DragonX's RandomX solution.)
|
||||
CDiskBlockIndex dbindex_old;
|
||||
if (!Read(key, dbindex_old)) {
|
||||
LogPrintf("%s: Failed to read index entry", __func__);
|
||||
@@ -472,7 +473,6 @@ bool CBlockTreeDB::Snapshot2(std::map <std::string, CAmount> &addressAmounts, Un
|
||||
iter->GetKey(keyObj);
|
||||
char chType = keyObj.first;
|
||||
CAddressIndexIteratorKey indexKey = keyObj.second;
|
||||
//fprintf(stderr, "chType=%d\n", chType);
|
||||
if (chType == DB_ADDRESSUNSPENTINDEX)
|
||||
{
|
||||
try {
|
||||
@@ -485,7 +485,7 @@ bool CBlockTreeDB::Snapshot2(std::map <std::string, CAmount> &addressAmounts, Un
|
||||
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
|
||||
if (ignored != ignoredMap.end())
|
||||
{
|
||||
fprintf(stderr,"ignoring %s\n", address.c_str());
|
||||
LogPrint("coindb", "ignoring %s\n", address.c_str());
|
||||
ignoredAddresses++;
|
||||
continue;
|
||||
}
|
||||
@@ -493,17 +493,14 @@ bool CBlockTreeDB::Snapshot2(std::map <std::string, CAmount> &addressAmounts, Un
|
||||
if ( pos == addressAmounts.end() )
|
||||
{
|
||||
// insert new address + utxo amount
|
||||
//fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] = nValue;
|
||||
totalAddresses++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update unspent tally for this address
|
||||
//fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] += nValue;
|
||||
}
|
||||
//fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
|
||||
// total += nValue;
|
||||
utxos++;
|
||||
total += nValue;
|
||||
@@ -517,12 +514,17 @@ bool CBlockTreeDB::Snapshot2(std::map <std::string, CAmount> &addressAmounts, Un
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
fprintf(stderr, "DONE reading index entries\n");
|
||||
break;
|
||||
// A genuine deserialization/LevelDB error here is NOT normal completion:
|
||||
// the for-loop's iter->Valid() already handles end-of-iteration, and
|
||||
// non-address key types are skipped by the chType check above. Swallowing
|
||||
// the exception and building a snapshot from partial data is wrong. Fail
|
||||
// like the inner catch, which the author marked consensus-relevant
|
||||
// ("we need to exit here if so for consensus code!").
|
||||
fprintf(stderr, "%s: LevelDB index iteration exception! - %s\n", __func__, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses);
|
||||
|
||||
|
||||
// this is for the snapshot RPC, you can skip this by passing a 0 as the last argument.
|
||||
if (ret)
|
||||
{
|
||||
@@ -675,23 +677,18 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
|
||||
|
||||
pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));
|
||||
//fprintf(stderr,"%s: Seeked cursor to block index\n",__FUNCTION__);
|
||||
|
||||
// Load mapBlockIndex
|
||||
while (pcursor->Valid()) {
|
||||
//fprintf(stderr,"%s: Valid cursor\n",__FUNCTION__);
|
||||
boost::this_thread::interruption_point();
|
||||
std::pair<char, uint256> key;
|
||||
if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
|
||||
//fprintf(stderr,"%s: Found DB_BLOCK_INDEX\n",__FUNCTION__);
|
||||
CDiskBlockIndex diskindex;
|
||||
if (pcursor->GetValue(diskindex)) {
|
||||
// Construct block index object
|
||||
//fprintf(stderr,"%s: Creating CBlockIndex...\n",__FUNCTION__);
|
||||
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
|
||||
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
|
||||
pindexNew->SetHeight(diskindex.GetHeight());
|
||||
//fprintf(stderr,"%s: Setting CBlockIndex height...\n",__FUNCTION__);
|
||||
pindexNew->nFile = diskindex.nFile;
|
||||
pindexNew->nDataPos = diskindex.nDataPos;
|
||||
pindexNew->nUndoPos = diskindex.nUndoPos;
|
||||
@@ -702,14 +699,13 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||
pindexNew->nTime = diskindex.nTime;
|
||||
pindexNew->nBits = diskindex.nBits;
|
||||
pindexNew->nNonce = diskindex.nNonce;
|
||||
// the Equihash solution will be loaded lazily from the dbindex entry
|
||||
// the solution (DragonX RandomX solution) will be loaded lazily from the dbindex entry
|
||||
// pindexNew->nSolution = diskindex.nSolution;
|
||||
pindexNew->nStatus = diskindex.nStatus;
|
||||
pindexNew->nCachedBranchId = diskindex.nCachedBranchId;
|
||||
pindexNew->nTx = diskindex.nTx;
|
||||
pindexNew->nSproutValue = diskindex.nSproutValue;
|
||||
pindexNew->nSaplingValue = diskindex.nSaplingValue;
|
||||
//fprintf(stderr,"%s: Setting CBlockIndex details...\n",__FUNCTION__);
|
||||
pindexNew->segid = diskindex.segid;
|
||||
pindexNew->nNotaryPay = diskindex.nNotaryPay;
|
||||
pindexNew->nPayments = diskindex.nPayments;
|
||||
@@ -725,7 +721,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||
pindexNew->nFullyShieldedPayments = diskindex.nFullyShieldedPayments;
|
||||
pindexNew->nNotarizations = diskindex.nNotarizations;
|
||||
|
||||
//fprintf(stderr,"loadguts ht.%d\n",pindexNew->GetHeight());
|
||||
// Consistency checks
|
||||
/*
|
||||
CBlockHeader header;
|
||||
|
||||
50
src/util.cpp
50
src/util.cpp
@@ -499,27 +499,35 @@ boost::filesystem::path GetDefaultDataDir()
|
||||
if ( SMART_CHAIN_SYMBOL[0] != 0 )
|
||||
strcpy(symbol,SMART_CHAIN_SYMBOL);
|
||||
else symbol[0] = 0;
|
||||
// OLD NAMES:
|
||||
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Komodo
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Komodo
|
||||
// Mac: ~/Library/Application Support/Komodo
|
||||
// Unix: ~/.komodo
|
||||
// DragonX stores its data under a per-chain subdirectory named after
|
||||
// SMART_CHAIN_SYMBOL (which is "DRAGONX"), so the default datadir resolves
|
||||
// to (Unix) ~/.hush/DRAGONX, (Mac) ~/Library/Application Support/Hush/DRAGONX,
|
||||
// or (Windows) %APPDATA%\Hush\DRAGONX.
|
||||
//
|
||||
// The "Hush" / "Komodo" parent-directory names below are retained from the
|
||||
// Hush/Komodo lineage: the ".hush"/"Hush" path is the current location, and
|
||||
// the ".komodo"/"Komodo" path is only probed as a backward-compatible
|
||||
// fallback for pre-existing legacy data directories. Do not change these
|
||||
// string literals -- they determine where node data is read from and written.
|
||||
|
||||
// NEW NAMES:
|
||||
// Current (per-symbol subdirectory lives under these parents):
|
||||
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Hush
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Hush
|
||||
// Mac: ~/Library/Application Support/Hush
|
||||
// Unix: ~/.hush
|
||||
|
||||
// ~/.hush was actually used by the original 1.x version of Hush, but we will
|
||||
// only make subdirectories inside of it, so we won't be able to overwrite
|
||||
// an old wallet.dat from the Ice Ages :)
|
||||
// Legacy fallback (only used if such a directory already exists):
|
||||
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Komodo
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Komodo
|
||||
// Mac: ~/Library/Application Support/Komodo
|
||||
// Unix: ~/.komodo
|
||||
|
||||
fs::path pathRet;
|
||||
#ifdef _WIN32
|
||||
// Windows
|
||||
pathRet = GetSpecialFolderPath(CSIDL_APPDATA) / "Hush" / symbol;
|
||||
// Always use .hush/HUSH3, if it exists (even if .komodo/HUSH3 exists)
|
||||
// Always use Hush\<symbol> (Hush\DRAGONX) if it exists, even if the legacy
|
||||
// Komodo\<symbol> directory also exists.
|
||||
if(fs::is_directory(pathRet)) {
|
||||
return pathRet;
|
||||
} else {
|
||||
@@ -528,7 +536,7 @@ boost::filesystem::path GetDefaultDataDir()
|
||||
// existing legacy directory, use that for backward compat
|
||||
return pathRet;
|
||||
} else {
|
||||
// For new clones, use Hush/ACNAME
|
||||
// For new nodes, use Hush\<symbol>
|
||||
pathRet = GetSpecialFolderPath(CSIDL_APPDATA) / "Hush" / symbol;
|
||||
return pathRet;
|
||||
}
|
||||
@@ -551,7 +559,7 @@ boost::filesystem::path GetDefaultDataDir()
|
||||
// create Library/Application Support/Hush if it doesn't exist
|
||||
TryCreateDirectory(tmppath);
|
||||
|
||||
// Always use Hush/HUSH3 if it exists
|
||||
// Always use Hush/<symbol> (Hush/DRAGONX) if it exists
|
||||
if(fs::is_directory(tmppath / symbol)) {
|
||||
return tmppath / symbol;
|
||||
} else {
|
||||
@@ -563,16 +571,16 @@ boost::filesystem::path GetDefaultDataDir()
|
||||
// Found legacy dir, use that
|
||||
return tmppath / symbol;
|
||||
} else {
|
||||
// For new clones, use Hush/ACNAME
|
||||
// For new nodes, use Hush/<symbol>
|
||||
tmppath = pathRet / "Hush" / symbol;
|
||||
}
|
||||
return tmppath;
|
||||
}
|
||||
#else
|
||||
// Unix
|
||||
// New directory :)
|
||||
// Unix: current default datadir is ~/.hush/<symbol> (i.e. ~/.hush/DRAGONX)
|
||||
fs::path tmppath = pathRet / ".hush" / symbol;
|
||||
// Always use .hush/HUSH3, if it exists (even if .komodo/HUSH3 exists)
|
||||
// Always use ~/.hush/<symbol> (~/.hush/DRAGONX) if it exists, even if the
|
||||
// legacy ~/.komodo/<symbol> directory also exists.
|
||||
if(fs::is_directory(tmppath)) {
|
||||
return tmppath;
|
||||
} else {
|
||||
@@ -582,7 +590,7 @@ boost::filesystem::path GetDefaultDataDir()
|
||||
// existing legacy directory, use that for backward compat
|
||||
return tmppath;
|
||||
} else {
|
||||
// For new clones, use .hush/ACNAME
|
||||
// For new nodes, use ~/.hush/<symbol>
|
||||
tmppath = pathRet / ".hush" / symbol;
|
||||
}
|
||||
return tmppath;
|
||||
@@ -598,13 +606,17 @@ static CCriticalSection csPathCached;
|
||||
|
||||
static boost::filesystem::path ZC_GetBaseParamsDir()
|
||||
{
|
||||
// Copied from GetDefaultDataDir and adapted for zcash params.
|
||||
// Copied from GetDefaultDataDir and adapted for the zk-SNARK parameter files.
|
||||
// DragonX reuses the upstream Sapling parameter directory layout, so these
|
||||
// locations retain the historical "ZcashParams" / ".zcash-params" names. Do
|
||||
// not change these string literals -- they determine where the proving and
|
||||
// verifying keys are loaded from.
|
||||
namespace fs = boost::filesystem;
|
||||
// Windows < Vista: C:\Documents and Settings\Username\Application Data\ZcashParams
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\ZcashParams
|
||||
// Mac: ~/Library/Application Support/ZcashParams
|
||||
// Unix: ~/.zcash-params
|
||||
// Debian packages: /usr/share/hush
|
||||
// System-wide install (Debian packages): /usr/share/hush
|
||||
fs::path pathRet;
|
||||
#ifdef _WIN32
|
||||
return GetSpecialFolderPath(CSIDL_APPDATA) / "ZcashParams";
|
||||
|
||||
@@ -22,10 +22,21 @@ extern std::string randomSietchZaddr();
|
||||
|
||||
// Serialized-size estimates for one spent input (kept in sync with rpcwallet.cpp)
|
||||
static const size_t AUTOSHIELD_CTXIN_DUST_SIZE = 148;
|
||||
// Every autoshield tx carries THREE Sapling OutputDescriptions -- the change
|
||||
// note to destZaddr plus the two Sietch dummies -- at ~948 bytes each. Reserving
|
||||
// 2000 for "header + sietch outputs" was ~900 bytes short before a single input
|
||||
// was counted, so a large enough round could build a tx over MAX_TX_SIZE.
|
||||
static const size_t AUTOSHIELD_SAPLING_OUTPUT_SIZE = 948;
|
||||
static const size_t AUTOSHIELD_TX_OVERHEAD = (3 * AUTOSHIELD_SAPLING_OUTPUT_SIZE) + 256;
|
||||
// Hard cap on inputs per round, mirroring z_shieldcoinbase's
|
||||
// SHIELD_COINBASE_DEFAULT_LIMIT. The byte estimate alone is not a safe bound:
|
||||
// with a P2PKH coinbase (-mineraddress) the 148-byte figure is exact rather than
|
||||
// conservative, so an under-estimate translates directly into an oversize tx.
|
||||
// The remainder is simply shielded on the next round.
|
||||
static const size_t AUTOSHIELD_MAX_INPUTS = 400;
|
||||
// Unrelated to the cap above despite sharing the value: this is a SIZE IN BYTES for
|
||||
// one spent P2SH input, mirroring CTXIN_SPEND_P2SH_SIZE in rpcwallet.cpp.
|
||||
static const size_t AUTOSHIELD_CTXIN_P2SH_SIZE = 400;
|
||||
// Expire unmined autoshield txs after this many blocks, so a tx cannot straddle
|
||||
// a network-upgrade activation.
|
||||
static const int AUTOSHIELD_EXPIRY_DELTA = 15;
|
||||
|
||||
AsyncRPCOperation_autoshieldcoinbase::AsyncRPCOperation_autoshieldcoinbase(int targetHeight)
|
||||
: targetHeight_(targetHeight) {}
|
||||
@@ -52,23 +63,8 @@ void AsyncRPCOperation_autoshieldcoinbase::main() {
|
||||
|
||||
try {
|
||||
success = main_impl();
|
||||
} catch (const UniValue& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
std::string message = find_value(objError, "message").get_str();
|
||||
set_error_code(code);
|
||||
set_error_message(message);
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
set_error_from_current_exception();
|
||||
}
|
||||
|
||||
stop_execution_clock();
|
||||
@@ -93,50 +89,34 @@ void AsyncRPCOperation_autoshieldcoinbase::main() {
|
||||
getId(), getStateAsString(), numTxCreated_, FormatMoney(amountShielded_));
|
||||
}
|
||||
|
||||
// Resolve the Sapling destination for auto-shielded coinbase.
|
||||
//
|
||||
// Recoverability is the hard requirement: coinbase we shield must land in an
|
||||
// address that a bare -mnemonic/-hdseed restore of THIS wallet's seed re-derives
|
||||
// on its own. A restore pre-derives exactly -mnemonicsaplinggap sapling accounts
|
||||
// starting at index 0, with saplingAccountCounter reset to 0 (init.cpp:2349-2355),
|
||||
// so the only self-recoverable destinations are the default addresses of
|
||||
// m/32'/<coin>'/i' for i < gap.
|
||||
//
|
||||
// We therefore DERIVE those accounts from the seed and pick the lowest index the
|
||||
// wallet already holds. Deriving is the only authoritative test. In particular
|
||||
// CKeyMetadata is NOT evidence of provenance: z_importkey / z_importwallet copy
|
||||
// both hdKeypath and seedFp verbatim out of the import source
|
||||
// (wallet.cpp:5522-5529 <- rpcdump.cpp:511-516), so a foreign key can claim any
|
||||
// keypath and any seed fingerprint. Filtering on metadata would let an imported
|
||||
// key win as "account 0" and silently receive every shielded reward.
|
||||
//
|
||||
// Caller must hold cs_wallet and must already have checked the wallet is unlocked.
|
||||
bool AsyncRPCOperation_autoshieldcoinbase::resolveDestination(
|
||||
libzcash::SaplingPaymentAddress& destOut, std::string& destStrOut) {
|
||||
// Read-only half of destination resolution, shared with init.cpp so the answer to
|
||||
// "where will auto-shielding send?" is available before the first round runs rather
|
||||
// than only after one has fired. Mutates nothing: no key generation, no caching.
|
||||
AutoShieldDestStatus ResolveAutoShieldDestinationReadOnly(
|
||||
libzcash::SaplingPaymentAddress& destOut, std::string& destStrOut, uint32_t& accountOut) {
|
||||
accountOut = AUTOSHIELD_ACCOUNT_NONE;
|
||||
|
||||
// 1. Explicit -autoshieldaddress override (validated as a spendable Sapling
|
||||
// zaddr at init.cpp:2494-2506). This also serves as the per-process cache
|
||||
// for whatever step 2/3 resolved.
|
||||
// zaddr in init.cpp). This doubles as the per-process cache for whatever
|
||||
// the derivation below resolved on an earlier round.
|
||||
if (!pwalletMain->autoShieldAddress.empty()) {
|
||||
auto decoded = DecodePaymentAddress(pwalletMain->autoShieldAddress);
|
||||
if (boost::get<libzcash::SaplingPaymentAddress>(&decoded) != nullptr) {
|
||||
destOut = boost::get<libzcash::SaplingPaymentAddress>(decoded);
|
||||
destStrOut = pwalletMain->autoShieldAddress;
|
||||
return true;
|
||||
return AutoShieldDestStatus::Resolved;
|
||||
}
|
||||
LogPrintf("%s: configured -autoshieldaddress is not a valid Sapling address\n", getId());
|
||||
return false;
|
||||
return AutoShieldDestStatus::InvalidOverride;
|
||||
}
|
||||
|
||||
// 2. Walk the restore window m/32'/coin'/[0, gap)' derived from the seed.
|
||||
HDSeed seed;
|
||||
if (!pwalletMain->GetHDSeedForDerivation(seed)) {
|
||||
LogPrintf("%s: no HD seed available; refusing to pick an autoshield destination\n", getId());
|
||||
return false;
|
||||
return AutoShieldDestStatus::NoSeed;
|
||||
}
|
||||
|
||||
// Mirror init.cpp:2349-2350's own clamp, and cap into the hardened index
|
||||
// space so (i | ZIP32_HARDENED_KEY_LIMIT) below stays well formed.
|
||||
// Mirror init.cpp's own clamp, and cap into the hardened index space so
|
||||
// (i | ZIP32_HARDENED_KEY_LIMIT) below stays well formed.
|
||||
int64_t gapArg = GetArg("-mnemonicsaplinggap", 100);
|
||||
if (gapArg < 0) {
|
||||
gapArg = 0;
|
||||
@@ -167,15 +147,77 @@ bool AsyncRPCOperation_autoshieldcoinbase::resolveDestination(
|
||||
if (pwalletMain->GetSaplingExtendedSpendingKey(addr, held)) {
|
||||
destOut = addr;
|
||||
destStrOut = EncodePaymentAddress(addr);
|
||||
// Cache for the life of the process; step 1 short-circuits later
|
||||
// rounds. Safe: we only cache post-validation.
|
||||
pwalletMain->autoShieldAddress = destStrOut;
|
||||
LogPrintf("%s: autoshield destination %s (seed-derived sapling account %u, gap %u)\n",
|
||||
getId(), destStrOut, (unsigned)i, (unsigned)saplingGap);
|
||||
return true;
|
||||
accountOut = i;
|
||||
return AutoShieldDestStatus::Resolved;
|
||||
}
|
||||
}
|
||||
|
||||
return AutoShieldDestStatus::NotFound;
|
||||
}
|
||||
|
||||
// Resolve the Sapling destination for auto-shielded coinbase.
|
||||
//
|
||||
// Recoverability is the hard requirement: coinbase we shield must land in an
|
||||
// address that a bare -mnemonic/-hdseed restore of THIS wallet's seed re-derives
|
||||
// on its own. A restore pre-derives exactly -mnemonicsaplinggap sapling accounts
|
||||
// starting at index 0, with saplingAccountCounter reset to 0 (init.cpp:2349-2355),
|
||||
// so the only self-recoverable destinations are the default addresses of
|
||||
// m/32'/<coin>'/i' for i < gap.
|
||||
//
|
||||
// We therefore DERIVE those accounts from the seed and pick the lowest index the
|
||||
// wallet already holds. Deriving is the only authoritative test. In particular
|
||||
// CKeyMetadata is NOT evidence of provenance: z_importkey / z_importwallet copy
|
||||
// both hdKeypath and seedFp verbatim out of the import source
|
||||
// (wallet.cpp:5522-5529 <- rpcdump.cpp:511-516), so a foreign key can claim any
|
||||
// keypath and any seed fingerprint. Filtering on metadata would let an imported
|
||||
// key win as "account 0" and silently receive every shielded reward.
|
||||
//
|
||||
// Caller must hold cs_wallet and must already have checked the wallet is unlocked.
|
||||
bool AsyncRPCOperation_autoshieldcoinbase::resolveDestination(
|
||||
libzcash::SaplingPaymentAddress& destOut, std::string& destStrOut) {
|
||||
|
||||
uint32_t account = AUTOSHIELD_ACCOUNT_NONE;
|
||||
switch (ResolveAutoShieldDestinationReadOnly(destOut, destStrOut, account)) {
|
||||
case AutoShieldDestStatus::Resolved:
|
||||
// Cache for the life of the process; the override branch of the resolver
|
||||
// short-circuits later rounds. Safe: we only cache post-validation.
|
||||
pwalletMain->autoShieldAddress = destStrOut;
|
||||
if (account == AUTOSHIELD_ACCOUNT_NONE) {
|
||||
LogPrintf("%s: autoshield destination %s (configured)\n", getId(), destStrOut);
|
||||
} else {
|
||||
LogPrintf("%s: autoshield destination %s (seed-derived sapling account %u)\n",
|
||||
getId(), destStrOut, (unsigned)account);
|
||||
}
|
||||
return true;
|
||||
case AutoShieldDestStatus::InvalidOverride:
|
||||
LogPrintf("%s: configured -autoshieldaddress is not a valid Sapling address\n", getId());
|
||||
return false;
|
||||
case AutoShieldDestStatus::NoSeed:
|
||||
LogPrintf("%s: no HD seed available; refusing to pick an autoshield destination\n", getId());
|
||||
return false;
|
||||
case AutoShieldDestStatus::NotFound:
|
||||
break; // nothing in the window yet: fall through and derive one
|
||||
}
|
||||
|
||||
// Re-establish the derivation context the resolver used, for step 3 below.
|
||||
HDSeed seed;
|
||||
if (!pwalletMain->GetHDSeedForDerivation(seed)) {
|
||||
LogPrintf("%s: no HD seed available; refusing to pick an autoshield destination\n", getId());
|
||||
return false;
|
||||
}
|
||||
int64_t gapArg = GetArg("-mnemonicsaplinggap", 100);
|
||||
if (gapArg < 0) {
|
||||
gapArg = 0;
|
||||
}
|
||||
if (gapArg > (int64_t)ZIP32_HARDENED_KEY_LIMIT) {
|
||||
gapArg = (int64_t)ZIP32_HARDENED_KEY_LIMIT;
|
||||
}
|
||||
const uint32_t saplingGap = (uint32_t)gapArg;
|
||||
const uint32_t bip44CoinType = Params().BIP44CoinType();
|
||||
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||
auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
|
||||
auto m_32h_cth = m_32h.Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT);
|
||||
|
||||
// 3. Nothing usable in the window yet: derive the next account, but only if
|
||||
// GenerateNewSaplingZKey will land INSIDE the window. It does NOT derive
|
||||
// at saplingAccountCounter: its do/while skips every index whose spending
|
||||
@@ -250,7 +292,7 @@ bool AsyncRPCOperation_autoshieldcoinbase::main_impl() {
|
||||
// from below), not the stale enqueue-time targetHeight_, so a queue delay
|
||||
// cannot slip a straddling expiry past this guard.
|
||||
auto nextActivationHeight = NextActivationHeight(tipHeight, consensusParams);
|
||||
if (nextActivationHeight && tipHeight + AUTOSHIELD_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||
if (nextActivationHeight && tipHeight + AUTO_OP_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||
LogPrintf("%s: autoshield tx could expire across a NU activation. Skipping this round.\n", opid);
|
||||
return true;
|
||||
}
|
||||
@@ -258,6 +300,27 @@ bool AsyncRPCOperation_autoshieldcoinbase::main_impl() {
|
||||
libzcash::SaplingPaymentAddress destZaddr;
|
||||
std::string destStr;
|
||||
std::vector<ShieldCoinbaseUTXO> inputs;
|
||||
|
||||
// Proof building below runs WITHOUT cs_wallet (deliberately, so wallet RPCs
|
||||
// are not stalled), which leaves a multi-second window in which a manual
|
||||
// z_shieldcoinbase or z_sendmany over the same miner address would re-select
|
||||
// these same coinbase outputs. AvailableCoins honours IsLockedCoin, so lock
|
||||
// them for the duration exactly as z_shieldcoinbase does. RAII because there
|
||||
// are several early returns between here and commit, and a leaked lock would
|
||||
// silently exclude those coins from every future round.
|
||||
struct ScopedCoinLocks {
|
||||
std::vector<COutPoint> locked;
|
||||
~ScopedCoinLocks() {
|
||||
// A destructor is noexcept by default; letting the lock acquisition
|
||||
// escape would turn a contended mutex into std::terminate.
|
||||
try {
|
||||
if (locked.empty()) return;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
// UnlockCoin takes a non-const reference (upstream signature).
|
||||
for (COutPoint& op : locked) pwalletMain->UnlockCoin(op);
|
||||
} catch (...) {}
|
||||
}
|
||||
} coinLocks;
|
||||
CAmount shieldedValue = 0;
|
||||
unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
|
||||
|
||||
@@ -277,10 +340,11 @@ bool AsyncRPCOperation_autoshieldcoinbase::main_impl() {
|
||||
}
|
||||
|
||||
// Gather matured, spendable coinbase UTXOs, byte-capped to a single tx.
|
||||
// AvailableCoins with fOnlySpendable already excludes immature coinbase
|
||||
// (< COINBASE_MATURITY) and outputs we don't own, so external
|
||||
// -mineraddress / pool coinbase naturally yields zero inputs.
|
||||
size_t estimatedTxSize = 2000; // header + sietch outputs headroom
|
||||
// AvailableCoins excludes immature coinbase unconditionally (wallet.cpp,
|
||||
// `IsCoinBase() && GetBlocksToMaturity() > 0`) and only ever returns outputs
|
||||
// we own, so external -mineraddress / pool coinbase yields zero inputs. The
|
||||
// second argument here is fOnlyConfirmed, not fOnlySpendable.
|
||||
size_t estimatedTxSize = AUTOSHIELD_TX_OVERHEAD;
|
||||
std::vector<COutput> vecOutputs;
|
||||
pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
|
||||
for (const COutput& out : vecOutputs) {
|
||||
@@ -293,6 +357,11 @@ bool AsyncRPCOperation_autoshieldcoinbase::main_impl() {
|
||||
}
|
||||
size_t increase = (boost::get<CScriptID>(&address) != nullptr)
|
||||
? AUTOSHIELD_CTXIN_P2SH_SIZE : AUTOSHIELD_CTXIN_DUST_SIZE;
|
||||
if (inputs.size() >= AUTOSHIELD_MAX_INPUTS) {
|
||||
LogPrintf("%s: reached per-round input cap (%d); deferring remaining coinbase to next round\n",
|
||||
opid, (int)AUTOSHIELD_MAX_INPUTS);
|
||||
break;
|
||||
}
|
||||
if (estimatedTxSize + increase >= max_tx_size) {
|
||||
// Size-safe batch; the remainder is shielded next round.
|
||||
LogPrintf("%s: reached per-tx size cap; deferring remaining coinbase to next round\n", opid);
|
||||
@@ -305,6 +374,12 @@ bool AsyncRPCOperation_autoshieldcoinbase::main_impl() {
|
||||
inputs.push_back(utxo);
|
||||
shieldedValue += out.tx->vout[out.i].nValue;
|
||||
}
|
||||
|
||||
for (const ShieldCoinbaseUTXO& t : inputs) {
|
||||
COutPoint outpt(t.txid, t.vout);
|
||||
pwalletMain->LockCoin(outpt);
|
||||
coinLocks.locked.push_back(outpt);
|
||||
}
|
||||
}
|
||||
|
||||
CAmount fee = pwalletMain->autoShieldFee;
|
||||
@@ -331,8 +406,13 @@ bool AsyncRPCOperation_autoshieldcoinbase::main_impl() {
|
||||
|
||||
// Build the t->z shield tx. Proof generation happens in Build() WITHOUT
|
||||
// holding cs_wallet (mirrors the sweep op) so we don't stall wallet RPCs.
|
||||
auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain);
|
||||
builder.SetExpiryHeight(tipHeight + AUTOSHIELD_EXPIRY_DELTA);
|
||||
// tipHeight, not targetHeight_: the builder's height selects the consensus
|
||||
// branch id (transaction_builder.cpp CurrentEpochBranchId), and the NU-straddle
|
||||
// guard above plus SetExpiryHeight below are both keyed off tipHeight. Using the
|
||||
// stale enqueue-time height here meant the guard was checking a height the
|
||||
// transaction was not actually signed against.
|
||||
auto builder = TransactionBuilder(consensusParams, tipHeight, pwalletMain);
|
||||
builder.SetExpiryHeight(tipHeight + AUTO_OP_EXPIRY_DELTA);
|
||||
builder.SetFee(fee);
|
||||
|
||||
for (const auto& t : inputs) {
|
||||
@@ -395,6 +475,13 @@ void AsyncRPCOperation_autoshieldcoinbase::setResult() {
|
||||
}
|
||||
|
||||
void AsyncRPCOperation_autoshieldcoinbase::cancel() {
|
||||
// Cancelling is how the scheduler stops an in-flight round, so unlike the base
|
||||
// class this must be able to move an EXECUTING operation to CANCELLED. What it
|
||||
// must not do is overwrite a state that is already terminal: the scheduler
|
||||
// cancels the previous operation when it enqueues the next one, and that one may
|
||||
// have already SUCCEEDED, whose result would otherwise be relabelled as cancelled.
|
||||
if (isSuccess() || isFailed() || isCancelled())
|
||||
return;
|
||||
set_state(OperationStatus::CANCELLED);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,25 @@
|
||||
#include "zcash/Address.hpp"
|
||||
#include "zcash/zip32.h"
|
||||
|
||||
// Default fee for automatic coinbase-shielding transactions
|
||||
static const CAmount DEFAULT_AUTOSHIELD_FEE = 10000;
|
||||
// Sentinel for "not a derived account" (i.e. the configured -autoshieldaddress).
|
||||
static const uint32_t AUTOSHIELD_ACCOUNT_NONE = UINT32_MAX;
|
||||
|
||||
enum class AutoShieldDestStatus {
|
||||
Resolved, // destOut/destStrOut are set
|
||||
NotFound, // no in-gap account held yet; the operation will derive one
|
||||
InvalidOverride, // -autoshieldaddress is set but is not a Sapling address
|
||||
NoSeed, // no HD seed available (e.g. locked wallet)
|
||||
};
|
||||
|
||||
// Resolve the auto-shield destination WITHOUT mutating the wallet: the configured
|
||||
// -autoshieldaddress if set, else the lowest in-gap seed-derived account the wallet
|
||||
// already holds. It deliberately does NOT generate a key, so init can call it purely
|
||||
// to answer "where will this send?" -- deriving a fresh account as a side effect of
|
||||
// populating a status field would be wrong. The operation's own resolveDestination
|
||||
// falls through to generation when this returns NotFound.
|
||||
// Caller must hold cs_wallet.
|
||||
AutoShieldDestStatus ResolveAutoShieldDestinationReadOnly(
|
||||
libzcash::SaplingPaymentAddress& destOut, std::string& destStrOut, uint32_t& accountOut);
|
||||
|
||||
// A periodic, wallet-local operation that drains matured *transparent* coinbase
|
||||
// UTXOs into a wallet-owned Sapling z-address in size-bounded batches. It is the
|
||||
|
||||
@@ -133,23 +133,8 @@ void AsyncRPCOperation_mergetoaddress::main()
|
||||
|
||||
try {
|
||||
success = main_impl();
|
||||
} catch (const UniValue& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
std::string message = find_value(objError, "message").get_str();
|
||||
set_error_code(code);
|
||||
set_error_message(message);
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
set_error_from_current_exception();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MINING
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
|
||||
CAmount fConsolidationTxFee = DEFAULT_CONSOLIDATION_FEE;
|
||||
bool fConsolidationMapUsed = false;
|
||||
const int CONSOLIDATION_EXPIRY_DELTA = 15;
|
||||
|
||||
// Number of Sietch dummy ("zdust") shielded outputs added to every consolidation
|
||||
// transaction to obscure the real output and keep the anonymity set large. This is
|
||||
// a wallet privacy-tuning parameter (not a consensus rule); the sweep operation uses
|
||||
// the same value under the name ZOUTS.
|
||||
static const int MIN_ZOUTS = 7;
|
||||
|
||||
extern string randomSietchZaddr();
|
||||
|
||||
@@ -47,24 +52,8 @@ void AsyncRPCOperation_saplingconsolidation::main() {
|
||||
|
||||
try {
|
||||
success = main_impl();
|
||||
} catch (const UniValue& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
std::string message = find_value(objError, "message").get_str();
|
||||
set_error_code(code);
|
||||
set_error_message(message);
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
set_error_from_current_exception();
|
||||
}
|
||||
|
||||
stop_execution_clock();
|
||||
@@ -107,8 +96,18 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
||||
auto opid=getId();
|
||||
LogPrintf("%s: Beginning AsyncRPCOperation_saplingconsolidation\n", opid);
|
||||
auto consensusParams = Params().GetConsensus();
|
||||
auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams);
|
||||
if (nextActivationHeight && targetHeight_ + CONSOLIDATION_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||
int tipHeight;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
tipHeight = (chainActive.Tip() != NULL) ? chainActive.Tip()->GetHeight() : targetHeight_;
|
||||
}
|
||||
|
||||
// Build and expire against tipHeight (execution-time), not the stale
|
||||
// enqueue-time targetHeight_, so the builder's consensus-branch selection and
|
||||
// the NU-straddle guard agree with the height the tx is signed for. Mirrors
|
||||
// the autoshield op (commit 65130c312).
|
||||
auto nextActivationHeight = NextActivationHeight(tipHeight, consensusParams);
|
||||
if (nextActivationHeight && tipHeight + AUTO_OP_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||
LogPrintf("%s: Consolidation txs would be created before a NU activation but may expire after. Skipping this round.\n",opid);
|
||||
setConsolidationResult(0, 0, std::vector<std::string>());
|
||||
return status;
|
||||
@@ -189,8 +188,8 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
||||
if (fromNotes.size() < minQuantity)
|
||||
continue;
|
||||
|
||||
auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain);
|
||||
builder.SetExpiryHeight(targetHeight_ + CONSOLIDATION_EXPIRY_DELTA);
|
||||
auto builder = TransactionBuilder(consensusParams, tipHeight, pwalletMain);
|
||||
builder.SetExpiryHeight(tipHeight + AUTO_OP_EXPIRY_DELTA);
|
||||
auto actualAmountToSend = amountToSend < fConsolidationTxFee ? 0 : amountToSend - fConsolidationTxFee;
|
||||
LogPrintf("%s: %s Beginning to create transaction with Sapling output amount=%s\n", __func__, opid, FormatMoney(actualAmountToSend));
|
||||
|
||||
@@ -230,10 +229,10 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
||||
builder.AddSaplingOutput(extsk.expsk.ovk, addr, actualAmountToSend);
|
||||
LogPrint("zrpcunsafe", "%s: Added consolidation output %s with amount=%li\n", opid, addr.GetHash().ToString().c_str(), actualAmountToSend);
|
||||
|
||||
// Add sietch zouts
|
||||
int MIN_ZOUTS = 7;
|
||||
// Add sietch zouts: MIN_ZOUTS dummy zero-value shielded outputs to
|
||||
// randomly-generated z-addresses, so the consolidation tx does not
|
||||
// shrink the anonymity set.
|
||||
for(size_t i = 0; i < MIN_ZOUTS; i++) {
|
||||
// In Privacy Zdust We Trust -- Duke
|
||||
string zdust = randomSietchZaddr();
|
||||
auto zaddr = DecodePaymentAddress(zdust);
|
||||
if (IsValidPaymentAddress(zaddr)) {
|
||||
@@ -305,6 +304,13 @@ void AsyncRPCOperation_saplingconsolidation::setConsolidationResult(int numTxCre
|
||||
}
|
||||
|
||||
void AsyncRPCOperation_saplingconsolidation::cancel() {
|
||||
// Cancelling is how the scheduler stops an in-flight round, so unlike the base
|
||||
// class this must be able to move an EXECUTING operation to CANCELLED. What it
|
||||
// must not do is overwrite a state that is already terminal: the scheduler
|
||||
// cancels the previous operation when it enqueues the next one, and that one may
|
||||
// have already SUCCEEDED, whose result would otherwise be relabelled as cancelled.
|
||||
if (isSuccess() || isFailed() || isCancelled())
|
||||
return;
|
||||
set_state(OperationStatus::CANCELLED);
|
||||
}
|
||||
|
||||
|
||||
@@ -155,23 +155,8 @@ void AsyncRPCOperation_sendmany::main() {
|
||||
|
||||
try {
|
||||
success = main_impl();
|
||||
} catch (const UniValue& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
std::string message = find_value(objError, "message").get_str();
|
||||
set_error_code(code);
|
||||
set_error_message(message);
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
set_error_from_current_exception();
|
||||
}
|
||||
|
||||
unlock_notes();
|
||||
@@ -215,9 +200,10 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
bool isPureTaddrOnlyTx = (isfromtaddr_ && z_outputs_.size() == 0);
|
||||
CAmount minersFee = fee_;
|
||||
|
||||
// TODO: fix this garbage ZEC prisoner mindset bullshit
|
||||
// When spending coinbase utxos, you can only specify a single zaddr as the change must go somewhere
|
||||
// and if there are multiple zaddrs, we don't know where to send it.
|
||||
// Coinbase-change routing constraint:
|
||||
// When spending coinbase UTXOs, only a single zaddr recipient may be specified, because the
|
||||
// change must be routed somewhere and with multiple zaddr recipients there is no unambiguous
|
||||
// destination for it. See the isSingleZaddrOutput / isMultipleZaddrOutput handling below.
|
||||
if (isfromtaddr_) {
|
||||
if (isSingleZaddrOutput) {
|
||||
bool b = find_utxos(true);
|
||||
@@ -325,14 +311,12 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
CScript scriptPubKey;
|
||||
for (auto t : t_inputs_) {
|
||||
scriptPubKey = GetScriptForDestination(std::get<4>(t));
|
||||
//printf("Checking new script: %s\n", scriptPubKey.ToString().c_str());
|
||||
uint256 txid = std::get<0>(t);
|
||||
int vout = std::get<1>(t);
|
||||
CAmount amount = std::get<2>(t);
|
||||
builder_.AddTransparentInput(COutPoint(txid, vout), scriptPubKey, amount);
|
||||
}
|
||||
// for other chains, set locktime to spend time locked coinbases
|
||||
//builder_.SetLockTime((uint32_t)chainActive.Tip()->GetMedianTimePast());
|
||||
} else {
|
||||
CMutableTransaction rawTx(tx_);
|
||||
for (SendManyInputUTXO & t : t_inputs_) {
|
||||
@@ -342,7 +326,6 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
CTxIn in(COutPoint(txid, vout));
|
||||
rawTx.vin.push_back(in);
|
||||
}
|
||||
//rawTx.nLockTime = (uint32_t)chainActive.Tip()->GetMedianTimePast();
|
||||
tx_ = CTransaction(rawTx);
|
||||
}
|
||||
}
|
||||
@@ -357,8 +340,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
|
||||
|
||||
/**
|
||||
* SCENARIO #0 (All HUSH and Hush Arrakis Chains)
|
||||
* Sprout not involved, so we just use the TransactionBuilder and we're done.
|
||||
* SCENARIO #0 (DragonX and all Sapling-only chains)
|
||||
* Sprout is not involved, so we just use the TransactionBuilder and we're done.
|
||||
* We added the transparent inputs to the builder earlier.
|
||||
*/
|
||||
if (isUsingBuilder_) {
|
||||
@@ -416,7 +399,6 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
}
|
||||
|
||||
// Fetch Sapling anchor and witnesses
|
||||
//LogPrintf("%s: Gathering anchors and witnesses\n", __FUNCTION__);
|
||||
uint256 anchor;
|
||||
std::vector<boost::optional<SaplingWitness>> witnesses;
|
||||
{
|
||||
@@ -510,7 +492,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
return true;
|
||||
}
|
||||
// END SCENARIO #0
|
||||
// No other scenarios, because Hush developers are elite.
|
||||
// No other scenarios: DragonX is Sapling-only (Sprout removed), so the builder path above
|
||||
// handles every supported case. Reaching here means the builder was not used, which is unexpected.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -625,7 +608,6 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//printf("%s\n", boost::apply_visitor(AddressVisitorString(), dest).c_str());
|
||||
if (!destinations.count(dest)) {
|
||||
continue;
|
||||
}
|
||||
@@ -673,7 +655,8 @@ void AsyncRPCOperation_sendmany::add_taddr_outputs_to_tx() {
|
||||
rawTx.vout.push_back(out);
|
||||
}
|
||||
if ( !hush_hardfork_active((uint32_t)chainActive.LastTip()->nTime) )
|
||||
rawTx.nLockTime = (uint32_t)time(NULL) - 60; // jl777
|
||||
// Pre-hardfork: set nLockTime slightly in the past so the tx is immediately spendable.
|
||||
rawTx.nLockTime = (uint32_t)time(NULL) - 60;
|
||||
else
|
||||
rawTx.nLockTime = (uint32_t)chainActive.Tip()->GetMedianTimePast();
|
||||
|
||||
@@ -703,7 +686,8 @@ void AsyncRPCOperation_sendmany::add_taddr_change_output_to_tx(CBitcoinAddress *
|
||||
CMutableTransaction rawTx(tx_);
|
||||
rawTx.vout.push_back(out);
|
||||
if ( !hush_hardfork_active((uint32_t)chainActive.LastTip()->nTime) )
|
||||
rawTx.nLockTime = (uint32_t)time(NULL) - 60; // jl777
|
||||
// Pre-hardfork: set nLockTime slightly in the past so the tx is immediately spendable.
|
||||
rawTx.nLockTime = (uint32_t)time(NULL) - 60;
|
||||
else
|
||||
rawTx.nLockTime = (uint32_t)chainActive.Tip()->GetMedianTimePast();
|
||||
tx_ = CTransaction(rawTx);
|
||||
|
||||
@@ -68,7 +68,7 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Empty inputs");
|
||||
}
|
||||
|
||||
if (donation < 0 || donation > 10 ) {
|
||||
if (donation > 10 ) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid donation percentage, must be an integer between 0 and 10 inclusive");
|
||||
}
|
||||
|
||||
@@ -116,23 +116,8 @@ void AsyncRPCOperation_shieldcoinbase::main() {
|
||||
|
||||
try {
|
||||
success = main_impl();
|
||||
} catch (const UniValue& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
std::string message = find_value(objError, "message").get_str();
|
||||
set_error_code(code);
|
||||
set_error_message(message);
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
set_error_from_current_exception();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MINING
|
||||
|
||||
@@ -19,7 +19,6 @@ extern string randomSietchZaddr();
|
||||
|
||||
CAmount fSweepTxFee = DEFAULT_SWEEP_FEE;
|
||||
bool fSweepMapUsed = false;
|
||||
const int SWEEP_EXPIRY_DELTA = 15;
|
||||
boost::optional<libzcash::SaplingPaymentAddress> rpcSweepAddress;
|
||||
|
||||
AsyncRPCOperation_sweep::AsyncRPCOperation_sweep(int targetHeight, bool fromRpc) : targetHeight_(targetHeight), fromRPC_(fromRpc){}
|
||||
@@ -46,23 +45,8 @@ void AsyncRPCOperation_sweep::main() {
|
||||
|
||||
try {
|
||||
success = main_impl();
|
||||
} catch (const UniValue& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
std::string message = find_value(objError, "message").get_str();
|
||||
set_error_code(code);
|
||||
set_error_message(message);
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
set_error_from_current_exception();
|
||||
}
|
||||
|
||||
stop_execution_clock();
|
||||
@@ -112,7 +96,7 @@ bool IsExcludedAddress(libzcash::SaplingPaymentAddress zaddr) {
|
||||
}
|
||||
} else {
|
||||
// This is an invalid sapling zaddr
|
||||
LogPrintf("%s: Invalid zsweepexclude zaddr %s, ignoring\n", sweepExcludeAddress);
|
||||
LogPrintf("%s: Invalid zsweepexclude zaddr %s, ignoring\n", __func__, sweepExcludeAddress);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -126,10 +110,21 @@ bool AsyncRPCOperation_sweep::main_impl() {
|
||||
auto opid=getId();
|
||||
LogPrintf("%s: Beginning asyncrpcoperation_sweep.\n", getId());
|
||||
auto consensusParams = Params().GetConsensus();
|
||||
auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams);
|
||||
if (nextActivationHeight && targetHeight_ + SWEEP_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||
int tipHeight;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
tipHeight = (chainActive.Tip() != NULL) ? chainActive.Tip()->GetHeight() : targetHeight_;
|
||||
}
|
||||
|
||||
// Key the NU-straddle guard and the tx builder/expiry off tipHeight (the
|
||||
// height we actually build and expire against), not the stale enqueue-time
|
||||
// targetHeight_, so a queue delay cannot slip a straddling expiry past this
|
||||
// guard. Mirrors the autoshield op (commit 65130c312).
|
||||
auto nextActivationHeight = NextActivationHeight(tipHeight, consensusParams);
|
||||
if (nextActivationHeight && tipHeight + AUTO_OP_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||
LogPrintf("%s: Sweep txs would be created before a NU activation but may expire after. Skipping this round.\n", getId());
|
||||
setSweepResult(0, 0, std::vector<std::string>());
|
||||
sweepComplete_ = true; // nothing to do this round; back nextSweep off one interval instead of re-dispatching every block
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -258,11 +253,8 @@ bool AsyncRPCOperation_sweep::main_impl() {
|
||||
fee = 0;
|
||||
}
|
||||
|
||||
auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain);
|
||||
{
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
builder.SetExpiryHeight(chainActive.Tip()->GetHeight()+ SWEEP_EXPIRY_DELTA);
|
||||
}
|
||||
auto builder = TransactionBuilder(consensusParams, tipHeight, pwalletMain);
|
||||
builder.SetExpiryHeight(tipHeight + AUTO_OP_EXPIRY_DELTA);
|
||||
LogPrintf("%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), FormatMoney(amountToSend - fee));
|
||||
|
||||
// Select Sapling notes
|
||||
@@ -364,6 +356,13 @@ void AsyncRPCOperation_sweep::setSweepResult(int numTxCreated, const CAmount& am
|
||||
}
|
||||
|
||||
void AsyncRPCOperation_sweep::cancel() {
|
||||
// Cancelling is how the scheduler stops an in-flight round, so unlike the base
|
||||
// class this must be able to move an EXECUTING operation to CANCELLED. What it
|
||||
// must not do is overwrite a state that is already terminal: the scheduler
|
||||
// cancels the previous operation when it enqueues the next one, and that one may
|
||||
// have already SUCCEEDED, whose result would otherwise be relabelled as cancelled.
|
||||
if (isSuccess() || isFailed() || isCancelled())
|
||||
return;
|
||||
set_state(OperationStatus::CANCELLED);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/foreach.hpp>
|
||||
// TODO: these are not set correctly by wolfssl for some reason. Ja bless.
|
||||
// Enable wolfSSL timing-resistant ECC and TFM (fastmath) code paths, which
|
||||
// harden against timing side-channels. wolfSSL gates these purely with #ifdef,
|
||||
// so the defined value is immaterial (any value enables the feature); we do not
|
||||
// rely on 420 meaning anything.
|
||||
#undef ECC_TIMING_RESISTANT
|
||||
#undef TFM_TIMING_RESISTANT
|
||||
#define ECC_TIMING_RESISTANT 420
|
||||
@@ -306,7 +309,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
||||
}
|
||||
if (keyPass && keyFail)
|
||||
{
|
||||
LogPrintf("Oh shit! The wallet is probably corrupted: Some keys decrypt but not all.\n");
|
||||
LogPrintf("The wallet is probably corrupted: some keys decrypt but not all.\n");
|
||||
assert(false);
|
||||
}
|
||||
if (keyFail || !keyPass)
|
||||
|
||||
@@ -165,12 +165,12 @@ private:
|
||||
// .second is the ciphertext.
|
||||
std::pair<uint256, std::vector<unsigned char>> cryptedMnemonicEntropy;
|
||||
CryptedKeyMap mapCryptedKeys;
|
||||
//CryptedSproutSpendingKeyMap mapCryptedSproutSpendingKeys;
|
||||
CryptedSaplingSpendingKeyMap mapCryptedSaplingSpendingKeys;
|
||||
|
||||
CKeyingMaterial vMasterKey;
|
||||
|
||||
//! if fUseCrypto is true, mapKeys, mapSproutSpendingKeys, and mapSaplingSpendingKeys must be empty
|
||||
//! if fUseCrypto is true, mapKeys and mapSaplingSpendingKeys must be empty
|
||||
//! (Sprout was removed; the former mapSproutSpendingKeys no longer exists)
|
||||
//! if fUseCrypto is false, vMasterKey must be empty
|
||||
bool fUseCrypto;
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ UniValue convertpassphrase(const UniValue& params, bool fHelp, const CPubKey& my
|
||||
"1. \"agamapassphrase\" (string, required) Agama passphrase\n"
|
||||
"\nResult:\n"
|
||||
"\"agamapassphrase\": \"agamapassphrase\", (string) Agama passphrase you entered\n"
|
||||
"\"address\": \"hushaddress\", (string) Address corresponding to your passphrase\n"
|
||||
"\"address\": \"dragonxaddress\", (string) Address corresponding to your passphrase\n"
|
||||
"\"pubkey\": \"publickeyhex\", (string) The hex value of the raw public key\n"
|
||||
"\"privkey\": \"privatekeyhex\", (string) The hex value of the raw private key\n"
|
||||
"\"wif\": \"wif\" (string) The private key in WIF format to use with 'importprivkey'\n"
|
||||
@@ -196,9 +196,9 @@ UniValue getrescaninfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
auto startHeight = pwalletMain->rescanStartHeight;
|
||||
auto currentHeight = chainActive.Height();
|
||||
// if current height is 0, progress=1 since there is nothing to rescan
|
||||
char progress[8];
|
||||
char progress[16];
|
||||
if (currentHeight != 0) {
|
||||
sprintf(progress, "%.4f", (double) rescanHeight / (double) currentHeight );
|
||||
snprintf(progress, sizeof(progress), "%.4f", (double) rescanHeight / (double) currentHeight );
|
||||
ret.push_back(Pair("rescan_progress", progress));
|
||||
}
|
||||
ret.push_back(Pair("rescan_start_height", startHeight));
|
||||
@@ -255,10 +255,10 @@ UniValue importprivkey(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
if (fHelp || params.size() < 1 || params.size() > 5)
|
||||
throw runtime_error(
|
||||
"importprivkey \"hushprivkey\" ( \"label\" rescan height secret_key)\n"
|
||||
"importprivkey \"dragonxprivkey\" ( \"label\" rescan height secret_key)\n"
|
||||
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"hushprivkey\" (string, required) The private key (see dumpprivkey)\n"
|
||||
"1. \"dragonxprivkey\" (string, required) The private key (see dumpprivkey)\n"
|
||||
"2. \"label\" (string, optional, default=\"\") An optional label\n"
|
||||
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
|
||||
"4. height (integer, optional, default=0) start at block height?\n"
|
||||
@@ -305,7 +305,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
if (params.size() > 4)
|
||||
{
|
||||
auto secret_key = AmountFromValue(params[4])/100000000;
|
||||
secret_key = AmountFromValue(params[4])/100000000;
|
||||
key = DecodeCustomSecret(strSecret, secret_key);
|
||||
} else {
|
||||
key = DecodeSecret(strSecret);
|
||||
@@ -378,7 +378,7 @@ UniValue importaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
std::vector<unsigned char> data(ParseHex(params[0].get_str()));
|
||||
script = CScript(data.begin(), data.end());
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address or script");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DragonX address or script");
|
||||
}
|
||||
|
||||
string strLabel = "";
|
||||
@@ -504,7 +504,7 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
|
||||
if (vstr.size() < 2)
|
||||
continue;
|
||||
|
||||
// Let's see if the address is a valid Hush spending key
|
||||
// Let's see if the address is a valid DragonX spending key
|
||||
if (fImportZKeys) {
|
||||
auto spendingkey = DecodeSpendingKey(vstr[0]);
|
||||
int64_t nTime = DecodeDumpTime(vstr[1]);
|
||||
@@ -524,7 +524,7 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
|
||||
continue;
|
||||
} else {
|
||||
LogPrintf("%s: Importing detected an error: invalid spending key. Trying as a transparent key...\n",__func__);
|
||||
// Not a valid spending key, so carry on and see if it's a Hush transparent address
|
||||
// Not a valid spending key, so carry on and see if it's a DragonX transparent address
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,25 +585,27 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
|
||||
}
|
||||
}
|
||||
|
||||
if (fRescan) {
|
||||
CBlockIndex *pindex = chainActive.LastTip();
|
||||
while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
|
||||
pindex = pindex->pprev;
|
||||
// A failed key/address add must surface on BOTH paths; previously this
|
||||
// check lived inside the fRescan block, so importwallet with rescan=false
|
||||
// silently reported success even when some keys failed to import.
|
||||
if (!fGood)
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
|
||||
|
||||
LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->GetHeight() + 1);
|
||||
if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
|
||||
pwalletMain->nTimeFirstKey = nTimeBegin;
|
||||
pwalletMain->ScanForWalletTransactions(pindex);
|
||||
pwalletMain->MarkDirty();
|
||||
if (fRescan) {
|
||||
CBlockIndex *pindex = chainActive.LastTip();
|
||||
while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
|
||||
pindex = pindex->pprev;
|
||||
|
||||
if (!fGood)
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
|
||||
LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->GetHeight() + 1);
|
||||
if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
|
||||
pwalletMain->nTimeFirstKey = nTimeBegin;
|
||||
pwalletMain->ScanForWalletTransactions(pindex);
|
||||
pwalletMain->MarkDirty();
|
||||
} else {
|
||||
LogPrintf("Importwallet without rescan successful\n");
|
||||
}
|
||||
|
||||
return NullUniValue; }
|
||||
|
||||
else{
|
||||
LogPrintf("Importwallet without Rescan successfull\n");
|
||||
return NullUniValue;}
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -659,7 +661,7 @@ UniValue z_exportwallet(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
"z_exportwallet \"filename\"\n"
|
||||
"\nExports all wallet keys, for taddr and zaddr, in a human-readable format. Overwriting an existing file is not permitted.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"filename\" (string, required) The filename, saved in folder set by hushd -exportdir option\n"
|
||||
"1. \"filename\" (string, required) The filename, saved in folder set by dragonxd -exportdir option\n"
|
||||
"\nResult:\n"
|
||||
"\"path\" (string) The full path of the destination file\n"
|
||||
"\nExamples:\n"
|
||||
@@ -680,7 +682,7 @@ UniValue dumpwallet(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
"dumpwallet \"filename\"\n"
|
||||
"\nDumps taddr wallet keys in a human-readable format. Overwriting an existing file is not permitted.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"filename\" (string, required) The filename, saved in folder set by hushd -exportdir option\n"
|
||||
"1. \"filename\" (string, required) The filename, saved in folder set by dragonxd -exportdir option\n"
|
||||
"\nResult:\n"
|
||||
"\"path\" (string) The full path of the destination file\n"
|
||||
"\nExamples:\n"
|
||||
@@ -736,7 +738,7 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
|
||||
std::sort(vKeyBirth.begin(), vKeyBirth.end());
|
||||
|
||||
// produce output
|
||||
file << strprintf("# Wallet dump created by Hush %s (%s)\n", CLIENT_BUILD);
|
||||
file << strprintf("# Wallet dump created by DragonX %s (%s)\n", CLIENT_BUILD);
|
||||
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
|
||||
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
|
||||
file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
|
||||
@@ -1231,7 +1233,6 @@ UniValue nspv_listtransactions(const UniValue& params, bool fHelp, const CPubKey
|
||||
CCflag = atoi((char *)params[1].get_str().c_str());
|
||||
if ( params.size() == 3 )
|
||||
skipcount = atoi((char *)params[2].get_str().c_str());
|
||||
//fprintf(stderr,"call txids cc.%d skip.%d\n",CCflag,skipcount);
|
||||
return(NSPV_addresstxids((char *)params[0].get_str().c_str(),CCflag,skipcount,0));
|
||||
}
|
||||
else throw runtime_error("nspv_listtransactions [address [isCC [skipcount]]]\n");
|
||||
@@ -1294,7 +1295,6 @@ UniValue nspv_spend(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
if ( NSPV_address.size() == 0 )
|
||||
throw runtime_error("to nspv_send you need an active nspv_login\n");
|
||||
satoshis = atof(params[1].get_str().c_str())*COIN + 0.0000000049;
|
||||
//fprintf(stderr,"satoshis.%lld from %.8f\n",(long long)satoshis,atof(params[1].get_str().c_str()));
|
||||
if ( satoshis < 1000 )
|
||||
throw runtime_error("amount too small\n");
|
||||
return(NSPV_spend((char *)NSPV_address.c_str(),(char *)params[0].get_str().c_str(),satoshis));
|
||||
|
||||
@@ -364,7 +364,7 @@ UniValue setaccount(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||
if (!IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DragonX address!");
|
||||
}
|
||||
|
||||
string strAccount;
|
||||
@@ -411,7 +411,7 @@ UniValue getaccount(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||
if (!IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DragonX address!");
|
||||
}
|
||||
|
||||
std::string strAccount;
|
||||
@@ -496,7 +496,6 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
|
||||
// Check amount
|
||||
if (nValue <= 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
|
||||
//fprintf(stderr,"nValue %.8f vs curBalance %.8f\n",(double)nValue/COIN,(double)curBalance/COIN);
|
||||
if (nValue > curBalance)
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
|
||||
|
||||
@@ -518,9 +517,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
|
||||
for (i=0; i<opretlen; i++)
|
||||
{
|
||||
opretpubkey[i] = opretbuf[i];
|
||||
//printf("%02x",ptr[i]);
|
||||
}
|
||||
//printf(" opretbuf[%d]\n",opretlen);
|
||||
CRecipient opret = { opretpubkey, opretValue, false };
|
||||
vecSend.push_back(opret);
|
||||
}
|
||||
@@ -574,7 +571,7 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||
if (!IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DragonX address!");
|
||||
}
|
||||
|
||||
// Amount
|
||||
@@ -665,7 +662,6 @@ UniValue kvupdate(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
if ( (n= (int32_t)params.size()) >= 3 )
|
||||
{
|
||||
flags = atoi(params[2].get_str().c_str());
|
||||
//printf("flags.%d (%s) n.%d\n",flags,params[2].get_str().c_str(),n);
|
||||
} else flags = 0;
|
||||
if ( n >= 4 )
|
||||
privkey = hush_kvprivkey(&pubkey,(char *)(n >= 4 ? params[3].get_str().c_str() : "password"));
|
||||
@@ -704,15 +700,13 @@ UniValue kvupdate(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
if ( hush_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
|
||||
{
|
||||
ret.push_back(Pair("error",(char *)"error verifying sig, passphrase is probably wrong"));
|
||||
printf("VERIFY ERROR\n");
|
||||
LogPrintf("VERIFY ERROR\n");
|
||||
return ret;
|
||||
} // else printf("verified immediately\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
//for (i=0; i<32; i++)
|
||||
// printf("%02x",((uint8_t *)&sig)[i]);
|
||||
//printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
|
||||
ret.push_back(Pair("coin",(char *)(SMART_CHAIN_SYMBOL[0] == 0 ? "HUSH3" : SMART_CHAIN_SYMBOL)));
|
||||
// The SMART_CHAIN_SYMBOL[0]==0 fallback is dead on DragonX (symbol is always "DRAGONX"); kept for defensiveness.
|
||||
ret.push_back(Pair("coin",(char *)(SMART_CHAIN_SYMBOL[0] == 0 ? "DRAGONX" : SMART_CHAIN_SYMBOL)));
|
||||
height = chainActive.LastTip()->GetHeight();
|
||||
if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
|
||||
ret.push_back(Pair("owner",refpubkey.GetHex()));
|
||||
@@ -749,9 +743,6 @@ UniValue kvupdate(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
}
|
||||
if ( (opretlen= hush_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
|
||||
opretlen++;
|
||||
//for (i=0; i<opretlen; i++)
|
||||
// printf("%02x",opretbuf[i]);
|
||||
//printf(" opretbuf keylen.%d valuesize.%d height.%d (%02x %02x %02x)\n",*(uint16_t *)&keyvalue[0],*(uint16_t *)&keyvalue[2],*(uint32_t *)&keyvalue[4],keyvalue[8],keyvalue[9],keyvalue[10]);
|
||||
EnsureWalletIsUnlocked();
|
||||
fee = hush_kvfee(flags,opretlen,keylen);
|
||||
ret.push_back(Pair("fee",(double)fee/COIN));
|
||||
@@ -905,7 +896,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp, const CPubKey&
|
||||
// Bitcoin address
|
||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||
if (!IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Hush address!");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DragonX address!");
|
||||
}
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
if (!IsMine(*pwalletMain, scriptPubKey)) {
|
||||
@@ -1462,7 +1453,7 @@ UniValue sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
CScript tmpspk;
|
||||
tmpspk << ParseHex(name_) << OP_CHECKSIG;
|
||||
if ( !ExtractDestination(tmpspk, dest, true) )
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Hush address or pubkey: ") + name_);
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid DragonX address or pubkey: ") + name_);
|
||||
}
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
@@ -1823,7 +1814,6 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
|
||||
BOOST_FOREACH(const COutputEntry& r, listReceived)
|
||||
{
|
||||
string account;
|
||||
//fprintf(stderr,"recv iter %s\n",wtx.GetHash().GetHex().c_str());
|
||||
if (pwalletMain->mapAddressBook.count(r.destination))
|
||||
account = pwalletMain->mapAddressBook[r.destination].name;
|
||||
if (fAllAccounts || (account == strAccount))
|
||||
@@ -1972,9 +1962,8 @@ UniValue listtransactions(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
CWalletTx *const pwtx = (*it).second.first;
|
||||
if (pwtx != 0)
|
||||
{
|
||||
//fprintf(stderr,"pwtx iter.%d %s\n",(int32_t)pwtx->nOrderPos,pwtx->GetHash().GetHex().c_str());
|
||||
ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
|
||||
} //else fprintf(stderr,"null pwtx\n");
|
||||
}
|
||||
CAccountingEntry *const pacentry = (*it).second.second;
|
||||
if (pacentry != 0)
|
||||
AcentryToJSON(*pacentry, strAccount, ret);
|
||||
@@ -2558,7 +2547,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
// slack space in .dat files; that is bad if the old data is
|
||||
// unencrypted private keys. So:
|
||||
StartShutdown();
|
||||
return "wallet encrypted; Hush server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
|
||||
return "wallet encrypted; DragonX server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
|
||||
}
|
||||
|
||||
UniValue lockunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
@@ -2866,7 +2855,7 @@ UniValue listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
" \"txid\" : \"txid\", (string) the transaction id \n"
|
||||
" \"vout\" : n, (numeric) the vout value\n"
|
||||
" \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
|
||||
" \"address\" : \"address\", (string) the Hush address\n"
|
||||
" \"address\" : \"address\", (string) the DragonX address\n"
|
||||
" \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
|
||||
" \"scriptPubKey\" : \"key\", (string) the script key\n"
|
||||
" \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
|
||||
@@ -2900,7 +2889,7 @@ UniValue listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
const UniValue& input = inputs[idx];
|
||||
CTxDestination dest = DecodeDestination(input.get_str());
|
||||
if (!IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Hush address: ") + input.get_str());
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid DragonX address: ") + input.get_str());
|
||||
}
|
||||
if (!destinations.insert(dest).second) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
|
||||
@@ -2959,7 +2948,6 @@ UniValue listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
|
||||
CBlockIndex *tipindex,*pindex = it->second;
|
||||
uint32_t locktime;
|
||||
//fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.LastTip(),locktime,txheight,pindex->GetHeight());
|
||||
}
|
||||
else if ( chainActive.LastTip() != 0 )
|
||||
txheight = (chainActive.LastTip()->GetHeight() - out.nDepth - 1);
|
||||
@@ -3345,6 +3333,83 @@ UniValue z_sweepstatus(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniValue z_autoshieldstatus(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (fHelp || params.size() > 0)
|
||||
throw runtime_error(
|
||||
"z_autoshieldstatus\n"
|
||||
"\nReport the state of automatic coinbase shielding: whether it is on, where it sends,\n"
|
||||
"and -- when it is off -- why.\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"autoshield\" : true|false, (boolean) whether auto-shielding is enabled\n"
|
||||
" \"running\" : true|false, (boolean) whether a round is in flight\n"
|
||||
" \"next_autoshield\" : n, (numeric) height of the next round\n"
|
||||
" \"autoshieldinterval\" : n, (numeric) blocks between rounds\n"
|
||||
" \"autoshieldaddress\" : \"zaddr\", (string) resolved destination; empty until first resolved\n"
|
||||
" \"autoshieldfee\" : n, (numeric) fee in puposhis\n"
|
||||
" \"autoshieldminutxos\" : n, (numeric) minimum matured coinbase utxos per round\n"
|
||||
" \"hdseedorigin\" : n, (numeric) 0 unrecorded, 1 created, 2 restored, 3 retrofit, 4 unknown\n"
|
||||
" \"hdseedorigin_desc\" : \"...\", (string) readable form of hdseedorigin\n"
|
||||
" \"seed_recoverable\" : true|false, (boolean) whether a seed phrase can be exported\n"
|
||||
" \"disabled_reason\" : \"...\" (string) why auto-shielding is not running, if it is not\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("z_autoshieldstatus", "")
|
||||
+ HelpExampleRpc("z_autoshieldstatus", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("autoshield", pwalletMain->fAutoShieldEnabled));
|
||||
ret.push_back(Pair("running", pwalletMain->fAutoShieldRunning));
|
||||
ret.push_back(Pair("next_autoshield", pwalletMain->nextAutoShield));
|
||||
ret.push_back(Pair("autoshieldinterval", pwalletMain->autoShieldInterval));
|
||||
ret.push_back(Pair("autoshieldaddress", pwalletMain->autoShieldAddress));
|
||||
ret.push_back(Pair("autoshieldfee", pwalletMain->autoShieldFee));
|
||||
ret.push_back(Pair("autoshieldminutxos", pwalletMain->autoShieldMinUtxos));
|
||||
|
||||
int origin = pwalletMain->hdSeedOrigin;
|
||||
std::string desc;
|
||||
switch (origin) {
|
||||
case CWallet::HDSEED_ORIGIN_CREATED: desc = "created on an empty wallet"; break;
|
||||
case CWallet::HDSEED_ORIGIN_RESTORED: desc = "restored from -mnemonic/-hdseed"; break;
|
||||
case CWallet::HDSEED_ORIGIN_RETROFIT: desc = "retrofitted onto a pre-existing wallet"; break;
|
||||
case CWallet::HDSEED_ORIGIN_UNKNOWN: desc = "predates provenance recording"; break;
|
||||
default: desc = "not yet recorded"; break;
|
||||
}
|
||||
ret.push_back(Pair("hdseedorigin", origin));
|
||||
ret.push_back(Pair("hdseedorigin_desc", desc));
|
||||
ret.push_back(Pair("seed_recoverable", pwalletMain->IsMnemonicSeed()));
|
||||
|
||||
// Say why it is off. A silent "false" is exactly what made the destination
|
||||
// un-inspectable in the first place.
|
||||
std::string why = "";
|
||||
if (!pwalletMain->fAutoShieldEnabled) {
|
||||
if (origin != CWallet::HDSEED_ORIGIN_CREATED && origin != CWallet::HDSEED_ORIGIN_RESTORED)
|
||||
why = "HD seed origin is not known-recoverable; back the seed up and pass -autoshield=1";
|
||||
else
|
||||
why = "disabled by -autoshield=0";
|
||||
} else if (pwalletMain->IsLocked()) {
|
||||
why = "wallet is locked; rounds are skipped until it is unlocked";
|
||||
} else if (pwalletMain->fSweepRunning || pwalletMain->fConsolidationRunning) {
|
||||
// Autoshield is mutually exclusive with sweep and consolidation. Without
|
||||
// this the RPC reports autoshield=true, running=false and an empty
|
||||
// reason while no round can actually start.
|
||||
why = strprintf("deferred while %s is running; rounds resume when it finishes",
|
||||
pwalletMain->fSweepRunning ? "z_sweep" : "sapling consolidation");
|
||||
} else if (pwalletMain->autoShieldAddress.empty()) {
|
||||
why = "no destination resolved yet; one will be derived from the HD seed on the first round";
|
||||
}
|
||||
ret.push_back(Pair("disabled_reason", why));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
@@ -3359,7 +3424,7 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&
|
||||
"This function is slow if no filters are given, use z_listreceivedbyaddress if you do not need filters."
|
||||
"\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"hushaddress:\" (string, required) \n"
|
||||
"1. \"dragonxaddress:\" (string, required) \n"
|
||||
"\n"
|
||||
"2. \"Minimum Confimations:\" (numeric, optional, default=0) \n"
|
||||
"\n"
|
||||
@@ -3396,13 +3461,13 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&
|
||||
" \"walletconflicts\": [conflicts], An array of wallet conflicts\n"
|
||||
" \"recieved\": { A list of receives from the transaction\n"
|
||||
" \"transparentReceived\": [{ An Array of txos received for transparent addresses\n"
|
||||
" \"address\": \"hushaddress\", (string) Hush transparent address (t-address)\n"
|
||||
" \"address\": \"dragonxaddress\", (string) DragonX transparent address (t-address)\n"
|
||||
" \"scriptPubKey\": \"script\", (string) Script for the transparent address (t-address)\n"
|
||||
" \"amount\": x.xxxx, (numeric) Value of output being received " + CURRENCY_UNIT + ", positive for receives\n"
|
||||
" \"vout\": : n, (numeric) the vout value\n"
|
||||
" }],\n"
|
||||
" \"saplingReceived\": [{ An Array of utxos/notes received for sapling addresses\n"
|
||||
" \"address\": \"hushaddress\", (string) Shielded address (z-address)\n"
|
||||
" \"address\": \"dragonxaddress\", (string) Shielded address (z-address)\n"
|
||||
" \"amount\": x.xxxx, (numeric) Value of output being received " + CURRENCY_UNIT + ", positive for receives\n"
|
||||
" \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
|
||||
" \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
|
||||
@@ -3535,12 +3600,12 @@ UniValue z_listsentbyaddress(const UniValue& params, bool fHelp,const CPubKey&)
|
||||
if (fHelp || params.size() > 5 || params.size() == 3)
|
||||
throw runtime_error(
|
||||
"z_listsentbyaddress\n"
|
||||
"\nReturns decrypted Hush outputs sent to a single address.\n"
|
||||
"\nReturns decrypted DragonX outputs sent to a single address.\n"
|
||||
"\n"
|
||||
"This function only returns information on addresses sent from wallet addresses with full spending keys."
|
||||
"\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"hushaddress:\" (string, required) \n"
|
||||
"1. \"dragonxaddress:\" (string, required) \n"
|
||||
"\n"
|
||||
"2. \"Minimum Confimations:\" (numeric, optional, default=0) \n"
|
||||
"\n"
|
||||
@@ -3578,13 +3643,13 @@ UniValue z_listsentbyaddress(const UniValue& params, bool fHelp,const CPubKey&)
|
||||
" \"sends\": { A list of outputs of where funds were sent to in the transaction,\n"
|
||||
" only available if the transaction has valid sends (inputs) belonging to the wallet\n"
|
||||
" \"transparentSends\": [{ An Array of spends (outputs) for transparent addresses of the receipient\n"
|
||||
" \"address\": \"hushaddress\", (string) Hush transparent address (t-address)\n"
|
||||
" \"scriptPubKey\": \"script\", (string) Script for the Hush transparent address (t-address)\n"
|
||||
" \"address\": \"dragonxaddress\", (string) DragonX transparent address (t-address)\n"
|
||||
" \"scriptPubKey\": \"script\", (string) Script for the DragonX transparent address (t-address)\n"
|
||||
" \"amount\": x.xxxx, (numeric) Value of output being sent " + CURRENCY_UNIT + ", negative for sends\n"
|
||||
" \"vout\": : n, (numeric) the vout value\n"
|
||||
" }],\n"
|
||||
" \"saplingSends\": [{ An Array of spends (outputs) for sapling addresses\n"
|
||||
" \"address\": \"hushaddress\", (string) Hush sapling address (z-address) of the receipient\n"
|
||||
" \"address\": \"dragonxaddress\", (string) DragonX sapling address (z-address) of the receipient\n"
|
||||
" \"amount\": x.xxxx, (numeric) Value of output being sent" + CURRENCY_UNIT + ", negative for sends\n"
|
||||
" \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
|
||||
" \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
|
||||
@@ -4213,7 +4278,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
string address = o.get_str();
|
||||
auto zaddr = DecodePaymentAddress(address);
|
||||
if (!IsValidPaymentAddress(zaddr)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid Hush zaddr: ") + address);
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid DragonX zaddr: ") + address);
|
||||
}
|
||||
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
||||
if (!fIncludeWatchonly && !hasSpendingKey) {
|
||||
@@ -4598,7 +4663,6 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK
|
||||
obj.push_back(Pair("outindex", (int)entry.op.n));
|
||||
obj.push_back(Pair("rawconfirmations", entry.confirmations));
|
||||
auto wtx = pwalletMain->mapWallet.at(entry.op.hash); //.ToString());
|
||||
//fprintf(stderr,"%s: txid=%s not found in wallet!\n", __func__, entry.op.hash.ToString().c_str());
|
||||
obj.push_back(Pair("time", wtx.GetTxTime()));
|
||||
|
||||
obj.push_back(Pair("confirmations", dpowconfs));
|
||||
@@ -4757,7 +4821,7 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& my
|
||||
// getbalance and "getbalance * 1 true" should return the same number
|
||||
// but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
|
||||
// pwalletMain->GetBalance() does not accept min depth parameter
|
||||
// so we use our own method to get balance of utxos, lulzwtfbbq
|
||||
// so we use our own method to get balance of utxos
|
||||
CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
|
||||
CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
|
||||
CAmount nTotalBalance = nBalance + nPrivateBalance;
|
||||
@@ -4793,7 +4857,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp, const CPubKey& my
|
||||
" \"rk\" : \"rk\", (string) The rk\n"
|
||||
" \"zkproof\" : \"zkproof\", (string) Hexadecimal string representation of raw zksnark proof\n"
|
||||
" \"outputPrev\" : n, (numeric) the index of the output within the vShieldedOutput\n"
|
||||
" \"address\" : \"zcashaddress\", (string) The Hush shielded address involved in the transaction\n"
|
||||
" \"address\" : \"dragonxaddress\", (string) The DragonX shielded address involved in the transaction\n"
|
||||
" \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
|
||||
" \"valueZat\" : xxxx (numeric) The amount in puposhis\n"
|
||||
" }\n"
|
||||
@@ -4803,7 +4867,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp, const CPubKey& my
|
||||
" {\n"
|
||||
" \"type\" : \"sapling\", (string) The type of address\n"
|
||||
" \"output\" : n, (numeric) the index of the output within the vShieldedOutput\n"
|
||||
" \"address\" : \"hushaddress\", (string) The Hush address involved in the transaction\n"
|
||||
" \"address\" : \"dragonxaddress\", (string) The DragonX address involved in the transaction\n"
|
||||
" \"outgoing\" : true|false (boolean) True if the output is not for an address in the wallet\n"
|
||||
" \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
|
||||
" \"valueZat\" : xxxx (numeric) The amount in puposhis\n"
|
||||
@@ -5043,186 +5107,96 @@ UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedO
|
||||
#define CTXIN_SPEND_DUST_SIZE 148
|
||||
#define CTXOUT_REGULAR_SIZE 34
|
||||
|
||||
UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
// Resolve the special fromaddress "z" (spend from any zaddr) to a concrete zaddr:
|
||||
// gather this wallet's Sapling notes, pick a random zaddr whose confirmed balance
|
||||
// covers the total outputs + fee. Extracted verbatim from z_sendmany (behavior-
|
||||
// preserving); throws JSONRPCError when no single zaddr has enough funds.
|
||||
static std::string SelectAnyZaddrSource(const UniValue& outputs, const UniValue& params)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
// TODO: refactor this and z_getbalances to use common code
|
||||
std::set<libzcash::PaymentAddress> zaddrs = {};
|
||||
std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
|
||||
pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
|
||||
|
||||
if (fHelp || params.size() < 2 || params.size() > 5)
|
||||
throw runtime_error(
|
||||
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee ) (opreturn)\n"
|
||||
"\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
|
||||
"\nChange generated from a taddr flows to a new taddr address, while change generated from a zaddr returns to itself."
|
||||
"\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from. Use 'z' to spend from any zaddr.\n"
|
||||
"2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
|
||||
" [{\n"
|
||||
" \"address\":address (string, required) The address is a taddr or zaddr\n"
|
||||
" \"amount\":amount (numeric, required) The amount to send this address\n"
|
||||
" \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
|
||||
" }, ... ]\n"
|
||||
"3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
|
||||
"4. fee (numeric, optional, default="
|
||||
+ strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
|
||||
"5. opreturn (string, optional) Hex encoded data for OP_RETURN. Or a utf8 string prefixed with 'utf8:' which will be automatically converted to hex\n"
|
||||
"\nResult:\n"
|
||||
"\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 5.0}]'")
|
||||
+ HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 5.0}]")
|
||||
+ HelpExampleCli("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]'")
|
||||
+ HelpExampleRpc("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\", [{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]")
|
||||
+ HelpExampleCli("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]' 1 0.0001 \"utf8: this will be converted to hex")
|
||||
+ HelpExampleRpc("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]' 1 0.0001 \"utf8: this will be converted to hex")
|
||||
);
|
||||
zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
int nMinDepth = 1;
|
||||
std::vector<SaplingNoteEntry> saplingEntries;
|
||||
pwalletMain->GetFilteredNotes(saplingEntries, zaddrs, nMinDepth);
|
||||
|
||||
// Hilarious that Komodo commented this out, opening themselves up to metadata attackz, lulz
|
||||
THROW_IF_SYNCING(HUSH_INSYNC);
|
||||
|
||||
// Check that the from address is valid.
|
||||
auto fromaddress = params[0].get_str();
|
||||
bool fromTaddr = false;
|
||||
bool fromSapling = false;
|
||||
uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
|
||||
UniValue outputs = params[1].get_array();
|
||||
|
||||
if (outputs.size()==0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
|
||||
|
||||
// TODO: implement special symbolic fromaddrs
|
||||
// TODO: list of (zaddr,amount)
|
||||
// "z" => spend from any zaddr
|
||||
// "t" => spend from any taddr
|
||||
// "*" => spend from any addr, zaddrs first
|
||||
if(fromaddress == "z") {
|
||||
// TODO: refactor this and z_getbalances to use common code
|
||||
std::set<libzcash::PaymentAddress> zaddrs = {};
|
||||
std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
|
||||
pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
|
||||
|
||||
zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
|
||||
|
||||
int nMinDepth = 1;
|
||||
std::vector<SaplingNoteEntry> saplingEntries;
|
||||
pwalletMain->GetFilteredNotes(saplingEntries, zaddrs, nMinDepth);
|
||||
|
||||
std::map<std::string, CAmount> mapBalances;
|
||||
for (auto & entry : saplingEntries) {
|
||||
auto zaddr = EncodePaymentAddress(entry.address);
|
||||
CAmount nBalance = CAmount(entry.note.value());
|
||||
if(mapBalances.count(zaddr)) {
|
||||
mapBalances[zaddr] += nBalance;
|
||||
} else {
|
||||
mapBalances[zaddr] = nBalance;
|
||||
}
|
||||
}
|
||||
std::vector<std::pair<std::string,CAmount>> vec;
|
||||
std::copy(mapBalances.begin(), mapBalances.end(), std::back_inserter<std::vector<std::pair<std::string,CAmount>>>(vec));
|
||||
|
||||
std::sort(vec.begin(), vec.end(), [](const std::pair<std::string, CAmount> &l, const std::pair<std::string,CAmount> &r)
|
||||
{
|
||||
if (l.second != r.second) {
|
||||
return l.second > r.second;
|
||||
}
|
||||
return l.first > r.first;
|
||||
});
|
||||
|
||||
//TODO: avoid calculating nTotalOut twice
|
||||
CAmount nTotalOut = 0;
|
||||
for (const UniValue& o : outputs.getValues()) {
|
||||
if (!o.isObject())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
|
||||
|
||||
UniValue av = find_value(o, "amount");
|
||||
CAmount nAmount = AmountFromValue( av );
|
||||
if (nAmount < 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
|
||||
|
||||
nTotalOut += nAmount;
|
||||
}
|
||||
|
||||
//GOAL: choose one random zaddress with enough funds
|
||||
CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE; // default when params.size()<=3 (was uninitialized)
|
||||
if (params.size() > 3) {
|
||||
if (params[3].get_real() == 0.0) {
|
||||
nFee = 0;
|
||||
} else {
|
||||
nFee = AmountFromValue( params[3] );
|
||||
}
|
||||
}
|
||||
|
||||
// the total amount needed in a single zaddr to use as fromaddress
|
||||
CAmount nMinBal = nTotalOut + nFee;
|
||||
|
||||
std::vector<std::string> vPotentialAddresses;
|
||||
for (auto & entry : vec) {
|
||||
if(entry.second >= nMinBal) {
|
||||
vPotentialAddresses.push_back(entry.first);
|
||||
}
|
||||
}
|
||||
|
||||
// select a random address with enough confirmed balance
|
||||
auto nPotentials = vPotentialAddresses.size();
|
||||
if (nPotentials > 0) {
|
||||
fprintf(stderr,"%s: Selecting one of %lu potential source zaddrs\n", __func__, nPotentials);
|
||||
fromaddress = vPotentialAddresses[ GetRandInt(nPotentials) ];
|
||||
std::map<std::string, CAmount> mapBalances;
|
||||
for (auto & entry : saplingEntries) {
|
||||
auto zaddr = EncodePaymentAddress(entry.address);
|
||||
CAmount nBalance = CAmount(entry.note.value());
|
||||
if(mapBalances.count(zaddr)) {
|
||||
mapBalances[zaddr] += nBalance;
|
||||
} else {
|
||||
// Automagic zaddr source selection failed, exit honorably
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "No single zaddr currently has enough funds to make that transaction, you may need to wait for confirmations.");
|
||||
}
|
||||
} else {
|
||||
CTxDestination taddr = DecodeDestination(fromaddress);
|
||||
fromTaddr = IsValidDestination(taddr);
|
||||
if (!fromTaddr) {
|
||||
auto res = DecodePaymentAddress(fromaddress);
|
||||
if (!IsValidPaymentAddress(res, branchId)) {
|
||||
// invalid
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
||||
}
|
||||
|
||||
// Check that we have the spending key
|
||||
if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), res)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
|
||||
}
|
||||
|
||||
// Remember whether this is a Sapling address
|
||||
fromSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
|
||||
mapBalances[zaddr] = nBalance;
|
||||
}
|
||||
}
|
||||
std::vector<std::pair<std::string,CAmount>> vec;
|
||||
std::copy(mapBalances.begin(), mapBalances.end(), std::back_inserter<std::vector<std::pair<std::string,CAmount>>>(vec));
|
||||
|
||||
std::sort(vec.begin(), vec.end(), [](const std::pair<std::string, CAmount> &l, const std::pair<std::string,CAmount> &r)
|
||||
{
|
||||
if (l.second != r.second) {
|
||||
return l.second > r.second;
|
||||
}
|
||||
return l.first > r.first;
|
||||
});
|
||||
|
||||
// Recipients
|
||||
std::vector<SendManyRecipient> taddrRecipients;
|
||||
std::vector<SendManyRecipient> zaddrRecipients;
|
||||
//TODO: avoid calculating nTotalOut twice
|
||||
CAmount nTotalOut = 0;
|
||||
// Optional OP_RETURN data
|
||||
CScript opret;
|
||||
UniValue opretValue;
|
||||
if(params.size() == 5) {
|
||||
opretValue = params[4].get_str();
|
||||
for (const UniValue& o : outputs.getValues()) {
|
||||
if (!o.isObject())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
|
||||
|
||||
// Support a prefix "utf8:" which allows giving utf8 text instead of hex
|
||||
if(opretValue.get_str().substr(0,5) == "utf8:") {
|
||||
auto str = opretValue.get_str().substr(5);
|
||||
if (utf8::is_valid(str)) {
|
||||
opretValue = HexStr(str);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid utf8 in opreturn");
|
||||
}
|
||||
UniValue av = find_value(o, "amount");
|
||||
CAmount nAmount = AmountFromValue( av );
|
||||
if (nAmount < 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
|
||||
|
||||
nTotalOut += nAmount;
|
||||
}
|
||||
|
||||
//GOAL: choose one random zaddress with enough funds
|
||||
CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE; // default when params.size()<=3 (was uninitialized)
|
||||
if (params.size() > 3) {
|
||||
if (params[3].get_real() == 0.0) {
|
||||
nFee = 0;
|
||||
} else {
|
||||
nFee = AmountFromValue( params[3] );
|
||||
}
|
||||
}
|
||||
|
||||
bool containsSaplingOutput = false;
|
||||
// the total amount needed in a single zaddr to use as fromaddress
|
||||
CAmount nMinBal = nTotalOut + nFee;
|
||||
|
||||
// Create the CScript representation of the OP_RETURN
|
||||
if (!opretValue.isNull()) {
|
||||
opret << OP_RETURN << ParseHex(opretValue.get_str().c_str());
|
||||
std::vector<std::string> vPotentialAddresses;
|
||||
for (auto & entry : vec) {
|
||||
if(entry.second >= nMinBal) {
|
||||
vPotentialAddresses.push_back(entry.first);
|
||||
}
|
||||
}
|
||||
|
||||
// select a random address with enough confirmed balance
|
||||
auto nPotentials = vPotentialAddresses.size();
|
||||
if (nPotentials > 0) {
|
||||
LogPrintf("%s: Selecting one of %lu potential source zaddrs\n", __func__, nPotentials);
|
||||
return vPotentialAddresses[ GetRandInt(nPotentials) ];
|
||||
}
|
||||
// Automagic zaddr source selection failed, exit honorably
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "No single zaddr currently has enough funds to make that transaction, you may need to wait for confirmations.");
|
||||
}
|
||||
|
||||
// Parse and validate the z_sendmany "outputs" array into taddr/zaddr recipient lists
|
||||
// (accumulating nTotalOut). Extracted verbatim from z_sendmany; throws JSONRPCError on
|
||||
// any malformed entry (unknown key, bad address, memo misuse/oversize, negative amount).
|
||||
static void ParseSendManyRecipients(const UniValue& outputs, uint32_t branchId,
|
||||
std::vector<SendManyRecipient>& taddrRecipients,
|
||||
std::vector<SendManyRecipient>& zaddrRecipients,
|
||||
CAmount& nTotalOut)
|
||||
{
|
||||
for (const UniValue& o : outputs.getValues()) {
|
||||
if (!o.isObject())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
|
||||
@@ -5284,6 +5258,116 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
|
||||
nTotalOut += nAmount;
|
||||
}
|
||||
}
|
||||
|
||||
UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (fHelp || params.size() < 2 || params.size() > 5)
|
||||
throw runtime_error(
|
||||
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee ) (opreturn)\n"
|
||||
"\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
|
||||
"\nChange generated from a taddr flows to a new taddr address, while change generated from a zaddr returns to itself."
|
||||
"\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from. Use 'z' to spend from any zaddr.\n"
|
||||
"2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
|
||||
" [{\n"
|
||||
" \"address\":address (string, required) The address is a taddr or zaddr\n"
|
||||
" \"amount\":amount (numeric, required) The amount to send this address\n"
|
||||
" \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
|
||||
" }, ... ]\n"
|
||||
"3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
|
||||
"4. fee (numeric, optional, default="
|
||||
+ strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
|
||||
"5. opreturn (string, optional) Hex encoded data for OP_RETURN. Or a utf8 string prefixed with 'utf8:' which will be automatically converted to hex\n"
|
||||
"\nResult:\n"
|
||||
"\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 5.0}]'")
|
||||
+ HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 5.0}]")
|
||||
+ HelpExampleCli("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]'")
|
||||
+ HelpExampleRpc("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\", [{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]")
|
||||
+ HelpExampleCli("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]' 1 0.0001 \"utf8: this will be converted to hex")
|
||||
+ HelpExampleRpc("z_sendmany", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 3.14}]' 1 0.0001 \"utf8: this will be converted to hex")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Guard against building shielded transactions before the chain is fully synced;
|
||||
// sending while behind the tip can leak metadata usable for linkability analysis.
|
||||
THROW_IF_SYNCING(HUSH_INSYNC);
|
||||
|
||||
// Check that the from address is valid.
|
||||
auto fromaddress = params[0].get_str();
|
||||
bool fromTaddr = false;
|
||||
bool fromSapling = false;
|
||||
uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
|
||||
UniValue outputs = params[1].get_array();
|
||||
|
||||
if (outputs.size()==0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
|
||||
|
||||
// TODO: implement special symbolic fromaddrs
|
||||
// TODO: list of (zaddr,amount)
|
||||
// "z" => spend from any zaddr
|
||||
// "t" => spend from any taddr
|
||||
// "*" => spend from any addr, zaddrs first
|
||||
if(fromaddress == "z") {
|
||||
fromaddress = SelectAnyZaddrSource(outputs, params);
|
||||
} else {
|
||||
CTxDestination taddr = DecodeDestination(fromaddress);
|
||||
fromTaddr = IsValidDestination(taddr);
|
||||
if (!fromTaddr) {
|
||||
auto res = DecodePaymentAddress(fromaddress);
|
||||
if (!IsValidPaymentAddress(res, branchId)) {
|
||||
// invalid
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
||||
}
|
||||
|
||||
// Check that we have the spending key
|
||||
if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), res)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
|
||||
}
|
||||
|
||||
// Remember whether this is a Sapling address
|
||||
fromSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Recipients
|
||||
std::vector<SendManyRecipient> taddrRecipients;
|
||||
std::vector<SendManyRecipient> zaddrRecipients;
|
||||
CAmount nTotalOut = 0;
|
||||
// Optional OP_RETURN data
|
||||
CScript opret;
|
||||
UniValue opretValue;
|
||||
if(params.size() == 5) {
|
||||
opretValue = params[4].get_str();
|
||||
|
||||
// Support a prefix "utf8:" which allows giving utf8 text instead of hex
|
||||
if(opretValue.get_str().substr(0,5) == "utf8:") {
|
||||
auto str = opretValue.get_str().substr(5);
|
||||
if (utf8::is_valid(str)) {
|
||||
opretValue = HexStr(str);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid utf8 in opreturn");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool containsSaplingOutput = false;
|
||||
|
||||
// Create the CScript representation of the OP_RETURN
|
||||
if (!opretValue.isNull()) {
|
||||
opret << OP_RETURN << ParseHex(opretValue.get_str().c_str());
|
||||
}
|
||||
|
||||
ParseSendManyRecipients(outputs, branchId, taddrRecipients, zaddrRecipients, nTotalOut);
|
||||
|
||||
std::vector<SaplingNoteEntry> saplingEntries;
|
||||
// find all unspent and unlocked notes in this zaddr
|
||||
@@ -5325,12 +5409,15 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
// SIETCH: Sprinkle our cave with some magic privacy zdust
|
||||
// End goal is to have this be as large as possible without slowing xtns down too much
|
||||
// A value of 7 will provide much stronger linkability privacy versus pre-Sietch operations
|
||||
// DEFAULT_MIN_ZOUTS (7): default number of dummy z-outputs padded onto each z_sendmany.
|
||||
// MAX_ZOUTS (50): upper bound for the operator-tunable -sietch-min-zouts arg.
|
||||
// The effective floor is clamped to [3, MAX_ZOUTS] below.
|
||||
unsigned int DEFAULT_MIN_ZOUTS=7;
|
||||
unsigned int MAX_ZOUTS=50;
|
||||
unsigned int MIN_ZOUTS=GetArg("--sietch-min-zouts", DEFAULT_MIN_ZOUTS);
|
||||
unsigned int MIN_ZOUTS=GetArg("-sietch-min-zouts", DEFAULT_MIN_ZOUTS);
|
||||
|
||||
if((MIN_ZOUTS<3) || (MIN_ZOUTS>MAX_ZOUTS)) {
|
||||
fprintf(stderr,"%s: Sietch min zouts must be >= 3 and <= %d, setting to default value of %d\n", __FUNCTION__, MAX_ZOUTS, DEFAULT_MIN_ZOUTS );
|
||||
LogPrintf("%s: Sietch min zouts must be >= 3 and <= %d, setting to default value of %d\n", __FUNCTION__, MAX_ZOUTS, DEFAULT_MIN_ZOUTS );
|
||||
MIN_ZOUTS=DEFAULT_MIN_ZOUTS;
|
||||
}
|
||||
|
||||
@@ -5394,9 +5481,8 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
txsize += GetSerializeSize(tx, SER_NETWORK, tx.nVersion);
|
||||
if (fromTaddr) {
|
||||
txsize += CTXIN_SPEND_DUST_SIZE;
|
||||
//TODO: On HUSH since block 340k there can no longer be taddr change,
|
||||
// (except for notary addresses)
|
||||
// so we can likely make a better estimation of max txsize
|
||||
// DragonX is ac_private=1 (fully shielded from genesis); transparent outputs are
|
||||
// banned, so in practice there is no taddr change and this estimate is conservative.
|
||||
txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
|
||||
}
|
||||
txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
|
||||
@@ -5466,7 +5552,10 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
// Create operation and add to global queue
|
||||
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(builder, contextualTx, fromaddress, taddrRecipients, zaddrRecipients, saplingNoteInputs, nMinDepth, nFee, contextInfo, opret) );
|
||||
q->addOperation(operation);
|
||||
if (!q->addOperation(operation)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR,
|
||||
"Async RPC queue is shutting down; the operation was not queued");
|
||||
}
|
||||
|
||||
if(fZdebug)
|
||||
LogPrintf("%s: Submitted to async queue\n", __FUNCTION__);
|
||||
@@ -5528,7 +5617,8 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Hilarious that Komodo commented this out, opening themselves up to metadata attackz, lulz
|
||||
// Guard against building shielded transactions before the chain is fully synced;
|
||||
// sending while behind the tip can leak metadata usable for linkability analysis.
|
||||
THROW_IF_SYNCING(HUSH_INSYNC);
|
||||
|
||||
// Validate the from address
|
||||
@@ -5694,7 +5784,13 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
// Create operation and add to global queue
|
||||
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(builder, contextualTx, inputs, destaddress, nFee, donation, contextInfo) );
|
||||
q->addOperation(operation);
|
||||
// The constructor has already locked the selected coins. Coin locks are
|
||||
// memory-only, so a refused queue at shutdown reclaims them with the process;
|
||||
// what must not happen is returning an opid for work that will never run.
|
||||
if (!q->addOperation(operation)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR,
|
||||
"Async RPC queue is shutting down; the operation was not queued");
|
||||
}
|
||||
AsyncRPCOperationId operationId = operation->getId();
|
||||
|
||||
// Return continuation information
|
||||
@@ -5768,7 +5864,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Hilarious that Komodo commented this out, opening themselves up to metadata attackz, lulz
|
||||
// Guard against building shielded transactions before the chain is fully synced;
|
||||
// sending while behind the tip can leak metadata usable for linkability analysis.
|
||||
THROW_IF_SYNCING(HUSH_INSYNC);
|
||||
|
||||
bool useAnyUTXO = false;
|
||||
@@ -5939,8 +6036,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
|
||||
if (maximum_utxo_size != 0) {
|
||||
//fprintf(stderr, "utxo txid.%s vout.%i nValue.%li scriptpubkeylength.%i\n",out.tx->GetHash().ToString().c_str(),out.i,nValue,out.tx->vout[out.i].scriptPubKey.size());
|
||||
if (nValue > maximum_utxo_size)
|
||||
if (nValue > maximum_utxo_size)
|
||||
continue;
|
||||
if (nValue == 10000 && out.tx->vout[out.i].scriptPubKey.size() == 35)
|
||||
continue;
|
||||
@@ -6001,7 +6097,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
size_t numUtxos = utxoInputs.size();
|
||||
size_t numNotes = saplingNoteInputs.size();
|
||||
|
||||
//fprintf(stderr, "num utxos.%li\n", numUtxos);
|
||||
if (numUtxos < 2 && numNotes == 0) {
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
|
||||
}
|
||||
@@ -6048,7 +6143,10 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
||||
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
||||
std::shared_ptr<AsyncRPCOperation> operation(
|
||||
new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, saplingNoteInputs, recipient, nFee, contextInfo) );
|
||||
q->addOperation(operation);
|
||||
if (!q->addOperation(operation)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR,
|
||||
"Async RPC queue is shutting down; the operation was not queued");
|
||||
}
|
||||
AsyncRPCOperationId operationId = operation->getId();
|
||||
|
||||
// Return continuation information
|
||||
@@ -6159,7 +6257,6 @@ int32_t hush_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33, void *pT
|
||||
script = (uint8_t *)&out.tx->vout[out.i].scriptPubKey[0];
|
||||
if ( out.tx->vout[out.i].scriptPubKey.size() != 35 || script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(notarypub33,script+1,33) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"scriptsize.%d [0] %02x\n",(int32_t)out.tx->vout[out.i].scriptPubKey.size(),script[0]);
|
||||
continue;
|
||||
}
|
||||
utxovalue = (uint64_t)nValue;
|
||||
@@ -6167,7 +6264,6 @@ int32_t hush_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33, void *pT
|
||||
utxotxid = out.tx->GetHash();
|
||||
utxovout = out.i;
|
||||
best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
|
||||
//fprintf(stderr,"check %s/v%d %llu\n",(char *)utxotxid.GetHex().c_str(),utxovout,(long long)utxovalue);
|
||||
|
||||
txNew.vin.resize(1);
|
||||
txNew.vout.resize((pTr!=0)+1);
|
||||
@@ -6188,15 +6284,14 @@ int32_t hush_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33, void *pT
|
||||
CTransaction txNewConst(txNew);
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
|
||||
if (!signSuccess)
|
||||
fprintf(stderr,"notaryvin failed to create signature\n");
|
||||
LogPrintf("notaryvin failed to create signature\n");
|
||||
else
|
||||
{
|
||||
UpdateTransaction(txNew,0,sigdata);
|
||||
ptr = (uint8_t *)&sigdata.scriptSig[0];
|
||||
siglen = sigdata.scriptSig.size();
|
||||
for (i=0; i<siglen; i++)
|
||||
utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
|
||||
//fprintf(stderr," siglen.%d notaryvin %s/v%d\n",siglen,utxotxid.GetHex().c_str(),utxovout);
|
||||
utxosig[i] = ptr[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -6349,6 +6444,7 @@ static const CRPCCommand commands[] =
|
||||
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
||||
{ "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
|
||||
{ "wallet", "z_sweepstatus", &z_sweepstatus, true },
|
||||
{ "wallet", "z_autoshieldstatus", &z_autoshieldstatus, true },
|
||||
{ "wallet", "z_consolidationstatus", &z_consolidationstatus, true },
|
||||
{ "wallet", "z_sendmany", &z_sendmany, false },
|
||||
{ "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false },
|
||||
|
||||
@@ -578,7 +578,7 @@ void CWallet::ChainTip(const CBlockIndex *pindex,
|
||||
}
|
||||
|
||||
void CWallet::RunSaplingSweep(int blockHeight) {
|
||||
// Sapling is always active since height=1 of HUSH+HACs
|
||||
// Sapling is always active since height=1 on DragonX
|
||||
// if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
|
||||
// return;
|
||||
// }
|
||||
@@ -592,6 +592,31 @@ void CWallet::RunSaplingSweep(int blockHeight) {
|
||||
// masked an unsynchronized mutation.) cs_wallet is recursive, so this is
|
||||
// safe even on any path that already holds it.
|
||||
LOCK(cs_wallet);
|
||||
|
||||
// Stale-baton guard. A successful-but-incomplete sweep round deliberately
|
||||
// returns with fSweepRunning still set and nextSweep unadvanced (see
|
||||
// AsyncRPCOperation_sweep::main), as a "continue draining next block" baton.
|
||||
// But every early return below leaves that baton set WITHOUT re-dispatching,
|
||||
// and RunSaplingConsolidation -- which is gated on fSweepRunning -- then
|
||||
// returns without advancing nextConsolidation, so the "consolidation is
|
||||
// within 5 blocks" blackout at the top of this function never lifts. That
|
||||
// is a self-sustaining three-way deadlock: sweep waits on consolidation,
|
||||
// consolidation waits on sweep, and autoshield shares the same gate, so a
|
||||
// wedged sweep silently disables coinbase shielding forever.
|
||||
// Only honour the baton while a sweep operation genuinely is in flight.
|
||||
if (fSweepRunning) {
|
||||
std::shared_ptr<AsyncRPCQueue> sweepQueue = getAsyncRPCQueue();
|
||||
std::shared_ptr<AsyncRPCOperation> inFlightSweep =
|
||||
(sweepQueue != nullptr) ? sweepQueue->getOperationForId(saplingSweepOperationId) : nullptr;
|
||||
bool inFlight = (inFlightSweep != nullptr) &&
|
||||
(inFlightSweep->isReady() || inFlightSweep->isExecuting());
|
||||
if (!inFlight) {
|
||||
LogPrintf("%s: clearing stale fSweepRunning at blockHeight=%d (no sweep operation in flight)\n",
|
||||
__func__, blockHeight);
|
||||
fSweepRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fSweepEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -626,15 +651,25 @@ void CWallet::RunSaplingSweep(int blockHeight) {
|
||||
std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingSweepOperationId);
|
||||
if (lastOperation != nullptr) {
|
||||
lastOperation->cancel();
|
||||
// Drop it from the queue's map as well. Nothing else ever removes these:
|
||||
// popOperationForId is only reached from z_getoperationresult, so on a node
|
||||
// running this every interval the map grew without bound.
|
||||
q->popOperationForId(saplingSweepOperationId);
|
||||
}
|
||||
pendingSaplingSweepTxs.clear();
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sweep(blockHeight + 5));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sweep(blockHeight + AUTO_OP_TARGET_HEIGHT_OFFSET));
|
||||
saplingSweepOperationId = operation->getId();
|
||||
q->addOperation(operation);
|
||||
if (!q->addOperation(operation)) {
|
||||
// Queue is closing (shutdown). Release the flag we just set, or it stays
|
||||
// set with no operation in flight and blocks every later round.
|
||||
LogPrintf("%s: async queue is not accepting operations; skipping this round\n", __func__);
|
||||
fSweepRunning = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::RunSaplingConsolidation(int blockHeight) {
|
||||
// Sapling is always active on HUSH+HACs
|
||||
// Sapling is always active on DragonX (activated at height=1)
|
||||
//if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
|
||||
// return;
|
||||
//}
|
||||
@@ -674,11 +709,21 @@ void CWallet::RunSaplingConsolidation(int blockHeight) {
|
||||
std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingConsolidationOperationId);
|
||||
if (lastOperation != nullptr) {
|
||||
lastOperation->cancel();
|
||||
// Drop it from the queue's map as well. Nothing else ever removes these:
|
||||
// popOperationForId is only reached from z_getoperationresult, so on a node
|
||||
// running this every interval the map grew without bound.
|
||||
q->popOperationForId(saplingConsolidationOperationId);
|
||||
}
|
||||
pendingSaplingConsolidationTxs.clear();
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_saplingconsolidation(blockHeight + 5));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_saplingconsolidation(blockHeight + AUTO_OP_TARGET_HEIGHT_OFFSET));
|
||||
saplingConsolidationOperationId = operation->getId();
|
||||
q->addOperation(operation);
|
||||
if (!q->addOperation(operation)) {
|
||||
// Queue is closing (shutdown). Release the flag we just set, or it stays
|
||||
// set with no operation in flight and blocks every later round.
|
||||
LogPrintf("%s: async queue is not accepting operations; skipping this round\n", __func__);
|
||||
fConsolidationRunning = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Periodically drain matured transparent coinbase into a wallet-owned Sapling
|
||||
@@ -729,16 +774,28 @@ void CWallet::RunAutoShieldCoinbase(int blockHeight) {
|
||||
std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingAutoShieldOperationId);
|
||||
if (lastOperation != nullptr) {
|
||||
lastOperation->cancel();
|
||||
// Drop it from the queue's map as well. Nothing else ever removes these:
|
||||
// popOperationForId is only reached from z_getoperationresult, so on a node
|
||||
// running this every interval the map grew without bound.
|
||||
q->popOperationForId(saplingAutoShieldOperationId);
|
||||
}
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_autoshieldcoinbase(blockHeight + 5));
|
||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_autoshieldcoinbase(blockHeight + AUTO_OP_TARGET_HEIGHT_OFFSET));
|
||||
saplingAutoShieldOperationId = operation->getId();
|
||||
q->addOperation(operation);
|
||||
if (!q->addOperation(operation)) {
|
||||
// Queue is closing (shutdown). Release the flag we just set, or it stays
|
||||
// set with no operation in flight and blocks every later round.
|
||||
LogPrintf("%s: async queue is not accepting operations; skipping this round\n", __func__);
|
||||
fAutoShieldRunning = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool CWallet::CommitAutomatedTx(const CTransaction& tx) {
|
||||
CWalletTx wtx(this, tx);
|
||||
CReserveKey reservekey(pwalletMain);
|
||||
fprintf(stderr,"%s: %s\n",__func__,tx.ToString().c_str());
|
||||
// No tx dump here: CommitTransaction already LogPrintf's the same wtx.ToString(),
|
||||
// and ToString() emits a line per vin, so with the 400-input autoshield cap this
|
||||
// printed tens of KB to stderr on every automated round.
|
||||
return CommitTransaction(wtx, reservekey);
|
||||
}
|
||||
|
||||
@@ -1103,9 +1160,6 @@ int64_t CWallet::NullifierCount()
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
if(fZdebug) {
|
||||
//fprintf(stderr,"%s:mapTxSaplingNullifers.size=%d\n",__FUNCTION__,(int)mapTxSaplingNullifiers.size() );
|
||||
//fprintf(stderr,"%s:mempool.getNullifiers.size=%d\n",__FUNCTION__,(int)mempool.getNullifiers().size() );
|
||||
//fprintf(stderr,"%s:cacheSaplingNullifiers.size=%d\n",__FUNCTION__,(int)pcoinsTip->getNullifiers().size() );
|
||||
}
|
||||
return pcoinsTip->getNullifiers().size();
|
||||
}
|
||||
@@ -1652,7 +1706,6 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries,
|
||||
{
|
||||
CWalletTx* wtx = &((*it).second);
|
||||
txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
|
||||
//fprintf(stderr,"ordered iter.%d %s\n",(int32_t)wtx->nOrderPos,wtx->GetHash().GetHex().c_str());
|
||||
}
|
||||
acentries.clear();
|
||||
walletdb.ListAccountCreditDebit(strAccount, acentries);
|
||||
@@ -1959,9 +2012,9 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
|
||||
vAllowListAddress = mapMultiArgs["-allowlistaddress"];
|
||||
if ( !vAllowListAddress.empty() )
|
||||
{
|
||||
fprintf(stderr, "Activated Wallet Filter \n Notary Address: %s \n Adding allowlist address's:\n", NotaryAddress.c_str());
|
||||
LogPrintf("Activated Wallet Filter \n Notary Address: %s \n Adding allowlist address's:\n", NotaryAddress.c_str());
|
||||
for ( auto wladdr : vAllowListAddress )
|
||||
fprintf(stderr, " %s\n", wladdr.c_str());
|
||||
LogPrintf(" %s\n", wladdr.c_str());
|
||||
}
|
||||
}
|
||||
if (fExisted || IsMine(tx) || IsFromMe(tx) || saplingNoteData.size() > 0) {
|
||||
@@ -1979,7 +2032,6 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
|
||||
{
|
||||
if ( CBitcoinAddress(address).ToString() == wladdr )
|
||||
{
|
||||
//fprintf(stderr, "We received from allowlisted address.%s\n", wladdr.c_str());
|
||||
numvinIsAllowList++;
|
||||
}
|
||||
}
|
||||
@@ -1987,7 +2039,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
|
||||
}
|
||||
// Now we know if it was a tx sent to us, by either a allowlisted address, or ourself.
|
||||
if ( numvinIsOurs != 0 )
|
||||
fprintf(stderr, "We sent from address: %s vins: %d\n",NotaryAddress.c_str(),numvinIsOurs);
|
||||
LogPrintf("We sent from address: %s vins: %d\n",NotaryAddress.c_str(),numvinIsOurs);
|
||||
if ( numvinIsOurs == 0 && numvinIsAllowList == 0 )
|
||||
return false;
|
||||
}
|
||||
@@ -2328,7 +2380,7 @@ isminetype CWallet::IsMine(const CTransaction& tx, uint32_t voutNum)
|
||||
|
||||
case TX_SCRIPTHASH:
|
||||
scriptID = CScriptID(uint160(vSolutions[0]));
|
||||
//TODO: remove CLTV stuff not relevant to Hush
|
||||
//TODO: evaluate whether this CLTV timelock handling is needed on DragonX
|
||||
if (this->GetCScript(scriptID, subscript))
|
||||
{
|
||||
// if this is a CLTV, handle it differently
|
||||
@@ -2990,14 +3042,12 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
|
||||
{
|
||||
if ( oneshot++ > 1 )
|
||||
{
|
||||
//fprintf(stderr,"skip change vout\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(fIsMine & filter))
|
||||
{
|
||||
//fprintf(stderr,"skip filtered vout %d %d\n",(int32_t)fIsMine,(int32_t)filter);
|
||||
continue;
|
||||
}
|
||||
// In either case, we need to get the destination address
|
||||
@@ -3518,7 +3568,6 @@ void CWallet::ReacceptWalletTransactions()
|
||||
bool invalid = state.IsInvalid(nDoS);
|
||||
|
||||
// log rejection and deletion
|
||||
//printf("ERROR reaccepting wallet transaction %s to mempool, reason: %s, DoS: %d\n", wtx.GetHash().ToString().c_str(), state.GetRejectReason().c_str(), nDoS);
|
||||
|
||||
if (!wtx.IsCoinBase() && invalid && nDoS > 0 && state.GetRejectReason() != "tx-overwinter-expired")
|
||||
{
|
||||
@@ -3536,11 +3585,8 @@ void CWallet::ReacceptWalletTransactions()
|
||||
bool CWalletTx::RelayWalletTransaction()
|
||||
{
|
||||
int64_t nNow = GetTime();
|
||||
//if(fZdebug)
|
||||
// LogPrintf("%s: now=%li\n",__func__,nNow);
|
||||
if ( pwallet == 0 )
|
||||
{
|
||||
//fprintf(stderr,"unexpected null pwallet in RelayWalletTransaction\n");
|
||||
return(false);
|
||||
}
|
||||
assert(pwallet->GetBroadcastTransactions());
|
||||
@@ -3778,7 +3824,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
|
||||
// Do not relay expired transactions, to avoid other nodes banning us
|
||||
// Current code will not ban nodes relaying expired txs but older nodes will
|
||||
if (wtx.nExpiryHeight > 0 && wtx.nExpiryHeight < chainActive.LastTip()->GetHeight()) {
|
||||
fprintf(stderr,"%s: ignoring expired tx %s with expiry %d at height %d\n", __func__, wtx.GetHash().ToString().c_str(), wtx.nExpiryHeight, chainActive.LastTip()->GetHeight() );
|
||||
LogPrintf("%s: ignoring expired tx %s with expiry %d at height %d\n", __func__, wtx.GetHash().ToString().c_str(), wtx.nExpiryHeight, chainActive.LastTip()->GetHeight() );
|
||||
// TODO: expired detection doesn't seem to work right
|
||||
// append to list of txs to delete
|
||||
// vwtxh.push_back(wtx.GetHash());
|
||||
@@ -4099,7 +4145,6 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
|
||||
nTotalLower += n;
|
||||
if ( nTotalLower > 4*nTargetValue + CENT )
|
||||
{
|
||||
//fprintf(stderr,"why bother with all the utxo if we have double what is needed?\n");
|
||||
break;
|
||||
}
|
||||
} else if (n < coinLowestLarger.first)
|
||||
@@ -4302,7 +4347,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC
|
||||
bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
|
||||
int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
|
||||
{
|
||||
uint64_t interest2 = 0; CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0;
|
||||
CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0;
|
||||
BOOST_FOREACH (const CRecipient& recipient, vecSend)
|
||||
{
|
||||
if (nValue < 0 || recipient.nAmount < 0)
|
||||
@@ -4423,7 +4468,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||
CAmount nValueIn = 0;
|
||||
bool fOnlyCoinbaseCoins = false;
|
||||
bool fNeedCoinbaseCoins = false;
|
||||
interest2 = 0;
|
||||
if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyCoinbaseCoins, fNeedCoinbaseCoins, coinControl))
|
||||
{
|
||||
if (fOnlyCoinbaseCoins && Params().GetConsensus().fCoinbaseMustBeProtected) {
|
||||
@@ -4442,15 +4486,13 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||
//reflecting an assumption the user would accept a bit more delay for
|
||||
//a chance at a free transaction.
|
||||
//But mempool inputs might still be in the mempool, so their age stays 0
|
||||
//fprintf(stderr,"nCredit %.8f interest %.8f\n",(double)nCredit/COIN,(double)pcoin.first->vout[pcoin.second].interest/COIN);
|
||||
int age = pcoin.first->GetDepthInMainChain();
|
||||
if (age != 0)
|
||||
age += 1;
|
||||
dPriority += (double)nCredit * age;
|
||||
}
|
||||
|
||||
CAmount nChange = (nValueIn - nValue + interest2);
|
||||
//fprintf(stderr,"wallet change %.8f (%.8f - %.8f) interest2 %.8f total %.8f\n",(double)nChange/COIN,(double)nValueIn/COIN,(double)nValue/COIN,(double)interest2/COIN,(double)nTotalValue/COIN);
|
||||
CAmount nChange = (nValueIn - nValue);
|
||||
if (nSubtractFeeFromAmount == 0)
|
||||
nChange -= nFeeRet;
|
||||
|
||||
@@ -4487,7 +4529,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"use notary pubkey\n");
|
||||
scriptChange = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
|
||||
}
|
||||
}
|
||||
@@ -4539,7 +4580,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||
txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
|
||||
std::numeric_limits<unsigned int>::max()-1));
|
||||
|
||||
// All Hush Arrakis Chains always have overwinter NU and so this option was never used
|
||||
// DragonX always has the Overwinter NU active and so this option was never used
|
||||
// Check mempooltxinputlimit to avoid creating a transaction which the local mempool rejects
|
||||
// const size_t limit = 0; // (size_t)GetArg("-mempooltxinputlimit", 0);
|
||||
//{
|
||||
@@ -4662,7 +4703,8 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
|
||||
// Add tx to wallet, because if it has change it's also ours,
|
||||
// otherwise just for transaction history.
|
||||
AddToWallet(wtxNew, false, pwalletdb);
|
||||
if (!AddToWallet(wtxNew, false, pwalletdb))
|
||||
LogPrintf("CommitTransaction(): Error: failed to persist wallet tx %s to disk; wallet may be out of sync with the ledger\n", wtxNew.GetHash().ToString());
|
||||
|
||||
// Notify that old coins are spent
|
||||
set<CWalletTx*> setCoins;
|
||||
@@ -4684,7 +4726,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
// Broadcast
|
||||
if (!wtxNew.AcceptToMemoryPool(false))
|
||||
{
|
||||
fprintf(stderr,"commit failed\n");
|
||||
// This must not fail. The transaction has already been signed and recorded.
|
||||
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
|
||||
return false;
|
||||
@@ -4734,7 +4775,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
||||
fFirstRunRet = false;
|
||||
if ( 0 ) // doesnt help
|
||||
{
|
||||
fprintf(stderr,"loading wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
|
||||
LogPrintf("loading wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
|
||||
FILE *fp;
|
||||
if ( (fp= fopen(strWalletFile.c_str(),"rb")) != 0 )
|
||||
{
|
||||
@@ -4742,9 +4783,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"prefetched wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
|
||||
DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
|
||||
//fprintf(stderr,"loaded wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
|
||||
if (nLoadWalletRet == DB_NEED_REWRITE)
|
||||
{
|
||||
if (CDB::Rewrite(strWalletFile, "\x04pool"))
|
||||
@@ -4929,7 +4968,6 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
|
||||
if (!HaveKey(keypool.vchPubKey.GetID()))
|
||||
throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
|
||||
assert(keypool.vchPubKey.IsValid());
|
||||
//LogPrintf("keypool reserve %d\n", nIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4951,7 +4989,6 @@ void CWallet::ReturnKey(int64_t nIndex)
|
||||
LOCK(cs_wallet);
|
||||
setKeyPool.insert(nIndex);
|
||||
}
|
||||
//LogPrintf("keypool return %d\n", nIndex);
|
||||
}
|
||||
|
||||
bool CWallet::GetKeyFromPool(CPubKey& result)
|
||||
@@ -5238,14 +5275,14 @@ void CWallet::LockNote(const SaplingOutPoint& output)
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
setLockedSaplingNotes.insert(output);
|
||||
fprintf(stderr,"%s: locking note %s...\n", __func__, output.hash.ToString().substr(0,8).c_str() );
|
||||
LogPrintf("%s: locking note %s...\n", __func__, output.hash.ToString().substr(0,8).c_str() );
|
||||
}
|
||||
|
||||
void CWallet::UnlockNote(const SaplingOutPoint& output)
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
setLockedSaplingNotes.erase(output);
|
||||
fprintf(stderr,"%s: unlocking note %s...\n", __func__, output.hash.ToString().substr(0,8).c_str() );
|
||||
LogPrintf("%s: unlocking note %s...\n", __func__, output.hash.ToString().substr(0,8).c_str() );
|
||||
}
|
||||
|
||||
void CWallet::UnlockAllSaplingNotes()
|
||||
@@ -5485,7 +5522,6 @@ int CMerkleTx::GetBlocksToMaturity() const
|
||||
int32_t depth = GetDepthInMainChain();
|
||||
int32_t ut = UnlockTime(0);
|
||||
int32_t toMaturity = (ut - chainActive.Height()) < 0 ? 0 : ut - chainActive.Height();
|
||||
//printf("depth.%i, unlockTime.%i, toMaturity.%i\n", depth, ut, toMaturity);
|
||||
ut = (COINBASE_MATURITY - depth) < 0 ? 0 : COINBASE_MATURITY - depth;
|
||||
return(ut < toMaturity ? toMaturity : ut);
|
||||
}
|
||||
@@ -5692,7 +5728,7 @@ SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingE
|
||||
if (params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight == Consensus::NetworkUpgrade::ALWAYS_ACTIVE) {
|
||||
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = nTime;
|
||||
} else {
|
||||
// TODO: set a better time for HUSH+HACs
|
||||
// TODO: set a better time for DragonX
|
||||
// 154051200 seconds from epoch is Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates
|
||||
m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = std::max((int64_t) 154051200, nTime);
|
||||
}
|
||||
|
||||
@@ -100,6 +100,19 @@ static const unsigned int DEFAULT_TX_RETENTION_LASTTX = 200;
|
||||
//Amount of transactions to delete per run while syncing
|
||||
static const int MAX_DELETE_TX_SIZE = 50000;
|
||||
|
||||
// Shared defaults for the automated wallet operations (sweep / consolidation /
|
||||
// auto-shield-coinbase). Fees are in puposhis (zats); intervals and offsets are
|
||||
// in blocks. Defined here so the CWallet scheduler fields below, init.cpp's
|
||||
// option parsing/help text, and the async ops reference one source of truth.
|
||||
static const CAmount DEFAULT_AUTOSHIELD_FEE = 10000;
|
||||
static const int DEFAULT_AUTOSHIELD_INTERVAL = 25;
|
||||
static const int MIN_AUTOSHIELD_INTERVAL = 5;
|
||||
static const int DEFAULT_AUTOSHIELD_MIN_UTXOS = 1;
|
||||
static const CAmount AUTOSHIELD_MIN_FEE = 1000; // comfortably above minRelayTxFee for a small tx
|
||||
static const CAmount AUTOSHIELD_MAX_FEE = 10000000; // 0.1 DRGX; no sane autoshield fee exceeds this
|
||||
static const int AUTO_OP_TARGET_HEIGHT_OFFSET = 5; // blocks of lookahead when scheduling an async op
|
||||
static const int AUTO_OP_EXPIRY_DELTA = 15; // NU-straddle expiry window, shared by all three ops
|
||||
|
||||
extern const char * DEFAULT_WALLET_DAT;
|
||||
|
||||
class CBlockIndex;
|
||||
@@ -810,10 +823,13 @@ public:
|
||||
bool fSweepExternalEnabled = false;
|
||||
bool fSweepRunning = false;
|
||||
|
||||
// Automatic coinbase shielding (t->z). Default ON but conditional: it is a
|
||||
// silent no-op on nodes where it cannot act (no wallet, external
|
||||
// Automatic coinbase shielding (t->z). The real default is computed in
|
||||
// init.cpp: ON only for known-recoverable seed provenance (CREATED/RESTORED),
|
||||
// conditional, and a silent no-op where it cannot act (no wallet, external
|
||||
// -mineraddress, non-mining, or locked wallet). See RunAutoShieldCoinbase.
|
||||
bool fAutoShieldEnabled = true;
|
||||
// The member defaults false so a CWallet that skips that init path never
|
||||
// auto-enables for provenance the gate would otherwise have rejected.
|
||||
bool fAutoShieldEnabled = false;
|
||||
bool fAutoShieldRunning = false;
|
||||
|
||||
std::atomic<bool> fAbortRescan{false};
|
||||
@@ -844,11 +860,11 @@ public:
|
||||
std::string consolidationAddress = "";
|
||||
|
||||
int nextAutoShield = 0;
|
||||
int autoShieldInterval = 25;
|
||||
CAmount autoShieldFee = 10000;
|
||||
int autoShieldInterval = DEFAULT_AUTOSHIELD_INTERVAL;
|
||||
CAmount autoShieldFee = DEFAULT_AUTOSHIELD_FEE;
|
||||
// Minimum matured coinbase UTXOs before a round fires, to avoid per-interval
|
||||
// fee churn on a single freshly-matured reward.
|
||||
int autoShieldMinUtxos = 1;
|
||||
int autoShieldMinUtxos = DEFAULT_AUTOSHIELD_MIN_UTXOS;
|
||||
// Configured destination z-addr override; also used to cache the resolved
|
||||
// wallet-owned destination so we keep reusing one address.
|
||||
std::string autoShieldAddress = "";
|
||||
|
||||
@@ -34,11 +34,18 @@
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
// Out-of-line definitions for CHDChain's in-class static constants. These are
|
||||
// only initialised in the class body, so any ODR use -- binding one to a const
|
||||
// reference, which is exactly what gtest's EXPECT_*/ASSERT_* macros do -- needs
|
||||
// a definition or the link fails. hush-gtest hit this on VERSION_HD_MNEMONIC.
|
||||
const int CHDChain::VERSION_HD_BASE;
|
||||
const int CHDChain::VERSION_HD_TRANSPARENT;
|
||||
const int CHDChain::VERSION_HD_MNEMONIC;
|
||||
const int CHDChain::CURRENT_VERSION;
|
||||
|
||||
using namespace std;
|
||||
|
||||
static uint64_t nAccountingEntryNumber = 0;
|
||||
static list<uint256> deadTxns;
|
||||
extern CBlockIndex *hush_blockindex(uint256 hash);
|
||||
|
||||
//
|
||||
// CWalletDB
|
||||
@@ -411,6 +418,9 @@ public:
|
||||
vector<uint256> vWalletUpgrade;
|
||||
// True once a well-formed "hdchain" record has been loaded.
|
||||
bool fHDChainRead;
|
||||
// True when that record had to be repaired on read (see the "hdchain" case
|
||||
// in ReadKeyValue); LoadWallet rewrites it in full form afterwards.
|
||||
bool fHDChainRepaired;
|
||||
|
||||
CWalletScanState() {
|
||||
nKeys = nCKeys = nKeyMeta = nZKeys = nCZKeys = nZKeyMeta = nSapZAddrs = 0;
|
||||
@@ -418,6 +428,7 @@ public:
|
||||
fAnyUnordered = false;
|
||||
nFileVersion = 0;
|
||||
fHDChainRead = false;
|
||||
fHDChainRepaired = false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -842,14 +853,48 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
else if (strType == "hdchain")
|
||||
{
|
||||
CHDChain chain;
|
||||
// Keep an untouched copy: a failed >> has already consumed part of ssValue.
|
||||
CDataStream ssRetry(ssValue.begin(), ssValue.end(), ssValue.GetType(), ssValue.GetVersion());
|
||||
try {
|
||||
ssValue >> chain;
|
||||
} catch (...) {
|
||||
// Do not let this land in the "user can live with it" bucket:
|
||||
// report it, and leave wss.fHDChainRead false so LoadWallet
|
||||
// turns it into DB_CORRUPT when a seed is present.
|
||||
strErr = "Error reading wallet database: hdchain record is corrupt";
|
||||
return false;
|
||||
// Downgrade repair. A build predating VERSION_HD_TRANSPARENT writes
|
||||
// this record back with only the four base fields while leaving
|
||||
// nVersion at whatever it read, so the version-gated reads above run
|
||||
// off the end. Without this, one address generated under such a build
|
||||
// makes the wallet unopenable here ("Wallet corrupted") even though
|
||||
// nothing is actually lost.
|
||||
//
|
||||
// Recovering is safe for a v1/v2 record: everything derivation needs
|
||||
// is either in the four-field prefix or in the separate hdseed record,
|
||||
// and the trailing counters are self-healing -- DeriveNewChildKey and
|
||||
// GenerateNewSaplingZKey both skip indices whose key the wallet
|
||||
// already holds, so restarting a counter at 0 re-walks past existing
|
||||
// keys instead of reissuing them.
|
||||
chain = CHDChain();
|
||||
try {
|
||||
ssRetry >> chain.nVersion;
|
||||
ssRetry >> chain.seedFp;
|
||||
ssRetry >> chain.nCreateTime;
|
||||
ssRetry >> chain.saplingAccountCounter;
|
||||
} catch (...) {
|
||||
// Short even in the base fields: genuinely corrupt.
|
||||
strErr = "Error reading wallet database: hdchain record is corrupt";
|
||||
return false;
|
||||
}
|
||||
if (chain.nVersion >= CHDChain::VERSION_HD_MNEMONIC) {
|
||||
// A record claiming to carry fMnemonicSeed must not have it
|
||||
// guessed: that flag selects the derivation input, so defaulting
|
||||
// it wrong yields a different key tree in silence. Fail loud, as
|
||||
// this branch always did.
|
||||
strErr = "Error reading wallet database: hdchain record is corrupt";
|
||||
return false;
|
||||
}
|
||||
chain.transparentChildCounter = 0;
|
||||
chain.fMnemonicSeed = false;
|
||||
wss.fHDChainRepaired = true;
|
||||
LogPrintf("Repairing a truncated hdchain record (nVersion=%d): it was last written by "
|
||||
"a wallet build that predates the transparent HD counter\n", chain.nVersion);
|
||||
}
|
||||
wss.fHDChainRead = true;
|
||||
pwallet->SetHDChain(chain, true);
|
||||
@@ -858,6 +903,12 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
{
|
||||
int64_t nOrigin = 0;
|
||||
ssValue >> nOrigin;
|
||||
// Clamp an out-of-range value (corrupt or hand-edited wallet.dat) to
|
||||
// UNKNOWN — the conservative origin that leaves autoshield OFF — rather
|
||||
// than trusting it to claim a known-recoverable (CREATED/RESTORED) seed.
|
||||
if (nOrigin < CWallet::HDSEED_ORIGIN_UNRECORDED || nOrigin > CWallet::HDSEED_ORIGIN_UNKNOWN) {
|
||||
nOrigin = CWallet::HDSEED_ORIGIN_UNKNOWN;
|
||||
}
|
||||
pwallet->hdSeedOrigin = (int)nOrigin;
|
||||
}
|
||||
else if (strType == "mnementropy")
|
||||
@@ -964,8 +1015,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
{
|
||||
// Leave other errors alone, if we try to fix them we might make things worse.
|
||||
fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
|
||||
// set rescan for any error that is not vin-empty on staking chains.
|
||||
if ( deadTxns.empty() && strType == "tx")
|
||||
if ( strType == "tx")
|
||||
SoftSetBoolArg("-rescan", true);
|
||||
}
|
||||
}
|
||||
@@ -981,32 +1031,21 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
result = DB_CORRUPT;
|
||||
}
|
||||
|
||||
if ( !deadTxns.empty() )
|
||||
{
|
||||
// staking chains with vin-empty error is a failed staking tx.
|
||||
// we remove then re add the tx here to stop needing a full rescan, which does not actually fix the problem.
|
||||
int32_t reAdded = 0;
|
||||
BOOST_FOREACH (uint256& hash, deadTxns)
|
||||
{
|
||||
fprintf(stderr, "Removing possible orphaned staking transaction from wallet.%s\n", hash.ToString().c_str());
|
||||
if (!EraseTx(hash))
|
||||
fprintf(stderr, "could not delete tx.%s\n",hash.ToString().c_str());
|
||||
uint256 blockhash; CTransaction tx; CBlockIndex* pindex;
|
||||
if ( GetTransaction(hash,tx,blockhash,false) && (pindex= hush_blockindex(blockhash)) != 0 && chainActive.Contains(pindex) )
|
||||
{
|
||||
CWalletTx wtx(pwallet,tx);
|
||||
pwallet->AddToWallet(wtx, true, NULL);
|
||||
reAdded++;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Cleared %li orphaned staking transactions from wallet. Readded %i real transactions.\n",deadTxns.size(),reAdded);
|
||||
fNoncriticalErrors = false;
|
||||
deadTxns.clear();
|
||||
}
|
||||
|
||||
if (fNoncriticalErrors && result == DB_LOAD_OK)
|
||||
result = DB_NONCRITICAL_ERROR;
|
||||
|
||||
// Rewrite a repaired record in full form so the next load is clean and the
|
||||
// transparent counter starts being persisted again.
|
||||
if (wss.fHDChainRepaired && pwallet->HaveHDSeed())
|
||||
{
|
||||
try {
|
||||
pwallet->SetHDChain(pwallet->GetHDChain(), false);
|
||||
LogPrintf("Rewrote the repaired hdchain record in full form\n");
|
||||
} catch (const std::exception& e) {
|
||||
LogPrintf("Could not rewrite the repaired hdchain record: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
// A wallet that holds an HD seed but whose hdchain record is missing or
|
||||
// unreadable is NOT safe to run. hdChain would fall back to its SetNull
|
||||
// defaults (walletdb.h:105-113), which (a) clears fMnemonicSeed, switching
|
||||
@@ -1018,7 +1057,9 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
// Fail loud instead of quietly deriving into the wrong tree.
|
||||
if (pwallet->HaveHDSeed() && !wss.fHDChainRead)
|
||||
{
|
||||
LogPrintf("Error loading wallet.dat: HD seed present but the hdchain record is missing or corrupt\n");
|
||||
LogPrintf("Error loading wallet.dat: HD seed present but the hdchain record is missing or corrupt. "
|
||||
"Recover by restoring from the seed phrase: move wallet.dat aside and start with "
|
||||
"-mnemonic=\"<your seed phrase>\" -rescan\n");
|
||||
return DB_CORRUPT;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,12 @@ fi
|
||||
|
||||
DESC=""
|
||||
SUFFIX=""
|
||||
if [ -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then
|
||||
# Allow the build system to supply the version when git metadata is unavailable:
|
||||
# container builds exclude .git, and a linked worktree's .git file points outside
|
||||
# the build context. Without this such builds are stamped "-unk".
|
||||
if [ -n "${DRAGONX_BUILD_DESC:-}" ]; then
|
||||
DESC="$DRAGONX_BUILD_DESC"
|
||||
elif [ -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then
|
||||
# clean 'dirty' status of touched files that haven't been modified
|
||||
git diff >/dev/null 2>/dev/null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user