Skip to content

Commit

Permalink
Merge pull request #5743 from knst/bitcoinserver-15639-p1
Browse files Browse the repository at this point in the history
refactor: pull libbitcoin_server code out of wallet code 3/N
  • Loading branch information
PastaPastaPasta authored Dec 17, 2023
2 parents 40f7ae8 + e3d9327 commit 714be63
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 49 deletions.
8 changes: 8 additions & 0 deletions src/interfaces/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ class Chain
//! Check if transaction will be final given chain height current time.
virtual bool checkFinalTx(const CTransaction& tx) = 0;

//! Check if transaction is locked by InstantSendManager
virtual bool isInstantSendLockedTx(const uint256& hash) = 0;

//! Check if block is chainlocked.
virtual bool hasChainLock(int height, const uint256& hash) = 0;

//! Return list of MN Collateral from outputs
virtual std::vector<COutPoint> listMNCollaterials(const std::vector<std::pair<const CTransactionRef&, unsigned int>>& outputs) = 0;
//! Return whether node has the block and optionally return block metadata
//! or contents.
virtual bool findBlock(const uint256& hash, const FoundBlock& block={}) = 0;
Expand Down
28 changes: 28 additions & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <interfaces/chain.h>
#include <interfaces/handler.h>
#include <interfaces/wallet.h>
#include <llmq/chainlocks.h>
#include <llmq/context.h>
#include <llmq/instantsend.h>
#include <mapport.h>
#include <masternode/sync.h>
Expand Down Expand Up @@ -715,6 +717,32 @@ class ChainImpl : public Chain
assert(std::addressof(::ChainActive()) == std::addressof(m_node.chainman->ActiveChain()));
return CheckFinalTx(m_node.chainman->ActiveChain().Tip(), tx);
}
bool isInstantSendLockedTx(const uint256& hash) override
{
if (m_node.llmq_ctx == nullptr || m_node.llmq_ctx->isman == nullptr) return false;
return m_node.llmq_ctx->isman->IsLocked(hash);
}
bool hasChainLock(int height, const uint256& hash) override
{
if (m_node.llmq_ctx == nullptr || m_node.llmq_ctx->clhandler == nullptr) return false;
return m_node.llmq_ctx->clhandler->HasChainLock(height, hash);
}
std::vector<COutPoint> listMNCollaterials(const std::vector<std::pair<const CTransactionRef&, unsigned int>>& outputs) override
{
const CBlockIndex *tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip());
CDeterministicMNList mnList{};
if (tip != nullptr && deterministicMNManager != nullptr) {
mnList = deterministicMNManager->GetListForBlock(tip);
}
std::vector<COutPoint> listRet;
for (const auto& [tx, index]: outputs) {
COutPoint nextOut{tx->GetHash(), index};
if (CDeterministicMNManager::IsProTxWithCollateral(tx, index) || mnList.HasMNByCollateral(nextOut)) {
listRet.emplace_back(nextOut);
}
}
return listRet;
}
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
Expand Down
14 changes: 2 additions & 12 deletions src/wallet/coinselection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <util/system.h>
#include <util/moneystr.h>

#include <llmq/instantsend.h>
#include <coinjoin/coinjoin.h>

#include <optional>
Expand Down Expand Up @@ -391,18 +390,9 @@ std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output)
return m_outputs.erase(it);
}

bool OutputGroup::IsLockedByInstantSend() const
bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter, bool isISLocked) const
{
for (const auto& output : m_outputs) {
if (!llmq::quorumInstantSendManager->IsLocked(output.outpoint.hash))
return false;
}
return true;
}

bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const
{
return (m_depth >= (m_from_me ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs) || IsLockedByInstantSend())
return (m_depth >= (m_from_me ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs) || isISLocked)
&& m_ancestors <= eligibility_filter.max_ancestors
&& m_descendants <= eligibility_filter.max_descendants;
}
Expand Down
3 changes: 1 addition & 2 deletions src/wallet/coinselection.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ struct OutputGroup
}
void Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants);
std::vector<CInputCoin>::iterator Discard(const CInputCoin& output);
bool IsLockedByInstantSend() const;
bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;
bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter, bool isISLocked) const;

//! Update the OutputGroup's fee, long_term_fee, and effective_value based on the given feerates
void SetFees(const CFeeRate effective_feerate, const CFeeRate long_term_feerate);
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();

if (fPruneMode)
if (pwallet->chain().havePruned())
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");

if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
Expand Down
3 changes: 1 addition & 2 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
#include <coinjoin/client.h>
#include <coinjoin/options.h>
#include <llmq/chainlocks.h>
#include <llmq/instantsend.h>

#include <stdint.h>

