From 6fda12612dfe6a71722123f095a8e1898e57fe06 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Wed, 19 Oct 2022 05:12:12 -0400 Subject: [PATCH 01/30] Initial implementation of abortrescan --- src/wallet/rpcdump.cpp | 30 ++++++++++++++++++++++++++++++ src/wallet/wallet.cpp | 13 +++++++++++++ src/wallet/wallet.h | 7 +++++++ 3 files changed, 50 insertions(+) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 6ba77f862..f25a7edd1 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -144,6 +144,36 @@ UniValue convertpassphrase(const UniValue& params, bool fHelp, const CPubKey& my return ret; } +UniValue abortrescan(const UniValue& params, bool fHelp, const CPubKey& mypk) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 0) + throw runtime_error( + "abortrescan\n" + "\nAbort a currently running rescan.\n" + "\nUse 'getrescaninfo' to get rescan progress details.\n" + "\nReturns true if aborting rescan, false otherwise.\n" + "\nArguments: none\n" + "\nExamples:\n" + "\nAbort rescan :\n" + + HelpExampleCli("abortrescan","") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("abortrescan","") + ); + if(!pwalletMain->fRescanning) { + LogPrintf("%s: no rescan running\n",__func__); + return false; + } + if(pwalletMain->IsAbortingRescan()) { + LogPrintf("%s: already aborting current rescan\n",__func__); + return false; + } + pwalletMain->AbortRescan(); + return true; +} + UniValue getrescaninfo(const UniValue& params, bool fHelp, const CPubKey& mypk) { if (!EnsureWalletIsAvailable(fHelp)) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9e8cd1aa4..1d32f8dd5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2778,6 +2778,19 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) while (pindex) { pwalletMain->rescanHeight = pindex->GetHeight(); + if(pwalletMain->fAbortRescan) { + //TODO: should we update witness caches? + LogPrintf("%s: Rescan aborted at block %d\n", pwalletMain->rescanHeight); + pwalletMain->fRescanning = false; + return ret; + } + if (ShutdownRequested()) { + //TODO: should we update witness caches? + LogPrintf("%s: Rescan interrupted by shutdown request at block %d\n", pwalletMain->rescanHeight); + pwalletMain->fRescanning = false; + return ret; + } + if (pindex->GetHeight() % 100 == 0 && dProgressTip - dProgressStart > 0.0) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 56bd327c8..0f8b2283c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -807,6 +807,13 @@ public: bool fSweepEnabled = false; bool fSweepExternalEnabled = false; bool fSweepRunning = false; + + std::atomic fAbortRescan{false}; + // abort current rescan + void AbortRescan() { fAbortRescan = true; } + // Are we currently aborting a rescan? + bool IsAbortingRescan() const { return fAbortRescan; } + // Are we currently rescanning? bool fRescanning = false; // Current height of our rescan From b94ec8030729011ad408d4846bb6f73df2eefcce Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Thu, 10 Nov 2022 22:38:04 -0500 Subject: [PATCH 02/30] Use RANDOMX_FLAG_FULL_MEM --- src/miner.cpp | 71 +++++++++++++++++++++++++++++++------------ src/wallet/wallet.cpp | 2 +- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 92acea2d9..f39b94979 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1065,6 +1065,23 @@ void static RandomXMiner() cancelSolver = true; } ); + randomx_flags flags = randomx_get_flags(); + // flags |= RANDOMX_FLAG_LARGE_PAGES; + flags |= RANDOMX_FLAG_FULL_MEM; + //flags |= RANDOMX_FLAG_JIT; + randomx_cache *randomxCache = randomx_alloc_cache(flags); + if (randomxCache == NULL) { + LogPrintf("RandomX cache is null, something is wrong, cannot mine!\n"); + return; + } + rxdebug("%s: created randomx flags + cache\n"); + + randomx_dataset *randomxDataset = randomx_alloc_dataset(flags); + rxdebug("%s: created dataset\n"); + if( randomxDataset == nullptr) { + LogPrintf("%s: allocating randomx dataset failed!\n", __func__); + return; + } miningTimer.start(); try { @@ -1181,8 +1198,8 @@ void static RandomXMiner() HASHTarget = arith_uint256().SetCompact(savebits); roundrobin_delay = ROUNDROBIN_DELAY; Mining_start = 0; - gotinvalid = 0; + while (true) { if ( gotinvalid != 0 ) { @@ -1199,7 +1216,7 @@ void static RandomXMiner() char randomxHash[RANDOMX_HASH_SIZE]; //fprintf(stderr,"RandomXMiner: created randomxHash of size %d\n", RANDOMX_HASH_SIZE); char randomxKey[82]; // randomx spec says keysize of >60 bytes is implementation-specific - // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^128 bits) of entropy + // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy // since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT); @@ -1211,14 +1228,6 @@ void static RandomXMiner() // fprintf(stderr,"RandomXMiner: created randomxKey=%s , randomxInput.size=%lu\n", randomxKey, randomxInput.size() ); //randomxInput); rxdebug("%s: randomxKey=%s randomxInput=%s\n", randomxKey, HexStr(randomxInput).c_str()); - randomx_flags flags = randomx_get_flags(); - randomx_cache *randomxCache = randomx_alloc_cache(flags); - if (randomxCache == NULL) { - LogPrintf("RandomX cache is null, something is wrong, cannot mine!\n"); - return; - } - // fprintf(stderr,"RandomXMiner: created randomx flags + cache\n"); - // With the defaults of 1024 and 64 // the key block will change every ~21.3 hours with a 75s block time // and every ~17 hours with the default 60s block time for HSCs @@ -1240,20 +1249,31 @@ void static RandomXMiner() randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey); rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str()); + } - randomx_vm *myVM = randomx_create_vm(flags, randomxCache, NULL); - if(myVM == NULL) { - LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n"); - return; - } + //TODO: this is hardcoded to use 2 threads instead of the number of mining threads + //std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2); + //std::thread t2(&randomx_init_dataset, randomxDataset, randomxCache, datasetItemCount / 2, datasetItemCount - datasetItemCount / 2); + //t1.join(); + //t2.join(); + auto datasetItemCount = randomx_dataset_item_count(); + rxdebug("%s: dataset items=%lu\n", datasetItemCount); + + randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount); + rxdebug("%s: dataset initialized\n"); + // randomx_release_cache(randomxCache); + // rxdebug("%s: cache released\n"); + + randomx_vm *myVM = randomx_create_vm(flags, nullptr, randomxDataset); + if(myVM == NULL) { + LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n"); + return; + } + randomx_calculate_hash(myVM, &randomxInput, sizeof randomxInput, randomxHash); - // rxdebug("calculated randomx hash\n"); - - randomx_destroy_vm(myVM); - // fprintf(stderr,"RandomXMiner: destroyed VM\n"); - randomx_release_cache(randomxCache); + rxdebug("%s: calculated randomx hash\n"); rxdebug("%s: randomxHash="); if (fRandomXDebug) { @@ -1263,6 +1283,9 @@ void static RandomXMiner() printf("\n"); } + randomx_destroy_vm(myVM); + rxdebug("%s: destroyed VM\n"); + // Use randomx hash to build a valid block std::function)> validBlock = @@ -1372,6 +1395,8 @@ void static RandomXMiner() pblock->nBits = savebits; } } + + } catch (const boost::thread_interrupted&) { miningTimer.stop(); c.disconnect(); @@ -1383,6 +1408,11 @@ void static RandomXMiner() fprintf(stderr,"RandomXMiner: runtime error: %s\n", e.what()); return; } + + randomx_release_dataset(randomxDataset); + rxdebug("%s: released dataset\n"); + randomx_release_cache(randomxCache); + rxdebug("%s: released cache\n"); miningTimer.stop(); c.disconnect(); } @@ -1859,6 +1889,7 @@ void static BitcoinMiner() LogPrintf("HushMiner runtime error: %s\n", e.what()); return; } + miningTimer.stop(); c.disconnect(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bc2d75752..001c42718 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2771,7 +2771,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) // our wallet birthday (as adjusted for block time variability) while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200))) { pindex = chainActive.Next(pindex); - pwalletMain->rescanHeight = pindex->GetHeight(); + pwalletMain->rescanHeight = pindex ? pindex->GetHeight() : 0; } ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup From c108db8f3c37cea6b0ec6a458863e5cf70d7f6d8 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Fri, 11 Nov 2022 06:42:51 -0500 Subject: [PATCH 03/30] Speed up randomx hashing by ~60X per core These code changes move various randomx setup code out of the inner mining loop, which significantly increases hashrate. Currently seeing ~60 hashes/second/core on a Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz. This code may have memory leaks, it does not destroy the randomx VM since it was causing coredumps. It also seems to use more memory, I am only able to mine on 2 cores with 16GB of RAM. Using more cores runs out of memory. --- src/miner.cpp | 108 +++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index f39b94979..1ff987e9b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1131,6 +1131,55 @@ void static RandomXMiner() { Mining_height = pindexPrev->GetHeight()+1; Mining_start = (uint32_t)time(NULL); + } + 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 + // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy + // since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long + snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT); + + // With the defaults of 1024 and 64 + // the key block will change every ~21.3 hours with a 75s block time + // and every ~17 hours with the default 60s block time for HSCs + int randomxInterval = GetArg("-ac_randomx_interval",1024); + // This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs + int randomxBlockLag = GetArg("-ac_randomx_lag", 64); + + // fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag); + rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height); + // Use the initial key at the start of the chain, until the first key block + if( (Mining_height) < randomxInterval + randomxBlockLag) { + randomx_init_cache(randomxCache, &randomxKey, sizeof randomxKey); + rxdebug("%s: initialized cache with initial key\n"); + } else { + rxdebug("%s: calculating keyHeight with randomxInterval=%d\n", randomxInterval); + // At heights between intervals, we use the same block key and wait randomxBlockLag blocks until changing + int keyHeight = ((Mining_height - randomxBlockLag) / randomxInterval) * randomxInterval; + uint256 randomxBlockKey = chainActive[keyHeight]->GetBlockHash(); + + randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey); + rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str()); + + } + + auto datasetItemCount = randomx_dataset_item_count(); + rxdebug("%s: dataset items=%lu\n", datasetItemCount); + //TODO: this is hardcoded to use 2 threads instead of the number of mining threads + //std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2); + //std::thread t2(&randomx_init_dataset, randomxDataset, randomxCache, datasetItemCount / 2, datasetItemCount - datasetItemCount / 2); + //t1.join(); + //t2.join(); + + randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount); + rxdebug("%s: dataset initialized\n"); + // randomx_release_cache(randomxCache); + // rxdebug("%s: cache released\n"); + + randomx_vm *myVM = randomx_create_vm(flags, nullptr, randomxDataset); + if(myVM == NULL) { + LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n"); + return; } //fprintf(stderr,"RandomXMiner: Mining_start=%u\n", Mining_start); #ifdef ENABLE_WALLET @@ -1185,6 +1234,7 @@ void static RandomXMiner() } else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",SMART_CHAIN_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT); } } + rxdebug("%s: incrementing extra nonce\n"); IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); // fprintf(stderr,"RandomXMiner: %u transactions in block\n",(int32_t)pblock->vtx.size()); LogPrintf("Running HushRandomXMiner with %u transactions in block (%u bytes)\n",pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION)); @@ -1213,13 +1263,6 @@ void static RandomXMiner() arith_uint256 hashTarget; hashTarget = HASHTarget; - char randomxHash[RANDOMX_HASH_SIZE]; - //fprintf(stderr,"RandomXMiner: created randomxHash of size %d\n", RANDOMX_HASH_SIZE); - char randomxKey[82]; // randomx spec says keysize of >60 bytes is implementation-specific - // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy - // since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long - snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT); - CDataStream randomxInput(SER_NETWORK, PROTOCOL_VERSION); // Use the current block as randomx input randomxInput << pblocktemplate->block; @@ -1228,50 +1271,7 @@ void static RandomXMiner() // fprintf(stderr,"RandomXMiner: created randomxKey=%s , randomxInput.size=%lu\n", randomxKey, randomxInput.size() ); //randomxInput); rxdebug("%s: randomxKey=%s randomxInput=%s\n", randomxKey, HexStr(randomxInput).c_str()); - // With the defaults of 1024 and 64 - // the key block will change every ~21.3 hours with a 75s block time - // and every ~17 hours with the default 60s block time for HSCs - int randomxInterval = GetArg("-ac_randomx_interval",1024); - // This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs - int randomxBlockLag = GetArg("-ac_randomx_lag", 64); - - // fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag); - rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height); - // Use the initial key at the start of the chain, until the first key block - if( (Mining_height) < randomxInterval + randomxBlockLag) { - randomx_init_cache(randomxCache, &randomxKey, sizeof randomxKey); - rxdebug("%s: initialized cache with initial key\n"); - } else { - rxdebug("%s: calculating keyHeight with randomxInterval=%d\n", randomxInterval); - // At heights between intervals, we use the same block key and wait randomxBlockLag blocks until changing - int keyHeight = ((Mining_height - randomxBlockLag) / randomxInterval) * randomxInterval; - uint256 randomxBlockKey = chainActive[keyHeight]->GetBlockHash(); - - randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey); - rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str()); - - } - - //TODO: this is hardcoded to use 2 threads instead of the number of mining threads - //std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2); - //std::thread t2(&randomx_init_dataset, randomxDataset, randomxCache, datasetItemCount / 2, datasetItemCount - datasetItemCount / 2); - //t1.join(); - //t2.join(); - auto datasetItemCount = randomx_dataset_item_count(); - rxdebug("%s: dataset items=%lu\n", datasetItemCount); - - randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount); - rxdebug("%s: dataset initialized\n"); - // randomx_release_cache(randomxCache); - // rxdebug("%s: cache released\n"); - - randomx_vm *myVM = randomx_create_vm(flags, nullptr, randomxDataset); - if(myVM == NULL) { - LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n"); - return; - } - - + rxdebug("%s: calculating randomx hash\n"); randomx_calculate_hash(myVM, &randomxInput, sizeof randomxInput, randomxHash); rxdebug("%s: calculated randomx hash\n"); @@ -1283,11 +1283,11 @@ void static RandomXMiner() printf("\n"); } - randomx_destroy_vm(myVM); - rxdebug("%s: destroyed VM\n"); + + //randomx_destroy_vm(myVM); + //rxdebug("%s: destroyed VM\n"); // Use randomx hash to build a valid block - std::function)> validBlock = #ifdef ENABLE_WALLET [&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams] From ca52c6beb87ecbe35b7571b5cf4f701f9060bc0f Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 11 Nov 2022 04:26:18 -0800 Subject: [PATCH 04/30] Avoid potential coredump if pindex is NULL --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bc2d75752..001c42718 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2771,7 +2771,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) // our wallet birthday (as adjusted for block time variability) while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200))) { pindex = chainActive.Next(pindex); - pwalletMain->rescanHeight = pindex->GetHeight(); + pwalletMain->rescanHeight = pindex ? pindex->GetHeight() : 0; } ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup From fcfe09d196a945a42b82496c2497fcc45e30b305 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sat, 12 Nov 2022 04:17:35 -0800 Subject: [PATCH 05/30] chainActive.Tip() can be NULL if have never synced to a chain tip before, so use chainActive.Height() instead --- src/init.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index ec2d3bdb1..b4cc62797 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2042,7 +2042,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } pwalletMain->consolidationInterval = consolidationInterval; - pwalletMain->nextConsolidation = pwalletMain->consolidationInterval + chainActive.Tip()->GetHeight(); + pwalletMain->nextConsolidation = pwalletMain->consolidationInterval + chainActive.Height(); LogPrintf("%s: set nextConsolidation=%d\n", __func__, pwalletMain->nextConsolidation ); //Validate Sapling Addresses @@ -2066,7 +2066,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) sweepInterval = 10; } pwalletMain->sweepInterval = sweepInterval; - pwalletMain->nextSweep = pwalletMain->sweepInterval + chainActive.Tip()->GetHeight(); + pwalletMain->nextSweep = pwalletMain->sweepInterval + chainActive.Height(); LogPrintf("%s: set nextSweep=%d with sweepInterval=%d\n", __func__, pwalletMain->nextSweep, pwalletMain->sweepInterval ); fSweepTxFee = GetArg("-zsweepfee", DEFAULT_SWEEP_FEE); fSweepMapUsed = !mapMultiArgs["-zsweepaddress"].empty(); From 81f0c7755e6d0958e9c68a1579e499c49cbf24c0 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sat, 12 Nov 2022 09:22:10 -0500 Subject: [PATCH 06/30] Code to test exact cause of the 'up only' diff bug --- src/pow.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pow.cpp b/src/pow.cpp index 753378ba9..31c9eafcf 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -526,7 +526,11 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, // Limit adjustment step and use medians to prevent time-warp attacks int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); - int64_t AWT = AveragingWindowTimespan(height) ; + + //NOTE: this will break HUSH+DRAGONX mainnet! For testing only. + int64_t AWT = params.AveragingWindowTimespan(); + //int64_t AWT = AveragingWindowTimespan(height) ; + nActualTimespan = AWT + (nActualTimespan - AWT)/4; LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); From 3dbe8d3c6bd730982f1e1aaece856ae00f1adfd9 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 15 Nov 2022 13:43:10 -0500 Subject: [PATCH 07/30] indentation --- src/miner.cpp | 53 ++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 1ff987e9b..97f093f1e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1132,36 +1132,37 @@ void static RandomXMiner() Mining_height = pindexPrev->GetHeight()+1; Mining_start = (uint32_t)time(NULL); } - 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 - // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy - // since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long - snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT); - // With the defaults of 1024 and 64 - // the key block will change every ~21.3 hours with a 75s block time - // and every ~17 hours with the default 60s block time for HSCs - int randomxInterval = GetArg("-ac_randomx_interval",1024); - // This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs - int randomxBlockLag = GetArg("-ac_randomx_lag", 64); + 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 + // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy + // since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long + snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT); - // fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag); - rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height); - // Use the initial key at the start of the chain, until the first key block - if( (Mining_height) < randomxInterval + randomxBlockLag) { - randomx_init_cache(randomxCache, &randomxKey, sizeof randomxKey); - rxdebug("%s: initialized cache with initial key\n"); - } else { - rxdebug("%s: calculating keyHeight with randomxInterval=%d\n", randomxInterval); - // At heights between intervals, we use the same block key and wait randomxBlockLag blocks until changing - int keyHeight = ((Mining_height - randomxBlockLag) / randomxInterval) * randomxInterval; - uint256 randomxBlockKey = chainActive[keyHeight]->GetBlockHash(); + // With the defaults of 1024 and 64 + // the key block will change every ~21.3 hours with a 75s block time + // and every ~17 hours with the default 60s block time for HSCs + int randomxInterval = GetArg("-ac_randomx_interval",1024); + // This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs + int randomxBlockLag = GetArg("-ac_randomx_lag", 64); - randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey); - rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str()); + // fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag); + rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height); + // Use the initial key at the start of the chain, until the first key block + if( (Mining_height) < randomxInterval + randomxBlockLag) { + randomx_init_cache(randomxCache, &randomxKey, sizeof randomxKey); + rxdebug("%s: initialized cache with initial key\n"); + } else { + rxdebug("%s: calculating keyHeight with randomxInterval=%d\n", randomxInterval); + // At heights between intervals, we use the same block key and wait randomxBlockLag blocks until changing + int keyHeight = ((Mining_height - randomxBlockLag) / randomxInterval) * randomxInterval; + uint256 randomxBlockKey = chainActive[keyHeight]->GetBlockHash(); - } + randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey); + rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str()); + + } auto datasetItemCount = randomx_dataset_item_count(); rxdebug("%s: dataset items=%lu\n", datasetItemCount); From d3b948005c8f68ca7efa7a89b26d1c5b877e0471 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 15 Nov 2022 13:44:47 -0500 Subject: [PATCH 08/30] indentation --- src/miner.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 97f093f1e..1b030ea18 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1065,23 +1065,24 @@ void static RandomXMiner() cancelSolver = true; } ); - randomx_flags flags = randomx_get_flags(); - // flags |= RANDOMX_FLAG_LARGE_PAGES; - flags |= RANDOMX_FLAG_FULL_MEM; - //flags |= RANDOMX_FLAG_JIT; - randomx_cache *randomxCache = randomx_alloc_cache(flags); - if (randomxCache == NULL) { - LogPrintf("RandomX cache is null, something is wrong, cannot mine!\n"); - return; - } - rxdebug("%s: created randomx flags + cache\n"); + randomx_flags flags = randomx_get_flags(); + // flags |= RANDOMX_FLAG_LARGE_PAGES; + flags |= RANDOMX_FLAG_FULL_MEM; + //flags |= RANDOMX_FLAG_JIT; + randomx_cache *randomxCache = randomx_alloc_cache(flags); + if (randomxCache == NULL) { + LogPrintf("RandomX cache is null, something is wrong, cannot mine!\n"); + return; + } + rxdebug("%s: created randomx flags + cache\n"); + randomx_dataset *randomxDataset = randomx_alloc_dataset(flags); + rxdebug("%s: created dataset\n"); + + if( randomxDataset == nullptr) { + LogPrintf("%s: allocating randomx dataset failed!\n", __func__); + return; + } - randomx_dataset *randomxDataset = randomx_alloc_dataset(flags); - rxdebug("%s: created dataset\n"); - if( randomxDataset == nullptr) { - LogPrintf("%s: allocating randomx dataset failed!\n", __func__); - return; - } miningTimer.start(); try { From c55d1cbc5f484e95f5e0f573e43aa4ce93dd795f Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 15 Nov 2022 14:02:02 -0500 Subject: [PATCH 09/30] Destroy randomx VM when we are done with it --- src/miner.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 1b030ea18..c1f6f73b6 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1066,6 +1066,7 @@ void static RandomXMiner() } ); randomx_flags flags = randomx_get_flags(); + // TODO: attempt to use large pages and fall back to no large pages // flags |= RANDOMX_FLAG_LARGE_PAGES; flags |= RANDOMX_FLAG_FULL_MEM; //flags |= RANDOMX_FLAG_JIT; @@ -1175,8 +1176,6 @@ void static RandomXMiner() randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount); rxdebug("%s: dataset initialized\n"); - // randomx_release_cache(randomxCache); - // rxdebug("%s: cache released\n"); randomx_vm *myVM = randomx_create_vm(flags, nullptr, randomxDataset); if(myVM == NULL) { @@ -1286,9 +1285,6 @@ void static RandomXMiner() printf("\n"); } - //randomx_destroy_vm(myVM); - //rxdebug("%s: destroyed VM\n"); - // Use randomx hash to build a valid block std::function)> validBlock = #ifdef ENABLE_WALLET @@ -1396,6 +1392,11 @@ void static RandomXMiner() pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); pblock->nBits = savebits; } + + rxdebug("%s: going to destroy rx VM\n"); + randomx_destroy_vm(myVM); + rxdebug("%s: destroyed VM\n"); + } From 1a4e8d4acfba44d4485dc68475a453e1b1ef6eea Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 15 Nov 2022 14:11:55 -0500 Subject: [PATCH 10/30] Initialize randomx dataset with 2 threads --- src/miner.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index c1f6f73b6..a222e4f16 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1168,13 +1168,15 @@ void static RandomXMiner() auto datasetItemCount = randomx_dataset_item_count(); rxdebug("%s: dataset items=%lu\n", datasetItemCount); - //TODO: this is hardcoded to use 2 threads instead of the number of mining threads - //std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2); - //std::thread t2(&randomx_init_dataset, randomxDataset, randomxCache, datasetItemCount / 2, datasetItemCount - datasetItemCount / 2); - //t1.join(); - //t2.join(); - randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount); + //TODO: this is hardcoded to use 2 threads instead of the number of mining threads + rxdebug("%s: initializing dataset with 2 threads\n"); + std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2); + std::thread t2(&randomx_init_dataset, randomxDataset, randomxCache, datasetItemCount / 2, datasetItemCount - datasetItemCount / 2); + t1.join(); + t2.join(); + + // randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount); rxdebug("%s: dataset initialized\n"); randomx_vm *myVM = randomx_create_vm(flags, nullptr, randomxDataset); From c8b2163c1c9df4aa69815847d708d7445e405ad4 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 15 Nov 2022 14:21:45 -0500 Subject: [PATCH 11/30] Optimize inner mining loop --- src/miner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index a222e4f16..8288ebfc4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1079,6 +1079,9 @@ 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; @@ -1166,9 +1169,6 @@ void static RandomXMiner() } - auto datasetItemCount = randomx_dataset_item_count(); - rxdebug("%s: dataset items=%lu\n", datasetItemCount); - //TODO: this is hardcoded to use 2 threads instead of the number of mining threads rxdebug("%s: initializing dataset with 2 threads\n"); std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2); From 665f89513417c0ab2277b205c25f560bbcde0a5a Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 15 Nov 2022 14:40:10 -0500 Subject: [PATCH 12/30] Optimize inner mining loop --- src/miner.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 8288ebfc4..bdf10ec56 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1065,6 +1065,8 @@ void static RandomXMiner() cancelSolver = true; } ); + miningTimer.start(); + randomx_flags flags = randomx_get_flags(); // TODO: attempt to use large pages and fall back to no large pages // flags |= RANDOMX_FLAG_LARGE_PAGES; @@ -1087,7 +1089,20 @@ void static RandomXMiner() return; } - miningTimer.start(); + + 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 + // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy + // since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long + snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT); + + // With the defaults of 1024 and 64 + // the key block will change every ~21.3 hours with a 75s block time + // and every ~17 hours with the default 60s block time for HSCs + int randomxInterval = GetArg("-ac_randomx_interval",1024); + // This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs + int randomxBlockLag = GetArg("-ac_randomx_lag", 64); try { // fprintf(stderr,"RandomXMiner: mining %s with randomx\n",SMART_CHAIN_SYMBOL); @@ -1138,19 +1153,6 @@ void static RandomXMiner() Mining_start = (uint32_t)time(NULL); } - 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 - // initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy - // since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long - snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT); - - // With the defaults of 1024 and 64 - // the key block will change every ~21.3 hours with a 75s block time - // and every ~17 hours with the default 60s block time for HSCs - int randomxInterval = GetArg("-ac_randomx_interval",1024); - // This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs - int randomxBlockLag = GetArg("-ac_randomx_lag", 64); // fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag); rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height); From b7adb511a63a65d7691b938bbdd167366c3be63a Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 15 Nov 2022 19:13:31 -0500 Subject: [PATCH 13/30] cleanup --- src/miner.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index bdf10ec56..2fbe958e7 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1089,7 +1089,6 @@ void static RandomXMiner() return; } - 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 @@ -1153,7 +1152,6 @@ void static RandomXMiner() Mining_start = (uint32_t)time(NULL); } - // fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag); rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height); // Use the initial key at the start of the chain, until the first key block @@ -1168,7 +1166,6 @@ void static RandomXMiner() randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey); rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str()); - } //TODO: this is hardcoded to use 2 threads instead of the number of mining threads @@ -1302,7 +1299,7 @@ void static RandomXMiner() rxdebug("%s: Checking solution against target\n"); pblock->nSolution = soln; solutionTargetChecks.increment(); - fprintf(stderr,"%s: solutionTargetChecks=%lu\n", __func__, solutionTargetChecks.get()); + // fprintf(stderr,"%s: solutionTargetChecks=%lu\n", __func__, solutionTargetChecks.get()); B = *pblock; h = UintToArith256(B.GetHash()); @@ -1683,7 +1680,7 @@ void static BitcoinMiner() LogPrint("pow", "- Checking solution against target\n"); pblock->nSolution = soln; solutionTargetChecks.increment(); - rxdebug("%s: solutionTargetChecks=%lu\n", solutionTargetChecks.get()); + // fprintf(stderr, "%s: solutionTargetChecks=%lu\n", __func__, solutionTargetChecks.get()); B = *pblock; h = UintToArith256(B.GetHash()); /*for (z=31; z>=16; z--) From 1b7f200d29ddc3bee77191139b12beaff11f7621 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Thu, 1 Dec 2022 14:55:53 -0500 Subject: [PATCH 14/30] Fix typo in getsnapshot docs --- src/rpc/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index cd8ee74b2..81ad0984e 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -1334,7 +1334,7 @@ UniValue getsnapshot(const UniValue& params, bool fHelp, const CPubKey& mypk) " \"utxos\": 14, (number) Total number of UTXOs in snapshot\n" " \"total_addresses\": 2, (number) Total number of addresses in snapshot,\n" " \"start_height\": 91, (number) Block height snapshot began\n" - " \"ending_height\": 91 (number) Block height snapsho finished,\n" + " \"ending_height\": 91 (number) Block height snapshot finished,\n" " \"start_time\": 1531982752, (number) Unix epoch time snapshot started\n" " \"end_time\": 1531982752 (number) Unix epoch time snapshot finished\n" "}\n" From f2f60196202f388508a187c3fcbd5055d59e174d Mon Sep 17 00:00:00 2001 From: onryo Date: Sun, 4 Dec 2022 13:57:07 +0000 Subject: [PATCH 15/30] rm hashFinalSproutRoot related to https://git.hush.is/hush/hush3/issues/248 --- src/main.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index acef0dd50..6f39e16ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5960,20 +5960,6 @@ bool static LoadBlockIndexDB() pblocktree->ReadFlag("spentindex", fSpentIndex); LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled"); - // Fill in-memory data - BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) - { - CBlockIndex* pindex = item.second; - // - This relationship will always be true even if pprev has multiple - // children, because hashSproutAnchor is technically a property of pprev, - // not its children. - // - This will miss chain tips; we handle the best tip below, and other - // tips will be handled by ConnectTip during a re-org. - if (pindex->pprev) { - pindex->pprev->hashFinalSproutRoot = pindex->hashSproutAnchor; - } - } - // Load pointer to end of best chain BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); if (it == mapBlockIndex.end()) From 01ff5c81f61746b7c5ceabb19b10215b8f617da2 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 6 Dec 2022 14:23:53 -0500 Subject: [PATCH 16/30] Improve some comments and ensure backcompat on HUSH mainnet Some comments turned out to be wrong and some could be more helpful. It turns out that when AveragingWindowTimespan was changed to fix a HUSH mainnet bug long ago, that introduced a bug for HSC's that do not use a 75s block time. Since the default is 60s that likely means all HSC's that will be created. There were no production HSC's in use at the time of that bugfix, so the bug went unnoticed until DRAGONX was launched. The bug then manifested as the DRAGONX difficulty bug, which cause the difficulty to never correct down, only up and lead to extremely long block times on DRAGONX mainnet. This code change ensures that HUSH mainnet uses the same hardcoded AWT as it did previously and all other HSC's will use params.AveragingWindowTimespan() , including DRAGONX mainnet. This seems less dangerous than changing AveragingWindowTimespan() on HUSH mainnet. --- src/pow.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index 31c9eafcf..a63ac8d21 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -509,8 +509,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead } // Changing this requires changing many other things and -// changes consensus. Have fun -- Duke -int64_t AveragingWindowTimespan(int32_t height) { +// might change consensus. Have fun -- Duke +// NOTE: Ony HUSH3 mainnet should use this function, all HSC's should use params.AveragigWindowTimespan() +int64_t AveragingWindowTimespan() { // used in const methods, beware! // This is the correct AWT for 75s blocktime, before block 340k // the correct value was 2550 when the blocktime was 150s @@ -527,9 +528,9 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); - //NOTE: this will break HUSH+DRAGONX mainnet! For testing only. - int64_t AWT = params.AveragingWindowTimespan(); - //int64_t AWT = AveragingWindowTimespan(height) ; + bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false; + // If this is HUSH3, use AWT function defined above, else use the one in params + int64_t AWT = ishush3 ? AveragingWindowTimespan() : params.AveragingWindowTimespan(); nActualTimespan = AWT + (nActualTimespan - AWT)/4; LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); From ae64eb239234fa743f5b0b2e89da836a8b6bc3a1 Mon Sep 17 00:00:00 2001 From: Duke Date: Sun, 18 Dec 2022 08:24:49 -0800 Subject: [PATCH 17/30] Remove alerts --- contrib/init/hushd.conf | 6 - contrib/init/hushd.openrc | 5 - qa/rpc-tests/test_framework/mininode.py | 19 --- src/Makefile.am | 4 - src/alert.cpp | 163 ------------------------ src/alert.h | 127 ------------------ src/alertkeys.h | 28 ---- src/chainparams.cpp | 2 - src/chainparams.h | 3 - src/deprecation.cpp | 4 - src/init.cpp | 9 +- src/main.cpp | 53 ++------ src/main.h | 5 - src/sendalert.cpp | 83 ------------ 14 files changed, 9 insertions(+), 502 deletions(-) delete mode 100644 src/alert.cpp delete mode 100644 src/alert.h delete mode 100644 src/alertkeys.h delete mode 100644 src/sendalert.cpp diff --git a/contrib/init/hushd.conf b/contrib/init/hushd.conf index 649df7796..eb26f3fdb 100644 --- a/contrib/init/hushd.conf +++ b/contrib/init/hushd.conf @@ -35,12 +35,6 @@ pre-start script echo echo "bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'" echo - echo "It is also recommended that you also set alertnotify so you are " - echo "notified of problems:" - echo - echo "ie: alertnotify=echo %%s | mail -s \"Hush Alert\"" \ - "admin@foo.com" - echo exit 1 fi diff --git a/contrib/init/hushd.openrc b/contrib/init/hushd.openrc index 08e04a00f..4443b1223 100644 --- a/contrib/init/hushd.openrc +++ b/contrib/init/hushd.openrc @@ -81,11 +81,6 @@ checkconfig() eerror "" eerror "bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'" eerror "" - eerror "It is also recommended that you also set alertnotify so you are " - eerror "notified of problems:" - eerror "" - eerror "ie: alertnotify=echo %%s | mail -s \"Hush Alert\"" \ - "admin@foo.com" eerror "" return 1 fi diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 421691bcb..69d3c75ac 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -984,24 +984,6 @@ class msg_addr(object): return "msg_addr(addrs=%s)" % (repr(self.addrs)) -class msg_alert(object): - command = "alert" - - def __init__(self): - self.alert = CAlert() - - def deserialize(self, f): - self.alert = CAlert() - self.alert.deserialize(f) - - def serialize(self): - r = "" - r += self.alert.serialize() - return r - - def __repr__(self): - return "msg_alert(alert=%s)" % (repr(self.alert), ) - class msg_inv(object): command = "inv" @@ -1370,7 +1352,6 @@ class NodeConn(asyncore.dispatcher): "version": msg_version, "verack": msg_verack, "addr": msg_addr, - "alert": msg_alert, "inv": msg_inv, "getdata": msg_getdata, "getblocks": msg_getblocks, diff --git a/src/Makefile.am b/src/Makefile.am index 5fe0118c0..684e1a611 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -122,7 +122,6 @@ BITCOIN_CORE_H = \ addressindex.h \ spentindex.h \ addrman.h \ - alert.h \ amount.h \ amqp/amqpabstractnotifier.h \ amqp/amqpconfig.h \ @@ -249,10 +248,7 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ - sendalert.cpp \ addrman.cpp \ - alert.cpp \ - alertkeys.h \ asyncrpcoperation.cpp \ asyncrpcqueue.cpp \ bloom.cpp \ diff --git a/src/alert.cpp b/src/alert.cpp deleted file mode 100644 index 9560a0c87..000000000 --- a/src/alert.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2016-2022 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ -#include "alert.h" -#include "clientversion.h" -#include "net.h" -#include "pubkey.h" -#include "timedata.h" -#include "ui_interface.h" -#include "util.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -map mapAlerts; -CCriticalSection cs_mapAlerts; - -void CUnsignedAlert::SetNull() -{ - nVersion = 1; - nRelayUntil = 0; - nExpiration = 0; - nID = 0; - nCancel = 0; - setCancel.clear(); - nMinVer = 0; - nMaxVer = 0; - setSubVer.clear(); - nPriority = 0; - - strComment.clear(); - strStatusBar.clear(); - strRPCError.clear(); -} - -std::string CUnsignedAlert::ToString() const -{ - std::string strSetCancel; - BOOST_FOREACH(int n, setCancel) - strSetCancel += strprintf("%d ", n); - std::string strSetSubVer; - BOOST_FOREACH(const std::string& str, setSubVer) - strSetSubVer += "\"" + str + "\" "; - return strprintf( - "CAlert(\n" - " nVersion = %d\n" - " nRelayUntil = %d\n" - " nExpiration = %d\n" - " nID = %d\n" - " nCancel = %d\n" - " setCancel = %s\n" - " nMinVer = %d\n" - " nMaxVer = %d\n" - " setSubVer = %s\n" - " nPriority = %d\n" - " strComment = \"%s\"\n" - " strStatusBar = \"%s\"\n" - " strRPCError = \"%s\"\n" - ")\n", - nVersion, - nRelayUntil, - nExpiration, - nID, - nCancel, - strSetCancel, - nMinVer, - nMaxVer, - strSetSubVer, - nPriority, - strComment, - strStatusBar, - strRPCError); -} - -void CAlert::SetNull() -{ - CUnsignedAlert::SetNull(); - vchMsg.clear(); - vchSig.clear(); -} - -bool CAlert::IsNull() const -{ - return (nExpiration == 0); -} - -uint256 CAlert::GetHash() const -{ - return Hash(this->vchMsg.begin(), this->vchMsg.end()); -} - -bool CAlert::IsInEffect() const -{ - return false; -} - -bool CAlert::Cancels(const CAlert& alert) const -{ - if (!IsInEffect()) - return false; // this was a no-op before 31403 - return (alert.nID <= nCancel || setCancel.count(alert.nID)); -} - -bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const -{ - // TODO: rework for client-version-embedded-in-strSubVer ? - return (IsInEffect() && - nMinVer <= nVersion && nVersion <= nMaxVer && - (setSubVer.empty() || setSubVer.count(strSubVerIn))); -} - -bool CAlert::AppliesToMe() const -{ - return false; -} - -bool CAlert::RelayTo(CNode* pnode) const -{ - return false; -} - -bool CAlert::CheckSignature(const std::vector& alertKey) const -{ - return false; -} - -CAlert CAlert::getAlertByHash(const uint256 &hash) -{ - CAlert retval; - return retval; -} - -bool CAlert::ProcessAlert(const std::vector& alertKey, bool fThread) -{ - return true; -} - -void CAlert::Notify(const std::string& strMessage, bool fThread) -{ - return; -} diff --git a/src/alert.h b/src/alert.h deleted file mode 100644 index f461c51c5..000000000 --- a/src/alert.h +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers -// Copyright (c) 2016-2022 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html - -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#ifndef HUSH_ALERT_H -#define HUSH_ALERT_H - -#include "serialize.h" -#include "sync.h" -#include -#include -#include -#include - -class CAlert; -class CNode; -class uint256; - -extern std::map mapAlerts; -extern CCriticalSection cs_mapAlerts; - -/** Alerts are for notifying old versions if they become too obsolete and - * need to upgrade. The message is displayed in the status bar. - * Alert messages are broadcast as a vector of signed data. Unserializing may - * not read the entire buffer if the alert is for a newer version, but older - * versions can still relay the original data. - */ -class CUnsignedAlert -{ -public: - int nVersion; - int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes - int64_t nExpiration; - int nID; - int nCancel; - std::set setCancel; - int nMinVer; // lowest version inclusive - int nMaxVer; // highest version inclusive - std::set setSubVer; // empty matches all - int nPriority; - - // Actions - std::string strComment; - std::string strStatusBar; - std::string strRPCError; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(this->nVersion); - READWRITE(nRelayUntil); - READWRITE(nExpiration); - READWRITE(nID); - READWRITE(nCancel); - READWRITE(setCancel); - READWRITE(nMinVer); - READWRITE(nMaxVer); - READWRITE(setSubVer); - READWRITE(nPriority); - - READWRITE(LIMITED_STRING(strComment, 65536)); - READWRITE(LIMITED_STRING(strStatusBar, 256)); - READWRITE(LIMITED_STRING(strRPCError, 256)); - } - - void SetNull(); - - std::string ToString() const; -}; - -/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ -class CAlert : public CUnsignedAlert -{ -public: - std::vector vchMsg; - std::vector vchSig; - - CAlert() - { - SetNull(); - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(vchMsg); - READWRITE(vchSig); - } - - void SetNull(); - bool IsNull() const; - uint256 GetHash() const; - bool IsInEffect() const; - bool Cancels(const CAlert& alert) const; - bool AppliesTo(int nVersion, const std::string& strSubVerIn) const; - bool AppliesToMe() const; - bool RelayTo(CNode* pnode) const; - bool CheckSignature(const std::vector& alertKey) const; - bool ProcessAlert(const std::vector& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread - static void Notify(const std::string& strMessage, bool fThread); - - /* - * Get copy of (active) alert object by hash. Returns a null alert if it is not found. - */ - static CAlert getAlertByHash(const uint256 &hash); -}; - -#endif // HUSH_ALERT_H diff --git a/src/alertkeys.h b/src/alertkeys.h deleted file mode 100644 index 0de5d269e..000000000 --- a/src/alertkeys.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2016-2022 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#ifndef HUSH_ALERTKEYS_H -#define HUSH_ALERTKEYS_H - -// REMINDER: DO NOT COMMIT YOUR PRIVATE KEYS TO THE GIT REPOSITORY, lulz - -const char* pszPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; -const char* pszTestNetPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - -#endif - diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 6f44af2da..6a7ca1ed1 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -142,7 +142,6 @@ public: pchMessageStart[1] = 0xee; pchMessageStart[2] = 0xe4; pchMessageStart[3] = 0x8d; - vAlertPubKey = ParseHex("038a1bd41a08f38edda51042988022933c5775dfce81f7bae0b32a9179650352ac"); nDefaultPort = 5420; nMinerThreads = 0; nMaxTipAge = 24 * 60 * 60; @@ -280,7 +279,6 @@ public: pchMessageStart[1] = 0x1F; pchMessageStart[2] = 0x7E; pchMessageStart[3] = 0x62; - vAlertPubKey = ParseHex("038a1bd41a08f38edda51042988022933c5775dfce81f7bae0b32a9179650352ac"); nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 1000; diff --git a/src/chainparams.h b/src/chainparams.h index 9e2707b31..e32a965ba 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -85,7 +85,6 @@ public: const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } - const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } const CBlock& GenesisBlock() const { return genesis; } @@ -134,8 +133,6 @@ public: protected: CChainParams() {} - //! Raw pub key bytes for the broadcast alert signing key. - std::vector vAlertPubKey; int nMinerThreads = 0; long nMaxTipAge = 0; int nDefaultPort = 0; diff --git a/src/deprecation.cpp b/src/deprecation.cpp index 3c68fc07e..572502460 100644 --- a/src/deprecation.cpp +++ b/src/deprecation.cpp @@ -19,8 +19,6 @@ ******************************************************************************/ #include "deprecation.h" - -#include "alert.h" #include "clientversion.h" #include "init.h" #include "ui_interface.h" @@ -51,7 +49,6 @@ void EnforceNodeDeprecation(int nHeight, bool forceLogging, bool fThread) { DEPRECATION_HEIGHT) + " " + _("You should upgrade to the latest version of Hush."); LogPrintf("*** %s\n", msg); - CAlert::Notify(msg, fThread); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); } StartShutdown(); @@ -60,7 +57,6 @@ void EnforceNodeDeprecation(int nHeight, bool forceLogging, bool fThread) { DEPRECATION_HEIGHT) + " " + _("You should upgrade to the latest version of Hush."); LogPrintf("*** %s\n", msg); - CAlert::Notify(msg, fThread); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING); } } diff --git a/src/init.cpp b/src/init.cpp index b4cc62797..6fe9c9299 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -87,7 +87,6 @@ using namespace std; #include "hush_defs.h" static const bool DEFAULT_STRATUM_ENABLE = false; -extern void ThreadSendAlert(); extern bool hush_dailysnapshot(int32_t height); extern int32_t HUSH_LOADINGBLOCKS; extern char SMART_CHAIN_SYMBOL[]; @@ -361,7 +360,6 @@ std::string HelpMessage(HelpMessageMode mode) string strUsage = HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); - strUsage += HelpMessageOpt("-alertnotify=", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-blocknotify=", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); strUsage += HelpMessageOpt("-checkblocks=", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288)); strUsage += HelpMessageOpt("-checklevel=", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3)); @@ -501,7 +499,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0)); strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)"); } - string debugCategories = "addrman, alert, bench, coindb, db, deletetx, estimatefee, http, libevent, lock, mempool, net, tls, partitioncheck, pow, proxy, prune, rand, randomx, reindex, rpc, selectcoins, stratum, tor, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these + string debugCategories = "addrman, bench, coindb, db, deletetx, estimatefee, http, libevent, lock, mempool, net, tls, partitioncheck, pow, proxy, prune, rand, randomx, reindex, rpc, selectcoins, stratum, tor, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + _("If is not supplied or if = 1, output all debugging information.") + " " + _(" can be:") + " " + debugCategories + "."); strUsage += HelpMessageOpt("-experimentalfeatures", _("Enable use of experimental features")); @@ -1380,8 +1378,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true); nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); - fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); - // Option to startup with mocktime set (used for regression testing): SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op @@ -2398,9 +2394,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif - // SENDALERT - threadGroup.create_thread(boost::bind(ThreadSendAlert)); - if(fDebug) fprintf(stderr,"%s end fRequestShutdown=%d\n", __FUNCTION__, !!fRequestShutdown); return !fRequestShutdown; diff --git a/src/main.cpp b/src/main.cpp index 6f39e16ee..c10184702 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,6 @@ #include "main.h" #include "sodium.h" #include "addrman.h" -#include "alert.h" #include "arith_uint256.h" #include "importcoin.h" #include "chainparams.h" @@ -106,7 +105,6 @@ bool fCheckpointsEnabled = true; bool fCoinbaseEnforcedProtectionEnabled = true; size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; -bool fAlerts = DEFAULT_ALERTS; // If the tip is older than this (in seconds), the node is considered to be in initial block download. int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false; @@ -2470,9 +2468,9 @@ void CheckForkWarningConditions() { if (!fLargeWorkForkFound && pindexBestForkBase) { - std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + - pindexBestForkBase->phashBlock->ToString() + std::string("'"); - CAlert::Notify(warning, true); + std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + pindexBestForkBase->phashBlock->ToString() + std::string("'"); + LogPrintf(warning); + LogPrintf("%s: %s\n", __func__, warning.c_str()); } if (pindexBestForkTip && pindexBestForkBase) { @@ -2480,12 +2478,9 @@ void CheckForkWarningConditions() pindexBestForkBase->GetHeight(), pindexBestForkBase->phashBlock->ToString(), pindexBestForkTip->GetHeight(), pindexBestForkTip->phashBlock->ToString()); fLargeWorkForkFound = true; - } - else - { + } else { std::string warning = std::string("Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely."); - LogPrintf("%s: %s\n", warning.c_str(), __func__); - CAlert::Notify(warning, true); + LogPrintf("%s: %s\n", __func__, warning.c_str()); fLargeWorkInvalidChainFound = true; } } else { @@ -6651,11 +6646,7 @@ void static CheckBlockIndex() assert(nNodes == forward.size()); } -////////////////////////////////////////////////////////////////////////////// -// // CAlert -// - std::string GetWarnings(const std::string& strFor) { int nPriority = 0; @@ -6686,23 +6677,6 @@ std::string GetWarnings(const std::string& strFor) strStatusBar = strRPC = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); } - // Alerts - { - LOCK(cs_mapAlerts); - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { - const CAlert& alert = item.second; - if (alert.AppliesToMe() && alert.nPriority > nPriority) - { - nPriority = alert.nPriority; - strStatusBar = alert.strStatusBar; - if (alert.nPriority >= ALERT_PRIORITY_SAFE_MODE) { - strRPC = alert.strRPCError; - } - } - } - } - if (strFor == "statusbar") return strStatusBar; else if (strFor == "rpc") @@ -6711,18 +6685,7 @@ std::string GetWarnings(const std::string& strFor) return "error"; } - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// // Messages -// - bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { @@ -7702,9 +7665,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } if (vInv.size() > 0) pfrom->PushMessage("inv", vInv); - } else if (fAlerts && strCommand == "alert") { - // Do not process alert p2p messages and give DoS penalty - Misbehaving(pfrom->GetId(), 10); + } else if (strCommand == "alert") { + // Do not process alert p2p messages + // Misbehaving(pfrom->GetId(), 10); } else if (!(nLocalServices & NODE_BLOOM) && (strCommand == "filterload" || strCommand == "filteradd")) { diff --git a/src/main.h b/src/main.h index 034629dbc..a76ce4333 100644 --- a/src/main.h +++ b/src/main.h @@ -71,10 +71,6 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 2000000;//MAX_BLOCK_SIZE; static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; /** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = DEFAULT_BLOCK_MAX_SIZE / 2; -/** Default for accepting alerts from the P2P network. */ -static const bool DEFAULT_ALERTS = true; -/** Minimum alert priority for enabling safe mode. */ -static const int ALERT_PRIORITY_SAFE_MODE = 4000; /** Maximum reorg length we will accept before we shut down and alert the user. */ static unsigned int MAX_REORG_LENGTH = _COINBASE_MATURITY - 1; /** Maximum number of signature check operations in an IsStandard() P2SH script */ @@ -165,7 +161,6 @@ extern bool fCheckpointsEnabled; extern bool fCoinbaseEnforcedProtectionEnabled; extern size_t nCoinCacheUsage; extern CFeeRate minRelayTxFee; -extern bool fAlerts; extern int64_t nMaxTipAge; /** Best header we've seen so far (used for getheaders queries' starting points). */ diff --git a/src/sendalert.cpp b/src/sendalert.cpp deleted file mode 100644 index 73116c4b8..000000000 --- a/src/sendalert.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2016-2022 The Hush developers -// Copyright (c) 2016 The Zcash developers -// Original code from: https://gist.github.com/laanwj/0e689cfa37b52bcbbb44 -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html - -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -/* - -To set up a new alert system ----------------------------- - -Create a new alert key pair: -openssl ecparam -name secp256k1 -genkey -param_enc explicit -outform PEM -out data.pem - -Get the private key in hex: -openssl ec -in data.pem -outform DER | tail -c 279 | xxd -p -c 279 - -Get the public key in hex: -openssl ec -in data.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65 - -Update the public keys found in chainparams.cpp. - - -To send an alert message ------------------------- - -Copy the private keys into alertkeys.h. - -Modify the alert parameters, id and message found in this file. - -Build and run with -sendalert or -printalert. - -./hushd -printtoconsole -sendalert - -One minute after starting up, the alert will be broadcast. It is then -flooded through the network until the nRelayUntil time, and will be -active until nExpiration OR the alert is cancelled. - -If you make a mistake, send another alert with nCancel set to cancel -the bad alert. - -*/ - -// Copyright (c) 2016-2022 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -#include "main.h" -#include "net.h" -#include "alert.h" -#include "init.h" -#include "util.h" -#include "utiltime.h" -#include "key.h" -#include "clientversion.h" -#include "chainparams.h" -#include "alertkeys.h" - -static const int64_t DAYS = 24 * 60 * 60; - -void ThreadSendAlert() -{ - if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert")) - return; - - fprintf(stderr,"Sending alerts not supported!\n"); - return; - -} From da5ae526e75430b57867cc5b92a07e2b21cc3b05 Mon Sep 17 00:00:00 2001 From: Duke Date: Sun, 18 Dec 2022 13:51:50 -0800 Subject: [PATCH 18/30] Fix compile issue --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index c10184702..58dc7b25e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2469,7 +2469,6 @@ void CheckForkWarningConditions() if (!fLargeWorkForkFound && pindexBestForkBase) { std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + pindexBestForkBase->phashBlock->ToString() + std::string("'"); - LogPrintf(warning); LogPrintf("%s: %s\n", __func__, warning.c_str()); } if (pindexBestForkTip && pindexBestForkBase) From 512da314a5d3accd506813b5330e3d1c376d5628 Mon Sep 17 00:00:00 2001 From: zanzibar <> Date: Fri, 6 Jan 2023 15:21:08 +0000 Subject: [PATCH 19/30] BIP155 (addrv2) Tor v3 + i2p --- configure.ac | 34 + contrib/seeds/generate-seeds.py | 161 ++-- contrib/seeds/nodes_main.txt | 17 +- contrib/seeds/nodes_test.txt | 10 +- doc/i2p.md | 161 ++++ doc/tor.md | 297 +++++--- qa/rpc-tests/httpbasics.py | 4 +- qa/rpc-tests/p2p-acceptblock.py | 4 +- qa/rpc-tests/proxy_test.py | 22 +- src/Makefile.am | 39 +- src/addrdb.cpp | 122 +++ src/addrdb.h | 90 +++ src/addrman.cpp | 323 +++++--- src/addrman.h | 220 ++++-- src/arith_uint256.cpp | 2 +- src/attributes.h | 20 + src/bitcoin-cli.cpp | 2 +- src/cc/Makefile | 25 +- src/chainparams.cpp | 6 +- src/chainparams.h | 9 +- src/chainparamsseeds.h | 43 +- src/coins.cpp | 3 + src/compat.h | 12 +- src/core_read.cpp | 2 +- src/core_write.cpp | 2 +- src/crypto/common.h | 7 + src/crypto/equihash.h | 2 +- src/crypto/sha3.cpp | 162 ++++ src/crypto/sha3.h | 42 ++ src/gtest/json_test_vectors.h | 2 +- src/gtest/test_deprecation.cpp | 2 +- src/gtest/test_merkletree.cpp | 2 +- src/gtest/test_rpc.cpp | 2 +- src/gtest/test_txid.cpp | 2 +- src/hash.h | 67 +- src/httprpc.cpp | 2 +- src/httpserver.cpp | 57 +- src/hush-tx.cpp | 2 +- src/i2p.cpp | 441 +++++++++++ src/i2p.h | 256 +++++++ src/init.cpp | 77 +- src/key_io.cpp | 2 +- src/main.cpp | 189 +++-- src/main.h | 3 + src/merkleblock.cpp | 2 +- src/metrics.cpp | 2 +- src/net.cpp | 679 +++++++++++++---- src/net.h | 140 +++- src/netaddress.cpp | 1222 +++++++++++++++++++++++++++++++ src/netaddress.h | 534 ++++++++++++++ src/netbase.cpp | 1212 ++++++------------------------ src/netbase.h | 245 ++----- src/netmessagemaker.h | 37 + src/prevector.h | 245 ++++--- src/primitives/block.cpp | 2 +- src/primitives/transaction.cpp | 2 +- src/protocol.cpp | 93 ++- src/protocol.h | 313 +++++++- src/random.cpp | 2 +- src/rest.cpp | 2 +- src/rpc/net.cpp | 65 +- src/rpc/protocol.cpp | 2 +- src/rpc/server.cpp | 2 +- src/script/script.cpp | 2 +- src/script/standard.cpp | 2 +- src/serialize.h | 320 +++++++- src/span.h | 252 +++++++ src/stratum.cpp | 15 +- src/streams.h | 96 ++- src/sync.cpp | 2 +- src/test-hush/test_addrman.cpp | 2 +- src/test-hush/testutils.cpp | 2 +- src/test/base32_tests.cpp | 2 +- src/test/base58_tests.cpp | 2 +- src/test/base64_tests.cpp | 2 +- src/test/bip32_tests.cpp | 2 +- src/test/bloom_tests.cpp | 2 +- src/test/coins_tests.cpp | 2 +- src/test/convertbits_tests.cpp | 2 +- src/test/crypto_tests.cpp | 2 +- src/test/hash_tests.cpp | 2 +- src/test/key_tests.cpp | 2 +- src/test/netbase_tests.cpp | 11 - src/test/rpc_tests.cpp | 2 +- src/test/serialize_tests.cpp | 2 +- src/test/util_tests.cpp | 2 +- src/timedata.cpp | 2 +- src/torcontrol.cpp | 80 +- src/torcontrol.h | 5 +- src/uint256.cpp | 2 +- src/util.cpp | 2 +- src/util/readwritefile.cpp | 47 ++ src/util/readwritefile.h | 29 + src/util/sock.cpp | 328 +++++++++ src/util/sock.h | 184 +++++ src/util/spanparsing.cpp | 68 ++ src/util/spanparsing.h | 50 ++ src/util/strencodings.cpp | 655 +++++++++++++++++ src/util/strencodings.h | 302 ++++++++ src/util/string.cpp | 6 + src/util/string.h | 99 +++ src/utilmoneystr.cpp | 2 +- src/utilstrencodings.cpp | 2 +- src/utiltime.cpp | 28 + src/utiltime.h | 11 + src/wallet/db.cpp | 2 +- src/wallet/wallet.h | 2 +- src/zcash/Note.cpp | 1 + 108 files changed, 8214 insertions(+), 2173 deletions(-) create mode 100644 doc/i2p.md create mode 100644 src/addrdb.cpp create mode 100644 src/addrdb.h create mode 100644 src/attributes.h create mode 100644 src/crypto/sha3.cpp create mode 100644 src/crypto/sha3.h create mode 100644 src/i2p.cpp create mode 100644 src/i2p.h create mode 100644 src/netaddress.cpp create mode 100644 src/netaddress.h create mode 100644 src/netmessagemaker.h create mode 100644 src/span.h create mode 100644 src/util/readwritefile.cpp create mode 100644 src/util/readwritefile.h create mode 100644 src/util/sock.cpp create mode 100644 src/util/sock.h create mode 100644 src/util/spanparsing.cpp create mode 100644 src/util/spanparsing.h create mode 100644 src/util/strencodings.cpp create mode 100644 src/util/strencodings.h create mode 100644 src/util/string.cpp create mode 100644 src/util/string.h diff --git a/configure.ac b/configure.ac index 94f48dd31..b46abbbce 100644 --- a/configure.ac +++ b/configure.ac @@ -221,6 +221,29 @@ if test "x$CXXFLAGS_overridden" = "xno"; then AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) fi + +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $SSE42_CXXFLAGS" +AC_MSG_CHECKING(for assembler crc32 support) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #if defined(_MSC_VER) + #include + #elif defined(__GNUC__) && defined(__SSE4_2__) + #include + #endif + ]],[[ + uint64_t l = 0; + l = _mm_crc32_u8(l, 0); + l = _mm_crc32_u32(l, 0); + l = _mm_crc32_u64(l, 0); + return l; + ]])], + [ AC_MSG_RESULT(yes); enable_hwcrc32=yes], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], @@ -241,6 +264,16 @@ AC_ARG_WITH([daemon], [build_bitcoind=$withval], [build_bitcoind=yes]) +GCC_TARGET=`$CC -dumpmachine 2>&1` +case $GCC_TARGET in + arm*-*-*) + have_arm=true + ;; + aarch64*-*-*) + have_arm=true + ;; +esac + use_pkgconfig=yes case $host in *mingw*) @@ -815,6 +848,7 @@ AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_MINING],[test x$enable_mining = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) +AM_CONDITIONAL([ARCH_ARM], [test x$have_arm = xtrue]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index ab9b4c68c..f50114d01 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -1,5 +1,6 @@ -#!/usr/bin/env python -# Copyright (c) 2014 Wladimir J. van der Laan +#!/usr/bin/env python3 +# Copyright (c) 2016-2022 The Hush developers +# Copyright (c) 2014-2021 The Bitcoin Core developers # Distributed under the GPLv3 software license, see the accompanying # file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html ''' @@ -11,45 +12,63 @@ argument: nodes_main.txt nodes_test.txt -These files must consist of lines in the format +These files must consist of lines in the format - : - [] + []: + [] + .onion: .onion - 0xDDBBCCAA (IPv4 little-endian old pnSeeds format) + .b32.i2p: + .b32.i2p The output will be two data structures with the peers in binary format: - static SeedSpec6 pnSeed6_main[]={ - ... - } - static SeedSpec6 pnSeed6_test[]={ + static const uint8_t chainparams_seed_{main,test}[]={ ... } -These should be pasted into `src/chainparamsseeds.h`. +To update the generated code : + +./contrib/seeds/generate-seeds.py contrib/seeds > src/chainparamsseeds.h + ''' -from __future__ import print_function, division + from base64 import b32decode -from binascii import a2b_hex -import sys, os +from enum import Enum +import struct +import sys +import os import re -# ipv4 in ipv6 prefix -pchIPv4 = bytearray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff]) -# tor-specific ipv6 prefix -pchOnionCat = bytearray([0xFD,0x87,0xD8,0x7E,0xEB,0x43]) +class BIP155Network(Enum): + IPV4 = 1 + IPV6 = 2 + TORV2 = 3 # no longer supported + TORV3 = 4 + I2P = 5 + CJDNS = 6 -def name_to_ipv6(addr): - if len(addr)>6 and addr.endswith('.onion'): +def name_to_bip155(addr): + '''Convert address string to BIP155 (networkID, addr) tuple.''' + if addr.endswith('.onion'): vchAddr = b32decode(addr[0:-6], True) - if len(vchAddr) != 16-len(pchOnionCat): - raise ValueError('Invalid onion %s' % s) - return pchOnionCat + vchAddr + if len(vchAddr) == 35: + assert vchAddr[34] == 3 + return (BIP155Network.TORV3, vchAddr[:32]) + elif len(vchAddr) == 10: + return (BIP155Network.TORV2, vchAddr) + else: + raise ValueError('Invalid onion %s' % vchAddr) + elif addr.endswith('.b32.i2p'): + vchAddr = b32decode(addr[0:-8] + '====', True) + if len(vchAddr) == 32: + return (BIP155Network.I2P, vchAddr) + else: + raise ValueError(f'Invalid I2P {vchAddr}') elif '.' in addr: # IPv4 - return pchIPv4 + bytearray((int(x) for x in addr.split('.'))) + return (BIP155Network.IPV4, bytes((int(x) for x in addr.split('.')))) elif ':' in addr: # IPv6 sub = [[], []] # prefix, suffix x = 0 @@ -66,14 +85,13 @@ def name_to_ipv6(addr): sub[x].append(val & 0xff) nullbytes = 16 - len(sub[0]) - len(sub[1]) assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) - return bytearray(sub[0] + ([0] * nullbytes) + sub[1]) - elif addr.startswith('0x'): # IPv4-in-little-endian - return pchIPv4 + bytearray(reversed(a2b_hex(addr[2:]))) + return (BIP155Network.IPV6, bytes(sub[0] + ([0] * nullbytes) + sub[1])) else: raise ValueError('Could not parse address %s' % addr) -def parse_spec(s, defaultport): - match = re.match('\[([0-9a-fA-F:]+)\](?::([0-9]+))?$', s) +def parse_spec(s): + '''Convert endpoint string to BIP155 (networkID, addr, port) tuple.''' + match = re.match(r'\[([0-9a-fA-F:]+)\](?::([0-9]+))?$', s) if match: # ipv6 host = match.group(1) port = match.group(2) @@ -84,17 +102,42 @@ def parse_spec(s, defaultport): (host,_,port) = s.partition(':') if not port: - port = defaultport + port = 0 else: port = int(port) - host = name_to_ipv6(host) + host = name_to_bip155(host) - return (host,port) + if host[0] == BIP155Network.TORV2: + return None # TORV2 is no longer supported, so we ignore it + else: + return host + (port, ) -def process_nodes(g, f, structname, defaultport): - g.write('static SeedSpec6 %s[] = {\n' % structname) - first = True +def ser_compact_size(l): + r = b"" + if l < 253: + r = struct.pack("B", l) + elif l < 0x10000: + r = struct.pack("H', spec[2]) + return r + +def process_nodes(g, f, structname): + g.write('static const uint8_t %s[] = {\n' % structname) for line in f: comment = line.find('#') if comment != -1: @@ -102,37 +145,37 @@ def process_nodes(g, f, structname, defaultport): line = line.strip() if not line: continue - if not first: - g.write(',\n') - first = False - (host,port) = parse_spec(line, defaultport) - hoststr = ','.join(('0x%02x' % b) for b in host) - g.write(' {{%s}, %i}' % (hoststr, port)) - g.write('\n};\n') + spec = parse_spec(line) + if spec is None: # ignore this entry (e.g. no longer supported addresses like TORV2) + continue + blob = bip155_serialize(spec) + hoststr = ','.join(('0x%02x' % b) for b in blob) + g.write(f' {hoststr}, // {line}\n') + g.write('};\n') def main(): if len(sys.argv)<2: print(('Usage: %s ' % sys.argv[0]), file=sys.stderr) - exit(1) + sys.exit(1) g = sys.stdout indir = sys.argv[1] - g.write('#ifndef BITCOIN_CHAINPARAMSSEEDS_H\n') - g.write('#define BITCOIN_CHAINPARAMSSEEDS_H\n') - g.write('/**\n') - g.write(' * List of fixed seed nodes for the bitcoin network\n') - g.write(' * AUTOGENERATED by contrib/seeds/generate-seeds.py\n') - g.write(' *\n') - g.write(' * Each line contains a 16-byte IPv6 address and a port.\n') - g.write(' * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.\n') - g.write(' */\n') - with open(os.path.join(indir,'nodes_main.txt'),'r') as f: - process_nodes(g, f, 'pnSeed6_main', 8233) + g.write('// Copyright (c) 2016-2022 The Hush developers\n') + g.write('// Distributed under the GPLv3 software license, see the accompanying\n') + g.write('// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html\n') + g.write('// THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY\n') + g.write('// Instead, run: ./contrib/seeds/generate-seeds.py contrib/seeds\n') + g.write('#ifndef HUSH_CHAINPARAMSSEEDS_H\n') + g.write('#define HUSH_CHAINPARAMSSEEDS_H\n') + g.write('// List of fixed seed nodes for the Hush network\n') + g.write('// Each line contains a BIP155 serialized address.\n') + g.write('//\n') + with open(os.path.join(indir,'nodes_main.txt'), 'r', encoding="utf8") as f: + process_nodes(g, f, 'chainparams_seed_main') g.write('\n') - with open(os.path.join(indir,'nodes_test.txt'),'r') as f: - process_nodes(g, f, 'pnSeed6_test', 18233) - g.write('#endif // BITCOIN_CHAINPARAMSSEEDS_H\n') - + with open(os.path.join(indir,'nodes_test.txt'), 'r', encoding="utf8") as f: + process_nodes(g, f, 'chainparams_seed_test') + g.write('#endif // HUSH_CHAINPARAMSSEEDS_H\n') + if __name__ == '__main__': main() - diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index a6e8be207..e9e68c259 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -1,6 +1,11 @@ -185.25.48.236:27485 -185.25.48.236:27487 -185.64.105.111:27485 -185.64.105.111:27487 -185.25.48.72:27485 -185.25.48.72:27487 +# node1.hush.land +185.241.61.43 + +# node2.hush.is +137.74.4.198 + +# lite.hushpool.is +149.28.102.219 + +# todo: torv3 +# todo: i2p diff --git a/contrib/seeds/nodes_test.txt b/contrib/seeds/nodes_test.txt index 98365ee50..be9218b99 100644 --- a/contrib/seeds/nodes_test.txt +++ b/contrib/seeds/nodes_test.txt @@ -1,11 +1,5 @@ # List of fixed seed nodes for testnet +# note: File must be non-empty to compile +1.2.3.4 # Onion nodes -thfsmmn2jbitcoin.onion -it2pj4f7657g3rhi.onion -nkf5e6b7pl4jfd4a.onion -4zhkir2ofl7orfom.onion -t6xj6wilh4ytvcs7.onion -i6y6ivorwakd7nw3.onion -ubqj4rsu3nqtxmtp.onion - diff --git a/doc/i2p.md b/doc/i2p.md new file mode 100644 index 000000000..e01573f9d --- /dev/null +++ b/doc/i2p.md @@ -0,0 +1,161 @@ +# I2P support in Hush + +It is possible to run a Hush or HSC full node as an +[I2P (Invisible Internet Project)](https://en.wikipedia.org/wiki/I2P) +service and connect to such services. + +This [glossary](https://geti2p.net/en/about/glossary) may be useful to get +started with I2P terminology. + +## Run with an I2P router (proxy) + +A running I2P router (proxy) with [SAM](https://geti2p.net/en/docs/api/samv3) +enabled is required. Options include: + +- [i2prouter (I2P Router)](https://geti2p.net), the official implementation in + Java +- [i2pd (I2P Daemon)](https://github.com/PurpleI2P/i2pd) + ([documentation](https://i2pd.readthedocs.io/en/latest)), a lighter + alternative in C++ (successfully tested with version 2.23 and up; version 2.36 + or later recommended) +- [i2p-zero](https://github.com/i2p-zero/i2p-zero) +- [other alternatives](https://en.wikipedia.org/wiki/I2P#Routers) + +Note the IP address and port the SAM proxy is listening to; usually, it is +`127.0.0.1:7656`. + +Once an I2P router with SAM enabled is up and running, use the following +configuration options: + +``` +-i2psam= + I2P SAM proxy to reach I2P peers and accept I2P connections (default: + none) + +-i2pacceptincoming + If set and -i2psam is also set then incoming I2P connections are + accepted via the SAM proxy. If this is not set but -i2psam is set + then only outgoing connections will be made to the I2P network. + Ignored if -i2psam is not set. Listening for incoming I2P + connections is done through the SAM proxy, not by binding to a + local address and port (default: 1) +``` + +In a typical situation, this suffices: + +``` +hushd -i2psam=127.0.0.1:7656 +``` + +The first time hushd connects to the I2P router, if +`-i2pacceptincoming=1`, then it will automatically generate a persistent I2P +address and its corresponding private key. The private key will be saved in a +file named `i2p_private_key` in the Hush data directory. The persistent +I2P address is used for accepting incoming connections and for making outgoing +connections if `-i2pacceptincoming=1`. If `-i2pacceptincoming=0` then only +outbound I2P connections are made and a different transient I2P address is used +for each connection to improve privacy. + +## Persistent vs transient I2P addresses + +In I2P connections, the connection receiver sees the I2P address of the +connection initiator. This is unlike the Tor network where the recipient does +not know who is connecting to them and can't tell if two connections are from +the same peer or not. + +If an I2P node is not accepting incoming connections, then Hush uses +random, one-time, transient I2P addresses for itself for outbound connections +to make it harder to discriminate, fingerprint or analyze it based on its I2P +address. + +## Additional configuration options related to I2P + +``` +-debug=i2p +``` + +Set the `debug=i2p` config logging option to see additional information in the +debug log about your I2P configuration and connections. Run `hush-cli help +logging` for more information. + +``` +-onlynet=i2p +``` + +Make automatic outbound connections only to I2P addresses. Inbound and manual +connections are not affected by this option. It can be specified multiple times +to allow multiple networks, e.g. onlynet=onion, onlynet=i2p. + +I2P support was added to Hush in version 3.9.3 and there may be fewer I2P +peers than Tor or IP ones. Therefore, using I2P alone without other networks may +make a node more susceptible to [Sybil +attacks](https://en.bitcoin.it/wiki/Weaknesses#Sybil_attack). You can use +`hush-cli -addrinfo` to see the number of I2P addresses known to your node. + +Another consideration with `onlynet=i2p` is that the initial blocks download +phase when syncing up a new node can be very slow. This phase can be sped up by +using other networks, for instance `onlynet=onion`, at the same time. + +In general, a node can be run with both onion and I2P hidden services (or +any/all of IPv4/IPv6/onion/I2P/CJDNS), which can provide a potential fallback if +one of the networks has issues. + +## I2P-related information + +There are several ways to see your I2P address if accepting +incoming I2P connections (`-i2pacceptincoming`): +- in the "Local addresses" output of CLI `-netinfo` +- in the "localaddresses" output of RPC `getnetworkinfo` +- in the debug log (grep for `AddLocal`; the I2P address ends in `.b32.i2p`) + +To see which I2P peers your node is connected to, use `hush-cli -netinfo 4` +or the `getpeerinfo` RPC (e.g. `hush-cli getpeerinfo`). + +To see which I2P addresses your node knows, use the `getnodeaddresses 0 i2p` +RPC. + +## Compatibility + +Hush uses the [SAM v3.1](https://geti2p.net/en/docs/api/samv3) protocol +to connect to the I2P network. Any I2P router that supports it can be used. + +## Ports in I2P and Hush + +Hush uses the [SAM v3.1](https://geti2p.net/en/docs/api/samv3) +protocol. One particularity of SAM v3.1 is that it does not support ports, +unlike newer versions of SAM (v3.2 and up) that do support them and default the +port numbers to 0. From the point of view of peers that use newer versions of +SAM or other protocols that support ports, a SAM v3.1 peer is connecting to them +on port 0, from source port 0. + +To allow future upgrades to newer versions of SAM, Hush sets its +listening port to 0 when listening for incoming I2P connections and advertises +its own I2P address with port 0. Furthermore, it will not attempt to connect to +I2P addresses with a non-zero port number because with SAM v3.1 the destination +port (`TO_PORT`) is always set to 0 and is not in the control of Hush. + +## Bandwidth + +I2P routers may route a large amount of general network traffic with their +default settings. Check your router's configuration to limit the amount of this +traffic relayed, if desired. + +With `i2pd`, the amount of bandwidth being shared with the wider network can be +adjusted with the `bandwidth`, `share` and `transittunnels` options in your +`i2pd.conf` file. For example, to limit total I2P traffic to 256KB/s and share +50% of this limit for a maximum of 20 transit tunnels: + +``` +bandwidth = 256 +share = 50 + +[limits] +transittunnels = 20 +``` + +If you prefer not to relay any public I2P traffic and only permit I2P traffic +from programs which are connecting via the SAM proxy, e.g. Hush, you +can set the `notransit` option to `true`. + +Similar bandwidth configuration options for the Java I2P router can be found in +`http://127.0.0.1:7657/config` under the "Bandwidth" tab. diff --git a/doc/tor.md b/doc/tor.md index c00db2fbd..fe0608888 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -1,154 +1,225 @@ -# Warning +# Tor - Do not assume Tor support works perfectly in Hush; better Tor support is currently being worked on. - -# Hush + Tor - -It is possible to run Hush as a Tor hidden service, and connect to such services. +It is possible to run Hush as a Tor onion service, and connect to such services. The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on port 9150. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) for how to properly configure Tor. +## Compatibility -1. Run Hush behind a Tor proxy -------------------------------- +- Starting with version 3.9.3, Hush only supports Tor version 3 hidden + services (Tor v3). Tor v2 addresses are ignored by Hush and neither + relayed nor stored. -The first step is running Hush behind a Tor proxy. This will already make all -outgoing connections be anonymized, but more is possible. +- Tor removed v2 support beginning with version 0.4.6. - -proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy - server will be used to try to reach .onion addresses as well. +## How to see information about your Tor configuration via Hush - -onion=ip:port Set the proxy server to use for Tor hidden services. You do not - need to set this if it's the same as -proxy. You can use -noonion - to explicitly disable access to hidden service. +There are several ways to see your local onion address in Hush: +- in the "Local addresses" output of CLI `-netinfo` +- in the "localaddresses" output of RPC `getnetworkinfo` +- in the debug log (grep for "AddLocal"; the Tor address ends in `.onion`) - -listen When using -proxy, listening is disabled by default. If you want - to run a hidden service (see next section), you'll need to enable - it explicitly. +You may set the `-debug=tor` config logging option to have additional +information in the debug log about your Tor configuration. - -connect=X When behind a Tor proxy, you can specify .onion addresses instead - -addnode=X of IP addresses or hostnames in these parameters. It requires - -seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with - other P2P nodes. +CLI `-addrinfo` returns the number of addresses known to your node per +network. This can be useful to see how many onion peers your node knows, +e.g. for `-onlynet=onion`. + +To fetch a number of onion addresses that your node knows, for example seven +addresses, use the `getnodeaddresses 7 onion` RPC. + +## 1. Run Hush behind a Tor proxy + +The first step is running Hush behind a Tor proxy. This will already anonymize all +outgoing connections, but more is possible. + + -proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy + server will be used to try to reach .onion addresses as well. + You need to use -noonion or -onion=0 to explicitly disable + outbound access to onion services. + + -onion=ip:port Set the proxy server to use for Tor onion services. You do not + need to set this if it's the same as -proxy. You can use -onion=0 + to explicitly disable access to onion services. + ------------------------------------------------------------------ + Note: Only the -proxy option sets the proxy for DNS requests; + with -onion they will not route over Tor, so use -proxy if you + have privacy concerns. + ------------------------------------------------------------------ + + -listen When using -proxy, listening is disabled by default. If you want + to manually configure an onion service (see section 3), you'll + need to enable it explicitly. + + -connect=X When behind a Tor proxy, you can specify .onion addresses instead + -addnode=X of IP addresses or hostnames in these parameters. It requires + -seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with + other P2P nodes. + + -onlynet=onion Make automatic outbound connections only to .onion addresses. + Inbound and manual connections are not affected by this option. + It can be specified multiple times to allow multiple networks, + e.g. onlynet=onion, onlynet=i2p, onlynet=cjdns. In a typical situation, this suffices to run behind a Tor proxy: - ./hushd -proxy=127.0.0.1:9050 + ./hushd -proxy=127.0.0.1:9050 -If using the Tor Browser Bundle: +## 2. Automatically create a Hush onion service - ./hushd -proxy=127.0.0.1:9150 +Hush makes use of Tor's control socket API to create and destroy +ephemeral onion services programmatically. This means that if Tor is running and +proper authentication has been configured, Hush automatically creates an +onion service to listen on. The goal is to increase the number of available +onion nodes. + +This feature is enabled by default if Hush is listening (`-listen`) and +it requires a Tor connection to work. It can be explicitly disabled with +`-listenonion=0`. If it is not disabled, it can be configured using the +`-torcontrol` and `-torpassword` settings. + +To see verbose Tor information in the hushd debug log, pass `-debug=tor`. + +### Control Port + +You may need to set up the Tor Control Port. On Linux distributions there may be +some or all of the following settings in `/etc/tor/torrc`, generally commented +out by default (if not, add them): + +``` +ControlPort 9051 +CookieAuthentication 1 +CookieAuthFileGroupReadable 1 +``` + +Add or uncomment those, save, and restart Tor (usually `systemctl restart tor` +or `sudo systemctl restart tor` on most systemd-based systems, including recent +Debian and Ubuntu, or just restart the computer). + +On some systems (such as Arch Linux), you may also need to add the following +line: + +``` +DataDirectoryGroupReadable 1 +``` + +### Authentication + +Connecting to Tor's control socket API requires one of two authentication +methods to be configured: cookie authentication or hushd's `-torpassword` +configuration option. + +#### Cookie authentication + +For cookie authentication, the user running hushd must have read access to +the `CookieAuthFile` specified in the Tor configuration. In some cases this is +preconfigured and the creation of an onion service is automatic. Don't forget to +use the `-debug=tor` hushd configuration option to enable Tor debug logging. + +If a permissions problem is seen in the debug log, e.g. `tor: Authentication +cookie /run/tor/control.authcookie could not be opened (check permissions)`, it +can be resolved by adding both the user running Tor and the user running +hushd to the same Tor group and setting permissions appropriately. + +On Debian-derived systems, the Tor group will likely be `debian-tor` and one way +to verify could be to list the groups and grep for a "tor" group name: + +``` +getent group | cut -d: -f1 | grep -i tor +``` + +You can also check the group of the cookie file. On most Linux systems, the Tor +auth cookie will usually be `/run/tor/control.authcookie`: + +``` +TORGROUP=$(stat -c '%G' /run/tor/control.authcookie) +``` + +Once you have determined the `${TORGROUP}` and selected the `${USER}` that will +run hushd, run this as root: + +``` +usermod -a -G ${TORGROUP} ${USER} +``` + +Then restart the computer (or log out) and log in as the `${USER}` that will run +hushd. + +#### `torpassword` authentication + +For the `-torpassword=password` option, the password is the clear text form that +was used when generating the hashed password for the `HashedControlPassword` +option in the Tor configuration file. + +The hashed password can be obtained with the command `tor --hash-password +password` (refer to the [Tor Dev +Manual](https://2019.www.torproject.org/docs/tor-manual.html.en) for more +details). +## 3. Manually create a Hush onion service -2. Run a Hush hidden server ----------------------------- +You can also manually configure your node to be reachable from the Tor network. +Add these lines to your `/etc/tor/torrc` (or equivalent config file): -If you configure your Tor system accordingly, it is possible to make your node also -reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent -config file): + HiddenServiceDir /var/lib/tor/hush-service/ + HiddenServicePort 18030 127.0.0.1:18032 - HiddenServiceDir /var/lib/tor/hush-service/ - HiddenServicePort 18030 127.0.0.1:18030 +The directory can be different of course, but virtual port numbers should be equal to +your hushd's P2P listen port (18030 by default), and target addresses and ports +should be equal to binding address and port for inbound Tor connections (127.0.0.1:18032 by default). -The directory can be different of course, but (both) port numbers should be equal to -your hushd's P2P listen port (18030 by default). + -externalip=X You can tell hush about its publicly reachable addresses using + this option, and this can be an onion address. Given the above + configuration, you can find your onion address in + /var/lib/tor/hush-service/hostname. For connections + coming from unroutable addresses (such as 127.0.0.1, where the + Tor proxy typically runs), onion addresses are given + preference for your node to advertise itself with. - -externalip=X You can tell Hush about its publicly reachable address using - this option, and this can be a .onion address. Given the above - configuration, you can find your onion address in - /var/lib/tor/hush-service/hostname. Onion addresses are given - preference for your node to advertize itself with, for connections - coming from unroutable addresses (such as 127.0.0.1, where the - Tor proxy typically runs). + You can set multiple local addresses with -externalip. The + one that will be rumoured to a particular peer is the most + compatible one and also using heuristics, e.g. the address + with the most incoming connections, etc. - -listen You'll need to enable listening for incoming connections, as this - is off by default behind a proxy. + -listen You'll need to enable listening for incoming connections, as this + is off by default behind a proxy. - -discover When -externalip is specified, no attempt is made to discover local - IPv4 or IPv6 addresses. If you want to run a dual stack, reachable - from both Tor and IPv4 (or IPv6), you'll need to either pass your - other addresses using -externalip, or explicitly enable -discover. - Note that both addresses of a dual-stack system may be easily - linkable using traffic analysis. + -discover When -externalip is specified, no attempt is made to discover local + IPv4 or IPv6 addresses. If you want to run a dual stack, reachable + from both Tor and IPv4 (or IPv6), you'll need to either pass your + other addresses using -externalip, or explicitly enable -discover. + Note that both addresses of a dual-stack system may be easily + linkable using traffic analysis. In a typical situation, where you're only reachable via Tor, this should suffice: - ./hushd -proxy=127.0.0.1:9050 -externalip=hushc0de123.onion -listen + ./hushd -proxy=127.0.0.1:9050 -externalip=7zvj7a2imdgkdbg4f2dryd5rgtrn7upivr5eeij4cicjh65pooxeshid.onion -listen -(obviously, replace the Onion address with your own). Currently only v2 HS's are supported. -It should be noted that you still listen on all devices and another node could establish a clearnet connection, when knowing +(obviously, replace the .onion address with your own). It should be noted that you still +listen on all devices and another node could establish a clearnet connection, when knowing your address. To mitigate this, additionally bind the address of your Tor proxy: - ./hushd ... -bind=127.0.0.1 + ./hushd ... -bind=127.0.0.1 If you don't care too much about hiding your node, and want to be reachable on IPv4 as well, use `discover` instead: - ./hushd ... -discover + ./hushd ... -discover -and open port 18030 on your firewall. +and open port 18030 on your firewall (or use port mapping, i.e., `-upnp` or `-natpmp`). -If you only want to use Tor to reach onion addresses, but not use it as a proxy +If you only want to use Tor to reach .onion addresses, but not use it as a proxy for normal IPv4/IPv6 communication, use: - ./hushd -onion=127.0.0.1:9050 -externalip=hushc0de123.onion -discover + ./hushd -onion=127.0.0.1:9050 -externalip=7zvj7a2imdgkdbg4f2dryd5rgtrn7upivr5eeij4cicjh65pooxeshid.onion -discover +## 4. Privacy recommendations -3. Automatically listen on Tor --------------------------------- - -Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket -API, to create and destroy 'ephemeral' hidden services programmatically. -Hush has been updated to make use of this. - -This means that if Tor is running (and proper authentication has been configured), -Hush automatically creates a hidden service to listen on. Hush will also use Tor -automatically to connect to other .onion nodes if the control socket can be -successfully opened. This will positively affect the number of available .onion -nodes and their usage. - -This new feature is enabled by default if Hush is listening (`-listen`), and -requires a Tor connection to work. It can be explicitly disabled with `-listenonion=0` -and, if not disabled, configured using the `-torcontrol` and `-torpassword` settings. -To show verbose debugging information, pass `-debug=tor`. - -Connecting to Tor's control socket API requires one of two authentication methods to be -configured. For cookie authentication the user running hushd must have write access -to the `CookieAuthFile` specified in Tor configuration. In some cases this is -preconfigured and the creation of a hidden service is automatic. If permission problems -are seen with `-debug=tor` they can be resolved by adding both the user running tor and -the user running hushd to the same group and setting permissions appropriately. On -Debian-based systems the user running hushd can be added to the debian-tor group, -which has the appropriate permissions. An alternative authentication method is the use -of the `-torpassword` flag and a `hash-password` which can be enabled and specified in -Tor configuration. - - -4. Connect to a Hush hidden server ------------------------------------ - -To test your set-up, you might want to try connecting via Tor on a different computer to just a -a single Hush hidden server. Launch hushd as follows: - - ./hushd -onion=127.0.0.1:9050 -connect=fuckzookoie6wxgio.onion - -Now use hush-cli to verify there is only a single peer connection. - - hush-cli getpeerinfo - - [ - { - "id" : 1, - "addr" : "zcashhoneypot.onion:18030", - ... - "version" : 1987420, - "subver" : "/GoldenSandtrout:3.6.0/", - ... - } - ] - -To connect to multiple Tor nodes, use: - - ./hushd -onion=127.0.0.1:9050 -addnode=hushbeef123.onion -dnsseed=0 -onlynet=onion +- Do not add anything but Hush ports to the onion service created in section 3. + If you run a web service too, create a new onion service for that. + Otherwise it is trivial to link them, which may reduce privacy. Onion + services created automatically (as in section 2) always have only one port + open. diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py index ff5544a2c..ec5393fe1 100755 --- a/qa/rpc-tests/httpbasics.py +++ b/qa/rpc-tests/httpbasics.py @@ -4,9 +4,7 @@ # Distributed under the GPLv3 software license, see the accompanying # file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -# # Test rpc http basics -# from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, start_nodes @@ -97,7 +95,7 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, True) # connection must be closed because bitcoind should use keep-alive by default + assert_equal(conn.sock!=None, True) # connection must be closed because hushd should use keep-alive by default if __name__ == '__main__': HTTPBasicsTest().main() diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py index 4dccdfae5..af28eecfc 100755 --- a/qa/rpc-tests/p2p-acceptblock.py +++ b/qa/rpc-tests/p2p-acceptblock.py @@ -116,8 +116,8 @@ class TestNode(NodeConnCB): class AcceptBlockTest(BitcoinTestFramework): def add_options(self, parser): parser.add_option("--testbinary", dest="testbinary", - default=os.getenv("BITCOIND", "bitcoind"), - help="bitcoind binary to test") + default=os.getenv("BITCOIND", "hushd"), + help="hushd binary to test") def setup_chain(self): initialize_chain_clean(self.options.tmpdir, 2) diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py index 1a200db56..eb69e6bae 100755 --- a/qa/rpc-tests/proxy_test.py +++ b/qa/rpc-tests/proxy_test.py @@ -13,10 +13,10 @@ import os ''' Test plan: -- Start bitcoind's with different proxy configurations +- Start hushd's with different proxy configurations - Use addnode to initiate connections - Verify that proxies are connected to, and the right connection command is given -- Proxy configurations to test on bitcoind side: +- Proxy configurations to test on hushd side: - `-proxy` (proxy everything) - `-onion` (proxy just onions) - `-proxyrandomize` Circuit randomization @@ -26,8 +26,8 @@ Test plan: - proxy on IPv6 - Create various proxies (as threads) -- Create bitcoinds that connect to them -- Manipulate the bitcoinds using addnode (onetry) an observe effects +- Create hushds that connect to them +- Manipulate the hushds using addnode (onetry) an observe effects addnode connect to IPv4 addnode connect to IPv6 @@ -78,7 +78,7 @@ class ProxyTest(BitcoinTestFramework): node.addnode("15.61.23.23:1234", "onetry") cmd = proxies[0].queue.get() assert(isinstance(cmd, Socks5Command)) - # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 + # Note: hushd's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 assert_equal(cmd.atyp, AddressType.DOMAINNAME) assert_equal(cmd.addr, "15.61.23.23") assert_equal(cmd.port, 1234) @@ -91,7 +91,7 @@ class ProxyTest(BitcoinTestFramework): node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry") cmd = proxies[1].queue.get() assert(isinstance(cmd, Socks5Command)) - # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 + # Note: hushd's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 assert_equal(cmd.atyp, AddressType.DOMAINNAME) assert_equal(cmd.addr, "1233:3432:2434:2343:3234:2345:6546:4534") assert_equal(cmd.port, 5443) @@ -102,24 +102,24 @@ class ProxyTest(BitcoinTestFramework): if test_onion: # Test: outgoing onion connection through node - node.addnode("bitcoinostk4e4re.onion:8333", "onetry") + node.addnode("hushostk4e4re.onion:18030", "onetry") cmd = proxies[2].queue.get() assert(isinstance(cmd, Socks5Command)) assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, "bitcoinostk4e4re.onion") - assert_equal(cmd.port, 8333) + assert_equal(cmd.addr, "hushostk4e4re.onion") + assert_equal(cmd.port, 18030) if not auth: assert_equal(cmd.username, None) assert_equal(cmd.password, None) rv.append(cmd) # Test: outgoing DNS name connection through node - node.addnode("node.noumenon:8333", "onetry") + node.addnode("node.noumenon:18030", "onetry") cmd = proxies[3].queue.get() assert(isinstance(cmd, Socks5Command)) assert_equal(cmd.atyp, AddressType.DOMAINNAME) assert_equal(cmd.addr, "node.noumenon") - assert_equal(cmd.port, 8333) + assert_equal(cmd.port, 18030) if not auth: assert_equal(cmd.username, None) assert_equal(cmd.password, None) diff --git a/src/Makefile.am b/src/Makefile.am index 684e1a611..70f148385 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,12 @@ AM_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = +if ARCH_ARM +PLATFORM_VARIANT = armv8.1-a+crypto +else +PLATFORM_VARIANT = x86-64 +endif + if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv @@ -28,6 +34,7 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include +BITCOIN_INCLUDES += -I$(srcdir)/cc/includes BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/include BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src/asn @@ -63,13 +70,13 @@ LIBBITCOIN_WALLET=libbitcoin_wallet.a endif $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -g " + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=$(PLATFORM_VARIANT) -g " $(LIBUNIVALUE): $(wildcard univalue/lib/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -g " + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=$(PLATFORM_VARIANT) -g " $(LIBCRYPTOCONDITIONS): $(wildcard cryptoconditions/src/*) $(wildcard cryptoconditions/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -g " + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=$(PLATFORM_VARIANT) -g " # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: @@ -122,6 +129,8 @@ BITCOIN_CORE_H = \ addressindex.h \ spentindex.h \ addrman.h \ + attributes.h \ + addrdb.h \ amount.h \ amqp/amqpabstractnotifier.h \ amqp/amqpconfig.h \ @@ -160,6 +169,7 @@ BITCOIN_CORE_H = \ hash.h \ httprpc.h \ httpserver.h \ + i2p.h \ init.h \ key.h \ key_io.h \ @@ -174,10 +184,13 @@ BITCOIN_CORE_H = \ mruset.h \ net.h \ netbase.h \ + netaddress.h \ + netmessagemaker.h \ noui.h \ policy/fees.h \ pow.h \ prevector.h \ + span.h \ primitives/block.h \ primitives/transaction.h \ protocol.h \ @@ -217,8 +230,13 @@ BITCOIN_CORE_H = \ uint252.h \ undo.h \ util.h \ + util/readwritefile.h \ + util/sock.h \ + util/string.h \ + util/spanparsing.h \ + util/strencodings.h \ utilmoneystr.h \ - utilstrencodings.h \ + # utilstrencodings.h \ utiltime.h \ validationinterface.h \ version.h \ @@ -249,6 +267,7 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ + addrdb.cpp \ asyncrpcoperation.cpp \ asyncrpcqueue.cpp \ bloom.cpp \ @@ -283,6 +302,7 @@ libbitcoin_server_a_SOURCES = \ deprecation.cpp \ httprpc.cpp \ httpserver.cpp \ + i2p.cpp \ init.cpp \ dbwrapper.cpp \ main.cpp \ @@ -357,6 +377,8 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/ripemd160.h \ crypto/sha1.cpp \ crypto/sha1.h \ + crypto/sha3.cpp \ + crypto/sha3.h \ crypto/sha256.cpp \ crypto/sha256.h \ crypto/sha512.cpp \ @@ -397,6 +419,7 @@ libbitcoin_common_a_SOURCES = \ key.cpp \ key_io.cpp \ keystore.cpp \ + netaddress.cpp \ netbase.cpp \ metrics.cpp \ primitives/block.cpp \ @@ -435,9 +458,13 @@ libbitcoin_util_a_SOURCES = \ uint256.cpp \ util.cpp \ utilmoneystr.cpp \ - utilstrencodings.cpp \ utiltime.cpp \ + util/strencodings.cpp \ util/asmap.cpp \ + util/sock.cpp \ + util/spanparsing.cpp \ + util/string.cpp \ + util/readwritefile.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) @@ -667,6 +694,8 @@ clean-local: -$(MAKE) -C univalue clean rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno -rm -f config.h + -rm -f *.a + -rm -f *.so .rc.o: @test -f $(WINDRES) diff --git a/src/addrdb.cpp b/src/addrdb.cpp new file mode 100644 index 000000000..e07e5cca1 --- /dev/null +++ b/src/addrdb.cpp @@ -0,0 +1,122 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Hush developers +// Distributed under the GPLv3 software license, see the accompanying +// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html + +#include "addrdb.h" +#include "addrman.h" +#include "chainparams.h" +#include "clientversion.h" +#include "fs.h" +#include "hash.h" +#include "random.h" +#include "streams.h" +#include "tinyformat.h" +#include "util.h" + +namespace { + +template +bool SerializeDB(Stream& stream, const Data& data) +{ + // Write and commit header, data + try { + CHashWriter hasher(stream.GetType(), stream.GetVersion()); + stream << FLATDATA(Params().MessageStart()) << data; + hasher << FLATDATA(Params().MessageStart()) << data; + stream << hasher.GetHash(); + } catch (const std::exception& e) { + return error("%s: Serialize or I/O error - %s", __func__, e.what()); + } + + return true; +} + +template +bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data) +{ + // Generate random temporary filename + unsigned short randv = 0; + GetRandBytes((unsigned char*)&randv, sizeof(randv)); + std::string tmpfn = strprintf("%s.%04x", prefix, randv); + + // open temp output file, and associate with CAutoFile + fs::path pathTmp = GetDataDir() / tmpfn; + FILE *file = fsbridge::fopen(pathTmp, "wb"); + CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: Failed to open file %s", __func__, pathTmp.string()); + + // Serialize + if (!SerializeDB(fileout, data)) return false; + FileCommit(fileout.Get()); + fileout.fclose(); + + // replace existing file, if any, with new file + if (!RenameOver(pathTmp, path)) + return error("%s: Rename-into-place failed", __func__); + + return true; +} + +template +bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true) +{ + try { + CHashVerifier verifier(&stream); + // de-serialize file header (network specific magic number) and .. + unsigned char pchMsgTmp[4]; + verifier >> 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 + verifier >> data; + + // verify checksum + if (fCheckSum) { + uint256 hashTmp; + stream >> hashTmp; + if (hashTmp != verifier.GetHash()) { + return error("%s: Checksum mismatch, data corrupted", __func__); + } + } + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + + return true; +} + +template +bool DeserializeFileDB(const fs::path& path, Data& data) +{ + // open input file, and associate with CAutoFile + FILE *file = fsbridge::fopen(path, "rb"); + CAutoFile filein(file, SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: Failed to open file %s", __func__, path.string()); + + return DeserializeDB(filein, data); +} + +} + +CBanDB::CBanDB() +{ + pathBanlist = GetDataDir() / "banlist.dat"; +} + +bool CBanDB::Write(const banmap_t& banSet) +{ + return SerializeFileDB("banlist", pathBanlist, banSet); +} + +bool CBanDB::Read(banmap_t& banSet) +{ + return DeserializeFileDB(pathBanlist, banSet); +} + diff --git a/src/addrdb.h b/src/addrdb.h new file mode 100644 index 000000000..a5cf7dc97 --- /dev/null +++ b/src/addrdb.h @@ -0,0 +1,90 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2016 The Bitcoin Core developers +// Distributed under the GPLv3 software license, see the accompanying +// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html + +#ifndef HUSH_ADDRDB_H +#define HUSH_ADDRDB_H + +#include "fs.h" +#include "serialize.h" + +#include +#include + +class CSubNet; +class CAddrMan; +class CDataStream; + +typedef enum BanReason +{ + BanReasonUnknown = 0, + BanReasonNodeMisbehaving = 1, + BanReasonManuallyAdded = 2 +} BanReason; + +class CBanEntry +{ +public: + static const int CURRENT_VERSION=1; + int nVersion; + int64_t nCreateTime; + int64_t nBanUntil; + uint8_t banReason; + + CBanEntry() + { + SetNull(); + } + + explicit CBanEntry(int64_t nCreateTimeIn) + { + SetNull(); + nCreateTime = nCreateTimeIn; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(nCreateTime); + READWRITE(nBanUntil); + READWRITE(banReason); + } + + void SetNull() + { + nVersion = CBanEntry::CURRENT_VERSION; + nCreateTime = 0; + nBanUntil = 0; + banReason = BanReasonUnknown; + } + + std::string banReasonToString() const + { + switch (banReason) { + case BanReasonNodeMisbehaving: + return "node misbehaving"; + case BanReasonManuallyAdded: + return "manually added"; + default: + return "unknown"; + } + } +}; + +typedef std::map banmap_t; + +/** Access to the banlist database (banlist.dat) */ +class CBanDB +{ +private: + fs::path pathBanlist; +public: + CBanDB(); + bool Write(const banmap_t& banSet); + bool Read(banmap_t& banSet); +}; + +#endif // HUSH_ADDRDB_H diff --git a/src/addrman.cpp b/src/addrman.cpp index d9b8a07cb..1148d5d7a 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -23,6 +23,7 @@ #include "hash.h" #include "serialize.h" #include "streams.h" +#include "init.h" int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector &asmap) const { @@ -53,6 +54,9 @@ int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) co bool CAddrInfo::IsTerrible(int64_t nNow) const { + if (fLocal) //never remove local addresses + return false; + if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute return false; @@ -71,6 +75,14 @@ bool CAddrInfo::IsTerrible(int64_t nNow) const return false; } +bool CAddrInfo::IsJustTried(int64_t nNow) const +{ + if (nLastTry && nLastTry >= nNow - 60) + return true; + + return false; +} + double CAddrInfo::GetChance(int64_t nNow) const { double fChance = 1.0; @@ -95,24 +107,30 @@ double CAddrInfo::GetChance(int64_t nNow) const CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId) { - std::map::iterator it = mapAddr.find(addr); + AssertLockHeld(cs); + + const auto it = mapAddr.find(addr); if (it == mapAddr.end()) - return NULL; + return nullptr; if (pnId) *pnId = (*it).second; - std::map::iterator it2 = mapInfo.find((*it).second); + const auto it2 = mapInfo.find((*it).second); if (it2 != mapInfo.end()) return &(*it2).second; - return NULL; + return nullptr; } CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) { - int nId = nIdCount++; + AssertLockHeld(cs); + + int nId = nIdCount; mapInfo[nId] = CAddrInfo(addr, addrSource); mapAddr[addr] = nId; mapInfo[nId].nRandomPos = vRandom.size(); vRandom.push_back(nId); + nNew++; + nIdCount++; if (pnId) *pnId = nId; return &mapInfo[nId]; @@ -120,6 +138,8 @@ CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, in void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) { + AssertLockHeld(cs); + if (nRndPos1 == nRndPos2) return; @@ -128,11 +148,13 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) int nId1 = vRandom[nRndPos1]; int nId2 = vRandom[nRndPos2]; - assert(mapInfo.count(nId1) == 1); - assert(mapInfo.count(nId2) == 1); + const auto it_1{mapInfo.find(nId1)}; + const auto it_2{mapInfo.find(nId2)}; + assert(it_1 != mapInfo.end()); + assert(it_2 != mapInfo.end()); - mapInfo[nId1].nRandomPos = nRndPos2; - mapInfo[nId2].nRandomPos = nRndPos1; + it_1->second.nRandomPos = nRndPos2; + it_2->second.nRandomPos = nRndPos1; vRandom[nRndPos1] = nId2; vRandom[nRndPos2] = nId1; @@ -140,41 +162,57 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) void CAddrMan::Delete(int nId) { - assert(mapInfo.count(nId) != 0); - CAddrInfo& info = mapInfo[nId]; - assert(!info.fInTried); - assert(info.nRefCount == 0); + AssertLockHeld(cs); + + const auto it{mapInfo.find(nId)}; + if (it != mapInfo.end()) { + CAddrInfo& info = (*it).second; + assert(!info.fInTried); + assert(info.nRefCount == 0); + + SwapRandom(info.nRandomPos, vRandom.size() - 1); + vRandom.pop_back(); + mapAddr.erase(info); + mapInfo.erase(nId); + nNew--; + } - SwapRandom(info.nRandomPos, vRandom.size() - 1); - vRandom.pop_back(); - mapAddr.erase(info); - mapInfo.erase(nId); - nNew--; } void CAddrMan::ClearNew(int nUBucket, int nUBucketPos) { + AssertLockHeld(cs); + // if there is an entry in the specified bucket, delete it. if (vvNew[nUBucket][nUBucketPos] != -1) { int nIdDelete = vvNew[nUBucket][nUBucketPos]; - CAddrInfo& infoDelete = mapInfo[nIdDelete]; - assert(infoDelete.nRefCount > 0); - infoDelete.nRefCount--; - vvNew[nUBucket][nUBucketPos] = -1; - if (infoDelete.nRefCount == 0) { - Delete(nIdDelete); + const auto it{mapInfo.find(nIdDelete)}; + if (it != mapInfo.end()) { + CAddrInfo& infoDelete = (*it).second; + assert(infoDelete.nRefCount > 0); + infoDelete.nRefCount--; + vvNew[nUBucket][nUBucketPos] = -1; + if (infoDelete.nRefCount == 0) { + Delete(nIdDelete); + } } } + } void CAddrMan::MakeTried(CAddrInfo& info, int nId) { + AssertLockHeld(cs); + // remove the entry from all new buckets - for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { - int pos = info.GetBucketPosition(nKey, true, bucket); + const int start_bucket{info.GetNewBucket(nKey, m_asmap)}; + for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) { + const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT}; + const int pos{info.GetBucketPosition(nKey, true, bucket)}; if (vvNew[bucket][pos] == nId) { vvNew[bucket][pos] = -1; info.nRefCount--; + if (info.nRefCount == 0) break; } } nNew--; @@ -215,67 +253,6 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId) info.fInTried = true; } -void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime) { - int nId; - CAddrInfo* pinfo = Find(addr, &nId); - - // if not found, bail out - if (!pinfo) - return; - - CAddrInfo& info = *pinfo; - - // check whether we are talking about the exact same CService (including same port) - if (info != addr) - return; - - // update info - info.nLastSuccess = nTime; - info.nLastTry = nTime; - info.nAttempts = 0; - // nTime is not updated here, to avoid leaking information about - // currently-connected peers. - - // if it is already in the tried set, don't do anything else - if (info.fInTried) - return; - - // find a bucket it is in now - int nRnd = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); - int nUBucket = -1; - for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) { - int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT; - int nBpos = info.GetBucketPosition(nKey, true, nB); - if (vvNew[nB][nBpos] == nId) { - nUBucket = nB; - break; - } - } - - // if no bucket is found, something bad happened; - // TODO: maybe re-add the node, but for now, just bail out - if (nUBucket == -1) - return; - - // which tried bucket to move the entry to - int tried_bucket = info.GetTriedBucket(nKey,m_asmap); - int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket); - - // Will moving this address into tried evict another entry? - if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) { - LogPrint("addrman", "Collision inserting element into tried table, moving %s to m_tried_collisions=%d\n", addr.ToString(), m_tried_collisions.size()); - if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) { - m_tried_collisions.insert(nId); - } - } else { - LogPrint("addrman", "Moving %s to tried\n", addr.ToString()); - printf("%s: Moving %s to tried\n", __func__, addr.ToString().c_str() ); - - // move nId to the tried tables - MakeTried(info, nId); - } -} - void CAddrMan::ResolveCollisions_() { for (std::set::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) { int id_new = *it; @@ -351,13 +328,59 @@ CAddrInfo CAddrMan::SelectTriedCollision_() { return mapInfo[id_old]; } +void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime) { + int nId; + CAddrInfo* pinfo = Find(addr, &nId); + + // if not found, bail out + if (!pinfo) + return; + + CAddrInfo& info = *pinfo; + + // check whether we are talking about the exact same CService (including same port) + if (info != addr) + return; + + // update info + info.nLastSuccess = nTime; + info.nLastTry = nTime; + info.nAttempts = 0; + // nTime is not updated here, to avoid leaking information about + // currently-connected peers. + + // if it is already in the tried set, don't do anything else + if (info.fInTried) + return; + + // find a bucket it is in now + int nRnd = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); + int nUBucket = -1; + for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) { + int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT; + int nBpos = info.GetBucketPosition(nKey, true, nB); + if (vvNew[nB][nBpos] == nId) { + nUBucket = nB; + break; + } + } + + // if no bucket is found, something bad happened; + // TODO: maybe re-add the node, but for now, just bail out + if (nUBucket == -1) + return; + + LogPrint("addrman", "Moving %s to tried\n", addr.ToString()); + + // move nId to the tried tables + MakeTried(info, nId); +} bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) { if (!addr.IsRoutable()) return false; - bool fNew = false; int nId; CAddrInfo* pinfo = Find(addr, &nId); @@ -392,19 +415,20 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP } else { pinfo = Create(addr, source, &nId); pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); - nNew++; - fNew = true; } int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap); int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); + bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; if (vvNew[nUBucket][nUBucketPos] != nId) { - bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; if (!fInsert) { - CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; - if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { - // Overwrite the existing new table entry. - fInsert = true; + const auto it{mapInfo.find(vvNew[nUBucket][nUBucketPos])}; + if (it != mapInfo.end()) { + CAddrInfo& infoExisting = (*it).second; + if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { + // Overwrite the existing new table entry. + fInsert = true; + } } } if (fInsert) { @@ -417,7 +441,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP } } } - return fNew; + return fInsert; } void CAddrMan::Attempt_(const CService& addr, int64_t nTime) @@ -454,10 +478,15 @@ CAddrInfo CAddrMan::Select_(bool newOnly) // Use a 50% chance for choosing between tried and new table entries. if (!newOnly && - (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { + (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { // use a tried node double fChanceFactor = 1.0; + double fReachableFactor = 1.0; + double fJustTried = 1.0; while (1) { + if (ShutdownRequested()) //break loop on shutdown request + return CAddrInfo(); + int i = 0; int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT); int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); @@ -472,14 +501,27 @@ CAddrInfo CAddrMan::Select_(bool newOnly) int nId = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (info.IsReachableNetwork()) { + //deprioritize unreachable networks + fReachableFactor = 0.25; + } + if (info.IsJustTried()) { + //deprioritize entries just tried + fJustTried = 0.10; + } + if (RandomInt(1 << 30) < fChanceFactor * fReachableFactor * fJustTried * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } } else { // use a new node double fChanceFactor = 1.0; + double fReachableFactor = 1.0; + double fJustTried = 1.0; while (1) { + if (ShutdownRequested()) //break loop on shutdown request + return CAddrInfo(); + int i = 0; int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); @@ -494,12 +536,20 @@ CAddrInfo CAddrMan::Select_(bool newOnly) int nId = vvNew[nUBucket][nUBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (info.IsReachableNetwork()) { + //deprioritize unreachable networks + fReachableFactor = 0.25; + } + if (info.IsJustTried()) { + //deprioritize entries just tried + fJustTried = 0.10; + } + if (RandomInt(1 << 30) < fChanceFactor * fReachableFactor * fJustTried * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } } - + return CAddrInfo(); } @@ -581,24 +631,59 @@ int CAddrMan::Check_() } #endif -void CAddrMan::GetAddr_(std::vector& vAddr) +void CAddrMan::GetAddr_(std::vector& vAddr, bool wants_addrv2) { unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom.size() / 100; if (nNodes > ADDRMAN_GETADDR_MAX) nNodes = ADDRMAN_GETADDR_MAX; + int addrv2Nodes = nNodes/5; + int ipv4Nodes = 0; + int ipv6Nodes = 0; + int torNodes = 0; + int i2pNodes = 0; + int cjdnsNodes = 0; + + // Randomize Nodes + for (unsigned int n = 0; n < vRandom.size(); n++) { + int nRndPos = RandomInt(vRandom.size() - n) + n; + SwapRandom(n, nRndPos); + } + // gather a list of random nodes, skipping those of low quality for (unsigned int n = 0; n < vRandom.size(); n++) { if (vAddr.size() >= nNodes) break; - int nRndPos = RandomInt(vRandom.size() - n) + n; - SwapRandom(n, nRndPos); assert(mapInfo.count(vRandom[n]) == 1); - const CAddrInfo& ai = mapInfo[vRandom[n]]; - if (!ai.IsTerrible()) - vAddr.push_back(ai); + + if (!ai.IsTerrible()) { + if (!wants_addrv2) { + vAddr.push_back(ai); + } else { + if (ai.IsIPv4() && ipv4Nodes <= addrv2Nodes) { + vAddr.push_back(ai); + ipv4Nodes++; + } + if (ai.IsIPv6() && ipv6Nodes <= addrv2Nodes) { + vAddr.push_back(ai); + ipv6Nodes++; + } + if (ai.IsCJDNS() && cjdnsNodes <= addrv2Nodes) { + vAddr.push_back(ai); + cjdnsNodes++; + } + if (ai.IsTor() && torNodes <= addrv2Nodes) { + vAddr.push_back(ai); + torNodes++; + } + if (ai.IsI2P() && i2pNodes <= addrv2Nodes) { + vAddr.push_back(ai); + i2pNodes++; + } + } + } } } @@ -622,10 +707,36 @@ void CAddrMan::Connected_(const CService& addr, int64_t nTime) info.nTime = nTime; } +void CAddrMan::SetLocal_(const CService& addr) +{ + CAddrInfo* pinfo = Find(addr); + + // if not found, bail out + if (!pinfo) + return; + + CAddrInfo& info = *pinfo; + + // check whether we are talking about the exact same CService (including same port) + if (info != addr) + return; + + // update info + info.fLocal = true; +} + int CAddrMan::RandomInt(int nMax){ return GetRandInt(nMax); } +void CAddrMan::GetAllPeers(std::map &info) { + + for(std::map::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { + info[(*it).second.ToStringIPPort()] = (*it).second.GetLastSuccess(); + } + return; +} + std::vector CAddrMan::DecodeAsmap(fs::path path) { std::vector bits; diff --git a/src/addrman.h b/src/addrman.h index 5738913d4..ab425d40e 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -24,6 +24,7 @@ #include "protocol.h" #include "random.h" #include "sync.h" +#include "streams.h" #include "timedata.h" #include "util.h" #include "fs.h" @@ -64,18 +65,17 @@ private: //! position in vRandom int nRandomPos; + //! Address is local + bool fLocal; + friend class CAddrMan; public: - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*(CAddress*)this); - READWRITE(source); - READWRITE(nLastSuccess); - READWRITE(nAttempts); + SERIALIZE_METHODS(CAddrInfo, obj) + { + READWRITEAS(CAddress, obj); + READ_WRITE(obj.source, obj.nLastSuccess, obj.nAttempts); } void Init() @@ -86,6 +86,7 @@ public: nRefCount = 0; fInTried = false; nRandomPos = -1; + fLocal = false; } CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) @@ -116,9 +117,15 @@ public: //! Determine whether the statistics about this entry are bad enough so that it can just be deleted bool IsTerrible(int64_t nNow = GetTime()) const; + //Determine if this entry was just tried + bool IsJustTried(int64_t nNow = GetTime()) const; + //! Calculate the relative chance this entry should be given when selecting nodes to connect to double GetChance(int64_t nNow = GetTime()) const; + //Returns the last successful connection + int64_t GetLastSuccess() {return nTime;} + }; /** Stochastic address manager @@ -199,8 +206,30 @@ private: //! critical section to protect the inner data structures mutable CCriticalSection cs; + //! Serialization versions. + enum Format : uint8_t { + V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88 + V1_DETERMINISTIC = 1, //!< for pre-asmap files + V2_ASMAP = 2, //!< for files including asmap version + V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format + }; + + //! The maximum format this software knows it can unserialize. Also, we always serialize + //! in this format. + //! The format (first byte in the serialized stream) can be higher than this and + //! still this software may be able to unserialize the file - if the second byte + //! (see `lowest_compatible` in `Unserialize()`) is less or equal to this. + static constexpr Format FILE_FORMAT = Format::V3_BIP155; + + //! The initial value of a field that is incremented every time an incompatible format + //! change is made (such that old software versions would not be able to parse and + //! understand the new file format). This is 32 because we overtook the "key size" + //! field which was 32 historically. + //! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead. + static constexpr uint8_t INCOMPATIBILITY_BASE = 32; + //! last used nId - int nIdCount; + int nIdCount GUARDED_BY(cs){0}; //! table with information about all nIds std::map mapInfo; @@ -280,12 +309,16 @@ protected: #endif //! Select several addresses at once. - void GetAddr_(std::vector &vAddr); + void GetAddr_(std::vector &vAddr, bool wants_addrv2); //! Mark an entry as currently-connected-to. void Connected_(const CService &addr, int64_t nTime); + //! Mark an entry as local + void SetLocal_(const CService &addr); + public: + void GetAllPeers(std::map &info); // Compressed IP->ASN mapping, loaded from a file when a node starts. // Should be always empty if no file was provided. // This mapping is then used for bucketing nodes in Addrman. @@ -336,13 +369,22 @@ public: * very little in common. */ template - void Serialize(Stream &s) const + void Serialize(Stream &s_) const + EXCLUSIVE_LOCKS_REQUIRED(!cs) { LOCK(cs); - unsigned char nVersion = 2; - s << nVersion; - s << ((unsigned char)32); + // Always serialize in the latest version (FILE_FORMAT). + + OverrideStream s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT); + + s << static_cast(FILE_FORMAT); + + // Increment `lowest_compatible` iff a newly introduced format is incompatible with + // the previous one. + static constexpr uint8_t lowest_compatible = Format::V3_BIP155; + s << static_cast(INCOMPATIBILITY_BASE + lowest_compatible); + s << nKey; s << nNew; s << nTried; @@ -393,22 +435,40 @@ public: } template - void Unserialize(Stream& s) + void Unserialize(Stream& s_) { LOCK(cs); - Clear(); - unsigned char nVersion; - s >> nVersion; - unsigned char nKeySize; - s >> nKeySize; - if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization"); + assert(vRandom.empty()); + + Format format; + s_ >> Using>(format); + + int stream_version = s_.GetVersion(); + if (format >= Format::V3_BIP155) { + // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress + // unserialize methods know that an address in addrv2 format is coming. + stream_version |= ADDRV2_FORMAT; + } + + OverrideStream s(&s_, s_.GetType(), stream_version); + + uint8_t compat; + s >> compat; + const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE; + if (lowest_compatible > FILE_FORMAT) { + throw std::ios_base::failure(strprintf( + "Unsupported format of addrman database: %u. It is compatible with formats >=%u, " + "but the maximum supported by this version of %s is %u.", + format, lowest_compatible, PACKAGE_NAME, static_cast(FILE_FORMAT))); + } + s >> nKey; s >> nNew; s >> nTried; int nUBuckets = 0; s >> nUBuckets; - if (nVersion != 0) { + if (format >= Format::V1_DETERMINISTIC) { nUBuckets ^= (1 << 30); } @@ -422,7 +482,7 @@ public: // Deserialize entries from the new table. for (int n = 0; n < nNew; n++) { - CAddrInfo &info = mapInfo[n]; + CAddrInfo& info = mapInfo[n]; s >> info; mapAddr[info] = n; info.nRandomPos = vRandom.size(); @@ -437,7 +497,7 @@ public: s >> info; int nKBucket = info.GetTriedBucket(nKey, m_asmap); int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); - if (vvTried[nKBucket][nKBucketPos] == -1) { + if (info.IsValid() && vvTried[nKBucket][nKBucketPos] == -1) { info.nRandomPos = vRandom.size(); info.fInTried = true; vRandom.push_back(nIdCount); @@ -452,60 +512,84 @@ public: nTried -= nLost; // Store positions in the new table buckets to apply later (if possible). - std::map entryToBucket; // Represents which entry belonged to which bucket when serializing + // An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets, + // so we store all bucket-entry_index pairs to iterate through later. + std::vector> bucket_entries; - for (int bucket = 0; bucket < nUBuckets; bucket++) { - int nSize = 0; - s >> nSize; - for (int n = 0; n < nSize; n++) { - int nIndex = 0; - s >> nIndex; - if (nIndex >= 0 && nIndex < nNew) { - entryToBucket[nIndex] = bucket; + for (int bucket = 0; bucket < nUBuckets; ++bucket) { + int num_entries{0}; + s >> num_entries; + for (int n = 0; n < num_entries; ++n) { + int entry_index{0}; + s >> entry_index; + if (entry_index >= 0 && entry_index < nNew) { + bucket_entries.emplace_back(bucket, entry_index); } } } - uint256 supplied_asmap_version; + // If the bucket count and asmap checksum haven't changed, then attempt + // to restore the entries to the buckets/positions they were in before + // serialization. + uint256 supplied_asmap_checksum; if (m_asmap.size() != 0) { - supplied_asmap_version = SerializeHash(m_asmap); + supplied_asmap_checksum = SerializeHash(m_asmap); } - uint256 serialized_asmap_version; - if (nVersion > 1) { - s >> serialized_asmap_version; + uint256 serialized_asmap_checksum; + if (format >= Format::V2_ASMAP) { + s >> serialized_asmap_checksum; + } + const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && + serialized_asmap_checksum == supplied_asmap_checksum}; + + if (!restore_bucketing) { + LogPrint("addrman", "Bucketing method was updated, re-bucketing addrman entries from disk\n"); } - for (int n = 0; n < nNew; n++) { - CAddrInfo &info = mapInfo[n]; - int bucket = entryToBucket[n]; - int nUBucketPos = info.GetBucketPosition(nKey, true, bucket); - if (nVersion == 2 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && - info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && serialized_asmap_version == supplied_asmap_version) { - // Bucketing has not changed, using existing bucket positions for the new table - vvNew[bucket][nUBucketPos] = n; - info.nRefCount++; - } else { - // In case the new table data cannot be used (nVersion unknown, bucket count wrong or new asmap), - // try to give them a reference based on their primary source address. - LogPrint("addrman", "Bucketing method was updated, re-bucketing addrman entries from disk\n"); - bucket = info.GetNewBucket(nKey, m_asmap); - nUBucketPos = info.GetBucketPosition(nKey, true, bucket); - if (vvNew[bucket][nUBucketPos] == -1) { - vvNew[bucket][nUBucketPos] = n; - info.nRefCount++; + for (auto bucket_entry : bucket_entries) { + int bucket{bucket_entry.first}; + const int entry_index{bucket_entry.second}; + // CAddrInfo& info = mapInfo[entry_index]; + + const auto it{mapInfo.find(entry_index)}; + if (it != mapInfo.end()) { + CAddrInfo& info = (*it).second; + + // Don't store the entry in the new bucket if it's not a valid address for our addrman + if (!info.IsValid()) continue; + + // The entry shouldn't appear in more than + // ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip + // this bucket_entry. + if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue; + + int bucket_position = info.GetBucketPosition(nKey, true, bucket); + if (restore_bucketing && vvNew[bucket][bucket_position] == -1) { + // Bucketing has not changed, using existing bucket positions for the new table + vvNew[bucket][bucket_position] = entry_index; + ++info.nRefCount; + } else { + // In case the new table data cannot be used (bucket count wrong or new asmap), + // try to give them a reference based on their primary source address. + bucket = info.GetNewBucket(nKey, m_asmap); + bucket_position = info.GetBucketPosition(nKey, true, bucket); + if (vvNew[bucket][bucket_position] == -1) { + vvNew[bucket][bucket_position] = entry_index; + ++info.nRefCount; + } } } } // Prune new entries with refcount 0 (as a result of collisions). int nLostUnk = 0; - for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) { + for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) { if (it->second.fInTried == false && it->second.nRefCount == 0) { - std::map::const_iterator itCopy = it++; + const auto itCopy = it++; Delete(itCopy->first); - nLostUnk++; + ++nLostUnk; } else { - it++; + ++it; } } if (nLost + nLostUnk > 0) { @@ -531,7 +615,6 @@ public: } } - nIdCount = 0; nTried = 0; nNew = 0; mapInfo.clear(); @@ -657,13 +740,13 @@ public: } //! Return a bunch of addresses, selected at random. - std::vector GetAddr() + std::vector GetAddr(bool wants_addrv2 = false) { Check(); std::vector vAddr; { LOCK(cs); - GetAddr_(vAddr); + GetAddr_(vAddr, wants_addrv2); } Check(); return vAddr; @@ -680,6 +763,17 @@ public: } } + //! Mark an entry as currently-connected-to. + void SetLocal(const CService &addr) + { + { + LOCK(cs); + Check(); + SetLocal_(addr); + Check(); + } + } + }; #endif // HUSH_ADDRMAN_H diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index da2dcd58b..af49e0033 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -19,7 +19,7 @@ ******************************************************************************/ #include "arith_uint256.h" #include "uint256.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include "crypto/common.h" #include #include diff --git a/src/attributes.h b/src/attributes.h new file mode 100644 index 000000000..a0afeb2f6 --- /dev/null +++ b/src/attributes.h @@ -0,0 +1,20 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Hush developers +// Distributed under the GPLv3 software license, see the accompanying +// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html + +#ifndef HUSH_ATTRIBUTES_H +#define HUSH_ATTRIBUTES_H + +#if defined(__clang__) +# if __has_attribute(lifetimebound) +# define LIFETIMEBOUND [[clang::lifetimebound]] +# else +# define LIFETIMEBOUND +# endif +#else +# define LIFETIMEBOUND +#endif + +#endif // HUSH_ATTRIBUTES_H diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index d6ac78c25..669a095ea 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -22,7 +22,7 @@ #include "rpc/client.h" #include "rpc/protocol.h" #include "util.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include #include #include diff --git a/src/cc/Makefile b/src/cc/Makefile index 3e988f279..24b94226a 100644 --- a/src/cc/Makefile +++ b/src/cc/Makefile @@ -2,9 +2,10 @@ SHELL = /bin/sh CC = gcc CC_DARWIN = g++-6 CC_WIN = x86_64-w64-mingw32-gcc-posix -CFLAGS_DARWIN = -std=c++11 -arch x86_64 -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -c -Wl,-undefined -Wl,dynamic_lookup -dynamiclib -CFLAGS = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -CFLAGS_WIN = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c +CFLAGS = -arch x86_64 +CXXFLAGS_DARWIN = -std=c++11 -arch x86_64 -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -c -Wl,-undefined -Wl,dynamic_lookup -dynamiclib +CXXFLAGS = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c +CXXFLAGS_WIN = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c DEBUGFLAGS = -O0 -D _DEBUG RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program $(info $(OS)) @@ -13,21 +14,27 @@ $(info $(OS)) TARGET = ../libcc.so TARGET_DARWIN = ../libcc.dylib TARGET_WIN = ../libcc.dll -SOURCES = cclib.cpp -#HEADERS = $(shell echo ../cryptoconditions/include/*.h) +SOURCES = cclib.cpp ../cJSON.c +OBJS = cclib.o ../cJSON.o all: $(TARGET) -$(TARGET): $(SOURCES) +%.o: %.c + $(CC) -o $@ $< $(CFLAGS) $(DEBUGFLAGS) + +%.o: %.cpp + $(CC) -o $@ $< $(CXXFLAGS) $(DEBUGFLAGS) + +$(TARGET): $(OBJS) $(info Building cclib to src/) ifeq ($(OS),Darwin) - $(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) $(SOURCES) + $(CC_DARWIN) $(CXXFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) $(OBJS) else ifeq ($(OS),Linux) - $(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) $(SOURCES) + $(CC) $(CXXFLAGS) $(DEBUGFLAGS) -o $(TARGET) $(OBJS) #else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host else $(info WINDOWS) - $(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) $(SOURCES) + $(CC_WIN) $(CXXFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) $(OBJS) endif clean: diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 6a7ca1ed1..b5a805607 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -24,7 +24,7 @@ #include "main.h" #include "crypto/equihash.h" #include "util.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include #include #include "chainparamsseeds.h" @@ -205,7 +205,7 @@ public: bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks"; bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main"; - vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); + vFixedSeeds = std::vector(std::begin(chainparams_seed_main), std::end(chainparams_seed_main)); fMiningRequiresPeers = true; fDefaultConsistencyChecks = false; @@ -313,7 +313,7 @@ public: bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling"; bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test"; - vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); + vFixedSeeds = std::vector(std::begin(chainparams_seed_test), std::end(chainparams_seed_test)); //fRequireRPCPassword = true; fMiningRequiresPeers = false;//true; diff --git a/src/chainparams.h b/src/chainparams.h index e32a965ba..3813ed983 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -36,11 +36,6 @@ struct CDNSSeedData { CDNSSeedData(const std::string &strName, const std::string &strHost) : name(strName), host(strHost) {} }; -struct SeedSpec6 { - uint8_t addr[16]; - uint16_t port; -}; - typedef std::map MapCheckpoints; @@ -108,7 +103,7 @@ public: const std::vector& DNSSeeds() const { return vSeeds; } const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; } - const std::vector& FixedSeeds() const { return vFixedSeeds; } + const std::vector& FixedSeeds() const { return vFixedSeeds; } const CCheckpointData& Checkpoints() const { return checkpointData; } /** Return the founder's reward address and script for a given block height */ std::string GetFoundersRewardAddressAtHeight(int height) const; @@ -146,7 +141,7 @@ protected: std::string strCurrencyUnits; uint32_t bip44CoinType; CBlock genesis; - std::vector vFixedSeeds; + std::vector vFixedSeeds; bool fMiningRequiresPeers = false; bool fDefaultConsistencyChecks = false; bool fRequireStandard = false; diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 663a9bcac..887b3d602 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -1,37 +1,20 @@ // Copyright (c) 2016-2022 The Hush developers -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - +// Distributed under the GPLv3 software license, see the accompanying +// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html +// THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY +// Instead, run: ./contrib/seeds/generate-seeds.py contrib/seeds #ifndef HUSH_CHAINPARAMSSEEDS_H #define HUSH_CHAINPARAMSSEEDS_H -/** - * List of fixed seed nodes for the bitcoin network - * AUTOGENERATED by contrib/seeds/generate-seeds.py - * - * Each line contains a 16-byte IPv6 address and a port. - * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly. - */ -static SeedSpec6 pnSeed6_main[] = { - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0xec}, 27485}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0xec}, 27487}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x40,0x69,0x6f}, 27485}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x40,0x69,0x6f}, 27487}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x48}, 27485}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x48}, 27487} +// List of fixed seed nodes for the Hush network +// Each line contains a BIP155 serialized address. +// +static const uint8_t chainparams_seed_main[] = { + 0x01,0x04,0xb9,0xf1,0x3d,0x2b,0x00,0x00, // 185.241.61.43 + 0x01,0x04,0x89,0x4a,0x04,0xc6,0x00,0x00, // 137.74.4.198 + 0x01,0x04,0x95,0x1c,0x66,0xdb,0x00,0x00, // 149.28.102.219 }; -static SeedSpec6 pnSeed6_test[] = { +static const uint8_t chainparams_seed_test[] = { + 0x01,0x04,0x01,0x02,0x03,0x04,0x00,0x00, // 1.2.3.4 }; #endif // HUSH_CHAINPARAMSSEEDS_H diff --git a/src/coins.cpp b/src/coins.cpp index 57e692444..5117bbd66 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -24,6 +24,9 @@ #include "hush_defs.h" #include "importcoin.h" #include +#include "util.h" +extern bool fZdebug; + /** * calculate number of bytes for the bitmask, and its number of non-zero bytes * each bit in the bitmask represents the availability of one output, but the diff --git a/src/compat.h b/src/compat.h index 045774e27..49eaaebae 100644 --- a/src/compat.h +++ b/src/compat.h @@ -78,6 +78,8 @@ typedef u_int SOCKET; #define SOCKET_ERROR -1 #endif +#define WSAEAGAIN EAGAIN + #ifdef _WIN32 #ifndef S_IRUSR #define S_IRUSR 0400 @@ -109,8 +111,14 @@ typedef u_int SOCKET; size_t strnlen( const char *start, size_t max_len); #endif // HAVE_DECL_STRNLEN -bool static inline IsSelectableSocket(SOCKET s) { -#ifdef _WIN32 +#ifndef WIN32 +typedef void* sockopt_arg_type; +#else +typedef char* sockopt_arg_type; +#endif + +bool static inline IsSelectableSocket(const SOCKET& s) { +#ifdef WIN32 return true; #else return (s < FD_SETSIZE); diff --git a/src/core_read.cpp b/src/core_read.cpp index 3e01a37e3..bd3be6dd0 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -27,7 +27,7 @@ #include "streams.h" #include #include "util.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include "version.h" #include diff --git a/src/core_write.cpp b/src/core_write.cpp index 8b890db21..c2932da01 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -29,7 +29,7 @@ #include #include "util.h" #include "utilmoneystr.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include #include diff --git a/src/crypto/common.h b/src/crypto/common.h index 2b6be0901..0ce6ebb40 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -62,6 +62,13 @@ void static inline WriteLE64(unsigned char* ptr, uint64_t x) memcpy(ptr, (char*)&v, 8); } +uint16_t static inline ReadBE16(const unsigned char* ptr) +{ + uint16_t x; + memcpy((char*)&x, ptr, 2); + return be16toh(x); +} + uint32_t static inline ReadBE32(const unsigned char* ptr) { uint32_t x; diff --git a/src/crypto/equihash.h b/src/crypto/equihash.h index 23530cc61..38a4946e1 100644 --- a/src/crypto/equihash.h +++ b/src/crypto/equihash.h @@ -8,7 +8,7 @@ #define HUSH_EQUIHASH_H #include "crypto/sha256.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include "sodium.h" #include "hush_nk.h" #include diff --git a/src/crypto/sha3.cpp b/src/crypto/sha3.cpp new file mode 100644 index 000000000..ad3b74f34 --- /dev/null +++ b/src/crypto/sha3.cpp @@ -0,0 +1,162 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 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 + +// Based on https://github.com/mjosaarinen/tiny_sha3/blob/master/sha3.c +// by Markku-Juhani O. Saarinen + +#include "crypto/sha3.h" +#include "crypto/common.h" +#include "span.h" + +#include +#include // For std::begin and std::end. + +#include + +// Internal implementation code. +namespace +{ +uint64_t Rotl(uint64_t x, int n) { return (x << n) | (x >> (64 - n)); } +} // namespace + +void KeccakF(uint64_t (&st)[25]) +{ + static constexpr uint64_t RNDC[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, + 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, + 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, + 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, + 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + static constexpr int ROUNDS = 24; + + for (int round = 0; round < ROUNDS; ++round) { + uint64_t bc0, bc1, bc2, bc3, bc4, t; + + // Theta + bc0 = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; + bc1 = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; + bc2 = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; + bc3 = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; + bc4 = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; + t = bc4 ^ Rotl(bc1, 1); st[0] ^= t; st[5] ^= t; st[10] ^= t; st[15] ^= t; st[20] ^= t; + t = bc0 ^ Rotl(bc2, 1); st[1] ^= t; st[6] ^= t; st[11] ^= t; st[16] ^= t; st[21] ^= t; + t = bc1 ^ Rotl(bc3, 1); st[2] ^= t; st[7] ^= t; st[12] ^= t; st[17] ^= t; st[22] ^= t; + t = bc2 ^ Rotl(bc4, 1); st[3] ^= t; st[8] ^= t; st[13] ^= t; st[18] ^= t; st[23] ^= t; + t = bc3 ^ Rotl(bc0, 1); st[4] ^= t; st[9] ^= t; st[14] ^= t; st[19] ^= t; st[24] ^= t; + + // Rho Pi + t = st[1]; + bc0 = st[10]; st[10] = Rotl(t, 1); t = bc0; + bc0 = st[7]; st[7] = Rotl(t, 3); t = bc0; + bc0 = st[11]; st[11] = Rotl(t, 6); t = bc0; + bc0 = st[17]; st[17] = Rotl(t, 10); t = bc0; + bc0 = st[18]; st[18] = Rotl(t, 15); t = bc0; + bc0 = st[3]; st[3] = Rotl(t, 21); t = bc0; + bc0 = st[5]; st[5] = Rotl(t, 28); t = bc0; + bc0 = st[16]; st[16] = Rotl(t, 36); t = bc0; + bc0 = st[8]; st[8] = Rotl(t, 45); t = bc0; + bc0 = st[21]; st[21] = Rotl(t, 55); t = bc0; + bc0 = st[24]; st[24] = Rotl(t, 2); t = bc0; + bc0 = st[4]; st[4] = Rotl(t, 14); t = bc0; + bc0 = st[15]; st[15] = Rotl(t, 27); t = bc0; + bc0 = st[23]; st[23] = Rotl(t, 41); t = bc0; + bc0 = st[19]; st[19] = Rotl(t, 56); t = bc0; + bc0 = st[13]; st[13] = Rotl(t, 8); t = bc0; + bc0 = st[12]; st[12] = Rotl(t, 25); t = bc0; + bc0 = st[2]; st[2] = Rotl(t, 43); t = bc0; + bc0 = st[20]; st[20] = Rotl(t, 62); t = bc0; + bc0 = st[14]; st[14] = Rotl(t, 18); t = bc0; + bc0 = st[22]; st[22] = Rotl(t, 39); t = bc0; + bc0 = st[9]; st[9] = Rotl(t, 61); t = bc0; + bc0 = st[6]; st[6] = Rotl(t, 20); t = bc0; + st[1] = Rotl(t, 44); + + // Chi Iota + bc0 = st[0]; bc1 = st[1]; bc2 = st[2]; bc3 = st[3]; bc4 = st[4]; + st[0] = bc0 ^ (~bc1 & bc2) ^ RNDC[round]; + st[1] = bc1 ^ (~bc2 & bc3); + st[2] = bc2 ^ (~bc3 & bc4); + st[3] = bc3 ^ (~bc4 & bc0); + st[4] = bc4 ^ (~bc0 & bc1); + bc0 = st[5]; bc1 = st[6]; bc2 = st[7]; bc3 = st[8]; bc4 = st[9]; + st[5] = bc0 ^ (~bc1 & bc2); + st[6] = bc1 ^ (~bc2 & bc3); + st[7] = bc2 ^ (~bc3 & bc4); + st[8] = bc3 ^ (~bc4 & bc0); + st[9] = bc4 ^ (~bc0 & bc1); + bc0 = st[10]; bc1 = st[11]; bc2 = st[12]; bc3 = st[13]; bc4 = st[14]; + st[10] = bc0 ^ (~bc1 & bc2); + st[11] = bc1 ^ (~bc2 & bc3); + st[12] = bc2 ^ (~bc3 & bc4); + st[13] = bc3 ^ (~bc4 & bc0); + st[14] = bc4 ^ (~bc0 & bc1); + bc0 = st[15]; bc1 = st[16]; bc2 = st[17]; bc3 = st[18]; bc4 = st[19]; + st[15] = bc0 ^ (~bc1 & bc2); + st[16] = bc1 ^ (~bc2 & bc3); + st[17] = bc2 ^ (~bc3 & bc4); + st[18] = bc3 ^ (~bc4 & bc0); + st[19] = bc4 ^ (~bc0 & bc1); + bc0 = st[20]; bc1 = st[21]; bc2 = st[22]; bc3 = st[23]; bc4 = st[24]; + st[20] = bc0 ^ (~bc1 & bc2); + st[21] = bc1 ^ (~bc2 & bc3); + st[22] = bc2 ^ (~bc3 & bc4); + st[23] = bc3 ^ (~bc4 & bc0); + st[24] = bc4 ^ (~bc0 & bc1); + } +} + +SHA3_256_& SHA3_256_::Write(Span data) +{ + if (m_bufsize && m_bufsize + data.size() >= sizeof(m_buffer)) { + // Fill the buffer and process it. + std::copy(data.begin(), data.begin() + sizeof(m_buffer) - m_bufsize, m_buffer + m_bufsize); + data = data.subspan(sizeof(m_buffer) - m_bufsize); + m_state[m_pos++] ^= ReadLE64(m_buffer); + m_bufsize = 0; + if (m_pos == RATE_BUFFERS) { + KeccakF(m_state); + m_pos = 0; + } + } + while (data.size() >= sizeof(m_buffer)) { + // Process chunks directly from the buffer. + m_state[m_pos++] ^= ReadLE64(data.data()); + data = data.subspan(8); + if (m_pos == RATE_BUFFERS) { + KeccakF(m_state); + m_pos = 0; + } + } + if (data.size()) { + // Keep the remainder in the buffer. + std::copy(data.begin(), data.end(), m_buffer + m_bufsize); + m_bufsize += data.size(); + } + return *this; +} + +SHA3_256_& SHA3_256_::Finalize(Span output) +{ + assert(output.size() == OUTPUT_SIZE); + std::fill(m_buffer + m_bufsize, m_buffer + sizeof(m_buffer), 0); + m_buffer[m_bufsize] ^= 0x06; + m_state[m_pos] ^= ReadLE64(m_buffer); + m_state[RATE_BUFFERS - 1] ^= 0x8000000000000000; + KeccakF(m_state); + for (unsigned i = 0; i < 4; ++i) { + WriteLE64(output.data() + 8 * i, m_state[i]); + } + return *this; +} + +SHA3_256_& SHA3_256_::Reset() +{ + m_bufsize = 0; + m_pos = 0; + std::fill(std::begin(m_state), std::end(m_state), 0); + return *this; +} diff --git a/src/crypto/sha3.h b/src/crypto/sha3.h new file mode 100644 index 000000000..2cbd67e93 --- /dev/null +++ b/src/crypto/sha3.h @@ -0,0 +1,42 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Hush developers +// Distributed under the GPLv3 software license, see the accompanying +// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html + +#ifndef HUSH_CRYPTO_SHA3_H +#define HUSH_CRYPTO_SHA3_H + +#include "span.h" + +#include +#include + +//! The Keccak-f[1600] transform. +void KeccakF(uint64_t (&st)[25]); + +class SHA3_256_ +{ +private: + uint64_t m_state[25] = {0}; + unsigned char m_buffer[8]; + unsigned m_bufsize = 0; + unsigned m_pos = 0; + + //! Sponge rate in bits. + static constexpr unsigned RATE_BITS = 1088; + + //! Sponge rate expressed as a multiple of the buffer size. + static constexpr unsigned RATE_BUFFERS = RATE_BITS / (8 * sizeof(m_buffer)); + + static_assert(RATE_BITS % (8 * sizeof(m_buffer)) == 0, "Rate must be a multiple of 8 bytes"); + +public: + static constexpr size_t OUTPUT_SIZE = 32; + + SHA3_256_() {} + SHA3_256_& Write(Span data); + SHA3_256_& Finalize(Span output); + SHA3_256_& Reset(); +}; + +#endif // HUSH_CRYPTO_SHA3_H diff --git a/src/gtest/json_test_vectors.h b/src/gtest/json_test_vectors.h index 82b7fda66..29049e50c 100644 --- a/src/gtest/json_test_vectors.h +++ b/src/gtest/json_test_vectors.h @@ -3,7 +3,7 @@ // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html #include -#include "utilstrencodings.h" +#include "util/strencodings.h" #include "version.h" #include "serialize.h" #include "streams.h" diff --git a/src/gtest/test_deprecation.cpp b/src/gtest/test_deprecation.cpp index af546b860..46ccc2595 100644 --- a/src/gtest/test_deprecation.cpp +++ b/src/gtest/test_deprecation.cpp @@ -11,7 +11,7 @@ #include "init.h" #include "ui_interface.h" #include "util.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include #include diff --git a/src/gtest/test_merkletree.cpp b/src/gtest/test_merkletree.cpp index 224d69a3e..2cebf223e 100644 --- a/src/gtest/test_merkletree.cpp +++ b/src/gtest/test_merkletree.cpp @@ -19,7 +19,7 @@ #include -#include "utilstrencodings.h" +#include "util/strencodings.h" #include "version.h" #include "serialize.h" #include "streams.h" diff --git a/src/gtest/test_rpc.cpp b/src/gtest/test_rpc.cpp index c64b7604c..f6ac48d82 100644 --- a/src/gtest/test_rpc.cpp +++ b/src/gtest/test_rpc.cpp @@ -10,7 +10,7 @@ #include "primitives/block.h" #include "rpc/server.h" #include "streams.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); diff --git a/src/gtest/test_txid.cpp b/src/gtest/test_txid.cpp index 6cf5dbd6c..dafc660b2 100644 --- a/src/gtest/test_txid.cpp +++ b/src/gtest/test_txid.cpp @@ -8,7 +8,7 @@ #include "streams.h" #include "uint256.h" #include "util.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" /* Test that removing #1144 succeeded by verifying the hash of a transaction is over the entire serialized form. diff --git a/src/hash.h b/src/hash.h index a37c00a1d..e71fc4888 100644 --- a/src/hash.h +++ b/src/hash.h @@ -28,9 +28,7 @@ #include "serialize.h" #include "uint256.h" #include "version.h" - #include "sodium.h" - #include typedef uint256 ChainCode; @@ -48,6 +46,18 @@ public: sha.Reset().Write(buf, sha.OUTPUT_SIZE).Finalize(hash); } + CHash256& Write(Span input) { + sha.Write(input.data(), input.size()); + return *this; + } + + void Finalize(Span output) { + assert(output.size() == OUTPUT_SIZE); + unsigned char buf[CSHA256::OUTPUT_SIZE]; + sha.Finalize(buf); + sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(output.data()); + } + CHash256& Write(const unsigned char *data, size_t len) { sha.Write(data, len); return *this; @@ -120,6 +130,23 @@ inline uint256 Hash(const T1 p1begin, const T1 p1end, return result; } +/** Compute the 256-bit hash of an object. */ +template +inline uint256 Hash(const T& in1) +{ + uint256 result; + CHash256().Write(MakeUCharSpan(in1)).Finalize(result); + return result; +} + +/** Compute the 256-bit hash of the concatenation of two objects. */ +template +inline uint256 Hash(const T1& in1, const T2& in2) { + uint256 result; + CHash256().Write(MakeUCharSpan(in1)).Write(MakeUCharSpan(in2)).Finalize(result); + return result; +} + /** Compute the 160-bit hash an object. */ template inline uint160 Hash160(const T1 pbegin, const T1 pend) @@ -178,6 +205,40 @@ public: } }; +/** Reads data from an underlying stream, while hashing the read data. */ +template +class CHashVerifier : public CHashWriter +{ +private: + Source* source; + +public: + explicit CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {} + + void read(char* pch, size_t nSize) + { + source->read(pch, nSize); + this->write(pch, nSize); + } + + void ignore(size_t nSize) + { + char data[1024]; + while (nSize > 0) { + size_t now = std::min(nSize, 1024); + read(data, now); + nSize -= now; + } + } + + template + CHashVerifier& operator>>(T&& obj) + { + // Unserialize from this stream + ::Unserialize(*this, obj); + return (*this); + } +}; /** A writer stream (for serialization) that computes a 256-bit BLAKE2b hash. */ class CBLAKE2bWriter @@ -221,6 +282,7 @@ public: } }; + /** Compute the 256-bit hash of an object's serialization. */ template uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) @@ -230,6 +292,7 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL return ss.GetHash(); } + unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash); void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 5b70c3215..d9dc2ca5a 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -24,7 +24,7 @@ #include "random.h" #include "sync.h" #include "util.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include "ui_interface.h" #include // boost::trim diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 2f9761a93..adcb3778d 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -7,11 +7,13 @@ #include "chainparamsbase.h" #include "compat.h" #include "util.h" +#include "util/strencodings.h" #include "netbase.h" #include "rpc/protocol.h" // For HTTP status codes #include "sync.h" #include "ui_interface.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" + #include #include #include @@ -22,6 +24,7 @@ #include #include #include +#include #include #include @@ -157,6 +160,7 @@ public: boost::unique_lock lock(cs); return queue.size(); } + size_t MaxDepth() { boost::unique_lock lock(cs); @@ -167,6 +171,7 @@ public: boost::unique_lock lock(cs); return numThreads; } + }; struct HTTPPathHandler @@ -196,7 +201,6 @@ std::vector pathHandlers; //! Bound listening sockets std::vector boundSockets; - int getWorkQueueDepth() { return workQueue->Depth(); @@ -227,12 +231,17 @@ static bool ClientAllowed(const CNetAddr& netaddr) static bool InitHTTPAllowList() { rpc_allow_subnets.clear(); - rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet - rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost + CNetAddr localv4; + CNetAddr localv6; + LookupHost("127.0.0.1", localv4, false); + LookupHost("::1", localv6, false); + rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet + rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost if (mapMultiArgs.count("-rpcallowip")) { const std::vector& vAllow = mapMultiArgs["-rpcallowip"]; BOOST_FOREACH (std::string strAllow, vAllow) { - CSubNet subnet(strAllow); + CSubNet subnet; + LookupSubNet(strAllow.c_str(), subnet); if (!subnet.IsValid()) { uiInterface.ThreadSafeMessageBox( strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow), @@ -273,6 +282,16 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m) /** HTTP request callback */ static void http_request_cb(struct evhttp_request* req, void* arg) { + // Disable reading to work around a libevent bug, fixed in 2.2.0. + if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { + evhttp_connection* conn = evhttp_request_get_connection(req); + if (conn) { + bufferevent* bev = evhttp_connection_get_bufferevent(conn); + if (bev) { + bufferevent_disable(bev, EV_READ); + } + } + } std::unique_ptr hreq(new HTTPRequest(req)); // Early address-based allow check @@ -315,11 +334,10 @@ static void http_request_cb(struct evhttp_request* req, void* arg) if (i != iend) { std::unique_ptr item(new HTTPWorkItem(hreq.release(), path, i->handler)); assert(workQueue); - if (workQueue->Enqueue(item.get())) { + if (workQueue->Enqueue(item.get())) item.release(); /* if true, queue took ownership */ - } else { - item->req->WriteReply(HTTP_INTERNAL, strprintf("Work queue depth %d exceeded", workQueue->Depth() )); - } + else + item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded"); } else { hreq->WriteReply(HTTP_NOTFOUND); } @@ -541,7 +559,7 @@ struct event_base* EventBase() static void httpevent_callback_fn(evutil_socket_t, short, void* data) { // Static handler: simply call inner handler - HTTPEvent *self = ((HTTPEvent*)data); + HTTPEvent *self = static_cast(data); self->handler(); if (self->deleteWhenTriggered) delete self; @@ -628,8 +646,21 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) struct evbuffer* evb = evhttp_request_get_output_buffer(req); assert(evb); evbuffer_add(evb, strReply.data(), strReply.size()); - HTTPEvent* ev = new HTTPEvent(eventBase, true, - boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL)); + auto req_copy = req; + HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{ + evhttp_send_reply(req_copy, nStatus, (const char*)NULL, (struct evbuffer *)NULL); + // Re-enable reading from the socket. This is the second part of the libevent + // workaround above. + if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { + evhttp_connection* conn = evhttp_request_get_connection(req_copy); + if (conn) { + bufferevent* bev = evhttp_connection_get_bufferevent(conn); + if (bev) { + bufferevent_enable(bev, EV_READ | EV_WRITE); + } + } + } + }); ev->trigger(0); replySent = true; req = 0; // transferred back to main thread @@ -644,7 +675,7 @@ CService HTTPRequest::GetPeer() const char* address = ""; uint16_t port = 0; evhttp_connection_get_peer(con, (char**)&address, &port); - peer = CService(address, port); + peer = LookupNumeric(address, port); } return peer; } diff --git a/src/hush-tx.cpp b/src/hush-tx.cpp index 6d3f2f94c..bb0d3dab7 100644 --- a/src/hush-tx.cpp +++ b/src/hush-tx.cpp @@ -29,7 +29,7 @@ #include #include "util.h" #include "utilmoneystr.h" -#include "utilstrencodings.h" +#include "util/strencodings.h" #include #include #include diff --git a/src/i2p.cpp b/src/i2p.cpp new file mode 100644 index 000000000..e8de66a81 --- /dev/null +++ b/src/i2p.cpp @@ -0,0 +1,441 @@ +// Copyright (c) 2020-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Hush developers +// Distributed under the GPLv3 software license, see the accompanying +// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace i2p { + +/** + * Swap Standard Base64 <-> I2P Base64. + * Standard Base64 uses `+` and `/` as last two characters of its alphabet. + * I2P Base64 uses `-` and `~` respectively. + * So it is easy to detect in which one is the input and convert to the other. + * @param[in] from Input to convert. + * @return converted `from` + */ +static std::string SwapBase64(const std::string& from) +{ + std::string to; + to.resize(from.size()); + for (size_t i = 0; i < from.size(); ++i) { + switch (from[i]) { + case '-': + to[i] = '+'; + break; + case '~': + to[i] = '/'; + break; + case '+': + to[i] = '-'; + break; + case '/': + to[i] = '~'; + break; + default: + to[i] = from[i]; + break; + } + } + return to; +} + +/** + * Decode an I2P-style Base64 string. + * @param[in] i2p_b64 I2P-style Base64 string. + * @return decoded `i2p_b64` + * @throw std::runtime_error if decoding fails + */ +static Binary DecodeI2PBase64(const std::string& i2p_b64) +{ + const std::string& std_b64 = SwapBase64(i2p_b64); + bool invalid; + Binary decoded = DecodeBase64(std_b64.c_str(), &invalid); + if (invalid) { + throw std::runtime_error(strprintf("Cannot decode Base64: \"%s\"", i2p_b64)); + } + return decoded; +} + +/** + * Derive the .b32.i2p address of an I2P destination (binary). + * @param[in] dest I2P destination. + * @return the address that corresponds to `dest` + * @throw std::runtime_error if conversion fails + */ +static CNetAddr DestBinToAddr(const Binary& dest) +{ + CSHA256 hasher; + hasher.Write(dest.data(), dest.size()); + unsigned char hash[CSHA256::OUTPUT_SIZE]; + hasher.Finalize(hash); + + CNetAddr addr; + const std::string addr_str = EncodeBase32(hash, false) + ".b32.i2p"; + if (!addr.SetSpecial(addr_str)) { + throw std::runtime_error(strprintf("Cannot parse I2P address: \"%s\"", addr_str)); + } + + return addr; +} + +/** + * Derive the .b32.i2p address of an I2P destination (I2P-style Base64). + * @param[in] dest I2P destination. + * @return the address that corresponds to `dest` + * @throw std::runtime_error if conversion fails + */ +static CNetAddr DestB64ToAddr(const std::string& dest) +{ + const Binary& decoded = DecodeI2PBase64(dest); + return DestBinToAddr(decoded); +} + +namespace sam { + +Session::Session(const fs::path& private_key_file, + const CService& control_host) + : m_private_key_file(private_key_file), m_control_host(control_host), + m_control_sock(std::unique_ptr(new Sock(INVALID_SOCKET))) +{ +} + +Session::~Session() +{ +} + +bool Session::Check() +{ + try { + LOCK(cs_i2p); + CreateIfNotCreatedAlready(); + return true; + } catch (const std::runtime_error& e) { + LogPrint("i2p","I2P: Error Checking Session: %s\n", e.what()); + CheckControlSock(); + } + return false; +} + +bool Session::Listen(Connection& conn) +{ + try { + LOCK(cs_i2p); + CreateIfNotCreatedAlready(); + conn.me = m_my_addr; + conn.sock = StreamAccept(); + return true; + } catch (const std::runtime_error& e) { + LogPrint("i2p","I2P: Error listening: %s\n", e.what()); + CheckControlSock(); + } + return false; +} + +bool Session::Accept(Connection& conn) +{ + try { + while (true) { + + // boost::this_thread::interruption_point(); + if (ShutdownRequested()) { + Disconnect(); + return false; + } + + + Sock::Event occurred; + if (!conn.sock->Wait(std::chrono::milliseconds{MAX_WAIT_FOR_IO}, Sock::RECV, &occurred)) { + throw std::runtime_error("wait on socket failed"); + } + + if ((occurred & Sock::RECV) == 0) { + // Timeout, no incoming connections within MAX_WAIT_FOR_IO. + continue; + } + + const std::string& peer_dest = + conn.sock->RecvUntilTerminator('\n', std::chrono::milliseconds{MAX_WAIT_FOR_IO}, MAX_MSG_SIZE); + + if (ShutdownRequested()) { + Disconnect(); + return false; + } + + conn.peer = CService(DestB64ToAddr(peer_dest), Params().GetDefaultPort()); + return true; + } + } catch (const std::runtime_error& e) { + LogPrint("i2p","I2P: Error accepting: %s\n", e.what()); + CheckControlSock(); + } + return false; +} + +bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error) +{ + proxy_error = true; + + std::string session_id; + std::unique_ptr sock; + conn.peer = to; + + try { + { + LOCK(cs_i2p); + CreateIfNotCreatedAlready(); + session_id = m_session_id; + conn.me = m_my_addr; + sock = Hello(); + } + + const Reply& lookup_reply = + SendRequestAndGetReply(*sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringIP())); + + const std::string& dest = lookup_reply.Get("VALUE"); + + const Reply& connect_reply = SendRequestAndGetReply( + *sock, strprintf("STREAM CONNECT ID=%s DESTINATION=%s SILENT=false", session_id, dest), + false); + + const std::string& result = connect_reply.Get("RESULT"); + + if (result == "OK") { + conn.sock = std::move(sock); + return true; + } + + if (result == "INVALID_ID") { + LOCK(cs_i2p); + Disconnect(); + throw std::runtime_error("Invalid session id"); + } + + if (result == "CANT_REACH_PEER" || result == "TIMEOUT" || "KEY_NOT_FOUND") { + proxy_error = false; + } + + throw std::runtime_error(strprintf("\"%s\"", connect_reply.full)); + } catch (const std::runtime_error& e) { + LogPrint("i2p","I2P: Error connecting to %s: %s\n", to.ToString(), e.what()); + CheckControlSock(); + return false; + } +} + +// Private methods + +std::string Session::Reply::Get(const std::string& key) const +{ + const auto& pos = keys.find(key); + if (pos == keys.end() || !pos->second.has_value()) { + throw std::runtime_error( + strprintf("Missing %s= in the reply to \"%s\": \"%s\"", key, request, full)); + } + return pos->second.value(); +} + +Session::Reply Session::SendRequestAndGetReply(const Sock& sock, + const std::string& request, + bool check_result_ok) const +{ + sock.SendComplete(request + "\n", std::chrono::milliseconds{MAX_WAIT_FOR_IO}); + + Reply reply; + + // Don't log the full "SESSION CREATE ..." because it contains our private key. + reply.request = request.substr(0, 14) == "SESSION CREATE" ? "SESSION CREATE ..." : request; + + // It could take a few minutes for the I2P router to reply as it is querying the I2P network + // (when doing name lookup, for example). + + reply.full = sock.RecvUntilTerminator('\n', std::chrono::minutes{3}, MAX_MSG_SIZE); + + for (const auto& kv : spanparsing::Split(reply.full, ' ')) { + const auto& pos = std::find(kv.begin(), kv.end(), '='); + if (pos != kv.end()) { + reply.keys.emplace(std::string{kv.begin(), pos}, std::string{pos + 1, kv.end()}); + } else { + reply.keys.emplace(std::string{kv.begin(), kv.end()}, boost::none); + } + } + + LogPrint("i2p","I2P: Handshake reply %s\n", reply.full); + + if (check_result_ok && reply.Get("RESULT") != "OK") { + if (!ShutdownRequested()) { + throw std::runtime_error(strprintf("Unexpected reply to \"%s\": \"%s\"", request, reply.full)); + } + } + + return reply; +} + +std::unique_ptr Session::Hello() const +{ + auto sock = CreateSock(m_control_host); + + if (!sock) { + throw std::runtime_error("Cannot create socket"); + } + + if (!ConnectSocketDirectly(m_control_host, *sock, nConnectTimeout)) { + throw std::runtime_error(strprintf("Cannot connect to %s", m_control_host.ToString())); + } + + SendRequestAndGetReply(*sock, "HELLO VERSION MIN=3.1 MAX=3.1"); + + return sock; +} + +void Session::CheckControlSock() +{ + LOCK(cs_i2p); + + std::string errmsg; + if (!m_control_sock->IsConnected(errmsg)) { + LogPrint("i2p","I2P: Control socket error: %s\n", errmsg); + Disconnect(); + } +} + +void Session::DestGenerate(const Sock& sock) +{ + // https://geti2p.net/spec/common-structures#key-certificates + // "7" or "EdDSA_SHA512_Ed25519" - "Recent Router Identities and Destinations". + // Use "7" because i2pd <2.24.0 does not recognize the textual form. + const Reply& reply = SendRequestAndGetReply(sock, "DEST GENERATE SIGNATURE_TYPE=7", false); + + m_private_key = DecodeI2PBase64(reply.Get("PRIV")); +} + +void Session::GenerateAndSavePrivateKey(const Sock& sock) +{ + DestGenerate(sock); + + // umask is set to 077 in init.cpp, which is ok (unless -sysperms is given) + if (!WriteBinaryFile(m_private_key_file, + std::string(m_private_key.begin(), m_private_key.end()))) { + throw std::runtime_error( + strprintf("Cannot save I2P private key to %s", m_private_key_file)); + } +} + +Binary Session::MyDestination() const +{ + // From https://geti2p.net/spec/common-structures#destination: + // "They are 387 bytes plus the certificate length specified at bytes 385-386, which may be + // non-zero" + static constexpr size_t DEST_LEN_BASE = 387; + static constexpr size_t CERT_LEN_POS = 385; + + uint16_t cert_len; + memcpy(&cert_len, &m_private_key.at(CERT_LEN_POS), sizeof(cert_len)); + cert_len = be16toh(cert_len); + + const size_t dest_len = DEST_LEN_BASE + cert_len; + + return Binary{m_private_key.begin(), m_private_key.begin() + dest_len}; +} + +void Session::CreateIfNotCreatedAlready() +{ + LOCK(cs_i2p); + + std::string errmsg; + if (m_control_sock->IsConnected(errmsg)) { + return; + } + + LogPrint("i2p","I2P: Creating SAM session with %s\n", m_control_host.ToString()); + + auto sock = Hello(); + + const std::pair i2pRead = ReadBinaryFile(m_private_key_file); + if (i2pRead.first) { + m_private_key.assign(i2pRead.second.begin(), i2pRead.second.end()); + } else { + GenerateAndSavePrivateKey(*sock); + } + + const std::string& session_id = GetRandHash().GetHex().substr(0, 10); // full is an overkill, too verbose in the logs + const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key)); + + SendRequestAndGetReply(*sock, strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s", + session_id, private_key_b64)); + + m_my_addr = CService(DestBinToAddr(MyDestination()), Params().GetDefaultPort()); + m_session_id = session_id; + m_control_sock = std::move(sock); + + LogPrint("i2p","I2P: SAM session created: session id=%s, my address=%s\n", m_session_id, + m_my_addr.ToString()); +} + +std::unique_ptr Session::StreamAccept() +{ + auto sock = Hello(); + + const Reply& reply = SendRequestAndGetReply( + *sock, strprintf("STREAM ACCEPT ID=%s SILENT=false", m_session_id), false); + + const std::string& result = reply.Get("RESULT"); + + if (result == "OK") { + return sock; + } + + if (result == "INVALID_ID") { + // If our session id is invalid, then force session re-creation on next usage. + Disconnect(); + } + + throw std::runtime_error(strprintf("\"%s\"", reply.full)); +} + +void Session::Disconnect() +{ + LOCK(cs_i2p); + try + { + if (m_control_sock->Get() != INVALID_SOCKET) { + if (m_session_id.empty()) { + LogPrint("i2p","I2P: Destroying incomplete session\n"); + } else { + LogPrint("i2p","I2P: Destroying session %s\n", m_session_id); + } + } + m_control_sock->Reset(); + m_session_id.clear(); + } + catch(std::bad_alloc&) + { + // when the node is shutting down, the call above might use invalid memory resulting in a + // std::bad_alloc exception when instantiating internal objs for handling log category + LogPrintf("(node is probably shutting down) Destroying session=%d\n", m_session_id); + } + + +} +} // namespace sam +} // namespace i2p diff --git a/src/i2p.h b/src/i2p.h new file mode 100644 index 000000000..8c1e0539c --- /dev/null +++ b/src/i2p.h @@ -0,0 +1,256 @@ +// Copyright (c) 2020-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Hush developers +// Distributed under the GPLv3 software license, see the accompanying +// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html + +#ifndef HUSH_I2P_H +#define HUSH_I2P_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace i2p { + +/** + * Binary data. + */ +using Binary = std::vector; + +/** + * An established connection with another peer. + */ +struct Connection { + /** Connected socket. */ + std::unique_ptr sock; + + /** Our I2P address. */ + CService me; + + /** The peer's I2P address. */ + CService peer; +}; + +namespace sam { + +/** + * The maximum size of an incoming message from the I2P SAM proxy (in bytes). + * Used to avoid a runaway proxy from sending us an "unlimited" amount of data without a terminator. + * The longest known message is ~1400 bytes, so this is high enough not to be triggered during + * normal operation, yet low enough to avoid a malicious proxy from filling our memory. + */ +static constexpr size_t MAX_MSG_SIZE{65536}; + +/** + * I2P SAM session. + */ +class Session +{ +public: + /** + * Construct a session. This will not initiate any IO, the session will be lazily created + * later when first used. + * @param[in] private_key_file Path to a private key file. If the file does not exist then the + * private key will be generated and saved into the file. + * @param[in] control_host Location of the SAM proxy. + */ + Session(const fs::path& private_key_file, + const CService& control_host); + + /** + * Destroy the session, closing the internally used sockets. The sockets that have been + * returned by `Accept()` or `Connect()` will not be closed, but they will be closed by + * the SAM proxy because the session is destroyed. So they will return an error next time + * we try to read or write to them. + */ + ~Session(); + + /** + * Check the control sock and restart if needed + */ + bool Check(); + + /** + * Start listening for an incoming connection. + * @param[out] conn Upon successful completion the `sock` and `me` members will be set + * to the listening socket and address. + * @return true on success + */ + bool Listen(Connection& conn); + + /** + * Wait for and accept a new incoming connection. + * @param[in,out] conn The `sock` member is used for waiting and accepting. Upon successful + * completion the `peer` member will be set to the address of the incoming peer. + * @return true on success + */ + bool Accept(Connection& conn); + + /** + * Connect to an I2P peer. + * @param[in] to Peer to connect to. + * @param[out] conn Established connection. Only set if `true` is returned. + * @param[out] proxy_error If an error occurs due to proxy or general network failure, then + * this is set to `true`. If an error occurs due to unreachable peer (likely peer is down), then + * it is set to `false`. Only set if `false` is returned. + * @return true on success + */ + bool Connect(const CService& to, Connection& conn, bool& proxy_error); + +protected: + + CCriticalSection cs_i2p; + +private: + /** + * A reply from the SAM proxy. + */ + struct Reply { + /** + * Full, unparsed reply. + */ + std::string full; + + /** + * Request, used for detailed error reporting. + */ + std::string request; + + /** + * A map of keywords from the parsed reply. + * For example, if the reply is "A=X B C=YZ", then the map will be + * keys["A"] == "X" + * keys["B"] == (empty std::optional) + * keys["C"] == "YZ" + */ + std::unordered_map> keys; + + /** + * Get the value of a given key. + * For example if the reply is "A=X B" then: + * Value("A") -> "X" + * Value("B") -> throws + * Value("C") -> throws + * @param[in] key Key whose value to retrieve + * @returns the key's value + * @throws std::runtime_error if the key is not present or if it has no value + */ + std::string Get(const std::string& key) const; + }; + + /** + * Send request and get a reply from the SAM proxy. + * @param[in] sock A socket that is connected to the SAM proxy. + * @param[in] request Raw request to send, a newline terminator is appended to it. + * @param[in] check_result_ok If true then after receiving the reply a check is made + * whether it contains "RESULT=OK" and an exception is thrown if it does not. + * @throws std::runtime_error if an error occurs + */ + Reply SendRequestAndGetReply(const Sock& sock, + const std::string& request, + bool check_result_ok = true) const; + + /** + * Open a new connection to the SAM proxy. + * @return a connected socket + * @throws std::runtime_error if an error occurs + */ + std::unique_ptr Hello() const EXCLUSIVE_LOCKS_REQUIRED(cs_i2p); + + /** + * Check the control socket for errors and possibly disconnect. + */ + void CheckControlSock(); + + /** + * Generate a new destination with the SAM proxy and set `m_private_key` to it. + * @param[in] sock Socket to use for talking to the SAM proxy. + * @throws std::runtime_error if an error occurs + */ + void DestGenerate(const Sock& sock) EXCLUSIVE_LOCKS_REQUIRED(cs_i2p); + + /** + * Generate a new destination with the SAM proxy, set `m_private_key` to it and save + * it on disk to `m_private_key_file`. + * @param[in] sock Socket to use for talking to the SAM proxy. + * @throws std::runtime_error if an error occurs + */ + void GenerateAndSavePrivateKey(const Sock& sock) EXCLUSIVE_LOCKS_REQUIRED(cs_i2p); + + /** + * Derive own destination from `m_private_key`. + * @see https://geti2p.net/spec/common-structures#destination + * @return an I2P destination + */ + Binary MyDestination() const EXCLUSIVE_LOCKS_REQUIRED(cs_i2p); + + /** + * Create the session if not already created. Reads the private key file and connects to the + * SAM proxy. + * @throws std::runtime_error if an error occurs + */ + void CreateIfNotCreatedAlready() EXCLUSIVE_LOCKS_REQUIRED(cs_i2p); + + /** + * Open a new connection to the SAM proxy and issue "STREAM ACCEPT" request using the existing + * session id. + * @return the idle socket that is waiting for a peer to connect to us + * @throws std::runtime_error if an error occurs + */ + std::unique_ptr StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(cs_i2p); + + /** + * Destroy the session, closing the internally used sockets. + */ + void Disconnect() EXCLUSIVE_LOCKS_REQUIRED(cs_i2p); + + /** + * The name of the file where this peer's private key is stored (in binary). + */ + const fs::path m_private_key_file; + + /** + * The host and port of the SAM control service. + */ + const CService m_control_host; + + /** + * The private key of this peer. + * @see The reply to the "DEST GENERATE" command in https://geti2p.net/en/docs/api/samv3 + */ + Binary m_private_key GUARDED_BY(cs_i2p); + + /** + * SAM control socket. + * Used to connect to the I2P SAM service and create a session + * ("SESSION CREATE"). With the established session id we later open + * other connections to the SAM service to accept incoming I2P + * connections and make outgoing ones. + * See https://geti2p.net/en/docs/api/samv3 + */ + std::unique_ptr m_control_sock GUARDED_BY(cs_i2p); + + /** + * Our .b32.i2p address. + * Derived from `m_private_key`. + */ + CService m_my_addr GUARDED_BY(cs_i2p); + + /** + * SAM session id. + */ + std::string m_session_id GUARDED_BY(cs_i2p); +}; + +} // namespace sam +} // namespace i2p + +#endif /* HUSH_I2P_H */ diff --git a/src/init.cpp b/src/init.cpp index 6fe9c9299..ed9359f2c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -246,14 +246,22 @@ void Shutdown() if (pcoinsTip != NULL) { FlushStateToDisk(); } - delete pcoinsTip; - pcoinsTip = NULL; - delete pcoinscatcher; - pcoinscatcher = NULL; - delete pcoinsdbview; - pcoinsdbview = NULL; - delete pblocktree; - pblocktree = NULL; + if (pcoinsTip != NULL) { + delete pcoinsTip; + pcoinsTip = NULL; + } + if (pcoinscatcher != NULL) { + delete pcoinscatcher; + pcoinscatcher = NULL; + } + if (pcoinsdbview != NULL) { + delete pcoinsdbview; + pcoinsdbview = NULL; + } + if (pblocktree != NULL) { + delete pblocktree; + pblocktree = NULL; + } } #ifdef ENABLE_WALLET if (pwalletMain) @@ -274,7 +282,7 @@ void Shutdown() #endif globalVerifyHandle.reset(); ECC_Stop(); - CNode::NetCleanup(); + // CNode::NetCleanup(); LogPrintf("%s: done\n", __func__); } @@ -325,7 +333,7 @@ bool static InitWarning(const std::string &str) } bool static Bind(const CService &addr, unsigned int flags) { - if (!(flags & BF_EXPLICIT) && IsLimited(addr)) + if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) return false; std::string strError; if (!BindListenPort(addr, strError, (flags & BF_ALLOWLIST) != 0)) { @@ -416,7 +424,14 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), 5000)); strUsage += HelpMessageOpt("-maxsendbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), 1000)); strUsage += HelpMessageOpt("-onion=", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); - strUsage += HelpMessageOpt("-onlynet=", _("Only connect to nodes in network (ipv4, ipv6 or onion)")); + strUsage += HelpMessageOpt("-nspv_msg", strprintf(_("Enable NSPV messages processing (default: true when -ac_private=1, otherwise false)"))); + + strUsage += HelpMessageOpt("-i2psam=", strprintf(_("I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)"))); + strUsage += HelpMessageOpt("-i2pacceptincoming", strprintf(_("If set and -i2psam is also set then incoming I2P connections are accepted via the SAM proxy. If this is not set but -i2psam is set then only outgoing connections will be made to the I2P network. Ignored if -i2psam is not set. Listening for incoming I2P connections is done through the SAM proxy, not by binding to a local address and port (default: 1)"))); + strUsage += HelpMessageOpt("-onlynet=", _("Only connect to nodes in network (ipv4, ipv6, onion or i2p)")); + strUsage += HelpMessageOpt("-disableipv4", _("Disable Ipv4 network connections") + " " + _("(default: 0)")); + strUsage += HelpMessageOpt("-disableipv6", _("Disable Ipv6 network connections") + " " + _("(default: 0)")); + strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with Bloom filters (default: %u)"), 1)); if (showDebug) @@ -1609,14 +1624,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) for (int n = 0; n < NET_MAX; n++) { enum Network net = (enum Network)n; if (!nets.count(net)) - SetLimited(net); + SetReachable(net, false); } } //fprintf(stderr,"%s tik19\n", __FUNCTION__); if (mapArgs.count("-allowlist")) { BOOST_FOREACH(const std::string& net, mapMultiArgs["-allowlist"]) { - CSubNet subnet(net); + CSubNet subnet; + LookupSubNet(net.c_str(), subnet); if (!subnet.IsValid()) return InitError(strprintf(_("Invalid netmask specified in -allowlist: '%s'"), net)); CNode::AddAllowlistedRange(subnet); @@ -1627,9 +1643,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // -proxy sets a proxy for all outgoing network traffic // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default std::string proxyArg = GetArg("-proxy", ""); - SetLimited(NET_ONION); + SetReachable(NET_ONION,false); if (proxyArg != "" && proxyArg != "0") { - proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize); + CService resolved(LookupNumeric(proxyArg.c_str(), 9050)); + proxyType addrProxy = proxyType(resolved, proxyRandomize); if (!addrProxy.IsValid()) return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg)); @@ -1637,9 +1654,20 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) SetProxy(NET_IPV6, addrProxy); SetProxy(NET_ONION, addrProxy); SetNameProxy(addrProxy); - SetLimited(NET_ONION, false); // by default, -proxy sets onion as reachable, unless -noonion later + SetReachable(NET_ONION, true); // by default, -proxy sets onion as reachable, unless -noonion later + } + + const std::string& i2psam_arg = GetArg("-i2psam", ""); + if (!i2psam_arg.empty()) { + CService addr; + if (!Lookup(i2psam_arg.c_str(), addr, 7656, fNameLookup) || !addr.IsValid()) { + return InitError(strprintf(_("Invalid -i2psam address or hostname: '%s'"), i2psam_arg)); + } + SetReachable(NET_I2P, true); + SetProxy(NET_I2P, proxyType{addr}); + } else { + SetReachable(NET_I2P, false); } - //fprintf(stderr,"%s tik20\n", __FUNCTION__); // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses // -noonion (or -onion=0) disables connecting to .onion entirely @@ -1647,13 +1675,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::string onionArg = GetArg("-onion", ""); if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 - SetLimited(NET_ONION); // set onions as unreachable + SetReachable(NET_ONION,false); // set onions as unreachable } else { - proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize); + CService resolved(LookupNumeric(onionArg.c_str(), 9050)); + proxyType addrOnion = proxyType(resolved, proxyRandomize); if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg)); SetProxy(NET_ONION, addrOnion); - SetLimited(NET_ONION, false); + SetReachable(NET_ONION, true); } } @@ -1692,10 +1721,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-externalip")) { BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) { - CService addrLocal(strAddr, GetListenPort(), fNameLookup); - if (!addrLocal.IsValid()) + CService addrLocal; + if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) { + AddLocal(addrLocal, LOCAL_MANUAL); + } else { return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); - AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL); + } } } diff --git a/src/key_io.cpp b/src/key_io.cpp index c3d5471d5..88477a834 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -9,7 +9,7 @@ #include #include #include