From ca78b9e6a859e32fbe36e7afb12c9c9403e8a5b0 Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Thu, 21 Aug 2014 00:42:55 +0400 Subject: [PATCH] Coins metadata load fixes * Don't load coin and meta if we unable to calculate suitable stake modifier for this coin; * Move definition of MapMeta to CWallet class; * Use MapMeta for stake weight calculation. --- src/kernel.cpp | 33 ++++++++++-------------- src/kernel.h | 14 +++++----- src/wallet.cpp | 75 ++++++++++++++++++------------------------------------- src/wallet.h | 3 ++ 4 files changed, 49 insertions(+), 76 deletions(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index 18db341..c4283ed 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -390,27 +390,22 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned } // Scan given coins set for kernel solution -bool ScanForStakeKernelHash(CoinsSet &setCoins, MetaMap &mapMeta, KernelSearchSettings &settings, CoinsSet::value_type &kernelcoin, unsigned int &nTimeTx, unsigned int &nBlockTime) +bool ScanForStakeKernelHash(MetaMap &mapMeta, KernelSearchSettings &settings, CoinsSet::value_type &kernelcoin, unsigned int &nTimeTx, unsigned int &nBlockTime) { uint256 hashProofOfStake = 0; - for(CoinsSet::const_iterator pcoin = setCoins.begin(); pcoin != setCoins.end(); pcoin++) + // txid => ((txindex, (tx, vout.n)), (block, modifier)) + for(MetaMap::const_iterator meta_item = mapMeta.begin(); meta_item != mapMeta.end(); meta_item++) { if (!fCoinsDataActual) break; - MetaMap::const_iterator mi = mapMeta.find(pcoin->first->GetHash()); - if (mi == mapMeta.end()) - { - if (fDebug) - printf("Unable to find %s in mapMeta, stopping\n", pcoin->first->GetHash().GetHex().c_str()); - fCoinsDataActual = false; - break; - } + CTxIndex txindex = (*meta_item).second.first.first; + CBlock block = (*meta_item).second.second.first; + uint64 nStakeModifier = (*meta_item).second.second.second; - CTxIndex txindex = (*mi).second.first; - CBlock block = (*mi).second.second.first; - uint64 nStakeModifier = (*mi).second.second.second; + // Get coin + CoinsSet::value_type pcoin = meta_item->second.first.second; static int nMaxStakeSearchInterval = 60; @@ -427,7 +422,7 @@ bool ScanForStakeKernelHash(CoinsSet &setCoins, MetaMap &mapMeta, KernelSearchSe nBlockTime = block.nTime; CBigNum bnTargetPerCoinDay; bnTargetPerCoinDay.SetCompact(settings.nBits); - int64 nValueIn = pcoin->first->vout[pcoin->second].nValue; + int64 nValueIn = pcoin.first->vout[pcoin.second].nValue; // Search backward in time from the given timestamp // Search nSearchInterval seconds back up to nMaxStakeSearchInterval @@ -435,13 +430,13 @@ bool ScanForStakeKernelHash(CoinsSet &setCoins, MetaMap &mapMeta, KernelSearchSe for (unsigned int n=0; nfirst->nTime, (int64)nTimeTx) / COIN / (24 * 60 * 60); + CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64)pcoin.first->nTime, (int64)nTimeTx) / COIN / (24 * 60 * 60); CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay; // Build kernel CDataStream ss(SER_GETHASH, 0); ss << nStakeModifier; - ss << nBlockTime << nTxOffset << pcoin->first->nTime << pcoin->second << nTimeTx; + ss << nBlockTime << nTxOffset << pcoin.first->nTime << pcoin.second << nTimeTx; // Calculate kernel hash hashProofOfStake = Hash(ss.begin(), ss.end()); @@ -450,15 +445,15 @@ bool ScanForStakeKernelHash(CoinsSet &setCoins, MetaMap &mapMeta, KernelSearchSe { if (fDebug) printf("nStakeModifier=0x%016"PRI64x", nBlockTime=%u nTxOffset=%u nTxPrevTime=%u nVout=%u nTimeTx=%u hashProofOfStake=%s Success=true\n", - nStakeModifier, nBlockTime, nTxOffset, pcoin->first->nTime, pcoin->second, nTimeTx, hashProofOfStake.GetHex().c_str()); + nStakeModifier, nBlockTime, nTxOffset, pcoin.first->nTime, pcoin.second, nTimeTx, hashProofOfStake.GetHex().c_str()); - kernelcoin = *pcoin; + kernelcoin = pcoin; return true; } if (fDebug) printf("nStakeModifier=0x%016"PRI64x", nBlockTime=%u nTxOffset=%u nTxPrevTime=%u nTxNumber=%u nTimeTx=%u hashProofOfStake=%s Success=false\n", - nStakeModifier, nBlockTime, nTxOffset, pcoin->first->nTime, pcoin->second, nTimeTx, hashProofOfStake.GetHex().c_str()); + nStakeModifier, nBlockTime, nTxOffset, pcoin.first->nTime, pcoin.second, nTimeTx, hashProofOfStake.GetHex().c_str()); } } diff --git a/src/kernel.h b/src/kernel.h index d24cac3..a0632f9 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -33,12 +33,6 @@ bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier); // Sets hashProofOfStake on success return bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool fPrintProofOfStake=false); -// Preloaded coins set -typedef set > CoinsSet; - -// Preloaded coins metadata (block header and stake modifier) -typedef map > > MetaMap; - // Coins scanning options typedef struct KernelSearchSettings { unsigned int nBits; // Packed difficulty @@ -48,8 +42,14 @@ typedef struct KernelSearchSettings { unsigned int nSearchInterval; // Number of seconds allowed to go into the past } KernelSearchSettings; +typedef set > CoinsSet; + +// Preloaded coins metadata +// txid => ((txindex, (tx, vout.n)), (block, modifier)) +typedef map >, pair > > MetaMap; + // Scan given coins set for kernel solution -bool ScanForStakeKernelHash(CoinsSet &setCoins, MetaMap &mapMeta, KernelSearchSettings &settings, CoinsSet::value_type &kernelcoin, unsigned int &nTimeTx, unsigned int &nBlockTime); +bool ScanForStakeKernelHash(MetaMap &mapMeta, KernelSearchSettings &settings, CoinsSet::value_type &kernelcoin, unsigned int &nTimeTx, unsigned int &nBlockTime); // Check kernel hash target and coinstake signature // Sets hashProofOfStake on success return diff --git a/src/wallet.cpp b/src/wallet.cpp index 477c4f3..22659da 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1620,40 +1620,15 @@ void CWallet::GetStakeWeightFromValue(const int64& nTime, const int64& nValue, u // NovaCoin: get current stake weight bool CWallet::GetStakeWeight(const CKeyStore& keystore, uint64& nMinWeight, uint64& nMaxWeight, uint64& nWeight) { - // Choose coins to use - int64 nBalance = GetBalance(); - int64 nReserveBalance = 0; - - if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) - { - error("GetStakeWeight : invalid reserve balance amount"); - return false; - } - - if (nBalance <= nReserveBalance) + if (mapMeta.size() == 0 || !fCoinsDataActual) return false; - vector vwtxPrev; - - static set > setCoins; - static uint256 hashPrevBlock; - - // Cache outputs unless best block or wallet transaction set changed - if (!fCoinsDataActual || setCoins.size() == 0) + // txid => ((txindex, (tx, vout.n)), (block, modifier)) + for(MetaMap::const_iterator meta_item = mapMeta.begin(); meta_item != mapMeta.end(); meta_item++) { - int64 nValueIn = 0; - if (!SelectCoinsSimple(nBalance - nReserveBalance, GetAdjustedTime(), nCoinbaseMaturity * 10, setCoins, nValueIn)) - return false; + // Get coin + CoinsSet::value_type pcoin = meta_item->second.first.second; - if (setCoins.empty()) - return false; - - fCoinsDataActual = true; - } - - CTxDB txdb("r"); - BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) - { int64 nTimeWeight = GetWeight((int64)pcoin.first->nTime, (int64)GetTime()); CBigNum bnCoinDayWeight = CBigNum(pcoin.first->vout[pcoin.second].nValue) * nTimeWeight / COIN / (24 * 60 * 60); @@ -1836,19 +1811,15 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int vector vwtxPrev; - static CoinsSet setCoins; - static MetaMap mapMeta; - CTxDB txdb("r"); { LOCK2(cs_main, cs_wallet); // Cache outputs unless best block or wallet transaction set changed - if (!fCoinsDataActual || setCoins.size() == 0) + if (!fCoinsDataActual) { - setCoins.clear(); mapMeta.clear(); - int64 nValueIn = 0; + CoinsSet setCoins; if (!SelectCoinsSimple(nBalance - nReserveBalance, txNew.nTime, nCoinbaseMaturity * 10, setCoins, nValueIn)) return false; @@ -1869,12 +1840,12 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int continue; uint64 nStakeModifier = 0; - if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) - return false; + continue; // Add meta record - mapMeta[pcoin->first->GetHash()] = make_pair(txindex, make_pair(block, nStakeModifier)); + // txid => ((txindex, (tx, vout.n)), (block, modifier)) + mapMeta[pcoin->first->GetHash()] = make_pair(make_pair(txindex, *pcoin), make_pair(block, nStakeModifier)); if (fDebug) printf("Load coin: %s\n", pcoin->first->GetHash().GetHex().c_str()); @@ -1895,14 +1866,14 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int settings.nBits = nBits; settings.nTime = txNew.nTime; settings.nOffset = 0; - settings.nLimit = setCoins.size(); + settings.nLimit = mapMeta.size(); settings.nSearchInterval = nSearchInterval; unsigned int nTimeTx, nBlockTime; COutPoint prevoutStake; CoinsSet::value_type kernelcoin; - if (ScanForStakeKernelHash(setCoins, mapMeta, settings, kernelcoin, nTimeTx, nBlockTime)) + if (ScanForStakeKernelHash(mapMeta, settings, kernelcoin, nTimeTx, nBlockTime)) { // Found a kernel if (fDebug && GetBoolArg("-printcoinstake")) @@ -1970,14 +1941,18 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int if (nCredit == 0 || nCredit > nBalance - nReserveBalance) return false; - for(CoinsSet::const_iterator pcoin = setCoins.begin(); pcoin != setCoins.end(); pcoin++) + // txid => ((txindex, (tx, vout.n)), (block, modifier)) + for(MetaMap::const_iterator meta_item = mapMeta.begin(); meta_item != mapMeta.end(); meta_item++) { + // Get coin + CoinsSet::value_type pcoin = meta_item->second.first.second; + // Attempt to add more inputs // Only add coins of the same key/address as kernel - if (txNew.vout.size() == 2 && ((pcoin->first->vout[pcoin->second].scriptPubKey == scriptPubKeyKernel || pcoin->first->vout[pcoin->second].scriptPubKey == txNew.vout[1].scriptPubKey)) - && pcoin->first->GetHash() != txNew.vin[0].prevout.hash) + if (txNew.vout.size() == 2 && ((pcoin.first->vout[pcoin.second].scriptPubKey == scriptPubKeyKernel || pcoin.first->vout[pcoin.second].scriptPubKey == txNew.vout[1].scriptPubKey)) + && pcoin.first->GetHash() != txNew.vin[0].prevout.hash) { - int64 nTimeWeight = GetWeight((int64)pcoin->first->nTime, (int64)txNew.nTime); + int64 nTimeWeight = GetWeight((int64)pcoin.first->nTime, (int64)txNew.nTime); // Stop adding more inputs if already too many inputs if (txNew.vin.size() >= 100) @@ -1986,18 +1961,18 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int if (nCredit > nCombineThreshold) break; // Stop adding inputs if reached reserve limit - if (nCredit + pcoin->first->vout[pcoin->second].nValue > nBalance - nReserveBalance) + if (nCredit + pcoin.first->vout[pcoin.second].nValue > nBalance - nReserveBalance) break; // Do not add additional significant input - if (pcoin->first->vout[pcoin->second].nValue > nCombineThreshold) + if (pcoin.first->vout[pcoin.second].nValue > nCombineThreshold) continue; // Do not add input that is still too young if (nTimeWeight < nStakeMaxAge) continue; - txNew.vin.push_back(CTxIn(pcoin->first->GetHash(), pcoin->second)); - nCredit += pcoin->first->vout[pcoin->second].nValue; - vwtxPrev.push_back(pcoin->first); + txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); + nCredit += pcoin.first->vout[pcoin.second].nValue; + vwtxPrev.push_back(pcoin.first); } } diff --git a/src/wallet.h b/src/wallet.h index 9a41935..195a6ce 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -80,6 +80,9 @@ private: // the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded int nWalletMaxVersion; + // selected coins metadata + map >, pair > > mapMeta; + public: mutable CCriticalSection cs_wallet; -- 1.7.1