Blackcoin Lore

This commit is contained in:
janko33bd
2017-05-30 21:33:31 +02:00
parent 597c9b42e5
commit 2fdd12b2ea
141 changed files with 4385 additions and 3872 deletions

View File

@@ -30,6 +30,18 @@ using namespace std;
int64_t nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
static void accountingDeprecationCheck()
{
if (!GetBoolArg("-enableaccounts", false))
throw runtime_error(
"Accounting API is deprecated and will be removed in future.\n"
"It can easily result in negative or odd balances if misused or misunderstood, which has happened in the field.\n"
"If you still want to enable it, add to your config file iknowaccountsarebroken=1\n");
if (GetBoolArg("-staking", true))
throw runtime_error("If you want to use accounting API, staking must be disabled, add to your config file staking=0\n");
}
std::string HelpRequiringPassphrase()
{
return pwalletMain && pwalletMain->IsCrypted()
@@ -49,10 +61,17 @@ bool EnsureWalletIsAvailable(bool avoidException)
return true;
}
// optional setting to unlock wallet for staking only
// serves to disable the trivial sendmoney when OS account compromised
// provides no real security
bool fWalletUnlockStakingOnly = false;
void EnsureWalletIsUnlocked()
{
if (pwalletMain->IsLocked())
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
if (fWalletUnlockStakingOnly)
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet is unlocked for staking only.");
}
void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
@@ -367,6 +386,8 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
return ret;
}
static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
{
CAmount curBalance = pwalletMain->GetBalance();
@@ -646,6 +667,8 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
accountingDeprecationCheck();
LOCK2(cs_main, pwalletMain->cs_wallet);
// Minimum confirmations
@@ -778,6 +801,8 @@ UniValue getbalance(const UniValue& params, bool fHelp)
return ValueFromAmount(nBalance);
}
accountingDeprecationCheck();
string strAccount = AccountFromValue(params[0]);
CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
@@ -827,6 +852,8 @@ UniValue movecmd(const UniValue& params, bool fHelp)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
accountingDeprecationCheck();
LOCK2(cs_main, pwalletMain->cs_wallet);
string strFrom = AccountFromValue(params[0]);
@@ -1305,6 +1332,8 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
accountingDeprecationCheck();
LOCK2(cs_main, pwalletMain->cs_wallet);
return ListReceived(params, true);
@@ -1563,6 +1592,8 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listaccounts", "6")
);
accountingDeprecationCheck();
LOCK2(cs_main, pwalletMain->cs_wallet);
int nMinDepth = 1;
@@ -1947,6 +1978,12 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp)
nWalletUnlockTime = GetTime() + nSleepTime;
RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
// ppcoin: if user OS account compromised prevent trivial sendmoney commands
if (params.size() > 2)
fWalletUnlockStakingOnly = params[2].get_bool();
else
fWalletUnlockStakingOnly = false;
return NullUniValue;
}

View File