Expand Down Expand Up @@ -158,7 +157,7 @@ WalletContext& EnsureWalletContext(const CoreContext& context)
static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry)
{
int confirms = wtx.GetDepthInMainChain();
bool fLocked = llmq::quorumInstantSendManager->IsLocked(wtx.GetHash());
bool fLocked = chain.isInstantSendLockedTx(wtx.GetHash());
bool chainlock = false;
if (confirms > 0) {
chainlock = wtx.IsChainLocked();
Expand Down
8 changes: 3 additions & 5 deletions src/wallet/scriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <script/descriptor.h>
#include <script/sign.h>
#include <shutdown.h>
#include <ui_interface.h>
#include <util/bip32.h>
#include <util/strencodings.h>
#include <util/system.h>
Expand Down Expand Up @@ -1437,7 +1436,7 @@ bool LegacyScriptPubKeyMan::TopUpInner(unsigned int kpSize)
int64_t progress_report_time = GetTime();
WalletLogPrintf("%s\n", strMsg);
if (should_show_progress) {
uiInterface.ShowProgress(strMsg, 0, false);
m_storage.UpdateProgress(strMsg, 0);
}

bool fInternal = false;
Expand All @@ -1458,15 +1457,14 @@ bool LegacyScriptPubKeyMan::TopUpInner(unsigned int kpSize)
progress_report_time = GetTime();
WalletLogPrintf("Still topping up. At key %lld. Progress=%f\n", current_index, dProgress);
if (should_show_progress) {
uiInterface.ShowProgress(strMsg, static_cast<int>(dProgress), false);
m_storage.UpdateProgress(strMsg, static_cast<int>(dProgress));
}
}
if (ShutdownRequested()) break;
}
WalletLogPrintf("Keypool added %d keys, size=%u (%u internal)\n",
current_index + 1, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size());
if (should_show_progress) {
uiInterface.ShowProgress("", 100, false);
m_storage.UpdateProgress("", 100);
}
}
NotifyCanGetAddressesChanged();
Expand Down
3 changes: 3 additions & 0 deletions src/wallet/scriptpubkeyman.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ class WalletStorage
virtual bool HasEncryptionKeys() const = 0;
virtual bool IsLocked(bool fForMixing = false) const = 0;

// for LegacyScriptPubKeyMan::TopUpInner needs:
virtual void UpdateProgress(const std::string&, int) = 0;

// methods below are unique from Dash due to different implementation of HD
virtual void NewKeyPoolCallback() = 0;
virtual void KeepDestinationCallback(bool erased) = 0;
Expand Down
69 changes: 42 additions & 27 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,13 @@

#include <coinjoin/client.h>
#include <coinjoin/options.h>
#include <evo/providertx.h>
#include <governance/governance.h>
#include <evo/deterministicmns.h>
#include <masternode/sync.h>

#include <univalue.h>

#include <evo/providertx.h>

#include <llmq/instantsend.h>
#include <llmq/chainlocks.h>
#include <algorithm>
#include <assert.h>

using interfaces::FoundBlock;
Expand Down Expand Up @@ -882,15 +879,16 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash);

auto mnList = deterministicMNManager->GetListAtChainTip();
std::vector<std::pair<const CTransactionRef&, unsigned int>> outputs;
for(unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
if (IsMine(wtx.tx->vout[i]) && !IsSpent(hash, i)) {
setWalletUTXO.insert(COutPoint(hash, i));
if (deterministicMNManager->IsProTxWithCollateral(wtx.tx, i) || mnList.HasMNByCollateral(COutPoint(hash, i))) {
LockCoin(COutPoint(hash, i));
}
outputs.emplace_back(wtx.tx, i);
}
}
for (const auto& outPoint : m_chain->listMNCollaterials(outputs)) {
LockCoin(outPoint);
}
}

if (!fInsertedNew)
Expand All @@ -907,16 +905,19 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
assert(wtx.m_confirm.block_height == confirm.block_height);
}

auto mnList = deterministicMNManager->GetListAtChainTip();
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
std::vector<std::pair<const CTransactionRef&, unsigned int>> outputs;
for(unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
if (IsMine(wtx.tx->vout[i]) && !IsSpent(hash, i)) {
bool new_utxo = setWalletUTXO.insert(COutPoint(hash, i)).second;
if (new_utxo && (deterministicMNManager->IsProTxWithCollateral(wtx.tx, i) || mnList.HasMNByCollateral(COutPoint(hash, i)))) {
LockCoin(COutPoint(hash, i));
if (new_utxo) {
outputs.emplace_back(wtx.tx, i);
fUpdated = true;
}
fUpdated |= new_utxo;
}
}
for (const auto& outPoint : m_chain->listMNCollaterials(outputs)) {
LockCoin(outPoint);
}
}

//// debug print
Expand Down Expand Up @@ -2720,6 +2721,13 @@ struct CompareByPriority
}
};

