#include "ui_interface.h"
#include "base58.h"
#include "kernel.h"
+#include <boost/algorithm/string/replace.hpp>
using namespace std;
extern int nStakeMaxAge;
if (fCompressed)
SetMinVersion(FEATURE_COMPRPUBKEY);
+ CPubKey pubkey = key.GetPubKey();
+
+ // Create new metadata
+ int64 nCreationTime = GetTime();
+ mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
+ if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
+ nTimeFirstKey = nCreationTime;
+
if (!AddKey(key))
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
return key.GetPubKey();
}
-bool CWallet::AddKey(const CKey& key, int64 nCreateTime)
+bool CWallet::AddKey(const CKey& key)
{
- if(!nCreateTime)
- nCreateTime = GetTime();
- if (!nTimeFirstKey || nCreateTime < nTimeFirstKey)
- nTimeFirstKey = nCreateTime;
+ CPubKey pubkey = key.GetPubKey();
if (!CCryptoKeyStore::AddKey(key))
return false;
if (!fFileBacked)
return true;
if (!IsCrypted())
- return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey(), nCreateTime);
+ return CWalletDB(strWalletFile).WriteKey(pubkey, key.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]);
return true;
}
-bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char> &vchCryptedSecret, int64 nCreateTime)
+bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
{
- if(!nCreateTime)
- nCreateTime = GetTime();
- if (!nTimeFirstKey || nCreateTime < nTimeFirstKey)
- nTimeFirstKey = nCreateTime;
-
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
if (!fFileBacked)
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
- return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret, nCreateTime);
+ return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]);
else
- return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, nCreateTime);
+ return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]);
}
return false;
}
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+
+ // notify an external script when a wallet transaction comes in or is updated
+ std::string strCmd = GetArg("-walletnotify", "");
+
+ if ( !strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+
}
return true;
}
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (pcoin->IsFinal() && pcoin->IsConfirmed())
+ if (pcoin->IsConfirmed())
nTotal += pcoin->GetAvailableCredit();
}
}
return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
}
-// NovaCoin: get current stake generation power
-uint64 CWallet::GetStakeMintPower(const CKeyStore& keystore, enum StakeWeightMode mode)
+// NovaCoin: get current stake weight
+uint64 CWallet::GetStakeWeight(const CKeyStore& keystore, enum StakeWeightMode mode)
{
LOCK2(cs_main, cs_wallet);
if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
{
- error("CreateCoinStake : invalid reserve balance amount");
+ error("GetStakeWeight : invalid reserve balance amount");
return 0;
}
if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex))
continue;
+ unsigned int nTime = pcoin.first->nTime;
+
switch(mode)
{
case STAKE_NORMAL:
// Do not count input that is still less than 30 days old
- if (pcoin.first->nTime + nStakeMinAge > GetTime())
+ if (nTime + nStakeMinAge > GetTime())
continue;
break;
case STAKE_MAXWEIGHT:
// Do not count input that is still less than 90 days old
- if (pcoin.first->nTime + nStakeMaxAge > GetTime())
+ if (nTime + nStakeMaxAge > GetTime())
continue;
break;
case STAKE_MINWEIGHT:
// Count only inputs with suitable age (from 30 to 90 days old)
- if (pcoin.first->nTime + nStakeMaxAge < GetTime())
+ if (nTime + nStakeMaxAge < GetTime())
continue;
- if (pcoin.first->nTime + nStakeMinAge > GetTime())
- continue;
- break;
- case STAKE_BELOWMIN:
- // Count only inputs with suitable age (less than 30 days old)
- if (pcoin.first->nTime + nStakeMinAge < GetTime())
+ if (nTime + nStakeMinAge > GetTime())
continue;
break;
}
- CBigNum bnCentSecond = CBigNum(pcoin.first->vout[pcoin.second].nValue) * (GetTime()-pcoin.first->nTime) / CENT;
- CBigNum bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
+ int64 nTimeWeight;
+
+ // Kernel hash weight starts from 0 at the 30-day min age
+ // this change increases active coins participating the hash and helps
+ // to secure the network when proof-of-stake difficulty is low
+ //
+ if(fTestNet || (STAKEWEIGHT_SWITCH_TIME < nTime))
+ {
+ // New rule since 01 Jan 2014: Maximum TimeWeight is 90 days.
+ nTimeWeight = min((int64)GetTime() - nTime - nStakeMinAge, (int64)nStakeMaxAge);
+ }
+ else
+ {
+ // Current rule: Maximum TimeWeight is 60 days.
+ nTimeWeight = min((int64)GetTime() - nTime, (int64)nStakeMaxAge) - nStakeMinAge;
+ }
+ CBigNum bnCoinDayWeight = CBigNum(pcoin.first->vout[pcoin.second].nValue) * nTimeWeight / COIN / (24 * 60 * 60);
- nCoinAge += bnCoinDay.getuint64();
+ nCoinAge += bnCoinDayWeight.getuint64();
}
if (fDebug && GetBoolArg("-printcoinage"))
- printf("StakePower bnCoinDay=%"PRI64d"\n", nCoinAge);
+ printf("StakeWeight bnCoinDay=%"PRI64d"\n", nCoinAge);
return nCoinAge;
}
{
// Search backward in time from the given txNew timestamp
// Search nSearchInterval seconds back up to nMaxStakeSearchInterval
- uint256 hashProofOfStake = 0;
+ uint256 hashProofOfStake = 0, targetProofOfStake = 0;
COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second);
- if (CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, *pcoin.first, prevoutStake, txNew.nTime - n, hashProofOfStake))
+ if (CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, *pcoin.first, prevoutStake, txNew.nTime - n, hashProofOfStake, targetProofOfStake))
{
// Found a kernel
if (fDebug && GetBoolArg("-printcoinstake"))
// Set output amount
if (txNew.vout.size() == 3)
{
+ // Should we use keys from pool for the last coinstake output?
+ if (fStakeUsePooledKeys)
+ {
+ CReserveKey reservekey((CWallet*) &keystore);
+
+ // Replace current key with the new one
+ txNew.vout[2].SetNull();
+ txNew.vout[2].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+
+ // Remove key from pool
+ reservekey.KeepKey();
+ }
+
txNew.vout[1].nValue = ((nCredit - nMinFee) / 2 / CENT) * CENT;
txNew.vout[2].nValue = nCredit - nMinFee - txNew.vout[1].nValue;
}
return true;
}
-bool CWallet::TopUpKeyPool()
+bool CWallet::TopUpKeyPool(unsigned int nSize)
{
{
LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile);
// Top up key pool
- unsigned int nTargetSize = max(GetArg("-keypool", 100), 0LL);
+ unsigned int nTargetSize;
+ if (nSize > 0)
+ nTargetSize = nSize;
+ else
+ nTargetSize = max(GetArg("-keypool", 100), 0LL);
+
while (setKeyPool.size() < (nTargetSize + 1))
{
int64 nEnd = 1;