zcashd/src/validationinterface.h

172 lines
6.3 KiB
C
Raw Normal View History

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2016-2023 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#ifndef BITCOIN_VALIDATIONINTERFACE_H
#define BITCOIN_VALIDATIONINTERFACE_H
#include <optional>
#include <boost/signals2/signal.hpp>
#include <boost/shared_ptr.hpp>
#include "miner.h"
#include "zcash/IncrementalMerkleTree.hpp"
/**
* Limit on the maximum number of blocks that will be staged for
* scanning before an interrupt will be handled.
*/
static const size_t WALLET_NOTIFY_MAX_BLOCKS = 1000;
class CBlock;
class CBlockIndex;
struct CBlockLocator;
class CReserveScript;
class CTransaction;
class CValidationInterface;
class CValidationState;
class uint256;
class BatchScanner {
public:
/**
* Adds a transaction to the batch scanner.
*
* `block_tag` is the hash of the block that triggered this txid being added
* to the batch, or the all-zeros hash to indicate that no block triggered
* it (i.e. it was a mempool change).
*/
virtual void AddTransaction(
const CTransaction &tx,
const std::vector<unsigned char> &txBytes,
wallet: Domain-separate batched txids with a "block tag" Previously when a transaction was queried for batch trial decryption, we identified it by its txid. This is sufficient to uniquely identify the transaction within the wallet, but was _not_ sufficient to uniquely identify it within a `ThreadNotifyWallets` loop. In particular, when a reorg occurs, and the same transaction is present in blocks on both sides of the reorg (or is reorged into the mempool and then conflicted out): - The first occurrence would batch the transaction's outputs and store a result receiver. - The second occurrence would overwrite the first occurrence's result receiver with its own. - The first occurrence would read the second's result receiver (which has identical results to the first batch), removing it from the `pending_results` map. - The second occurrence would not find any receiver in the map, and would mark the transaction as having no decrypted results. We fix this by annotating each batched transaction with the hash of the block that triggered it being trial-decrypted: either the block being disconnected, the block being connected, or the null hash to indicate a new transaction in the mempool. This is sufficient to domain-separate all possible sources of duplicate txids: - If a transaction is moved to the mempool via a block disconnection, or from the mempool (either mined or conflicted) via a block connection, its txid will appear twice: once with the block in question's hash, and once with the null hash. - If a transaction is present in both a disconnected and a connected block (mined on both sides of the fork), its txid will appear twice: once each with the two block's txids. Both of the above rely on the assumption that block hashes are collision resistant, which in turn relies on SHA-256 being collision resistant.
2022-07-22 07:38:34 -07:00
const uint256 &blockTag,
const int nHeight) = 0;
/**
* Flushes any pending batches.
*
* After calling this, every transaction passed to `AddTransaction` should
* have its result available when the matching call to `SyncTransaction` is
* made.
*/
virtual void Flush() = 0;
/**
* Notifies the batch scanner of updated transaction data (transaction, and
* optionally the block it is found in).
*
* This will be called with transactions in the same order as they were
* `AddTransaction`.
*/
virtual void SyncTransaction(
const CTransaction &tx,
const CBlock *pblock,
const int nHeight) = 0;
};
struct MerkleFrontiers {
SproutMerkleTree sprout;
SaplingMerkleTree sapling;
OrchardMerkleFrontier orchard;
};
// These functions dispatch to one or all registered wallets
/** Register a wallet to receive updates from core */
void RegisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister a wallet from core */
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister all wallets from core */
void UnregisterAllValidationInterfaces();
class CValidationInterface {
protected:
virtual void UpdatedBlockTip(const CBlockIndex *pindex) {}
virtual BatchScanner* GetBatchScanner() { return nullptr; }
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock, const int nHeight) {}
virtual void EraseFromWallet(const uint256 &hash) {}
virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, std::optional<MerkleFrontiers> added) {}
virtual void UpdatedTransaction(const uint256 &hash) {}
virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
virtual void GetAddressForMining(std::optional<MinerAddress>&) {};
friend void ::RegisterValidationInterface(CValidationInterface*);
friend void ::UnregisterValidationInterface(CValidationInterface*);
friend void ::UnregisterAllValidationInterfaces();
};
// aggregate_non_null_values is a combiner which places any non-nullptr values
// returned from slots into a container.
template<typename Container>
struct aggregate_non_null_values
{
typedef Container result_type;
template<typename InputIterator>
Container operator()(InputIterator first, InputIterator last) const
{
Container values;
while (first != last) {
auto ptr = *first;
if (ptr != nullptr) {
values.push_back(ptr);
}
++first;
}
return values;
}
};
struct CMainSignals {
/** Notifies listeners of updated block chain tip */
boost::signals2::signal<void (const CBlockIndex *)> UpdatedBlockTip;
/**
* Requests a pointer to the listener's batch scanner for shielded outputs,
* if it has one.
*
* The listener is responsible for managing the memory of the batch scanner.
* In practice each listener will have a single persistent batch scanner.
*
* This signal is called at the start of each notification loop, which runs
* on integer second boundaries. This is an opportunity for the listener to
* perform any updating of the batch scanner's internal state (such as
* updating its set of incoming viewing keys).
*
* Listeners of this signal should not listen to `SyncTransaction` or they
* will be notified about transactions twice.
*/
boost::signals2::signal<
BatchScanner* (),
aggregate_non_null_values<std::vector<BatchScanner*>>> GetBatchScanner;
/**
2022-07-22 11:33:27 -07:00
* Notifies listeners of updated transaction data (the transaction, and
* optionally the block it is found in).
*
* Listeners of this signal should not listen to `GetBatchScanner` or they
* will be notified about transactions twice.
*/
boost::signals2::signal<void (const CTransaction &, const CBlock *, const int nHeight)> SyncTransaction;
/** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */
boost::signals2::signal<void (const uint256 &)> EraseTransaction;
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
/** Notifies listeners of a change to the tip of the active block chain. */
boost::signals2::signal<void (const CBlockIndex *, const CBlock *, std::optional<MerkleFrontiers>)> ChainTip;
/** Tells listeners to broadcast their data. */
boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast;
/** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
/** Notifies listeners that an address for mining is required (coinbase) */
boost::signals2::signal<void (std::optional<MinerAddress>&)> AddressForMining;
};
CMainSignals& GetMainSignals();
void ThreadNotifyWallets(CBlockIndex *pindexLastTip);
#endif // BITCOIN_VALIDATIONINTERFACE_H