@@ -16,6 +16,7 @@
#include "main.h"
#include "net.h"
#include "policy/policy.h"
#include "pos.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "script/script.h"
@@ -40,6 +41,9 @@ unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
static int64_t GetStakeCombineThreshold() { return 500 * COIN; }
static int64_t GetStakeSplitThreshold() { return 2 * GetStakeCombineThreshold(); }
/**
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
* Override with -mintxfee
@@ -53,6 +57,8 @@ CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
CAmount nReserveBalance = 0;
CAmount nMinimumInputValue = 0;
/** @defgroup mapWallet
*
@@ -491,6 +497,304 @@ void CWallet::AddToSpends(const uint256& wtxid)
AddToSpends(txin.prevout, wtxid);
}
void CWallet::AvailableCoinsForStaking(std::vector<COutput>& vCoins) const
{
vCoins.clear();
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
int nDepth = pcoin->GetDepthInMainChain();
if (nDepth < 1)
continue;
if (nDepth < nStakeMinConfirmations)
continue;
if (pcoin->GetBlocksToMaturity() > 0)
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
isminetype mine = IsMine(pcoin->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0))
vCoins.push_back(COutput(pcoin, i, nDepth,
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
(mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO));
}
}
}
}
// Select some coins without random shuffle or best subset approximation
bool CWallet::SelectCoinsForStaking(CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
{
vector<COutput> vCoins;
AvailableCoinsForStaking(vCoins);
setCoinsRet.clear();
nValueRet = 0;
BOOST_FOREACH(COutput output, vCoins)
{
const CWalletTx *pcoin = output.tx;
int i = output.i;
// Stop if we've chosen enough inputs
if (nValueRet >= nTargetValue)
break;
int64_t n = pcoin->vout[i].nValue;
pair<int64_t,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
if (n >= nTargetValue)
{
// If input value is greater or equal to target then simply insert
// it into the current subset and exit
setCoinsRet.insert(coin.second);
nValueRet += coin.first;
break;
}
else if (n < nTargetValue + CENT)
{
setCoinsRet.insert(coin.second);
nValueRet += coin.first;
}
}
return true;
}
bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, int64_t nTime, const COutPoint& prevout, int64_t* pBlockTime)
{
uint256 hashProofOfStake, targetProofOfStake;
CTransaction txPrev;
CDiskTxPos txindex;
if (!ReadFromDisk(txPrev, txindex, *pblocktree, prevout))
return false;
// Read block header
CBlock block;
const CDiskBlockPos& pos = CDiskBlockPos(txindex.nFile, txindex.nPos);
if (!ReadBlockFromDisk(block, pos, Params().GetConsensus()))
return false;
int nDepth;
if (IsConfirmedInNPrevBlocks(txindex, pindexPrev, nStakeMinConfirmations - 1, nDepth))
return false;
if (pBlockTime)
*pBlockTime = block.GetBlockTime();
LogPrintf("looking for coinstake for real \n");
return CheckStakeKernelHash(pindexPrev, nBits, new CCoins(txPrev, pindexPrev->nHeight), prevout, nTime);
}
// miner's coin stake reward
int64_t GetProofOfStakeReward(const CBlockIndex* pindexPrev, int64_t nCoinAge, int64_t nFees)
{
int64_t nSubsidy;
if (Params().GetConsensus().IsProtocolV3(pindexPrev->nTime))
nSubsidy = COIN * 3 / 2;
else
nSubsidy = nCoinAge * 1 * CENT * 33 / (365 * 33 + 8);
LogPrint("creation", "GetProofOfStakeReward(): create=%s nCoinAge=%d\n", FormatMoney(nSubsidy), nCoinAge);
return nSubsidy + nFees;
}
bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CAmount& nFees, CMutableTransaction& tx, CKey& key)
{
CBlockIndex* pindexPrev = pindexBestHeader;
arith_uint256 bnTargetPerCoinDay;
bnTargetPerCoinDay.SetCompact(nBits);
struct CMutableTransaction txNew(tx);
txNew.vin.clear();
txNew.vout.clear();
// Mark coin stake transaction
CScript scriptEmpty;
scriptEmpty.clear();
txNew.vout.push_back(CTxOut(0, scriptEmpty));
// Choose coins to use
CAmount nBalance = GetBalance();
if (nBalance <= nReserveBalance)
return false;
vector<const CWalletTx*> vwtxPrev;
set<pair<const CWalletTx*,unsigned int> > setCoins;
CAmount nValueIn = 0;
// Select coins with suitable depth
CAmount nTargetValue = nBalance - nReserveBalance;
if (!SelectCoinsForStaking(nTargetValue, setCoins, nValueIn))
return false;
if (setCoins.empty())
return false;
int64_t nCredit = 0;
CScript scriptPubKeyKernel;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*, unsigned int)& pcoin, setCoins)
{
static int nMaxStakeSearchInterval = 60;
bool fKernelFound = false;
for (unsigned int n=0; n<min(nSearchInterval,(int64_t)nMaxStakeSearchInterval) && !fKernelFound && pindexPrev == pindexBestHeader; n++)
{
boost::this_thread::interruption_point();
// Search backward in time from the given txNew timestamp
// Search nSearchInterval seconds back up to nMaxStakeSearchInterval
COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second);
int64_t nBlockTime;
//LogPrintf("looking for coinstake \n");
if (CheckKernel(pindexPrev, nBits, txNew.nTime - n, prevoutStake, &nBlockTime))
{
// Found a kernel
LogPrint("coinstake", "CreateCoinStake : kernel found\n");
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
CScript scriptPubKeyOut;
scriptPubKeyKernel = pcoin.first->vout[pcoin.second].scriptPubKey;
if (!Solver(scriptPubKeyKernel, whichType, vSolutions))
{
LogPrint("coinstake", "CreateCoinStake : failed to parse kernel\n");
break;
}
LogPrint("coinstake", "CreateCoinStake : parsed kernel type=%d\n", whichType);
if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH)
{
LogPrint("coinstake", "CreateCoinStake : no support for kernel type=%d\n", whichType);
break; // only support pay to public key and pay to address
}
if (whichType == TX_PUBKEYHASH) // pay to address type
{
// convert to pay to public key type
if (!keystore.GetKey(uint160(vSolutions[0]), key))
{
LogPrint("coinstake", "CreateCoinStake : failed to get key for kernel type=%d\n", whichType);
break; // unable to find corresponding public key
}
scriptPubKeyOut << key.GetPubKey().getvch() << OP_CHECKSIG;
}
if (whichType == TX_PUBKEY)
{
if (!keystore.GetKey(Hash160(vSolutions[0]), key))
{
LogPrint("coinstake", "CreateCoinStake : failed to get key for kernel type=%d\n", whichType);
break; // unable to find corresponding public key
}
if (key.GetPubKey() != vSolutions[0])
{
LogPrint("coinstake", "CreateCoinStake : invalid key for kernel type=%d\n", whichType);
break; // keys mismatch
}
scriptPubKeyOut = scriptPubKeyKernel;
}
txNew.nTime -= n;
txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
nCredit += pcoin.first->vout[pcoin.second].nValue;
vwtxPrev.push_back(pcoin.first);
txNew.vout.push_back(CTxOut(0, scriptPubKeyOut));
LogPrint("coinstake", "CreateCoinStake : added kernel type=%d\n", whichType);
fKernelFound = true;
break;
}
}
if (fKernelFound)
break; // if kernel is found stop searching
}
if (nCredit == 0 || nCredit > nBalance - nReserveBalance)
return false;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*, unsigned int)& pcoin, setCoins)
{
// 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)
{
// Stop adding more inputs if already too many inputs
if (txNew.vin.size() >= 10)
break;
// Stop adding inputs if reached reserve limit
if (nCredit + pcoin.first->vout[pcoin.second].nValue > nBalance - nReserveBalance)
break;
// Do not add additional significant input
if (pcoin.first->vout[pcoin.second].nValue >= GetStakeCombineThreshold())
continue;
txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
nCredit += pcoin.first->vout[pcoin.second].nValue;
vwtxPrev.push_back(pcoin.first);
}
}
// Calculate coin age reward
{
uint64_t nCoinAge;
if (!GetCoinAge(txNew, *pblocktree, pindexPrev, nCoinAge))
return error("CreateCoinStake : failed to calculate coin age");
int64_t nReward = GetProofOfStakeReward(pindexPrev, nCoinAge, nFees);
if (nReward <= 0)
return false;
nCredit += nReward;
}
if (nCredit >= GetStakeSplitThreshold())
txNew.vout.push_back(CTxOut(0, txNew.vout[1].scriptPubKey)); //split stake
// Set output amount
if (txNew.vout.size() == 3)
{
txNew.vout[1].nValue = (nCredit / 2 / CENT) * CENT;
txNew.vout[2].nValue = nCredit - txNew.vout[1].nValue;
}
else
txNew.vout[1].nValue = nCredit;
// Sign
int nIn = 0;
BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev)
{
if (!SignSignature(*this, *pcoin, txNew, nIn++, SIGHASH_ALL))
return error("CreateCoinStake : failed to sign coinstake");
}
// Limit size
unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_STANDARD_TX_SIZE)
return error("CreateCoinStake : exceeded coinstake size limit");
// Successfully generated coinstake
tx = CTransaction(txNew);
return true;
}
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
@@ -1051,7 +1355,7 @@ int CWalletTx::GetRequestCount() const
int nRequests = -1;
{
LOCK(pwallet->cs_wallet);
if (IsCoinBase())
if (IsCoinBase() || IsCoinStake())
{
// Generated block
if (!hashUnset())
@@ -1120,7 +1424,7 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
// In either case, we need to get the destination address
CTxDestination address;
if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
if (!ExtractDestination(txout.scriptPubKey, address)&& !txout.IsUnspendable())
{
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
@@ -1244,7 +1548,7 @@ void CWallet::ReacceptWalletTransactions()
int nDepth = wtx.GetDepthInMainChain();
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
if (!wtx.IsCoinBase() && !wtx.IsCoinStake() && (nDepth == 0 && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
}
@@ -1262,7 +1566,7 @@ void CWallet::ReacceptWalletTransactions()
bool CWalletTx::RelayWalletTransaction()
{
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
if (!IsCoinBase() && !IsCoinStake())
{
if (GetDepthInMainChain() == 0 && !isAbandoned()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
@@ -1319,7 +1623,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
CAmount CWalletTx::GetCredit(const isminefilter& filter) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
return 0;
int64_t credit = 0;
@@ -1351,7 +1655,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
{
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0 && IsInMainChain())
{
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
@@ -1363,13 +1667,27 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
return 0;
}
CAmount CWalletTx::GetImmatureStakeCredit(bool fUseCache) const
{
if (IsCoinStake() && GetBlocksToMaturity() > 0 && IsInMainChain())
{
if (fUseCache && fImmatureStakeCreditCached)
return nImmatureStakeCreditCached;
nImmatureStakeCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
fImmatureStakeCreditCached = true;
return nImmatureStakeCreditCached;
}
return 0;
}
CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
{
if (pwallet == 0)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
return 0;
if (fUseCache && fAvailableCreditCached)
@@ -1395,7 +1713,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
{
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0 && IsInMainChain())
{
if (fUseCache && fImmatureWatchCreditCached)
return nImmatureWatchCreditCached;
@@ -1413,7 +1731,7 @@ CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
return 0;
if (fUseCache && fAvailableWatchCreditCached)
@@ -1597,6 +1915,20 @@ CAmount CWallet::GetImmatureBalance() const
return nTotal;
}
CAmount CWallet::GetStakeBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
nTotal += pcoin->GetImmatureStakeCredit();
}
}
return nTotal;
}
CAmount CWallet::GetWatchOnlyBalance() const
{
CAmount nTotal = 0;
@@ -1659,7 +1991,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (fOnlyConfirmed && !pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0)
continue;
int nDepth = pcoin->GetDepthInMainChain();
@@ -1891,7 +2223,7 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
}
bool res = nTargetValue <= nValueFromPresetInputs ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 10, vCoins, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet));
@@ -1996,6 +2328,8 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
txNew.nLockTime = chainActive.Height();
txNew.nTime = GetAdjustedTime();
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
@@ -2322,6 +2656,8 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
// But always obey the maximum
if (nFeeNeeded > maxTxFee)
nFeeNeeded = maxTxFee;
if(nFeeNeeded < DEFAULT_TRANSACTION_FEE)
nFeeNeeded = DEFAULT_TRANSACTION_FEE;
return nFeeNeeded;
}
@@ -2586,7 +2922,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
if (!CheckFinalTx(*pcoin) || !pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0)
continue;
int nDepth = pcoin->GetDepthInMainChain();
@@ -2831,6 +3167,38 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
}
}
uint64_t CWallet::GetStakeWeight() const
{
// Choose coins to use
CAmount nBalance = GetBalance();
if (nBalance <= nReserveBalance)
return 0;
vector<const CWalletTx*> vwtxPrev;
set<pair<const CWalletTx*,unsigned int> > setCoins;
CAmount nValueIn = 0;
CAmount nTargetValue = nBalance - nReserveBalance;
if (!SelectCoinsForStaking(nTargetValue, setCoins, nValueIn))
return 0;
if (setCoins.empty())
return 0;
uint64_t nWeight = 0;
LOCK2(cs_main, cs_wallet);
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
if (pcoin.first->GetDepthInMainChain() >= nStakeMinConfirmations)
nWeight += pcoin.first->vout[pcoin.second].nValue;
}
return nWeight;
}
/** @} */ // end of Actions
class CAffectedKeysVisitor : public boost::static_visitor<void> {
@@ -3027,7 +3395,7 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
if (!(IsCoinBase() || IsCoinStake()))
return 0;
return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
}

