diff --git a/autogen.sh b/autogen.sh
index 3e26a1830..6932fae53 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,4 +1,7 @@
#!/bin/sh
+# Copyright (c) 2016-2021 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
set -e
srcdir="$(dirname $0)"
cd "$srcdir"
diff --git a/configure.ac b/configure.ac
index 526ad358d..35da30d2a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 3)
-define(_CLIENT_VERSION_MINOR, 7)
-define(_CLIENT_VERSION_REVISION, 1)
+define(_CLIENT_VERSION_MINOR, 8)
+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)))
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
diff --git a/doc/man/hush-cli.1 b/doc/man/hush-cli.1
index 63d05ac06..668b3c4a7 100644
--- a/doc/man/hush-cli.1
+++ b/doc/man/hush-cli.1
@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
-.TH HUSH-CLI "1" "April 2021" "hush-cli v3.7.1" "User Commands"
+.TH HUSH-CLI "1" "July 2021" "hush-cli v3.8.0" "User Commands"
.SH NAME
-hush-cli \- manual page for hush-cli v3.7.1
+hush-cli \- manual page for hush-cli v3.8.0
.SH DESCRIPTION
-Hush RPC client version v3.7.1\-2da07fe58\-dirty
+Hush RPC client version v3.8.0\-10a6706e7\-dirty
.PP
In order to ensure you are adequately protecting your privacy when using Hush,
please see .
diff --git a/doc/man/hush-tx.1 b/doc/man/hush-tx.1
index 37c17b9b4..5c07d059a 100644
--- a/doc/man/hush-tx.1
+++ b/doc/man/hush-tx.1
@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
-.TH HUSH-TX "1" "April 2021" "hush-tx v3.7.1" "User Commands"
+.TH HUSH-TX "1" "July 2021" "hush-tx v3.8.0" "User Commands"
.SH NAME
-hush-tx \- manual page for hush-tx v3.7.1
+hush-tx \- manual page for hush-tx v3.8.0
.SH DESCRIPTION
-hush\-tx utility version v3.7.1\-2da07fe58\-dirty
+hush\-tx utility version v3.8.0\-10a6706e7\-dirty
.SS "Usage:"
.TP
hush\-tx [options] [commands]
diff --git a/doc/man/hushd.1 b/doc/man/hushd.1
index 23959cf1b..e73677110 100644
--- a/doc/man/hushd.1
+++ b/doc/man/hushd.1
@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
-.TH HUSHD "1" "April 2021" "hushd v3.7.1" "User Commands"
+.TH HUSHD "1" "July 2021" "hushd v3.8.0" "User Commands"
.SH NAME
-hushd \- manual page for hushd v3.7.1
+hushd \- manual page for hushd v3.8.0
.SH DESCRIPTION
-Hush Daemon version v3.7.1\-2da07fe58\-dirty
+Hush Daemon version v3.8.0\-10a6706e7\-dirty
.PP
In order to ensure you are adequately protecting your privacy when using Hush,
please see .
@@ -341,10 +341,19 @@ Minimum fee (in HUSH/kB) to allow for OP_RETURN transactions (default:
.IP
Fee (in HUSH/kB) to add to transactions you send (default: 0.00)
.HP
+\fB\-keepnotewitnesscache\fR
+.IP
+Keep partial Sapling Note Witness cache. Must be used with \fB\-rescanheight\fR
+to find missing cache items.
+.HP
\fB\-rescan\fR
.IP
Rescan the block chain for missing wallet transactions on startup
.HP
+\fB\-rescanheight\fR
+.IP
+Rescan from specified height when rescan=1 on startup
+.HP
\fB\-salvagewallet\fR
.IP
Attempt to recover private keys from a corrupt wallet.dat on startup
diff --git a/doc/relnotes/README.md b/doc/relnotes/README.md
index 002b23513..529063a8e 100644
--- a/doc/relnotes/README.md
+++ b/doc/relnotes/README.md
@@ -10,6 +10,32 @@ and no longer on Github, since they banned Duke Leto and
also because they censor many people around the world and work with
evil organizations.
+# Hush 3.8.0 "XXX YYY"
+
+This is an OPTIONAL release, but since it contains many privacy improvements, it's HIGHLY RECOMMENDED for all users to upgrade.
+
+ * New Sietch feature: Randomized change output location
+ * Zcash and Pirate always put the change as the last shielded output, which leaks metadata. Hush no longer has this metadata leakage.
+ * This feature improves the `z_sendmany`, `z_mergetoaddress` and `z_shieldtocoinbase` since it's done in the Hush TransactionBuilder.
+ * New Sietch feature: Sitech-ified `z_shieldcoinbase`
+ * This RPC now leaks less metadata by making it hard for blockchain analysts to know which of the three outputs has value.
+ * This also increases Hush's "anonset velocity", which is how fast we increase our anonymity set, or "anonset".
+ * Previously you could only run `stop` while Hush was in RPC warmup, but now additional RPCs are allowed:
+ * `stop` - Oops, you started hushd on accident a few seconds ago? Now you can stop it without waiting.
+ * `help` - Get help during long rescans, finally!
+ * `z_listaddresses` - See a list of all zaddrs in this wallet, even during a long rescan!
+ * `z_exportkey` - Export a key from this node, even during rescan!
+ * `listaddresses` - See a list of taddrs as soon as we load the wallet.
+ * `dumpprivkey` - Dump the private key of a taddr, even when node isn't fully synced!
+ * `getpeerinfo` - See current peers even before we get enough peers to start syncing or a long rescan!
+ * `-keepnotewitnesscache` prevents the Sapling Note Witness cache from being deleted from wallet.dat on shutdown.
+ * `-rescanheight` can be used with `-keepnotewitnesscache` and `-rescan` to do a partial rescan of history and avoid completely rebuilding the Witness Cache.
+ * `-zindex` data is now stored on disk in the new `zindex.dat` file
+ * All nodes that use `-zindex` will now have reliable anonset statistics even after a restart
+ * Improvements to the RPC help documentation
+ * `hushd.bat` for Windows now uses the ASN map via `-asmap` and has the latest seed nodes
+ * `hushd-tx.bat` for Windows now exists for making raw transactions on Windows
+
# Hush 3.7.1 "Neologistic Nautilus"
```
diff --git a/src/chain.h b/src/chain.h
index 1d8f2a462..bb0b2897f 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -266,7 +266,7 @@ public:
int64_t nPayments;
//! (memory only) Number of shielded transactions (of any kind) in the block up to and including this block.
- //! A shielded transaction is defined as a transaction that contains at least 1 JoinSplit, which includes
+ //! A shielded transaction is defined as a transaction that contains at least 1 ShieldedInput or ShieldedOutput
//! shielding/de-shielding and other complex transaction possibilties including multiple taddrs/zaddrs as
//! inputs and outputs.
int64_t nShieldedTx;
@@ -278,7 +278,7 @@ public:
int64_t nShieldedSpends;
//! (memory only) Number of fully shielded transactions. A fully shielded transaction is defined
- //! as a transaction containing JoinSplits and only shielded inputs and outputs, i.e. no transparent
+ //! as a transaction containing only shielded inputs and outputs, i.e. no transparent
// inputs or outputs: z->z or z->(z,z) or z->(z,z,z,) etc...
int64_t nFullyShieldedTx;
@@ -295,7 +295,7 @@ public:
int64_t nFullyShieldedPayments;
//! (memory only) Number of deshielding transactions. A deshielding transaction is defined
- //! as a transaction containing JoinSplits and at least one transparent output.
+ //! as a transaction containing ShieldedInputs and at least one transparent output.
int64_t nDeshieldingTx;
//! (memory only) Number of deshielding payments. A deshielding payment is defined
@@ -303,7 +303,7 @@ public:
int64_t nDeshieldingPayments;
//! (memory only) Number of shielding transactions. A shielding transaction is defined
- //! as a transaction containing JoinSplits and at least one transparent input
+ //! as a transaction containing ShieldedOutputs and at least one transparent input
// i.e. t->z or t->(z,t) or z->(z,z,t)
int64_t nShieldingTx;
@@ -322,7 +322,7 @@ public:
int64_t nChainPayments;
//! (memory only) Number of shielded transactions (of any kind) in the chain up to and including this block.
- //! A shielded transaction is defined as a transaction that contains at least 1 JoinSplit, which includes
+ //! A shielded transaction is defined as a transaction that contains at least 1 ShieldedInput or ShieldedOutput
//! shielding/de-shielding and other complex transaction possibilties including multiple taddrs/zaddrs as
//! inputs and outputs.
int64_t nChainShieldedTx;
@@ -334,7 +334,7 @@ public:
int64_t nChainShieldedSpends;
//! (memory only) Number of fully shielded transactions. A fully shielded transaction is defined
- //! as a transaction containing JoinSplits and only shielded inputs and outputs, i.e. no transparent
+ //! as a transaction containing and only shielded inputs and outputs, i.e. no transparent
// inputs or outputs: z->z or z->(z,z) or z->(z,z,z,) etc...
int64_t nChainFullyShieldedTx;
@@ -351,7 +351,7 @@ public:
int64_t nChainFullyShieldedPayments;
//! (memory only) Number of deshielding transactions. A deshielding transaction is defined
- //! as a transaction containing JoinSplits and at least one transparent output.
+ //! as a transaction containing ShieldedInputs and at least one transparent output.
int64_t nChainDeshieldingTx;
//! (memory only) Number of deshielding payments. A deshielding payment is defined
@@ -359,7 +359,7 @@ public:
int64_t nChainDeshieldingPayments;
//! (memory only) Number of shielding transactions. A shielding transaction is defined
- //! as a transaction containing JoinSplits and at least one transparent input
+ //! as a transaction containing ShieldedOutputs and at least one transparent input
// i.e. t->z or t->(z,t) or z->(z,z,t)
int64_t nChainShieldingTx;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 9cd9bb7f9..c6dd5f1f9 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -783,11 +783,79 @@ void *chainparams_commandline() {
(492000, uint256S("0x00000013bbbff98ddab19a3178a0088a20628791e94963e5d1ea635015dfa9c6"))
(493000, uint256S("0x00000001ed829c061ba14f6953e79d99577079adf5526f1e43e6dc9d9f9571bf"))
(494000, uint256S("0x00000018dfeced2d1584a1003fefa4349810239bade096e53b4fa6bbc38a1685"))
- (495000, uint256S("0x0000001816af55724cd49c0bfe02c9eac29b4a73db2b7d868b958218a03e6c94"))
- (496000, uint256S("0x000000007e2019c5246db5a75122c6826822fa154d68a51eee2ff23f54ec668e")),
- (int64_t) 1618760194, // time of last checkpointed block
- (int64_t) 842496, // total txs
- (double) 1812 // txs in the last day before block 496013
+ (495000, uint256S("0x0000001816af55724cd49c0bfe02c9eac29b4a73db2b7d868b958218a03e6c94"))
+ (496000, uint256S("0x000000007e2019c5246db5a75122c6826822fa154d68a51eee2ff23f54ec668e"))
+ (497000, uint256S("0x0000000aa5803c0825cfa1a34227d0ecb80be191674365a372f71611eacdc742"))
+ (498000, uint256S("0x000000166385022d4b4ade0921a5f6c7d4aec56257cd679f7c441aeb0552b28c"))
+ (499000, uint256S("0x0000002ce5e48efb664e936c9551b2781c742416e519d3a023d087036519507b"))
+ (500000, uint256S("0x0000000cdfe9389bde0e9f1d649dd2f19ee69d765b00907aa681c3cdaad0bdb6"))
+ (501000, uint256S("0x00000028736fd4ce6995a46d217c0022d2882165b5f716e94f255877c73f474a"))
+ (502000, uint256S("0x000000459520215ade21db91a83ad47a806320ba3e290d686149bcf5672e132a"))
+ (503000, uint256S("0x000000086aee5827d0254e1176a4dfd5c8a7958ee1f61458bdb1eb4d6ffbc131"))
+ (504000, uint256S("0x000000474906b6ad537fe14eca1316c7be23f181bc554a2244c97634a6d361a7"))
+ (505000, uint256S("0x00000035db569efc139988b7d506529bb482284bf2dfc40060159b321883974d"))
+ (506000, uint256S("0x0000000c55ddd54e1f0aa6a59abe774f0e14501743c2594184772031f5bf51fd"))
+ (507000, uint256S("0x000000061ca0ea34d5d3ddd5d8ceb0dcf9a0720483efd98155c0aa3774387e60"))
+ (508000, uint256S("0x00000004bd6cdfbbee3945b897c4d6b6f49199d788151fe5536417d31d2f36ab"))
+ (509000, uint256S("0x0000000b73f9dd08528827a8224decf6635462d2adabac9301e5c17b7a24a5f4"))
+ (510000, uint256S("0x00000004c41a5b61302564abc741195c915fdf9edd12669f93ac5d4443613664"))
+ (511000, uint256S("0x000000094319bb7199e5697e458520e95639dcec5180d4442e1470f48feaf125"))
+ (512000, uint256S("0x00000014516f2d52467edd913c52e1742ca8a767debd9294bbbf8f39bdbae506"))
+ (513000, uint256S("0x000000177739b5379d196b74faeaabf35dbb9d3f6f9e172f659f68b3288a71c3"))
+ (514000, uint256S("0x0000000940533509d21f249ab0b0144923e65050a24dbf53863c9c07fd21fd6b"))
+ (515000, uint256S("0x000000007d256fc4cbfff1c05f83550b8dfdf093b060a98fafac6a090e349bc1"))
+ (516000, uint256S("0x000000029ee7abc14842e22b4f3e7e3c640c55fa2a898773c83ff34ceb2a5482"))
+ (517000, uint256S("0x00000019ca7705b4a8b35ae1aa4071401ed1de7449306ef8a34716637f43c2f1"))
+ (518000, uint256S("0x00000013f4aa06fca6c2a57e80c3950d0e7613f3bcba0b52887d4c7579e5b20a"))
+ (519000, uint256S("0x0000000b7d1e4efbbb38c91e838a50876be93a6549fdaeb534ec1d8657117e69"))
+ (520000, uint256S("0x00000000c2fb98b56bf9c549406710b57308081663230a477c7b5983720a456a"))
+ (521000, uint256S("0x0000000d48660709c9fd60f01b71260e0e6ba3875cdb109b7b037ec6b80f3098"))
+ (522000, uint256S("0x00000019d0ad6bdebc9d39a5b9a6ae4d844b45bbfcdd97885841a1d8033c956f"))
+ (523000, uint256S("0x000000121da004ec14c89b67151439765a19aadbdf4d4feca701cce7c3820efb"))
+ (524000, uint256S("0x00000003d3445c4cb6e980751cd8119679d572f57bbaa3b9c9114e397841827e"))
+ (525000, uint256S("0x0000000b2a079f083c86f9ab8b0f73dc511c20f6aa44d7735f29409df966f026"))
+ (526000, uint256S("0x00000004d3ae427a98336ee4bc5e60f00ebd4c88f9ffdd18003f17535465888a"))
+ (527000, uint256S("0x000000057e5cb13f42332f59b6c2d6f333369b8e4d9bdf6fa9bb441e2ddb5c51"))
+ (528000, uint256S("0x000000045f51825c19aab9d1d620d7073c2114ccf3e40f63d66c729c71c2bc05"))
+ (529000, uint256S("0x000000116ac2795cdbde2d3af6d804d9dbf445d2ed12d7cf13c155540f10c119"))
+ (530000, uint256S("0x0000000be4932b469923d826991810109f2c2ca50d5fa0133c765b5ab96bf315"))
+ (531000, uint256S("0x0000000a7fdd8ce073da5d95fcbefba5d0366c9b834cac914889108094d0cd18"))
+ (532000, uint256S("0x0000000600d2ea28f32220c054e2ae66ec8471a2f755ef219a0c81e4a4296135"))
+ (533000, uint256S("0x0000000a5f4a460970f6dcd3a271315f936648c854c1a7bb251dbc7996f90e92"))
+ (534000, uint256S("0x00000009b5d0615eb98f06820cc6d66af542b8bbde0cabe5b54b6e7625e77803"))
+ (535000, uint256S("0x0000000ac06f5d79b927f2dfb54eecd72f9ada28fa59092f5c3c83627b281605"))
+ (536000, uint256S("0x000000037a51adb2cccf29b9c164386c8418959db16606b70a1389fb8755829f"))
+ (537000, uint256S("0x0000000a129157792e233e233f85693625abb14be90362ff727ab97e8d5ec340"))
+ (538000, uint256S("0x00000015e13085045c090a51e9c1114749fa7b465009f2ad70ff278d9ae05b5c"))
+ (539000, uint256S("0x00000001953384069e477f7e1839dc0498cbeb951adb32bcbf3b96ef487fce4a"))
+ (540000, uint256S("0x0000000281246b5d2e845aa711b6af76c8cc0d1f39ba25fe414f83bbe47544bb"))
+ (541000, uint256S("0x0000000f27b777a942d6317438836258c4e34bd3761736a2b32cc2b7c8305d71"))
+ (542000, uint256S("0x00000005d4667fb45a862d91ba843acbaee033915bf75536c67aeca1a2a3a5ff"))
+ (543000, uint256S("0x0000000509b08619049b1aec8e715d971b8dbc2175acf7874a37b9ce13dfb137"))
+ (544000, uint256S("0x0000000582563d79bf72a925ae3bc5c6f0eacbdb317c92fa89eb56d570427fd7"))
+ (545000, uint256S("0x0000000ff9df3d3a00d682f069819acbc5697b42da69a78f6e07486ac68f0e49"))
+ (546000, uint256S("0x00000004653460c603fa7a70292a85e286272b587f0b9cea7e73b765e8b0ef7b"))
+ (547000, uint256S("0x000000074c5f411190c5bf788a37a00506935015df4872cc5471416abadb757d"))
+ (548000, uint256S("0x00000005444a4ecd1eea940ad5395f2f7839967ee5b01be4a9b68755de4395ac"))
+ (549000, uint256S("0x0000000216eafee0e40374b8e8db63118cb4e3adc3159068bdafff1f0e0d9deb"))
+ (550000, uint256S("0x0000000056b84bc88604b9df668b60c020a6926b2dfdcd09955e5d8d3e7a5ca7"))
+ (551000, uint256S("0x0000000adaaeb79c5c6c49038d7206f88d5b4ecaaf21aaca09b5a7d548f76b25"))
+ (552000, uint256S("0x00000004185669b566e62cbebc9c50930c8ae0d5c42f23280262a7f55b726553"))
+ (553000, uint256S("0x00000010112434cdb0203a053e0c22ef16b9d39b8feed2328d7ff97013b216be"))
+ (554000, uint256S("0x00000006dacee96c0f48fc7250c71cc1e746befa84af8cd2ed0499d8d24cc6cb"))
+ (555000, uint256S("0x00000001b3b2c149029d5a2e7cedb0683c97692a52cbc91bb532cb78bbcadcc0"))
+ (556000, uint256S("0x0000000397bdd61939cc3d2c39360c5e3713ef9dd82b8cedac17075b8e177304"))
+ (557000, uint256S("0x0000000414bb81b82a2e71608086ac585dba19ca249067c9e967d6f44a1d3163"))
+ (558000, uint256S("0x00000003516d27423b1b5b60eab97d425e7be3f08f14bafd935666b1e955608e"))
+ (559000, uint256S("0x00000005c44ef4543da5924e65f0fd2d2c8fe926b2f3995b83ccfd1463b443d7"))
+ (560000, uint256S("0x00000002eb33454ba48e61a50351686115c47cb59b8fb0496432ad58e0484acf"))
+ (561000, uint256S("0x00000004172d5940c07ec6d493e410fbab8a05dc73e350505e1540d7336eb353"))
+ (562000, uint256S("0x00000000d9caaf66ad7782046886d3bfdf966c0a015dbae64042cd0c35e516e4"))
+ (563000, uint256S("0x000000000d953e53c65145bfb41ba544a9ce9e5432c9ed8eabd39873dfcb8ab0"))
+ (564000, uint256S("0x0000000d49258678c42bc2ea6f9e5d1206c578da8dc564d1a6114ce68bf77817")),
+ (int64_t) 1623979514, // time of last checkpointed block
+ (int64_t) 922687, // total txs
+ (double) 1219 // txs in the last day before block 564690
};
} else {
diff --git a/src/clientversion.h b/src/clientversion.h
index a7e850e7c..375f82690 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -29,8 +29,8 @@
//! 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 3
-#define CLIENT_VERSION_MINOR 7
-#define CLIENT_VERSION_REVISION 1
+#define CLIENT_VERSION_MINOR 8
+#define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 50
//! Set to true for release, false for prerelease or test build
diff --git a/src/hush-tx.bat b/src/hush-tx.bat
new file mode 100644
index 000000000..f3e24881d
--- /dev/null
+++ b/src/hush-tx.bat
@@ -0,0 +1,14 @@
+@call :GET_CURRENT_DIR
+@cd %THIS_DIR%
+komodo-tx.exe -ac_name=HUSH3 %1 %2 %3 %4 %5 %6 %7 %8 %9
+@goto :EOF
+
+:GET_CURRENT_DIR
+@pushd %~dp0
+@set THIS_DIR=%CD%
+@popd
+@goto :EOF
+
+
+
+
diff --git a/src/hushd.bat b/src/hushd.bat
index b2580ffaf..5f578d6b6 100644
--- a/src/hushd.bat
+++ b/src/hushd.bat
@@ -1,6 +1,6 @@
@call :GET_CURRENT_DIR
@cd %THIS_DIR%
-komodod.exe -ac_name=HUSH3 -ac_sapling=1 -ac_reward=0,1125000000,562500000 -ac_halving=129,340000,840000 -ac_end=128,340000,5422111 -ac_eras=3 -ac_blocktime=150 -ac_cc=2 -ac_ccenable=228,234,235,236,241 -ac_founders=1 -ac_supply=6178674 -ac_perc=11111111 -clientname=GoldenSandtrout -addnode=64.120.113.130 -addnode=209.58.144.205 -addnode=94.130.35.94 -addnode=188.165.212.101 -ac_cclib=hush3 -ac_script=76a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac -daemon %1 %2 %3 %4 %5 %6 %7 %8 %9
+komodod.exe -ac_name=HUSH3 -ac_sapling=1 -ac_reward=0,1125000000,562500000 -ac_halving=129,340000,840000 -ac_end=128,340000,5422111 -ac_eras=3 -ac_blocktime=150 -ac_cc=2 -ac_ccenable=228,234,235,236,241 -ac_founders=1 -ac_supply=6178674 -ac_perc=11111111 -clientname=GoldenSandtrout -asmap -addnode=node1.hush.is -addnode=node2.hush.is -addnode=node3.hush.is -addnode=node4.hush.is -addnode=node5.hush.is -addnode=node6.hush.is -addnode=node7.hush.is -addnode=node8.hush.is -ac_cclib=hush3 -ac_script=76a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac -daemon %1 %2 %3 %4 %5 %6 %7 %8 %9
@goto :EOF
:GET_CURRENT_DIR
diff --git a/src/init.cpp b/src/init.cpp
index 2624945bf..01916ee76 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -466,7 +466,11 @@ std::string HelpMessage(HelpMessageMode mode)
CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-opretmintxfee=", strprintf(_("Minimum fee (in %s/kB) to allow for OP_RETURN transactions (default: %s)"), CURRENCY_UNIT, 400000 ));
strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
+ // If this is used incorrectly (-rescanheight too large), then the local wallet may attempt to spend funds which it does not have witness data about
+ // which will cause a "missing inputs" error when added to the mempool. Rescanning from correct height will fix this.
+ strUsage += HelpMessageOpt("-keepnotewitnesscache", _("Keep partial Sapling Note Witness cache. Must be used with -rescanheight to find missing cache items."));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
+ strUsage += HelpMessageOpt("-rescanheight", _("Rescan from specified height when rescan=1 on startup"));
strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup"));
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1));
@@ -2072,8 +2076,22 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
CBlockIndex *pindexRescan = chainActive.Tip();
if (clearWitnessCaches || GetBoolArg("-rescan", false))
{
- pwalletMain->ClearNoteWitnessCache();
+ int rescanHeight = GetArg("-rescanheight", 0);
+ // Must be used with -rescanheight
+ if( GetBoolArg("-keepnotewitnesscache", false) && rescanHeight > 0 ) {
+ LogPrintf("%s: keeping NoteWitnessCache with rescan height=%d\n", __func__, rescanHeight);
+ } else {
+ pwalletMain->ClearNoteWitnessCache();
+ }
+
pindexRescan = chainActive.Genesis();
+ if (rescanHeight > 0) {
+ if (rescanHeight > chainActive.Tip()->GetHeight()) {
+ pindexRescan = chainActive.Tip();
+ } else {
+ pindexRescan = chainActive[rescanHeight];
+ }
+ }
} else {
CWalletDB walletdb(strWalletFile);
CBlockLocator locator;
diff --git a/src/main.cpp b/src/main.cpp
index 8887292d4..ec02f3a79 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -76,6 +76,7 @@ using namespace std;
CCriticalSection cs_main;
extern uint8_t NOTARY_PUBKEY33[33];
extern int32_t HUSH_LOADINGBLOCKS,HUSH_LONGESTCHAIN,HUSH_INSYNC,HUSH_CONNECTING,HUSH_EXTRASATOSHI;
+extern CZindexStats zstats;
int32_t HUSH_NEWBLOCKS;
int32_t hush_block2pubkey33(uint8_t *pubkey33,CBlock *block);
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
@@ -572,6 +573,102 @@ namespace {
} // anon namespace
+// CZindexDB
+CZindexDB::CZindexDB()
+{
+ pathAddr = GetDataDir() / "zindex.dat";
+}
+
+bool CZindexDB::Read(CZindexStats& zstats)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fopen(pathAddr.string().c_str(), "rb");
+ CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
+ if (filein.IsNull())
+ return error("%s: Failed to open file %s", __func__, pathAddr.string());
+
+ // use file size to size memory buffer
+ int fileSize = boost::filesystem::file_size(pathAddr);
+ int dataSize = fileSize - sizeof(uint256);
+ // Don't try to resize to a negative number if file is small
+ if (dataSize < 0)
+ dataSize = 0;
+ vector vchData;
+ vchData.resize(dataSize);
+ uint256 hashIn;
+
+ // read data and checksum from file
+ try {
+ filein.read((char *)&vchData[0], dataSize);
+ filein >> hashIn;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+ filein.fclose();
+
+ CDataStream ssZstats(vchData, SER_DISK, CLIENT_VERSION);
+
+ // verify stored checksum matches input data
+ uint256 hashTmp = Hash(ssZstats.begin(), ssZstats.end());
+ if (hashIn != hashTmp)
+ return error("%s: zstats Checksum mismatch, data corrupted", __func__);
+
+ unsigned char pchMsgTmp[4];
+ try {
+ // de-serialize file header (network specific magic number) and ..
+ ssZstats >> FLATDATA(pchMsgTmp);
+
+ // ... verify the network matches ours
+ if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
+ return error("%s: Invalid network magic number", __func__);
+
+ // de-serialize data into one CZindexStats object
+ ssZstats >> zstats;
+ } catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
+}
+
+bool CZindexDB::Write(const CZindexStats& zstats)
+{
+ // Generate random temporary filename
+ unsigned short randv = 0;
+ GetRandBytes((unsigned char*)&randv, sizeof(randv));
+ std::string tmpfn = strprintf("zindex.dat.%04x", randv);
+
+ // serialize zstats, checksum data up to that point, then append checksum
+ CDataStream ssZstats(SER_DISK, CLIENT_VERSION);
+ ssZstats << FLATDATA(Params().MessageStart());
+ ssZstats << zstats;
+ uint256 hash = Hash(ssZstats.begin(), ssZstats.end());
+ ssZstats << hash;
+
+ // open temp output file, and associate with CAutoFile
+ boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
+ if (fileout.IsNull())
+ return error("%s: Failed to open file %s", __func__, pathTmp.string());
+
+ // Write and commit header, data
+ try {
+ fileout << ssZstats;
+ } catch (const std::exception& e) {
+ return error("%s: Serialize or I/O error - %s", __func__, e.what());
+ }
+ FileCommit(fileout.Get());
+ fileout.fclose();
+
+ // replace existing zindex.dat, if any, with new zindex.dat.XXXX
+ if (!RenameOver(pathTmp, pathAddr))
+ return error("%s: Rename-into-place failed", __func__);
+
+ return true;
+}
+
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
LOCK(cs_main);
CNodeState *state = State(nodeid);
@@ -3928,7 +4025,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
- if ( HUSH_LONGESTCHAIN != 0 && (pindexNew->GetHeight() == HUSH_LONGESTCHAIN || pindexNew->GetHeight() == HUSH_LONGESTCHAIN+1) )
+ if ( HUSH_LONGESTCHAIN != 0 && (pindexNew->GetHeight() >= HUSH_LONGESTCHAIN ))
HUSH_INSYNC = (int32_t)pindexNew->GetHeight();
else HUSH_INSYNC = 0;
//fprintf(stderr,"connect.%d insync.%d ASSETCHAINS_SAPLING.%d\n",(int32_t)pindexNew->GetHeight(),HUSH_INSYNC,ASSETCHAINS_SAPLING);
@@ -4429,13 +4526,6 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
// pool. So we invert the sign here.
saplingValue += -tx.valueBalance;
- /*
- for (auto js : tx.vjoinsplit) {
- sproutValue += js.vpub_old;
- sproutValue -= js.vpub_new;
- }
- */
-
// Ignore following stats unless -zindex enabled
if (!fZindex)
continue;
@@ -4560,6 +4650,39 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
if (fZdebug) {
//fprintf(stderr,"%s: setting blockchain zstats with zspends=%d, zouts=%d\n", __FUNCTION__, nShieldedSpendsInBlock, nShieldedOutputsInBlock );
}
+ if (pindex->pprev) {
+ // If chain stats are zero (such as after restart), load data from zindex.dat
+ if (pindex->pprev->nChainNotarizations == 0)
+ pindex->pprev->nChainNotarizations = zstats.nChainNotarizations;
+ if (pindex->pprev->nChainShieldedTx == 0)
+ pindex->pprev->nChainShieldedTx = zstats.nChainShieldedTx;
+ if (pindex->pprev->nChainShieldedOutputs == 0)
+ pindex->pprev->nChainShieldedOutputs = zstats.nChainShieldedOutputs;
+ if (pindex->pprev->nChainShieldedSpends == 0) {
+ pindex->pprev->nChainShieldedSpends = zstats.nChainShieldedSpends;
+ // TODO: if zstats.nHeight != chainActive.Height() the stats will be off
+ fprintf(stderr, "%s: loaded anonymity set of %li at stats height=%li vs local height=%d from disk\n", __func__, zstats.nChainShieldedOutputs - zstats.nChainShieldedSpends, zstats.nHeight, chainActive.Height() );
+ }
+ if (pindex->pprev->nChainFullyShieldedTx == 0)
+ pindex->pprev->nChainFullyShieldedTx = zstats.nChainFullyShieldedTx;
+ if (pindex->pprev->nChainShieldingTx == 0)
+ pindex->pprev->nChainShieldingTx = zstats.nChainShieldingTx;
+ if (pindex->pprev->nChainDeshieldingTx == 0)
+ pindex->pprev->nChainDeshieldingTx = zstats.nChainDeshieldingTx;
+ if (pindex->pprev->nChainPayments == 0) {
+ fprintf(stderr, "%s: setting nChainPayments=%li at height %d\n", __func__, zstats.nChainPayments, chainActive.Height() );
+ pindex->pprev->nChainPayments = zstats.nChainPayments;
+ }
+ if (pindex->pprev->nChainShieldedPayments == 0)
+ pindex->pprev->nChainShieldedPayments = zstats.nChainShieldedPayments;
+ if (pindex->pprev->nChainFullyShieldedPayments == 0)
+ pindex->pprev->nChainFullyShieldedPayments = zstats.nChainFullyShieldedPayments;
+ if (pindex->pprev->nChainShieldingPayments == 0)
+ pindex->pprev->nChainShieldingPayments = zstats.nChainShieldingPayments;
+ if (pindex->pprev->nChainDeshieldingPayments == 0)
+ pindex->pprev->nChainDeshieldingPayments = zstats.nChainDeshieldingPayments;
+ }
+
pindex->nChainNotarizations = (pindex->pprev ? pindex->pprev->nChainNotarizations : 0) + pindex->nNotarizations;
pindex->nChainShieldedTx = (pindex->pprev ? pindex->pprev->nChainShieldedTx : 0) + pindex->nShieldedTx;
pindex->nChainShieldedOutputs = (pindex->pprev ? pindex->pprev->nChainShieldedOutputs : 0) + pindex->nShieldedOutputs;
@@ -4572,6 +4695,23 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
pindex->nChainFullyShieldedPayments = (pindex->pprev ? pindex->pprev->nChainFullyShieldedPayments : 0) + pindex->nFullyShieldedPayments;
pindex->nChainShieldingPayments = (pindex->pprev ? pindex->pprev->nChainShieldingPayments : 0) + pindex->nShieldingPayments;
pindex->nChainDeshieldingPayments = (pindex->pprev ? pindex->pprev->nChainDeshieldingPayments : 0) + pindex->nDeshieldingPayments;
+
+ // Update in-memory structure that gets serialized to zindex.dat
+ zstats.nHeight = pindex->GetHeight();
+ zstats.nChainNotarizations = pindex->nChainNotarizations ;
+ zstats.nChainShieldedTx = pindex->nChainShieldedTx ;
+ zstats.nChainShieldedOutputs = pindex->nChainShieldedOutputs ;
+ zstats.nChainShieldedSpends = pindex->nChainShieldedSpends ;
+ zstats.nChainFullyShieldedTx = pindex->nChainFullyShieldedTx ;
+ zstats.nChainShieldingTx = pindex->nChainShieldingTx ;
+ zstats.nChainDeshieldingTx = pindex->nChainDeshieldingTx ;
+ zstats.nChainPayments = pindex->nChainPayments ;
+ zstats.nChainShieldedPayments = pindex->nChainShieldedPayments ;
+ zstats.nChainFullyShieldedPayments = pindex->nChainFullyShieldedPayments ;
+ zstats.nChainShieldingPayments = pindex->nChainShieldingPayments ;
+ zstats.nChainDeshieldingPayments = pindex->nChainDeshieldingPayments ;
+ fprintf(stderr,"%s: setting zstats with height,zouts,zspends,anonset=%li,%li,%li,%li\n", __FUNCTION__, zstats.nHeight, zstats.nChainShieldedOutputs, zstats.nChainShieldedSpends, zstats.nChainShieldedOutputs - zstats.nChainShieldedSpends);
+
}
if (pindex->pprev) {
@@ -4610,6 +4750,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
}
}
+
if (fZindex)
fprintf(stderr, "ht.%d, ShieldedPayments=%d, ShieldedTx=%d, ShieldedOutputs=%d, FullyShieldedTx=%d, ntz=%d\n",
pindexNew->GetHeight(), nShieldedPayments, nShieldedTx, nShieldedOutputs, nFullyShieldedTx, nNotarizations );
diff --git a/src/main.h b/src/main.h
index 078e48cef..676a069cd 100644
--- a/src/main.h
+++ b/src/main.h
@@ -950,4 +950,114 @@ std::pair>, uint64_t> DrainRecent
void SetChainNotifiedSequence(uint64_t recentlyConflictedSequence);
bool ChainIsFullyNotified();
+class CZindexStats
+{
+//private:
+public:
+ int64_t nHeight;
+ int64_t nChainTx;
+ int64_t nChainNotarizations;
+ int64_t nChainPayments;
+ int64_t nChainShieldedTx;
+ int64_t nChainShieldedOutputs;
+ int64_t nChainShieldedSpends;
+ int64_t nChainFullyShieldedTx;
+ int64_t nChainShieldingPayments;
+ int64_t nChainShieldedPayments;
+ int64_t nChainFullyShieldedPayments;
+ int64_t nChainDeshieldingTx;
+ int64_t nChainDeshieldingPayments;
+ int64_t nChainShieldingTx;
+
+ size_t Height() const
+ {
+ return nHeight;
+ }
+
+ void Clear()
+ {
+ LOCK(cs_main);
+ nChainTx=0;
+ nChainNotarizations=0;
+ nChainPayments=0;
+ nChainShieldedTx=0;
+ nChainShieldedOutputs=0;
+ nChainShieldedSpends=0;
+ nChainFullyShieldedTx=0;
+ nChainShieldingPayments=0;
+ nChainShieldedPayments=0;
+ nChainFullyShieldedPayments=0;
+ nChainDeshieldingTx=0;
+ nChainDeshieldingPayments=0;
+ nChainShieldingTx=0;
+ }
+
+ CZindexStats()
+ {
+ Clear();
+ }
+
+ ~CZindexStats()
+ {
+ }
+
+ template void Serialize(Stream &s) const
+ {
+ LOCK(cs_main);
+
+ // So we can detect a new version and force a rescan
+ unsigned char nVersion = 1;
+ s << nVersion;
+ s << nHeight;
+ s << nChainTx;
+ s << nChainNotarizations;
+ s << nChainPayments;
+ s << nChainShieldedTx;
+ s << nChainShieldedOutputs;
+ s << nChainShieldedSpends;
+ s << nChainFullyShieldedTx;
+ s << nChainShieldingPayments;
+ s << nChainShieldedPayments;
+ s << nChainFullyShieldedPayments;
+ s << nChainDeshieldingTx;
+ s << nChainDeshieldingPayments;
+ s << nChainShieldingTx;
+ }
+
+ template void Unserialize(Stream& s)
+ {
+ LOCK(cs_main);
+
+ Clear();
+ unsigned char nVersion;
+ s >> nVersion;
+ s >> nHeight;
+ s >> nChainTx;
+ s >> nChainNotarizations;
+ s >> nChainPayments;
+ s >> nChainShieldedTx;
+ s >> nChainShieldedOutputs;
+ s >> nChainShieldedSpends;
+ s >> nChainFullyShieldedTx;
+ s >> nChainShieldingPayments;
+ s >> nChainShieldedPayments;
+ s >> nChainFullyShieldedPayments;
+ s >> nChainDeshieldingTx;
+ s >> nChainDeshieldingPayments;
+ s >> nChainShieldingTx;
+ }
+};
+
+// Wrapper for zindex.dat stats
+class CZindexDB
+{
+private:
+ boost::filesystem::path pathAddr;
+public:
+ CZindexDB();
+ bool Write(const CZindexStats& zstats);
+ bool Read(CZindexStats& zstats);
+};
+
+
#endif // HUSH_MAIN_H
diff --git a/src/miner.cpp b/src/miner.cpp
index 159682f32..7ce7cf404 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -210,10 +210,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
// Collect memory pool transactions into the block
CAmount nFees = 0;
- // we will attempt to spend any cheats we see
- CTransaction cheatTx;
- boost::optional cheatSpend;
-
uint256 cbHash;
boost::this_thread::interruption_point(); // exit thread before entering locks.
@@ -861,19 +857,26 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
scriptPubKey = CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG;
} else {
{
- if (!reservekey.GetReservedKey(pubkey))
- {
- return NULL;
- }
- scriptPubKey.resize(35);
- ptr = (uint8_t *)pubkey.begin();
- scriptPubKey[0] = 33;
- for (i=0; i<33; i++) {
- scriptPubKey[i+1] = ptr[i];
- }
- scriptPubKey[34] = OP_CHECKSIG;
- }
- }
+ // Support mining with -disablewallet and minetolocalwallet=0
+ if (!GetBoolArg("-disablewallet", false)) {
+ // wallet enabled
+ if (!reservekey.GetReservedKey(pubkey))
+ return NULL;
+ scriptPubKey.clear();
+ scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
+ } else {
+ // wallet disabled
+ CTxDestination dest = DecodeDestination(GetArg("-mineraddress", ""));
+ if (IsValidDestination(dest)) {
+ // CKeyID keyID = boost::get(dest);
+ // scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
+ scriptPubKey = GetScriptForDestination(dest);
+ } else {
+ return NULL;
+ }
+ }
+ }
+ }
return CreateNewBlock(pubkey, scriptPubKey, gpucount, isStake);
}
@@ -895,29 +898,6 @@ void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,st
}
}
-void komodo_broadcast(CBlock *pblock,int32_t limit)
-{
- if (IsInitialBlockDownload())
- return;
- int32_t n = 1;
- //fprintf(stderr,"broadcast new block t.%u\n",(uint32_t)time(NULL));
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- {
- if ( pnode->hSocket == INVALID_SOCKET )
- continue;
- if ( (rand() % n) == 0 )
- {
- pnode->PushMessage("block", *pblock);
- if ( n++ > limit )
- break;
- }
- }
- }
- //fprintf(stderr,"finished broadcast new block t.%u\n",(uint32_t)time(NULL));
-}
-
static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
#else
static bool ProcessBlockFound(CBlock* pblock)
@@ -972,7 +952,6 @@ static bool ProcessBlockFound(CBlock* pblock)
return error("HushMiner: ProcessNewBlock, block not accepted");
TrackMinedBlock(pblock->GetHash());
- //komodo_broadcast(pblock,16);
return true;
}
diff --git a/src/net.cpp b/src/net.cpp
index 808df788c..d7833b4a0 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -48,6 +48,11 @@ using namespace hush;
// Satoshi originally used 10 seconds(!), did they know something Peter Wuille didn't?
#define DUMP_ADDRESSES_INTERVAL 300
+// This is every 2 blocks, on avg, on HUSH3
+#define DUMP_ZINDEX_INTERVAL 150
+
+#define CHECK_PLZ_STOP_INTERVAL 120
+
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
@@ -89,10 +94,10 @@ namespace {
};
}
+
// Global state variables
extern uint16_t ASSETCHAINS_P2PPORT;
extern char SMART_CHAIN_SYMBOL[65];
-
bool fDiscover = true;
bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK | NODE_NSPV;
@@ -103,11 +108,14 @@ static CNode* pnodeLocalHost = NULL;
uint64_t nLocalHostNonce = 0;
static std::vector vhListenSocket;
CAddrMan addrman;
+CZindexStats zstats;
int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
bool fAddressesInitialized = false;
std::string strSubVersion;
TLSManager tlsmanager = TLSManager();
+extern void StartShutdown();
+
vector vNodes;
CCriticalSection cs_vNodes;
map mapRelay;
@@ -1400,6 +1408,28 @@ void DumpAddresses()
LogPrint("net", "Flushed %d addresses to peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart);
}
+void DumpZindexStats()
+{
+ int64_t nStart = GetTimeMillis();
+
+ CZindexDB zdb;
+ zdb.Write(zstats);
+
+ LogPrintf("Flushed stats at height %li to zindex.dat %dms\n", zstats.Height(), GetTimeMillis() - nStart);
+}
+
+void CheckIfWeShouldStop()
+{
+ // If the RPC interface is "stuck", such as filling up with deadlocks
+ // and cannot process any more requests, the only option was to kill the full node.
+ // This is a disk-based method where a node can realize it should stop, and which
+ // can help avoid extremely long rescans
+ if(boost::filesystem::exists(GetDataDir() / "plz_stop")) {
+ LogPrintf("%s: Found plz_stop file, shutting down...\n", __func__);
+ StartShutdown();
+ }
+}
+
void static ProcessOneShot()
{
string strDest;
@@ -1909,8 +1939,40 @@ void static Discover(boost::thread_group& threadGroup)
#endif
}
+//extern CWallet pwalletMain;
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
{
+
+ CheckIfWeShouldStop();
+
+ if (fZindex) {
+ uiInterface.InitMessage(_("Loading zindex stats..."));
+ int64_t nStart = GetTimeMillis();
+ {
+ CZindexDB zdb;
+ if (!zdb.Read(zstats)) {
+ // The first time nodes use zindex.dat code, no file will be found
+ // TODO: rescan if invalid only
+ LogPrintf("Invalid or missing zindex.dat! Generating new...\n");
+
+ //bool update = true;
+ //pwalletMain->ScanForWalletTransactions(chainActive.Genesis(),update);
+
+ // We assume this is the first startup with zindex.dat code, and serialize current data to disk.
+ DumpZindexStats();
+
+ // Now read-in the stats we just wrote to disk to memory
+ if(!zdb.Read(zstats)) {
+ LogPrintf("Invalid or missing zindex.dat! Stats may be corrupt\n");
+ } else {
+ LogPrintf("Loaded stats at height %li from zindex.dat %dms\n", zstats.Height(), GetTimeMillis() - nStart);
+ }
+ } else {
+ LogPrintf("Loaded stats at height %li from zindex.dat %dms\n", zstats.Height(), GetTimeMillis() - nStart);
+ }
+ }
+ }
+
uiInterface.InitMessage(_("Loading addresses..."));
// Load addresses for peers.dat
int64_t nStart = GetTimeMillis();
@@ -1919,8 +1981,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!adb.Read(addrman))
LogPrintf("Invalid or missing peers.dat! This can happen when upgrading. Whatevz, recreating\n");
}
- LogPrintf("Loaded %i addresses from peers.dat %dms\n",
- addrman.size(), GetTimeMillis() - nStart);
+ LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart);
fAddressesInitialized = true;
if (semOutbound == NULL) {
@@ -1968,6 +2029,13 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
// Dump network addresses
scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL);
+
+ // Dump zindex stats if -zindex is enabled
+ if (fZindex) {
+ scheduler.scheduleEvery(&DumpZindexStats, DUMP_ZINDEX_INTERVAL);
+ }
+
+ scheduler.scheduleEvery(&CheckIfWeShouldStop, CHECK_PLZ_STOP_INTERVAL);
}
bool StopNode()
@@ -1977,6 +2045,9 @@ bool StopNode()
for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++)
semOutbound->post();
+ // persist current zindex stats to disk before we exit
+ DumpZindexStats();
+
if (HUSH_NSPV_FULLNODE && fAddressesInitialized)
{
DumpAddresses();
diff --git a/src/net.h b/src/net.h
index bdc56de1b..d55d500e1 100644
--- a/src/net.h
+++ b/src/net.h
@@ -223,6 +223,7 @@ public:
int nStartingHeight;
uint64_t nSendBytes;
uint64_t nRecvBytes;
+ bool fRelayTxes;
bool fAllowlisted; // If true this node bypasses DoS ban limits
bool fFeeler; // If true this node is being used as a short lived feeler.
double dPingTime;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 7c38ef1eb..609f26420 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1660,10 +1660,12 @@ UniValue getchaintxstats(const UniValue& params, bool fHelp, const CPubKey& mypk
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
}
}
+ LogPrintf("%s: blockcount = %d\n", __func__, blockcount);
const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->GetHeight() - blockcount);
int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast();
int nTxDiff = pindex->nChainTx - pindexPast->nChainTx;
+ LogPrintf("%s: pindexPast.height = %d, pindex.height = %d\n", __func__, pindexPast->GetHeight(), pindex->GetHeight() );
UniValue ret(UniValue::VOBJ);
ret.pushKV("time", (int64_t)pindex->nTime);
@@ -1695,6 +1697,7 @@ UniValue getchaintxstats(const UniValue& params, bool fHelp, const CPubKey& mypk
ret.pushKV("window_tx_count", nTxDiff);
ret.pushKV("window_interval", nTimeDiff);
int64_t nPaymentsDiff = pindex->nChainPayments - pindexPast->nChainPayments;
+ LogPrintf("%s: pindexPast.nChainPayments = %d, pindex.nChainPayments = %d\n", __func__, pindexPast->nChainPayments, pindex->nChainPayments );
int64_t nShieldedTxDiff = pindex->nChainShieldedTx - pindexPast->nChainShieldedTx;
int64_t nShieldingTxDiff = pindex->nChainShieldingTx - pindexPast->nChainShieldingTx;
int64_t nDeshieldingTxDiff = pindex->nChainDeshieldingTx - pindexPast->nChainDeshieldingTx;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 46c3cf24d..4533b0196 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -95,6 +95,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
" \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
" \"bytessent\": n, (numeric) The total bytes sent\n"
" \"bytesrecv\": n, (numeric) The total bytes received\n"
+ " \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n"
" \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"timeoffset\": ttt, (numeric) The time offset in seconds (deprecated, always 0)\n"
" \"pingtime\": n, (numeric) ping time\n"
@@ -146,6 +147,8 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
obj.push_back(Pair("lastrecv", stats.nLastRecv));
obj.push_back(Pair("bytessent", stats.nSendBytes));
obj.push_back(Pair("bytesrecv", stats.nRecvBytes));
+ obj.push_back(Pair("relaytxes", stats.fRelayTxes));
+
obj.push_back(Pair("conntime", stats.nTimeConnected));
obj.push_back(Pair("timeoffset", 0));
obj.push_back(Pair("pingtime", stats.dPingTime));
@@ -177,15 +180,15 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
}
int32_t HUSH_LONGESTCHAIN;
+static int32_t hush_longest_depth = 0;
int32_t hush_longestchain()
{
- static int32_t depth;
int32_t ht,n=0,num=0,maxheight=0,height = 0;
- if ( depth < 0 )
- depth = 0;
- if ( depth == 0 )
+ if ( hush_longest_depth < 0 )
+ hush_longest_depth = 0;
+ if ( hush_longest_depth == 0 )
{
- depth++;
+ hush_longest_depth++;
vector vstats;
{
//LOCK(cs_main);
@@ -212,7 +215,7 @@ int32_t hush_longestchain()
if ( ht > height )
height = ht;
}
- depth--;
+ hush_longest_depth--;
if ( num > (n >> 1) )
{
if ( 0 && height != HUSH_LONGESTCHAIN )
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 1914aa8df..82fcfdf97 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -646,7 +646,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp, const CPubKey&
" ]\n"
"2. \"outputs\" (object, required) a json object with outputs\n"
" {\n"
- " \"address\": x.xxx, (numeric or string, required) The key is the komodo address or script (in hex), the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n"
+ " \"address\": x.xxx, (numeric or string, required) The key is the HUSH address or script (in hex), the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n"
" \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n"
" ,...\n"
" }\n"
@@ -821,7 +821,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp, const CPubKey&
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
- " \"RTZMZHDFSTFQst8XmX2dR4DaH87cEUs3gC\" (string) komodo address\n"
+ " \"RTZMZHDFSTFQst8XmX2dR4DaH87cEUs3gC\" (string) HUSH address\n"
" ,...\n"
" ]\n"
" }\n"
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 5ae2c88e1..e999cc423 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -825,9 +825,13 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms
{
LOCK(cs_rpcWarmup);
if (fRPCInWarmup) {
- // hush-cli stop is the only valid RPC command during warmup
- // We don't know if we have valid blocks or wallet yet, nothing else is safe
- if (pcmd->name != "stop") {
+ // Most RPCs are unsafe to run during warmup, but stop+help are fine
+ // Others may not have data loaded yet, such as wallet details, but
+ // those RPCs are written defensively to deal with that. Allowing these
+ // few RPCs means we can see our addresses and make private key backups
+ // while a very long wallet rescan is happening
+ if (pcmd->name != "stop" && pcmd->name != "help" && pcmd->name != "z_listaddresses" && pcmd->name != "z_exportkey" &&
+ pcmd->name != "listaddresses" && pcmd->name != "dumpprivkey" && pcmd->name != "getpeerinfo" ) {
throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
}
}
diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp
index c17051ff9..3ff6269b2 100644
--- a/src/transaction_builder.cpp
+++ b/src/transaction_builder.cpp
@@ -59,6 +59,13 @@ void TransactionBuilder::AddSaplingOutput(
mtx.valueBalance -= value;
}
+// randomize the order of outputs
+void TransactionBuilder::ShuffleOutputs()
+{
+ LogPrintf("%s: Shuffling %d zouts\n", __func__, outputs.size() );
+ random_shuffle( outputs.begin(), outputs.end(), GetRandInt );
+}
+
void TransactionBuilder::AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value, uint32_t _nSequence)
{
if (keystore == nullptr) {
@@ -212,6 +219,9 @@ boost::optional TransactionBuilder::Build()
mtx.vShieldedSpend.push_back(sdesc);
}
+ // Prevent leaking metadata about the position of change output
+ ShuffleOutputs();
+
// Create Sapling OutputDescriptions
for (auto output : outputs) {
auto cm = output.note.cm();
diff --git a/src/transaction_builder.h b/src/transaction_builder.h
index dba7e7b43..89a8d6580 100644
--- a/src/transaction_builder.h
+++ b/src/transaction_builder.h
@@ -92,6 +92,8 @@ public:
CAmount value,
std::array memo = {{0}});
+ void ShuffleOutputs();
+
// Assumes that the value correctly corresponds to the provided UTXO.
void AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value, uint32_t nSequence = 0xffffffff);
diff --git a/src/version.h b/src/version.h
index fde7afc4b..3c8f28347 100644
--- a/src/version.h
+++ b/src/version.h
@@ -21,7 +21,7 @@
#define HUSH_VERSION_H
// network protocol versioning
-static const int PROTOCOL_VERSION = 1987422;
+static const int PROTOCOL_VERSION = 1987423;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
//! In this version, 'getheaders' was introduced.
diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp
index e432ffdb0..a4d4857e0 100644
--- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp
+++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp
@@ -46,6 +46,7 @@
using namespace libzcash;
extern uint64_t ASSETCHAINS_TIMELOCKGTE;
+extern string randomSietchZaddr();
AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
TransactionBuilder builder,
@@ -229,6 +230,17 @@ bool ShieldToAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) c
// Send all value to the target z-addr
m_op->builder_.SendChangeTo(zaddr, ovk);
+ // Sietchified Shielding of Coinbase Funds
+ // Add Sietch zouts so it's unclear which zout contains value :)
+ // This reduces metadata leakage of coinbase t=>z tx's
+ CAmount amount = 0;
+ auto zdust1 = DecodePaymentAddress(randomSietchZaddr());
+ auto zdust2 = DecodePaymentAddress(randomSietchZaddr());
+ auto sietchZout1 = boost::get(zdust1);
+ auto sietchZout2 = boost::get(zdust2);
+ m_op->builder_.AddSaplingOutput(ovk, sietchZout1, amount);
+ m_op->builder_.AddSaplingOutput(ovk, sietchZout2, amount);
+
// Build the transaction
auto maybe_tx = m_op->builder_.Build();
if (!maybe_tx) {
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 8a5398945..e5a7d2034 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -201,7 +201,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp, const CPubKey& mypk)
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"4. height (integer, optional, default=0) start at block height?\n"
"5. secret_key (integer, optional, default=188) decimal value used to import WIFs of other coins\n"
- "\nNote: This call can take minutes to complete if rescan is true.\n"
+ "\nNote: This call can take a long time to complete if rescan is true.\n"
"\nExamples:\n"
"\nDump a private key\n"
+ HelpExampleCli("dumpprivkey", "\"myaddress\"") +
@@ -295,7 +295,7 @@ UniValue importaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
"1. \"address\" (string, required) The address\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
- "\nNote: This call can take minutes to complete if rescan is true.\n"
+ "\nNote: This call can take a long time to complete if rescan is true.\n"
"\nExamples:\n"
"\nImport an address with rescan\n"
+ HelpExampleCli("importaddress", "\"myaddress\"") +
@@ -749,7 +749,7 @@ UniValue z_importkey(const UniValue& params, bool fHelp, const CPubKey& mypk)
"1. \"zkey\" (string, required) The zkey (see z_exportkey)\n"
"2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n"
"3. startHeight (numeric, optional, default=0) Block height to start rescan from\n"
- "\nNote: This call can take minutes to complete if rescan is true.\n"
+ "\nNote: This call can take a long time to complete if rescan is true.\n"
"\nExamples:\n"
"\nExport a zkey\n"
+ HelpExampleCli("z_exportkey", "\"myaddress\"") +
@@ -841,7 +841,7 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp, const CPubKey& m
"2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n"
"3. startHeight (numeric, optional, default=0) Block height to start rescan from\n"
"4. zaddr (string, optional, default=\"\") zaddr in case of importing viewing key for Sapling\n"
- "\nNote: This call can take minutes to complete if rescan is true.\n"
+ "\nNote: This call can take a long time to complete if rescan is true.\n"
"\nExamples:\n"
"\nImport a viewing key\n"
+ HelpExampleCli("z_importviewingkey", "\"vkey\"") +
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 1b90c56a5..4da6204e6 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1103,7 +1103,7 @@ UniValue cleanwallettransactions(const UniValue& params, bool fHelp, const CPubK
if (fHelp || params.size() > 1 )
throw runtime_error(
"cleanwallettransactions \"txid\"\n"
- "\nRemove all txs that are spent. You can clear all txs bar one, by specifiying a txid.\n"
+ "\nRemove all transparent UTXOs that are spent. You can clear all transactions bar one, by specifiying a txid.\n"
"\nPlease backup your wallet.dat before running this command.\n"
"\nArguments:\n"
"1. \"txid\" (string, optional) The transaction id to keep.\n"
@@ -1133,9 +1133,7 @@ UniValue cleanwallettransactions(const UniValue& params, bool fHelp, const CPubK
if ( !pwalletMain->IsMine(tmp_tx) )
{
throw runtime_error("\nThe transaction is not yours!\n");
- }
- else
- {
+ } else {
for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
@@ -1145,14 +1143,10 @@ UniValue cleanwallettransactions(const UniValue& params, bool fHelp, const CPubK
}
}
}
- }
- else
- {
+ } else {
throw runtime_error("\nThe transaction could not be found!\n");
}
- }
- else
- {
+ } else {
// get all locked utxos to relock them later.
vector vLockedUTXO;
pwalletMain->ListLockedCoins(vLockedUTXO);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 0a848ff33..3bc3b99cd 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -480,13 +480,19 @@ void CWallet::ChainTip(const CBlockIndex *pindex,
pblock->GetBlockTime() > GetTime() - 144*ASSETCHAINS_BLOCKTIME)
{
BuildWitnessCache(pindex, false);
- RunSaplingConsolidation(pindex->GetHeight());
- DeleteWalletTransactions(pindex);
+ if (fSaplingConsolidationEnabled) {
+ RunSaplingConsolidation(pindex->GetHeight());
+ }
+ if (fTxDeleteEnabled) {
+ DeleteWalletTransactions(pindex);
+ }
} else {
//Build initial witnesses on every block
BuildWitnessCache(pindex, true);
- if (initialDownloadCheck && pindex->GetHeight() % fDeleteInterval == 0) {
- DeleteWalletTransactions(pindex);
+ if (fTxDeleteEnabled) {
+ if (initialDownloadCheck && pindex->GetHeight() % fDeleteInterval == 0) {
+ DeleteWalletTransactions(pindex);
+ }
}
}
} else {
@@ -902,12 +908,15 @@ int64_t CWallet::NullifierCount()
void CWallet::ClearNoteWitnessCache()
{
LOCK(cs_wallet);
+ int notes = 0;
for (std::pair& wtxItem : mapWallet) {
for (mapSaplingNoteData_t::value_type& item : wtxItem.second.mapSaplingNoteData) {
item.second.witnesses.clear();
item.second.witnessHeight = -1;
+ notes++;
}
}
+ LogPrintf("%s: Cleared witness data from %d wallet items and %d SaplingNotes\n", __func__, mapWallet.size(), notes);
}
void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
@@ -1122,6 +1131,7 @@ void CWallet::BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly)
nd->witnessHeight = pblockindex->GetHeight();
}
}
+
}
}
@@ -2378,12 +2388,6 @@ bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
return pwalletdb->WriteTx(GetHash(), *this);
}
-void CWallet::WitnessNoteCommitment(std::vector commitments,
- std::vector>& witnesses,
- uint256 &final_anchor)
-{
-}
-
/**
* Reorder the transactions based on block hieght and block index.
* Transactions can get out of order when they are deleted and subsequently
@@ -2734,8 +2738,10 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
BuildWitnessCache(pindex, true);
//Delete Transactions
- if (pindex->GetHeight() % fDeleteInterval == 0)
- DeleteWalletTransactions(pindex);
+ if (fTxDeleteEnabled) {
+ if (pindex->GetHeight() % fDeleteInterval == 0)
+ DeleteWalletTransactions(pindex);
+ }
if (GetTime() >= nNow + 60) {
nNow = GetTime();
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index d78834727..965ab5b22 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1122,10 +1122,6 @@ public:
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
void RescanWallet();
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
- void WitnessNoteCommitment(
- std::vector commitments,
- std::vector>& witnesses,
- uint256 &final_anchor);
void ReorderWalletTransactions(std::map, CWalletTx*> &mapSorted, int64_t &maxOrderPos);
void UpdateWalletTransactionOrder(std::map, CWalletTx*> &mapSorted, bool resetOrder);
void DeleteTransactions(std::vector &removeTxs);