main.cpp

Created Diff never expires
20 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
811 lines
22 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
812 lines
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// file COPYING or http://www.opensource.org/licenses/mit-license.php.


#include "alert.h"
#include "alert.h"
#include "checkpoints.h"
#include "checkpoints.h"
#include "db.h"
#include "db.h"
#include "txdb.h"
#include "net.h"
#include "net.h"
#include "init.h"
#include "init.h"
#include "ui_interface.h"
#include "ui_interface.h"
#include "kernel.h"
#include "kernel.h"
#include "scrypt_mine.h"
#include "scrypt_mine.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/config.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/uniform_int_distribution.hpp>


using namespace std;
using namespace std;
using namespace boost;
using namespace boost;


//
//
// Global state
// Global state
//
//


CCriticalSection cs_setpwalletRegistered;
CCriticalSection cs_setpwalletRegistered;
set<CWallet*> setpwalletRegistered;
set<CWallet*> setpwalletRegistered;


CCriticalSection cs_main;
CCriticalSection cs_main;


CTxMemPool mempool;
CTxMemPool mempool;
unsigned int nTransactionsUpdated = 0;
unsigned int nTransactionsUpdated = 0;


map<uint256, CBlockIndex*> mapBlockIndex;
map<uint256, CBlockIndex*> mapBlockIndex;
set<pair<COutPoint, unsigned int> > setStakeSeen;
set<pair<COutPoint, unsigned int> > setStakeSeen;
uint256 hashGenesisBlock = hashGenesisBlockOfficial;
uint256 hashGenesisBlock = hashGenesisBlockOfficial;
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20);
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20);
static CBigNum bnProofOfStakeLimit(~uint256(0) >> 20);
static CBigNum bnProofOfStakeLimit(~uint256(0) >> 20);


static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 20);
static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 20);
static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 20);
static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 20);


unsigned int nStakeMinAge = 20 * 60; // minimum age for coin age: 30m
unsigned int nStakeMinAge = 20 * 60; // minimum age for coin age: 20m
unsigned int nStakeMaxAge = 60 * 45 ; // stake age of full weight: 1hr
unsigned int nStakeMaxAge = 60 * 45 ; // stake age of full weight: 45m
unsigned int nStakeTargetSpacing = 3*60; // 30 sec block spacing
unsigned int nStakeTargetSpacing = 3*60; // 180 sec block spacing


int64 nChainStartTime = 1503369778;
int64 nChainStartTime = 1503369778;
int nCoinbaseMaturity = 10;
int nCoinbaseMaturity = 10;
CBlockIndex* pindexGenesisBlock = NULL;
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
int nBestHeight = -1;
CBigNum bnBestChainTrust = 0;
uint256 nBestChainTrust = 0;
CBigNum bnBestInvalidTrust = 0;
uint256 nBestInvalidTrust = 0;
uint256 hashBestChain = 0;
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
CBlockIndex* pindexBest = NULL;
int64 nTimeBestReceived = 0;
int64 nTimeBestReceived = 0;


CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have


map<uint256, CBlock*> mapOrphanBlocks;
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
set<pair<COutPoint, unsigned int> > setStakeSeenOrphan;
set<pair<COutPoint, unsigned int> > setStakeSeenOrphan;
map<uint256, uint256> mapProofOfStake;
map<uint256, uint256> mapProofOfStake;


map<uint256, CDataStream*> mapOrphanTransactions;
map<uint256, CDataStream*> mapOrphanTransactions;
map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;


// Constant stuff for coinbase transactions we create:
// Constant stuff for coinbase transactions we create:
CScript COINBASE_FLAGS;
CScript COINBASE_FLAGS;


const string strMessageMagic = "Morningstar Signed Message:\n";
const string strMessageMagic = "Eidas Signed Message:\n";


double dHashesPerSec;
double dHashesPerSec;
int64 nHPSTimerStart;
int64 nHPSTimerStart;


// Settings
// Settings
int64 nTransactionFee = MIN_TX_FEE;
int64 nTransactionFee = MIN_TX_FEE;




