Compare commits
6
Commits
5634aed750
..
v1.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da191e447d | ||
|
|
fc26e2e0a0 | ||
|
|
1d2d5f32d0 | ||
|
|
c1040028e4 | ||
|
|
a6b6f80db0 | ||
|
|
3aac75e94f |
@@ -3,7 +3,7 @@
|
||||
.SH NAME
|
||||
dragonx-cli \- manual page for dragonx-cli v1.3.0
|
||||
.SH DESCRIPTION
|
||||
DragonX RPC client version v1.3.0\-af7d9e230
|
||||
DragonX RPC client version v1.3.0
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
DragonX, please see <https://dragonx.is/security/>.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.SH NAME
|
||||
dragonx-tx \- manual page for dragonx-tx v1.3.0
|
||||
.SH DESCRIPTION
|
||||
hush\-tx utility version v1.3.0\-af7d9e230
|
||||
hush\-tx utility version v1.3.0
|
||||
.SS "Usage:"
|
||||
.TP
|
||||
hush\-tx [options] <hex\-tx> [commands]
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
.SH NAME
|
||||
dragonxd \- manual page for dragonxd v1.3.0
|
||||
.SH DESCRIPTION
|
||||
DragonX Daemon version v1.3.0\-af7d9e230
|
||||
DragonX Daemon version v1.3.0
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
DragonX, please see <https://dragonx.is/security/>.
|
||||
|
||||
+6
-2
@@ -257,14 +257,18 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
|
||||
event_base_dispatch(base.get());
|
||||
|
||||
if (response.status == 0) {
|
||||
// Report the port we ACTUALLY dialled. ASSETCHAINS_RPCPORT is a separate global that is
|
||||
// initialised to the mainnet default at the top of this file and never assigned here, so
|
||||
// using it made every failure claim port 21769 no matter what -rpcport was given -- which
|
||||
// reads as "your -rpcport was ignored" and sends you chasing a config bug that isn't there.
|
||||
throw CConnectionFailed(strprintf("couldn't connect to server at port %d : %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)",
|
||||
ASSETCHAINS_RPCPORT, http_errorstring(response.error), response.error));
|
||||
port, http_errorstring(response.error), response.error));
|
||||
} else if (response.status == HTTP_UNAUTHORIZED) {
|
||||
throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
|
||||
} else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) {
|
||||
throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
|
||||
} else if (response.body.empty()) {
|
||||
throw std::runtime_error(strprintf("no response from server at port %d", ASSETCHAINS_RPCPORT ));
|
||||
throw std::runtime_error(strprintf("no response from server at port %d", port));
|
||||
}
|
||||
|
||||
// Parse reply
|
||||
|
||||
+13
-2
@@ -2654,8 +2654,19 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
nStart = GetTimeMillis();
|
||||
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
|
||||
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
|
||||
pwalletMain->SetBestChain(chainActive.GetLocator());
|
||||
nWalletDBUpdated++;
|
||||
// ONLY record "scanned to the tip" if the scan actually reached it. An aborted or
|
||||
// shutdown-interrupted scan that stamps a tip locator tells the next startup there is
|
||||
// nothing left to scan (the chainActive.Tip() != pindexRescan guard above then skips
|
||||
// the rescan entirely), so every transaction in the unscanned range stays out of
|
||||
// mapWallet permanently: invisible to getbalance and unspendable. The scan writes its
|
||||
// own locator at the interrupt point instead.
|
||||
if (pwalletMain->fLastRescanCompleted) {
|
||||
pwalletMain->SetBestChain(chainActive.GetLocator());
|
||||
nWalletDBUpdated++;
|
||||
} else {
|
||||
LogPrintf("Rescan did not complete; leaving the best-block locator at the scan's own "
|
||||
"checkpoint so the remaining range is rescanned on the next start\n");
|
||||
}
|
||||
|
||||
// Restore wallet transaction metadata after -zapwallettxes=1
|
||||
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
|
||||
|
||||
+7
-1
@@ -22,7 +22,13 @@
|
||||
|
||||
// network protocol versioning
|
||||
// DragonX 1.0.0 - bumped to separate from old HUSH/DragonX nodes with RandomX bug
|
||||
static const int PROTOCOL_VERSION = 2000000;
|
||||
// DragonX 1.3.0 - bumped for the consensus changes in this release (BLOCK_VALID_CONTEXT
|
||||
// no longer overwrites the validity level, the dead CBOPRET coinbase
|
||||
// price check is gone, and pow.cpp lost 157 lines). MIN_PEER_PROTO_VERSION
|
||||
// is deliberately NOT raised: it currently equals this value, and raising
|
||||
// it would disconnect every node still on v1.0.3 -- which is all users,
|
||||
// since no release has ever been installable (unsigned archives).
|
||||
static const int PROTOCOL_VERSION = 2000001;
|
||||
//! initial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
//! In this version, 'getheaders' was introduced.
|
||||
|
||||
+74
-6
@@ -801,10 +801,18 @@ bool CWallet::CommitAutomatedTx(const CTransaction& tx) {
|
||||
|
||||
void CWallet::SetBestChain(const CBlockLocator& loc)
|
||||
{
|
||||
// Default ctor => fFlushOnClose=true => ~CDB runs a full BDB txn_checkpoint over the entire
|
||||
// cache. Fine for the hourly/shutdown callers; ruinous inside a scan (see SetBestChainNoFlush).
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
SetBestChainINTERNAL(walletdb, loc);
|
||||
}
|
||||
|
||||
bool CWallet::SetBestChainNoFlush(const CBlockLocator& loc)
|
||||
{
|
||||
CWalletDB walletdb(strWalletFile, "r+", false);
|
||||
return SetBestChainINTERNAL(walletdb, loc);
|
||||
}
|
||||
|
||||
std::set<std::pair<libzcash::PaymentAddress, uint256>> CWallet::GetNullifiersForAddresses(
|
||||
const std::set<libzcash::PaymentAddress> & addresses)
|
||||
{
|
||||
@@ -1436,8 +1444,9 @@ void CWallet::BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly)
|
||||
return;
|
||||
}
|
||||
if (pwalletMain->fAbortRescan) {
|
||||
// Do NOT clear fRescanning here: a witness rebuild is not a rescan, and clearing it from
|
||||
// this path desynchronises the flag from ScanForWalletTransactions, which owns it.
|
||||
LogPrintf("%s: rescan aborted during witness rebuild\n", __func__);
|
||||
pwalletMain->fRescanning = false;
|
||||
return;
|
||||
}
|
||||
int h = pbi->GetHeight();
|
||||
@@ -3434,6 +3443,12 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
if(fZdebug)
|
||||
LogPrintf("%s: fUpdate=%d now=%li\n",__func__,fUpdate,nNow);
|
||||
|
||||
// fAbortRescan is sticky: nothing else in the tree ever clears it, so without this a single
|
||||
// `abortrescan` RPC would disable every later scan AND every later BuildWitnessCache for the
|
||||
// lifetime of the process (BuildWitnessCache bails on the same flag), freezing witness heights
|
||||
// while the chain advances and progressively rendering notes unspendable.
|
||||
pwalletMain->fAbortRescan = false;
|
||||
pwalletMain->fLastRescanCompleted = false;
|
||||
pwalletMain->fRescanning = true;
|
||||
CBlockIndex* pindex = pindexStart;
|
||||
pwalletMain->rescanStartHeight = pindex->GetHeight();
|
||||
@@ -3448,6 +3463,51 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
pwalletMain->rescanHeight = pindex ? pindex->GetHeight() : 0;
|
||||
}
|
||||
|
||||
// --- interrupt checkpoint setup -------------------------------------------------------
|
||||
// Where does the wallet currently believe it has scanned to? A checkpoint may only ever
|
||||
// ADVANCE that point, and only if this scan is contiguous with it. The RPC entry points
|
||||
// (rescan / importprivkey / z_importkey / z_importviewingkey) take a caller-supplied start
|
||||
// height validated only against chainActive.Height(), so a scan can legitimately begin far
|
||||
// ABOVE the persisted locator -- writing a checkpoint from such a scan would mark the
|
||||
// skipped range as scanned and hide any funds in it.
|
||||
CBlockIndex* pindexPersisted = NULL;
|
||||
{
|
||||
CWalletDB walletdb(strWalletFile, "r+", false);
|
||||
CBlockLocator locPersisted;
|
||||
if (walletdb.ReadBestBlock(locPersisted))
|
||||
pindexPersisted = FindForkInGlobalIndex(chainActive, locPersisted);
|
||||
}
|
||||
const bool fMayCheckpoint = pindexPersisted != NULL &&
|
||||
pindexStart->GetHeight() <= pindexPersisted->GetHeight() + 1;
|
||||
if (!fMayCheckpoint) {
|
||||
LogPrintf("%s: scan starts at %d but the wallet is persisted at %d; progress will NOT be "
|
||||
"checkpointed on interrupt (a non-contiguous scan cannot safely advance the locator)\n",
|
||||
__func__, pindexStart->GetHeight(),
|
||||
pindexPersisted ? pindexPersisted->GetHeight() : -1);
|
||||
}
|
||||
|
||||
// Persist progress when the scan is cut short. `pindexStopped` is the block we were ABOUT to
|
||||
// scan, so the last fully-processed block is its parent. Resume restarts AT the locator's own
|
||||
// block (CChain::GetLocator pushes it first; FindForkInGlobalIndex returns it), giving one
|
||||
// block of deliberate overlap -- idempotent, because AddToWallet only merges when the tx is
|
||||
// already present. No witness work is needed: witnesses are re-derived from each note's own
|
||||
// witnessHeight, and witnessRootValidated is in-memory-only so every note is revalidated
|
||||
// against hashFinalSaplingRoot on the next start.
|
||||
auto checkpointProgress = [&](const CBlockIndex* pindexStopped) {
|
||||
if (!fMayCheckpoint || !pindexStopped || !pindexStopped->pprev)
|
||||
return;
|
||||
const CBlockIndex* pindexDone = pindexStopped->pprev;
|
||||
if (pindexDone->GetHeight() <= pindexPersisted->GetHeight())
|
||||
return; // never move the locator backwards
|
||||
if (SetBestChainNoFlush(chainActive.GetLocator(pindexDone))) {
|
||||
LogPrintf("%s: checkpointed scan progress at height %d\n", __func__, pindexDone->GetHeight());
|
||||
} else {
|
||||
LogPrintf("%s: FAILED to checkpoint scan progress at height %d; the scan will replay "
|
||||
"from height %d on the next start\n", __func__, pindexDone->GetHeight(),
|
||||
pindexPersisted->GetHeight());
|
||||
}
|
||||
};
|
||||
|
||||
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
|
||||
double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false);
|
||||
double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip(), false);
|
||||
@@ -3456,15 +3516,20 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
{
|
||||
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;
|
||||
// The witness caches do NOT need updating here: on resume each note's witnesses are
|
||||
// re-derived from its own witnessHeight, independently of the locator, and
|
||||
// witnessRootValidated is in-memory-only so a full validation pass runs next boot.
|
||||
// What DOES need saving is the locator -- see the checkpoint below.
|
||||
pwalletMain->fRescanning = false;
|
||||
pwalletMain->fAbortRescan = false; // consume it; see the note at scan entry
|
||||
LogPrintf("%s: Rescan aborted at block %d\n", __func__, pwalletMain->rescanHeight);
|
||||
checkpointProgress(pindex);
|
||||
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;
|
||||
LogPrintf("%s: Rescan interrupted by shutdown request at block %d\n", __func__, pwalletMain->rescanHeight);
|
||||
checkpointProgress(pindex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3525,6 +3590,9 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
|
||||
// we are no longer rescanning
|
||||
pwalletMain->fRescanning = false;
|
||||
// Reached only by running the loop to the end of the active chain. Callers use this to decide
|
||||
// whether it is honest to record the wallet as scanned up to the tip.
|
||||
pwalletMain->fLastRescanCompleted = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+23
-9
@@ -833,6 +833,10 @@ public:
|
||||
bool fAutoShieldRunning = false;
|
||||
|
||||
std::atomic<bool> fAbortRescan{false};
|
||||
//! True only when the last ScanForWalletTransactions ran to completion. An aborted or
|
||||
//! shutdown-interrupted scan leaves this false, so callers must not record the wallet as
|
||||
//! scanned up to the chain tip -- doing so makes the unscanned range permanently invisible.
|
||||
bool fLastRescanCompleted = false;
|
||||
// abort current rescan
|
||||
void AbortRescan() { fAbortRescan = true; }
|
||||
// Are we currently aborting a rescan?
|
||||
@@ -904,17 +908,22 @@ protected:
|
||||
*/
|
||||
void DecrementNoteWitnesses(const CBlockIndex* pindex);
|
||||
|
||||
//! Returns true only if the atomic write actually committed. Callers that checkpoint during a
|
||||
//! long scan need to know: a silently-failing checkpoint would otherwise be retried forever at
|
||||
//! full cost while never making progress.
|
||||
template <typename WalletDB>
|
||||
void SetBestChainINTERNAL(WalletDB& walletdb, const CBlockLocator& loc) {
|
||||
bool SetBestChainINTERNAL(WalletDB& walletdb, const CBlockLocator& loc) {
|
||||
if (!walletdb.TxnBegin()) {
|
||||
// This needs to be done atomically, so don't do it at all
|
||||
LogPrintf("SetBestChain(): Couldn't start atomic write\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
LOCK(cs_wallet);
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
auto wtx = wtxItem.second;
|
||||
// By reference: a copy here deep-copies every note's witness deque
|
||||
// (WITNESS_CACHE_SIZE entries) for every transaction, on every call.
|
||||
const CWalletTx& wtx = wtxItem.second;
|
||||
// We skip transactions for which mapSaplingNoteData
|
||||
// is empty. This covers transactions that have no Sapling data
|
||||
// (i.e. are purely transparent), as well as shielding and unshielding
|
||||
@@ -923,32 +932,33 @@ protected:
|
||||
if (!walletdb.WriteTx(wtxItem.first, wtx)) {
|
||||
LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n");
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!walletdb.WriteWitnessCacheSize(nWitnessCacheSize)) {
|
||||
LogPrintf("SetBestChain(): Failed to write nWitnessCacheSize, aborting atomic write\n");
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!walletdb.WriteBestBlock(loc)) {
|
||||
LogPrintf("SetBestChain(): Failed to write best block, aborting atomic write\n");
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
} catch (const std::exception &exc) {
|
||||
// Unexpected failure
|
||||
LogPrintf("SetBestChain(): Unexpected error during atomic write:\n");
|
||||
LogPrintf("%s\n", exc.what());
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!walletdb.TxnCommit()) {
|
||||
// Couldn't commit all to db, but in-memory state is fine
|
||||
LogPrintf("SetBestChain(): Couldn't commit atomic write\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1282,8 +1292,12 @@ public:
|
||||
void RunSaplingConsolidation(int blockHeight);
|
||||
void RunAutoShieldCoinbase(int blockHeight);
|
||||
bool CommitAutomatedTx(const CTransaction& tx);
|
||||
/** Saves witness caches and best block locator to disk. */
|
||||
/** Saves witness caches and best block locator to disk. Overrides CValidationInterface. */
|
||||
void SetBestChain(const CBlockLocator& loc);
|
||||
/** As SetBestChain, but for use INSIDE a long scan: opens the wallet DB with fFlushOnClose=false
|
||||
* so the call does not trigger a full BDB txn_checkpoint over the whole cache (see the comment
|
||||
* at CWallet::SetBestChain), and reports whether the write actually committed. */
|
||||
bool SetBestChainNoFlush(const CBlockLocator& loc);
|
||||
std::set<std::pair<libzcash::PaymentAddress, uint256>> GetNullifiersForAddresses(const std::set<libzcash::PaymentAddress> & addresses);
|
||||
bool IsNoteSaplingChange(const std::set<std::pair<libzcash::PaymentAddress, uint256>> & nullifierSet, const libzcash::PaymentAddress & address, const SaplingOutPoint & entry);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user