static bool isGroupISLocked(const OutputGroup& group, interfaces::Chain& chain)
{
return std::all_of(group.m_outputs.begin(), group.m_outputs.end(), [&chain](const auto& output) {
return chain.isInstantSendLockedTx(output.outpoint.hash);
});
}

bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<OutputGroup> groups,
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType) const
{
Expand All @@ -2739,7 +2747,8 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil

// Filter by the min conf specs and add to utxo_pool and calculate effective value
for (OutputGroup& group : groups) {
if (!group.EligibleForSpending(eligibility_filter)) continue;
bool isISLocked = isGroupISLocked(group, chain());
if (!group.EligibleForSpending(eligibility_filter, isISLocked)) continue;

if (coin_selection_params.m_subtract_fee_outputs) {
// Set the effective feerate to 0 as we don't want to use the effective value since the fees will be deducted from the output
Expand All @@ -2758,7 +2767,8 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
} else {
// Filter by the min conf specs and add to utxo_pool
for (const OutputGroup& group : groups) {
if (!group.EligibleForSpending(eligibility_filter)) continue;
bool isISLocked = isGroupISLocked(group, chain());
if (!group.EligibleForSpending(eligibility_filter, isISLocked)) continue;
utxo_pool.push_back(group);
}
bnb_used = false;
Expand Down Expand Up @@ -3856,18 +3866,19 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
// This avoids accidental spending of collaterals. They can still be unlocked manually if a spend is really intended.
void CWallet::AutoLockMasternodeCollaterals()
{
auto mnList = deterministicMNManager->GetListAtChainTip();
std::vector<std::pair<const CTransactionRef&, unsigned int>> outputs;

LOCK(cs_wallet);
for (const auto& pair : mapWallet) {
for (unsigned int i = 0; i < pair.second.tx->vout.size(); ++i) {
if (IsMine(pair.second.tx->vout[i]) && !IsSpent(pair.first, i)) {
if (deterministicMNManager->IsProTxWithCollateral(pair.second.tx, i) || mnList.HasMNByCollateral(COutPoint(pair.first, i))) {
LockCoin(COutPoint(pair.first, i));
}
outputs.emplace_back(pair.second.tx, i);
}
}
}
for (const auto& outPoint : m_chain->listMNCollaterials(outputs)) {
LockCoin(outPoint);
}
}

DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
Expand Down Expand Up @@ -4292,18 +4303,17 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const

void CWallet::ListProTxCoins(std::vector<COutPoint>& vOutpts) const
{
auto mnList = deterministicMNManager->GetListAtChainTip();
std::vector<std::pair<const CTransactionRef&, unsigned int>> outputs;

AssertLockHeld(cs_wallet);
for (const auto &o : setWalletUTXO) {
auto it = mapWallet.find(o.hash);
if (it != mapWallet.end()) {
const auto &p = it->second;
if (deterministicMNManager->IsProTxWithCollateral(p.tx, o.n) || mnList.HasMNByCollateral(o)) {
vOutpts.emplace_back(o);
}
const auto &ptx = it->second;
outputs.emplace_back(ptx.tx, o.n);
}
}
vOutpts = m_chain->listMNCollaterials(outputs);
}

/** @} */ // end of Actions
Expand Down Expand Up @@ -5132,7 +5142,7 @@ bool CWalletTx::IsLockedByInstantSend() const
if (fIsChainlocked) {
fIsInstantSendLocked = false;
} else if (!fIsInstantSendLocked) {
fIsInstantSendLocked = llmq::quorumInstantSendManager->IsLocked(GetHash());
fIsInstantSendLocked = pwallet->chain().isInstantSendLockedTx(GetHash());
}
return fIsInstantSendLocked;
}
Expand All @@ -5145,7 +5155,7 @@ bool CWalletTx::IsChainLocked() const
bool active;
int height;
if (pwallet->chain().findBlock(m_confirm.hashBlock, FoundBlock().inActiveChain(active).height(height)) && active) {
fIsChainlocked = llmq::chainLocksHandler->HasChainLock(height, m_confirm.hashBlock);
fIsChainlocked = pwallet->chain().hasChainLock(height, m_confirm.hashBlock);
}
}
return fIsChainlocked;
Expand Down Expand Up @@ -5501,3 +5511,8 @@ bool CWallet::GenerateNewHDChainEncrypted(const SecureString& secureMnemonic, co

return false;
}

void CWallet::UpdateProgress(const std::string& title, int nProgress)
{
ShowProgress(title, nProgress);
}
2 changes: 2 additions & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
bool IsLocked(bool fForMixing = false) const override;
bool Lock(bool fForMixing = false);

void UpdateProgress(const std::string& title, int nProgress) override;

std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);

typedef std::multimap<int64_t, CWalletTx*> TxItems;
Expand Down

0 comments on commit 714be63

Please sign in to comment.