// Used during database migration.
bool fDisableSignatureChecking = false;


//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// dispatching functions
// dispatching functions
//
//


// These functions dispatch to one or all registered wallets
// These functions dispatch to one or all registered wallets




void RegisterWallet(CWallet* pwalletIn)
void RegisterWallet(CWallet* pwalletIn)
{
{
{
{
LOCK(cs_setpwalletRegistered);
LOCK(cs_setpwalletRegistered);
setpwalletRegistered.insert(pwalletIn);
setpwalletRegistered.insert(pwalletIn);
}
}
}
}


void UnregisterWallet(CWallet* pwalletIn)
void UnregisterWallet(CWallet* pwalletIn)
{
{
{
{
LOCK(cs_setpwalletRegistered);
LOCK(cs_setpwalletRegistered);
setpwalletRegistered.erase(pwalletIn);
setpwalletRegistered.erase(pwalletIn);
}
}
}
}


// check whether the passed transaction is from us
// check whether the passed transaction is from us
bool static IsFromMe(CTransaction& tx)
bool static IsFromMe(CTransaction& tx)
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
if (pwallet->IsFromMe(tx))
if (pwallet->IsFromMe(tx))
return true;
return true;
return false;
return false;
}
}


// get the wallet transaction with the given hash (if it exists)
// get the wallet transaction with the given hash (if it exists)
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
if (pwallet->GetTransaction(hashTx,wtx))
if (pwallet->GetTransaction(hashTx,wtx))
return true;
return true;
return false;
return false;
}
}


// erases transaction with the given hash from all wallets
// erases transaction with the given hash from all wallets
void static EraseFromWallets(uint256 hash)
void static EraseFromWallets(uint256 hash)
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->EraseFromWallet(hash);
pwallet->EraseFromWallet(hash);
}
}


// make sure all wallets know about the given transaction, in the given block
// make sure all wallets know about the given transaction, in the given block
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fConnect)
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fConnect)
{
{
if (!fConnect)
if (!fConnect)
{
{
// ppcoin: wallets need to refund inputs when disconnecting coinstake
// Eidas: wallets need to refund inputs when disconnecting coinstake
if (tx.IsCoinStake())
if (tx.IsCoinStake())
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
if (pwallet->IsFromMe(tx))
if (pwallet->IsFromMe(tx))
pwallet->DisableTransaction(tx);
pwallet->DisableTransaction(tx);
}
}
return;
return;
}
}


BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
}
}


// notify wallets about a new best chain
// notify wallets about a new best chain
void static SetBestChain(const CBlockLocator& loc)
void static SetBestChain(const CBlockLocator& loc)
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->SetBestChain(loc);
pwallet->SetBestChain(loc);
}
}


// notify wallets about an updated transaction
// notify wallets about an updated transaction
void static UpdatedTransaction(const uint256& hashTx)
void static UpdatedTransaction(const uint256& hashTx)
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->UpdatedTransaction(hashTx);
pwallet->UpdatedTransaction(hashTx);
}
}


// dump all wallets
// dump all wallets
void static PrintWallets(const CBlock& block)
void static PrintWallets(const CBlock& block)
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->PrintWallet(block);
pwallet->PrintWallet(block);
}
}


// notify wallets about an incoming inventory (for request counts)
// notify wallets about an incoming inventory (for request counts)
void static Inventory(const uint256& hash)
void static Inventory(const uint256& hash)
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->Inventory(hash);
pwallet->Inventory(hash);
}
}


// ask wallets to resend their transactions
// ask wallets to resend their transactions
void ResendWalletTransactions()
void ResendWalletTransactions()
{
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->ResendWalletTransactions();
pwallet->ResendWalletTransactions();
}
}






//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// mapOrphanTransactions
// mapOrphanTransactions
//
//


