Blackcoin Lore
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user