|
| 1 | +// Copyright (c) 2023-present The Bitcoin Core developers |
| 2 | +// Distributed under the MIT software license, see the accompanying |
| 3 | +// file COPYING or http://www.opensource.org/licenses/mit-license.php. |
| 4 | + |
| 5 | +#include <index/bip352.h> |
| 6 | + |
| 7 | +#include <common/bip352.h> |
| 8 | +#include <chainparams.h> |
| 9 | +#include <coins.h> |
| 10 | +#include <common/args.h> |
| 11 | +#include <index/disktxpos.h> |
| 12 | +#include <node/blockstorage.h> |
| 13 | +#include <pubkey.h> |
| 14 | +#include <primitives/transaction.h> |
| 15 | + |
| 16 | +#include <undo.h> |
| 17 | +#include <validation.h> |
| 18 | + |
| 19 | +#include <dbwrapper.h> |
| 20 | +#include <hash.h> |
| 21 | + |
| 22 | +constexpr uint8_t DB_SILENT_PAYMENT_INDEX{'s'}; |
| 23 | +/* Save space on mainnet by starting the index at Taproot activation. |
| 24 | + * Copying the height here assuming DEPLOYMENT_TAPROOT will be dropped: |
| 25 | + * https://github.com/bitcoin/bitcoin/pull/26201/ |
| 26 | + * Only apply this storage optimization on mainnet. |
| 27 | + */ |
| 28 | +const int TAPROOT_MAINNET_ACTIVATION_HEIGHT{709632}; |
| 29 | + |
| 30 | +std::unique_ptr<BIP352Index> g_bip352_index; |
| 31 | + |
| 32 | +/** Access to the silent payment index database (indexes/bip352/) */ |
| 33 | +class BIP352Index::DB : public BaseIndex::DB |
| 34 | +{ |
| 35 | +public: |
| 36 | + explicit DB(size_t n_cache_size, bool f_memory = false, bool f_wipe = false); |
| 37 | + |
| 38 | + bool WriteSilentPayments(const std::pair<uint256, std::vector<CPubKey>>& tweaks); |
| 39 | +}; |
| 40 | + |
| 41 | +BIP352Index::DB::DB(size_t n_cache_size, bool f_memory, bool f_wipe) : |
| 42 | + BaseIndex::DB(gArgs.GetDataDirNet() / "indexes" / "bip352", n_cache_size, f_memory, f_wipe) |
| 43 | +{} |
| 44 | + |
| 45 | +bool BIP352Index::DB::WriteSilentPayments(const std::pair<uint256, std::vector<CPubKey>>& tweaks) |
| 46 | +{ |
| 47 | + CDBBatch batch(*this); |
| 48 | + batch.Write(std::make_pair(DB_SILENT_PAYMENT_INDEX, tweaks.first), tweaks.second); |
| 49 | + return WriteBatch(batch); |
| 50 | +} |
| 51 | + |
| 52 | +BIP352Index::BIP352Index(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe) |
| 53 | + : BaseIndex(std::move(chain), "bip352 index", /*start_height=*/Params().IsTestChain() ? 0 : TAPROOT_MAINNET_ACTIVATION_HEIGHT), m_db(std::make_unique<BIP352Index::DB>(n_cache_size, f_memory, f_wipe)) |
| 54 | +{} |
| 55 | + |
| 56 | +BIP352Index::~BIP352Index() = default; |
| 57 | + |
| 58 | +bool BIP352Index::GetSilentPaymentKeys(const std::vector<CTransactionRef>& txs, const CBlockUndo& block_undo, std::vector<CPubKey>& tweaked_pub_key_sums) const |
| 59 | +{ |
| 60 | + assert(txs.size() - 1 == block_undo.vtxundo.size()); |
| 61 | + |
| 62 | + for (size_t i=0; i < txs.size(); i++) { |
| 63 | + auto& tx = txs.at(i); |
| 64 | + |
| 65 | + if (!bip352::MaybeSilentPayment(tx)) continue; |
| 66 | + |
| 67 | + // -1 as blockundo does not have coinbase tx |
| 68 | + CTxUndo undoTX{block_undo.vtxundo.at(i - 1)}; |
| 69 | + std::map<COutPoint, Coin> coins; |
| 70 | + |
| 71 | + for (size_t j = 0; j < tx->vin.size(); j++) { |
| 72 | + coins[tx->vin.at(j).prevout] = undoTX.vprevout.at(j); |
| 73 | + } |
| 74 | + |
| 75 | + std::optional<CPubKey> tweaked_pk = bip352::GetSerializedSilentPaymentsPublicData(tx->vin, coins); |
| 76 | + if (tweaked_pk) tweaked_pub_key_sums.push_back(tweaked_pk.value()); |
| 77 | + } |
| 78 | + |
| 79 | + return true; |
| 80 | +} |
| 81 | + |
| 82 | +interfaces::Chain::NotifyOptions BIP352Index::CustomOptions() |
| 83 | +{ |
| 84 | + interfaces::Chain::NotifyOptions options; |
| 85 | + options.connect_undo_data = true; |
| 86 | + return options; |
| 87 | +} |
| 88 | + |
| 89 | +bool BIP352Index::CustomAppend(const interfaces::BlockInfo& block) |
| 90 | +{ |
| 91 | + // Exclude genesis block transaction because outputs are not spendable. This |
| 92 | + // is needed on non-mainnet chains because m_start_height is 0 by default. |
| 93 | + if (block.height == 0) return true; |
| 94 | + |
| 95 | + // Exclude pre-taproot |
| 96 | + if (block.height < m_start_height) return true; |
| 97 | + |
| 98 | + std::vector<CPubKey> tweaked_pub_key_sums; |
| 99 | + GetSilentPaymentKeys(Assert(block.data)->vtx, *Assert(block.undo_data), tweaked_pub_key_sums); |
| 100 | + |
| 101 | + return m_db->WriteSilentPayments(make_pair(block.hash, tweaked_pub_key_sums)); |
| 102 | +} |
| 103 | + |
| 104 | +bool BIP352Index::FindSilentPayment(const uint256& block_hash, std::vector<CPubKey>& tweaked_pub_key_sums) const |
| 105 | +{ |
| 106 | + return m_db->Read(std::make_pair(DB_SILENT_PAYMENT_INDEX, block_hash), tweaked_pub_key_sums); |
| 107 | +} |
| 108 | + |
| 109 | +BaseIndex::DB& BIP352Index::GetDB() const { return *m_db; } |
0 commit comments