bool AddOrphanTx(const CDataStream& vMsg)
bool AddOrphanTx(const CDataStream& vMsg)
{
{
CTransaction tx;
CTransaction tx;
CDataStream(vMsg) >> tx;
CDataStream(vMsg) >> tx;
uint256 hash = tx.GetHash();
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
if (mapOrphanTransactions.count(hash))
return false;
return false;


CDataStream* pvMsg = new CDataStream(vMsg);
CDataStream* pvMsg = new CDataStream(vMsg);


// Ignore big transactions, to avoid a
// Ignore big transactions, to avoid a
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// large transaction with a missing parent then we assume
// large transaction with a missing parent then we assume
// it will rebroadcast it later, after the parent transaction(s)
// it will rebroadcast it later, after the parent transaction(s)
// have been mined or received.
// have been mined or received.
// 10,000 orphans, each of which is at most 5,000 bytes big is
// 10,000 orphans, each of which is at most 5,000 bytes big is
// at most 500 megabytes of orphans:
// at most 500 megabytes of orphans:
if (pvMsg->size() > 5000)
if (pvMsg->size() > 5000)
{
{
printf("ignoring large orphan tx (size: %"PRIszu", hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
printf("ignoring large orphan tx (size: %" PRIszu ", hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
delete pvMsg;
delete pvMsg;
return false;
return false;
}
}


mapOrphanTransactions[hash] = pvMsg;
mapOrphanTransactions[hash] = pvMsg;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));


printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().substr(0,10).c_str(),
printf("stored orphan tx %s (mapsz %" PRIszu ")\n", hash.ToString().substr(0,10).c_str(),
mapOrphanTransactions.size());
mapOrphanTransactions.size());
return true;
return true;
}
}


void static EraseOrphanTx(uint256 hash)
void static EraseOrphanTx(uint256 hash)
{
{
if (!mapOrphanTransactions.count(hash))
if (!mapOrphanTransactions.count(hash))
return;
return;
const CDataStream* pvMsg = mapOrphanTransactions[hash];
const CDataStream* pvMsg = mapOrphanTransactions[hash];
CTransaction tx;
CTransaction tx;
CDataStream(*pvMsg) >> tx;
CDataStream(*pvMsg) >> tx;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
{
mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
}
}
delete pvMsg;
delete pvMsg;
mapOrphanTransactions.erase(hash);
mapOrphanTransactions.erase(hash);
}
}


unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
{
{
unsigned int nEvicted = 0;
unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans)
while (mapOrphanTransactions.size() > nMaxOrphans)
{
{
// Evict a random orphan:
// Evict a random orphan:
uint256 randomhash = GetRandHash();
uint256 randomhash = GetRandHash();
map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
it = mapOrphanTransactions.begin();
EraseOrphanTx(it->first);
EraseOrphanTx(it->first);
++nEvicted;
++nEvicted;
}
}
return nEvicted;
return nEvicted;
}
}






//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// CTransaction and CTxIndex
// CTransaction and CTxIndex
//
//


bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet)
bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet)
{
{
SetNull();
SetNull();
if (!txdb.ReadTxIndex(prevout.hash, txindexRet))
if (!txdb.ReadTxIndex(prevout.hash, txindexRet))
return false;
return false;
if (!ReadFromDisk(txindexRet.pos))
if (!ReadFromDisk(txindexRet.pos))
return false;
return false;
if (prevout.n >= vout.size())
if (prevout.n >= vout.size())
{
{
SetNull();
SetNull();
return false;
return false;
}
}
return true;
return true;
}
}


bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout)
bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout)
{
{
CTxIndex txindex;
CTxIndex txindex;
return ReadFromDisk(txdb, prevout, txindex);
return ReadFromDisk(txdb, prevout, txindex);
}
}


bool CTransaction::ReadFromDisk(COutPoint prevout)
bool CTransaction::ReadFromDisk(COutPoint prevout)
{
{
CTxDB txdb("r");
CTxDB txdb("r");
CTxIndex txindex;
CTxIndex txindex;
return ReadFromDisk(txdb, prevout, txindex);
return ReadFromDisk(txdb, prevout, txindex);
}
}