View File

@@ -32,21 +32,24 @@
*/
extern CFeeRate payTxFee;
extern CAmount maxTxFee;
extern CAmount nReserveBalance;
extern CAmount nMinimumInputValue;
extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
extern bool fSendFreeTransactions;
extern bool fWalletUnlockStakingOnly;
static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
//! -paytxfee default
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
static const CAmount DEFAULT_TRANSACTION_FEE = 10000;
//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
static const CAmount nHighTransactionFeeWarning = 0.01 * COIN;
static const CAmount nHighTransactionFeeWarning = 0.1 * COIN;
//! -fallbackfee default
static const CAmount DEFAULT_FALLBACK_FEE = 20000;
static const CAmount DEFAULT_FALLBACK_FEE = 10000;
//! -mintxfee default
static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
static const CAmount DEFAULT_TRANSACTION_MINFEE = 10000;
//! -maxtxfee default
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 1 * COIN;
//! minimum change amount
static const CAmount MIN_CHANGE = CENT;
//! Default for -spendzeroconfchange
@@ -240,6 +243,7 @@ public:
mutable bool fDebitCached;
mutable bool fCreditCached;
mutable bool fImmatureCreditCached;
mutable bool fImmatureStakeCreditCached;
mutable bool fAvailableCreditCached;
mutable bool fWatchDebitCached;
mutable bool fWatchCreditCached;
@@ -249,6 +253,7 @@ public:
mutable CAmount nDebitCached;
mutable CAmount nCreditCached;
mutable CAmount nImmatureCreditCached;
mutable CAmount nImmatureStakeCreditCached;
mutable CAmount nAvailableCreditCached;
mutable CAmount nWatchDebitCached;
mutable CAmount nWatchCreditCached;
@@ -289,7 +294,9 @@ public:
fDebitCached = false;
fCreditCached = false;
fImmatureCreditCached = false;
fImmatureStakeCreditCached = false;
fAvailableCreditCached = false;
fImmatureCreditCached = false;
fWatchDebitCached = false;
fWatchCreditCached = false;
fImmatureWatchCreditCached = false;
@@ -298,6 +305,7 @@ public:
nDebitCached = 0;
nCreditCached = 0;
nImmatureCreditCached = 0;
nImmatureStakeCreditCached = 0;
nAvailableCreditCached = 0;
nWatchDebitCached = 0;
nWatchCreditCached = 0;
@@ -374,6 +382,7 @@ public:
CAmount GetDebit(const isminefilter& filter) const;
CAmount GetCredit(const isminefilter& filter) const;
CAmount GetImmatureCredit(bool fUseCache=true) const;
CAmount GetImmatureStakeCredit(bool fUseCache=true) const;
CAmount GetAvailableCredit(bool fUseCache=true) const;
CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const;
CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const;
@@ -653,6 +662,7 @@ public:
CAmount GetBalance() const;
CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const;
CAmount GetStakeBalance() const;
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
@@ -795,6 +805,10 @@ public:
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx);
bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CAmount& nFees, CMutableTransaction& tx, CKey& key);
bool SelectCoinsForStaking(CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
void AvailableCoinsForStaking(std::vector<COutput>& vCoins) const;
uint64_t GetStakeWeight() const;
};
/** A key allocated from the key pool. */
@@ -934,5 +948,5 @@ public:
private:
std::vector<char> _ssExtra;
};
bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, int64_t nTime, const COutPoint& prevout, int64_t* pBlockTime = NULL);
#endif // BITCOIN_WALLET_WALLET_H