From 01b4f32dffacb690a469ebb01d5a19af83c5ed10 Mon Sep 17 00:00:00 2001 From: alex v Date: Thu, 1 Aug 2024 14:46:39 +0200 Subject: [PATCH] allow flexible staking --- src/blsct/wallet/keyman.cpp | 2 +- src/blsct/wallet/keyman.h | 4 + src/blsct/wallet/txfactory.cpp | 127 +++++++++++++++++-------- src/blsct/wallet/txfactory.h | 15 +-- src/blsct/wallet/txfactory_global.cpp | 2 +- src/blsct/wallet/txfactory_global.h | 7 +- src/test/blsct/pos/pos_chain_tests.cpp | 4 +- src/wallet/rpc/spend.cpp | 6 +- src/wallet/wallet.cpp | 18 ++-- 9 files changed, 122 insertions(+), 63 deletions(-) diff --git a/src/blsct/wallet/keyman.cpp b/src/blsct/wallet/keyman.cpp index a4e2cca763a7f..4c13c62a6e31c 100644 --- a/src/blsct/wallet/keyman.cpp +++ b/src/blsct/wallet/keyman.cpp @@ -833,7 +833,7 @@ bool KeyMan::OutputIsChange(const CTxOut& out) const blsct::SubAddressIdentifier subAddId; if (GetSubAddressId(id, subAddId)) { - return subAddId.account == -1; + return subAddId.account == CHANGE_ACCOUNT; } return false; diff --git a/src/blsct/wallet/keyman.h b/src/blsct/wallet/keyman.h index 45ae7573b9ed6..833b1881d806f 100644 --- a/src/blsct/wallet/keyman.h +++ b/src/blsct/wallet/keyman.h @@ -21,6 +21,10 @@ #include namespace blsct { + +const int64_t CHANGE_ACCOUNT = -1; +const int64_t STAKING_ACCOUNT = -2; + class Manager { protected: diff --git a/src/blsct/wallet/txfactory.cpp b/src/blsct/wallet/txfactory.cpp index 3939c81032855..978e712b0ce75 100644 --- a/src/blsct/wallet/txfactory.cpp +++ b/src/blsct/wallet/txfactory.cpp @@ -13,39 +13,39 @@ using Scalars = Elements; namespace blsct { -void TxFactoryBase::AddOutput(const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId, const CreateOutputType& type, const CAmount& minStake) +void TxFactoryBase::AddOutput(const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id, const CreateTransactionType& type, const CAmount& minStake) { UnsignedOutput out; - out = CreateOutput(destination.GetKeys(), nAmount, sMemo, tokenId, Scalar::Rand(), type, minStake); + out = CreateOutput(destination.GetKeys(), nAmount, sMemo, token_id, Scalar::Rand(), type, minStake); - if (nAmounts.count(tokenId) == 0) - nAmounts[tokenId] = {0, 0}; + if (nAmounts.count(token_id) == 0) + nAmounts[token_id] = {0, 0}; - nAmounts[tokenId].nFromOutputs += nAmount; + nAmounts[token_id].nFromOutputs += nAmount; - if (vOutputs.count(tokenId) == 0) - vOutputs[tokenId] = std::vector(); + if (vOutputs.count(token_id) == 0) + vOutputs[token_id] = std::vector(); - vOutputs[tokenId].push_back(out); + vOutputs[token_id].push_back(out); } -bool TxFactoryBase::AddInput(const CAmount& amount, const MclScalar& gamma, const PrivateKey& spendingKey, const TokenId& tokenId, const COutPoint& outpoint, const bool& rbf) +bool TxFactoryBase::AddInput(const CAmount& amount, const MclScalar& gamma, const PrivateKey& spendingKey, const TokenId& token_id, const COutPoint& outpoint, const bool& rbf) { - if (vInputs.count(tokenId) == 0) - vInputs[tokenId] = std::vector(); + if (vInputs.count(token_id) == 0) + vInputs[token_id] = std::vector(); - vInputs[tokenId].push_back({CTxIn(outpoint, CScript(), rbf ? MAX_BIP125_RBF_SEQUENCE : CTxIn::SEQUENCE_FINAL), amount, gamma, spendingKey}); + vInputs[token_id].push_back({CTxIn(outpoint, CScript(), rbf ? MAX_BIP125_RBF_SEQUENCE : CTxIn::SEQUENCE_FINAL), amount, gamma, spendingKey}); - if (nAmounts.count(tokenId) == 0) - nAmounts[tokenId] = {0, 0}; + if (nAmounts.count(token_id) == 0) + nAmounts[token_id] = {0, 0}; - nAmounts[tokenId].nFromInputs += amount; + nAmounts[token_id].nFromInputs += amount; return true; } std::optional -TxFactoryBase::BuildTx(const blsct::DoublePublicKey& changeDestination, const CAmount& minStake, const bool& fUnstake, const bool& fSubtractedFee) +TxFactoryBase::BuildTx(const blsct::DoublePublicKey& changeDestination, const CAmount& minStake, const CreateTransactionType& type, const bool& fSubtractedFee) { CAmount nFee = BLSCT_DEFAULT_FEE * (vInputs.size() + vOutputs.size()); @@ -81,7 +81,7 @@ TxFactoryBase::BuildTx(const blsct::DoublePublicKey& changeDestination, const CA for (auto& change : mapChange) { if (change.second == 0) continue; - auto changeOutput = CreateOutput(changeDestination, change.second, "Change", change.first, MclScalar::Rand(), fUnstake ? STAKED_COMMITMENT : NORMAL, minStake); + auto changeOutput = CreateOutput(changeDestination, change.second, "Change", change.first, MclScalar::Rand(), type == CreateTransactionType::STAKED_COMMITMENT_UNSTAKE ? STAKED_COMMITMENT : NORMAL, minStake); tx.vout.push_back(changeOutput.out); gammaAcc = gammaAcc - changeOutput.gamma; txSigs.push_back(PrivateKey(changeOutput.blindingKey).Sign(changeOutput.out.GetHash())); @@ -101,26 +101,55 @@ TxFactoryBase::BuildTx(const blsct::DoublePublicKey& changeDestination, const CA return std::nullopt; } -std::optional TxFactoryBase::CreateTransaction(const std::vector& inputCandidates, const blsct::DoublePublicKey& changeDestination, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId, const CreateOutputType& type, const CAmount& minStake, const bool& fUnstake) +std::optional TxFactoryBase::CreateTransaction(const std::vector& inputCandidates, const blsct::DoublePublicKey& changeDestination, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id, const CreateTransactionType& type, const CAmount& minStake) { auto tx = blsct::TxFactoryBase(); CAmount inAmount = 0; - for (const auto& output : inputCandidates) { - tx.AddInput(output.amount, output.gamma, output.spendingKey, output.tokenId, COutPoint(output.outpoint.hash, output.outpoint.n)); - inAmount += output.amount; - if (tx.nAmounts[tokenId].nFromInputs > nAmount + (long long)(BLSCT_DEFAULT_FEE * (tx.vInputs.size() + 2))) break; - } + if (type == STAKED_COMMITMENT) { + CAmount inputFromStakedCommitments = 0; + for (const auto& output : inputCandidates) { + if (!output.is_staked_commitment) + continue; + + tx.AddInput(output.amount, output.gamma, output.spendingKey, output.token_id, COutPoint(output.outpoint.hash, output.outpoint.n)); - CAmount subtract = 0; - bool fChangeNeeded = inAmount > nAmount; + inputFromStakedCommitments += output.amount; + } + for (const auto& output : inputCandidates) { + if (output.is_staked_commitment) + continue; - if (fUnstake) - subtract = (BLSCT_DEFAULT_FEE * (tx.vInputs.size() + 1 + fChangeNeeded)); + tx.AddInput(output.amount, output.gamma, output.spendingKey, output.token_id, COutPoint(output.outpoint.hash, output.outpoint.n)); - tx.AddOutput(destination, nAmount - subtract, sMemo, tokenId, type, minStake); + inAmount += output.amount; + + if (tx.nAmounts[token_id].nFromInputs - inputFromStakedCommitments > nAmount + (long long)(BLSCT_DEFAULT_FEE * (tx.vInputs.size() + 2))) + break; + } + + if (nAmount + inputFromStakedCommitments < minStake) { + throw std::runtime_error(strprintf("A minimum of %s is required to stake", FormatMoney(minStake))); + } + + tx.AddOutput(destination, nAmount + inputFromStakedCommitments, sMemo, token_id, type, minStake); + } else { + for (const auto& output : inputCandidates) { + tx.AddInput(output.amount, output.gamma, output.spendingKey, output.token_id, COutPoint(output.outpoint.hash, output.outpoint.n)); + inAmount += output.amount; + if (tx.nAmounts[token_id].nFromInputs > nAmount + (long long)(BLSCT_DEFAULT_FEE * (tx.vInputs.size() + 2))) break; + } - return tx.BuildTx(changeDestination, minStake, fUnstake); + CAmount subtract = 0; + bool fChangeNeeded = inAmount > nAmount; + + if (type == CreateTransactionType::STAKED_COMMITMENT_UNSTAKE) + subtract = (BLSCT_DEFAULT_FEE * (tx.vInputs.size() + 1 + fChangeNeeded)); + + tx.AddOutput(destination, nAmount - subtract, sMemo, token_id, type, minStake); + } + + return tx.BuildTx(changeDestination, minStake, type); } bool TxFactory::AddInput(const CCoinsViewCache& cache, const COutPoint& outpoint, const bool& rbf) @@ -180,18 +209,10 @@ TxFactory::BuildTx() return TxFactoryBase::BuildTx(std::get(km->GetNewDestination(-1).value())); } -std::optional TxFactory::CreateTransaction(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId, const CreateOutputType& type, const CAmount& minStake, const bool& fUnstake) +void TxFactoryBase::AddAvailableCoins(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const wallet::CoinFilterParams& coins_params, std::vector& inputCandidates) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet) { LOCK(wallet->cs_wallet); - wallet::CoinFilterParams coins_params; - coins_params.min_amount = 0; - coins_params.only_blsct = true; - coins_params.include_staked_commitment = (fUnstake == true); - coins_params.token_id = tokenId; - - std::vector inputCandidates; - for (const wallet::COutput& output : AvailableCoins(*wallet, nullptr, std::nullopt, coins_params).All()) { auto tx = wallet->GetWalletTx(output.outpoint.hash); @@ -201,10 +222,36 @@ std::optional TxFactory::CreateTransaction(wallet::CWallet* auto out = tx->tx->vout[output.outpoint.n]; auto recoveredInfo = tx->GetBLSCTRecoveryData(output.outpoint.n); - inputCandidates.push_back({recoveredInfo.amount, recoveredInfo.gamma, blsct_km->GetSpendingKeyForOutput(out), out.tokenId, COutPoint(output.outpoint.hash, output.outpoint.n)}); + inputCandidates.push_back({recoveredInfo.amount, recoveredInfo.gamma, blsct_km->GetSpendingKeyForOutput(out), out.tokenId, COutPoint(output.outpoint.hash, output.outpoint.n), out.IsStakedCommitment()}); } +} + +void TxFactoryBase::AddAvailableCoins(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const TokenId& token_id, const CreateTransactionType& type, std::vector& inputCandidates) +{ + wallet::CoinFilterParams coins_params; + coins_params.min_amount = 0; + coins_params.only_blsct = true; + coins_params.include_staked_commitment = (type == CreateTransactionType::STAKED_COMMITMENT_UNSTAKE); + coins_params.token_id = token_id; + + AddAvailableCoins(wallet, blsct_km, coins_params, inputCandidates); + + if (type == CreateTransactionType::STAKED_COMMITMENT) { + coins_params.include_staked_commitment = true; + AddAvailableCoins(wallet, blsct_km, coins_params, inputCandidates); + } +} + +std::optional TxFactory::CreateTransaction(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id, const CreateTransactionType& type, const CAmount& minStake) +{ + std::vector inputCandidates; + + TxFactoryBase::AddAvailableCoins(wallet, blsct_km, token_id, type, inputCandidates); + + auto changeType = type == CreateTransactionType::STAKED_COMMITMENT_UNSTAKE ? STAKING_ACCOUNT : CHANGE_ACCOUNT; + auto changeAddress = std::get(blsct_km->GetNewDestination(changeType).value()); - return TxFactoryBase::CreateTransaction(inputCandidates, std::get(blsct_km->GetNewDestination(fUnstake ? -2 : -1).value()), destination, nAmount, sMemo, tokenId, type, minStake, fUnstake); + return TxFactoryBase::CreateTransaction(inputCandidates, changeAddress, destination, nAmount, sMemo, token_id, type, minStake); } } // namespace blsct \ No newline at end of file diff --git a/src/blsct/wallet/txfactory.h b/src/blsct/wallet/txfactory.h index 489d75007b0b0..9e727a79a0e13 100644 --- a/src/blsct/wallet/txfactory.h +++ b/src/blsct/wallet/txfactory.h @@ -19,8 +19,9 @@ struct InputCandidates { CAmount amount; MclScalar gamma; blsct::PrivateKey spendingKey; - TokenId tokenId; + TokenId token_id; COutPoint outpoint; + bool is_staked_commitment; }; class TxFactoryBase @@ -34,10 +35,12 @@ class TxFactoryBase public: TxFactoryBase(){}; - void AddOutput(const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId = TokenId(), const CreateOutputType& type = NORMAL, const CAmount& minStake = 0); - bool AddInput(const CAmount& amount, const MclScalar& gamma, const blsct::PrivateKey& spendingKey, const TokenId& tokenId, const COutPoint& outpoint, const bool& rbf = false); - std::optional BuildTx(const blsct::DoublePublicKey& changeDestination, const CAmount& minStake = 0, const bool& fUnstake = false, const bool& fSubtractedFee = false); - static std::optional CreateTransaction(const std::vector& inputCandidates, const blsct::DoublePublicKey& changeDestination, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId = TokenId(), const CreateOutputType& type = NORMAL, const CAmount& minStake = 0, const bool& fUnstake = false); + void AddOutput(const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id = TokenId(), const CreateTransactionType& type = NORMAL, const CAmount& minStake = 0); + bool AddInput(const CAmount& amount, const MclScalar& gamma, const blsct::PrivateKey& spendingKey, const TokenId& token_id, const COutPoint& outpoint, const bool& rbf = false); + std::optional BuildTx(const blsct::DoublePublicKey& changeDestination, const CAmount& minStake = 0, const CreateTransactionType& type = NORMAL, const bool& fSubtractedFee = false); + static std::optional CreateTransaction(const std::vector& inputCandidates, const blsct::DoublePublicKey& changeDestination, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id = TokenId(), const CreateTransactionType& type = NORMAL, const CAmount& minStake = 0); + static void AddAvailableCoins(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const wallet::CoinFilterParams& coins_params, std::vector& inputCandidates) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet); + static void AddAvailableCoins(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const TokenId& token_id, const CreateTransactionType& type, std::vector& inputCandidates); }; class TxFactory : public TxFactoryBase @@ -51,7 +54,7 @@ class TxFactory : public TxFactoryBase bool AddInput(wallet::CWallet* wallet, const COutPoint& outpoint, const bool& rbf = false) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet); bool AddInput(const CCoinsViewCache& cache, const COutPoint& outpoint, const bool& rbf = false); std::optional BuildTx(); - static std::optional CreateTransaction(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId = TokenId(), const CreateOutputType& type = NORMAL, const CAmount& minStake = 0, const bool& fUnstake = false); + static std::optional CreateTransaction(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id = TokenId(), const CreateTransactionType& type = NORMAL, const CAmount& minStake = 0); }; } // namespace blsct diff --git a/src/blsct/wallet/txfactory_global.cpp b/src/blsct/wallet/txfactory_global.cpp index 97929f8942711..9f3bf35635b19 100644 --- a/src/blsct/wallet/txfactory_global.cpp +++ b/src/blsct/wallet/txfactory_global.cpp @@ -43,7 +43,7 @@ Signature UnsignedOutput::GetSignature() const return Signature::Aggregate(txSigs); } -UnsignedOutput CreateOutput(const blsct::DoublePublicKey& destKeys, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId, const Scalar& blindingKey, const CreateOutputType& type, const CAmount& minStake) +UnsignedOutput CreateOutput(const blsct::DoublePublicKey& destKeys, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId, const Scalar& blindingKey, const CreateTransactionType& type, const CAmount& minStake) { bulletproofs::RangeProofLogic rp; auto ret = UnsignedOutput(); diff --git a/src/blsct/wallet/txfactory_global.h b/src/blsct/wallet/txfactory_global.h index 36f86b254650c..9252cdf5e533f 100644 --- a/src/blsct/wallet/txfactory_global.h +++ b/src/blsct/wallet/txfactory_global.h @@ -59,14 +59,15 @@ struct Amounts { CAmount nFromOutputs; }; -enum CreateOutputType { +enum CreateTransactionType { NORMAL, - STAKED_COMMITMENT + STAKED_COMMITMENT, + STAKED_COMMITMENT_UNSTAKE }; CTransactionRef AggregateTransactions(const std::vector& txs); -UnsignedOutput CreateOutput(const blsct::DoublePublicKey& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId = TokenId(), const Scalar& blindingKey = Scalar::Rand(), const CreateOutputType& type = NORMAL, const CAmount& minStake = 0); +UnsignedOutput CreateOutput(const blsct::DoublePublicKey& destination, const CAmount& nAmount, std::string sMemo, const TokenId& tokenId = TokenId(), const Scalar& blindingKey = Scalar::Rand(), const CreateTransactionType& type = NORMAL, const CAmount& minStake = 0); } // namespace blsct #endif // TXFACTORY_GLOBAL_H diff --git a/src/test/blsct/pos/pos_chain_tests.cpp b/src/test/blsct/pos/pos_chain_tests.cpp index dfd6d69caf1f3..5e20f6c41c37d 100644 --- a/src/test/blsct/pos/pos_chain_tests.cpp +++ b/src/test/blsct/pos/pos_chain_tests.cpp @@ -25,7 +25,7 @@ BOOST_FIXTURE_TEST_SUITE(pos_chain_tests, WalletTestingSetup) Coin CreateCoin(const blsct::DoublePublicKey& recvAddress) { Coin coin; - auto out = blsct::CreateOutput(recvAddress, 1000 * COIN, "test", TokenId(), Scalar::Rand(), blsct::CreateOutputType::STAKED_COMMITMENT, 1000 * COIN); + auto out = blsct::CreateOutput(recvAddress, 1000 * COIN, "test", TokenId(), Scalar::Rand(), blsct::CreateTransactionType::STAKED_COMMITMENT, 1000 * COIN); coin.nHeight = 1; coin.out = out.out; return coin; @@ -58,7 +58,7 @@ BOOST_FIXTURE_TEST_CASE(StakedCommitment, TestBLSCTChain100Setup) Coin coin2 = CreateCoin(recvAddress); Coin coin3; - auto out3 = blsct::CreateOutput(recvAddress, 1000 * COIN, "test", TokenId(), Scalar::Rand(), blsct::CreateOutputType::STAKED_COMMITMENT, 999 * COIN); + auto out3 = blsct::CreateOutput(recvAddress, 1000 * COIN, "test", TokenId(), Scalar::Rand(), blsct::CreateTransactionType::STAKED_COMMITMENT, 999 * COIN); coin3.nHeight = 1; coin3.out = out3.out; diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 34ee0f12b5ac6..d0120bc60ca80 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -218,7 +218,7 @@ UniValue SendBLSCTMoney(CWallet& wallet, std::vector& recipient std::shuffle(recipients.begin(), recipients.end(), FastRandomContext()); // Send - auto outputType = recipients[0].fStakeCommitment ? blsct::CreateOutputType::STAKED_COMMITMENT : blsct::CreateOutputType::NORMAL; + auto outputType = recipients[0].fStakeCommitment ? blsct::CreateTransactionType::STAKED_COMMITMENT : blsct::CreateTransactionType::NORMAL; auto minStake = recipients[0].fStakeCommitment ? minStakeIn : 0; auto res = blsct::TxFactory::CreateTransaction(&wallet, wallet.GetBLSCTKeyMan(), recipients[0].destination, recipients[0].nAmount, recipients[0].sMemo, TokenId(), outputType, minStake); @@ -255,10 +255,10 @@ UniValue UnstakeBLSCT(CWallet& wallet, std::vector& recipients, std::shuffle(recipients.begin(), recipients.end(), FastRandomContext()); // Send - auto outputType = blsct::CreateOutputType::NORMAL; + auto outputType = blsct::CreateTransactionType::STAKED_COMMITMENT_UNSTAKE; auto minStake = minStakeIn; - auto res = blsct::TxFactory::CreateTransaction(&wallet, wallet.GetBLSCTKeyMan(), recipients[0].destination, recipients[0].nAmount, recipients[0].sMemo, TokenId(), outputType, minStake, true); + auto res = blsct::TxFactory::CreateTransaction(&wallet, wallet.GetBLSCTKeyMan(), recipients[0].destination, recipients[0].nAmount, recipients[0].sMemo, TokenId(), outputType, minStake); if (!res) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Not enough funds available"); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1a383fa467f8c..215f9ce07897a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1251,6 +1251,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS { AssertLockHeld(cs_wallet); + std::vector vHashToZap; + if (auto* conf = std::get_if(&state)) { for (const CTxIn& txin : tx.vin) { std::pair range = mapTxSpends.equal_range(txin.prevout); @@ -1260,13 +1262,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), conf->confirmed_block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second); } else { - std::vector vHash; - vHash.push_back(range.first->second); - std::vector vHashOut; - - if (ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) { - AbandonTransaction(range.first->second); - } + vHashToZap.push_back(range.first->second); } } range.first++; @@ -1274,6 +1270,12 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS } } + std::vector vHashOut; + + if (ZapSelectTx(vHashToZap, vHashOut) != DBErrors::LOAD_OK) { + throw std::runtime_error("DB error zapping conflicted transaction, load failed"); + } + bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) return false; if (fExisted || IsMine(tx) || IsFromMe(tx)) { @@ -1305,6 +1307,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS } } + // Block disconnection override an abandoned tx as unconfirmed // which means user may have to call abandontransaction again TxState tx_state = std::visit([](auto&& s) -> TxState { return s; }, state); @@ -1314,6 +1317,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS // As we only store arriving transaction in this process, and we don't want an inconsistent state, let's throw an error. throw std::runtime_error("DB error adding transaction to wallet, write failed"); } + return true; } }