bool CTransaction::IsStandard() const
bool CTransaction::IsStandard() const
{
{
if (nVersion > CTransaction::CURRENT_VERSION)
if (nVersion > CTransaction::CURRENT_VERSION)
return false;
return false;


BOOST_FOREACH(const CTxIn& txin, vin)
BOOST_FOREACH(const CTxIn& txin, vin)
{
{
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
// ~65-byte public keys, plus a few script ops.
// ~65-byte public keys, plus a few script ops.
if (txin.scriptSig.size() > 500)
if (txin.scriptSig.size() > 500)
return false;
return false;
if (!txin.scriptSig.IsPushOnly())
if (!txin.scriptSig.IsPushOnly())
return false;
return false;
}
}
BOOST_FOREACH(const CTxOut& txout, vout) {
BOOST_FOREACH(const CTxOut& txout, vout) {
if (!::IsStandard(txout.scriptPubKey))
if (!::IsStandard(txout.scriptPubKey))
return false;
return false;
if (txout.nValue == 0)
if (txout.nValue == 0)
return false;
return false;
}
}
return true;
return true;
}
}


//
//
// Check transaction inputs, and make sure any
// Check transaction inputs, and make sure any
// pay-to-script-hash transactions are evaluating IsStandard scripts
// pay-to-script-hash transactions are evaluating IsStandard scripts
//
//
// Why bother? To avoid denial-of-service attacks; an attacker
// Why bother? To avoid denial-of-service attacks; an attacker
// can submit a standard HASH... OP_EQUAL transaction,
// can submit a standard HASH... OP_EQUAL transaction,
// which will get accepted into blocks. The redemption
// which will get accepted into blocks. The redemption
// script can be anything; an attacker could use a very
// script can be anything; an attacker could use a very
// expensive-to-check-upon-redemption script like:
// expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
//
//
bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
{
{
if (IsCoinBase())
if (IsCoinBase())
return true; // Coinbases don't use vin normally
return true; // Coinbases don't use vin normally


for (unsigned int i = 0; i < vin.size(); i++)
for (unsigned int i = 0; i < vin.size(); i++)
{
{
const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
const CTxOut& prev = GetOutputFor(vin[i], mapInputs);


vector<vector<unsigned char> > vSolutions;
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
// get the scriptPubKey corresponding to this input:
const CScript& prevScript = prev.scriptPubKey;
const CScript& prevScript = prev.scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions))
if (!Solver(prevScript, whichType, vSolutions))
return false;
return false;
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
if (nArgsExpected < 0)
if (nArgsExpected < 0)
return false;
return false;


// Transactions with extra stuff in their scriptSigs are
// Transactions with extra stuff in their scriptSigs are
// non-standard. Note that this EvalScript() call will
// non-standard. Note that this EvalScript() call will
// be quick, because if there are any operations
// be quick, because if there are any operations
// beside "push data" in the scriptSig the
// beside "push data" in the scriptSig the
// IsStandard() call returns false
// IsStandard() call returns false
vector<vector<unsigned char> > stack;
vector<vector<unsigned char> > stack;
if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
if (!EvalScript(stack, vin[i].scriptSig, *this, i, false, 0))
return false;
return false;


if (whichType == TX_SCRIPTHASH)
if (whichType == TX_SCRIPTHASH)
{
{
if (stack.empty())
if (stack.empty())
return false;
return false;
CScript subscript(stack.back().begin(), stack.back().end());
CScript subscript(stack.back().begin(), stack.back().end());
vector<vector<unsigned char> > vSolutions2;
vector<vector<unsigned char> > vSolutions2;
txnouttype whichType2;
txnouttype whichType2;
if (!Solver(subscript, whichType2, vSolutions2))
if (!Solver(subscript, whichType2, vSolutions2))
return false;
return false;
if (whichType2 == TX_SCRIPTHASH)
if (whichType2 == TX_SCRIPTHASH)
return false;
return false;


int tmpExpected;
int tmpExpected;
tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
if (tmpExpected < 0)
if (tmpExpected < 0)
return false;
return false;
nArgsExpected += tmpExpected;
nArgsExpected += tmpExpected;
}
}


if (stack.size() != (unsigned int)nArgsExpected)
if (stack.size() != (unsigned int)nArgsExpected)
return false;
return false;
}
}


