// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2011 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"
+#include "checkpoints.h"
#include "db.h"
#include "net.h"
#include "init.h"
CCriticalSection cs_main;
-CCriticalSection cs_mapPubKeys;
-map<uint160, vector<unsigned char> > mapPubKeys;
-
-map<uint256, CTransaction> mapTransactions;
+static map<uint256, CTransaction> mapTransactions;
CCriticalSection cs_mapTransactions;
unsigned int nTransactionsUpdated = 0;
map<COutPoint, CInPoint> mapNextTx;
map<uint256, CBlockIndex*> mapBlockIndex;
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
-CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
-const int nTotalBlocksEstimate = 131000; // Conservative estimate of total nr of blocks on main chain
-const int nInitialBlockThreshold = 10000; // Regard blocks up until N-threshold as "initial download"
+static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
+const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBigNum bnBestChainWork = 0;
// Settings
int fGenerateBitcoins = false;
int64 nTransactionFee = 0;
-CAddress addrIncoming;
int fLimitProcessors = false;
int nLimitProcessors = 1;
int fMinimizeToTray = true;
bool CTransaction::CheckTransaction() const
{
// Basic checks that don't depend on any context
- if (vin.empty() || vout.empty())
- return error("CTransaction::CheckTransaction() : vin or vout empty");
-
+ if (vin.empty())
+ return error("CTransaction::CheckTransaction() : vin empty");
+ if (vout.empty())
+ return error("CTransaction::CheckTransaction() : vout empty");
// Size limits
if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
return error("CTransaction::CheckTransaction() : size limits failed");
return error("CTransaction::CheckTransaction() : txout total out of range");
}
+ // Check for duplicate inputs
+ set<COutPoint> vInOutPoints;
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ {
+ if (vInOutPoints.count(txin.prevout))
+ return false;
+ vInOutPoints.insert(txin.prevout);
+ }
+
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
return true;
}
-// Return conservative estimate of total number of blocks, 0 if unknown
-int GetTotalBlocksEstimate()
-{
- if(fTestNet)
- {
- return 0;
- }
- else
- {
- return nTotalBlocksEstimate;
- }
-}
-
bool IsInitialBlockDownload()
{
- if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold))
+ if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
return true;
static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
// Read txindex
CTxIndex txindex;
bool fFound = true;
- if (fMiner && mapTestPool.count(prevout.hash))
+ if ((fBlock || fMiner) && mapTestPool.count(prevout.hash))
{
// Get txindex from current proposed changes
txindex = mapTestPool[prevout.hash];
txindex.vSpent[prevout.n] = posThisTx;
// Write back
- if (fBlock)
- {
- if (!txdb.UpdateTxIndex(prevout.hash, txindex))
- return error("ConnectInputs() : UpdateTxIndex failed");
- }
- else if (fMiner)
+ if (fBlock || fMiner)
{
mapTestPool[prevout.hash] = txindex;
}
if (fBlock)
{
- // Add transaction to disk index
- if (!txdb.AddTxIndex(*this, posThisTx, pindexBlock->nHeight))
- return error("ConnectInputs() : AddTxPos failed");
+ // Add transaction to changes
+ mapTestPool[GetHash()] = CTxIndex(posThisTx, vout.size());
}
else if (fMiner)
{
//// issue here: it doesn't know the version
unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
- map<uint256, CTxIndex> mapUnused;
+ map<uint256, CTxIndex> mapQueuedChanges;
int64 nFees = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
{
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
nTxPos += ::GetSerializeSize(tx, SER_DISK);
- if (!tx.ConnectInputs(txdb, mapUnused, posThisTx, pindex, nFees, true, false))
+ if (!tx.ConnectInputs(txdb, mapQueuedChanges, posThisTx, pindex, nFees, true, false))
return false;
}
+ // Write queued txindex changes
+ for (map<uint256, CTxIndex>::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi)
+ {
+ if (!txdb.UpdateTxIndex((*mi).first, (*mi).second))
+ return error("ConnectBlock() : UpdateTxIndex failed");
+ }
if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
return false;
return error("AcceptBlock() : contains a non-final transaction");
// Check that the block chain matches the known block chain up to a checkpoint
- if (!fTestNet)
- if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) ||
- (nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) ||
- (nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) ||
- (nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) ||
- (nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) ||
- (nHeight == 105000 && hash != uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) ||
- (nHeight == 118000 && hash != uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553")))
- return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
+ if (!Checkpoints::CheckBlock(nHeight, hash))
+ return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
// Write block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
if (hashBestChain == hash)
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
- if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 118000))
+ if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 140700))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
return true;
-template<typename Stream>
-bool static ScanMessageStart(Stream& s)
-{
- // Scan ahead to the next pchMessageStart, which should normally be immediately
- // at the file pointer. Leaves file pointer at end of pchMessageStart.
- s.clear(0);
- short prevmask = s.exceptions(0);
- const char* p = BEGIN(pchMessageStart);
- try
- {
- loop
- {
- char c;
- s.read(&c, 1);
- if (s.fail())
- {
- s.clear(0);
- s.exceptions(prevmask);
- return false;
- }
- if (*p != c)
- p = BEGIN(pchMessageStart);
- if (*p == c)
- {
- if (++p == END(pchMessageStart))
- {
- s.clear(0);
- s.exceptions(prevmask);
- return true;
- }
- }
- }
- }
- catch (...)
- {
- s.clear(0);
- s.exceptions(prevmask);
- return false;
- }
-}
-
bool CheckDiskSpace(uint64 nAdditionalBytes)
{
uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
return strStatusBar;
else if (strFor == "rpc")
return strRPC;
- assert(("GetWarnings() : invalid parameter", false));
+ assert(!"GetWarnings() : invalid parameter");
return "error";
}
// 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.
-char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
+unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
static map<unsigned int, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
- if (fDebug)
+ if (fDebug) {
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
- printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
+ printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
+ }
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
printf("dropmessagestest DROPPING RECV MESSAGE\n");
// Ask the first connected node for block updates
static int nAskedForBlocks;
- if (!pfrom->fClient && (nAskedForBlocks < 1 || vNodes.size() <= 1))
+ if (!pfrom->fClient &&
+ (pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) &&
+ (nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
pfrom->PushGetBlocks(pindexBest, uint256(0));
return error("message addr size() = %d", vAddr.size());
// Store the new addresses
+ CAddrDB addrDB;
+ addrDB.TxnBegin();
int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr)
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
- AddAddress(addr, 2 * 60 * 60);
+ AddAddress(addr, 2 * 60 * 60, &addrDB);
pfrom->AddAddressKnown(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
}
}
}
+ addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
}
pfrom->AddInventoryKnown(inv);
bool fAlreadyHave = AlreadyHave(txdb, inv);
- printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
+ if (fDebug)
+ printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
if (!fAlreadyHave)
pfrom->AskFor(inv);
if (pindex)
pindex = pindex->pnext;
int nLimit = 500 + locator.GetDistanceBack();
+ unsigned int nBytes = 0;
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
if (pindex->GetBlockHash() == hashStop)
{
- printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ printf(" getblocks stopping at %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
- if (--nLimit <= 0)
+ CBlock block;
+ block.ReadFromDisk(pindex, true);
+ nBytes += block.GetSerializeSize(SER_NETWORK);
+ if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
{
// When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory.
- printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ printf(" getblocks stopping at limit %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
- mapReuseKey[pfrom->addr.ip] = pwalletMain->GetKeyFromKeyPool();
+ pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
// Send back approval of order and pubkey to use
CScript scriptPubKey;
vGetData.clear();
}
}
+ mapAlreadyAskedFor[inv] = nNow;
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
}
}
-
+// Some explaining would be appreciated
class COrphan
{
public:
}
-void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime)
+void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
- int64 nNow = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
- if (++nExtraNonce >= 0x7f && nNow > nPrevTime+1)
+ static uint256 hashPrevBlock;
+ if (hashPrevBlock != pblock->hashPrevBlock)
{
- nExtraNonce = 1;
- nPrevTime = nNow;
+ nExtraNonce = 0;
+ hashPrevBlock = pblock->hashPrevBlock;
}
- pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
+ ++nExtraNonce;
+ pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}
reservekey.KeepKey();
// Track how many getdata requests this block gets
- CRITICAL_BLOCK(wallet.cs_mapRequestCount)
+ CRITICAL_BLOCK(wallet.cs_wallet)
wallet.mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node
// Each thread has its own key and counter
CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
- int64 nPrevTime = 0;
while (fGenerateBitcoins)
{
auto_ptr<CBlock> pblock(CreateNewBlock(reservekey));
if (!pblock.get())
return;
- IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce, nPrevTime);
+ IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());