Files
dragonx/src/wallet/asyncrpcoperation_sweep.h
T
DanSandClaude Opus 4.8 4d72e5fc30 wallet: fix sweep-scheduler wedge and unsynchronized driver mutation
The zaddr-sweep op cleared fSweepRunning/nextSweep only on the sweepComplete
success path (inside main_impl), so a cancelled or throwing sweep left
fSweepRunning stuck true. Since fSweepRunning now also gates consolidation and
the default-on autoshield, a persistently failing sweep (e.g. a corrupt-witness
note) would wedge all three background ops for the session.

Move the scheduler bookkeeping into main() so it runs on every terminal state
(success/failure/exception/cancel), guarded by op id. Preserve the intended
"keep draining every block until swept" model: on a successful-but-incomplete
round the flag stays set and nextSweep is not advanced; on completion OR on
failure/exception the flag is released and nextSweep backs off one interval, so
a failing sweep no longer retries every block or wedges the other ops.

Also fix RunSaplingSweep to take cs_wallet itself (was AssertLockHeld, a no-op
in release builds) since ChainTip does not hold it there and the driver mutates
scheduler state + enqueues -- matching RunSaplingConsolidation and
RunAutoShieldCoinbase.

sweepComplete is recorded via a new member; saplingSweepOperationId made public.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-21 18:55:16 -05:00

47 lines
1.7 KiB
C++

// Copyright (c) 2016-2024 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 "amount.h"
#include "asyncrpcoperation.h"
#include "univalue.h"
#include "zcash/Address.hpp"
#include "zcash/zip32.h"
//Default fee used for sweep transactions
static const CAmount DEFAULT_SWEEP_FEE = 10000;
extern CAmount fSweepTxFee;
extern bool fSweepMapUsed;
extern boost::optional<libzcash::SaplingPaymentAddress> rpcSweepAddress;
class AsyncRPCOperation_sweep : public AsyncRPCOperation
{
public:
AsyncRPCOperation_sweep(int targetHeight, bool fromRpc = false);
virtual ~AsyncRPCOperation_sweep();
// We don't want to be copied or moved around
AsyncRPCOperation_sweep(AsyncRPCOperation_sweep const&) = delete; // Copy construct
AsyncRPCOperation_sweep(AsyncRPCOperation_sweep&&) = delete; // Move construct
AsyncRPCOperation_sweep& operator=(AsyncRPCOperation_sweep const&) = delete; // Copy assign
AsyncRPCOperation_sweep& operator=(AsyncRPCOperation_sweep&&) = delete; // Move assign
virtual void main();
virtual void cancel();
virtual UniValue getStatus() const;
private:
int targetHeight_;
bool fromRPC_;
// Set by main_impl(): true iff there was nothing left to sweep this round.
// Read by main() to decide scheduler bookkeeping. Defaults false so an
// exception (which skips main_impl's assignment) is treated as "not done".
bool sweepComplete_ = false;
bool main_impl();
void setSweepResult(int numTxCreated, const CAmount& amountSwept, const std::vector<std::string>& sweepTxIds);
};