return true;
return true;
}
}


unsigned int
unsigned int
CTransaction::GetLegacySigOpCount() const
CTransaction::GetLegacySigOpCount() const
{
{
unsigned int nSigOps = 0;
unsigned int nSigOps = 0;
BOOST_FOREACH(const CTxIn& txin, vin)
BOOST_FOREACH(const CTxIn& txin, vin)
{
{
nSigOps += txin.scriptSig.GetSigOpCount(false);
nSigOps += txin.scriptSig.GetSigOpCount(false);
}
}
BOOST_FOREACH(const CTxOut& txout, vout)
BOOST_FOREACH(const CTxOut& txout, vout)
{
{
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
}
}
return nSigOps;
return nSigOps;
}
}




int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
{
{
if (fClient)
if (fClient)
{
{
if (hashBlock == 0)
if (hashBlock == 0)
return 0;
return 0;
}
}
else
else
{
{
CBlock blockTmp;
CBlock blockTmp;
if (pblock == NULL)
if (pblock == NULL)
{
{
// Load the block this tx is in
// Load the block this tx is in
CTxIndex txindex;
CTxIndex txindex;
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return 0;
return 0;
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return 0;
return 0;
pblock = &blockTmp;
pblock = &blockTmp;
}
}


// Update the tx's hashBlock
// Update the tx's hashBlock
hashBlock = pblock->GetHash();
hashBlock = pblock->GetHash();


// Locate the transaction
// Locate the transaction
for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
if (pblock->vtx[nIndex] == *(CTransaction*)this)
if (pblock->vtx[nIndex] == *(CTransaction*)this)
break;
break;
if (nIndex == (int)pblock->vtx.size())
if (nIndex == (int)pblock->vtx.size())
{
{
vMerkleBranch.clear();
vMerkleBranch.clear();
nIndex = -1;
nIndex = -1;
printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
return 0;
return 0;
}
}


// Fill in merkle branch
// Fill in merkle branch
vMerkleBranch = pblock->GetMerkleBranch(nIndex);
vMerkleBranch = pblock->GetMerkleBranch(nIndex);
}
}


// Is the tx in a block that's in the main chain
// Is the tx in a block that's in the main chain
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
if (mi == mapBlockIndex.end())
return 0;
return 0;
CBlockIndex* pindex = (*mi).second;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
if (!pindex || !pindex->IsInMainChain())
return 0;
return 0;


return pindexBest->nHeight - pindex->nHeight + 1;
return pindexBest->nHeight - pindex->nHeight + 1;
}
}








bool CTransaction::CheckTransaction() const
bool CTransaction::CheckTransaction() const
{
{
// Basic checks that don't depend on any context
// Basic checks that don't depend on any context
if (vin.empty())
if (vin.empty())
return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
if (vout.empty())
if (vout.empty())
return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
// Size limits
// Size limits
if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));


// Check for negative or overflow output values
// Check for negative or overflow output values
int64 nValueOut = 0;
int64 nValueOut = 0;
for (unsigned int i = 0; i < vout.size(); i++)
for (unsigned int i = 0; i < vout.size(); i++)
{
{
const CTxOut& txout = vout[i];
const CTxOut& txout = vout[i];
if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake())
if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake())
return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));
return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));


// ppcoin: enforce minimum output amount
// Eidas: enforce minimum output amount
if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT)
if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum"));
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum"));


if (txout.nValue > MAX_MONEY)
if (txout.nValue > MAX_MONEY)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
nValueOut += txout.nValue;
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
if (!MoneyRange(nValueOut))
return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
}
}


// Check for duplicate inputs
// Check for duplicate inputs
set<COutPoint> vInOutPoints;
set<COutPoint> vInOutPoints;
BOOST_FOREACH(const CTxIn& txin, vin)
BOOST_FOREACH(const CTxIn& txin, vin)
{
{
if (vInOutPoints.count(txin.prevout))
if (vInOutPoints.count(txin.prevout))
return false;
return false;
vInOutPoints.insert(txin.prevout);
vInOutPoints.insert(txin.prevout);
}
}


