* 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.
}
// 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;
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
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());
{
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());
}
}
// 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
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
// 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);
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;
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());
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"))
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)
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);
}
}
// 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;