Untitled diff
337 removals
807 lines
330 additions
804 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/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/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) >> 24);
static CBigNum bnProofOfStakeLimit(~uint256(0) >> 20);
static CBigNum bnProofOfStakeHardLimit(~uint256(0) >> 30);
static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 16);
static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 20);
static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 20);
static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 20);
unsigned int nStakeMinAge = 60 * 60 * 24 * 10; // minimum age for coin age - 10 days
unsigned int nStakeMinAge = 60 * 60 * 8; // time at which weight begins to build
unsigned int nStakeMaxAge = 60 * 60 * 24 * 30; // stake age of full weight - 30 days
unsigned int nStakeMinAgeV2 = 60 * 60 * 24 * 88 / 10; // functionally the minimum age is 8.8 days
unsigned int nStakeTargetSpacing = 1 * 30; // 1-minute block spacing
unsigned int nStakeMaxAge = 60 * 60 * 24 * 30; // stake age of full weight: -1
int64_t nChainStartTime = 1371910049;
unsigned int nStakeTargetSpacing = 90; // 90 sec block spacing
int nCoinbaseMaturity = 5;
int64 nChainStartTime = 1399495660;
int nCoinbaseMaturity = 10;
CBlockIndex* pindexGenesisBlock = NULL;
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
int nBestHeight = -1;
uint256 nBestChainTrust = 0;
CBigNum bnBestChainTrust = 0;
uint256 nBestInvalidTrust = 0;
CBigNum bnBestInvalidTrust = 0;
uint256 hashBestChain = 0;
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
CBlockIndex* pindexBest = NULL;
int64_t nTimeBestReceived = 0;
int64 nTimeBestReceived = 0;
bool fHaveGUI = false;
bool fHaveGUI = false;
bool fImporting = false; //Tranz need to fix this 66b02c93
bool fReindex = false; // Tranz need to fix this 7fea4846
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, CTransaction> mapOrphanTransactions;
map<uint256, CDataStream*> mapOrphanTransactions;
map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
map<unsigned int, unsigned int> mapHashedBlocks;
map<std::string, std::pair<int, int> > mapGetBlocksRequests;
std::map <std::string, int> mapPeerRejectedBlocks;
bool fStrictProtocol = false;
bool fStrictIncoming = false;
// Constant stuff for coinbase transactions we create:
// Constant stuff for coinbase transactions we create:
CScript COINBASE_FLAGS;
CScript COINBASE_FLAGS;
const string strMessageMagic = "HoboNickels Signed Message:\n";
const string strMessageMagic = "HyperStake Signed Message:\n";
double dHashesPerSec;
double dHashesPerSec;
int64_t nHPSTimerStart;
int64 nHPSTimerStart;
// Settings
// Settings
int64_t nTransactionFee = MIN_TX_FEE;
int64 nTransactionFee = MIN_TX_FEE;
int64_t nMinimumInputValue = MIN_TX_FEE;
int64_t nSplitThreshold = GetProofOfWorkReward();
int64_t nCombineThreshold = GetProofOfWorkReward() * 2;
extern enum Checkpoints::CPMode CheckpointsMode;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// 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);
}
}
}
}
void UnregisterAllWallets()
{
{
LOCK(cs_setpwalletRegistered);
setpwalletRegistered.clear();
Text moved to lines 798-800
}
}
// 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)
LOCK(cs_setpwalletRegistered);
if (pwallet->IsFromMe(tx))
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
return true;
if (pwallet->IsFromMe(tx))
return false;
return true;
}
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)
LOCK(cs_setpwalletRegistered);
if (pwallet->GetTransaction(hashTx,wtx))
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
return true;
if (pwallet->GetTransaction(hashTx,wtx))
return false;
return true;
}
return false;
}
// erases transaction with the given hash from all wallets
void static EraseFromWallets(uint256 hash)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
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
// ppcoin: wallets need to refund inputs when disconnecting coinstake
if (tx.IsCoinStake())
if (tx.IsCoinStake())
{
{
LOCK(cs_setpwalletRegistered);
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)
LOCK(cs_setpwalletRegistered);
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
}
}
// Add wallet transactions that aren't already in a block to mapTransactions
void ReacceptWalletTransactions()
{
{
LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->ReacceptWalletTransactions();
}
}
}
// 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)
LOCK(cs_setpwalletRegistered);
pwallet->SetBestChain(loc);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
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)
LOCK(cs_setpwalletRegistered);
pwallet->UpdatedTransaction(hashTx);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
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)
LOCK(cs_setpwalletRegistered);
pwallet->PrintWallet(block);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
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)
LOCK(cs_setpwalletRegistered);
pwallet->Inventory(hash);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->Inventory(hash);
}
}
}
// ask wallets to resend their transactions
// ask wallets to resend their transactions
void ResendWalletTransactions(bool fForce)
void ResendWalletTransactions()
{
{
LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->ResendWalletTransactions(fForce);
}
Text moved with changes to lines 712-717 (84.2% similarity)
}
//////////////////////////////////////////////////////////////////////////////
//
// Registration of network node signals.
//
namespace {
// Maintain validation-specific state about nodes, protected by cs_main, instead
// by CNode's own locks. This simplifies asynchronous operation, where
// processing of incoming data is done after the ProcessMessage call returns,
// and we're no longer holding the node's locks.
struct CNodeState {
// Accumulated misbehaviour score for this peer.
int nMisbehavior;
// Whether this peer should be disconnected and banned.
bool fShouldBan;
// String name of this peer (debugging/logging purposes).
std::string name;
CNodeState() {
nMisbehavior = 0;
fShouldBan = false;
}
};
map<NodeId, CNodeState> mapNodeState;
// Requires cs_main. (Tranz Locks removed for now due to deadlock)
CNodeState *State(NodeId pnode) {
map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
if (it == mapNodeState.end())
return NULL;
return &it->second;
}
int GetHeight()
{
return nBestHeight;
}
void InitializeNode(NodeId nodeid, const CNode *pnode) {
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
state.name = pnode->addrName;
}
void FinalizeNode(NodeId nodeid) {
mapNodeState.erase(nodeid);
}
}
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
CNodeState *state = State(nodeid);
if (state == NULL)
return false;
stats.nMisbehavior = state->nMisbehavior;
Text moved to lines 693-695
return true;
}
void RegisterNodeSignals(CNodeSignals& nodeSignals)
{
nodeSignals.GetHeight.connect(&GetHeight);
nodeSignals.ProcessMessages.connect(&ProcessMessages);
nodeSignals.SendMessages.connect(&SendMessages);
nodeSignals.InitializeNode.connect(&InitializeNode);
nodeSignals.FinalizeNode.connect(&FinalizeNode);
}
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
{
{
nodeSignals.GetHeight.disconnect(&GetHeight);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
pwallet->ResendWalletTransactions();
nodeSignals.SendMessages.disconnect(&SendMessages);
nodeSignals.InitializeNode.disconnect(&InitializeNode);
nodeSignals.FinalizeNode.disconnect(&FinalizeNode);
}
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// mapOrphanTransactions
// mapOrphanTransactions
//
//
bool AddOrphanTx(const CTransaction& tx)
bool AddOrphanTx(const CDataStream& vMsg)
{
{
CTransaction 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);
// 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)
size_t nSize = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
if (nSize > 5000)
{
{
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", nSize, hash.ToString().substr(0,10));
printf("ignoring large orphan tx (size: %"PRIszu", hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
delete pvMsg;
return false;
return false;
}
}
mapOrphanTransactions[hash] = tx;
mapOrphanTransactions[hash] = pvMsg;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));
LogPrint("mempool", "stored orphan tx %s (mapsz %u)\n", hash.ToString().substr(0,10),
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 CTransaction& tx = mapOrphanTransactions[hash];
const CDataStream* pvMsg = mapOrphanTransactions[hash];
CTransaction 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;
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, CTransaction>::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;
}
}
Text moved to lines 749-752
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// 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 IsStandardTx(const CTransaction& tx)
bool CTransaction::IsStandard() const
{
{
if (tx.nVersion > CTransaction::CURRENT_VERSION)
if (nVersion > CTransaction::CURRENT_VERSION)
return false;
// Treat non-final transactions as non-standard to prevent a specific type
// of double-spend attack, as well as DoS attacks. (if the transaction
// can't be mined, the attacker isn't expending resources broadcasting it)
// Basically we don't want to propagate transactions that can't included in
// the next block.
//
// However, IsFinalTx() is confusing... Without arguments, it uses
// chainActive.Height() to evaluate nLockTime; when a block is accepted, chainActive.Height()
// is set to the value of nHeight in the block. However, when IsFinalTx()
// is called within CBlock::AcceptBlock(), the height of the block *being*
// evaluated is what is used. Thus if we want to know if a transaction can
// be part of the *next* block, we need to call IsFinalTx() with one more
// than chainActive.Height().
//
// Timestamps on the other hand don't get any special treatment, because we
// can't know what timestamp the next block will have, and there aren't
// timestamp applications where it matters.
if (!IsFinalTx(tx, nBestHeight + 1)) {
return false;
}
// nTime has different purpose from nLockTime but can be used in similar attacks
if (tx.nTime > FutureDrift(GetAdjustedTime())) {
return false;
}
// Extremely large transactions with lots of inputs can cost the network
// almost as much to process as they cost the sender in fees, because
// computing signature hashes is O(ninputs*txsize). Limiting transactions
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
if (sz >= MAX_STANDARD_TX_SIZE)
return false;
return false;
BOOST_FOREACH(const CTxIn& txin, vin)
BOOST_FOREACH(const CTxIn& txin, tx.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;
if (!txin.scriptSig.HasCanonicalPushes())
return false;
}
}
BOOST_FOREACH(const CTxOut& txout, vout) {
unsigned int nDataOut = 0;
if (!::IsStandard(txout.scriptPubKey))
txnouttype whichType;
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
if (!::IsStandard(txout.scriptPubKey, whichType))
return false;
return false;
if (whichType == TX_NULL_DATA)
nDataOut++;
if (txout.nValue == 0)
if (txout.nValue == 0)
return false;
return false;
if (!txout.scriptPubKey.HasCanonicalPushes())
return false;
}
// only one OP_RETURN txout is permitted
if (nDataOut > 1) {
return false;
}
}
return true;
return true;
}
}
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
AssertLockHeld(cs_main);
// Time based nLockTime implemented in 0.1.6
if (tx.nLockTime == 0)
return true;
if (nBlockHeight == 0)
nBlockHeight = nBestHeight;
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (!txin.IsFinal())
return false;
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, 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)
{
{
AssertLockHeld(cs_main);
if (fClient)
CBlock blockTmp;
if (pblock == NULL)
{
{
// Load the block this tx is in
if (hashBlock == 0)
CTxIndex txindex;
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return 0;
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return 0;
return 0;
pblock = &blockTmp;
}
}
else
{
CBlock blockTmp;
if (pblock == NULL)
{
// Load the block this tx is in
CTxIndex txindex;
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return 0;
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return 0;
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;
LogPrintf("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
vMerkleBranch = pblock->GetMerkleBranch(nIndex);
}
}
// Fill in merkle branch
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"));
// Time (prevent mempool memory exhaustion attack)
if (nTime > GetAdjustedTime() + nMaxClockDrift)
return DoS(10, error("CTransaction::CheckTransaction() : timestamp is too far into the future"));
// 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_t 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
// ppcoin: 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 < 0)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue is negative"));
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_t 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_t 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_t nMinFee = (1 + (int64_t)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 max(nMinFee, MIN_TX_FEE);
}
}
bool AcceptToMemoryPool(CTxMemPool& pool, CTransaction &tx,
bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
bool* pfMissingInputs)
bool* pfMissingInputs)
{
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
if (pfMissingInputs)
*pfMissingInputs = false;
*pfMissingInputs = false;
if (!tx.CheckTransaction())
if (!tx.CheckTransaction())
return error("AcceptToMemoryPool : 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("AcceptToMemoryPool : 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
// ppcoin: coinstake is also only valid in a block, not as a loose transaction
if (tx.IsCoinStake())
if (tx.IsCoinStake())
return tx.DoS(100, error("AcceptToMemoryPool : 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
if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
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 && !IsStandardTx(tx))
if (!fTestNet && !tx.IsStandard())
return error("AcceptToMemoryPool : nonstandard transaction type");
return error("CTxMemPool::accept() : nonstandard transaction type");
// is it already in the memory pool?
// Do we already have it?
uint256 hash = tx.GetHash();
uint256 hash = tx.GetHash();
{
if (pool.exists(hash))
LOCK(cs);
return false;
if (mapTx.count(hash))
return false;
}
if (fCheckInputs)
if (txdb.ContainsTx(hash))
return false;
// Check for conflicts with in-memory transactions
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
{
LOCK(pool.cs); // protect pool.mapNextTx
COutPoint outpoint = tx.vin[i].prevout;
for (unsigned int i = 0; i < tx.vin.size(); i++)
if (mapNextTx.count(outpoint))
{
{
COutPoint outpoint = tx.vin[i].prevout;
// Disable replacement feature for now
if (pool.mapNextTx.count(outpoint))
return false;
{
// Disable replacement feature for now
// Allow replacing with a newer version of the same transaction
if (i != 0)
return false;
ptxOld = mapNextTx[outpoint].ptx;
if (ptxOld->IsFinal())
return false;
if (!tx.IsNewerThan(*ptxOld))
return false;
return false;
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
COutPoint outpoint = tx.vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
return false;
}
}
break;
}
}
}
}
if (fCheckInputs)
{
{
CTxDB txdb("r");
// do we already have it?
if (txdb.ContainsTx(hash))
return false;
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("AcceptToMemoryPool : FetchInputs found invalid tx %s", hash.ToString().substr(0,10));
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("AcceptToMemoryPool : 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_t 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_t 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("AcceptToMemoryPool : not enough fees %s, %d < %d",
return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
has
hash.ToString().c_str(),
nFees, txMinFee);
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
if (nFees < MIN_RELAY_TX_FEE)
{
static CCriticalSection cs;
static double dFreeCount;
static int64 nLastTime;
int64 nNow = GetTime();
{
LOCK(cs);
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
if (fDebug)
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
}
// Check against previous transactions
// 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))
{
return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
}
// Store transaction in memory
{
LOCK(cs);
if (ptxOld)
{
printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
remove(*ptxOld);
}
addUnchecked(hash, tx);
}
///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet
if (ptxOld)
EraseFromWallets(ptxOld->GetHash());
printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n",
hash.ToString().substr(0,10).c_str(),
mapTx.size());
Text moved from lines 284-286
return true;
}
bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
{
return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs);
}
bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
{
// Add to memory pool without checking anything. Don't call this directly,
// call CTxMemPool::accept to properly check the transaction first.
{
mapTx[hash] = tx;
for (unsigned int i = 0; i < tx.vin.size(); i++)
mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
nTransactionsUpdated++;
}
return true;
Text moved with changes from lines 227-232 (84.2% similarity)
}
bool CTxMemPool::remove(CTransaction &tx)
{
// Remove transaction from memory pool
{
LOCK(cs);
uint256 hash = tx.GetHash();
if (mapTx.count(hash))
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
mapTx.erase(hash);
nTransactionsUpdated++;
}
}
return true;
}
void CTxMemPool::clear()
{
LOCK(cs);
mapTx.clear();
mapNextTx.clear();
++nTransactionsUpdated;
}
void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
{
vtxid.clear();
LOCK(cs);
vtxid.reserve(mapTx.size());
for (map<uint256, CTransaction>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
vtxid.push_back((*mi).first);
}
Text moved from lines 376-379
int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
{
if (hashBlock == 0 || nIndex == -1)
return 0;
// Find the block it claims to be in
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
return 0;
// Make sure the merkle branch connects to this block
if (!fMerkleVerified)
{
if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
return 0;
fMerkleVerified = true;
}
pindexRet = pindex;
return pindexBest->nHeight - pindex->nHeight + 1;
}
int CMerkleTx::GetBlocksToMaturity() const
{
if (!(IsCoinBase() || IsCoinStake()))
return 0;
return max(0, (nCoinbaseMaturity+20) - GetDepthInMainChain());
}
bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
{
if (fClient)
{
if (!IsInMainChain() && !ClientConnectInputs())
return false;
return CTransaction::AcceptToMemoryPool(txdb, false);
}
else
{
return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs);
Text moved from lines 116-118
}
}
bool CMerkleTx::AcceptToMemoryPool()
{
CTxDB txdb("r");
retu