if (IsCoinBase())
if (IsCoinBase())
{
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
}
}
else
else
{
{
BOOST_FOREACH(const CTxIn& txin, vin)
BOOST_FOREACH(const CTxIn& txin, vin)
if (txin.prevout.IsNull())
if (txin.prevout.IsNull())
return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
}
}


return true;
return true;
}
}




int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree,
int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree,
enum GetMinFee_mode mode, unsigned int nBytes) const
enum GetMinFee_mode mode, unsigned int nBytes) const
{
{
// Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
// Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;


unsigned int nNewBlockSize = nBlockSize + nBytes;
unsigned int nNewBlockSize = nBlockSize + nBytes;
int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;


// To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
// To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
if (nMinFee < nBaseFee)
if (nMinFee < nBaseFee)
{
{
BOOST_FOREACH(const CTxOut& txout, vout)
BOOST_FOREACH(const CTxOut& txout, vout)
if (txout.nValue < CENT)
if (txout.nValue < CENT)
nMinFee = nBaseFee;
nMinFee = nBaseFee;
}
}


// Raise the price as the block approaches full
// Raise the price as the block approaches full
if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
{
{
if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN)
if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN)
return MAX_MONEY;
return MAX_MONEY;
nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize);
nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize);
}
}


if (!MoneyRange(nMinFee))
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
nMinFee = MAX_MONEY;
return nMinFee;
return nMinFee;
}
}




bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
bool* pfMissingInputs)
bool* pfMissingInputs)
{
{
if (pfMissingInputs)
if (pfMissingInputs)
*pfMissingInputs = false;
*pfMissingInputs = false;


if (!tx.CheckTransaction())
if (!tx.CheckTransaction())
return error("CTxMemPool::accept() : CheckTransaction failed");
return error("CTxMemPool::accept() : CheckTransaction failed");


// Coinbase is only valid in a block, not as a loose transaction
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
if (tx.IsCoinBase())
return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));
return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));


// ppcoin: coinstake is also only valid in a block, not as a loose transaction
// Eidas: coinstake is also only valid in a block, not as a loose transaction
if (tx.IsCoinStake())
if (tx.IsCoinStake())
return tx.DoS(100, error("CTxMemPool::accept() : coinstake as individual tx"));
return tx.DoS(100, error("CTxMemPool::accept() : coinstake as individual tx"));


// To help v0.1.5 clients who would see it as a negative number
// To help v0.1.5 clients who would see it as a negative number
if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");


// Rather not work on nonstandard transactions (unless -testnet)
// Rather not work on nonstandard transactions (unless -testnet)
if (!fTestNet && !tx.IsStandard())
if (!fTestNet && !tx.IsStandard())
return error("CTxMemPool::accept() : nonstandard transaction type");
return error("CTxMemPool::accept() : nonstandard transaction type");


// Do we already have it?
// Do we already have it?
uint256 hash = tx.GetHash();
uint256 hash = tx.GetHash();
{
{
LOCK(cs);
LOCK(cs);
if (mapTx.count(hash))
if (mapTx.count(hash))
return false;
return false;
}
}
if (fCheckInputs)
if (fCheckInputs)
if (txdb.ContainsTx(hash))
if (txdb.ContainsTx(hash))
return false;
return false;


// Check for conflicts with in-memory transactions
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
CTransaction* ptxOld = NULL;
for (unsigned int i = 0; i < tx.vin.size(); i++)
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
{
COutPoint outpoint = tx.vin[i].prevout;
COutPoint outpoint = tx.vin[i].prevout;
if (mapNextTx.count(outpoint))
if (mapNextTx.count(outpoint))
{
{
// Disable replacement feature for now
// Disable replacement feature for now
return false;
return false;


// Allow replacing with a newer version of the same transaction
// Allow replacing with a newer version of the same transaction
if (i != 0)
if (i != 0)
return false;
return false;
ptxOld = mapNextTx[outpoint].ptx;
ptxOld = mapNextTx[outpoint].ptx;
if (ptxOld->IsFinal())
if (ptxOld->IsFinal())
return false;
return false;
if (!tx.IsNewerThan(*ptxOld))
if (!tx.IsNewerThan(*ptxOld))
return false;
return false;
for (unsigned int i = 0; i < tx.vin.size(); i++)
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
{
COutPoint outpoint = tx.vin[i].prevout;
COutPoint outpoint = tx.vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
return false;
return false;
}
}
break;
break;
}
}
}
}


