Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
7723 lines (6661 sloc) 318 KB
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2018 The KORE developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
#include "addrman.h"
#include "alert.h"
#include "arith_uint256.h" // Legacy
#include "base58.h"
#include "blocksignature.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
#include "init.h"
#include "invalid.h"
#include "kernel.h"
#include "legacy/consensus/merkle.h"
#include "merkleblock.h"
#include "miner.h"
#include "net.h"
#include "pos.h" // Old from Kore, will be deprecated
#include "pow.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
#include "utilmoneystr.h"
#include "validationinterface.h"
#include "wallet.h"
#include <condition_variable>
#include <mutex>
#include <sstream>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
using namespace boost;
using namespace std;
#if defined(NDEBUG)
#error "KORE cannot be compiled without assertions."
#endif
// 6 comes from OPCODE (1) + vch.size() (1) + BIGNUM size (4)
#define SCRIPT_OFFSET 6
// For Script size (BIGNUM/Uint256 size)
#define BIGNUM_SIZE 4
/**
* Global state
*/
CCriticalSection cs_main;
BlockMap mapBlockIndex;
map<uint256, uint256> mapProofOfStake;
set<pair<COutPoint, unsigned int> > setStakeSeen;
map<unsigned int, unsigned int> mapHashedBlocks;
CChain chainActive;
CBlockIndex* pindexBestHeader = NULL;
int64_t nTimeBestReceived = 0;
std::mutex csBestBlock;
std::condition_variable cvBlockChange;
int nScriptCheckThreads = 0;
bool fImporting = false;
bool fReindex = false;
bool fTxIndex = true;
bool fHavePruned = false; // Legacy
bool fPruneMode = false; // Legacy
uint64_t nPruneTarget = 0; // Legacy
bool fAddrIndex = false; // Legacy
size_t nCoinCacheUsage = 5000 * 300; // Legacy
// TODO: Remove?
//bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; // Legacy
bool fRequireStandard = true; // Legacy
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP_LEGACY; // Legacy
bool fIsBareMultisigStd = true;
bool fCheckBlockIndex = false;
bool fVerifyingBlocks = false;
unsigned int nCoinCacheSize = 5000;
bool fAlerts = DEFAULT_ALERTS;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; // Legacy
int nChainHeight = -1;
CMedianFilter<int> cPeerBlockCounts(5, 0);
int64_t nReserveBalance = 0;
/** Fees smaller than this (in uKORE) are considered zero fee (for relaying and mining)
* We are ~100 times smaller then bitcoin now (2015-06-23), set minRelayTxFee only 10 times higher
* so it's still 10 times lower comparing to bitcoin.
*/
CFeeRate minRelayTxFee = CFeeRate(10000);
CTxMemPool mempool(::minRelayTxFee);
struct COrphanTx {
CTransaction tx;
NodeId fromPeer;
};
map<uint256, COrphanTx> mapOrphanTransactions;
map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
map<uint256, int64_t> mapRejectedBlocks;
void EraseOrphansFor(NodeId peer);
static void CheckBlockIndex();
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
const string strMessageMagic = "Kore Signed Message:\n";
// Internal stuff
namespace
{
struct CBlockIndexWorkComparator {
bool operator()(CBlockIndex* pa, CBlockIndex* pb) const
{
// First sort by most total work, ...
if (pa->nChainWork > pb->nChainWork) return false;
if (pa->nChainWork < pb->nChainWork) return true;
// ... then by earliest time received, ...
if (pa->nSequenceId < pb->nSequenceId) return false;
if (pa->nSequenceId > pb->nSequenceId) return true;
// Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if (pa < pb) return false;
if (pa > pb) return true;
// Identical blocks.
return false;
}
};
CBlockIndex* pindexBestInvalid;
/**
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
* as good as our current tip or better. Entries may be failed, though.
*/
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
/** Number of nodes with fSyncStarted. */
int nSyncStarted = 0;
/** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. */
multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
int nLastBlockFile = 0;
/** Global flag to indicate we should check to see if there are
* block/undo files that should be deleted. Set on startup
* or if we allocate more file space when we're in prune mode
*/
bool fCheckForPruning = false; // Legacy
/**
* Every received block is assigned a unique and increasing identifier, so we
* know which one to give priority in case of a fork.
*/
CCriticalSection cs_nBlockSequenceId;
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
uint32_t nBlockSequenceId = 1;
/**
* Sources of received blocks, to be able to send them reject messages or ban
* them, if processing happens afterwards. Protected by cs_main.
*/
map<uint256, NodeId> mapBlockSource;
/**
* Filter for transactions that were recently rejected by
* AcceptToMemoryPool. These are not rerequested until the chain tip
* changes, at which point the entire filter is reset. Protected by
* cs_main.
*
* Without this filter we'd be re-requesting txs from each of our peers,
* increasing bandwidth consumption considerably. For instance, with 100
* peers, half of which relay a tx we don't accept, that might be a 50x
* bandwidth increase. A flooding attacker attempting to roll-over the
* filter using minimum-sized, 60byte, transactions might manage to send
* 1000/sec if we have fast peers, so we pick 120,000 to give our peers a
* two minute window to send invs to us.
*
* Decreasing the false positive rate is fairly cheap, so we pick one in a
* million to make it highly unlikely for users to have issues with this
* filter.
*
* Memory used: 1.7MB
*/
boost::scoped_ptr<CRollingBloomFilter> recentRejects;
uint256 hashRecentRejectsChainTip;
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
CBlockIndex* pindex; //! Optional.
int64_t nTime; //! Time of "getdata" request in microseconds.
int nValidatedQueuedBefore; //! Number of blocks queued with validated headers (globally) at the time this one is requested.
bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
/** Number of blocks in flight with validated headers. */
int nQueuedValidatedHeaders = 0;
/** Number of preferable block download peers. */
int nPreferredDownload = 0;
/** Dirty block index entries. */
set<CBlockIndex*> setDirtyBlockIndex;
/** Dirty block file entries. */
set<int> setDirtyFileInfo;
/** Number of peers from which we're downloading blocks. */
int nPeersWithValidatedDownloads = 0;
} // namespace
//////////////////////////////////////////////////////////////////////////////
//
// Registration of network node signals.
//
namespace
{
struct CBlockReject {
unsigned char chRejectCode;
string strRejectReason;
uint256 hashBlock;
};
/**
* 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 {
//! The peer's address
CService address;
//! Whether we have a fully established connection.
bool fCurrentlyConnected;
//! Accumulated misbehaviour score for this peer.
int nMisbehavior;
//! Whether this peer should be disconnected and banned (unless whitelisted).
bool fShouldBan;
//! String name of this peer (debugging/logging purposes).
std::string name;
//! List of asynchronously-determined block rejections to notify this peer about.
std::vector<CBlockReject> rejects;
//! The best known block we know this peer has announced.
CBlockIndex* pindexBestKnownBlock;
//! The hash of the last unknown block this peer has announced.
uint256 hashLastUnknownBlock;
//! The last full block we both have.
CBlockIndex* pindexLastCommonBlock;
//! The best header we have sent our peer.
CBlockIndex* pindexBestHeaderSent_Legacy;
//! Whether we've started headers synchronization with this peer.
bool fSyncStarted;
//! Since when we're stalling block download progress (in microseconds), or 0.
int64_t nStallingSince;
list<QueuedBlock> vBlocksInFlight;
int nBlocksInFlight;
int nBlocksInFlightValidHeaders; // Legacy
int64_t nDownloadingSince; // Legacy
//! Whether we consider this a preferred download peer.
bool fPreferredDownload;
bool fPreferHeaders; // Legacy
CNodeState()
{
fCurrentlyConnected = false;
nMisbehavior = 0;
fShouldBan = false;
pindexBestKnownBlock = NULL;
hashLastUnknownBlock = uint256(0);
pindexLastCommonBlock = NULL;
pindexBestHeaderSent_Legacy = NULL;
fSyncStarted = false;
nStallingSince = 0;
nBlocksInFlight = 0;
fPreferredDownload = false;
//Legacy
nDownloadingSince = 0;
nBlocksInFlightValidHeaders = 0;
fPreferHeaders = false;
}
};
/** Map maintaining per-node state. Requires cs_main. */
map<NodeId, CNodeState> mapNodeState;
// Requires cs_main.
CNodeState* State(NodeId pnode)
{
map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
if (it == mapNodeState.end())
return NULL;
return &it->second;
}
int GetHeight()
{
while (!ShutdownRequested()) {
TRY_LOCK(cs_main, lockMain);
if (!lockMain) {
MilliSleep(50);
continue;
}
return chainActive.Height();
}
}
void UpdatePreferredDownload(CNode* node, CNodeState* state)
{
nPreferredDownload -= state->fPreferredDownload;
// Whether this node should be marked as a preferred download node.
state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;
nPreferredDownload += state->fPreferredDownload;
}
void InitializeNode(NodeId nodeid, const CNode* pnode)
{
LOCK(cs_main);
CNodeState& state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
state.name = pnode->addrName;
state.address = pnode->addr;
}
void FinalizeNode(NodeId nodeid)
{
LOCK(cs_main);
CNodeState* state = State(nodeid);
if (state->fSyncStarted)
nSyncStarted--;
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
AddressCurrentlyConnected(state->address);
}
BOOST_FOREACH (const QueuedBlock& entry, state->vBlocksInFlight)
mapBlocksInFlight.erase(entry.hash);
EraseOrphansFor(nodeid);
nPreferredDownload -= state->fPreferredDownload;
mapNodeState.erase(nodeid);
}
void FinalizeNode_Legacy(NodeId nodeid)
{
LOCK(cs_main);
CNodeState* state = State(nodeid);
if (state->fSyncStarted)
nSyncStarted--;
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
AddressCurrentlyConnected(state->address);
}
BOOST_FOREACH (const QueuedBlock& entry, state->vBlocksInFlight) {
mapBlocksInFlight.erase(entry.hash);
}
EraseOrphansFor(nodeid);
nPreferredDownload -= state->fPreferredDownload;
nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
assert(nPeersWithValidatedDownloads >= 0);
mapNodeState.erase(nodeid);
if (mapNodeState.empty()) {
// Do a consistency check after the last peer is removed.
assert(mapBlocksInFlight.empty());
assert(nPreferredDownload == 0);
assert(nPeersWithValidatedDownloads == 0);
}
}
bool FinalizeNode_Fork(NodeId nodeid)
{
if (UseLegacyCode(chainActive.Height())) {
FinalizeNode_Legacy(nodeid);
} else {
FinalizeNode(nodeid);
}
}
// Requires cs_main.
void MarkBlockAsReceived(const uint256& hash)
{
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState* state = State(itInFlight->second.first);
nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders;
state->vBlocksInFlight.erase(itInFlight->second.second);
state->nBlocksInFlight--;
state->nStallingSince = 0;
mapBlocksInFlight.erase(itInFlight);
}
}
// Requires cs_main.
// Returns a bool indicating whether we requested this block.
bool MarkBlockAsReceived_Legacy(const uint256& hash)
{
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState* state = State(itInFlight->second.first);
state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) {
// Last validated block on the queue was received.
nPeersWithValidatedDownloads--;
}
if (state->vBlocksInFlight.begin() == itInFlight->second.second) {
// First block on the queue was received, update the start download time for the next one
state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros());
}
state->vBlocksInFlight.erase(itInFlight->second.second);
state->nBlocksInFlight--;
state->nStallingSince = 0;
mapBlocksInFlight.erase(itInFlight);
return true;
}
return false;
}
// Requires cs_main.
void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex* pindex = NULL)
{
CNodeState* state = State(nodeid);
assert(state != NULL);
// Make sure it's not listed somewhere already.
MarkBlockAsReceived(hash);
QueuedBlock newentry = {hash, pindex, GetTimeMicros(), nQueuedValidatedHeaders, pindex != NULL};
nQueuedValidatedHeaders += newentry.fValidatedHeaders;
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
state->nBlocksInFlight++;
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
}
// Requires cs_main.
void MarkBlockAsInFlight_Legacy(NodeId nodeid, const uint256& hash, CBlockIndex* pindex = NULL)
{
CNodeState* state = State(nodeid);
assert(state != NULL);
// Make sure it's not listed somewhere already.
MarkBlockAsReceived_Legacy(hash);
QueuedBlock newentry = {hash, pindex, pindex != NULL};
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
state->nBlocksInFlight++;
state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders;
if (state->nBlocksInFlight == 1) {
// We're starting a block download (batch) from this peer.
state->nDownloadingSince = GetTimeMicros();
}
if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) {
nPeersWithValidatedDownloads++;
}
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
}
/** Check whether the last unknown block a peer advertized is not yet known. */
void ProcessBlockAvailability(NodeId nodeid)
{
CNodeState* state = State(nodeid);
assert(state != NULL);
if (state->hashLastUnknownBlock != 0) {
BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock);
if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) {
if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
state->pindexBestKnownBlock = itOld->second;
state->hashLastUnknownBlock = uint256(0);
}
}
}
/** Update tracking information about which blocks a peer is assumed to have. */
void UpdateBlockAvailability(NodeId nodeid, const uint256& hash)
{
CNodeState* state = State(nodeid);
assert(state != NULL);
ProcessBlockAvailability(nodeid);
BlockMap::iterator it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end() && it->second->nChainWork > 0) {
// An actually better block was announced.
if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
state->pindexBestKnownBlock = it->second;
} else {
// An unknown block was announced; just assume that the latest one is the best one.
state->hashLastUnknownBlock = hash;
}
}
/** Find the last common ancestor two blocks have.
* Both pa and pb must be non-NULL. */
CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb)
{
if (pa->nHeight > pb->nHeight) {
pa = pa->GetAncestor(pb->nHeight);
} else if (pb->nHeight > pa->nHeight) {
pb = pb->GetAncestor(pa->nHeight);
}
while (pa != pb && pa && pb) {
pa = pa->pprev;
pb = pb->pprev;
}
// Eventually all chain branches meet at the genesis block.
assert(pa == pb);
return pa;
}
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries. */
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller)
{
if (count == 0)
return;
vBlocks.reserve(vBlocks.size() + count);
CNodeState* state = State(nodeid);
assert(state != NULL);
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid);
if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) {
// This peer has nothing interesting.
return;
}
if (state->pindexLastCommonBlock == NULL) {
// Bootstrap quickly by guessing a parent of our best tip is the forking point.
// Guessing wrong in either direction is not a problem.
state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())];
}
// If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
// of their current tip anymore. Go back enough to fix that.
state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock);
if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
return;
std::vector<CBlockIndex*> vToFetch;
CBlockIndex* pindexWalk = state->pindexLastCommonBlock;
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
// download that next block if the window were 1 larger.
int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;
int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
NodeId waitingfor = -1;
while (pindexWalk->nHeight < nMaxHeight) {
// Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards
// pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive
// as iterating over ~100 CBlockIndex* entries anyway.
int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128));
vToFetch.resize(nToFetch);
pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch);
vToFetch[nToFetch - 1] = pindexWalk;
for (unsigned int i = nToFetch - 1; i > 0; i--) {
vToFetch[i - 1] = vToFetch[i]->pprev;
}
// Iterate over those blocks in vToFetch (in forward direction), adding the ones that
// are not yet downloaded and not in flight to vBlocks. In the mean time, update
// pindexLastCommonBlock as long as all ancestors are already downloaded.
BOOST_FOREACH (CBlockIndex* pindex, vToFetch) {
if (!pindex->IsValid(BLOCK_VALID_TREE)) {
// We consider the chain that this peer is on invalid.
return;
}
if (pindex->nStatus & BLOCK_HAVE_DATA) {
if (pindex->nChainTx)
state->pindexLastCommonBlock = pindex;
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
// The block is not already downloaded, and not yet in flight.
if (pindex->nHeight > nWindowEnd) {
// We reached the end of the window.
if (vBlocks.size() == 0 && waitingfor != nodeid) {
// We aren't able to fetch anything, but we would be if the download window was one larger.
nodeStaller = waitingfor;
}
return;
}
vBlocks.push_back(pindex);
if (vBlocks.size() == count) {
return;
}
} else if (waitingfor == -1) {
// This is the first already-in-flight block.
waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first;
}
}
}
}
} // namespace
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats)
{
LOCK(cs_main);
CNodeState* state = State(nodeid);
if (state == NULL)
return false;
stats.nMisbehavior = state->nMisbehavior;
stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
BOOST_FOREACH (const QueuedBlock& queue, state->vBlocksInFlight) {
if (queue.pindex)
stats.vHeightInFlight.push_back(queue.pindex->nHeight);
}
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_Fork);
}
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
{
nodeSignals.GetHeight.disconnect(&GetHeight);
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
nodeSignals.SendMessages.disconnect(&SendMessages);
nodeSignals.InitializeNode.disconnect(&InitializeNode);
nodeSignals.FinalizeNode.disconnect(&FinalizeNode_Fork);
}
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{
// Find the first block the caller has in the main chain
BOOST_FOREACH (const uint256& hash, locator.vHave) {
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) {
CBlockIndex* pindex = (*mi).second;
if (chain.Contains(pindex))
return pindex;
}
}
return chain.Genesis();
}
CCoinsViewCache* pcoinsTip = NULL;
CBlockTreeDB* pblocktree = NULL;
static const int32_t GetCurrentTransactionVersion()
{
return UseLegacyCode() ? 1 : 2;
}
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
//
bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
return false;
// Ignore big transactions, to avoid a
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// large transaction with a missing parent then we assume
// it will rebroadcast it later, after the parent transaction(s)
// have been mined or received.
// 10,000 orphans, each of which is at most 5,000 bytes big is
// at most 500 megabytes of orphans:
unsigned int sz = tx.GetSerializeSize(SER_NETWORK, GetCurrentTransactionVersion());
if (sz > 5000) {
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
return false;
}
mapOrphanTransactions[hash].tx = tx;
mapOrphanTransactions[hash].fromPeer = peer;
BOOST_FOREACH (const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(),
mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size());
return true;
}
void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
return;
BOOST_FOREACH (const CTxIn& txin, it->second.tx.vin) {
map<uint256, set<uint256> >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash);
if (itPrev == mapOrphanTransactionsByPrev.end())
continue;
itPrev->second.erase(hash);
if (itPrev->second.empty())
mapOrphanTransactionsByPrev.erase(itPrev);
}
mapOrphanTransactions.erase(it);
}
void EraseOrphansFor(NodeId peer)
{
int nErased = 0;
map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
while (iter != mapOrphanTransactions.end()) {
map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer) {
EraseOrphanTx(maybeErase->second.tx.GetHash());
++nErased;
}
}
if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer);
}
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans) {
// Evict a random orphan:
uint256 randomhash = GetRandHash();
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
EraseOrphanTx(it->first);
++nEvicted;
}
return nEvicted;
}
bool IsStandardTx(const CTransaction& tx, string& reason, bool isLoadingTx)
{
if (isLoadingTx)
return true;
AssertLockHeld(cs_main);
if (tx.GetVersion() > GetCurrentTransactionVersion() || tx.GetVersion() < 1) {
reason = "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 be 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, chainActive.Height() + 1)) {
reason = "non-final";
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, GetCurrentTransactionVersion());
unsigned int nMaxSize = MAX_STANDARD_TX_SIZE;
if (sz >= nMaxSize) {
reason = "tx-size";
return false;
}
for (const CTxIn& txin : tx.vin) {
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
// keys. (remember the 520 byte limit on redeemScript size) That works
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
// bytes of scriptSig, which we round off to 1650 bytes for some minor
// future-proofing. That's also enough to spend a 20-of-20
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
// considered standard)
if (txin.scriptSig.size() > 1650) {
reason = "scriptsig-size";
return false;
}
if (!txin.scriptSig.IsPushOnly()) {
reason = "scriptsig-not-pushonly";
return false;
}
}
unsigned int nDataOut = 0;
txnouttype whichType;
BOOST_FOREACH (const CTxOut& txout, tx.vout) {
if (!::IsStandard(txout.scriptPubKey, whichType)) {
reason = "scriptpubkey";
return false;
}
if (whichType == TX_NULL_DATA)
nDataOut++;
else if (whichType == TX_MULTISIG && !fIsBareMultisigStd) {
reason = "bare-multisig";
return false;
} else if (txout.IsDust(::minRelayTxFee)) {
reason = "dust";
return false;
}
}
// only one OP_RETURN txout is permitted
if (nDataOut > 1) {
reason = "multi-op-return";
return false;
}
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 = chainActive.Height();
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 to mitigate two
* potential denial-of-service attacks:
*
* 1. scriptSigs with extra data stuffed into them,
* not consumed by scriptPubKey (or P2SH script)
* 2. P2SH scripts with a crazy number of expensive
* CHECKSIG/CHECKMULTISIG operations
*/
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
return true;
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
const CScript& prevScript = prev.scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions))
return false;
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
if (nArgsExpected < 0)
return false;
// Transactions with extra stuff in their scriptSigs are
// non-standard. Note that this EvalScript() call will
// be quick, because if there are any operations
// beside "push data" in the scriptSig
// IsStandard() will have already returned false
// and this method isn't called.
vector<vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, false, BaseSignatureChecker()))
return false;
if (whichType == TX_SCRIPTHASH) {
if (stack.empty())
return false;
CScript subscript(stack.back().begin(), stack.back().end());
vector<vector<unsigned char> > vSolutions2;
txnouttype whichType2;
if (Solver(subscript, whichType2, vSolutions2)) {
int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
if (tmpExpected < 0)
return false;
nArgsExpected += tmpExpected;
} else {
// Any other Script with less than 15 sigops OK:
unsigned int sigops = subscript.GetSigOpCount(true);
// ... extra data left on the stack after execution is OK, too:
return (sigops <= MAX_P2SH_SIGOPS);
}
}
if (stack.size() != (unsigned int)nArgsExpected)
return false;
}
return true;
}
bool AreInputsStandard_Legacy(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
std::vector<std::vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
const CScript& prevScript = prev.scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions))
return false;
if (whichType == TX_SCRIPTHASH) {
std::vector<std::vector<unsigned char> > stack;
// convert the scriptSig into a stack, so we can inspect the redeemScript
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), 0))
return false;
if (stack.empty())
return false;
CScript subscript(stack.back().begin(), stack.back().end());
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
return false;
}
}
}
return true;
}
unsigned int GetLegacySigOpCount(const CTransaction& tx)
{
unsigned int nSigOps = 0;
BOOST_FOREACH (const CTxIn& txin, tx.vin) {
nSigOps += txin.scriptSig.GetSigOpCount(false);
}
BOOST_FOREACH (const CTxOut& txout, tx.vout) {
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
}
return nSigOps;
}
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
{
if (tx.IsCoinBase())
return 0;
unsigned int nSigOps = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxOut& prevout = inputs.GetOutputFor(tx.vin[i]);
if (prevout.scriptPubKey.IsPayToScriptHash())
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
}
return nSigOps;
}
int GetInputAge(CTxIn& vin)
{
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
{
LOCK(mempool.cs);
CCoinsViewMemPool viewMempool(pcoinsTip, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
const CCoins* coins = view.AccessCoins(vin.prevout.hash);
if (coins) {
if (coins->nHeight < 0) return 0;
return (chainActive.Tip()->nHeight + 1) - coins->nHeight;
} else
return -1;
}
}
bool MoneyRange(CAmount nValueOut)
{
return nValueOut >= 0 && nValueOut <= Params().GetMaxMoneyOut();
}
bool CheckTransaction(const CTransaction& tx, CValidationState& state)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
// Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE_LEGACY)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
// Check for negative or overflow output values
CAmount nValueOut = 0;
BOOST_FOREACH (const CTxOut& txout, tx.vout) {
if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsLegacyCoinStake())
return state.DoS(100, error("CheckTransaction(): txout empty for user transaction"));
if (txout.nValue < 0)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > Params().GetMaxMoneyOut())
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}
// Check for duplicate inputs
set<COutPoint> vInOutPoints;
BOOST_FOREACH (const CTxIn& txin, tx.vin) {
if (vInOutPoints.count(txin.prevout))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
vInOutPoints.insert(txin.prevout);
}
if (tx.IsCoinBase()) {
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
} else {
BOOST_FOREACH (const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
}
return true;
}
bool CheckFinalTx(const CTransaction& tx, int flags)
{
AssertLockHeld(cs_main);
// By convention a negative value for flags indicates that the
// current network-enforced consensus rules should be used. In
// a future soft-fork scenario that would mean checking which
// rules would be enforced for the next block and setting the
// appropriate flags. At the present time no soft-forks are
// scheduled, so no flags are set.
flags = std::max(flags, 0);
// CheckFinalTx() uses chainActive.Height()+1 to evaluate
// nLockTime because 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().
const int nBlockHeight = chainActive.Height() + 1;
// BIP113 will require that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.
// When the next block is created its previous block will be the current
// chain tip, so we use that to calculate the median time passed to
// IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set.
const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) ? chainActive.Tip()->GetMedianTimePast() : GetAdjustedTime();
return IsFinalTx(tx, nBlockHeight, nBlockTime);
}
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
{
{
LOCK(mempool.cs);
uint256 hash = tx.GetHash();
double dPriorityDelta = 0;
CAmount nFeeDelta = 0;
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
if (dPriorityDelta > 0 || nFeeDelta > 0)
return 0;
}
CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);
if (fAllowFree) {
// There is a free transaction area in blocks created by most miners,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
nMinFee = 0;
}
if (!MoneyRange(nMinFee))
nMinFee = Params().GetMaxMoneyOut();
return nMinFee;
}
ThresholdState VersionBitsTipState_Legacy(CChainParams::DeploymentPos pos)
{
LOCK(cs_main);
return VersionBitsState(chainActive.Tip(), pos, versionbitscache);
}
bool TestLockPointValidity(const LockPoints* lp)
{
AssertLockHeld(cs_main);
assert(lp);
// If there are relative lock times then the maxInputBlock will be set
// If there are no relative lock times, the LockPoints don't depend on the chain
if (lp->maxInputBlock) {
// Check whether chainActive is an extension of the block at which the LockPoints
// calculation was valid. If not LockPoints are no longer valid
if (!chainActive.Contains(lp->maxInputBlock)) {
return false;
}
}
// LockPoints still valid
return true;
}
/**
* Calculates the block height and previous block's median time past at
* which the transaction will be considered final in the context of BIP 68.
* Also removes from the vector of input heights any entries which did not
* correspond to sequence locked inputs as they do not affect the calculation.
*/
static std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction& tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
{
assert(prevHeights->size() == tx.vin.size());
// Will be set to the equivalent height- and time-based nLockTime
// values that would be necessary to satisfy all relative lock-
// time constraints given our view of block chain history.
// The semantics of nLockTime are the last invalid height/time, so
// use -1 to have the effect of any height or time being valid.
int nMinHeight = -1;
int64_t nMinTime = -1;
// tx.nVersion is signed integer so requires cast to unsigned otherwise
// we would be doing a signed comparison and half the range of nVersion
// wouldn't support BIP 68.
bool fEnforceBIP68 = static_cast<uint32_t>(tx.GetVersion()) >= 2 && flags & LOCKTIME_VERIFY_SEQUENCE;
// Do not enforce sequence numbers as a relative lock time
// unless we have been instructed to
if (!fEnforceBIP68) {
return std::make_pair(nMinHeight, nMinTime);
}
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex];
// Sequence numbers with the most significant bit set are not
// treated as relative lock-times, nor are they given any
// consensus-enforced meaning at this point.
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
// The height of this input is not relevant for sequence locks
(*prevHeights)[txinIndex] = 0;
continue;
}
int nCoinHeight = (*prevHeights)[txinIndex];
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight - 1, 0))->GetMedianTimePast();
// NOTE: Subtract 1 to maintain nLockTime semantics
// BIP 68 relative lock times have the semantics of calculating
// the first block or time at which the transaction would be
// valid. When calculating the effective block time or height
// for the entire transaction, we switch to using the
// semantics of nLockTime which is the last invalid block
// time or height. Thus we subtract 1 from the calculated
// time or height.
// Time-based relative lock-times are measured from the
// smallest allowed timestamp of the block containing the
// txout being spent, which is the median time past of the
// block prior.
nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
} else {
nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
}
}
return std::make_pair(nMinHeight, nMinTime);
}
static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
{
assert(block.pprev);
int64_t nBlockTime = block.pprev->GetMedianTimePast();
if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
return false;
return true;
}
bool SequenceLocks(const CTransaction& tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
{
return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
}
bool CheckSequenceLocks(const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints)
{
AssertLockHeld(cs_main);
AssertLockHeld(mempool.cs);
CBlockIndex* tip = chainActive.Tip();
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
// height based locks because when SequenceLocks() is called within
// ConnectBlock(), 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 use one more than chainActive.Height()
index.nHeight = tip->nHeight + 1;
std::pair<int, int64_t> lockPair;
if (useExistingLockPoints) {
assert(lp);
lockPair.first = lp->height;
lockPair.second = lp->time;
} else {
// pcoinsTip contains the UTXO set for chainActive.Tip()
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex];
CCoins coins;
if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) {
return error("%s: Missing input", __func__);
}
if (coins.nHeight == MEMPOOL_HEIGHT) {
// Assume all mempool transaction confirm in the next block
prevheights[txinIndex] = tip->nHeight + 1;
} else {
prevheights[txinIndex] = coins.nHeight;
}
}
lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);
if (lp) {
lp->height = lockPair.first;
lp->time = lockPair.second;
// Also store the hash of the block with the highest height of
// all the blocks which have sequence locked prevouts.
// This hash needs to still be on the chain
// for these LockPoint calculations to be valid
// Note: It is impossible to correctly calculate a maxInputBlock
// if any of the sequence locked inputs depend on unconfirmed txs,
// except in the special case where the relative lock time/height
// is 0, which is equivalent to no sequence lock. Since we assume
// input height of tip+1 for mempool txs and test the resulting
// lockPair from CalculateSequenceLocks against tip+1. We know
// EvaluateSequenceLocks will fail if there was a non-zero sequence
// lock on a mempool input, so we can use the return value of
// CheckSequenceLocks to indicate the LockPoints validity
int maxInputHeight = 0;
BOOST_FOREACH (int height, prevheights) {
// Can ignore mempool inputs since we'll fail if they had non-zero locks
if (height != tip->nHeight + 1) {
maxInputHeight = std::max(maxInputHeight, height);
}
}
lp->maxInputBlock = tip->GetAncestor(maxInputHeight);
}
}
return EvaluateSequenceLocks(index, lockPair);
}
void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
{
int expired = pool.Expire(GetTime() - age);
if (expired != 0)
LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired);
std::vector<uint256> vNoSpendsRemaining;
pool.TrimToSize(limit, &vNoSpendsRemaining);
BOOST_FOREACH (const uint256& removed, vNoSpendsRemaining)
pcoinsTip->Uncache(removed);
}
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage_Legacy(const CValidationState& state)
{
return strprintf("%s%s (code %i)",
state.GetRejectReason(),
state.GetDebugMessage_Legacy().empty() ? "" : ", " + state.GetDebugMessage_Legacy(),
state.GetRejectCode());
}
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, std::vector<uint256>& vHashTxnToUncache, bool ignoreFees, bool isLoadingTx)
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
*pfMissingInputs = false;
if (!CheckTransaction(tx, state))
return state.DoS(100, error("AcceptToMemoryPool: : CheckTransaction failed"), REJECT_INVALID, "bad-tx");
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
return state.DoS(100, error("AcceptToMemoryPool: : coinbase as individual tx"),
REJECT_INVALID, "coinbase");
// Coinstake is only valid in a block, not as a loose transaction
if (tx.IsCoinStake())
return state.DoS(100, error("AcceptToMemoryPool: coinstake as individual tx. txid=%s", tx.GetHash().GetHex()),
REJECT_INVALID, "coinstake");
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason;
if (Params().RequireStandard() && !IsStandardTx(tx, reason, isLoadingTx))
return state.DoS(0,
error("AcceptToMemoryPool : nonstandard transaction: %s", reason),
REJECT_NONSTANDARD, reason);
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
if (!isLoadingTx && !CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
// is it already in the memory pool?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool");
// Check for conflicts with in-memory transactions
set<uint256> setConflicts;
{
LOCK(pool.cs); // protect pool.mapNextTx
BOOST_FOREACH (const CTxIn& txin, tx.vin) {
if (pool.mapNextTx.count(txin.prevout)) {
const CTransaction* ptxConflicting = pool.mapNextTx[txin.prevout].ptx;
if (!setConflicts.count(ptxConflicting->GetHash())) {
// Allow opt-out of transaction replacement by setting
// nSequence >= maxint-1 on all inputs.
//
// maxint-1 is picked to still allow use of nLockTime by
// non-replacable transactions. All inputs rather than just one
// is for the sake of multi-party protocols, where we don't
// want a single party to be able to disable replacement.
//
// The opt-out ignores descendants as anyone relying on
// first-seen mempool behavior should be checking all
// unconfirmed ancestors anyway; doing otherwise is hopelessly
// insecure.
bool fReplacementOptOut = true;
if (fEnableReplacement) {
BOOST_FOREACH (const CTxIn& txin, ptxConflicting->vin) {
if (txin.nSequence < std::numeric_limits<unsigned int>::max() - 1) {
fReplacementOptOut = false;
break;
}
}
}
if (fReplacementOptOut)
return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
setConflicts.insert(ptxConflicting->GetHash());
}
}
}
}
{
CCoinsView dummy;
CCoinsViewCache view(&dummy);
CAmount nValueIn = 0;
LockPoints lp;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
// do we already have it?
bool fHadTxInCache = pcoinsTip->HaveCoinsInCache_Legacy(hash);
if (view.HaveCoins(hash)) {
if (!fHadTxInCache)
vHashTxnToUncache.push_back(hash);
return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known");
}
// do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
// and only helps with filling in pfMissingInputs (to determine missing vs spent).
BOOST_FOREACH (const CTxIn txin, tx.vin) {
if (!pcoinsTip->HaveCoinsInCache_Legacy(txin.prevout.hash))
vHashTxnToUncache.push_back(txin.prevout.hash);
if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs)
*pfMissingInputs = true;
return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid()
}
//Check for invalid/fraudulent inputs
if (!ValidOutPoint(txin.prevout, chainActive.Height())) {
return state.Invalid(error("%s : tried to spend invalid input %s in tx %s", __func__, txin.prevout.ToString(),
tx.GetHash().GetHex()),
REJECT_INVALID, "bad-txns-invalid-inputs");
}
}
// are the actual inputs available?
if (!view.HaveInputs(tx))
return state.Invalid(error("AcceptToMemoryPool : inputs already spent"),
REJECT_DUPLICATE, "bad-txns-inputs-spent");
// Bring the best block into scope
view.GetBestBlock();
nValueIn = view.GetValueIn(tx);
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
// Only accept BIP68 sequence locked transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
// CoinsViewCache instead of create its own
if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
}
// Check for non-standard pay-to-script-hash in inputs
if (Params().RequireStandard() && !AreInputsStandard(tx, view))
return state.Invalid(error("AcceptToMemoryPool: : nonstandard transaction input"), REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn - nValueOut;
// nModifiedFees includes any fee deltas from PrioritiseTransaction
CAmount nModifiedFees = nFees;
double nPriorityDummy = 0;
pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
CAmount inChainInputValue;
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false;
BOOST_FOREACH (const CTxIn& txin, tx.vin) {
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
if (coins->IsCoinBase()) {
fSpendsCoinbase = true;
break;
}
}
unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
unsigned int nSize = entry.GetTxSize();
unsigned int nMaxSigOps = MAX_TX_SIGOPS_CURRENT;
if (nSigOps > nMaxSigOps || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp))
return state.DoS(0,
error("AcceptToMemoryPool : too many sigops %s, %d > %d",
hash.ToString(), nSigOps, nMaxSigOps),
REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
// Don't accept it if it can't get into a block
// but prioritise dstx and don't check fees for it
if (!ignoreFees) {
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE_LEGACY) * 1000000).GetFee(nSize);
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY_LEGACY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();
LOCK(csFreeLimiter);
// 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", DEFAULT_LIMITFREERELAY_LEGACY) * 10 * 1000)
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction");
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount + nSize);
dFreeCount += nSize;
}
if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
return state.Invalid(false,
REJECT_HIGHFEE_LEGACY, "absurdly-high-fee",
strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000));
// Check if it's economically rational to mine this transaction rather
// than the ones it replaces.
CAmount nConflictingFees = 0;
size_t nConflictingSize = 0;
uint64_t nConflictingCount = 0;
CTxMemPool::setEntries allConflicting;
// If we don't hold the lock allConflicting might be incomplete; the
// subsequent RemoveStaged() and addUnchecked() calls don't guarantee
// mempool consistency for us.
LOCK(pool.cs);
if (setConflicts.size()) {
CFeeRate newFeeRate(nModifiedFees, nSize);
set<uint256> setConflictsParents;
const int maxDescendantsToVisit = 100;
CTxMemPool::setEntries setIterConflicting;
BOOST_FOREACH (const uint256& hashConflicting, setConflicts) {
CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting);
if (mi == pool.mapTx.end())
continue;
// Save these to avoid repeated lookups
setIterConflicting.insert(mi);
// If this entry is "dirty", then we don't have descendant
// state for this transaction, which means we probably have
// lots of in-mempool descendants.
// Don't allow replacements of dirty transactions, to ensure
// that we don't spend too much time walking descendants.
// This should be rare.
if (mi->IsDirty()) {
return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s; cannot replace tx %s with untracked descendants", hash.ToString(), mi->GetTx().GetHash().ToString()), REJECT_NONSTANDARD, "too many potential replacements");
}
// Don't allow the replacement to reduce the feerate of the
// mempool.
//
// We usually don't want to accept replacements with lower
// feerates than what they replaced as that would lower the
// feerate of the next block. Requiring that the feerate always
// be increased is also an easy-to-reason about way to prevent
// DoS attacks via replacements.
//
// The mining code doesn't (currently) take children into
// account (CPFP) so we only consider the feerates of
// transactions being directly replaced, not their indirect
// descendants. While that does mean high feerate children are
// ignored when deciding whether or not to replace, we do
// require the replacement to pay more overall fees too,
// mitigating most cases.
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
if (newFeeRate <= oldFeeRate) {
return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s; new feerate %s <= old feerate %s", hash.ToString(), newFeeRate.ToString(), oldFeeRate.ToString()), REJECT_INSUFFICIENTFEE, "insufficient fee");
}
BOOST_FOREACH (const CTxIn& txin, mi->GetTx().vin) {
setConflictsParents.insert(txin.prevout.hash);
}
nConflictingCount += mi->GetCountWithDescendants();
}
// This potentially overestimates the number of actual descendants
// but we just want to be conservative to avoid doing too much
// work.
if (nConflictingCount <= maxDescendantsToVisit) {
// If not too many to replace, then calculate the set of
// transactions that would have to be evicted
BOOST_FOREACH (CTxMemPool::txiter it, setIterConflicting) {
pool.CalculateDescendants(it, allConflicting);
}
BOOST_FOREACH (CTxMemPool::txiter it, allConflicting) {
nConflictingFees += it->GetModifiedFee();
nConflictingSize += it->GetTxSize();
}
} else {
return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s; too many potential replacements (%d > %d)\n", hash.ToString(), nConflictingCount, maxDescendantsToVisit), REJECT_NONSTANDARD, "too many potential replacements");
}
for (unsigned int j = 0; j < tx.vin.size(); j++) {
// We don't want to accept replacements that require low
// feerate junk to be mined first. Ideally we'd keep track of
// the ancestor feerates and make the decision based on that,
// but for now requiring all new inputs to be confirmed works.
if (!setConflictsParents.count(tx.vin[j].prevout.hash)) {
// Rather than check the UTXO set - potentially expensive -
// it's cheaper to just check if the new input refers to a
// tx that's in the mempool.
if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end())
return state.DoS(0, error("AcceptToMemoryPool: replacement %s adds unconfirmed input, idx %d", hash.ToString(), j), REJECT_NONSTANDARD, "replacement-adds-unconfirmed");
}
}
// The replacement must pay greater fees than the transactions it
// replaces - if we did the bandwidth used by those conflicting
// transactions would not be paid for.
if (nModifiedFees < nConflictingFees) {
return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s", hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)),
REJECT_INSUFFICIENTFEE, "insufficient fee");
}
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::minRelayTxFee.GetFee(nSize)) {
return state.DoS(0,
error("AcceptToMemoryPool: rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(), FormatMoney(nDeltaFees), FormatMoney(::minRelayTxFee.GetFee(nSize))),
REJECT_INSUFFICIENTFEE, "insufficient fee");
}
}
// Remove conflicting transactions from the mempool
BOOST_FOREACH (const CTxMemPool::txiter it, allConflicting) {
LogPrint("mempool", "replacing tx %s with %s for %s KORE additional fees, %d delta bytes\n",
it->GetTx().GetHash().ToString(),
hash.ToString(),
FormatMoney(nModifiedFees - nConflictingFees),
(int)nSize - (int)nConflictingSize);
}
pool.RemoveStaged(allConflicting);
}
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true))
return false;
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
// transactions to pass as valid when they're actually invalid. For
// instance the STRICTENC flag was incorrectly allowing certain
// CHECKSIG NOT scripts to pass, even though they were invalid.
//
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) {
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage_Legacy(state));
}
// Calculate in-mempool ancestors, up to a limit.
CTxMemPool::setEntries setAncestors;
size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT_LEGACY);
size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT_LEGACY) * 1000;
size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT_LEGACY);
size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT_LEGACY) * 1000;
std::string errString;
if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
return state.DoS(0, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString);
}
// A transaction that spends outputs that would be replaced by it is invalid. Now
// that we have the set of all ancestors we can detect this
// pathological case by making sure setConflicts and setAncestors don't
// intersect.
BOOST_FOREACH (CTxMemPool::txiter ancestorIt, setAncestors) {
const uint256& hashAncestor = ancestorIt->GetTx().GetHash();
if (setConflicts.count(hashAncestor)) {
return state.DoS(10, error("AcceptToMemoryPool: %s spends conflicting transaction %s", hash.ToString(), hashAncestor.ToString()), REJECT_INVALID, "bad-txns-spends-conflicting-tx");
}
}
// Store transaction in memory
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
// trim mempool and check if tx was trimmed
if (!fOverrideMempoolLimit) {
LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE_LEGACY) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY_LEGACY) * 60 * 60);
if (!pool.exists(hash))
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full");
}
}
SyncWithWallets(tx, NULL);
return true;
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, bool ignoreFees, bool isLoadingTx)
{
std::vector<uint256> vHashTxToUncache;
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, fRejectAbsurdFee, vHashTxToUncache, ignoreFees, isLoadingTx);
if (!res) {
BOOST_FOREACH (const uint256& hashTx, vHashTxToUncache)
pcoinsTip->Uncache(hashTx);
}
return res;
}
bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee, bool isDSTX)
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
*pfMissingInputs = false;
if (!CheckTransaction(tx, state))
return error("AcceptableInputs: CheckTransaction failed");
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
return state.DoS(100, error("AcceptableInputs: coinbase as individual tx"),
REJECT_INVALID, "coinbase");
// is it already in the memory pool?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
return false;
// Check for conflicts with in-memory transactions
{
LOCK(pool.cs); // protect pool.mapNextTx
for (unsigned int i = 0; i < tx.vin.size(); i++) {
COutPoint outpoint = tx.vin[i].prevout;
if (pool.mapNextTx.count(outpoint)) {
// Disable replacement feature for now
return false;
}
}
}
{
CCoinsView dummy;
CCoinsViewCache view(&dummy);
CAmount nValueIn = 0;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
// do we already have it?
if (view.HaveCoins(hash))
return false;
// do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
// only helps filling in pfMissingInputs (to determine missing vs spent).
for (const CTxIn txin : tx.vin) {
if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs)
*pfMissingInputs = true;
return false;
}
// check for invalid/fraudulent inputs
if (!ValidOutPoint(txin.prevout, chainActive.Height())) {
return state.Invalid(error("%s: tried to spend invalid input %s in tx %s", __func__, txin.prevout.ToString(),
tx.GetHash().GetHex()),
REJECT_INVALID, "bad-txns-invalid-inputs");
}
}
// are the actual inputs available?
if (!view.HaveInputs(tx))
return state.Invalid(error("AcceptableInputs: inputs already spent"),
REJECT_DUPLICATE, "bad-txns-inputs-spent");
// Bring the best block into scope
view.GetBestBlock();
nValueIn = view.GetValueIn(tx);
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
}
// Check for non-standard pay-to-script-hash in inputs
// for any real tx this will be checked on AcceptToMemoryPool anyway
// if (Params().RequireStandard() && !AreInputsStandard(tx, view))
// return error("AcceptableInputs: nonstandard transaction input");
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
// itself can contain sigops MAX_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
unsigned int nSigOps = GetLegacySigOpCount(tx);
unsigned int nMaxSigOps = MAX_TX_SIGOPS_CURRENT;
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > nMaxSigOps)
return state.DoS(0,
error("AcceptableInputs: too many sigops %s, %d > %d",
hash.ToString(), nSigOps, nMaxSigOps),
REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn - nValueOut;
CAmount inChainInputValue;
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height());
unsigned int nSize = entry.GetTxSize();
// Don't accept it if it can't get into a block
// but prioritise dstx and don't check fees for it
if (isDSTX) {
mempool.PrioritiseTransaction(hash, hash.ToString(), 1000, 0.1 * COIN);
} else { // same as !ignoreFees for AcceptToMemoryPool
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee)
return state.DoS(0, error("AcceptableInputs: not enough fees %s, %d < %d", hash.ToString(), nFees, txMinFee),
REJECT_INSUFFICIENTFEE, "insufficient fee");
// Require that free transactions have sufficient priority to be mined in the next block.
CAmount inChainInputValue;
if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1, inChainInputValue))) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize)) {
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();
LOCK(csFreeLimiter);
// 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", 30) * 10 * 1000)
return state.DoS(0, error("AcceptableInputs: free transaction rejected by rate limiter"),
REJECT_INSUFFICIENTFEE, "rate limited free transaction");
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount + nSize);
dFreeCount += nSize;
}
}
if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
return error("AcceptableInputs: insane fees %s, %d > %d",
hash.ToString(),
nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!CheckInputs(tx, state, view, false, STANDARD_SCRIPT_VERIFY_FLAGS, true)) {
return error("AcceptableInputs: ConnectInputs failed %s", hash.ToString());
}
}
return true;
}
bool FindTransactionsByDestination(const CTxDestination& dest, std::set<CExtDiskTxPos>& setpos)
{
uint160 addrid;
const CKeyID* pkeyid = boost::get<CKeyID>(&dest);
if (pkeyid)
addrid = static_cast<uint160>(*pkeyid);
if (addrid.IsNull()) {
const CScriptID* pscriptid = boost::get<CScriptID>(&dest);
if (pscriptid)
addrid = static_cast<uint160>(*pscriptid);
}
if (addrid.IsNull())
return false;
LOCK(cs_main);
if (!fAddrIndex)
return false;
std::vector<CExtDiskTxPos> vPos;
if (!pblocktree->ReadAddrIndex(addrid, vPos))
return false;
setpos.insert(vPos.begin(), vPos.end());
return true;
}
/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
bool GetTransaction(const uint256& hash, CTransaction& txOut, uint256& hashBlock, bool fAllowSlow)
{
CBlockIndex* pindexSlow = NULL;
{
LOCK(cs_main);
{
if (mempool.lookup(hash, txOut)) {
return true;
}
}
if (fTxIndex) {
CDiskTxPos postx;
if (pblocktree->ReadTxIndex(hash, postx)) {
CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
if (file.IsNull())
return error("%s: OpenBlockFile failed", __func__);
CBlockHeader header;
try {
file >> header;
fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
file >> txOut;
} catch (std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
hashBlock = header.GetHash();
if (txOut.GetHash() != hash)
return error("%s : txid mismatch", __func__);
return true;
}
// transaction not found in the index, nothing more can be done
return false;
}
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
int nHeight = -1;
{
CCoinsViewCache& view = *pcoinsTip;
const CCoins* coins = view.AccessCoins(hash);
if (coins)
nHeight = coins->nHeight;
}
if (nHeight > 0)
pindexSlow = chainActive[nHeight];
}
}
if (pindexSlow) {
CBlock block;
if (ReadBlockFromDisk(block, pindexSlow)) {
BOOST_FOREACH (const CTransaction& tx, block.vtx) {
if (tx.GetHash() == hash) {
txOut = tx;
hashBlock = pindexSlow->GetBlockHash();
return true;
}
}
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////////
//
// CBlock and CBlockIndex
//
bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos)
{
// Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("WriteBlockToDisk : OpenBlockFile failed");
// Write index header
unsigned int nSize = fileout.GetSerializeSize(block);
fileout << FLATDATA(Params().MessageStart()) << nSize;
// Write block
long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0)
return error("WriteBlockToDisk : ftell failed");
pos.nPos = (unsigned int)fileOutPos;
fileout << block;
return true;
}
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
{
block.SetNull();
// Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
return error("ReadBlockFromDisk : OpenBlockFile failed");
// Read block
try {
filein >> block;
} catch (std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
// Check the header
if (block.IsProofOfWork()) {
if (UseLegacyCode(block)) {
if (!CheckProofOfWork_Legacy(block.GetHash(), block.nBits))
return error("ReadBlockFromDisk : Errors in block header");
} else {
if (!CheckProofOfWork(block.GetHash(), block.nBits))
return error("ReadBlockFromDisk : Errors in block header");
}
}
return true;
}
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
{
if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
return false;
if (block.GetHash() != pindex->GetBlockHash()) {
if (fDebug) {
LogPrintf("%s : block=%s index=%s\n", __func__, block.GetHash().ToString().c_str(), pindex->GetBlockHash().ToString().c_str());
LogPrintf(" %s \n", block.ToString());
}
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index");
}
return true;
}
double ConvertBitsToDouble(unsigned int nBits)
{
int nShift = (nBits >> 24) & 0xff;
double dDiff =
(double)0x0000ffff / (double)(nBits & 0x00ffffff);
while (nShift < 29) {
dDiff *= 256.0;
nShift++;
}
while (nShift > 29) {
dDiff /= 256.0;
nShift--;
}
return dDiff;
}
CAmount GetProofOfStakeSubsidy_Legacy(int nHeight, CAmount input)
{
CAmount subsidy = input + input * 0.00024;
return subsidy;
}
int64_t GetBlockValue(int nHeight)
{
if (Params().EnableBigRewards()) {
if (nHeight >= 0 && nHeight <= 50)
return 40000 * COIN;
}
return 5 * COIN;
}
CAmount GetMasternodeFundPayment(CAmount blockReward, CAmount stakedBalance, CBlockIndex* pindexPrev)
{
double moneySupplyDouble = pindexPrev->nMoneySupply;
double blockRewardDouble = (double)blockReward;
double stakedBalanceDouble = (double)min(stakedBalance, MAXIMUM_STAKE_VALUE);
return (1 - ((4e-13 * stakedBalanceDouble) + (1e-58 * pow(stakedBalanceDouble, 2) * moneySupplyDouble) + 0.43)) * blockReward;
}
int GetBestPeerHeight()
{
return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
}
bool IsInitialBlockDownload()
{
const CChainParams& chainParams = Params();
LOCK(cs_main);
if (fImporting || fReindex || fVerifyingBlocks || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate())
return true;
static bool lockIBDState = false;
if (lockIBDState)
return false;
bool state = (chainActive.Height() < pindexBestHeader->nHeight - 2 * 60 || // 60 Blocks per hour
pindexBestHeader->GetBlockTime() < GetTime() - chainParams.GetMaxTipAge()); // ~1440 blocks behind -> 2 x fork detection time
if (!state)
lockIBDState = true;
return state;
}
bool fLargeWorkForkFound = false;
bool fLargeWorkInvalidChainFound = false;
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
void CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
// (we assume we don't get stuck on a fork before the last checkpoint)
if (IsInitialBlockDownload())
return;
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
// of our head, drop it
if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72)
pindexBestForkTip = NULL;
if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * Params().GetCoinMaturity()))) {
if (!fLargeWorkForkFound && pindexBestForkBase) {
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
CAlert::Notify(warning, true);
}
if (pindexBestForkTip && pindexBestForkBase) {
LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__,
pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(),
pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString());
fLargeWorkForkFound = true;
} else {
LogPrintf("%s: Warning: Found invalid chain at least ~%d blocks longer than our best chain.\nChain state database corruption likely.\n", __func__, Params().GetCoinMaturity());
fLargeWorkInvalidChainFound = true;
}
} else {
fLargeWorkForkFound = false;
fLargeWorkInvalidChainFound = false;
}
}
void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
{
AssertLockHeld(cs_main);
// If we are on a fork that is sufficiently large, set a warning flag
CBlockIndex* pfork = pindexNewForkTip;
CBlockIndex* plonger = chainActive.Tip();
while (pfork && pfork != plonger) {
while (plonger && plonger->nHeight > pfork->nHeight)
plonger = plonger->pprev;
if (pfork == plonger)
break;
pfork = pfork->pprev;
}
// We define a condition which we should warn the user about as a fork of at least 7 blocks
// who's tip is within 72 blocks (+/- 3 hours if no one mines it) of ours
// or a chain that is entirely longer than ours and invalid (note that this should be detected by both)
// We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network
// hash rate operating on the fork.
// We define it this way because it allows us to only store the highest fork tip (+ base) which meets
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&
pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) &&
chainActive.Height() - pindexNewForkTip->nHeight < 72) {
pindexBestForkTip = pindexNewForkTip;
pindexBestForkBase = pfork;
}
CheckForkWarningConditions();
}
// Requires cs_main.
void Misbehaving(NodeId pnode, int howmuch, std::string reason)
{
if (howmuch == 0)
return;
CNodeState* state = State(pnode);
if (state == NULL)
return;
state->nMisbehavior += howmuch;
int banscore = GetArg("-banscore", 100);
LogPrintf("Misbehaving: %s (%d -> %d)\n", state->name, state->nMisbehavior - howmuch, state->nMisbehavior);
LogPrintf("Reason: %s", reason);
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) {
LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name, state->nMisbehavior - howmuch, state->nMisbehavior);
state->fShouldBan = true;
}
}
void static InvalidChainFound(CBlockIndex* pindexNew)
{
if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
pindexBestInvalid = pindexNew;
if (fDebug)
LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
log(pindexNew->nChainWork.getdouble()) / log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime()));
CBlockIndex* tip = chainActive.Tip();
assert(tip);
if (fDebug)
LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__,
tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble()) / log(2.0),
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime()));
CheckForkWarningConditions();
}
void static InvalidBlockFound(CBlockIndex* pindex, const CValidationState& state)
{
int nDoS = 0;
if (state.IsInvalid(nDoS)) {
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
if (it != mapBlockSource.end() && State(it->second)) {
CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
State(it->second)->rejects.push_back(reject);
if (nDoS > 0)
Misbehaving(it->second, nDoS, "Invalid block found");
}
}
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
}
}
void UpdateCoins(const CTransaction& tx, CValidationState& state, CCoinsViewCache& inputs, CTxUndo& txundo, int nHeight)
{
// mark inputs spent
if (!tx.IsCoinBase()) {
txundo.vprevout.reserve(tx.vin.size());
BOOST_FOREACH (const CTxIn& txin, tx.vin) {
CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash);
unsigned nPos = txin.prevout.n;
if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull())
assert(false);
// mark an outpoint spent, and construct undo information
txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos]));
bool ret = coins->Spend(txin.prevout, txundo.vprevout.back());
}
// add outputs
inputs.ModifyNewCoins(tx.GetHash())->FromTx(tx, nHeight);
} else {
// add outputs for coinbase tx
// In this case call the full ModifyCoins which will do a database
// lookup to be sure the coins do not already exist otherwise we do not
// know whether to mark them fresh or not. We want the duplicate coinbases
// before BIP30 to still be properly overwritten.
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
}
}
bool CScriptCheck::operator()()
{
const CScript& scriptSig = ptxTo->vin[nIn].scriptSig;
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) {
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
}
return true;
}
CBitcoinAddress addressExp1("DQZzqnSR6PXxagep1byLiRg9ZurCZ5KieQ");
CBitcoinAddress addressExp2("DTQYdnNqKuEHXyNeeYhPQGGGdqHbXYwjpj");
bool ValidOutPoint(const COutPoint out, int nHeight)
{
bool isInvalid = nHeight >= Params().HeightToFork() && invalid_out::ContainsOutPoint(out);
return !isInvalid;
}
CAmount GetInvalidUTXOValue()
{
CAmount nValue = 0;
for (auto out : invalid_out::setInvalidOutPoints) {
bool fSpent = false;
CCoinsViewCache cache(pcoinsTip);
const CCoins* coins = cache.AccessCoins(out.hash);
if (!coins || !coins->IsAvailable(out.n))
fSpent = true;
if (!fSpent)
nValue += coins->vout[out.n].nValue;
}
return nValue;
}
int GetSpendHeight(const CCoinsViewCache& inputs)
{
LOCK(cs_main);
CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
return pindexPrev->nHeight + 1;
}
bool CheckInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck>* pvChecks)
{
if (!tx.IsCoinBase()) {
if (pvChecks)
pvChecks->reserve(tx.vin.size());
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if (!inputs.HaveInputs(tx))
return state.Invalid(error("CheckInputs() : %s inputs unavailable", tx.GetHash().ToString()));
// While checking, GetBestBlock() refers to the parent block.
// This is also true for mempool checks.
int nSpendHeight = GetSpendHeight(inputs);
CAmount nValueIn = 0;
CAmount nFees = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint& prevout = tx.vin[i].prevout;
const CCoins* coins = inputs.AccessCoins(prevout.hash);
assert(coins);
// If prev is coinbase, check that it's matured
if (coins->IsCoinBase()) {
if (coins->IsCoinStake()) {
CTransaction txStake;
uint256 blockHash;
if (!GetTransaction(prevout.hash, txStake, blockHash, true))
return state.Invalid(
error("CheckInputs(): could not find tx %s", prevout.hash.ToString()),
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
if (txStake.IsLegacyCoinStake() && nSpendHeight - coins->nHeight < Params().GetCoinMaturity())
return state.Invalid(
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
}
if (nSpendHeight - coins->nHeight < Params().GetCoinMaturity())
return state.Invalid(
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
}
// Check transaction timestamp
if (coins->nTime > tx.nTime)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-time-earlier-than-input");
// Check for negative or overflow input values
nValueIn += coins->vout[prevout.n].nValue;
if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs() : txin values out of range"),
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
}
if (!tx.IsCoinStake()) {
if (nValueIn < tx.GetValueOut())
return state.DoS(100, error("CheckInputs() : %s value in (%s) < value out (%s)", tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())),
REJECT_INVALID, "bad-txns-in-belowout");
// Tally transaction fees
CAmount nTxFee = nValueIn - tx.GetValueOut();
if (nTxFee < 0)
return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()),
REJECT_INVALID, "bad-txns-fee-negative");
nFees += nTxFee;
if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs() : nFees out of range"),
REJECT_INVALID, "bad-txns-fee-outofrange");
}
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
// Helps prevent CPU exhaustion attacks.
// Skip ECDSA signature verification when connecting blocks
// before the last block chain checkpoint. This is safe because block merkle hashes are
// still computed and checked, and any change will be caught at the next checkpoint.
if (fScriptChecks) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint& prevout = tx.vin[i].prevout;
const CCoins* coins = inputs.AccessCoins(prevout.hash);
assert(coins);
// Verify signature
CScriptCheck check(*coins, tx, i, flags, cacheStore);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
} else if (!check()) {
if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) {
// Check whether the failure was caused by a
// non-mandatory script verification check, such as
// non-standard DER encodings or non-null dummy
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check2.GetScriptError())));
}
// Failures of other flags indicate a transaction that is
// invalid in new blocks, e.g. a invalid P2SH. We DoS ban
// such nodes as they are not following the protocol. That
// said during an upgrade careful thought should be taken
// as to the correct behavior - we may want to continue
// peering with non-upgraded nodes even after a soft-fork
// super-majority vote has passed.
return state.DoS(100, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
}
}
}
}
return true;
}
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
{
if (UseLegacyCode(block))
return DisconnectBlock_Legacy(block, state, pindex, view, pfClean);
if (pindex->GetBlockHash() != view.GetBestBlock() && fDebug)
LogPrintf("%s : pindex=%s view=%s\n", __func__, pindex->GetBlockHash().GetHex(), view.GetBestBlock().GetHex());
assert(pindex->GetBlockHash() == view.GetBestBlock());
if (pfClean)
*pfClean = false;
bool fClean = true;
CBlockUndo blockUndo;
CDiskBlockPos pos = pindex->GetUndoPos();
if (pos.IsNull())
return error("DisconnectBlock() : no undo data available");
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
return error("DisconnectBlock() : failure reading undo data");
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock() : block and undo data inconsistent");
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction& tx = block.vtx[i];
uint256 hash = tx.GetHash();
// Check that all outputs are available and match the outputs in the block itself
// exactly. Note that transactions with only provably unspendable outputs won't
// have outputs available even in the block itself, so we handle that case
// specially with outsEmpty.
{
CCoins outsEmpty;
CCoinsModifier outs = view.ModifyCoins(hash);
outs->ClearUnspendable();
CCoins outsBlock(tx, pindex->nHeight);
// The CCoins serialization does not serialize negative numbers.
// No network rules currently depend on the version here, so an inconsistency is harmless
// but it must be corrected before txout nversion ever influences a network rule.
if (outsBlock.nVersion < 0)
outs->nVersion = outsBlock.nVersion;
if (*outs != outsBlock)
fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted");
// remove outputs
outs->Clear();
}
// restore inputs
if (!tx.IsCoinBase()) {
const CTxUndo& txundo = blockUndo.vtxundo[i - 1];
if (txundo.vprevout.size() != tx.vin.size())
return error("DisconnectBlock() : transaction and undo data inconsistent - txundo.vprevout.siz=%d tx.vin.siz=%d", txundo.vprevout.size(), tx.vin.size());
for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint& out = tx.vin[j].prevout;
const CTxInUndo& undo = txundo.vprevout[j];
CCoinsModifier coins = view.ModifyCoins(out.hash);
if (undo.nHeight != 0) {
// undo data contains height: this is the last output of the prevout tx being spent
if (!coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing transaction");
coins->FromUndo(undo);
} else {
if (coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data adding output to missing transaction");
}
if (coins->IsAvailable(out.n))
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output");
if (coins->vout.size() < out.n + 1)
coins->vout.resize(out.n + 1);
coins->vout[out.n] = undo.txout;
}
}
}
// move best block pointer to prevout block
view.SetBestBlock(pindex->pprev->GetBlockHash());
if (pfClean) {
*pfClean = fClean;
return true;
} else {
return fClean;
}
}
/**
* Apply the undo operation of a CTxInUndo to the given chain state.
* @param undo The undo object.
* @param view The coins view to which to apply the changes.
* @param out The out point that corresponds to the tx input.
* @return True on success.
*/
static bool ApplyTxInUndo_Legacy(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
{
bool fClean = true;
CCoinsModifier coins = view.ModifyCoins(out.hash);
if (undo.nHeight != 0) {
// undo data contains height: this is the last output of the prevout tx being spent
if (!coins->IsPruned())
fClean = fClean && error("%s: undo data overwriting existing transaction", __func__);
coins->FromUndo(undo);
} else {
if (coins->IsPruned())
fClean = fClean && error("%s: undo data adding output to missing transaction", __func__);
}
if (coins->IsAvailable(out.n))
fClean = fClean && error("%s: undo data overwriting existing output", __func__);
if (coins->vout.size() < out.n + 1)
coins->vout.resize(out.n + 1);
coins->vout[out.n] = undo.txout;
return fClean;
}
bool UndoReadFromDisk_Legacy(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock)
{
// Open history file to read
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
return error("%s: OpenBlockFile failed", __func__);
// Read block
uint256 hashChecksum;
try {
filein >> blockundo;
filein >> hashChecksum;
} catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
// Verify checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << blockundo;
if (hashChecksum != hasher.GetHash())
return error("%s: Checksum mismatch", __func__);
return true;
}
bool DisconnectBlock_Legacy(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
{
assert(pindex->GetBlockHash() == view.GetBestBlock());
if (pfClean)
*pfClean = false;
bool fClean = true;
CBlockUndo blockUndo;
CDiskBlockPos pos = pindex->GetUndoPos();
if (pos.IsNull())
return error("DisconnectBlock(): no undo data available");
if (!UndoReadFromDisk_Legacy(blockUndo, pos, pindex->pprev->GetBlockHash()))
return error("DisconnectBlock(): failure reading undo data");
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock(): block and undo data inconsistent");
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction& tx = block.vtx[i];
uint256 hash = tx.GetHash();
if (hash.ToString() == "b5f5580e459252fd1bf6547b62daf70af8100fc0b835b524b30b95aa2f48f6d3")
cout << "here here";
if (fDebug)
LogPrintf("tx Hash %s pos=%d\n", hash.ToString().c_str(), i);
// Check that all outputs are available and match the outputs in the block itself
// exactly.
{
CCoinsModifier outs = view.ModifyCoins(hash);
outs->ClearUnspendable();
CCoins outsBlock(tx, pindex->nHeight);
// The CCoins serialization does not serialize negative numbers.
// No network rules currently depend on the version here, so an inconsistency is harmless
// but it must be corrected before txout nversion ever influences a network rule.
if (outsBlock.nVersion < 0)
outs->nVersion = outsBlock.nVersion;
if (*outs != outsBlock)
fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted");
// remove outputs
outs->Clear();
}
// restore inputs
if (i > 0) { // not coinbases
const CTxUndo& txundo = blockUndo.vtxundo[i - 1];
if (txundo.vprevout.size() != tx.vin.size())
return error("DisconnectBlock(): transaction and undo data inconsistent");
for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint& out = tx.vin[j].prevout;
const CTxInUndo& undo = txundo.vprevout[j];
if (!ApplyTxInUndo_Legacy(undo, view, out))
fClean = false;
}
}
}
// move best block pointer to prevout block
view.SetBestBlock(pindex->pprev->GetBlockHash());
if (pfClean) {
*pfClean = fClean;
return true;
}
return fClean;
}
void static FlushBlockFile(bool fFinalize = false)
{
LOCK(cs_LastBlockFile);
CDiskBlockPos posOld(nLastBlockFile, 0);
FILE* fileOld = OpenBlockFile(posOld);
if (fileOld) {
if (fFinalize)
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
if (fFinalize)
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
FileCommit(fileOld);
fclose(fileOld);
}
}
bool FindUndoPos(CValidationState& state, int nFile, CDiskBlockPos& pos, unsigned int nAddSize);
bool FindUndoPos_Legacy(CValidationState& state, int nFile, CDiskBlockPos& pos, unsigned int nAddSize);
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
void ThreadScriptCheck()
{
RenameThread("kore-scriptch");
scriptcheckqueue.Thread();
}
bool RecalculateKORESupply(int nHeightStart)
{
if (nHeightStart > chainActive.Height())
return false;
CBlockIndex* pindex = chainActive[nHeightStart];
CAmount nSupplyPrev = pindex->pprev->nMoneySupply;
while (true) {
if (pindex->nHeight % 1000 == 0 && fDebug) LogPrintf("%s : block %d...\n", __func__, pindex->nHeight);
CBlock block;
assert(ReadBlockFromDisk(block, pindex));
CAmount nValueIn = 0;
CAmount nValueOut = 0;
for (const CTransaction tx : block.vtx) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
if (tx.IsCoinBase())
break;
COutPoint prevout = tx.vin[i].prevout;
CTransaction txPrev;
uint256 hashBlock;
assert(GetTransaction(prevout.hash, txPrev, hashBlock, true));
nValueIn += txPrev.vout[prevout.n].nValue;
}
for (unsigned int i = 0; i < tx.vout.size(); i++) {
if (i == 0 && tx.IsCoinStake())
continue;
nValueOut += tx.vout[i].nValue;
}
}
// Rewrite money supply
pindex->nMoneySupply = nSupplyPrev + nValueOut - nValueIn;
nSupplyPrev = pindex->nMoneySupply;
assert(pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex)));
if (pindex->nHeight < chainActive.Height())
pindex = chainActive.Next(pindex);
else
break;
}
return true;
}
int32_t ComputeBlockVersion_Legacy(const CBlockIndex* pindexPrev)
{
LOCK(cs_main);
int32_t nVersion = VERSIONBITS_TOP_BITS;
for (int i = 0; i < (int)CChainParams::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
ThresholdState state = VersionBitsState(pindexPrev, (CChainParams::DeploymentPos)i, versionbitscache);
if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) {
nVersion |= VersionBitsMask((CChainParams::DeploymentPos)i);
}
}
return nVersion;
}
// This is a Legacy Class
/**
* Threshold condition checker that triggers when unknown versionbits are seen on the network.
*/
class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
{
private:
int bit;
public:
WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
int64_t BeginTime() const { return 0; }
int64_t EndTime() const { return std::numeric_limits<int64_t>::max(); }
int Period() const { return Params().GetMinerConfirmationWindow(); }
int Threshold() const { return Params().GetRuleChangeActivationThreshold(); }
bool Condition(const CBlockIndex* pindex) const
{
return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
((pindex->nVersion >> bit) & 1) != 0 &&
((ComputeBlockVersion_Legacy(pindex->pprev) >> bit) & 1) == 0;
}
};
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; // Legacy
static int64_t nTimeCheck = 0; // Legacy
static int64_t nTimeForks = 0; // Legacy
static int64_t nTimeVerify = 0;
static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 0;
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck, bool fAlreadyChecked)
{
if (UseLegacyCode(block))
return ConnectBlock_Legacy(block, state, pindex, view, fJustCheck);
AssertLockHeld(cs_main);
// Check it again in case a previous version let a bad block in
if (!fAlreadyChecked && !CheckBlock(block, state, !fJustCheck, !fJustCheck))
return false;
// verify that the view's current state corresponds to the previous block
uint256 hashPrevBlock = pindex->pprev == NULL ? uint256(0) : pindex->pprev->GetBlockHash();
if (hashPrevBlock != view.GetBestBlock() && fDebug)
LogPrintf("%s: hashPrev=%s view=%s\n", __func__, hashPrevBlock.ToString().c_str(), view.GetBestBlock().ToString().c_str());
assert(hashPrevBlock == view.GetBestBlock());
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
if (block.GetHash() == Params().HashGenesisBlock()) {
view.SetBestBlock(pindex->GetBlockHash());
return true;
}
if (pindex->nHeight > Params().GetLastPoWBlock() && block.IsProofOfWork())
return state.DoS(100, error("ConnectBlock() : PoW period ended"),
REJECT_INVALID, "PoW-ended");
bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate();
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
// If such overwrites are allowed, coinbases and transactions depending upon those
// can be duplicated to remove the ability to spend the first instance -- even after
// being sent to another address.
// See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information.
// This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
// already refuses previously-known transaction ids entirely.
// This rule was originally applied all blocks whose timestamp was after March 15, 2012, 0:00 UTC.
// Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the
// two in the chain that violate it. This prevents exploiting the issue against nodes in their
// initial block download.
bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash.
!((pindex->nHeight == 91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight == 91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
BOOST_FOREACH (const CTransaction& tx, block.vtx) {
const CCoins* coins = view.AccessCoins(tx.GetHash());
if (coins && !coins->IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
}
}
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
int64_t nTimeStart = GetTimeMicros();
CAmount nFees = 0;
int nInputs = 0;
unsigned int nSigOps = 0;
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
CBlockUndo blockundo;
blockundo.vtxundo.reserve(block.vtx.size() - 1);
CAmount nValueOut = 0;
CAmount nValueIn = 0;
unsigned int nMaxBlockSigOps = MAX_BLOCK_SIGOPS_CURRENT;
vector<uint256> vSpendsInBlock;
uint256 hashBlock = block.GetHash();
for (unsigned int i = 0; i < block.vtx.size(); i++) {
const CTransaction& tx = block.vtx[i];
nInputs += tx.vin.size();
nSigOps += GetLegacySigOpCount(tx);
if (nSigOps > nMaxBlockSigOps)
return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops");
if (!tx.IsCoinBase()) {
if (!view.HaveInputs(tx))
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
REJECT_INVALID, "bad-txns-inputs-missingorspent");
// Check that the inputs are not marked as invalid/fraudulent
for (CTxIn in : tx.vin) {
if (!ValidOutPoint(in.prevout, pindex->nHeight)) {
return state.DoS(100, error("ConnectBlock(): tried to spend invalid input %s in tx %s", in.prevout.ToString(), tx.GetHash().GetHex()),
REJECT_INVALID, "bad-txns-invalid-inputs");
}
}
// Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block.
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > nMaxBlockSigOps)
return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops");
if (!tx.IsCoinStake())
nFees += view.GetValueIn(tx) - tx.GetValueOut();
nValueIn += view.GetValueIn(tx);
std::vector<CScriptCheck> vChecks;
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG;
if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
nValueOut += tx.GetValueOut();
CTxUndo undoDummy;
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
}
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
// track money supply and mint amount info
CAmount nMoneySupplyPrev = pindex->pprev ? pindex->pprev->nMoneySupply : 0;
pindex->nMoneySupply = nMoneySupplyPrev + nValueOut - nValueIn;
pindex->nMint = pindex->nMoneySupply - nMoneySupplyPrev + nFees;
int64_t nTime1 = GetTimeMicros();
nTimeConnect += nTime1 - nTimeStart;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n",
(unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(),
nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs - 1), nTimeConnect * 0.000001);
//PoW phase redistributed fees to miner. PoS stage destroys fees.
CAmount nExpectedMint = GetBlockReward(pindex->pprev) + nFees;
//Check that the block does not overmint
if (nExpectedMint != pindex->nMint) {
return state.DoS(100, error("ConnectBlock(): reward pays too much (actual=%s vs limit=%s)", FormatMoney(pindex->nMint), FormatMoney(nExpectedMint)),
REJECT_INVALID, "bad-cb-amount");
}
if (!control.Wait())
return state.DoS(100, false);
int64_t nTime2 = GetTimeMicros();
nTimeVerify += nTime2 - nTimeStart;
LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime2 - nTimeStart),
nInputs <= 1 ? 0 : 0.001 * (nTime2 - nTimeStart) / (nInputs - 1), nTimeVerify * 0.000001);
//IMPORTANT NOTE: Nothing before this point should actually store to disk (or even memory)
if (fJustCheck)
return true;
// Write undo information to disk
if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
if (pindex->GetUndoPos().IsNull()) {
CDiskBlockPos pos;
if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock(): FindUndoPos failed");
if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash()))
return state.Abort("Failed to write undo data");
// update nUndoPos in block index
pindex->nUndoPos = pos.nPos;
pindex->nStatus |= BLOCK_HAVE_UNDO;
}
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
setDirtyBlockIndex.insert(pindex);
}
if (fTxIndex && !pblocktree->WriteTxIndex(vPos))
return state.Abort("Failed to write transaction index");
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime3 = GetTimeMicros();
nTimeIndex += nTime3 - nTime2;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001);
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = block.vtx[0].GetHash();
int64_t nTime4 = GetTimeMicros();
nTimeCallbacks += nTime4 - nTime3;
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001);
return true;
}
// Index either: a) every data push >=8 bytes, b) if no such pushes, the entire script
void static BuildAddrIndex_Legacy(const CScript& script, const CExtDiskTxPos& pos, std::vector<std::pair<uint160, CExtDiskTxPos> >& out)
{
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
std::vector<unsigned char> data;
opcodetype opcode;
bool fHaveData = false;
while (pc < pend) {
script.GetOp(pc, opcode, data);
if (0 <= opcode && opcode <= OP_PUSHDATA4 && data.size() >= 8) { // data element
uint160 addrid;
if (data.size() <= 20) {
memcpy(&addrid, &data[0], data.size());
} else {
addrid = Hash160(data);
}
out.push_back(std::make_pair(addrid, pos));
fHaveData = true;
}
}
if (!fHaveData) {
uint160 addrid = Hash160(script);
out.push_back(std::make_pair(addrid, pos));
}
}
bool UndoWriteToDisk_Legacy(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("%s: OpenUndoFile failed", __func__);
// Write index header
unsigned int nSize = fileout.GetSerializeSize(blockundo);
fileout << FLATDATA(messageStart) << nSize;
// Write undo data
long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0)
return error("%s: ftell failed", __func__);
pos.nPos = (unsigned int)fileOutPos;
fileout << blockundo;
// calculate & write checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << blockundo;
fileout << hasher.GetHash();
return true;
}
bool ConnectBlock_Legacy(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
{
const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
int64_t nTimeStart = GetTimeMicros();
CTxUndo undoDummy;
CBlockUndo blockundo;
if (pindex->nHeight > Params().GetLastPoWBlock() && block.IsProofOfWork())
return state.DoS(100, error("ConnectBlock() : PoW period ended"),
REJECT_INVALID, "PoW-ended");
// Check it again in case a previous version let a bad block in
if (!CheckBlock_Legacy(block, state, !fJustCheck, !fJustCheck))
return false;
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
if (block.GetHash() == Params().HashGenesisBlock()) {
if (!fJustCheck)
view.SetBestBlock(pindex->GetBlockHash());
return true;
}
// verify that the view's current state corresponds to the previous block
uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash();
if (fDebug)
LogPrintf("ConnectBlock_Legacy block height: %d hashPrevBlock: %s", pindex->nHeight, hashPrevBlock.ToString());
assert(hashPrevBlock == view.GetBestBlock());
// Check proof-of-stake
if (block.IsProofOfStake()) {
const COutPoint& prevout = block.vtx[1].vin[0].prevout;
const CCoins* coins = view.AccessCoins(prevout.hash);
if (!coins)
return state.DoS(100, error("%s: kernel input unavailable", __func__), REJECT_INVALID, "bad-cs-kernel");
if (fDebug) {
LogPrintf("ConnectBlock_Legacy - Coin found hash: %s \n", prevout.hash.ToString());
LogPrintf(" %s \n", coins->ToString());
}
// Check proof-of-stake min confirmations
if (pindex->nHeight - coins->nHeight < Params().GetCoinMaturity())
return state.DoS(100, error("%s: tried to stake at depth %d", __func__, pindex->nHeight - coins->nHeight), REJECT_INVALID, "bad-cs-premature");
if (coins->nTime + 4 * 60 * 60 > block.vtx[1].nTime) // Min age requirement
return error("CheckProofOfStake_Legacy() : min age violation - nTimeBlockFrom=%d nStakeMinAge=%d nTimeTx=%d \n", coins->nTime, 4 * 60 * 60, block.vtx[1].nTime);
if (!CheckStakeKernelHash_Legacy(pindex->pprev, block.nBits, coins, prevout, block.vtx[1].nTime))
return state.DoS(100, error("%s: proof-of-stake hash doesn't match nBits", __func__), REJECT_INVALID, "bad-cs-proofhash");
}
bool fScriptChecks = true;
if (Checkpoints::fEnabled) {
CBlockIndex* pindexLastCheckpoint = Checkpoints::GetLastCheckpoint();
if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) {
// This block is an ancestor of a checkpoint: disable script checks
fScriptChecks = false;
}
}
int64_t nTime1 = GetTimeMicros();
nTimeCheck += nTime1 - nTimeStart;
LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001);
BOOST_FOREACH (const CTransaction& tx, block.vtx) {
const CCoins* coins = view.AccessCoins(tx.GetHash());
if (coins && !coins->IsPruned())
return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "bad-txns-BIP30");
}
bool fStrictPayToScriptHash = true;
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | SCRIPT_VERIFY_NULLDUMMY | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
int nLockTimeFlags = LOCKTIME_VERIFY_SEQUENCE;
int64_t nTime2 = GetTimeMicros();
nTimeForks += nTime2 - nTime1;
LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
std::vector<int> prevheights;
CAmount nFees = 0;
CAmount nActualStakeReward = 0;
int nInputs = 0;
unsigned int nSigOps = 0;
CExtDiskTxPos pos(CDiskTxPos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())), pindex->nHeight);
std::vector<std::pair<uint256, CDiskTxPos> > vPosTxid;
std::vector<std::pair<uint160, CExtDiskTxPos> > vPosAddrid;
if (fTxIndex)
vPosTxid.reserve(block.vtx.size());
if (fAddrIndex)
vPosAddrid.reserve(4 * block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
for (unsigned int i = 0; i < block.vtx.size(); i++) {
const CTransaction& tx = block.vtx[i];
nInputs += tx.vin.size();
nSigOps += GetLegacySigOpCount(tx);
if (nSigOps > MAX_BLOCK_SIGOPS_LEGACY)
return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops");
if (!tx.IsCoinBase()) {
if (!view.HaveInputs(tx))
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), REJECT_INVALID, "bad-txns-inputs-missingorspent");
// Check that transaction is BIP68 final
// BIP68 lock checks (as opposed to nLockTime checks) must
// be in ConnectBlock because they require the UTXO set
prevheights.resize(tx.vin.size());
for (size_t j = 0; j < tx.vin.size(); j++) {
prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight;
}
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal");
}
if (fStrictPayToScriptHash) {
// Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block.
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_BLOCK_SIGOPS_LEGACY)
return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops");
}
if (tx.IsCoinStake())
nActualStakeReward = tx.GetValueOut() - view.GetValueIn(tx);
else {
nFees += view.GetValueIn(tx) - tx.GetValueOut();
}
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; // Don't cache results if we're actually connecting blocks (still consult the cache, though)
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL))
return error("ConnectBlock(): CheckInputs on %s failed with %s", tx.GetHash().ToString(), FormatStateMessage_Legacy(state));
control.Add(vChecks);
}
if (fTxIndex)
vPosTxid.push_back(std::make_pair(tx.GetHash(), pos));
if (fAddrIndex) {
if (!tx.IsCoinBase()) {
BOOST_FOREACH (const CTxIn& txin, tx.vin) {
CCoins coins;
view.GetCoins(txin.prevout.hash, coins);
BuildAddrIndex_Legacy(coins.vout[txin.prevout.n].scriptPubKey, pos, vPosAddrid);
}
}
BOOST_FOREACH (const CTxOut& txout, tx.vout)
BuildAddrIndex_Legacy(txout.scriptPubKey, pos, vPosAddrid);
}
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
}
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime3 = GetTimeMicros();
nTimeConnect += nTime3 - nTime2;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs - 1), nTimeConnect * 0.000001);
CAmount blockReward = nFees + GetBlockValue(pindex->nHeight);
if (block.vtx[0].GetValueOut() > blockReward && pindex->nHeight > 1)
return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount");
if (block.IsProofOfStake()) {
CAmount nValueIns = 0;
CTransaction tx2;
uint256 hash;
BOOST_FOREACH (const CTxIn& txin, block.vtx[1].vin) {
if (GetTransaction(txin.prevout.hash, tx2, hash, true))
if (tx2.vout.size() > txin.prevout.n)
nValueIns += tx2.vout[txin.prevout.n].nValue;
}
CAmount blockReward = nFees + GetProofOfStakeSubsidy_Legacy(pindex->nHeight, nValueIns);
if (nActualStakeReward > blockReward)
return state.DoS(100, error("ConnectBlock(): coinstake pays too much (actual=%d vs limit=%d)", nActualStakeReward, blockReward), REJECT_INVALID, "bad-cs-amount");
}
CAmount reward = block.IsProofOfStake() ? nActualStakeReward : block.vtx[0].GetValueOut();
if (block.IsProofOfStake()) {
pindex->SetProofOfStake();
pindex->SetProofOfStake_Legacy();
}
pindex->nMoneySupply = (pindex->pprev ? pindex->pprev->nMoneySupply : 0) + reward;
if (!fJustCheck)
pindex->nStakeModifierOld = ComputeStakeModifier_Legacy(pindex->pprev, block.IsProofOfStake() ? block.vtx[1].vin[0].prevout.hash : pindex->GetBlockHash());
if (fJustCheck)
return true;
if (!control.Wait())
return state.DoS(100, false);
int64_t nTime4 = GetTimeMicros();
nTimeVerify += nTime4 - nTime2;
LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs - 1), nTimeVerify * 0.000001);
// Write undo information to disk
if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
if (pindex->GetUndoPos().IsNull()) {
CDiskBlockPos pos;
if (!FindUndoPos_Legacy(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock(): FindUndoPos failed");
if (!UndoWriteToDisk_Legacy(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
return AbortNode(state, "Failed to write undo data");
// update nUndoPos in block index
pindex->nUndoPos = pos.nPos;
pindex->nStatus |= BLOCK_HAVE_UNDO;
}
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
setDirtyBlockIndex.insert(pindex);
}
if (fTxIndex)
if (!pblocktree->WriteTxIndex(vPosTxid))
return AbortNode(state, "Failed to write transaction index");
if (fAddrIndex)
if (!pblocktree->AddAddrIndex(vPosAddrid))
return AbortNode(state, "Failed to write address index");
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime5 = GetTimeMicros();
nTimeIndex += nTime5 - nTime4;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = block.vtx[0].GetHash();
int64_t nTime6 = GetTimeMicros();
nTimeCallbacks += nTime6 - nTime5;
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);
return true;
}
enum FlushStateMode {
FLUSH_STATE_NONE, // legacy
FLUSH_STATE_IF_NEEDED,
FLUSH_STATE_PERIODIC,
FLUSH_STATE_ALWAYS
};
/**
* Update the on-disk chain state.
* The caches and indexes are flushed depending on the mode we're called with
* if they're too large, if it's been a while since the last write,
* or always and in all cases if we're in prune mode and are deleting files.
*/
bool static FlushStateToDisk(CValidationState& state, FlushStateMode mode)
{
const CChainParams& chainparams = Params();
LOCK2(cs_main, cs_LastBlockFile);
static int64_t nLastWrite = 0;
static int64_t nLastFlush = 0;
static int64_t nLastSetChain = 0;
std::set<int> setFilesToPrune;
bool fFlushForPrune = false;
try {
if (fPruneMode && fCheckForPruning && !fReindex) {
FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight());
fCheckForPruning = false;
if (!setFilesToPrune.empty()) {
fFlushForPrune = true;
if (!fHavePruned) {
pblocktree->WriteFlag("prunedblockfiles", true);
fHavePruned = true;
}
}
}
int64_t nNow = GetTimeMicros();
// Avoid writing/flushing immediately after startup.
if (nLastWrite == 0) {
nLastWrite = nNow;
}
if (nLastFlush == 0) {
nLastFlush = nNow;
}
if (nLastSetChain == 0) {
nLastSetChain = nNow;
}
size_t cacheSize = pcoinsTip->DynamicMemoryUsage();
// The cache is large and close to the limit, but we have time now (not in the middle of a block processing).
bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0 / 9) > nCoinCacheUsage;
// The cache is over the limit, we have to write now.
bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage;
// It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash.
bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000;
// It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000;
// Combine all conditions that result in a full cache flush.
bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
// Write blocks and block index to disk.
if (fDoFullFlush || fPeriodicWrite) {
// Depend on nMinDiskSpace to ensure we can write block index
if (!CheckDiskSpace(0))
return state.Error("out of disk space");
// First make sure all block and undo data is flushed to disk.
FlushBlockFile();
// Then update all block file information (which may refer to block and undo files).
{
std::vector<std::pair<int, const CBlockFileInfo*> > vFiles;
vFiles.reserve(setDirtyFileInfo.size());
for (set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end();) {
vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it]));
setDirtyFileInfo.erase(it++);
}
std::vector<const CBlockIndex*> vBlocks;
vBlocks.reserve(setDirtyBlockIndex.size());
for (set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end();) {
vBlocks.push_back(*it);
setDirtyBlockIndex.erase(it++);
}
if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) {
return AbortNode(state, "Files to write to block index database");
}
}
// Finally remove any pruned files
if (fFlushForPrune)
UnlinkPrunedFiles(setFilesToPrune);
nLastWrite = nNow;
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
if (fDoFullFlush) {
// Typical CCoins structures on disk are around 128 bytes in size.
// Pushing a new one to the database can cause it to be written
// twice (once in the log, and once in the tables). This is already
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize()))
return state.Error("out of disk space");
// Flush the chainstate (which may refer to block index entries).
if (!pcoinsTip->Flush())
return AbortNode(state, "Failed to write to coin database");
nLastFlush = nNow;
}
if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
// Update best block in wallet (so we can detect restored wallets).
GetMainSignals().SetBestChain(chainActive.GetLocator());
nLastSetChain = nNow;
}
} catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error while flushing: ") + e.what());
}
return true;
}
void FlushStateToDisk()
{
CValidationState state;
FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
}
/**
* BLOCK PRUNING CODE
*/
/* Calculate the amount of disk space the block & undo files currently use */
uint64_t CalculateCurrentUsage_Legacy()
{
uint64_t retval = 0;
BOOST_FOREACH (const CBlockFileInfo& file, vinfoBlockFile) {
retval += file.nSize + file.nUndoSize;
}
return retval;
}
/* Prune a block file (modify associated database entries)*/
void PruneOneBlockFile_Legacy(const int fileNumber)
{
for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) {
CBlockIndex* pindex = it->second;
if (pindex->nFile == fileNumber) {
pindex->nStatus &= ~BLOCK_HAVE_DATA;
pindex->nStatus &= ~BLOCK_HAVE_UNDO;
pindex->nFile = 0;
pindex->nDataPos = 0;
pindex->nUndoPos = 0;
setDirtyBlockIndex.insert(pindex);
// Prune from mapBlocksUnlinked -- any block we prune would have
// to be downloaded again in order to consider its chain, at which
// point it would be considered as a candidate for
// mapBlocksUnlinked or setBlockIndexCandidates.
std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev);
while (range.first != range.second) {
std::multimap<CBlockIndex*, CBlockIndex*>::iterator it = range.first;
range.first++;
if (it->second == pindex) {
mapBlocksUnlinked.erase(it);
}
}
}
}
vinfoBlockFile[fileNumber].SetNull();
setDirtyFileInfo.insert(fileNumber);
}
void UnlinkPrunedFiles(std::set<int>& setFilesToPrune)
{
for (set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
CDiskBlockPos pos(*it, 0);
boost::filesystem::remove(GetBlockPosFilename(pos, "blk"));
boost::filesystem::remove(GetBlockPosFilename(pos, "rev"));
if (fDebug)
LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
}
}
/* Calculate the block/rev files that should be deleted to remain under target*/
void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight)
{
LOCK2(cs_main, cs_LastBlockFile);
if (chainActive.Tip() == NULL || nPruneTarget == 0) {
return;
}
if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) {
return;
}
unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP;
uint64_t nCurrentUsage = CalculateCurrentUsage_Legacy();
// We don't check to prune until after we've allocated new space for files
// So we should leave a buffer under our target to account for another allocation
// before the next pruning.
uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE;
uint64_t nBytesToPrune;
int count = 0;
if (nCurrentUsage + nBuffer >= nPruneTarget) {
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {
nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize;
if (vinfoBlockFile[fileNumber].nSize == 0)
continue;
if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target?
break;
// don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
continue;
PruneOneBlockFile_Legacy(fileNumber);
// Queue up the files for removal
setFilesToPrune.insert(fileNumber);
nCurrentUsage -= nBytesToPrune;
count++;
}
}
LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n",
nPruneTarget / 1024 / 1024, nCurrentUsage / 1024 / 1024,
((int64_t)nPruneTarget - (int64_t)nCurrentUsage) / 1024 / 1024,
nLastBlockWeCanPrune, count);
}
void PruneAndFlush()
{
CValidationState state;
fCheckForPruning = true;
FlushStateToDisk(state, FLUSH_STATE_NONE);
}
bool UseLegacyCode(const CBlockHeader& block)
{
return (block.nVersion & ~CBlockHeader::SIGNALING_NEW_VERSION_MASK) <= (CBlockHeader::CURRENT_VERSION & ~CBlockHeader::SIGNALING_NEW_VERSION_MASK);
}
bool UseLegacyCode(int nHeight)
{
return nHeight < Params().HeightToFork();
}
bool UseLegacyCode()
{
return chainActive.Tip()->nHeight < Params().HeightToFork();
}
/** Update chainActive and related internal data structures. */
void static UpdateTip(CBlockIndex* pindexNew)
{
const CChainParams& chainParams = Params();
chainActive.SetTip(pindexNew);
// New best block
nChainHeight = pindexNew->nHeight;
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
if (fDebug)
LogPrintf("%s:\n", __func__);
LogPrintf("New Best Block: %s\n", chainActive.Tip()->GetBlockHash().ToString());
LogPrintf("Height: %d\n", chainActive.Height());
LogPrintf("log2_work: %.8g\n", log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0));
LogPrintf("tx: %lu\n", (unsigned long)chainActive.Tip()->nChainTx);
LogPrintf("date: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()));
LogPrintf("progress: %f\n", Checkpoints::GuessVerificationProgress(Params().GetTxData(), chainActive.Tip()));
LogPrintf("cache: %.1fMiB(%utx)\n", pcoinsTip->DynamicMemoryUsage() * (1.0 / (1 << 20)), pcoinsTip->GetCacheSize());
cvBlockChange.notify_all();
// Check the version of the last 100 blocks to see if we need to upgrade:
static bool fWarned = false;
if (!IsInitialBlockDownload()) {
int nUpgraded = 0;
const CBlockIndex* pindex = chainActive.Tip();
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
ThresholdState state = checker.GetStateFor(pindex, warningcache[bit]);
if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) {
if (state == THRESHOLD_ACTIVE) {
strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
if (!fWarned) {
CAlert::Notify(strMiscWarning, true);
fWarned = true;
}
}
else
LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit);
}
}
}
}
/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
bool static DisconnectTip(CValidationState& state, bool isLoadingTx = false)
{
CBlockIndex* pindexDelete = chainActive.Tip();
assert(pindexDelete);
// Read block from disk.
CBlock block;
if (!ReadBlockFromDisk(block, pindexDelete))
return AbortNode(state, "Failed to read block");
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
CCoinsViewCache view(pcoinsTip);
if (!DisconnectBlock(block, state, pindexDelete, view))
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
assert(view.Flush());
}
LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
// Write the chain state to disk, if necessary.