Compare commits

...

18 Commits

Author SHA1 Message Date
Duke
a7939139b2 Merge remote-tracking branch 'origin/abortrescan' into dev
Conflicts:
	src/wallet/wallet.cpp
2023-02-05 18:16:36 -08:00
Duke
9977e12acf Merge branch 'dragonx' into dev 2023-02-05 18:08:40 -08:00
Duke Leto
01ff5c81f6 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.
2022-12-06 14:23:53 -05:00
Duke Leto
b7adb511a6 cleanup 2022-11-15 19:13:31 -05:00
Duke Leto
665f895134 Optimize inner mining loop 2022-11-15 14:40:10 -05:00
Duke Leto
c8b2163c1c Optimize inner mining loop 2022-11-15 14:21:45 -05:00
Duke Leto
1a4e8d4acf Initialize randomx dataset with 2 threads 2022-11-15 14:11:55 -05:00
Duke Leto
c55d1cbc5f Destroy randomx VM when we are done with it 2022-11-15 14:02:02 -05:00
Duke Leto
d3b948005c indentation 2022-11-15 13:44:47 -05:00
Duke Leto
3dbe8d3c6b indentation 2022-11-15 13:43:10 -05:00
Duke Leto
0926dfca75 Merge branch 'duke' into awt 2022-11-12 09:25:36 -05:00
Duke Leto
81f0c7755e Code to test exact cause of the 'up only' diff bug 2022-11-12 09:22:10 -05:00
Duke Leto
c108db8f3c 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.
2022-11-11 06:42:51 -05:00
Duke Leto
b94ec80307 Use RANDOMX_FLAG_FULL_MEM 2022-11-10 22:38:04 -05:00
Duke Leto
c81b49c96c fix params for testcoins 2022-11-08 09:55:46 -05:00
Duke Leto
24dc8252a3 Add scripts to research randomx difficulty problems 2022-11-08 09:29:05 -05:00
Duke Leto
591b9e4c7d Merge branch 'dev' into duke 2022-11-08 09:17:00 -05:00
Duke Leto
6fda12612d Initial implementation of abortrescan 2022-10-19 05:12:12 -04:00
9 changed files with 208 additions and 56 deletions

View File

@ -1067,6 +1067,42 @@ void static RandomXMiner()
);
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;
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");
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;
}
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);
@ -1115,6 +1151,38 @@ void static RandomXMiner()
Mining_height = pindexPrev->GetHeight()+1;
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
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
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);
if(myVM == NULL) {
LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n");
return;
}
//fprintf(stderr,"RandomXMiner: Mining_start=%u\n", Mining_start);
#ifdef ENABLE_WALLET
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, pindexPrev->GetHeight()+1, gpucount, 0);
@ -1168,6 +1236,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));
@ -1181,8 +1250,8 @@ void static RandomXMiner()
HASHTarget = arith_uint256().SetCompact(savebits);
roundrobin_delay = ROUNDROBIN_DELAY;
Mining_start = 0;
gotinvalid = 0;
while (true)
{
if ( gotinvalid != 0 ) {
@ -1196,13 +1265,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^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;
@ -1211,49 +1273,9 @@ 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
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());
}
randomx_vm *myVM = randomx_create_vm(flags, randomxCache, NULL);
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("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,8 +1285,8 @@ void static RandomXMiner()
printf("\n");
}
// Use randomx hash to build a valid block
// Use randomx hash to build a valid block
std::function<bool(std::vector<unsigned char>)> validBlock =
#ifdef ENABLE_WALLET
[&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams]
@ -1277,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());
@ -1371,7 +1393,14 @@ 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");
}
} catch (const boost::thread_interrupted&) {
miningTimer.stop();
c.disconnect();
@ -1383,6 +1412,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();
}
@ -1646,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--)
@ -1859,6 +1893,7 @@ void static BitcoinMiner()
LogPrintf("HushMiner runtime error: %s\n", e.what());
return;
}
miningTimer.stop();
c.disconnect();
}

View File

@ -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
@ -526,7 +527,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) ;
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);

13
src/testdragonx-cli Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Copyright 2016-2022 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
./hush-cli -ac_name=TESTDRAGONX $@

17
src/testdragonxd Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Copyright 2016-2022 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
BLOCKTIME=18
SUPPLY=0
# Remember Remember the 5th November for freedom of speech is not free!!
./hush-smart-chain -ac_name=TESTDRAGONX -ac_algo=randomx -ac_halving=3500000 -ac_reward=300000000 -ac_blocktime=$BLOCKTIME -ac_private=1 -ac_supply=$SUPPLY -debug=randomx $@

13
src/testequihash-cli Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Copyright 2016-2022 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
./hush-cli -ac_name=TESTEQUIHASH $@

18
src/testequihashd Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Copyright 2016-2022 The Hush Developers
# Copyright 2022 The DragonX Developers
# Released under the GPLv3
# set working directory to the location of this script
# readlink -f does not always exist
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
cd $DIR
BLOCKTIME=18
SUPPLY=0
# same as TESTDRAGONX except equihash and different ac_name
# and debug=pow which is the equivalent of debug=randomx for equihash mining
./hush-smart-chain -ac_name=TESTEQUIHASH -ac_halving=3500000 -ac_reward=300000000 -ac_blocktime=$BLOCKTIME -ac_private=1 -ac_supply=$SUPPLY -debug=pow $@

View File

@ -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))

View File

@ -2780,6 +2780,20 @@ 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))));

View File

@ -807,6 +807,13 @@ public:
bool fSweepEnabled = false;
bool fSweepExternalEnabled = false;
bool fSweepRunning = false;
std::atomic<bool> 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