// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
map<uint256, CDataStream*> mapOrphanTransactions;
multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
+// Constant stuff for coinbase transactions we create:
+CScript COINBASE_FLAGS;
+
+const string strMessageMagic = "Bitcoin Signed Message:\n";
+
double dHashesPerSec;
int64 nHPSTimerStart;
// expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
//
-bool CTransaction::AreInputsStandard(const std::map<uint256, std::pair<CTxIndex, CTransaction> >& mapInputs) const
+bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
{
- if (fTestNet)
- return true; // Allow non-standard on testnet
+ if (IsCoinBase())
+ return true; // Coinbases don't use vin normally
for (int i = 0; i < vin.size(); i++)
{
- COutPoint prevout = vin[i].prevout;
-
- std::map<uint256, std::pair<CTxIndex, CTransaction> >::const_iterator mi = mapInputs.find(prevout.hash);
- if (mi == mapInputs.end())
- return false;
-
- const CTransaction& txPrev = (mi->second).second;
- assert(prevout.n < txPrev.vout.size());
+ const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
- const CScript& prevScript = txPrev.vout[prevout.n].scriptPubKey;
+ const CScript& prevScript = prev.scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions))
return false;
+ int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
+
+ // 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 the
+ // IsStandard() call returns false
+ vector<vector<unsigned char> > stack;
+ if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
+ return false;
+
if (whichType == TX_SCRIPTHASH)
{
- vector<vector<unsigned char> > stack;
-
- if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
- return false;
if (stack.empty())
return false;
CScript subscript(stack.back().begin(), stack.back().end());
- if (!::IsStandard(subscript))
+ vector<vector<unsigned char> > vSolutions2;
+ txnouttype whichType2;
+ if (!Solver(subscript, whichType2, vSolutions2))
return false;
+ if (whichType2 == TX_SCRIPTHASH)
+ return false;
+ nArgsExpected += ScriptSigArgsExpected(whichType2, vSolutions2);
}
+
+ if (stack.size() != nArgsExpected)
+ return false;
}
return true;
if (fCheckInputs)
{
- map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
+ MapPrevTx mapInputs;
map<uint256, CTxIndex> mapUnused;
- if (!FetchInputs(txdb, mapUnused, false, false, mapInputs))
+ bool fInvalid = false;
+ if (!FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
{
+ if (fInvalid)
+ return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
if (pfMissingInputs)
*pfMissingInputs = true;
return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
}
// Check for non-standard pay-to-script-hash in inputs
- if (!AreInputsStandard(mapInputs))
+ if (!AreInputsStandard(mapInputs) && !fTestNet)
return error("AcceptToMemoryPool() : nonstandard transaction input");
- // Check against previous transactions
- int64 nFees = 0;
- int nSigOps = 0;
- if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false, nSigOps))
- {
- if (pfMissingInputs)
- *pfMissingInputs = true;
- return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
- }
+ // Note: if you modify this code to accept non-standard transactions, then
+ // you should add code here to check that the transaction does a
+ // reasonable number of ECDSA signature verifications.
- // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
- // attacks disallow transactions with more than one SigOp per 65 bytes.
- // 65 bytes because that is the minimum size of an ECDSA signature
+ int64 nFees = GetValueIn(mapInputs)-GetValueOut();
unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
- if (nSigOps > nSize / 65 || nSize < 100)
- return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
// Don't accept it if it can't get into a block
if (nFees < GetMinFee(1000, true, GMF_RELAY))
dFreeCount += nSize;
}
}
+
+ // Check against previous transactions
+ // This is done last to help prevent CPU exhaustion denial-of-service attacks.
+ if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
+ {
+ return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
+ }
}
// Store transaction in memory
//
unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
{
+ // Testnet has min-difficulty blocks
+ // after nTargetSpacing*2 time between blocks:
+ if (fTestNet && nTime > nTargetSpacing*2)
+ return bnProofOfWorkLimit.GetCompact();
+
CBigNum bnResult;
bnResult.SetCompact(nBase);
while (nTime > 0 && bnResult < bnProofOfWorkLimit)
return bnResult.GetCompact();
}
-unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
+unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock)
{
+ unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact();
// Genesis block
if (pindexLast == NULL)
- return bnProofOfWorkLimit.GetCompact();
+ return nProofOfWorkLimit;
// Only change once per interval
if ((pindexLast->nHeight+1) % nInterval != 0)
+ {
+ // Special rules for testnet after 15 Feb 2012:
+ if (fTestNet && pblock->nTime > 1329264000)
+ {
+ // If the new block's timestamp is more than 2* 10 minutes
+ // then allow mining of a min-difficulty block.
+ if (pblock->nTime - pindexLast->nTime > nTargetSpacing*2)
+ return nProofOfWorkLimit;
+ else
+ {
+ // Return the last non-special-min-difficulty-rules-block
+ const CBlockIndex* pindex = pindexLast;
+ while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit)
+ pindex = pindex->pprev;
+ return pindex->nBits;
+ }
+ }
+
return pindexLast->nBits;
+ }
// Go back by what we want to be 14 days worth of blocks
const CBlockIndex* pindexFirst = pindexLast;
bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
- bool fBlock, bool fMiner, map<uint256, pair<CTxIndex, CTransaction> >& inputsRet)
+ bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid)
{
+ // FetchInputs can return false either because we just haven't seen some inputs
+ // (in which case the transaction should be stored as an orphan)
+ // or because the transaction is malformed (in which case the transaction should
+ // be dropped). If tx is definitely invalid, fInvalid will be set to true.
+ fInvalid = false;
+
if (IsCoinBase())
return true; // Coinbase transactions have no inputs to fetch.
for (int i = 0; i < vin.size(); i++)
{
const COutPoint prevout = vin[i].prevout;
+ assert(inputsRet.count(prevout.hash) != 0);
const CTxIndex& txindex = inputsRet[prevout.hash].first;
const CTransaction& txPrev = inputsRet[prevout.hash].second;
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
+ {
+ // Revisit this if/when transaction replacement is implemented and allows
+ // adding inputs:
+ fInvalid = true;
return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
+ }
}
return true;
}
-bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inputs,
+const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const
+{
+ MapPrevTx::const_iterator mi = inputs.find(input.prevout.hash);
+ if (mi == inputs.end())
+ throw std::runtime_error("CTransaction::GetOutputFor() : prevout.hash not found");
+
+ const CTransaction& txPrev = (mi->second).second;
+ if (input.prevout.n >= txPrev.vout.size())
+ throw std::runtime_error("CTransaction::GetOutputFor() : prevout.n out of range");
+
+ return txPrev.vout[input.prevout.n];
+}
+
+int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
+{
+ if (IsCoinBase())
+ return 0;
+
+ int64 nResult = 0;
+ for (int i = 0; i < vin.size(); i++)
+ {
+ nResult += GetOutputFor(vin[i], inputs).nValue;
+ }
+ return nResult;
+
+}
+
+int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
+{
+ if (IsCoinBase())
+ return 0;
+
+ int nSigOps = 0;
+ for (int i = 0; i < vin.size(); i++)
+ {
+ const CTxOut& prevout = GetOutputFor(vin[i], inputs);
+ if (prevout.scriptPubKey.IsPayToScriptHash())
+ nSigOps += prevout.scriptPubKey.GetSigOpCount(vin[i].scriptSig);
+ }
+ return nSigOps;
+}
+
+bool CTransaction::ConnectInputs(MapPrevTx inputs,
map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
- const CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64 nMinFee)
+ const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash)
{
// Take over previous transactions' spent pointers
// fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
if (!IsCoinBase())
{
int64 nValueIn = 0;
+ int64 nFees = 0;
for (int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
- bool fStrictPayToScriptHash = true;
- if (fBlock)
- {
- // To avoid being on the short end of a block-chain split,
- // don't do secondary validation of pay-to-script-hash transactions
- // until blocks with timestamps after paytoscripthashtime:
- int64 nEvalSwitchTime = GetArg("paytoscripthashtime", 1329264000); // Feb 15, 2012
- fStrictPayToScriptHash = (pindexBlock->nTime >= nEvalSwitchTime);
- }
- // if !fBlock, then always be strict-- don't accept
- // invalid-under-new-rules pay-to-script-hash transactions into
- // our memory pool (don't relay them, don't include them
- // in blocks we mine).
-
- // Skip ECDSA signature verification when connecting blocks (fBlock=true)
- // before the last blockchain checkpoint. This is safe because block merkle hashes are
- // still computed and checked, and any change will be caught at the next checkpoint.
- if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
- {
- // Verify signature
- if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0))
- return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
- }
-
// Check for conflicts (double-spend)
// 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 (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return DoS(100, error("ConnectInputs() : txin values out of range"));
- // Calculate sigOps accurately:
- nSigOpsRet += txPrev.vout[prevout.n].scriptPubKey.GetSigOpCount(vin[i].scriptSig);
+ // Skip ECDSA signature verification when connecting blocks (fBlock=true)
+ // before the last blockchain checkpoint. This is safe because block merkle hashes are
+ // still computed and checked, and any change will be caught at the next checkpoint.
+ if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
+ {
+ // Verify signature
+ if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0))
+ return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
+ }
// Mark outpoints as spent
txindex.vSpent[prevout.n] = posThisTx;
int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
- if (nTxFee < nMinFee)
- return false;
nFees += nTxFee;
if (!MoneyRange(nFees))
return DoS(100, error("ConnectInputs() : nFees out of range"));
}
- if (fBlock)
- {
- // Add transaction to changes
- mapTestPool[GetHash()] = CTxIndex(posThisTx, vout.size());
- }
- else if (fMiner)
- {
- // Add transaction to test pool
- mapTestPool[GetHash()] = CTxIndex(CDiskTxPos(1,1,1), vout.size());
- }
-
return true;
}
if (!CheckBlock())
return false;
+ // To avoid being on the short end of a block-chain split,
+ // don't do secondary validation of pay-to-script-hash transactions
+ // until blocks with timestamps after paytoscripthashtime (see init.cpp for default).
+ // This code can be removed once a super-majority of the network has upgraded.
+ int64 nEvalSwitchTime = GetArg("-paytoscripthashtime", std::numeric_limits<int64_t>::max());
+ bool fStrictPayToScriptHash = (pindex->nTime >= nEvalSwitchTime);
+
//// issue here: it doesn't know the version
unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
int nSigOps = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
{
+ nSigOps += tx.GetLegacySigOpCount();
+ if (nSigOps > MAX_BLOCK_SIGOPS)
+ return DoS(100, error("ConnectBlock() : too many sigops"));
+
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
nTxPos += ::GetSerializeSize(tx, SER_DISK);
- map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
- if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs))
- return false;
+ MapPrevTx mapInputs;
+ if (!tx.IsCoinBase())
+ {
+ bool fInvalid;
+ if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid))
+ return false;
- int nTxOps = 0;
- if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, nFees, true, false, nTxOps))
- return false;
+ 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 += tx.GetP2SHSigOpCount(mapInputs);
+ if (nSigOps > MAX_BLOCK_SIGOPS)
+ return DoS(100, error("ConnectBlock() : too many sigops"));
+ }
- nSigOps += nTxOps;
- if (nSigOps > MAX_BLOCK_SIGOPS)
- return DoS(100, error("ConnectBlock() : too many sigops"));
- // There is a different MAX_BLOCK_SIGOPS check in AcceptBlock();
- // a block must satisfy both to make it into the best-chain
- // (AcceptBlock() is always called before ConnectBlock())
+ nFees += tx.GetValueIn(mapInputs)-tx.GetValueOut();
+
+ if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fStrictPayToScriptHash))
+ return false;
+ }
+
+ mapQueuedChanges[tx.GetHash()] = CTxIndex(posThisTx, tx.vout.size());
}
// Write queued txindex changes
if (!tx.CheckTransaction())
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
- // Pre-pay-to-script-hash (before version 0.6), this is how sigops
- // were counted; there is another check in ConnectBlock when
- // transaction inputs are fetched to count pay-to-script-hash sigops:
int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
int nHeight = pindexPrev->nHeight+1;
// Check proof of work
- if (nBits != GetNextWorkRequired(pindexPrev))
+ if (nBits != GetNextWorkRequired(pindexPrev, this))
return DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev
if (!pfrom->fInbound)
{
// Advertise our address
- if (addrLocalHost.IsRoutable() && !fUseProxy)
+ if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() &&
+ !IsInitialBlockDownload())
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
// Address refresh broadcast
static int64 nLastRebroadcast;
- if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
+ if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
{
- nLastRebroadcast = GetTime();
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
{
// Periodically clear setAddrKnown to allow refresh broadcasts
- pnode->setAddrKnown.clear();
+ if (nLastRebroadcast)
+ pnode->setAddrKnown.clear();
// Rebroadcast our address
- if (addrLocalHost.IsRoutable() && !fUseProxy)
+ if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable())
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
}
}
}
+ nLastRebroadcast = GetTime();
}
// Clear out old addresses periodically so it's not too much work at once
map<uint256, CTxIndex> mapTestPool;
uint64 nBlockSize = 1000;
uint64 nBlockTx = 0;
- int nBlockSigOps1 = 100; // pre-0.6 count of sigOps
- int nBlockSigOps2 = 100; // post-0.6 count of sigOps
+ int nBlockSigOps = 100;
while (!mapPriority.empty())
{
// Take highest priority transaction off priority queue
continue;
// Legacy limits on sigOps:
- int nTxSigOps1 = tx.GetLegacySigOpCount();
- if (nBlockSigOps1 + nTxSigOps1 >= MAX_BLOCK_SIGOPS)
+ int nTxSigOps = tx.GetLegacySigOpCount();
+ if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
// Transaction fee required depends on block size
// Connecting shouldn't fail due to dependency on other memory pool transactions
// because we're already processing them in order of dependency
map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
- map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
- if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs))
+ MapPrevTx mapInputs;
+ bool fInvalid;
+ if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid))
continue;
- int nTxSigOps2 = 0;
- if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nTxSigOps2, nMinFee))
+ int64 nTxFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
+ if (nTxFees < nMinFee)
continue;
- if (nBlockSigOps2 + nTxSigOps2 >= MAX_BLOCK_SIGOPS)
+
+ nTxSigOps += tx.GetP2SHSigOpCount(mapInputs);
+ if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
+
+ if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true))
+ continue;
+ mapTestPoolTmp[tx.GetHash()] = CTxIndex(CDiskTxPos(1,1,1), tx.vout.size());
swap(mapTestPool, mapTestPoolTmp);
// Added
pblock->vtx.push_back(tx);
nBlockSize += nTxSize;
++nBlockTx;
- nBlockSigOps1 += nTxSigOps1;
- nBlockSigOps2 += nTxSigOps2;
+ nBlockSigOps += nTxSigOps;
+ nFees += nTxFees;
// Add transactions that depend on this one to the priority queue
uint256 hash = tx.GetHash();
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
- pblock->nBits = GetNextWorkRequired(pindexPrev);
+ pblock->nBits = GetNextWorkRequired(pindexPrev, pblock.get());
pblock->nNonce = 0;
return pblock.release();
hashPrevBlock = pblock->hashPrevBlock;
}
++nExtraNonce;
- pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
-
- // Put "/P2SH/" in the coinbase so everybody can tell when
- // a majority of miners support it
- const char* pszP2SH = "/P2SH/";
- pblock->vtx[0].vin[0].scriptSig += CScript() << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
+ pblock->vtx[0].vin[0].scriptSig = (CScript() << pblock->nTime << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();