aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp593
1 files changed, 329 insertions, 264 deletions
diff --git a/src/main.cpp b/src/main.cpp
index f0c08d273..d35891440 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -11,6 +11,7 @@
#include "init.h"
#include "ui_interface.h"
#include "checkqueue.h"
+#include "chainparams.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -32,8 +33,6 @@ unsigned int nTransactionsUpdated = 0;
map<uint256, CBlockIndex*> mapBlockIndex;
std::vector<CBlockIndex*> vBlockIndexByHeight;
-uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
-static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
uint256 nBestChainWork = 0;
@@ -100,9 +99,16 @@ void UnregisterWallet(CWallet* pwalletIn)
}
}
+void UnregisterAllWallets()
+{
+ LOCK(cs_setpwalletRegistered);
+ setpwalletRegistered.clear();
+}
+
// get the wallet transaction with the given hash (if it exists)
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
if (pwallet->GetTransaction(hashTx,wtx))
return true;
@@ -112,6 +118,7 @@ bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
// erases transaction with the given hash from all wallets
void static EraseFromWallets(uint256 hash)
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->EraseFromWallet(hash);
}
@@ -119,6 +126,7 @@ void static EraseFromWallets(uint256 hash)
// make sure all wallets know about the given transaction, in the given block
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate);
}
@@ -126,6 +134,7 @@ void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock*
// notify wallets about a new best chain
void static SetBestChain(const CBlockLocator& loc)
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->SetBestChain(loc);
}
@@ -133,6 +142,7 @@ void static SetBestChain(const CBlockLocator& loc)
// notify wallets about an updated transaction
void static UpdatedTransaction(const uint256& hashTx)
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->UpdatedTransaction(hashTx);
}
@@ -140,6 +150,7 @@ void static UpdatedTransaction(const uint256& hashTx)
// dump all wallets
void static PrintWallets(const CBlock& block)
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->PrintWallet(block);
}
@@ -147,6 +158,7 @@ void static PrintWallets(const CBlock& block)
// notify wallets about an incoming inventory (for request counts)
void static Inventory(const uint256& hash)
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->Inventory(hash);
}
@@ -154,12 +166,11 @@ void static Inventory(const uint256& hash)
// ask wallets to resend their transactions
void static ResendWalletTransactions()
{
+ LOCK(cs_setpwalletRegistered);
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->ResendWalletTransactions();
}
-
-
//////////////////////////////////////////////////////////////////////////////
//
// Registration of network node signals.
@@ -177,7 +188,95 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals)
nodeSignals.SendMessages.disconnect(&SendMessages);
}
+//////////////////////////////////////////////////////////////////////////////
+//
+// CBlockLocator implementation
+//
+CBlockLocator::CBlockLocator(uint256 hashBlock)
+{
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi != mapBlockIndex.end())
+ Set((*mi).second);
+}
+
+void CBlockLocator::Set(const CBlockIndex* pindex)
+{
+ vHave.clear();
+ int nStep = 1;
+ while (pindex)
+ {
+ vHave.push_back(pindex->GetBlockHash());
+
+ // Exponentially larger steps back
+ for (int i = 0; pindex && i < nStep; i++)
+ pindex = pindex->pprev;
+ if (vHave.size() > 10)
+ nStep *= 2;
+ }
+ vHave.push_back(Params().HashGenesisBlock());
+}
+
+int CBlockLocator::GetDistanceBack()
+{
+ // Retrace how far back it was in the sender's branch
+ int nDistance = 0;
+ int nStep = 1;
+ BOOST_FOREACH(const uint256& hash, vHave)
+ {
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ if (mi != mapBlockIndex.end())
+ {
+ CBlockIndex* pindex = (*mi).second;
+ if (pindex->IsInMainChain())
+ return nDistance;
+ }
+ nDistance += nStep;
+ if (nDistance > 10)
+ nStep *= 2;
+ }
+ return nDistance;
+}
+
+CBlockIndex *CBlockLocator::GetBlockIndex()
+{
+ // Find the first block the caller has in the main chain
+ BOOST_FOREACH(const uint256& hash, vHave)
+ {
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ if (mi != mapBlockIndex.end())
+ {
+ CBlockIndex* pindex = (*mi).second;
+ if (pindex->IsInMainChain())
+ return pindex;
+ }
+ }
+ return pindexGenesisBlock;
+}
+
+uint256 CBlockLocator::GetBlockHash()
+{
+ // Find the first block the caller has in the main chain
+ BOOST_FOREACH(const uint256& hash, vHave)
+ {
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ if (mi != mapBlockIndex.end())
+ {
+ CBlockIndex* pindex = (*mi).second;
+ if (pindex->IsInMainChain())
+ return hash;
+ }
+ }
+ return Params().HashGenesisBlock();
+}
+
+int CBlockLocator::GetHeight()
+{
+ CBlockIndex* pindex = GetBlockIndex();
+ if (!pindex)
+ return 0;
+ return pindex->nHeight;
+}
//////////////////////////////////////////////////////////////////////////////
//
@@ -372,38 +471,53 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
-bool IsStandardTx(const CTransaction& tx)
+bool IsStandardTx(const CTransaction& tx, string& reason)
{
- if (tx.nVersion > CTransaction::CURRENT_VERSION)
+ if (tx.nVersion > CTransaction::CURRENT_VERSION) {
+ reason = "version";
return false;
+ }
- if (!IsFinalTx(tx))
+ if (!IsFinalTx(tx)) {
+ 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, CTransaction::CURRENT_VERSION);
- if (sz >= MAX_STANDARD_TX_SIZE)
+ if (sz >= MAX_STANDARD_TX_SIZE) {
+ reason = "tx-size";
return false;
+ }
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
// ~65-byte public keys, plus a few script ops.
- if (txin.scriptSig.size() > 500)
+ if (txin.scriptSig.size() > 500) {
+ reason = "scriptsig-size";
return false;
- if (!txin.scriptSig.IsPushOnly())
+ }
+ if (!txin.scriptSig.IsPushOnly()) {
+ reason = "scriptsig-not-pushonly";
return false;
+ }
}
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
- if (!::IsStandard(txout.scriptPubKey))
+ if (!::IsStandard(txout.scriptPubKey)) {
+ reason = "scriptpubkey";
return false;
- if (txout.IsDust(CTransaction::nMinRelayTxFee))
+ }
+ if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
+ reason = "dust";
return false;
+ }
}
+
return true;
}
@@ -542,7 +656,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if (pcoinsTip->GetCoins(GetHash(), coins)) {
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
if (pindex) {
- if (!blockTmp.ReadFromDisk(pindex))
+ if (!ReadBlockFromDisk(blockTmp, pindex))
return 0;
pblock = &blockTmp;
}
@@ -634,30 +748,23 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return true;
}
-int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize, bool fAllowFree, enum GetMinFee_mode mode)
+int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mode)
{
// Base fee is either nMinTxFee or nMinRelayTxFee
int64 nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee;
unsigned int nBytes = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- unsigned int nNewBlockSize = nBlockSize + nBytes;
int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
if (fAllowFree)
{
- if (nBlockSize == 1)
- {
- // Transactions under 10K are free
- // (about 4500 BTC if made of 50 BTC inputs)
- if (nBytes < 10000)
- nMinFee = 0;
- }
- else
- {
- // Free transaction area
- if (nNewBlockSize < 27000)
- nMinFee = 0;
- }
+ // 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
+ // * If we are creating a transaction we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 17000
+ // (= 10000) to be considered safe and assume they can likely make it into this section
+ if (nBytes < (mode == GMF_SEND ? (DEFAULT_BLOCK_PRIORITY_SIZE - 17000) : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)))
+ nMinFee = 0;
}
// To limit dust spam, require base fee if any output is less than 0.01
@@ -668,14 +775,6 @@ int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize, bool fAllowFree
nMinFee = nBaseFee;
}
- // Raise the price as the block approaches full
- if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
- {
- if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN)
- return MAX_MONEY;
- nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize);
- }
-
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
@@ -712,8 +811,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
// Rather not work on nonstandard transactions (unless -testnet)
- if (!fTestNet && !IsStandardTx(tx))
- return error("CTxMemPool::accept() : nonstandard transaction type");
+ string reason;
+ if (!TestNet() && !IsStandardTx(tx, reason))
+ return error("CTxMemPool::accept() : nonstandard transaction: %s",
+ reason.c_str());
// is it already in the memory pool?
uint256 hash = tx.GetHash();
@@ -787,7 +888,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
}
// Check for non-standard pay-to-script-hash in inputs
- if (!AreInputsStandard(tx, view) && !fTestNet)
+ if (!TestNet() && !AreInputsStandard(tx, view))
return error("CTxMemPool::accept() : nonstandard transaction input");
// Note: if you modify this code to accept non-standard transactions, then
@@ -798,7 +899,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
// Don't accept it if it can't get into a block
- int64 txMinFee = GetMinFee(tx, 1000, true, GMF_RELAY);
+ int64 txMinFee = GetMinFee(tx, true, GMF_RELAY);
if (fLimitFree && nFees < txMinFee)
return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
hash.ToString().c_str(),
@@ -1044,7 +1145,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
if (pindexSlow) {
CBlock block;
- if (block.ReadFromDisk(pindexSlow)) {
+ if (ReadBlockFromDisk(block, pindexSlow)) {
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
if (tx.GetHash() == hash) {
txOut = tx;
@@ -1076,12 +1177,62 @@ CBlockIndex* FindBlockByHeight(int nHeight)
return vBlockIndexByHeight[nHeight];
}
-bool CBlock::ReadFromDisk(const CBlockIndex* pindex)
+bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
+{
+ // Open history file to append
+ CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
+ if (!fileout)
+ 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);
+ if (fileOutPos < 0)
+ return error("WriteBlockToDisk() : ftell failed");
+ pos.nPos = (unsigned int)fileOutPos;
+ fileout << block;
+
+ // Flush stdio buffers and commit to disk before returning
+ fflush(fileout);
+ if (!IsInitialBlockDownload())
+ FileCommit(fileout);
+
+ return true;
+}
+
+bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
{
- if (!ReadFromDisk(pindex->GetBlockPos()))
+ block.SetNull();
+
+ // Open history file to read
+ CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
+ if (!filein)
+ return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed");
+
+ // Read block
+ try {
+ filein >> block;
+ }
+ catch (std::exception &e) {
+ return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+ }
+
+ // Check the header
+ if (!CheckProofOfWork(block.GetHash(), block.nBits))
+ return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header");
+
+ return true;
+}
+
+bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
+{
+ if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
return false;
- if (GetHash() != pindex->GetBlockHash())
- return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
+ if (block.GetHash() != pindex->GetBlockHash())
+ return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index");
return true;
}
@@ -1097,8 +1248,8 @@ int64 static GetBlockValue(int nHeight, int64 nFees)
{
int64 nSubsidy = 50 * COIN;
- // Subsidy is cut in half every 210000 blocks, which will occur approximately every 4 years
- nSubsidy >>= (nHeight / 210000);
+ // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
+ nSubsidy >>= (nHeight / Params().SubsidyHalvingInterval());
return nSubsidy + nFees;
}
@@ -1113,28 +1264,29 @@ static const int64 nInterval = nTargetTimespan / nTargetSpacing;
//
unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
{
+ const CBigNum &bnLimit = Params().ProofOfWorkLimit();
// Testnet has min-difficulty blocks
// after nTargetSpacing*2 time between blocks:
- if (fTestNet && nTime > nTargetSpacing*2)
- return bnProofOfWorkLimit.GetCompact();
+ if (TestNet() && nTime > nTargetSpacing*2)
+ return bnLimit.GetCompact();
CBigNum bnResult;
bnResult.SetCompact(nBase);
- while (nTime > 0 && bnResult < bnProofOfWorkLimit)
+ while (nTime > 0 && bnResult < bnLimit)
{
// Maximum 400% adjustment...
bnResult *= 4;
// ... in best-case exactly 4-times-normal target time
nTime -= nTargetTimespan*4;
}
- if (bnResult > bnProofOfWorkLimit)
- bnResult = bnProofOfWorkLimit;
+ if (bnResult > bnLimit)
+ bnResult = bnLimit;
return bnResult.GetCompact();
}
unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
- unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact();
+ unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();
// Genesis block
if (pindexLast == NULL)
@@ -1143,9 +1295,9 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl
// Only change once per interval
if ((pindexLast->nHeight+1) % nInterval != 0)
{
- // Special difficulty rule for testnet:
- if (fTestNet)
+ if (TestNet())
{
+ // Special difficulty rule for testnet:
// 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)
@@ -1159,7 +1311,6 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl
return pindex->nBits;
}
}
-
return pindexLast->nBits;
}
@@ -1183,8 +1334,8 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl
bnNew *= nActualTimespan;
bnNew /= nTargetTimespan;
- if (bnNew > bnProofOfWorkLimit)
- bnNew = bnProofOfWorkLimit;
+ if (bnNew > Params().ProofOfWorkLimit())
+ bnNew = Params().ProofOfWorkLimit();
/// debug print
printf("GetNextWorkRequired RETARGET\n");
@@ -1201,7 +1352,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
bnTarget.SetCompact(nBits);
// Check range
- if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit)
+ if (bnTarget <= 0 || bnTarget > Params().ProofOfWorkLimit())
return error("CheckProofOfWork() : nBits below minimum work");
// Check proof of work matches claimed amount
@@ -1319,7 +1470,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
// Updating time can change work required on testnet:
- if (fTestNet)
+ if (TestNet())
block.nBits = GetNextWorkRequired(pindexPrev, &block);
}
@@ -1483,7 +1634,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
-bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean)
+bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
{
assert(pindex == view.GetBestBlock());
@@ -1499,12 +1650,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
return error("DisconnectBlock() : failure reading undo data");
- if (blockUndo.vtxundo.size() + 1 != vtx.size())
+ if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock() : block and undo data inconsistent");
// undo transactions in reverse order
- for (int i = vtx.size() - 1; i >= 0; i--) {
- const CTransaction &tx = vtx[i];
+ 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
@@ -1597,10 +1748,10 @@ void ThreadScriptCheck() {
scriptcheckqueue.Thread();
}
-bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck)
+bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
{
// Check it again in case a previous version let a bad block in
- if (!CheckBlock(state, !fJustCheck, !fJustCheck))
+ if (!CheckBlock(block, state, !fJustCheck, !fJustCheck))
return false;
// verify that the view's current state corresponds to the previous block
@@ -1608,7 +1759,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
- if (GetHash() == hashGenesisBlock) {
+ if (block.GetHash() == Params().HashGenesisBlock()) {
view.SetBestBlock(pindex);
pindexGenesisBlock = pindex;
return true;
@@ -1632,8 +1783,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
- for (unsigned int i=0; i<vtx.size(); i++) {
- uint256 hash = GetTxHash(i);
+ for (unsigned int i = 0; i < block.vtx.size(); i++) {
+ uint256 hash = block.GetTxHash(i);
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
}
@@ -1654,12 +1805,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
int64 nFees = 0;
int nInputs = 0;
unsigned int nSigOps = 0;
- CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size()));
+ CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
- vPos.reserve(vtx.size());
- for (unsigned int i=0; i<vtx.size(); i++)
+ vPos.reserve(block.vtx.size());
+ for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- const CTransaction &tx = vtx[i];
+ const CTransaction &tx = block.vtx[i];
nInputs += tx.vin.size();
nSigOps += GetLegacySigOpCount(tx);
@@ -1690,19 +1841,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
}
CTxUndo txundo;
- UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i));
+ UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
- vPos.push_back(std::make_pair(GetTxHash(i), pos));
+ vPos.push_back(std::make_pair(block.GetTxHash(i), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64 nTime = GetTimeMicros() - nStart;
if (fBenchmark)
- printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
+ printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
- if (GetValueOut(vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
- return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
+ if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
+ return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
if (!control.Wait())
return state.DoS(100, false);
@@ -1743,8 +1894,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
assert(view.SetBestBlock(pindex));
// Watch for transactions paying to me
- for (unsigned int i=0; i<vtx.size(); i++)
- SyncWithWallets(GetTxHash(i), vtx[i], this, true);
+ for (unsigned int i = 0; i < block.vtx.size(); i++)
+ SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true);
return true;
}
@@ -1790,10 +1941,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector<CTransaction> vResurrect;
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
CBlock block;
- if (!block.ReadFromDisk(pindex))
+ if (!ReadBlockFromDisk(block, pindex))
return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros();
- if (!block.DisconnectBlock(state, pindex, view))
+ if (!DisconnectBlock(block, state, pindex, view))
return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
if (fBenchmark)
printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
@@ -1810,10 +1961,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector<CTransaction> vDelete;
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
CBlock block;
- if (!block.ReadFromDisk(pindex))
+ if (!ReadBlockFromDisk(block, pindex))
return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros();
- if (!block.ConnectBlock(state, pindex, view)) {
+ if (!ConnectBlock(block, state, pindex, view)) {
if (state.IsInvalid()) {
InvalidChainFound(pindexNew);
InvalidBlockFound(pindex);
@@ -1923,25 +2074,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
}
-bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
+bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos)
{
// Check for duplicate
- uint256 hash = GetHash();
+ uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash))
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str()));
// Construct new block index object
- CBlockIndex* pindexNew = new CBlockIndex(*this);
+ CBlockIndex* pindexNew = new CBlockIndex(block);
assert(pindexNew);
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
- map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
+ map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
if (miPrev != mapBlockIndex.end())
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
}
- pindexNew->nTx = vtx.size();
+ pindexNew->nTx = block.vtx.size();
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256();
pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
pindexNew->nFile = pos.nFile;
@@ -1962,7 +2113,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
UpdatedTransaction(hashPrevBestCoinBase);
- hashPrevBestCoinBase = GetTxHash(0);
+ hashPrevBestCoinBase = block.GetTxHash(0);
}
if (!pblocktree->Flush())
@@ -2068,51 +2219,51 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
}
-bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const
+bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
{
// These are checks that are independent of context
// that can be verified before saving an orphan block.
// Size limits
- if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
+ if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
- if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits))
+ if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits))
return state.DoS(50, error("CheckBlock() : proof of work failed"));
// Check timestamp
- if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
+ if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return state.Invalid(error("CheckBlock() : block timestamp too far in the future"));
// First transaction must be coinbase, the rest must not be
- if (vtx.empty() || !vtx[0].IsCoinBase())
+ if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
return state.DoS(100, error("CheckBlock() : first tx is not coinbase"));
- for (unsigned int i = 1; i < vtx.size(); i++)
- if (vtx[i].IsCoinBase())
+ for (unsigned int i = 1; i < block.vtx.size(); i++)
+ if (block.vtx[i].IsCoinBase())
return state.DoS(100, error("CheckBlock() : more than one coinbase"));
// Check transactions
- BOOST_FOREACH(const CTransaction& tx, vtx)
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed");
// Build the merkle tree already. We need it anyway later, and it makes the
// block cache the transaction hashes, which means they don't need to be
// recalculated many times during this block's validation.
- BuildMerkleTree();
+ block.BuildMerkleTree();
// Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack:
set<uint256> uniqueTx;
- for (unsigned int i=0; i<vtx.size(); i++) {
- uniqueTx.insert(GetTxHash(i));
+ for (unsigned int i = 0; i < block.vtx.size(); i++) {
+ uniqueTx.insert(block.GetTxHash(i));
}
- if (uniqueTx.size() != vtx.size())
+ if (uniqueTx.size() != block.vtx.size())
return state.DoS(100, error("CheckBlock() : duplicate transaction"));
unsigned int nSigOps = 0;
- BOOST_FOREACH(const CTransaction& tx, vtx)
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
{
nSigOps += GetLegacySigOpCount(tx);
}
@@ -2120,40 +2271,40 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkle root
- if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
+ if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true;
}
-bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
+bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
{
// Check for duplicate
- uint256 hash = GetHash();
+ uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash))
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
// Get prev block index
CBlockIndex* pindexPrev = NULL;
int nHeight = 0;
- if (hash != hashGenesisBlock) {
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
+ if (hash != Params().HashGenesisBlock()) {
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
return state.DoS(10, error("AcceptBlock() : prev block not found"));
pindexPrev = (*mi).second;
nHeight = pindexPrev->nHeight+1;
// Check proof of work
- if (nBits != GetNextWorkRequired(pindexPrev, this))
+ if (block.nBits != GetNextWorkRequired(pindexPrev, &block))
return state.DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev
- if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
+ if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"));
// Check that all transactions are finalized
- BOOST_FOREACH(const CTransaction& tx, vtx)
- if (!IsFinalTx(tx, nHeight, GetBlockTime()))
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ if (!IsFinalTx(tx, nHeight, block.GetBlockTime()))
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"));
// Check that the block chain matches the known block chain up to a checkpoint
@@ -2161,23 +2312,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight));
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
- if (nVersion < 2)
+ if (block.nVersion < 2)
{
- if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
- (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
+ if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
+ (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
{
return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"));
}
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
- if (nVersion >= 2)
+ if (block.nVersion >= 2)
{
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
- if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
- (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
+ if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
+ (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
{
CScript expect = CScript() << nHeight;
- if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
+ if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin()))
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
}
}
@@ -2185,16 +2336,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
// Write block to history file
try {
- unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
+ unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
if (dbp != NULL)
blockPos = *dbp;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL))
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.nTime, dbp != NULL))
return error("AcceptBlock() : FindBlockPos failed");
if (dbp == NULL)
- if (!WriteToDisk(blockPos))
+ if (!WriteBlockToDisk(block, blockPos))
return state.Abort(_("Failed to write block"));
- if (!AddToBlockIndex(state, blockPos))
+ if (!AddToBlockIndex(block, state, blockPos))
return error("AcceptBlock() : AddToBlockIndex failed");
} catch(std::runtime_error &e) {
return state.Abort(_("System error: ") + e.what());
@@ -2246,7 +2397,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str()));
// Preliminary checks
- if (!pblock->CheckBlock(state))
+ if (!CheckBlock(*pblock, state))
return error("ProcessBlock() : CheckBlock FAILED");
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
@@ -2287,7 +2438,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
}
// Store to disk
- if (!pblock->AcceptBlock(state, dbp))
+ if (!AcceptBlock(*pblock, state, dbp))
return error("ProcessBlock() : AcceptBlock FAILED");
// Recursively process any orphan blocks that depended on this one
@@ -2303,7 +2454,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
CBlock* pblockOrphan = (*mi).second;
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
CValidationState stateDummy;
- if (pblockOrphan->AcceptBlock(stateDummy))
+ if (AcceptBlock(*pblockOrphan, stateDummy))
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan;
@@ -2616,14 +2767,13 @@ bool static LoadBlockIndexDB()
return true;
}
-bool VerifyDB() {
+bool VerifyDB(int nCheckLevel, int nCheckDepth)
+{
if (pindexBest == NULL || pindexBest->pprev == NULL)
return true;
// Verify blocks in the best chain
- int nCheckLevel = GetArg("-checklevel", 3);
- int nCheckDepth = GetArg( "-checkblocks", 288);
- if (nCheckDepth == 0)
+ if (nCheckDepth <= 0)
nCheckDepth = 1000000000; // suffices until the year 19000
if (nCheckDepth > nBestHeight)
nCheckDepth = nBestHeight;
@@ -2641,10 +2791,10 @@ bool VerifyDB() {
break;
CBlock block;
// check level 0: read from disk
- if (!block.ReadFromDisk(pindex))
- return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ if (!ReadBlockFromDisk(block, pindex))
+ return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
// check level 1: verify block validity
- if (nCheckLevel >= 1 && !block.CheckBlock(state))
+ if (nCheckLevel >= 1 && !CheckBlock(block, state))
return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
@@ -2658,7 +2808,7 @@ bool VerifyDB() {
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) {
bool fClean = true;
- if (!block.DisconnectBlock(state, pindex, coins, &fClean))
+ if (!DisconnectBlock(block, state, pindex, coins, &fClean))
return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
pindexState = pindex->pprev;
if (!fClean) {
@@ -2678,9 +2828,9 @@ bool VerifyDB() {
boost::this_thread::interruption_point();
pindex = pindex->GetNextInMainChain();
CBlock block;
- if (!block.ReadFromDisk(pindex))
- return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
- if (!block.ConnectBlock(state, pindex, coins))
+ if (!ReadBlockFromDisk(block, pindex))
+ return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ if (!ConnectBlock(block, state, pindex, coins))
return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
}
}
@@ -2704,21 +2854,9 @@ void UnloadBlockIndex()
bool LoadBlockIndex()
{
- if (fTestNet)
- {
- pchMessageStart[0] = 0x0b;
- pchMessageStart[1] = 0x11;
- pchMessageStart[2] = 0x09;
- pchMessageStart[3] = 0x07;
- hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
- }
-
- //
// Load block index from databases
- //
if (!fReindex && !LoadBlockIndexDB())
return false;
-
return true;
}
@@ -2735,55 +2873,17 @@ bool InitBlockIndex() {
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
if (!fReindex) {
- // Genesis Block:
- // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
- // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
- // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
- // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
- // vMerkleTree: 4a5e1e
-
- // Genesis block
- const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
- CTransaction txNew;
- txNew.vin.resize(1);
- txNew.vout.resize(1);
- txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
- txNew.vout[0].nValue = 50 * COIN;
- txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
- CBlock block;
- block.vtx.push_back(txNew);
- block.hashPrevBlock = 0;
- block.hashMerkleRoot = block.BuildMerkleTree();
- block.nVersion = 1;
- block.nTime = 1231006505;
- block.nBits = 0x1d00ffff;
- block.nNonce = 2083236893;
-
- if (fTestNet)
- {
- block.nTime = 1296688602;
- block.nNonce = 414098458;
- }
-
- //// debug print
- uint256 hash = block.GetHash();
- printf("%s\n", hash.ToString().c_str());
- printf("%s\n", hashGenesisBlock.ToString().c_str());
- printf("%s\n", block.hashMerkleRoot.ToString().c_str());
- assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
- block.print();
- assert(hash == hashGenesisBlock);
-
- // Start new block file
try {
+ CBlock &block = const_cast<CBlock&>(Params().GenesisBlock());
+ // Start new block file
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
return error("LoadBlockIndex() : FindBlockPos failed");
- if (!block.WriteToDisk(blockPos))
+ if (!WriteBlockToDisk(block, blockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed");
- if (!block.AddToBlockIndex(state, blockPos))
+ if (!AddToBlockIndex(block, state, blockPos))
return error("LoadBlockIndex() : genesis block not accepted");
} catch(std::runtime_error &e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
@@ -2839,7 +2939,7 @@ void PrintBlockTree()
// print item
CBlock block;
- block.ReadFromDisk(pindex);
+ ReadBlockFromDisk(block, pindex);
printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
pindex->nHeight,
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
@@ -2892,10 +2992,10 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
try {
// locate a header
unsigned char buf[4];
- blkdat.FindByte(pchMessageStart[0]);
+ blkdat.FindByte(Params().MessageStart()[0]);
nRewind = blkdat.GetPos()+1;
blkdat >> FLATDATA(buf);
- if (memcmp(buf, pchMessageStart, 4))
+ if (memcmp(buf, Params().MessageStart(), 4))
continue;
// read size
blkdat >> nSize;
@@ -3040,12 +3140,6 @@ bool static AlreadyHave(const CInv& inv)
-// The message start string is designed to be unlikely to occur in normal data.
-// The characters are rarely used upper ASCII, not valid as UTF-8, and produce
-// a large 4-byte int at any alignment.
-unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
-
-
void static ProcessGetData(CNode* pfrom)
{
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
@@ -3069,7 +3163,7 @@ void static ProcessGetData(CNode* pfrom)
if (mi != mapBlockIndex.end())
{
CBlock block;
- block.ReadFromDisk((*mi).second);
+ ReadBlockFromDisk(block, (*mi).second);
if (inv.type == MSG_BLOCK)
pfrom->PushMessage("block", block);
else // MSG_FILTERED_BLOCK)
@@ -3504,6 +3598,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv(MSG_TX, tx.GetHash());
pfrom->AddInventoryKnown(inv);
+ // Truncate messages to the size of the tx in them
+ unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+ unsigned int oldSize = vMsg.size();
+ if (nSize < oldSize) {
+ vMsg.resize(nSize);
+ printf("truncating oversized TX %s (%u -> %u)\n",
+ tx.GetHash().ToString().c_str(),
+ oldSize, nSize);
+ }
+
bool fMissingInputs = false;
CValidationState state;
if (mempool.accept(state, tx, true, &fMissingInputs))
@@ -3768,7 +3872,7 @@ bool ProcessMessages(CNode* pfrom)
it++;
// Scan for message start
- if (memcmp(msg.hdr.pchMessageStart, pchMessageStart, sizeof(pchMessageStart)) != 0) {
+ if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) {
printf("\n\nPROCESSMESSAGE: INVALID MESSAGESTART\n\n");
fOk = false;
break;
@@ -4186,7 +4290,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay
- unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000);
+ unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
// Minimum block size you want to create; block will be filled with free transactions
@@ -4314,7 +4418,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// Prioritize by fee once past the priority size or we run out of high-priority
// transactions:
if (!fSortedByFee &&
- ((nBlockSize + nTxSize >= nBlockPrioritySize) || (dPriority < COIN * 144 / 250)))
+ ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
{
fSortedByFee = true;
comparer = TxPriorityCompare(fSortedByFee);
@@ -4391,7 +4495,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
indexDummy.nHeight = pindexPrev->nHeight + 1;
CCoinsViewCache viewNew(*pcoinsTip, true);
CValidationState state;
- if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true))
+ if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
}
@@ -4512,8 +4616,12 @@ void static BitcoinMiner(CWallet *pwallet)
unsigned int nExtraNonce = 0;
try { loop {
- while (vNodes.empty())
- MilliSleep(1000);
+ if (Params().NetworkID() != CChainParams::REGTEST) {
+ // Busy-wait for the network to come online so we don't waste time mining
+ // on an obsolete chain. In regtest mode we expect to fly solo.
+ while (vNodes.empty())
+ MilliSleep(1000);
+ }
//
// Create new block
@@ -4575,6 +4683,12 @@ void static BitcoinMiner(CWallet *pwallet)
SetThreadPriority(THREAD_PRIORITY_NORMAL);
CheckWork(pblock, *pwalletMain, reservekey);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
+
+ // In regression test mode, stop mining after a block is found. This
+ // allows developers to controllably generate a block on demand.
+ if (Params().NetworkID() == CChainParams::REGTEST)
+ throw boost::thread_interrupted();
+
break;
}
}
@@ -4610,7 +4724,7 @@ void static BitcoinMiner(CWallet *pwallet)
// Check for stop or if block needs to be rebuilt
boost::this_thread::interruption_point();
- if (vNodes.empty())
+ if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST)
break;
if (nBlockNonce >= 0xffff0000)
break;
@@ -4622,7 +4736,7 @@ void static BitcoinMiner(CWallet *pwallet)
// Update nTime every few seconds
UpdateTime(*pblock, pindexPrev);
nBlockTime = ByteReverse(pblock->nTime);
- if (fTestNet)
+ if (TestNet())
{
// Changing pblock->nTime can change work required on testnet:
nBlockBits = ByteReverse(pblock->nBits);
@@ -4642,8 +4756,12 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
static boost::thread_group* minerThreads = NULL;
int nThreads = GetArg("-genproclimit", -1);
- if (nThreads < 0)
- nThreads = boost::thread::hardware_concurrency();
+ if (nThreads < 0) {
+ if (Params().NetworkID() == CChainParams::REGTEST)
+ nThreads = 1;
+ else
+ nThreads = boost::thread::hardware_concurrency();
+ }
if (minerThreads != NULL)
{
@@ -4660,59 +4778,6 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
}
-// Amount compression:
-// * If the amount is 0, output 0
-// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
-// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
-// * call the result n
-// * output 1 + 10*(9*n + d - 1) + e
-// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
-// (this is decodable, as d is in [1-9] and e is in [0-9])
-
-uint64 CTxOutCompressor::CompressAmount(uint64 n)
-{
- if (n == 0)
- return 0;
- int e = 0;
- while (((n % 10) == 0) && e < 9) {
- n /= 10;
- e++;
- }
- if (e < 9) {
- int d = (n % 10);
- assert(d >= 1 && d <= 9);
- n /= 10;
- return 1 + (n*9 + d - 1)*10 + e;
- } else {
- return 1 + (n - 1)*10 + 9;
- }
-}
-
-uint64 CTxOutCompressor::DecompressAmount(uint64 x)
-{
- // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9
- if (x == 0)
- return 0;
- x--;
- // x = 10*(9*n + d - 1) + e
- int e = x % 10;
- x /= 10;
- uint64 n = 0;
- if (e < 9) {
- // x = 9*n + d - 1
- int d = (x % 9) + 1;
- x /= 9;
- // x = n
- n = x*10 + d;
- } else {
- n = x+1;
- }
- while (e) {
- n *= 10;
- e--;
- }
- return n;
-}
class CMainCleanup