On this ac_private=1 chain miners accumulate one transparent coinbase UTXO per block (the only transparent output the chain permits). It had to be shielded manually via z_shieldcoinbase, and left unshielded it is the sole persistent metadata leak on the chain and the source of miner UTXO-fragmentation send failures. Add AsyncRPCOperation_autoshieldcoinbase: a periodic, default-on wallet op driven from CWallet::ChainTip alongside sweep/consolidation, draining matured coinbase into a wallet-owned Sapling z-address in size-bounded batches. - Enqueue-only driver (RunAutoShieldCoinbase): takes only cs_wallet in the notify context; all gathering runs on the async worker under LOCK2(cs_main, cs_wallet). - Dedicated op (not a reuse of z_shieldcoinbase) so it never toggles mining. - Default-ON but conditional: silent no-op on -disablewallet, external -mineraddress, non-mining, or locked wallets (explicit IsLocked() guard). - Destination is reuse-then-create; -autoshieldaddress override is spend-key-validated at init so funds cannot be stranded. - Sweep-model bookkeeping: advances nextAutoShield and clears the running flag on every terminal state; an op-id guard stops a stale op clobbering scheduler state; a self-guard stops cancel/re-enqueue churn. - Sietch-padded output shape matches manual z_shieldcoinbase txns. Config: -autoshield (default true), -autoshieldinterval, -autoshieldaddress, -autoshieldfee (range-validated), -autoshieldminutxos. Incorporates fixes from an 8-angle code review: CAmount fee type with init-time range validation, op-id-guarded flag bookkeeping, driver self-guard, and a tipHeight-consistent NU-activation guard. Note: the fConsolidationRunning / nextConsolidation consolidation-scheduler wedge is a pre-existing bug, left for a separate change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
2.5 KiB
C++
59 lines
2.5 KiB
C++
// Copyright (c) 2016-2024 The Hush developers
|
|
// Copyright (c) 2024-2026 The DragonX developers
|
|
// Distributed under the GPLv3 software license, see the accompanying
|
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
#ifndef ASYNCRPCOPERATION_AUTOSHIELDCOINBASE_H
|
|
#define ASYNCRPCOPERATION_AUTOSHIELDCOINBASE_H
|
|
|
|
#include "amount.h"
|
|
#include "asyncrpcoperation.h"
|
|
#include "univalue.h"
|
|
#include "zcash/Address.hpp"
|
|
#include "zcash/zip32.h"
|
|
|
|
// Default fee for automatic coinbase-shielding transactions
|
|
static const CAmount DEFAULT_AUTOSHIELD_FEE = 10000;
|
|
|
|
// A periodic, wallet-local operation that drains matured *transparent* coinbase
|
|
// UTXOs into a wallet-owned Sapling z-address in size-bounded batches. It is the
|
|
// automatic sibling of the manual z_shieldcoinbase RPC and mirrors the dispatch
|
|
// model of AsyncRPCOperation_sweep (self-gathers on the async worker thread,
|
|
// commits via CWallet::CommitAutomatedTx). It never mints a transparent output,
|
|
// so it respects the ac_private=1 transparent-output ban, and it deliberately
|
|
// does NOT toggle mining (unlike z_shieldcoinbase) so it can run every interval
|
|
// on a mining node without thrashing the miner.
|
|
class AsyncRPCOperation_autoshieldcoinbase : public AsyncRPCOperation
|
|
{
|
|
public:
|
|
AsyncRPCOperation_autoshieldcoinbase(int targetHeight);
|
|
virtual ~AsyncRPCOperation_autoshieldcoinbase();
|
|
|
|
// We don't want to be copied or moved around
|
|
AsyncRPCOperation_autoshieldcoinbase(AsyncRPCOperation_autoshieldcoinbase const&) = delete;
|
|
AsyncRPCOperation_autoshieldcoinbase(AsyncRPCOperation_autoshieldcoinbase&&) = delete;
|
|
AsyncRPCOperation_autoshieldcoinbase& operator=(AsyncRPCOperation_autoshieldcoinbase const&) = delete;
|
|
AsyncRPCOperation_autoshieldcoinbase& operator=(AsyncRPCOperation_autoshieldcoinbase&&) = delete;
|
|
|
|
virtual void main();
|
|
virtual void cancel();
|
|
virtual UniValue getStatus() const;
|
|
|
|
private:
|
|
int targetHeight_;
|
|
int numTxCreated_ = 0;
|
|
CAmount amountShielded_ = 0;
|
|
std::vector<std::string> shieldTxIds_;
|
|
|
|
bool main_impl();
|
|
|
|
// Resolve a spendable, wallet-owned Sapling destination: the configured
|
|
// -autoshieldaddress if set, else the first spendable z-addr the wallet
|
|
// holds, else a freshly generated one (requires an unlocked wallet).
|
|
// Returns false if none is available (e.g. locked wallet with no z-addr).
|
|
bool resolveDestination(libzcash::SaplingPaymentAddress& destOut, std::string& destStrOut);
|
|
|
|
void setResult();
|
|
};
|
|
|
|
#endif /* ASYNCRPCOPERATION_AUTOSHIELDCOINBASE_H */
|