Coins metadata load fixes
authorCryptoManiac <balthazar@yandex.ru>
Wed, 20 Aug 2014 20:42:55 +0000 (00:42 +0400)
committerCryptoManiac <balthazar@yandex.ru>
Wed, 20 Aug 2014 20:42:55 +0000 (00:42 +0400)
* 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
src/kernel.h
src/wallet.cpp
src/wallet.h

index 18db341..c4283ed 100644 (file)
@@ -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; n<nCurrentSearchInterval && fCoinsDataActual && !fShutdown; n++)
         {
             nTimeTx = settings.nTime - n;
-            CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64)pcoin->first->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());
         }
     }
 
index d24cac3..a0632f9 100644 (file)
@@ -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<pair<const CWalletTx*,unsigned int> > CoinsSet;
-
-// Preloaded coins metadata (block header and stake modifier)
-typedef map<uint256, pair<CTxIndex, pair<CBlock, uint64> > > 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<pair<const CWalletTx*,unsigned int> > CoinsSet;
+
+// Preloaded coins metadata
+// txid => ((txindex, (tx, vout.n)), (block, modifier))
+typedef map<uint256, pair<pair<CTxIndex, pair<const CWalletTx*,unsigned int> >, pair<CBlock, uint64> > > 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
index 477c4f3..22659da 100644 (file)
@@ -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<const CWalletTx*> vwtxPrev;
-
-    static set<pair<const CWalletTx*,unsigned int> > 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<const CWalletTx*> 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);
         }
     }
 
index 9a41935..195a6ce 100644 (file)
@@ -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<uint256, pair<pair<CTxIndex, pair<const CWalletTx*,unsigned int> >, pair<CBlock, uint64> > > mapMeta;
+
 public:
     mutable CCriticalSection cs_wallet;