diff --git a/src/hdmint/tracker.cpp b/src/hdmint/tracker.cpp index f46e3334d4..fe7de8c94a 100644 --- a/src/hdmint/tracker.cpp +++ b/src/hdmint/tracker.cpp @@ -14,6 +14,7 @@ #include "libzerocoin/Zerocoin.h" #include "main.h" #include "zerocoin_v3.h" +#include "txmempool.h" using namespace std; using namespace sigma; @@ -36,7 +37,7 @@ void CHDMintTracker::Init() { //Load all CZerocoinEntries and CHDMints from the database if (!fInitialized) { - ListMints(false, false); + ListMints(false, false, false, true); fInitialized = true; } } @@ -380,6 +381,32 @@ void CHDMintTracker::RemovePending(const uint256& txid) mapPendingSpends.erase(hashSerial); } +bool CHDMintTracker::IsMempoolSpendOurs(const std::set& setMempool, const uint256& hashSerial){ + // get transaction back from mempool + // if spend, get hash of serial + // if matches mint.hashSerial, mark pending spend. + for(auto& mempoolTxid : setMempool){ + auto it = mempool.mapTx.find(mempoolTxid); + if (it == mempool.mapTx.end()) + continue; + + const CTransaction &tx = it->GetTx(); + for (const CTxIn& txin : tx.vin) { + if (txin.IsSigmaSpend()) { + std::unique_ptr spend; + uint32_t pubcoinId; + std::tie(spend, pubcoinId) = sigma::ParseSigmaSpend(txin); + uint256 mempoolHashSerial = primitives::GetSerialHash(spend->getCoinSerialNumber()); + if(mempoolHashSerial==hashSerial){ + return true; + } + } + } + } + + return false; +} + bool CHDMintTracker::UpdateMetaStatus(const std::set& setMempool, CMintMeta& mint) { uint256 hashPubcoin = mint.GetPubCoinValueHash(); @@ -390,24 +417,18 @@ bool CHDMintTracker::UpdateMetaStatus(const std::set& setMempool, CMint bool isMintInChain = GetOutPoint(outPoint, pubCoin); const uint256& txidMint = outPoint.hash; - //See if there is internal record of spending this mint (note this is memory only, would reset on restart) + //See if there is internal record of spending this mint (note this is memory only, would reset on restart - next function checks this) bool isPendingSpend = static_cast(mapPendingSpends.count(mint.hashSerial)); + // Mempool might hold pending spend + if(!isPendingSpend) + isPendingSpend = IsMempoolSpendOurs(setMempool, mint.hashSerial); + // See if there is a blockchain record of spending this mint CSigmaState *sigmaState = sigma::CSigmaState::GetState(); Scalar bnSerial; bool isConfirmedSpend = sigmaState->IsUsedCoinSerialHash(bnSerial, mint.hashSerial); - // Double check the mempool for pending spend - if (isPendingSpend) { - uint256 txidPendingSpend = mapPendingSpends.at(mint.hashSerial); - if (!setMempool.count(txidPendingSpend) || isConfirmedSpend) { - RemovePending(txidPendingSpend); - isPendingSpend = false; - LogPrintf("%s : Pending txid %s removed because not in mempool\n", __func__, txidPendingSpend.GetHex()); - } - } - bool isUsed = isPendingSpend || isConfirmedSpend; if ((mint.nHeight==-1) || (mint.nId==-1) || !isMintInChain || isUsed != mint.isUsed) { @@ -552,6 +573,43 @@ void CHDMintTracker::UpdateSpendStateFromBlock(const sigma::spend_info_container UpdateFromBlock(mintPoolEntries, updatedMeta); } +void CHDMintTracker::UpdateSpendStateFromMempool(const vector& spentSerials){ + CWalletDB walletdb(strWalletFile); + std::vector updatedMeta; + std::list> mintPoolEntries; + uint160 hashSeedMasterEntry; + CKeyID seedId; + int32_t nCount; + std::set setMempool; + { + LOCK(mempool.cs); + mempool.getTransactions(setMempool); + } + for(auto& spentSerial : spentSerials){ + uint256 spentSerialHash = primitives::GetSerialHash(spentSerial); + CMintMeta meta; + GroupElement pubcoin; + // Check serialHash in db + if(walletdb.ReadPubcoin(spentSerialHash, pubcoin)){ + // If found in db but not in memory - this is likely a resync + if(!Get(spentSerialHash, meta)){ + uint256 hashPubcoin = primitives::GetPubCoinValueHash(pubcoin); + if(!walletdb.ReadMintPoolPair(hashPubcoin, hashSeedMasterEntry, seedId, nCount)){ + continue; + } + MintPoolEntry mintPoolEntry(hashSeedMasterEntry, seedId, nCount); + mintPoolEntries.push_back(std::make_pair(hashPubcoin, mintPoolEntry)); + continue; + } + if(UpdateMetaStatus(setMempool, meta)){ + updatedMeta.emplace_back(meta); + } + } + } + + UpdateFromBlock(mintPoolEntries, updatedMeta); +} + list CHDMintTracker::MintsAsZerocoinEntries(bool fUnusedOnly, bool fMatureOnly){ list listPubcoin; CWalletDB walletdb(strWalletFile); @@ -565,11 +623,12 @@ list CHDMintTracker::MintsAsZerocoinEntries(bool fUnusedOnly, bool return listPubcoin; } -std::vector CHDMintTracker::ListMints(bool fUnusedOnly, bool fMatureOnly, bool fUpdateStatus, bool fWrongSeed) +std::vector CHDMintTracker::ListMints(bool fUnusedOnly, bool fMatureOnly, bool fUpdateStatus, bool fLoad, bool fWrongSeed) { + LOCK2(cs_main, pwalletMain->cs_wallet); std::vector setMints; CWalletDB walletdb(strWalletFile); - if (fUpdateStatus) { + if (fLoad) { std::list listMintsDB; walletdb.ListSigmaPubCoin(listMintsDB); for (auto& mint : listMintsDB){ @@ -598,12 +657,14 @@ std::vector CHDMintTracker::ListMints(bool fUnusedOnly, bool fMatureO continue; // Update the metadata of the mints if requested - if (fUpdateStatus && UpdateMetaStatus(setMempool, mint)) { - if (mint.isArchived) - continue; + if (fUpdateStatus){ + if(UpdateMetaStatus(setMempool, mint)) { + if (mint.isArchived) + continue; - // Mint was updated, queue for overwrite - vOverWrite.emplace_back(mint); + // Mint was updated, queue for overwrite + vOverWrite.emplace_back(mint); + } } if (fUnusedOnly && mint.isUsed) diff --git a/src/hdmint/tracker.h b/src/hdmint/tracker.h index 6364bf6da2..27ee2e6200 100644 --- a/src/hdmint/tracker.h +++ b/src/hdmint/tracker.h @@ -19,6 +19,7 @@ class CHDMintTracker std::string strWalletFile; std::map mapSerialHashes; std::map mapPendingSpends; //serialhash, txid of spend + bool IsMempoolSpendOurs(const std::set& setMempool, const uint256& hashSerial); bool UpdateMetaStatus(const std::set& setMempool, CMintMeta& mint); public: CHDMintTracker(std::string strWalletFile); @@ -42,8 +43,9 @@ class CHDMintTracker void UpdateFromBlock(const std::list>& mintPoolEntries, const std::vector& updatedMeta); void UpdateMintStateFromBlock(const std::vector& mints); void UpdateSpendStateFromBlock(const sigma::spend_info_container& spentSerials); + void UpdateSpendStateFromMempool(const vector& spentSerials); list MintsAsZerocoinEntries(bool fUnusedOnly = true, bool fMatureOnly = true); - std::vector ListMints(bool fUnusedOnly = true, bool fMatureOnly = true, bool fUpdateStatus = true, bool fWrongSeed = false); + std::vector ListMints(bool fUnusedOnly = true, bool fMatureOnly = true, bool fUpdateStatus = true, bool fLoad = false, bool fWrongSeed = false); void RemovePending(const uint256& txid); void SetPubcoinUsed(const uint256& hashPubcoin, const uint256& txid); void SetPubcoinNotUsed(const uint256& hashPubcoin); diff --git a/src/init.cpp b/src/init.cpp index 16075b2a02..8254f9ce97 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -868,6 +868,9 @@ void ThreadImport(std::vector vImportFiles) { if (!GetBoolArg("-disablewallet", false) && zwalletMain) { zwalletMain->SyncWithChain(); } + if (GetBoolArg("-zapwallettxes", false)) { + pwalletMain->hdMintTracker->ListMints(); + } #endif } diff --git a/src/main.cpp b/src/main.cpp index f918d29a15..a6471fa9eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1800,10 +1800,14 @@ bool AcceptToMemoryPoolWorker( if (tx.IsZerocoinSpend() && markZcoinSpendTransactionSerial) zcState->AddSpendToMempool(zcSpendSerials, hash); - if (tx.IsSigmaSpend() && markZcoinSpendTransactionSerial) - sigmaState->AddSpendToMempool(zcSpendSerialsV3, hash); - + if (tx.IsSigmaSpend()){ + if(markZcoinSpendTransactionSerial) + sigmaState->AddSpendToMempool(zcSpendSerialsV3, hash); + LogPrintf("Updating mint tracker state from Mempool.."); + pwalletMain->hdMintTracker->UpdateSpendStateFromMempool(zcSpendSerialsV3); + } SyncWithWallets(tx, NULL, NULL); + LogPrintf("AcceptToMemoryPoolWorker -> OK\n"); return true; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 91d2f5f67b..257889de0d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2893,7 +2893,7 @@ void CWallet::ListAvailableCoinsMintCoins(vector &vCoins, bool fOnlyCo void CWallet::ListAvailableSigmaMintCoins(vector &vCoins, bool fOnlyConfirmed) const { vCoins.clear(); - LOCK(cs_wallet); + LOCK2(cs_main, cs_wallet); list listOwnCoins; CWalletDB walletdb(pwalletMain->strWalletFile); listOwnCoins = pwalletMain->hdMintTracker->MintsAsZerocoinEntries(); @@ -6946,7 +6946,7 @@ bool CWallet::CommitSigmaTransaction(CWalletTx& wtxNew, std::vector throw std::runtime_error(_("Failed to write coin serial number into wallet")); } - //Set spent mint as used + //Set spent mint as used in memory uint256 hashPubcoin = primitives::GetPubCoinValueHash(coin.value); pwalletMain->hdMintTracker->SetPubcoinUsed(hashPubcoin, wtxNew.GetHash()); CMintMeta metaCheck = pwalletMain->hdMintTracker->GetMetaFromPubcoin(hashPubcoin); @@ -6955,6 +6955,9 @@ bool CWallet::CommitSigmaTransaction(CWalletTx& wtxNew, std::vector LogPrintf("SpendZerocoin() : %s\n", strError.c_str()); } + //Set spent mint as used in DB + pwalletMain->hdMintTracker->UpdateState(metaCheck); + // update CSigmaEntry coin.IsUsed = true; coin.id = id;