From a90f03ce6dd3347689229fa4bff1116e838f309e Mon Sep 17 00:00:00 2001 From: Duke Date: Wed, 16 Aug 2023 10:37:23 -0400 Subject: [PATCH 01/22] Fix build-debian-package.sh docs and document how to make an aarch64 deb --- doc/release-process.md | 2 ++ util/build-debian-package.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/release-process.md b/doc/release-process.md index 93fec2434..08cedae03 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -122,3 +122,5 @@ Install deps on Linux: ## Platform-specific notes Use `./util/build-mac.sh` to compile on Apple/Mac systems, use `./util/build-win.sh` to build on Windows and `./util/build-arm.sh` to build on ARMv8 systems. + +Use `./util/build-debian-package.sh aarch64` to build a Debian package for aarch64 . diff --git a/util/build-debian-package.sh b/util/build-debian-package.sh index 11e9c1073..595118d19 100755 --- a/util/build-debian-package.sh +++ b/util/build-debian-package.sh @@ -4,7 +4,7 @@ # file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html ## Usages: ## ./util/build-debian-package.sh # build amd64 package -## ARCH=aarch64 ./util/build-debian-package.sh # build package for specific archiecture +## ./util/build-debian-package.sh aarch64 # build package for specific archiecture ARCH=${1:-amd64} echo "Let There Be Hush Debian Packages" From bacc08e81743aca5b7b31f6346268c3a44e9fa7b Mon Sep 17 00:00:00 2001 From: Duke Date: Sun, 3 Sep 2023 08:37:19 -0400 Subject: [PATCH 02/22] Remove sprout data from valuePools This codebase does not support sprout, the data will always be zero/empty and is essentially useless cruft, so we delete it. --- src/rpc/blockchain.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 7bdf840da..6f34bbc80 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -324,7 +324,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("blocktype", "mined")); UniValue valuePools(UniValue::VARR); - valuePools.push_back(ValuePoolDesc("sprout", blockindex->nChainSproutValue, blockindex->nSproutValue)); valuePools.push_back(ValuePoolDesc("sapling", blockindex->nChainSaplingValue, blockindex->nSaplingValue)); result.push_back(Pair("valuePools", valuePools)); @@ -1310,14 +1309,10 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp, const CPubKey& my obj.push_back(Pair("chainwork", chainActive.LastTip()->chainPower.chainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); - //SproutMerkleTree tree; - //pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), tree); - //obj.push_back(Pair("commitments", static_cast(tree.size()))); obj.push_back(Pair("commitments", 0)); CBlockIndex* tip = chainActive.LastTip(); UniValue valuePools(UniValue::VARR); - valuePools.push_back(ValuePoolDesc("sprout", tip->nChainSproutValue, boost::none)); valuePools.push_back(ValuePoolDesc("sapling", tip->nChainSaplingValue, boost::none)); obj.push_back(Pair("valuePools", valuePools)); From bd38a125129de4bd18a9c9b7e2c49cc35d2c6753 Mon Sep 17 00:00:00 2001 From: Duke Date: Sun, 3 Sep 2023 08:40:06 -0400 Subject: [PATCH 03/22] Remove useless sprout key from coinsupply RPC --- src/rpc/misc.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index a65c020c2..20fd31147 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -429,7 +429,6 @@ UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk) " \"height\" : 420, (integer) The height of this coin supply data\n" " \"supply\" : \"555.0\", (float) The transparent coin supply\n" " \"zfunds\" : \"0.55555\", (float) The shielded coin supply (in zaddrs)\n" - " \"sprout\" : \"0.000\", (float) The sprout coin supply (in zcaddrs)\n" " \"total\" : \"555.55555\", (float) The total coin supply, i.e. sum of supply + zfunds\n" "}\n" "\nExamples:\n" @@ -449,7 +448,6 @@ UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk) result.push_back(Pair("height", (int)height)); result.push_back(Pair("supply", ValueFromAmount(supply))); result.push_back(Pair("zfunds", ValueFromAmount(zfunds))); - result.push_back(Pair("sprout", ValueFromAmount(sproutfunds))); result.push_back(Pair("total", ValueFromAmount(zfunds + supply))); if ( ASSETCHAINS_BLOCKTIME > 0 ) { From e2521ac2fac01577cd53b5e40e24d5ad31434ec9 Mon Sep 17 00:00:00 2001 From: Duke Date: Sun, 3 Sep 2023 08:48:06 -0400 Subject: [PATCH 04/22] Remove unused sproutfunds argument --- src/hush_bitcoind.h | 15 ++++++--------- src/rpc/misc.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/hush_bitcoind.h b/src/hush_bitcoind.h index b09c756ad..712c6854e 100644 --- a/src/hush_bitcoind.h +++ b/src/hush_bitcoind.h @@ -1790,9 +1790,9 @@ int32_t hush_scpublic(uint32_t tiptime) return 0; } -int64_t hush_newcoins(int64_t *zfundsp,int64_t *sproutfundsp,int32_t nHeight,CBlock *pblock) +int64_t hush_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock) { - CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0,sproutfunds=0; + CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0; n = pblock->vtx.size(); for (i=0; i 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 ) @@ -1840,11 +1839,11 @@ int64_t hush_newcoins(int64_t *zfundsp,int64_t *sproutfundsp,int32_t nHeight,CBl return(voutsum - vinsum); } -int64_t hush_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height) +int64_t hush_coinsupply(int64_t *zfundsp,int32_t height) { - CBlockIndex *pindex; CBlock block; int64_t zfunds=0,sproutfunds=0,supply = 0; + CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0; //fprintf(stderr,"coinsupply %d\n",height); - *zfundsp = *sproutfundsp = 0; + *zfundsp = 0; if ( (pindex= hush_chainactive(height)) != 0 ) { while ( pindex != 0 && pindex->GetHeight() > 0 ) @@ -1852,7 +1851,7 @@ int64_t hush_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height) if ( pindex->newcoins == 0 && pindex->zfunds == 0 ) { if ( hush_blockload(block,pindex) == 0 ) { - pindex->newcoins = hush_newcoins(&pindex->zfunds,&pindex->sproutfunds,pindex->GetHeight(),&block); + pindex->newcoins = hush_newcoins(&pindex->zfunds,pindex->GetHeight(),&block); } else { fprintf(stderr,"error loading block.%d\n",pindex->GetHeight()); return(0); @@ -1860,13 +1859,11 @@ int64_t hush_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height) } supply += pindex->newcoins; zfunds += pindex->zfunds; - sproutfunds += pindex->sproutfunds; //printf("start ht.%d new %.8f -> supply %.8f zfunds %.8f -> %.8f\n",pindex->GetHeight(),dstr(pindex->newcoins),dstr(supply),dstr(pindex->zfunds),dstr(zfunds)); pindex = pindex->pprev; } } *zfundsp = zfunds; - *sproutfundsp = sproutfunds; return(supply); } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 20fd31147..fcc44d2b9 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -65,7 +65,7 @@ int32_t hush_whoami(char *pubkeystr,int32_t height,uint32_t timestamp); extern int32_t HUSH_LASTMINED,HUSH_LONGESTCHAIN,IS_HUSH_NOTARY,HUSH_INSYNC; extern char SMART_CHAIN_SYMBOL[HUSH_SMART_CHAIN_MAXLEN]; uint32_t hush_segid32(char *coinaddr); -int64_t hush_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height); +int64_t hush_coinsupply(int64_t *zfundsp,int32_t height); int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *hushnotarized_heightp); uint64_t hush_notarypayamount(int32_t nHeight, int64_t notarycount); int32_t hush_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); @@ -416,7 +416,7 @@ public: UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk) { - int32_t height = 0; int32_t currentHeight; int64_t blocks_per_year,zf1,zf3,zf12,sf1,sf3,sf12,sproutfunds,zfunds,supply1,supply3,supply12,supply = 0; UniValue result(UniValue::VOBJ); + int32_t height = 0; int32_t currentHeight; int64_t blocks_per_year,zf1,zf3,zf12,zfunds,supply1,supply3,supply12,supply = 0; UniValue result(UniValue::VOBJ); if (fHelp || params.size() > 1) throw runtime_error("coinsupply \n" "\nReturn coin supply information at a given block height. If no height is given, the current height is used.\n" @@ -441,7 +441,7 @@ UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk) currentHeight = chainActive.Height(); if (height >= 0 && height <= currentHeight) { - if ( (supply= hush_coinsupply(&zfunds,&sproutfunds,height)) > 0 ) + if ( (supply= hush_coinsupply(&zfunds,height)) > 0 ) { result.push_back(Pair("result", "success")); result.push_back(Pair("coin", SMART_CHAIN_SYMBOL[0] == 0 ? "HUSH" : SMART_CHAIN_SYMBOL)); @@ -454,9 +454,9 @@ UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk) blocks_per_year = 24*3600*365 / ASSETCHAINS_BLOCKTIME; if ( height > blocks_per_year ) { - supply1 = hush_coinsupply(&zf1,&sf1,height - blocks_per_year/12); - supply3 = hush_coinsupply(&zf3,&sf3,height - blocks_per_year/4); - supply12 = hush_coinsupply(&zf12,&sf12,height - blocks_per_year); + supply1 = hush_coinsupply(&zf1,height - blocks_per_year/12); + supply3 = hush_coinsupply(&zf3,height - blocks_per_year/4); + supply12 = hush_coinsupply(&zf12,height - blocks_per_year); if ( supply1 != 0 && supply3 != 0 && supply12 != 0 ) { result.push_back(Pair("lastmonth", ValueFromAmount(supply1+zf1))); From 1c45a71b05abea9f5a984316941b9420d44a7344 Mon Sep 17 00:00:00 2001 From: Duke Date: Sun, 3 Sep 2023 08:52:28 -0400 Subject: [PATCH 05/22] Remove dead code --- src/hush_bitcoind.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hush_bitcoind.h b/src/hush_bitcoind.h index 712c6854e..8d7756430 100644 --- a/src/hush_bitcoind.h +++ b/src/hush_bitcoind.h @@ -1786,7 +1786,7 @@ int32_t hush_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) int32_t hush_scpublic(uint32_t tiptime) { - // HUSH does not support public blockchains, go use something else if you want no privacy + // HUSH does not support surveillance coins, go use something else if you want no privacy return 0; } @@ -1832,8 +1832,6 @@ int64_t hush_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock) zfunds -= tx.valueBalance; } *zfundsp = zfunds; - if ( SMART_CHAIN_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times - return(3 * SATOSHIDEN); //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 ) //. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds)); return(voutsum - vinsum); From 96ae2d61ca5a392cb476da4c7f6ab1f638839a7f Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 4 Sep 2023 08:22:12 -0400 Subject: [PATCH 06/22] z_getstats RPC that calculates various stats about ztxs in a block range --- src/wallet/rpcwallet.cpp | 144 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index cdf16c695..b10650137 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3636,6 +3636,149 @@ UniValue z_listsentbyaddress(const UniValue& params, bool fHelp,const CPubKey&) return ret; } +UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "z_getstats\n" + "\nReturns statistics about ztxs in block height or block height range\n" + "\nArguments:\n" + "1. \"height\" (number, required) The block height\n" + "1. \"end_height\" (number, optional) The ending block height\n" + "\nResult:\n" + "\njson\n" + "\nExamples:\n" + + HelpExampleCli("z_getstats 123", "456") + + HelpExampleRpc("z_getstats 123", "456") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + std::string strHeight = params[0].get_str(); + int nHeight = -1; + try { + nHeight = std::stoi(strHeight); + } catch (const std::exception &e) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); + } + + if (nHeight < 0 || nHeight > chainActive.Height()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); + } + auto strHash = chainActive[nHeight]->GetBlockHash().GetHex(); + uint256 hash(uint256S(strHash)); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + + if(!ReadBlockFromDisk(block, pblockindex,1)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + int total_ztxs, total_zins, total_zouts = 0; + int largest_zins, largest_zouts = 0; + + // given a single block height, we calculate stats for that height + if (params.size() == 1) { + BOOST_FOREACH(const CTransaction&tx, block.vtx) + { + int num_zins, num_zouts = 0; + // ignore coinbase txs which have no zins or zouts + if(!tx.IsCoinBase()) { + num_zouts = tx.vShieldedOutput.size(); + num_zins = tx.vShieldedSpend.size(); + // tx must have some zins and zouts to count towards our stats, + // which ignores shielding coinbase txs, which have only transparent inputs + // This mostly will only count "z2z" txs but also counts (z,t)=>z and z=>(z,t) + // which are possible but unlikely, since RPCs will not create them + if(num_zins > 0 && num_zouts > 0) { + total_ztxs++; + total_zins += num_zins; + total_zouts += num_zouts; + if (num_zins > largest_zins) { + largest_zins = num_zins; + } + if (num_zouts > largest_zouts) { + largest_zouts = num_zouts; + } + } + } + } + } else { + // given two blocks, we calculate delta for that range + std::string strHeight2 = params[1].get_str(); + int nHeight2 = -1; + try { + nHeight2 = std::stoi(strHeight2); + } catch (const std::exception &e) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid ending block height parameter"); + } + + if (nHeight2 <= nHeight) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Ending block height must be larger than starting height"); + } + + if (nHeight2 < 0 || nHeight2 > chainActive.Height()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Ending block height out of range"); + } + + // get the delta for every block in the range + for(int currentHeight = nHeight; currentHeight <= nHeight2; currentHeight++) { + auto strHash = chainActive[currentHeight]->GetBlockHash().GetHex(); + uint256 hash(uint256S(strHash)); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + + if(!ReadBlockFromDisk(block, pblockindex,1)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + BOOST_FOREACH(const CTransaction&tx, block.vtx) + { + int num_zins, num_zouts = 0; + // ignore coinbase txs which have no zins or zouts + if(!tx.IsCoinBase()) { + num_zouts = tx.vShieldedOutput.size(); + num_zins = tx.vShieldedSpend.size(); + if(num_zins > 0 && num_zouts > 0) { + total_ztxs++; + total_zins += num_zins; + total_zouts += num_zouts; + } + if (num_zins > largest_zins) { + largest_zins = num_zins; + } + if (num_zouts > largest_zouts) { + largest_zouts = num_zouts; + } + } + } + } + } + UniValue ret(UniValue::VOBJ); + double avg_zins = total_ztxs > 0 ? total_zins / total_ztxs : 0.0; + double avg_zouts = total_ztxs > 0 ? total_zouts / total_ztxs : 0.0; + ret.pushKV("total_ztxs", total_ztxs); + ret.pushKV("avg_zins", avg_zins); + ret.pushKV("avg_zouts", avg_zouts); + ret.pushKV("largest_zins", largest_zins); + ret.pushKV("largest_zouts", largest_zouts); + return ret; +} + UniValue z_anonsetblockdelta(const UniValue& params, bool fHelp, const CPubKey& mypk) { if (!EnsureWalletIsAvailable(fHelp)) @@ -8489,6 +8632,7 @@ static const CRPCCommand commands[] = { "wallet", "z_listunspent", &z_listunspent, false }, { "wallet", "z_getbalance", &z_getbalance, false }, { "wallet", "z_getbalances", &z_getbalances, false }, + { "wallet", "z_getstats", &z_getstats, true }, { "wallet", "z_anonsettxdelta", &z_anonsettxdelta, true }, { "wallet", "z_anonsetblockdelta", &z_anonsetblockdelta, true }, { "wallet", "z_gettotalbalance", &z_gettotalbalance, false }, From 0f4956dcd54d715e4881db74bfa51a092193b7b6 Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 4 Sep 2023 08:50:05 -0400 Subject: [PATCH 07/22] Initialize variables in z_getstats correctly --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b10650137..01c379ecd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3682,8 +3682,8 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) if(!ReadBlockFromDisk(block, pblockindex,1)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - int total_ztxs, total_zins, total_zouts = 0; - int largest_zins, largest_zouts = 0; + int total_ztxs = 0, total_zins = 0, total_zouts = 0; + int largest_zins = 0, largest_zouts = 0; // given a single block height, we calculate stats for that height if (params.size() == 1) { From 8eaba566fdf4732bdddfd42eac2ebb56e9dbba14 Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 4 Sep 2023 08:57:23 -0400 Subject: [PATCH 08/22] Force avg zins/zouts to be a double --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 01c379ecd..7c52b744e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3769,8 +3769,8 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) } } UniValue ret(UniValue::VOBJ); - double avg_zins = total_ztxs > 0 ? total_zins / total_ztxs : 0.0; - double avg_zouts = total_ztxs > 0 ? total_zouts / total_ztxs : 0.0; + double avg_zins = total_ztxs > 0 ? (double) total_zins / total_ztxs : 0.0; + double avg_zouts = total_ztxs > 0 ? (double) total_zouts / total_ztxs : 0.0; ret.pushKV("total_ztxs", total_ztxs); ret.pushKV("avg_zins", avg_zins); ret.pushKV("avg_zouts", avg_zouts); From 7ea88bb303372eb91bebb0da908ce6ac0c484de0 Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 4 Sep 2023 09:03:06 -0400 Subject: [PATCH 09/22] Return total zins+zouts in json --- src/wallet/rpcwallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7c52b744e..d88a7a4d0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3772,6 +3772,8 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) double avg_zins = total_ztxs > 0 ? (double) total_zins / total_ztxs : 0.0; double avg_zouts = total_ztxs > 0 ? (double) total_zouts / total_ztxs : 0.0; ret.pushKV("total_ztxs", total_ztxs); + ret.pushKV("total_zins", total_zins); + ret.pushKV("total_zouts", total_zouts); ret.pushKV("avg_zins", avg_zins); ret.pushKV("avg_zouts", avg_zouts); ret.pushKV("largest_zins", largest_zins); From ff7a5970325e1f0417a28dcfdd1257703608c5cf Mon Sep 17 00:00:00 2001 From: Duke Date: Tue, 5 Sep 2023 00:35:11 -0400 Subject: [PATCH 10/22] Lots of more data for z_getstats --- src/wallet/rpcwallet.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d88a7a4d0..90997e6ce 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3683,7 +3683,9 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); int total_ztxs = 0, total_zins = 0, total_zouts = 0; + int total_ztxs_10_or_more_zins = 0, total_ztxs_10_or_more_zouts = 0; int largest_zins = 0, largest_zouts = 0; + std::string largest_zins_txid = "", largest_zouts_txid = ""; // given a single block height, we calculate stats for that height if (params.size() == 1) { @@ -3695,24 +3697,33 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) num_zouts = tx.vShieldedOutput.size(); num_zins = tx.vShieldedSpend.size(); // tx must have some zins and zouts to count towards our stats, - // which ignores shielding coinbase txs, which have only transparent inputs + // which ignores shielding coinbase txs, which have only transparent inputs. // This mostly will only count "z2z" txs but also counts (z,t)=>z and z=>(z,t) - // which are possible but unlikely, since RPCs will not create them + // which are possible but unlikely, since RPCs cannot currently create (z,t)=>z txs + // and z=>(z,t) are disallowed when ac_private=1 if(num_zins > 0 && num_zouts > 0) { total_ztxs++; total_zins += num_zins; total_zouts += num_zouts; if (num_zins > largest_zins) { largest_zins = num_zins; + largest_zins_txid = tx.GetHash().ToString(); } if (num_zouts > largest_zouts) { largest_zouts = num_zouts; + largest_zouts_txid = tx.GetHash().ToString(); + } + if (num_zins >= 10) { + total_ztxs_10_or_more_zins++; + } + if (num_zouts >= 10) { + total_ztxs_10_or_more_zouts++; } } } } } else { - // given two blocks, we calculate delta for that range + // given two blocks, we calculate stats for that range std::string strHeight2 = params[1].get_str(); int nHeight2 = -1; try { @@ -3729,7 +3740,7 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) throw JSONRPCError(RPC_INVALID_PARAMETER, "Ending block height out of range"); } - // get the delta for every block in the range + // get the stats for every block in the range for(int currentHeight = nHeight; currentHeight <= nHeight2; currentHeight++) { auto strHash = chainActive[currentHeight]->GetBlockHash().GetHex(); uint256 hash(uint256S(strHash)); @@ -3760,9 +3771,17 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) } if (num_zins > largest_zins) { largest_zins = num_zins; + largest_zins_txid = tx.GetHash().ToString(); } if (num_zouts > largest_zouts) { largest_zouts = num_zouts; + largest_zouts_txid = tx.GetHash().ToString(); + } + if (num_zins >= 10) { + total_ztxs_10_or_more_zins++; + } + if (num_zouts >= 10) { + total_ztxs_10_or_more_zouts++; } } } @@ -3774,10 +3793,14 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) ret.pushKV("total_ztxs", total_ztxs); ret.pushKV("total_zins", total_zins); ret.pushKV("total_zouts", total_zouts); + ret.pushKV("total_ztxs_10_or_more_zins", total_ztxs_10_or_more_zins); + ret.pushKV("total_ztxs_10_or_more_zouts", total_ztxs_10_or_more_zouts); ret.pushKV("avg_zins", avg_zins); ret.pushKV("avg_zouts", avg_zouts); ret.pushKV("largest_zins", largest_zins); + ret.pushKV("largest_zins_txid", largest_zins_txid); ret.pushKV("largest_zouts", largest_zouts); + ret.pushKV("largest_zouts_txid", largest_zouts_txid); return ret; } From 4aca3493e39910d5e75bf84f5455a16303180ea2 Mon Sep 17 00:00:00 2001 From: Duke Date: Tue, 5 Sep 2023 11:30:27 -0400 Subject: [PATCH 11/22] Even more zstats Example data for the entire history of the current HUSH mainnet : ./src/hush-cli z_getstats 1 1487622 { "total_ztxs": 414962, "total_zins": 798083, "total_zouts": 3312131, "total_ztxs_10_or_more_zins": 6789, "total_ztxs_25_or_more_zins": 1779, "total_ztxs_50_or_more_zins": 688, "total_ztxs_100_or_more_zins": 174, "total_ztxs_10_or_more_zouts": 2855, "total_ztxs_25_or_more_zouts": 394, "total_ztxs_50_or_more_zouts": 314, "total_ztxs_100_or_more_zouts": 208, "avg_zins": 1.923267672702561, "avg_zouts": 7.981769415030774, "largest_zins": 517, "largest_zins_txid": "69f126edd5a0189fbbe84b0824eb48e16eddf180e7d5d4f34c4296d0f868ac7f", "largest_zouts": 210, "largest_zouts_txid": "2a3155f73fab9191978e77e03be8ec7167372c4549113a6eb3f8a9d343f749ba" } --- src/wallet/rpcwallet.cpp | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 90997e6ce..0be79dd3d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3684,6 +3684,9 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) int total_ztxs = 0, total_zins = 0, total_zouts = 0; int total_ztxs_10_or_more_zins = 0, total_ztxs_10_or_more_zouts = 0; + int total_ztxs_25_or_more_zins = 0, total_ztxs_25_or_more_zouts = 0; + int total_ztxs_50_or_more_zins = 0, total_ztxs_50_or_more_zouts = 0; + int total_ztxs_100_or_more_zins = 0, total_ztxs_100_or_more_zouts = 0; int largest_zins = 0, largest_zouts = 0; std::string largest_zins_txid = "", largest_zouts_txid = ""; @@ -3715,10 +3718,30 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) } if (num_zins >= 10) { total_ztxs_10_or_more_zins++; + if (num_zins >= 25) { + total_ztxs_25_or_more_zins++; + if (num_zins >= 50) { + total_ztxs_50_or_more_zins++; + if (num_zins >= 100) { + total_ztxs_100_or_more_zins++; + } + } + } } if (num_zouts >= 10) { total_ztxs_10_or_more_zouts++; + if (num_zouts >= 25) { + total_ztxs_25_or_more_zouts++; + if (num_zouts >= 50) { + total_ztxs_50_or_more_zouts++; + if (num_zouts >= 100) { + total_ztxs_100_or_more_zouts++; + } + } + } } + + } } } @@ -3779,9 +3802,27 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) } if (num_zins >= 10) { total_ztxs_10_or_more_zins++; + if (num_zins >= 25) { + total_ztxs_25_or_more_zins++; + if (num_zins >= 50) { + total_ztxs_50_or_more_zins++; + if (num_zins >= 100) { + total_ztxs_100_or_more_zins++; + } + } + } } if (num_zouts >= 10) { total_ztxs_10_or_more_zouts++; + if (num_zouts >= 25) { + total_ztxs_25_or_more_zouts++; + if (num_zouts >= 50) { + total_ztxs_50_or_more_zouts++; + if (num_zouts >= 100) { + total_ztxs_100_or_more_zouts++; + } + } + } } } } @@ -3794,7 +3835,13 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) ret.pushKV("total_zins", total_zins); ret.pushKV("total_zouts", total_zouts); ret.pushKV("total_ztxs_10_or_more_zins", total_ztxs_10_or_more_zins); + ret.pushKV("total_ztxs_25_or_more_zins", total_ztxs_25_or_more_zins); + ret.pushKV("total_ztxs_50_or_more_zins", total_ztxs_50_or_more_zins); + ret.pushKV("total_ztxs_100_or_more_zins", total_ztxs_100_or_more_zins); ret.pushKV("total_ztxs_10_or_more_zouts", total_ztxs_10_or_more_zouts); + ret.pushKV("total_ztxs_25_or_more_zouts", total_ztxs_25_or_more_zouts); + ret.pushKV("total_ztxs_50_or_more_zouts", total_ztxs_50_or_more_zouts); + ret.pushKV("total_ztxs_100_or_more_zouts", total_ztxs_100_or_more_zouts); ret.pushKV("avg_zins", avg_zins); ret.pushKV("avg_zouts", avg_zouts); ret.pushKV("largest_zins", largest_zins); From 7c45e66fbeefa354c4169ce230eb061b92c3adbe Mon Sep 17 00:00:00 2001 From: Duke Date: Fri, 8 Sep 2023 08:28:14 -0400 Subject: [PATCH 12/22] Also return start and ending height in z_getstats json --- src/wallet/rpcwallet.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0be79dd3d..8467c0453 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3689,6 +3689,8 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) int total_ztxs_100_or_more_zins = 0, total_ztxs_100_or_more_zouts = 0; int largest_zins = 0, largest_zouts = 0; std::string largest_zins_txid = "", largest_zouts_txid = ""; + UniValue ret(UniValue::VOBJ); + ret.pushKV("start_height", nHeight); // given a single block height, we calculate stats for that height if (params.size() == 1) { @@ -3763,6 +3765,8 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) throw JSONRPCError(RPC_INVALID_PARAMETER, "Ending block height out of range"); } + ret.pushKV("end_height", nHeight2); + // get the stats for every block in the range for(int currentHeight = nHeight; currentHeight <= nHeight2; currentHeight++) { auto strHash = chainActive[currentHeight]->GetBlockHash().GetHex(); @@ -3828,7 +3832,6 @@ UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk) } } } - UniValue ret(UniValue::VOBJ); double avg_zins = total_ztxs > 0 ? (double) total_zins / total_ztxs : 0.0; double avg_zouts = total_ztxs > 0 ? (double) total_zouts / total_ztxs : 0.0; ret.pushKV("total_ztxs", total_ztxs); From 09555fbee29ece5f35c39b77d189a3ebee32fe81 Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 18 Sep 2023 12:43:27 -0400 Subject: [PATCH 13/22] Allow abortrescan during RPC warmup If we don't, we can get the hilarious error message that the node is Rescanning... when trying to run abortrescan when the node automatically does a rescan on boot. --- src/rpc/server.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 703cdc7b9..679e6ffc2 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -832,7 +832,8 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms 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" ) { + pcmd->name != "dumpprivkey" && pcmd->name != "getpeerinfo" && pcmd->name != "getnetworkinfo" && + pcmd->name != "abortrescan") { throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus); } } From 2308db22eec78d0a10bde0f674243b2700d59e4a Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 18 Sep 2023 12:58:03 -0400 Subject: [PATCH 14/22] Antispam defenses This code is inspired by https://github.com/PirateNetwork/pirate/commit/db292a49ddc13374f43b8c16217e171316be53d7 with various improvements that will be documented below. The largest improvement is that this code will defend against a spammer using shielded inputs (zins) or shielded outputs (zouts) while the Pirate code only defends against zout spam. We wrote a new RPC called z_getstats to study exactly what the distribution of shielded inputs (zins) and shielded outputs (zouts) look like on HUSH mainnet. Sietch will never make a ztx that contains more than 9 zouts and so transactions with 10 or more zouts are extremely rare. They correspond to custom transactions created via code or CLI or mining pool payouts. We allow at most one of these per block. If there are two, one will remain in the mempool and be mined in the subsequent block. Our code is more strict, as Pirate will allow up to 6 of these transactions in a single block. Transactions with many shielded inputs do occur normally when users spend many small shielded unspent outputs (zutxos) in one transaction, but we determined that a cutoff of 50 zins is quite rare. Between blocks 14000000 and 15000000 only 27 ztxs had 50 or more zins, which is 0.03% . We allow at most one of these per block and if there are more, they will wait to be mined in a subsequent block. Also note that a transaction can match both criteria of having large zins and large zouts, so for instance, if there is a transaction with 50 zins and 10 zouts, it counts towards both requirements and no other transactions with >=50 zins or >=10 zouts will be mined in that block. If >=200 transactions with either large zins or large zouts are broadcast to the network it will take at least 200 blocks for them to be mined and so via existing rules for ztx expiration they will expire and be removed from the mempool, since by default all ztxs expire after 200 blocks. Since normal ztxs that match these criteria are very rare, the only case when this might happen is during a spam attack and so the attackers transactions expiring is another part of these defenses. Other improvements are that we log txids of transactions with large zins or zouts and we do not support a command line option to turn this protection off. This forces a potential attacker to compile their own custom code if they want to subvert these protections on their own node and blocks they mine. Similar to Pirate, these changes are not consensus changes but may be made consensus requirements in the future. These protections are not specific to HUSH and are enabled for all HSC's, including DragonX. --- src/miner.cpp | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index ee85a52eb..227ba999b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -279,11 +279,16 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 vecPriority.reserve(mempool.mapTx.size() + 1); //fprintf(stderr,"%s: going to add txs from mempool\n", __func__); - // now add transactions from the mem pool + // 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 + uint32_t large_zouts = 0; // number of ztxs with large number of outputs in block + const uint32_t LARGE_ZINS_MAX = 1; // max ztxs with large zins per block + const uint32_t LARGE_ZOUTS_MAX = 1; // max ztxs with large zouts per block + const uint32_t LARGE_ZINS_THRESHOLD = 50; // min number of zins to be considered large + const uint32_t LARGE_ZOUTS_THRESHOLD = 10; // min number of zouts to be considered large for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); - mi != mempool.mapTx.end(); ++mi) - { + mi != mempool.mapTx.end(); ++mi) { const CTransaction& tx = mi->GetTx(); int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) @@ -466,6 +471,18 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 // 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) { + LogPrintf("%s: skipping ztx %s with %d zins because there are already %d ztxs with large zins\n", + __func__, tx.GetHash().ToString().c_str(), tx.vShieldedSpend.size(), LARGE_ZINS_MAX); + continue; + } + + if(tx.vShieldedOutput.size() >= LARGE_ZOUTS_THRESHOLD && large_zouts >= LARGE_ZOUTS_MAX) { + LogPrintf("%s: skipping ztx %s with %d zouts because there are already %d ztxs with large zouts\n", + __func__, tx.GetHash().ToString().c_str(), tx.vShieldedOutput.size(), LARGE_ZOUTS_MAX); + continue; + } + // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // fprintf(stderr,"%s: nTxSize = %u\n", __func__, nTxSize); @@ -576,6 +593,18 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 nBlockSigOps += nTxSigOps; nFees += nTxFees; + if(tx.vShieldedOutput.size() >= LARGE_ZOUTS_THRESHOLD) { + large_zouts++; + LogPrintf("%s: txid=%s has large zouts=%d (%d large zouts in block)\n", __func__, tx.GetHash().ToString().c_str(), + tx.vShieldedOutput.size(), large_zouts ); + } + + if(tx.vShieldedSpend.size() >= LARGE_ZINS_THRESHOLD) { + large_zins++; + LogPrintf("%s: txid=%s has large zins=%d (%d large zouts in block)\n", __func__, tx.GetHash().ToString().c_str(), + tx.vShieldedSpend.size(), large_zins ); + } + if (fPrintPriority) { LogPrintf("priority %.1f fee %s txid %s\n",dPriority, feeRate.ToString(), tx.GetHash().ToString()); From d7cbdcab2839277a3a11308be60e42e1494ec59e Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 18 Sep 2023 20:44:16 -0400 Subject: [PATCH 15/22] Always log when skipping a zaddr during z_importwallet --- src/wallet/rpcdump.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 79463087d..39b5caf38 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -515,14 +515,15 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys auto addResult = boost::apply_visitor( AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus(), nTime, hdKeypath, seedFpStr, true), spendingkey); if (addResult == KeyAlreadyExists){ - LogPrint("zrpc", "Skipping import of zaddr (key already present)\n"); + LogPrintf("%s: Skipping import of zaddr (key already present)\n", __func__); } else if (addResult == KeyNotAdded) { // Something went wrong fGood = false; + LogPrintf("%s: Skipping import of zaddr (something went wrong)\n", __func__); } continue; } else { - LogPrint("zrpc", "Importing detected an error: invalid spending key. Trying as a transparent key...\n"); + 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 } } From aa5cbee69cc284aa343239f2dd0e0330f9efe8e5 Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 18 Sep 2023 20:57:47 -0400 Subject: [PATCH 16/22] Remove dead code --- src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2c037297b..55b26b70b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1863,8 +1863,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa view.GetBestBlock(); nValueIn = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime); - if ( 0 && interest != 0 ) - fprintf(stderr,"add interest %.8f\n",(double)interest/COIN); // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool view.SetBackend(dummy); } From c8a88e116835e5ae736936b2b8c2abe7214b2a3a Mon Sep 17 00:00:00 2001 From: Duke Date: Sat, 7 Oct 2023 14:07:34 -0400 Subject: [PATCH 17/22] Check null randomx dataset before calling randomx_dataset_item_count --- src/miner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index ee85a52eb..2f372483c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1072,14 +1072,14 @@ void static RandomXMiner() randomx_dataset *randomxDataset = randomx_alloc_dataset(flags); rxdebug("%s: created dataset\n"); - auto datasetItemCount = randomx_dataset_item_count(); - rxdebug("%s: dataset items=%lu\n", datasetItemCount); - if( randomxDataset == nullptr) { LogPrintf("%s: allocating randomx dataset failed!\n", __func__); return; } + auto datasetItemCount = randomx_dataset_item_count(); + rxdebug("%s: dataset items=%lu\n", datasetItemCount); + char randomxHash[RANDOMX_HASH_SIZE]; rxdebug("%s: created randomxHash of size %d\n", RANDOMX_HASH_SIZE); char randomxKey[82]; // randomx spec says keysize of >60 bytes is implementation-specific From b386cd1acf78d4d6079eedf66e3b23e36009fc1e Mon Sep 17 00:00:00 2001 From: Duke Date: Sat, 7 Oct 2023 14:15:12 -0400 Subject: [PATCH 18/22] Scripts to test this branch --- antispam | 4 ++++ qa/pull-tester/rpc-tests.sh | 1 + qa/pull-tester/tests-config.sh.in | 1 - qa/rpc-tests/test_framework/util.py | 28 ++++++++++++++++++---------- qa/rpc-tests/wallet_sapling.py | 6 +++--- test_antispam | 9 +++++++++ 6 files changed, 35 insertions(+), 14 deletions(-) create mode 100755 antispam create mode 100755 test_antispam diff --git a/antispam b/antispam new file mode 100755 index 000000000..a9d3572a9 --- /dev/null +++ b/antispam @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "./src/hush-cli -ac_name=ANTISPAM $@" +./src/hush-cli -ac_name=ANTISPAM $@ diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index b1cbabec9..bed1a5417 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -14,6 +14,7 @@ export BITCOIND=${REAL_BITCOIND} #Run the tests testScripts=( + 'antispam.py' 'dpow.py' 'dpowconfs.py' 'ac_private.py' diff --git a/qa/pull-tester/tests-config.sh.in b/qa/pull-tester/tests-config.sh.in index 5122ba085..47546707b 100755 --- a/qa/pull-tester/tests-config.sh.in +++ b/qa/pull-tester/tests-config.sh.in @@ -11,7 +11,6 @@ EXEEXT="@EXEEXT@" @ENABLE_WALLET_TRUE@ENABLE_WALLET=1 @BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=1 @BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=1 -@ENABLE_PROTON_TRUE@ENABLE_PROTON=1 REAL_BITCOIND="$BUILDDIR/src/hushd${EXEEXT}" REAL_BITCOINCLI="$BUILDDIR/src/hush-cli${EXEEXT}" diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index a0b409970..3280be573 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -104,10 +104,10 @@ def initialize_datadir(dirname, n): f.write("showmetrics=0\n"); f.write("rpcuser=hush\n"); f.write("rpcpassword=puppy\n"); - #f.write("port="+str(p2p_port(n))+"\n"); - #rpcport = str(rpc_port(n)) - #f.write("rpcport="+rpcport+"\n"); - #print "RPC port=" + rpcport + f.write("port="+str(p2p_port(n))+"\n"); + rpcport = str(rpc_port(n)) + f.write("rpcport="+rpcport+"\n"); + print "RPC port=" + rpcport f.write("listenonion=0\n"); # TODO: maybe make these optional, via arg to initialize_datadir, defaulted to on for now f.write("addressindex=1\n"); @@ -148,7 +148,7 @@ def initialize_chain(test_dir): rpcs = [] for i in range(4): try: - url = "http://rt:rt@127.0.0.1:%d"%(rpc_port(i),) + url = "http://hush:puppy@127.0.0.1:%d"%(rpc_port(i),) rpcs.append(AuthServiceProxy(url)) except: sys.stderr.write("Error connecting to "+url+"\n") @@ -165,11 +165,13 @@ def initialize_chain(test_dir): for j in range(25): set_node_times(rpcs, block_time) rpcs[peer].generate(1) - block_time += 10*60 + # TODO: HUSH3 has 75s blocktime, other HSCs could be different + block_time += 10*75 # Must sync before next peer starts generating blocks sync_blocks(rpcs) # Shut them down, and clean up cache directories: + print("Stopping nodes") stop_nodes(rpcs) wait_bitcoinds() for i in range(4): @@ -182,8 +184,9 @@ def initialize_chain(test_dir): for i in range(4): from_dir = os.path.join("cache", "node"+str(i)) to_dir = os.path.join(test_dir, "node"+str(i)) + print("Copying " + from_dir + " to " + to_dir) shutil.copytree(from_dir, to_dir) - initialize_datadir(test_dir, i) # Overwrite port/rpcport in hush.conf + initialize_datadir(test_dir, i) # Overwrite port/rpcport in HUSH3.conf def initialize_chain_clean(test_dir, num_nodes): """ @@ -218,9 +221,10 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= """ Start a hushd and return RPC connection to it """ + print("Starting node " + str(i)) datadir = os.path.join(dirname, "node"+str(i)) # creating special config in case of cryptocondition asset chain test - if extra_args[0] == '-ac_name=REGTEST': + if len(extra_args) > 0 and extra_args[0] == '-ac_name=REGTEST': configpath = datadir + "/REGTEST.conf" with open(configpath, "w+") as config: config.write("regtest=1\n") @@ -259,7 +263,8 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= if os.getenv("PYTHON_DEBUG", ""): print "start_node: calling hush-cli -rpcwait getblockcount returned" devnull.close() - port = extra_args[3] + #port = extra_args[3] + port = rpc_port(i) username = rpc_username() password = rpc_password() url = "http://%s:%s@%s:%d" % (username, password, rpchost or '127.0.0.1', int(port[9:])) @@ -276,6 +281,7 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None): """ Start multiple hushds, return RPC connections to them """ + print("Starting " + str(num_nodes) + " nodes") if extra_args is None: extra_args = [ None for i in range(num_nodes) ] if binary is None: binary = [ None for i in range(num_nodes) ] return [ start_node(i, dirname, extra_args[i], rpchost, binary=binary[i]) for i in range(num_nodes) ] @@ -288,6 +294,7 @@ def check_node(i): return bitcoind_processes[i].returncode def stop_node(node, i): + print("Stopping node " + i) node.stop() bitcoind_processes[i].wait() del bitcoind_processes[i] @@ -298,11 +305,12 @@ def stop_nodes(nodes): del nodes[:] # Emptying array closes connections as a side effect def set_node_times(nodes, t): + print("Setting nodes time to " + t) for node in nodes: node.setmocktime(t) def wait_bitcoinds(): - # Wait for all bitcoinds to cleanly exit + print("Waiting for all nodes to cleanly exit") for bitcoind in bitcoind_processes.values(): bitcoind.wait() bitcoind_processes.clear() diff --git a/qa/rpc-tests/wallet_sapling.py b/qa/rpc-tests/wallet_sapling.py index c9e796b72..cca928c44 100755 --- a/qa/rpc-tests/wallet_sapling.py +++ b/qa/rpc-tests/wallet_sapling.py @@ -19,9 +19,9 @@ class WalletSaplingTest(BitcoinTestFramework): def setup_nodes(self): return start_nodes(4, self.options.tmpdir, [[ - '-nuparams=5ba81b19:201', # Overwinter - '-nuparams=76b809bb:203', # Sapling - '-experimentalfeatures', '-zmergetoaddress', + #'-nuparams=5ba81b19:201', # Overwinter + #'-nuparams=76b809bb:203', # Sapling + #'-experimentalfeatures', '-zmergetoaddress', ]] * 4) def run_test(self): diff --git a/test_antispam b/test_antispam new file mode 100755 index 000000000..b51d802fe --- /dev/null +++ b/test_antispam @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# any CLI args given to this script will be passed along +# example: ./test_antispam -debug=blah +./src/hushd -ac_name=ANTISPAM -ac_private=1 -ac_blocktime=180 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 -testnode=1 $@ + +# to run via the debugger +# type "run" when gdb prompt appears +#gdb --args ./src/hushd -- -ac_algo=randomx -ac_name=ANTISPAM -ac_private=1 -ac_blocktime=180 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 -testnode=1 From 84a0c2c35ec9298ee6baa86f9210ed6dcd028103 Mon Sep 17 00:00:00 2001 From: Duke Date: Sat, 7 Oct 2023 14:16:59 -0400 Subject: [PATCH 19/22] antispam test --- qa/rpc-tests/antispam.py | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 qa/rpc-tests/antispam.py diff --git a/qa/rpc-tests/antispam.py b/qa/rpc-tests/antispam.py new file mode 100755 index 000000000..9913eef56 --- /dev/null +++ b/qa/rpc-tests/antispam.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python2 +# Copyright (c) 2016-2023 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 + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException +from test_framework.util import ( + assert_equal, + start_nodes, + wait_and_assert_operationid_status, +) + +from decimal import Decimal + +class AntispamTest(BitcoinTestFramework): + + def setup_nodes(self): + return start_nodes(2, self.options.tmpdir, [[ ]] * 2) + + def run_test(self): + # Sanity-check the test harness + assert_equal(self.nodes[0].getblockcount(), 200) + + # make sure we can mine a block + self.nodes[1].generate(1) + self.sync_all() + + # make a new zaddr on each node + saplingAddr0 = self.nodes[0].z_getnewaddress() + saplingAddr1 = self.nodes[1].z_getnewaddress() + + # Verify addresses + assert(saplingAddr0 in self.nodes[0].z_listaddresses()) + assert(saplingAddr1 in self.nodes[1].z_listaddresses()) + assert_equal(self.nodes[0].z_validateaddress(saplingAddr0)['type'], 'sapling') + assert_equal(self.nodes[0].z_validateaddress(saplingAddr1)['type'], 'sapling') + + # Verify balance + assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('0')) + assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0')) + +if __name__ == '__main__': + AntispamTest().main() From b200dcb2c7807886b01fc26d4a83e2411664c159 Mon Sep 17 00:00:00 2001 From: Duke Date: Tue, 10 Oct 2023 12:03:41 -0400 Subject: [PATCH 20/22] Update test_antispam --- test_antispam | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_antispam b/test_antispam index b51d802fe..5ccfb4752 100755 --- a/test_antispam +++ b/test_antispam @@ -2,8 +2,9 @@ # any CLI args given to this script will be passed along # example: ./test_antispam -debug=blah -./src/hushd -ac_name=ANTISPAM -ac_private=1 -ac_blocktime=180 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 -testnode=1 $@ +#./src/hushd -ac_name=ANTISPAM -ac_private=1 -ac_blocktime=180 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 -testnode=1 $@ +./src/hushd -ac_name=ANTISPAM -ac_private=1 -ac_blocktime=180 -ac_reward=500000000 -ac_supply=55555 $@ # to run via the debugger # type "run" when gdb prompt appears #gdb --args ./src/hushd -- -ac_algo=randomx -ac_name=ANTISPAM -ac_private=1 -ac_blocktime=180 -ac_reward=500000000 -ac_supply=55555 -gen=1 -genproclimit=1 -testnode=1 From 7db6745056683a07d0851dc40846dbcb961c1f7e Mon Sep 17 00:00:00 2001 From: Duke Date: Tue, 10 Oct 2023 12:05:53 -0400 Subject: [PATCH 21/22] s/zouts/zins/ in debug log --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 768e6f397..01b907e80 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -601,7 +601,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 if(tx.vShieldedSpend.size() >= LARGE_ZINS_THRESHOLD) { large_zins++; - LogPrintf("%s: txid=%s has large zins=%d (%d large zouts in block)\n", __func__, tx.GetHash().ToString().c_str(), + LogPrintf("%s: txid=%s has large zins=%d (%d large zins in block)\n", __func__, tx.GetHash().ToString().c_str(), tx.vShieldedSpend.size(), large_zins ); } From 963ce1e444bcb9d8a4ab43179c2a70c251f07193 Mon Sep 17 00:00:00 2001 From: Duke Date: Tue, 10 Oct 2023 22:04:15 -0400 Subject: [PATCH 22/22] Release randomx dataset+cache when mining is interrupted or errors --- src/miner.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/miner.cpp b/src/miner.cpp index 01b907e80..b1a4b917f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1424,12 +1424,24 @@ void static RandomXMiner() } catch (const boost::thread_interrupted&) { miningTimer.stop(); c.disconnect(); + + randomx_release_dataset(randomxDataset); + rxdebug("%s: released dataset\n"); + randomx_release_cache(randomxCache); + rxdebug("%s: released cache\n"); + LogPrintf("HushRandomXMiner terminated\n"); throw; } catch (const std::runtime_error &e) { miningTimer.stop(); c.disconnect(); fprintf(stderr,"RandomXMiner: runtime error: %s\n", e.what()); + + randomx_release_dataset(randomxDataset); + rxdebug("%s: released dataset\n"); + randomx_release_cache(randomxCache); + rxdebug("%s: released cache\n"); + return; }