if (fCheckInputs)
if (fCheckInputs)
{
{
MapPrevTx mapInputs;
MapPrevTx mapInputs;
map<uint256, CTxIndex> mapUnused;
map<uint256, CTxIndex> mapUnused;
bool fInvalid = false;
bool fInvalid = false;
if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
{
{
if (fInvalid)
if (fInvalid)
return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
if (pfMissingInputs)
if (pfMissingInputs)
*pfMissingInputs = true;
*pfMissingInputs = true;
return false;
return false;
}
}


// Check for non-standard pay-to-script-hash in inputs
// Check for non-standard pay-to-script-hash in inputs
if (!tx.AreInputsStandard(mapInputs) && !fTestNet)
if (!tx.AreInputsStandard(mapInputs) && !fTestNet)
return error("CTxMemPool::accept() : nonstandard transaction input");
return error("CTxMemPool::accept() : nonstandard transaction input");


// Note: if you modify this code to accept non-standard transactions, then
// Note: if you modify this code to accept non-standard transactions, then
// you should add code here to check that the transaction does a
// you should add code here to check that the transaction does a
// reasonable number of ECDSA signature verifications.
// reasonable number of ECDSA signature verifications.


int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);


// Don't accept it if it can't get into a block
// Don't accept it if it can't get into a block
int64 txMinFee = tx.GetMinFee(1000, false, GMF_RELAY, nSize);
int64 txMinFee = tx.GetMinFee(1000, false, GMF_RELAY, nSize);
if (nFees < txMinFee)
if (nFees < txMinFee)
return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
return error("CTxMemPool::accept() : not enough fees %s, %" PRI64d " < %" PRI64d,
hash.ToString().c_str(),
hash.ToString().c_str(),
nFees, txMinFee);
nFees, txMinFee);


// Continuously rate-limit free transactions
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
// be annoying or make others' transactions take longer to confirm.
if (nFees < MIN_RELAY_TX_FEE)
if (nFees < MIN_RELAY_TX_FEE)
{
{
static CCriticalSection cs;
static CCriticalSection cs;
static double dFreeCount;
static double dFreeCount;
static int64 nLastTime;
static int64 nLastTime;
int64 nNow = GetTime();
int64 nNow = GetTime();


{
{
LOCK(cs);
LOCK(cs);
// Use an exponentially decaying ~10-minute window:
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
// At default rate it would take over a month to fill 1GB
if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
if (fDebug)
if (fDebug)
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
dFreeCount += nSize;
}
}
}
}


// Check against previous transactions
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
{
{
return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
}
}
}


// Store transaction in memory
// Store transaction in memory
{
{
LOCK(cs);
LOCK(cs);
if (ptxOld)
if (ptxOld)
{
{
printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
remove(*ptxOld);
remove(*ptxOld);
}
}
addUnchecked(hash, tx);
addUnchecked(hash, tx);
}
}


///// are we sure this is ok when loading transactions or restoring block txes
///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet
// If updated, erase old tx from wallet
if (ptxOld)
if (ptxOld)
EraseFromWallets(ptxOld->GetHash());
EraseFromWallets(ptxOld->GetHash());


printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n",
printf("CTxMemPool::accept() : accepted %s (poolsz %" PRIszu ")\n",
hash.ToString().substr(0,10).c_str(),
hash.ToString().substr(0,10).c_str(),
mapTx.size());
mapTx.size());
return true;
return true;
}
}


bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
{
{
return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs);
return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs);
}
}


bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
{
{
// Add to memory pool without checking anything. Don't call this directly,
// Add to memory pool without checking anything. Don't call this directly,
// call CTxMemPool::accept to properly check the transaction first.
// call CTxMemPool::accept to properly check the transaction first.
{
{
mapTx[hash] = tx;
mapTx[hash] = tx;
for (unsigned int i = 0; i < tx.vin.size(); i++)
for (unsigned int i = 0; i < tx.vin.size(); i++)
mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
nTransactionsUpdated++;
nTransactionsUpdated++;
}
}
return true;
return true;
}
}




bool CTxMemPool::remove(CTransaction &tx)
bool CTxMemPool::remove(CTransaction &tx)
{
{
// Remove transaction from memory pool
// Remove transaction from memory pool
{
{
LOCK(cs);
LOCK(cs);
uint256 hash = tx.GetHash();
uint256 hash = tx.GetHash();
if (mapTx.count(hash))
if (mapTx.count(hash))
{
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
mapNextTx.erase(txin.prevout);
mapTx.erase(hash);
mapTx.erase(hash);
nTransactionsUpdated++;
nTransactionsUpdated++;
}
}
}
}
return true;
return true;
}
}


void CTxMemPool::clear()
void CTxMemPool::clear()
{
{
LOCK(cs);
LOCK(cs);
mapTx.clear();
mapTx.clear();
mapNextTx.clear();
mapNextTx.clear();
++nTransactionsUpdated;
++nTransactionsUpdated;
}
}


void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
{
{
vtxid.clear();
vtxid.clear();


LOCK(cs);
LOCK(cs);
vtxid.reserve(mapTx.size());
vtxid.reserve(mapTx.size());
for (map<uint256, CTransaction>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
for (map<uint256, CTransaction>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
vtxid.push_back((*mi).first);
vtxid.push_back((*mi).first);
}
}








int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
{
{
if (hashBlock == 0 || nIndex == -1)
if (hashBlock == 0 || nIndex == -1)
return 0;
return 0;


// Find the block it claims to be in
// Find the block it claims to be in
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
if (mi == mapBlockIndex.end())
return 0;
return 0;
CBlockIndex* pindex = (*mi).second;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
if (!pindex || !pindex->IsInMainChain())
return 0;
return 0;


// Make sure the merkle branch connects to this block
// Make sure the merkle branch connects to this block
if (!fMerkleVerified)
if (!fMerkleVerified)
{
{
if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
return 0;
return 0;
fMerkleVerified = true;
fMerkleVerified = true;
}
}


pindexRet = pindex;
pindexRet = pindex;
return pindexBest->nHeight - pindex->nHeight + 1;
return pindexBest->nHeight - pindex->nHeight + 1;
}
}




int CMerkleTx::GetBlocksToMaturity() const
int CMerkleTx::GetBlocksToMaturity() const
{
{
if (!(IsCoinBase() || IsCoinStake()))
if (!(IsCoinBase() || IsCoinStake()))
return 0;
return 0;
return max(0, (nCoinbaseMaturity+20) - GetDepthInMainChain());
return max(0, (nCoinbaseMaturity+(GetAdjustedTime() > FORK_TIME ? 30 : 20)) - GetDepthInMainChain());
}
}




bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
{
{
if (fClient)
if (fClient)
{
{
if (!IsInMainChain() && !ClientConnectInputs())
if (!IsInMainChain() && !ClientConnectInputs())
return false;
return false;
return CTransaction::AcceptToMemoryPool(txdb, false);
return CTransaction::AcceptToMemoryPool(txdb, false);
}
}
else
else
{
{
return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs);
return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs);
}
}
}
}


bool CMerkleTx::AcceptToMemoryPool()
bool CMerkleTx::AcceptToMemoryPool()
{
{
CTxDB txdb("r");
CTxDB txdb("r");
return AcceptToMemoryPool(txdb);
return AcceptToMemoryPool(txdb);
}
}






bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
{
{


{
{
LOCK(mempool.cs);
LOCK(mempool.cs);
// Add previous supporting transactions first
// Add previous supporting transactions first
BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
BOOST_
{
if (!(tx.IsCoinBase() || tx.IsCoinStake()))
{
uint256 hash = tx.GetHash();