// Copyright (c) 2009 Satoshi Nakamoto
// 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 "sha.h"
//
// Global state
//
CCriticalSection cs_main ;
map < uint256 , CTransaction > mapTransactions ;
CCriticalSection cs_mapTransactions ;
unsigned int nTransactionsUpdated = 0 ;
map < COutPoint , CInPoint > mapNextTx ;
map < uint256 , CBlockIndex * > mapBlockIndex ;
const uint256 hashGenesisBlock ( " 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f " ) ;
CBlockIndex * pindexGenesisBlock = NULL ;
int nBestHeight = - 1 ;
uint256 hashBestChain = 0 ;
CBlockIndex * pindexBest = NULL ;
map < uint256 , CBlock * > mapOrphanBlocks ;
multimap < uint256 , CBlock * > mapOrphanBlocksByPrev ;
map < uint256 , CDataStream * > mapOrphanTransactions ;
multimap < uint256 , CDataStream * > mapOrphanTransactionsByPrev ;
map < uint256 , CWalletTx > mapWallet ;
vector < uint256 > vWalletUpdated ;
CCriticalSection cs_mapWallet ;
map < vector < unsigned char > , CPrivKey > mapKeys ;
map < uint160 , vector < unsigned char > > mapPubKeys ;
CCriticalSection cs_mapKeys ;
CKey keyUser ;
string strSetDataDir ;
int nDropMessagesTest = 0 ;
// Settings
int fGenerateBitcoins = false ;
int64 nTransactionFee = 0 ;
CAddress addrIncoming ;
int fLimitProcessors = false ;
int nLimitProcessors = 1 ;
//////////////////////////////////////////////////////////////////////////////
//
// mapKeys
//
bool AddKey ( const CKey & key )
{
CRITICAL_BLOCK ( cs_mapKeys )
{
mapKeys [ key . GetPubKey ( ) ] = key . GetPrivKey ( ) ;
mapPubKeys [ Hash160 ( key . GetPubKey ( ) ) ] = key . GetPubKey ( ) ;
}
return CWalletDB ( ) . WriteKey ( key . GetPubKey ( ) , key . GetPrivKey ( ) ) ;
}
vector < unsigned char > GenerateNewKey ( )
{
CKey key ;
key . MakeNewKey ( ) ;
if ( ! AddKey ( key ) )
throw runtime_error ( " GenerateNewKey() : AddKey failed \ n " ) ;
return key . GetPubKey ( ) ;
}
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
//
bool AddToWallet ( const CWalletTx & wtxIn )
{
uint256 hash = wtxIn . GetHash ( ) ;
CRITICAL_BLOCK ( cs_mapWallet )
{
// Inserts only if not already there, returns tx inserted or tx found
pair < map < uint256 , CWalletTx > : : iterator , bool > ret = mapWallet . insert ( make_pair ( hash , wtxIn ) ) ;
CWalletTx & wtx = ( * ret . first ) . second ;
bool fInsertedNew = ret . second ;
if ( fInsertedNew )
wtx . nTimeReceived = GetAdjustedTime ( ) ;
//// debug print
printf ( " AddToWallet %s %s \n " , wtxIn . GetHash ( ) . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) , fInsertedNew ? " new " : " update " ) ;
if ( ! fInsertedNew )
{
// Merge
bool fUpdated = false ;
if ( wtxIn . hashBlock ! = 0 & & wtxIn . hashBlock ! = wtx . hashBlock )
{
wtx . hashBlock = wtxIn . hashBlock ;
fUpdated = true ;
}
if ( wtxIn . nIndex ! = - 1 & & ( wtxIn . vMerkleBranch ! = wtx . vMerkleBranch | | wtxIn . nIndex ! = wtx . nIndex ) )
{
wtx . vMerkleBranch = wtxIn . vMerkleBranch ;
wtx . nIndex = wtxIn . nIndex ;
fUpdated = true ;
}
if ( wtxIn . fFromMe & & wtxIn . fFromMe ! = wtx . fFromMe )
{
wtx . fFromMe = wtxIn . fFromMe ;
fUpdated = true ;
}
if ( wtxIn . fSpent & & wtxIn . fSpent ! = wtx . fSpent )
{
wtx . fSpent = wtxIn . fSpent ;
fUpdated = true ;
}
if ( ! fUpdated )
return true ;
}
// Write to disk
if ( ! wtx . WriteToDisk ( ) )
return false ;
// Notify UI
vWalletUpdated . push_back ( hash ) ;
}
// Refresh UI
MainFrameRepaint ( ) ;
return true ;
}
bool AddToWalletIfMine ( const CTransaction & tx , const CBlock * pblock )
{
if ( tx . IsMine ( ) | | mapWallet . count ( tx . GetHash ( ) ) )
{
CWalletTx wtx ( tx ) ;
// Get merkle branch if transaction was found in a block
if ( pblock )
wtx . SetMerkleBranch ( pblock ) ;
return AddToWallet ( wtx ) ;
}
return true ;
}
bool EraseFromWallet ( uint256 hash )
{
CRITICAL_BLOCK ( cs_mapWallet )
{
if ( mapWallet . erase ( hash ) )
CWalletDB ( ) . EraseTx ( hash ) ;
}
return true ;
}
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
//
void AddOrphanTx ( const CDataStream & vMsg )
{
CTransaction tx ;
CDataStream ( vMsg ) > > tx ;
uint256 hash = tx . GetHash ( ) ;
if ( mapOrphanTransactions . count ( hash ) )
return ;
CDataStream * pvMsg = mapOrphanTransactions [ hash ] = new CDataStream ( vMsg ) ;
foreach ( const CTxIn & txin , tx . vin )
mapOrphanTransactionsByPrev . insert ( make_pair ( txin . prevout . hash , pvMsg ) ) ;
}
void EraseOrphanTx ( uint256 hash )
{
if ( ! mapOrphanTransactions . count ( hash ) )
return ;
const CDataStream * pvMsg = mapOrphanTransactions [ hash ] ;
CTransaction tx ;
CDataStream ( * pvMsg ) > > tx ;
foreach ( const CTxIn & txin , tx . vin )
{
for ( multimap < uint256 , CDataStream * > : : iterator mi = mapOrphanTransactionsByPrev . lower_bound ( txin . prevout . hash ) ;
mi ! = mapOrphanTransactionsByPrev . upper_bound ( txin . prevout . hash ) ; )
{
if ( ( * mi ) . second = = pvMsg )
mapOrphanTransactionsByPrev . erase ( mi + + ) ;
else
mi + + ;
}
}
delete pvMsg ;
mapOrphanTransactions . erase ( hash ) ;
}
//////////////////////////////////////////////////////////////////////////////
//
// CTransaction
//
bool CTxIn : : IsMine ( ) const
{
CRITICAL_BLOCK ( cs_mapWallet )
{
map < uint256 , CWalletTx > : : iterator mi = mapWallet . find ( prevout . hash ) ;
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
if ( prevout . n < prev . vout . size ( ) )
if ( prev . vout [ prevout . n ] . IsMine ( ) )
return true ;
}
}
return false ;
}
int64 CTxIn : : GetDebit ( ) const
{
CRITICAL_BLOCK ( cs_mapWallet )
{
map < uint256 , CWalletTx > : : iterator mi = mapWallet . find ( prevout . hash ) ;
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
if ( prevout . n < prev . vout . size ( ) )
if ( prev . vout [ prevout . n ] . IsMine ( ) )
return prev . vout [ prevout . n ] . nValue ;
}
}
return 0 ;
}
int64 CWalletTx : : GetTxTime ( ) const
{
if ( ! fTimeReceivedIsTxTime & & hashBlock ! = 0 )
{
// If we did not receive the transaction directly, we rely on the block's
// time to figure out when it happened. We use the median over a range
// of blocks to try to filter out inaccurate block times.
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
if ( mi ! = mapBlockIndex . end ( ) )
{
CBlockIndex * pindex = ( * mi ) . second ;
if ( pindex )
return pindex - > GetMedianTime ( ) ;
}
}
return nTimeReceived ;
}
int CMerkleTx : : SetMerkleBranch ( const CBlock * pblock )
{
if ( fClient )
{
if ( hashBlock = = 0 )
return 0 ;
}
else
{
CBlock blockTmp ;
if ( pblock = = NULL )
{
// Load the block this tx is in
CTxIndex txindex ;
if ( ! CTxDB ( " r " ) . ReadTxIndex ( GetHash ( ) , txindex ) )
return 0 ;
if ( ! blockTmp . ReadFromDisk ( txindex . pos . nFile , txindex . pos . nBlockPos , true ) )
return 0 ;
pblock = & blockTmp ;
}
// Update the tx's hashBlock
hashBlock = pblock - > GetHash ( ) ;
// Locate the transaction
for ( nIndex = 0 ; nIndex < pblock - > vtx . size ( ) ; nIndex + + )
if ( pblock - > vtx [ nIndex ] = = * ( CTransaction * ) this )
break ;
if ( nIndex = = pblock - > vtx . size ( ) )
{
vMerkleBranch . clear ( ) ;
nIndex = - 1 ;
printf ( " ERROR: SetMerkleBranch() : couldn't find tx in block \n " ) ;
return 0 ;
}
// Fill in merkle branch
vMerkleBranch = pblock - > GetMerkleBranch ( nIndex ) ;
}
// Is the tx in a block that's in the main chain
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
if ( mi = = mapBlockIndex . end ( ) )
return 0 ;
CBlockIndex * pindex = ( * mi ) . second ;
if ( ! pindex | | ! pindex - > IsInMainChain ( ) )
return 0 ;
return pindexBest - > nHeight - pindex - > nHeight + 1 ;
}
void CWalletTx : : AddSupportingTransactions ( CTxDB & txdb )
{
vtxPrev . clear ( ) ;
const int COPY_DEPTH = 3 ;
if ( SetMerkleBranch ( ) < COPY_DEPTH )
{
vector < uint256 > vWorkQueue ;
foreach ( const CTxIn & txin , vin )
vWorkQueue . push_back ( txin . prevout . hash ) ;
// This critsect is OK because txdb is already open
CRITICAL_BLOCK ( cs_mapWallet )
{
map < uint256 , const CMerkleTx * > mapWalletPrev ;
set < uint256 > setAlreadyDone ;
for ( int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
{
uint256 hash = vWorkQueue [ i ] ;
if ( setAlreadyDone . count ( hash ) )
continue ;
setAlreadyDone . insert ( hash ) ;
CMerkleTx tx ;
if ( mapWallet . count ( hash ) )
{
tx = mapWallet [ hash ] ;
foreach ( const CMerkleTx & txWalletPrev , mapWallet [ hash ] . vtxPrev )
mapWalletPrev [ txWalletPrev . GetHash ( ) ] = & txWalletPrev ;
}
else if ( mapWalletPrev . count ( hash ) )
{
tx = * mapWalletPrev [ hash ] ;
}
else if ( ! fClient & & txdb . ReadDiskTx ( hash , tx ) )
{
;
}
else
{
printf ( " ERROR: AddSupportingTransactions() : unsupported transaction \n " ) ;
continue ;
}
int nDepth = tx . SetMerkleBranch ( ) ;
vtxPrev . push_back ( tx ) ;
if ( nDepth < COPY_DEPTH )
foreach ( const CTxIn & txin , tx . vin )
vWorkQueue . push_back ( txin . prevout . hash ) ;
}
}
}
reverse ( vtxPrev . begin ( ) , vtxPrev . end ( ) ) ;
}
bool CTransaction : : AcceptTransaction ( CTxDB & txdb , bool fCheckInputs , bool * pfMissingInputs )
{
if ( pfMissingInputs )
* pfMissingInputs = false ;
// Coinbase is only valid in a block, not as a loose transaction
if ( IsCoinBase ( ) )
return error ( " AcceptTransaction() : coinbase as individual tx " ) ;
if ( ! CheckTransaction ( ) )
return error ( " AcceptTransaction() : CheckTransaction failed " ) ;
// To help v0.1.5 clients who would see it as negative number. please delete this later.
if ( nLockTime > INT_MAX )
return error ( " AcceptTransaction() : not accepting nLockTime beyond 2038 " ) ;
// Do we already have it?
uint256 hash = GetHash ( ) ;
CRITICAL_BLOCK ( cs_mapTransactions )
if ( mapTransactions . count ( hash ) )
return false ;
if ( fCheckInputs )
if ( txdb . ContainsTx ( hash ) )
return false ;
// Check for conflicts with in-memory transactions
CTransaction * ptxOld = NULL ;
for ( int i = 0 ; i < vin . size ( ) ; i + + )
{
COutPoint outpoint = vin [ i ] . prevout ;
if ( mapNextTx . count ( outpoint ) )
{
// Allow replacing with a newer version of the same transaction
if ( i ! = 0 )
return false ;
ptxOld = mapNextTx [ outpoint ] . ptx ;
if ( ! IsNewerThan ( * ptxOld ) )
return false ;
for ( int i = 0 ; i < vin . size ( ) ; i + + )
{
COutPoint outpoint = vin [ i ] . prevout ;
if ( ! mapNextTx . count ( outpoint ) | | mapNextTx [ outpoint ] . ptx ! = ptxOld )
return false ;
}
break ;
}
}
// Check against previous transactions
map < uint256 , CTxIndex > mapUnused ;
int64 nFees = 0 ;
if ( fCheckInputs & & ! ConnectInputs ( txdb , mapUnused , CDiskTxPos ( 1 , 1 , 1 ) , 0 , nFees , false , false ) )
{
if ( pfMissingInputs )
* pfMissingInputs = true ;
return error ( " AcceptTransaction() : ConnectInputs failed % s " , hash.ToString().substr(0,6).c_str()) ;
}
// Store transaction in memory
CRITICAL_BLOCK ( cs_mapTransactions )
{
if ( ptxOld )
{
printf ( " mapTransaction.erase(%s) replacing with new version \n " , ptxOld - > GetHash ( ) . ToString ( ) . c_str ( ) ) ;
mapTransactions . erase ( ptxOld - > GetHash ( ) ) ;
}
AddToMemoryPool ( ) ;
}
///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet
if ( ptxOld )
EraseFromWallet ( ptxOld - > GetHash ( ) ) ;
printf ( " AcceptTransaction(): accepted %s \n " , hash . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) ) ;
return true ;
}
bool CTransaction : : AddToMemoryPool ( )
{
// Add to memory pool without checking anything. Don't call this directly,
// call AcceptTransaction to properly check the transaction first.
CRITICAL_BLOCK ( cs_mapTransactions )
{
uint256 hash = GetHash ( ) ;
mapTransactions [ hash ] = * this ;
for ( int i = 0 ; i < vin . size ( ) ; i + + )
mapNextTx [ vin [ i ] . prevout ] = CInPoint ( & mapTransactions [ hash ] , i ) ;
nTransactionsUpdated + + ;
}
return true ;
}
bool CTransaction : : RemoveFromMemoryPool ( )
{
// Remove transaction from memory pool
CRITICAL_BLOCK ( cs_mapTransactions )
{
foreach ( const CTxIn & txin , vin )
mapNextTx . erase ( txin . prevout ) ;
mapTransactions . erase ( GetHash ( ) ) ;
nTransactionsUpdated + + ;
}
return true ;
}
int CMerkleTx : : GetDepthInMainChain ( ) const
{
if ( hashBlock = = 0 | | nIndex = = - 1 )
return 0 ;
// Find the block it claims to be in
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
if ( mi = = mapBlockIndex . end ( ) )
return 0 ;
CBlockIndex * pindex = ( * mi ) . second ;
if ( ! pindex | | ! pindex - > IsInMainChain ( ) )
return 0 ;
// Make sure the merkle branch connects to this block
if ( ! fMerkleVerified )
{
if ( CBlock : : CheckMerkleBranch ( GetHash ( ) , vMerkleBranch , nIndex ) ! = pindex - > hashMerkleRoot )
return 0 ;
fMerkleVerified = true ;
}
return pindexBest - > nHeight - pindex - > nHeight + 1 ;
}
int CMerkleTx : : GetBlocksToMaturity ( ) const
{
if ( ! IsCoinBase ( ) )
return 0 ;
return max ( 0 , ( COINBASE_MATURITY + 20 ) - GetDepthInMainChain ( ) ) ;
}
bool CMerkleTx : : AcceptTransaction ( CTxDB & txdb , bool fCheckInputs )
{
if ( fClient )
{
if ( ! IsInMainChain ( ) & & ! ClientConnectInputs ( ) )
return false ;
return CTransaction : : AcceptTransaction ( txdb , false ) ;
}
else
{
return CTransaction : : AcceptTransaction ( txdb , fCheckInputs ) ;
}
}
bool CWalletTx : : AcceptWalletTransaction ( CTxDB & txdb , bool fCheckInputs )
{
CRITICAL_BLOCK ( cs_mapTransactions )
{
foreach ( CMerkleTx & tx , vtxPrev )
{
if ( ! tx . IsCoinBase ( ) )
{
uint256 hash = tx . GetHash ( ) ;
if ( ! mapTransactions . count ( hash ) & & ! txdb . ContainsTx ( hash ) )
tx . AcceptTransaction ( txdb , fCheckInputs ) ;
}
}
if ( ! IsCoinBase ( ) )
return AcceptTransaction ( txdb , fCheckInputs ) ;
}
return true ;
}
void ReacceptWalletTransactions ( )
{
// Reaccept any txes of ours that aren't already in a block
CTxDB txdb ( " r " ) ;
CRITICAL_BLOCK ( cs_mapWallet )
{
foreach ( PAIRTYPE ( const uint256 , CWalletTx ) & item , mapWallet )
{
CWalletTx & wtx = item . second ;
if ( ! wtx . IsCoinBase ( ) & & ! txdb . ContainsTx ( wtx . GetHash ( ) ) )
wtx . AcceptWalletTransaction ( txdb , false ) ;
}
}
}
void CWalletTx : : RelayWalletTransaction ( CTxDB & txdb )
{
foreach ( const CMerkleTx & tx , vtxPrev )
{
if ( ! tx . IsCoinBase ( ) )
{
uint256 hash = tx . GetHash ( ) ;
if ( ! txdb . ContainsTx ( hash ) )
RelayMessage ( CInv ( MSG_TX , hash ) , ( CTransaction ) tx ) ;
}
}
if ( ! IsCoinBase ( ) )
{
uint256 hash = GetHash ( ) ;
if ( ! txdb . ContainsTx ( hash ) )
{
printf ( " Relaying wtx %s \n " , hash . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) ) ;
RelayMessage ( CInv ( MSG_TX , hash ) , ( CTransaction ) * this ) ;
}
}
}
void RelayWalletTransactions ( )
{
static int64 nLastTime ;
if ( GetTime ( ) - nLastTime < 10 * 60 )
return ;
nLastTime = GetTime ( ) ;
// Rebroadcast any of our txes that aren't in a block yet
printf ( " RelayWalletTransactions() \n " ) ;
CTxDB txdb ( " r " ) ;
CRITICAL_BLOCK ( cs_mapWallet )
{
// Sort them in chronological order
multimap < unsigned int , CWalletTx * > mapSorted ;
foreach ( PAIRTYPE ( const uint256 , CWalletTx ) & item , mapWallet )
{
CWalletTx & wtx = item . second ;
mapSorted . insert ( make_pair ( wtx . nTimeReceived , & wtx ) ) ;
}
foreach ( PAIRTYPE ( const unsigned int , CWalletTx * ) & item , mapSorted )
{
CWalletTx & wtx = * item . second ;
wtx . RelayWalletTransaction ( txdb ) ;
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// CBlock and CBlockIndex
//
bool CBlock : : ReadFromDisk ( const CBlockIndex * pblockindex , bool fReadTransactions )
{
return ReadFromDisk ( pblockindex - > nFile , pblockindex - > nBlockPos , fReadTransactions ) ;
}
uint256 GetOrphanRoot ( const CBlock * pblock )
{
// Work back to the first block in the orphan chain
while ( mapOrphanBlocks . count ( pblock - > hashPrevBlock ) )
pblock = mapOrphanBlocks [ pblock - > hashPrevBlock ] ;
return pblock - > GetHash ( ) ;
}
int64 CBlock : : GetBlockValue ( int64 nFees ) const
{
int64 nSubsidy = 50 * COIN ;
// Subsidy is cut in half every 4 years
nSubsidy > > = ( nBestHeight / 210000 ) ;
return nSubsidy + nFees ;
}
unsigned int GetNextWorkRequired ( const CBlockIndex * pindexLast )
{
const unsigned int nTargetTimespan = 14 * 24 * 60 * 60 ; // two weeks
const unsigned int nTargetSpacing = 10 * 60 ;
const unsigned int nInterval = nTargetTimespan / nTargetSpacing ;
// Genesis block
if ( pindexLast = = NULL )
return bnProofOfWorkLimit . GetCompact ( ) ;
// Only change once per interval
if ( ( pindexLast - > nHeight + 1 ) % nInterval ! = 0 )
return pindexLast - > nBits ;
// Go back by what we want to be 14 days worth of blocks
const CBlockIndex * pindexFirst = pindexLast ;
for ( int i = 0 ; pindexFirst & & i < nInterval - 1 ; i + + )
pindexFirst = pindexFirst - > pprev ;
assert ( pindexFirst ) ;
// Limit adjustment step
unsigned int nActualTimespan = pindexLast - > nTime - pindexFirst - > nTime ;
printf ( " nActualTimespan = %d before bounds \n " , nActualTimespan ) ;
if ( nActualTimespan < nTargetTimespan / 4 )
nActualTimespan = nTargetTimespan / 4 ;
if ( nActualTimespan > nTargetTimespan * 4 )
nActualTimespan = nTargetTimespan * 4 ;
// Retarget
CBigNum bnNew ;
bnNew . SetCompact ( pindexLast - > nBits ) ;
bnNew * = nActualTimespan ;
bnNew / = nTargetTimespan ;
if ( bnNew > bnProofOfWorkLimit )
bnNew = bnProofOfWorkLimit ;
/// debug print
printf ( " \n \n \n GetNextWorkRequired RETARGET ***** \n " ) ;
printf ( " nTargetTimespan = %d nActualTimespan = %d \n " , nTargetTimespan , nActualTimespan ) ;
printf ( " Before: %08x %s \n " , pindexLast - > nBits , CBigNum ( ) . SetCompact ( pindexLast - > nBits ) . getuint256 ( ) . ToString ( ) . c_str ( ) ) ;
printf ( " After: %08x %s \n " , bnNew . GetCompact ( ) , bnNew . getuint256 ( ) . ToString ( ) . c_str ( ) ) ;
return bnNew . GetCompact ( ) ;
}
bool CTransaction : : DisconnectInputs ( CTxDB & txdb )
{
// Relinquish previous transactions' spent pointers
if ( ! IsCoinBase ( ) )
{
foreach ( const CTxIn & txin , vin )
{
COutPoint prevout = txin . prevout ;
// Get prev txindex from disk
CTxIndex txindex ;
if ( ! txdb . ReadTxIndex ( prevout . hash , txindex ) )
return error ( " DisconnectInputs() : ReadTxIndex failed " ) ;
if ( prevout . n > = txindex . vSpent . size ( ) )
return error ( " DisconnectInputs() : prevout . n out of range " ) ;
// Mark outpoint as not spent
txindex . vSpent [ prevout . n ] . SetNull ( ) ;
// Write back
txdb . UpdateTxIndex ( prevout . hash , txindex ) ;
}
}
// Remove transaction from index
if ( ! txdb . EraseTxIndex ( * this ) )
return error ( " DisconnectInputs() : EraseTxPos failed " ) ;
return true ;
}
bool CTransaction : : ConnectInputs ( CTxDB & txdb , map < uint256 , CTxIndex > & mapTestPool , CDiskTxPos posThisTx , int nHeight , int64 & nFees , bool fBlock , bool fMiner , int64 nMinFee )
{
// Take over previous transactions' spent pointers
if ( ! IsCoinBase ( ) )
{
int64 nValueIn = 0 ;
for ( int i = 0 ; i < vin . size ( ) ; i + + )
{
COutPoint prevout = vin [ i ] . prevout ;
// Read txindex
CTxIndex txindex ;
bool fFound = true ;
if ( fMiner & & mapTestPool . count ( prevout . hash ) )
{
// Get txindex from current proposed changes
txindex = mapTestPool [ prevout . hash ] ;
}
else
{
// Read txindex from txdb
fFound = txdb . ReadTxIndex ( prevout . hash , txindex ) ;
}
if ( ! fFound & & ( fBlock | | fMiner ) )
return fMiner ? false : error ( " ConnectInputs() : %s prev tx %s index entry not found " , GetHash ( ) . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) , prevout . hash . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) ) ;
// Read txPrev
CTransaction txPrev ;
if ( ! fFound | | txindex . pos = = CDiskTxPos ( 1 , 1 , 1 ) )
{
// Get prev tx from single transactions in memory
CRITICAL_BLOCK ( cs_mapTransactions )
{
if ( ! mapTransactions . count ( prevout . hash ) )
return error ( " ConnectInputs() : % s mapTransactions prev not found % s " , GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str()) ;
txPrev = mapTransactions [ prevout . hash ] ;
}
if ( ! fFound )
txindex . vSpent . resize ( txPrev . vout . size ( ) ) ;
}
else
{
// Get prev tx from disk
if ( ! txPrev . ReadFromDisk ( txindex . pos ) )
return error ( " ConnectInputs() : % s ReadFromDisk prev tx % s failed " , GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str()) ;
}
if ( prevout . n > = txPrev . vout . size ( ) | | prevout . n > = txindex . vSpent . size ( ) )
return error ( " ConnectInputs() : % s prevout . n out of range % d % d % d " , GetHash().ToString().substr(0,6).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size()) ;
// If prev is coinbase, check that it's matured
if ( txPrev . IsCoinBase ( ) )
for ( CBlockIndex * pindex = pindexBest ; pindex & & nBestHeight - pindex - > nHeight < COINBASE_MATURITY - 1 ; pindex = pindex - > pprev )
if ( pindex - > nBlockPos = = txindex . pos . nBlockPos & & pindex - > nFile = = txindex . pos . nFile )
return error ( " ConnectInputs() : tried to spend coinbase at depth % d " , nBestHeight - pindex->nHeight) ;
// Verify signature
if ( ! VerifySignature ( txPrev , * this , i ) )
return error ( " ConnectInputs() : % s VerifySignature failed " , GetHash().ToString().substr(0,6).c_str()) ;
// Check for conflicts
if ( ! txindex . vSpent [ prevout . n ] . IsNull ( ) )
return fMiner ? false : error ( " ConnectInputs() : %s prev tx already used at %s " , GetHash ( ) . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) , txindex . vSpent [ prevout . n ] . ToString ( ) . c_str ( ) ) ;
// Mark outpoints as spent
txindex . vSpent [ prevout . n ] = posThisTx ;
// Write back
if ( fBlock )
txdb . UpdateTxIndex ( prevout . hash , txindex ) ;
else if ( fMiner )
mapTestPool [ prevout . hash ] = txindex ;
nValueIn + = txPrev . vout [ prevout . n ] . nValue ;
}
// Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut ( ) ;
if ( nTxFee < 0 )
return error ( " ConnectInputs() : % s nTxFee < 0 " , GetHash().ToString().substr(0,6).c_str()) ;
if ( nTxFee < nMinFee )
return false ;
nFees + = nTxFee ;
}
if ( fBlock )
{
// Add transaction to disk index
if ( ! txdb . AddTxIndex ( * this , posThisTx , nHeight ) )
return error ( " ConnectInputs() : AddTxPos failed " ) ;
}
else if ( fMiner )
{
// Add transaction to test pool
mapTestPool [ GetHash ( ) ] = CTxIndex ( CDiskTxPos ( 1 , 1 , 1 ) , vout . size ( ) ) ;
}
return true ;
}
bool CTransaction : : ClientConnectInputs ( )
{
if ( IsCoinBase ( ) )
return false ;
// Take over previous transactions' spent pointers
CRITICAL_BLOCK ( cs_mapTransactions )
{
int64 nValueIn = 0 ;
for ( int i = 0 ; i < vin . size ( ) ; i + + )
{
// Get prev tx from single transactions in memory
COutPoint prevout = vin [ i ] . prevout ;
if ( ! mapTransactions . count ( prevout . hash ) )
return false ;
CTransaction & txPrev = mapTransactions [ prevout . hash ] ;
if ( prevout . n > = txPrev . vout . size ( ) )
return false ;
// Verify signature
if ( ! VerifySignature ( txPrev , * this , i ) )
return error ( " ConnectInputs() : VerifySignature failed " ) ;
///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
///// this has to go away now that posNext is gone
// // Check for conflicts
// if (!txPrev.vout[prevout.n].posNext.IsNull())
// return error("ConnectInputs() : prev tx already used");
//
// // Flag outpoints as used
// txPrev.vout[prevout.n].posNext = posThisTx;
nValueIn + = txPrev . vout [ prevout . n ] . nValue ;
}
if ( GetValueOut ( ) > nValueIn )
return false ;
}
return true ;
}
bool CBlock : : DisconnectBlock ( CTxDB & txdb , CBlockIndex * pindex )
{
// Disconnect in reverse order
for ( int i = vtx . size ( ) - 1 ; i > = 0 ; i - - )
if ( ! vtx [ i ] . DisconnectInputs ( txdb ) )
return false ;
// Update block index on disk without changing it in memory.
// The memory index structure will be changed after the db commits.
if ( pindex - > pprev )
{
CDiskBlockIndex blockindexPrev ( pindex - > pprev ) ;
blockindexPrev . hashNext = 0 ;
txdb . WriteBlockIndex ( blockindexPrev ) ;
}
return true ;
}
bool CBlock : : ConnectBlock ( CTxDB & txdb , CBlockIndex * pindex )
{
//// 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 ;
int64 nFees = 0 ;
foreach ( CTransaction & tx , vtx )
{
CDiskTxPos posThisTx ( pindex - > nFile , pindex - > nBlockPos , nTxPos ) ;
nTxPos + = : : GetSerializeSize ( tx , SER_DISK ) ;
if ( ! tx . ConnectInputs ( txdb , mapUnused , posThisTx , pindex - > nHeight , nFees , true , false ) )
return false ;
}
if ( vtx [ 0 ] . GetValueOut ( ) > GetBlockValue ( nFees ) )
return false ;
// Update block index on disk without changing it in memory.
// The memory index structure will be changed after the db commits.
if ( pindex - > pprev )
{
CDiskBlockIndex blockindexPrev ( pindex - > pprev ) ;
blockindexPrev . hashNext = pindex - > GetBlockHash ( ) ;
txdb . WriteBlockIndex ( blockindexPrev ) ;
}
// Watch for transactions paying to me
foreach ( CTransaction & tx , vtx )
AddToWalletIfMine ( tx , this ) ;
return true ;
}
bool Reorganize ( CTxDB & txdb , CBlockIndex * pindexNew )
{
printf ( " *** REORGANIZE *** \n " ) ;
// Find the fork
CBlockIndex * pfork = pindexBest ;
CBlockIndex * plonger = pindexNew ;
while ( pfork ! = plonger )
{
if ( ! ( pfork = pfork - > pprev ) )
return error ( " Reorganize() : pfork - > pprev is null " ) ;
while ( plonger - > nHeight > pfork - > nHeight )
if ( ! ( plonger = plonger - > pprev ) )
return error ( " Reorganize() : plonger - > pprev is null " ) ;
}
// List of what to disconnect
vector < CBlockIndex * > vDisconnect ;
for ( CBlockIndex * pindex = pindexBest ; pindex ! = pfork ; pindex = pindex - > pprev )
vDisconnect . push_back ( pindex ) ;
// List of what to connect
vector < CBlockIndex * > vConnect ;
for ( CBlockIndex * pindex = pindexNew ; pindex ! = pfork ; pindex = pindex - > pprev )
vConnect . push_back ( pindex ) ;
reverse ( vConnect . begin ( ) , vConnect . end ( ) ) ;
// Disconnect shorter branch
vector < CTransaction > vResurrect ;
foreach ( CBlockIndex * pindex , vDisconnect )
{
CBlock block ;
if ( ! block . ReadFromDisk ( pindex - > nFile , pindex - > nBlockPos , true ) )
return error ( " Reorganize() : ReadFromDisk for disconnect failed " ) ;
if ( ! block . DisconnectBlock ( txdb , pindex ) )
return error ( " Reorganize() : DisconnectBlock failed " ) ;
// Queue memory transactions to resurrect
foreach ( const CTransaction & tx , block . vtx )
if ( ! tx . IsCoinBase ( ) )
vResurrect . push_back ( tx ) ;
}
// Connect longer branch
vector < CTransaction > vDelete ;
for ( int i = 0 ; i < vConnect . size ( ) ; i + + )
{
CBlockIndex * pindex = vConnect [ i ] ;
CBlock block ;
if ( ! block . ReadFromDisk ( pindex - > nFile , pindex - > nBlockPos , true ) )
return error ( " Reorganize() : ReadFromDisk for connect failed " ) ;
if ( ! block . ConnectBlock ( txdb , pindex ) )
{
// Invalid block, delete the rest of this branch
txdb . TxnAbort ( ) ;
for ( int j = i ; j < vConnect . size ( ) ; j + + )
{
CBlockIndex * pindex = vConnect [ j ] ;
pindex - > EraseBlockFromDisk ( ) ;
txdb . EraseBlockIndex ( pindex - > GetBlockHash ( ) ) ;
mapBlockIndex . erase ( pindex - > GetBlockHash ( ) ) ;
delete pindex ;
}
return error ( " Reorganize() : ConnectBlock failed " ) ;
}
// Queue memory transactions to delete
foreach ( const CTransaction & tx , block . vtx )
vDelete . push_back ( tx ) ;
}
if ( ! txdb . WriteHashBestChain ( pindexNew - > GetBlockHash ( ) ) )
return error ( " Reorganize() : WriteHashBestChain failed " ) ;
// Commit now because resurrecting could take some time
txdb . TxnCommit ( ) ;
// Disconnect shorter branch
foreach ( CBlockIndex * pindex , vDisconnect )
if ( pindex - > pprev )
pindex - > pprev - > pnext = NULL ;
// Connect longer branch
foreach ( CBlockIndex * pindex , vConnect )
if ( pindex - > pprev )
pindex - > pprev - > pnext = pindex ;
// Resurrect memory transactions that were in the disconnected branch
foreach ( CTransaction & tx , vResurrect )
tx . AcceptTransaction ( txdb , false ) ;
// Delete redundant memory transactions that are in the connected branch
foreach ( CTransaction & tx , vDelete )
tx . RemoveFromMemoryPool ( ) ;
return true ;
}
bool CBlock : : AddToBlockIndex ( unsigned int nFile , unsigned int nBlockPos )
{
// Check for duplicate
uint256 hash = GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
return error ( " AddToBlockIndex() : % s already exists " , hash.ToString().substr(0,14).c_str()) ;
// Construct new block index object
CBlockIndex * pindexNew = new CBlockIndex ( nFile , nBlockPos , * this ) ;
if ( ! pindexNew )
return error ( " AddToBlockIndex() : new CBlockIndex failed " ) ;
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . insert ( make_pair ( hash , pindexNew ) ) . first ;
pindexNew - > phashBlock = & ( ( * mi ) . first ) ;
map < uint256 , CBlockIndex * > : : iterator miPrev = mapBlockIndex . find ( hashPrevBlock ) ;
if ( miPrev ! = mapBlockIndex . end ( ) )
{
pindexNew - > pprev = ( * miPrev ) . second ;
pindexNew - > nHeight = pindexNew - > pprev - > nHeight + 1 ;
}
CTxDB txdb ;
txdb . TxnBegin ( ) ;
txdb . WriteBlockIndex ( CDiskBlockIndex ( pindexNew ) ) ;
// New best
if ( pindexNew - > nHeight > nBestHeight )
{
if ( pindexGenesisBlock = = NULL & & hash = = hashGenesisBlock )
{
pindexGenesisBlock = pindexNew ;
txdb . WriteHashBestChain ( hash ) ;
}
else if ( hashPrevBlock = = hashBestChain )
{
// Adding to current best branch
if ( ! ConnectBlock ( txdb , pindexNew ) | | ! txdb . WriteHashBestChain ( hash ) )
{
txdb . TxnAbort ( ) ;
pindexNew - > EraseBlockFromDisk ( ) ;
mapBlockIndex . erase ( pindexNew - > GetBlockHash ( ) ) ;
delete pindexNew ;
return error ( " AddToBlockIndex() : ConnectBlock failed " ) ;
}
txdb . TxnCommit ( ) ;
pindexNew - > pprev - > pnext = pindexNew ;
// Delete redundant memory transactions
foreach ( CTransaction & tx , vtx )
tx . RemoveFromMemoryPool ( ) ;
}
else
{
// New best branch
if ( ! Reorganize ( txdb , pindexNew ) )
{
txdb . TxnAbort ( ) ;
return error ( " AddToBlockIndex() : Reorganize failed " ) ;
}
}
// New best link
hashBestChain = hash ;
pindexBest = pindexNew ;
nBestHeight = pindexBest - > nHeight ;
nTransactionsUpdated + + ;
printf ( " AddToBlockIndex: new best=%s height=%d \n " , hashBestChain . ToString ( ) . substr ( 0 , 14 ) . c_str ( ) , nBestHeight ) ;
}
txdb . TxnCommit ( ) ;
txdb . Close ( ) ;
if ( pindexNew = = pindexBest )
{
// Relay wallet transactions that haven't gotten in yet
RelayWalletTransactions ( ) ;
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase ;
CRITICAL_BLOCK ( cs_mapWallet )
vWalletUpdated . push_back ( hashPrevBestCoinBase ) ;
hashPrevBestCoinBase = vtx [ 0 ] . GetHash ( ) ;
}
MainFrameRepaint ( ) ;
return true ;
}
bool CBlock : : CheckBlock ( ) const
{
// 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_SIZE | | : : GetSerializeSize ( * this , SER_DISK ) > MAX_SIZE )
return error ( " CheckBlock() : size limits failed " ) ;
// Check timestamp
if ( nTime > GetAdjustedTime ( ) + 2 * 60 * 60 )
return 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 ( ) )
return error ( " CheckBlock() : first tx is not coinbase " ) ;
for ( int i = 1 ; i < vtx . size ( ) ; i + + )
if ( vtx [ i ] . IsCoinBase ( ) )
return error ( " CheckBlock() : more than one coinbase " ) ;
// Check transactions
foreach ( const CTransaction & tx , vtx )
if ( ! tx . CheckTransaction ( ) )
return error ( " CheckBlock() : CheckTransaction failed " ) ;
// Check proof of work matches claimed amount
if ( CBigNum ( ) . SetCompact ( nBits ) > bnProofOfWorkLimit )
return error ( " CheckBlock() : nBits below minimum work " ) ;
if ( GetHash ( ) > CBigNum ( ) . SetCompact ( nBits ) . getuint256 ( ) )
return error ( " CheckBlock() : hash doesn ' t match nBits " ) ;
// Check merkleroot
if ( hashMerkleRoot ! = BuildMerkleTree ( ) )
return error ( " CheckBlock() : hashMerkleRoot mismatch " ) ;
return true ;
}
bool CBlock : : AcceptBlock ( )
{
// Check for duplicate
uint256 hash = GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
return error ( " AcceptBlock() : block already in mapBlockIndex " ) ;
// Get prev block index
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( hashPrevBlock ) ;
if ( mi = = mapBlockIndex . end ( ) )
return error ( " AcceptBlock() : prev block not found " ) ;
CBlockIndex * pindexPrev = ( * mi ) . second ;
// Check timestamp against prev
if ( nTime < = pindexPrev - > GetMedianTimePast ( ) )
return error ( " AcceptBlock() : block ' s timestamp is too early " ) ;
// Check that all transactions are finalized (starting around 30 Nov 2009)
if ( nBestHeight > 31000 ) // 25620 + 5320
foreach ( const CTransaction & tx , vtx )
if ( ! tx . IsFinal ( nTime ) )
return error ( " AcceptBlock() : contains a non - final transaction " ) ;
// Check proof of work
if ( nBits ! = GetNextWorkRequired ( pindexPrev ) )
return error ( " AcceptBlock() : incorrect proof of work " ) ;
// Write block to history file
if ( ! CheckDiskSpace ( : : GetSerializeSize ( * this , SER_DISK ) ) )
return error ( " AcceptBlock() : out of disk space " ) ;
unsigned int nFile ;
unsigned int nBlockPos ;
if ( ! WriteToDisk ( ! fClient , nFile , nBlockPos ) )
return error ( " AcceptBlock() : WriteToDisk failed " ) ;
if ( ! AddToBlockIndex ( nFile , nBlockPos ) )
return error ( " AcceptBlock() : AddToBlockIndex failed " ) ;
if ( hashBestChain = = hash )
RelayInventory ( CInv ( MSG_BLOCK , hash ) ) ;
// // Add atoms to user reviews for coins created
// vector<unsigned char> vchPubKey;
// if (ExtractPubKey(vtx[0].vout[0].scriptPubKey, false, vchPubKey))
// {
// unsigned short nAtom = GetRand(USHRT_MAX - 100) + 100;
// vector<unsigned short> vAtoms(1, nAtom);
// AddAtomsAndPropagate(Hash(vchPubKey.begin(), vchPubKey.end()), vAtoms, true);
// }
return true ;
}
bool ProcessBlock ( CNode * pfrom , CBlock * pblock )
{
// Check for duplicate
uint256 hash = pblock - > GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
return error ( " ProcessBlock() : already have block % d % s " , mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,14).c_str()) ;
if ( mapOrphanBlocks . count ( hash ) )
return error ( " ProcessBlock() : already have block ( orphan ) % s " , hash.ToString().substr(0,14).c_str()) ;
// Preliminary checks
if ( ! pblock - > CheckBlock ( ) )
{
delete pblock ;
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
}
// If don't already have its previous block, shunt it off to holding area until we get it
if ( ! mapBlockIndex . count ( pblock - > hashPrevBlock ) )
{
printf ( " ProcessBlock: ORPHAN BLOCK, prev=%s \n " , pblock - > hashPrevBlock . ToString ( ) . substr ( 0 , 14 ) . c_str ( ) ) ;
mapOrphanBlocks . insert ( make_pair ( hash , pblock ) ) ;
mapOrphanBlocksByPrev . insert ( make_pair ( pblock - > hashPrevBlock , pblock ) ) ;
// Ask this guy to fill in what we're missing
if ( pfrom )
pfrom - > PushMessage ( " getblocks " , CBlockLocator ( pindexBest ) , GetOrphanRoot ( pblock ) ) ;
return true ;
}
// Store to disk
if ( ! pblock - > AcceptBlock ( ) )
{
delete pblock ;
return error ( " ProcessBlock() : AcceptBlock FAILED " ) ;
}
delete pblock ;
// Recursively process any orphan blocks that depended on this one
vector < uint256 > vWorkQueue ;
vWorkQueue . push_back ( hash ) ;
for ( int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
{
uint256 hashPrev = vWorkQueue [ i ] ;
for ( multimap < uint256 , CBlock * > : : iterator mi = mapOrphanBlocksByPrev . lower_bound ( hashPrev ) ;
mi ! = mapOrphanBlocksByPrev . upper_bound ( hashPrev ) ;
+ + mi )
{
CBlock * pblockOrphan = ( * mi ) . second ;
if ( pblockOrphan - > AcceptBlock ( ) )
vWorkQueue . push_back ( pblockOrphan - > GetHash ( ) ) ;
mapOrphanBlocks . erase ( pblockOrphan - > GetHash ( ) ) ;
delete pblockOrphan ;
}
mapOrphanBlocksByPrev . erase ( hashPrev ) ;
}
printf ( " ProcessBlock: ACCEPTED \n " ) ;
return true ;
}
template < typename Stream >
bool 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 ;
}
}
string GetAppDir ( )
{
string strDir ;
if ( ! strSetDataDir . empty ( ) )
{
strDir = strSetDataDir ;
}
else if ( getenv ( " APPDATA " ) )
{
strDir = strprintf ( " %s \\ Bitcoin " , getenv ( " APPDATA " ) ) ;
}
else if ( getenv ( " USERPROFILE " ) )
{
string strAppData = strprintf ( " %s \\ Application Data " , getenv ( " USERPROFILE " ) ) ;
static bool fMkdirDone ;
if ( ! fMkdirDone )
{
fMkdirDone = true ;
_mkdir ( strAppData . c_str ( ) ) ;
}
strDir = strprintf ( " %s \\ Bitcoin " , strAppData . c_str ( ) ) ;
}
else
{
return " . " ;
}
static bool fMkdirDone ;
if ( ! fMkdirDone )
{
fMkdirDone = true ;
_mkdir ( strDir . c_str ( ) ) ;
}
return strDir ;
}
bool CheckDiskSpace ( int64 nAdditionalBytes )
{
wxLongLong nFreeBytesAvailable = 0 ;
if ( ! wxGetDiskSpace ( GetDataDir ( ) , NULL , & nFreeBytesAvailable ) )
{
printf ( " ERROR: wxGetDiskSpace() failed \n " ) ;
return true ;
}
// Check for 15MB because database could create another 10MB log file at any time
if ( nFreeBytesAvailable < ( int64 ) 15000000 + nAdditionalBytes )
{
fShutdown = true ;
wxMessageBox ( " Warning: Your disk space is low " , " Bitcoin " , wxICON_EXCLAMATION ) ;
_beginthread ( Shutdown , 0 , NULL ) ;
return false ;
}
return true ;
}
FILE * OpenBlockFile ( unsigned int nFile , unsigned int nBlockPos , const char * pszMode )
{
if ( nFile = = - 1 )
return NULL ;
FILE * file = fopen ( strprintf ( " %s \\ blk%04d.dat " , GetAppDir ( ) . c_str ( ) , nFile ) . c_str ( ) , pszMode ) ;
if ( ! file )
return NULL ;
if ( nBlockPos ! = 0 & & ! strchr ( pszMode , ' a ' ) & & ! strchr ( pszMode , ' w ' ) )
{
if ( fseek ( file , nBlockPos , SEEK_SET ) ! = 0 )
{
fclose ( file ) ;
return NULL ;
}
}
return file ;
}
static unsigned int nCurrentBlockFile = 1 ;
FILE * AppendBlockFile ( unsigned int & nFileRet )
{
nFileRet = 0 ;
loop
{
FILE * file = OpenBlockFile ( nCurrentBlockFile , 0 , " ab " ) ;
if ( ! file )
return NULL ;
if ( fseek ( file , 0 , SEEK_END ) ! = 0 )
return NULL ;
// FAT32 filesize max 4GB, fseek and ftell max 2GB, so we must stay under 2GB
if ( ftell ( file ) < 0x7F000000 - MAX_SIZE )
{
nFileRet = nCurrentBlockFile ;
return file ;
}
fclose ( file ) ;
nCurrentBlockFile + + ;
}
}
bool LoadBlockIndex ( bool fAllowNew )
{
//
// Load block index
//
CTxDB txdb ( " cr " ) ;
if ( ! txdb . LoadBlockIndex ( ) )
return false ;
txdb . Close ( ) ;
//
// Init with genesis block
//
if ( mapBlockIndex . empty ( ) )
{
if ( ! fAllowNew )
return false ;
// Genesis Block:
// GetHash() = 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
// hashMerkleRoot = 0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
// txNew.vin[0].scriptSig = 486604799 4 0x736B6E616220726F662074756F6C69616220646E6F63657320666F206B6E697262206E6F20726F6C6C65636E61684320393030322F6E614A2F33302073656D695420656854
// txNew.vout[0].nValue = 5000000000
// txNew.vout[0].scriptPubKey = 0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704 OP_CHECKSIG
// block.nVersion = 1
// block.nTime = 1231006505
// block.nBits = 0x1d00ffff
// block.nNonce = 2083236893
// 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
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 > ( ( unsigned char * ) pszTimestamp , ( unsigned char * ) pszTimestamp + strlen ( pszTimestamp ) ) ;
txNew . vout [ 0 ] . nValue = 50 * COIN ;
txNew . vout [ 0 ] . scriptPubKey = CScript ( ) < < CBigNum ( " 0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704 " ) < < 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 ;
//// debug print, delete this later
printf ( " %s \n " , block . GetHash ( ) . ToString ( ) . c_str ( ) ) ;
printf ( " %s \n " , block . hashMerkleRoot . ToString ( ) . c_str ( ) ) ;
printf ( " %s \n " , hashGenesisBlock . ToString ( ) . c_str ( ) ) ;
txNew . vout [ 0 ] . scriptPubKey . print ( ) ;
block . print ( ) ;
assert ( block . hashMerkleRoot = = uint256 ( " 0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b " ) ) ;
assert ( block . GetHash ( ) = = hashGenesisBlock ) ;
// Start new block file
unsigned int nFile ;
unsigned int nBlockPos ;
if ( ! block . WriteToDisk ( ! fClient , nFile , nBlockPos ) )
return error ( " LoadBlockIndex() : writing genesis block to disk failed " ) ;
if ( ! block . AddToBlockIndex ( nFile , nBlockPos ) )
return error ( " LoadBlockIndex() : genesis block not accepted " ) ;
}
return true ;
}
void PrintBlockTree ( )
{
// precompute tree structure
map < CBlockIndex * , vector < CBlockIndex * > > mapNext ;
for ( map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . begin ( ) ; mi ! = mapBlockIndex . end ( ) ; + + mi )
{
CBlockIndex * pindex = ( * mi ) . second ;
mapNext [ pindex - > pprev ] . push_back ( pindex ) ;
// test
//while (rand() % 3 == 0)
// mapNext[pindex->pprev].push_back(pindex);
}
vector < pair < int , CBlockIndex * > > vStack ;
vStack . push_back ( make_pair ( 0 , pindexGenesisBlock ) ) ;
int nPrevCol = 0 ;
while ( ! vStack . empty ( ) )
{
int nCol = vStack . back ( ) . first ;
CBlockIndex * pindex = vStack . back ( ) . second ;
vStack . pop_back ( ) ;
// print split or gap
if ( nCol > nPrevCol )
{
for ( int i = 0 ; i < nCol - 1 ; i + + )
printf ( " | " ) ;
printf ( " | \\ \n " ) ;
}
else if ( nCol < nPrevCol )
{
for ( int i = 0 ; i < nCol ; i + + )
printf ( " | " ) ;
printf ( " | \n " ) ;
}
nPrevCol = nCol ;
// print columns
for ( int i = 0 ; i < nCol ; i + + )
printf ( " | " ) ;
// print item
CBlock block ;
block . ReadFromDisk ( pindex , true ) ;
printf ( " %d (%u,%u) %s %s tx %d " ,
pindex - > nHeight ,
pindex - > nFile ,
pindex - > nBlockPos ,
block . GetHash ( ) . ToString ( ) . substr ( 0 , 14 ) . c_str ( ) ,
DateTimeStr ( block . nTime ) . c_str ( ) ,
block . vtx . size ( ) ) ;
CRITICAL_BLOCK ( cs_mapWallet )
{
if ( mapWallet . count ( block . vtx [ 0 ] . GetHash ( ) ) )
{
CWalletTx & wtx = mapWallet [ block . vtx [ 0 ] . GetHash ( ) ] ;
printf ( " mine: %d %d %d " , wtx . GetDepthInMainChain ( ) , wtx . GetBlocksToMaturity ( ) , wtx . GetCredit ( ) ) ;
}
}
printf ( " \n " ) ;
// put the main timechain first
vector < CBlockIndex * > & vNext = mapNext [ pindex ] ;
for ( int i = 0 ; i < vNext . size ( ) ; i + + )
{
if ( vNext [ i ] - > pnext )
{
swap ( vNext [ 0 ] , vNext [ i ] ) ;
break ;
}
}
// iterate children
for ( int i = 0 ; i < vNext . size ( ) ; i + + )
vStack . push_back ( make_pair ( nCol + i , vNext [ i ] ) ) ;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Messages
//
bool AlreadyHave ( CTxDB & txdb , const CInv & inv )
{
switch ( inv . type )
{
case MSG_TX : return mapTransactions . count ( inv . hash ) | | txdb . ContainsTx ( inv . hash ) ;
case MSG_BLOCK : return mapBlockIndex . count ( inv . hash ) | | mapOrphanBlocks . count ( inv . hash ) ;
case MSG_REVIEW : return true ;
case MSG_PRODUCT : return mapProducts . count ( inv . hash ) ;
}
// Don't know what it is, just say we already got one
return true ;
}
bool ProcessMessages ( CNode * pfrom )
{
CDataStream & vRecv = pfrom - > vRecv ;
if ( vRecv . empty ( ) )
return true ;
//printf("ProcessMessages(%d bytes)\n", vRecv.size());
//
// Message format
// (4) message start
// (12) command
// (4) size
// (x) data
//
loop
{
// Scan for message start
CDataStream : : iterator pstart = search ( vRecv . begin ( ) , vRecv . end ( ) , BEGIN ( pchMessageStart ) , END ( pchMessageStart ) ) ;
if ( vRecv . end ( ) - pstart < sizeof ( CMessageHeader ) )
{
if ( vRecv . size ( ) > sizeof ( CMessageHeader ) )
{
printf ( " \n \n PROCESSMESSAGE MESSAGESTART NOT FOUND \n \n " ) ;
vRecv . erase ( vRecv . begin ( ) , vRecv . end ( ) - sizeof ( CMessageHeader ) ) ;
}
break ;
}
if ( pstart - vRecv . begin ( ) > 0 )
printf ( " \n \n PROCESSMESSAGE SKIPPED %d BYTES \n \n " , pstart - vRecv . begin ( ) ) ;
vRecv . erase ( vRecv . begin ( ) , pstart ) ;
// Read header
CMessageHeader hdr ;
vRecv > > hdr ;
if ( ! hdr . IsValid ( ) )
{
printf ( " \n \n PROCESSMESSAGE: ERRORS IN HEADER %s \n \n \n " , hdr . GetCommand ( ) . c_str ( ) ) ;
continue ;
}
string strCommand = hdr . GetCommand ( ) ;
// Message size
unsigned int nMessageSize = hdr . nMessageSize ;
if ( nMessageSize > vRecv . size ( ) )
{
// Rewind and wait for rest of message
///// need a mechanism to give up waiting for overlong message size error
//printf("message-break\n");
vRecv . insert ( vRecv . begin ( ) , BEGIN ( hdr ) , END ( hdr ) ) ;
Sleep ( 100 ) ;
break ;
}
// Copy message to its own buffer
CDataStream vMsg ( vRecv . begin ( ) , vRecv . begin ( ) + nMessageSize , vRecv . nType , vRecv . nVersion ) ;
vRecv . ignore ( nMessageSize ) ;
// Process message
bool fRet = false ;
try
{
CheckForShutdown ( 2 ) ;
CRITICAL_BLOCK ( cs_main )
fRet = ProcessMessage ( pfrom , strCommand , vMsg ) ;
CheckForShutdown ( 2 ) ;
}
catch ( std : : ios_base : : failure & e ) {
if ( strstr ( e . what ( ) , " CDataStream::read() : end of data " ) )
{
// Allow exceptions from underlength message on vRecv
LogException ( & e , " ProcessMessage() " ) ;
}
else
PrintException ( & e , " ProcessMessage() " ) ;
} catch ( std : : exception & e ) {
PrintException ( & e , " ProcessMessage() " ) ;
} catch ( . . . ) {
PrintException ( NULL , " ProcessMessage() " ) ;
}
if ( ! fRet )
printf ( " ProcessMessage(%s, %d bytes) FAILED \n " , strCommand . c_str ( ) , nMessageSize ) ;
}
vRecv . Compact ( ) ;
return true ;
}
bool ProcessMessage ( CNode * pfrom , string strCommand , CDataStream & vRecv )
{
static map < unsigned int , vector < unsigned char > > mapReuseKey ;
RandAddSeedPerfmon ( ) ;
printf ( " received: %s (%d bytes) \n " , strCommand . c_str ( ) , vRecv . size ( ) ) ;
if ( nDropMessagesTest > 0 & & GetRand ( nDropMessagesTest ) = = 0 )
{
printf ( " dropmessages DROPPING RECV MESSAGE \n " ) ;
return true ;
}
if ( strCommand = = " version " )
{
// Each connection can only send one version message
if ( pfrom - > nVersion ! = 0 )
return false ;
int64 nTime ;
CAddress addrMe ;
CAddress addrFrom ;
uint64 nNonce = 1 ;
vRecv > > pfrom - > nVersion > > pfrom - > nServices > > nTime > > addrMe ;
if ( pfrom - > nVersion > = 106 & & ! vRecv . empty ( ) )
vRecv > > addrFrom > > nNonce ;
if ( pfrom - > nVersion = = 0 )
return false ;
// Disconnect if we connected to ourself
if ( nNonce = = nLocalHostNonce )
{
pfrom - > fDisconnect = true ;
pfrom - > vRecv . clear ( ) ;
pfrom - > vSend . clear ( ) ;
return true ;
}
pfrom - > vSend . SetVersion ( min ( pfrom - > nVersion , VERSION ) ) ;
pfrom - > vRecv . SetVersion ( min ( pfrom - > nVersion , VERSION ) ) ;
pfrom - > fClient = ! ( pfrom - > nServices & NODE_NETWORK ) ;
if ( pfrom - > fClient )
{
pfrom - > vSend . nType | = SER_BLOCKHEADERONLY ;
pfrom - > vRecv . nType | = SER_BLOCKHEADERONLY ;
}
AddTimeData ( pfrom - > addr . ip , nTime ) ;
// Ask the first connected node for block updates
static bool fAskedForBlocks ;
if ( ! fAskedForBlocks & & ! pfrom - > fClient )
{
fAskedForBlocks = true ;
pfrom - > PushMessage ( " getblocks " , CBlockLocator ( pindexBest ) , uint256 ( 0 ) ) ;
}
pfrom - > fSuccessfullyConnected = true ;
printf ( " version message: version %d \n " , pfrom - > nVersion ) ;
}
else if ( pfrom - > nVersion = = 0 )
{
// Must have a version message before anything else
return false ;
}
else if ( strCommand = = " addr " )
{
vector < CAddress > vAddr ;
vRecv > > vAddr ;
// Clear addrknown lists periodically to allow refresh broadcasts
static int64 nLastClearedAddrKnown ;
if ( nLastClearedAddrKnown < GetAdjustedTime ( ) - 24 * 60 * 60 )
{
nLastClearedAddrKnown = GetAdjustedTime ( ) ;
CRITICAL_BLOCK ( cs_vNodes )
foreach ( CNode * pnode , vNodes )
pnode - > setAddrKnown . clear ( ) ;
}
// Store the new addresses
CAddrDB addrdb ;
foreach ( const CAddress & addr , vAddr )
{
if ( fShutdown )
return true ;
AddAddress ( addrdb , addr ) ;
pfrom - > AddAddressKnown ( addr ) ;
if ( ! pfrom - > fGetAddr & & addr . IsRoutable ( ) )
{
// Put on lists to send to other nodes
CRITICAL_BLOCK ( cs_vNodes )
foreach ( CNode * pnode , vNodes )
pnode - > PushAddress ( addr ) ;
}
}
pfrom - > fGetAddr = false ;
}
else if ( strCommand = = " inv " )
{
vector < CInv > vInv ;
vRecv > > vInv ;
CTxDB txdb ( " r " ) ;
foreach ( const CInv & inv , vInv )
{
if ( fShutdown )
return true ;
pfrom - > AddInventoryKnown ( inv ) ;
bool fAlreadyHave = AlreadyHave ( txdb , inv ) ;
printf ( " got inventory: %s %s \n " , inv . ToString ( ) . c_str ( ) , fAlreadyHave ? " have " : " new " ) ;
if ( ! fAlreadyHave )
pfrom - > AskFor ( inv ) ;
else if ( inv . type = = MSG_BLOCK & & mapOrphanBlocks . count ( inv . hash ) )
pfrom - > PushMessage ( " getblocks " , CBlockLocator ( pindexBest ) , GetOrphanRoot ( mapOrphanBlocks [ inv . hash ] ) ) ;
}
}
else if ( strCommand = = " getdata " )
{
vector < CInv > vInv ;
vRecv > > vInv ;
foreach ( const CInv & inv , vInv )
{
if ( fShutdown )
return true ;
printf ( " received getdata for: %s \n " , inv . ToString ( ) . c_str ( ) ) ;
if ( inv . type = = MSG_BLOCK )
{
// Send block from disk
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( inv . hash ) ;
if ( mi ! = mapBlockIndex . end ( ) )
{
//// could optimize this to send header straight from blockindex for client
CBlock block ;
block . ReadFromDisk ( ( * mi ) . second , ! pfrom - > fClient ) ;
pfrom - > PushMessage ( " block " , block ) ;
}
}
else if ( inv . IsKnownType ( ) )
{
// Send stream from relay memory
CRITICAL_BLOCK ( cs_mapRelay )
{
map < CInv , CDataStream > : : iterator mi = mapRelay . find ( inv ) ;
if ( mi ! = mapRelay . end ( ) )
pfrom - > PushMessage ( inv . GetCommand ( ) , ( * mi ) . second ) ;
}
}
}
}
else if ( strCommand = = " getblocks " )
{
CBlockLocator locator ;
uint256 hashStop ;
vRecv > > locator > > hashStop ;
// Find the first block the caller has in the main chain
CBlockIndex * pindex = locator . GetBlockIndex ( ) ;
// Send the rest of the chain
if ( pindex )
pindex = pindex - > pnext ;
printf ( " getblocks %d to %s \n " , ( pindex ? pindex - > nHeight : - 1 ) , hashStop . ToString ( ) . substr ( 0 , 14 ) . c_str ( ) ) ;
for ( ; pindex ; pindex = pindex - > pnext )
{
if ( pindex - > GetBlockHash ( ) = = hashStop )
{
printf ( " getblocks stopping at %d %s \n " , pindex - > nHeight , pindex - > GetBlockHash ( ) . ToString ( ) . substr ( 0 , 14 ) . c_str ( ) ) ;
break ;
}
// Bypass setInventoryKnown in case an inventory message got lost
CRITICAL_BLOCK ( pfrom - > cs_inventory )
{
CInv inv ( MSG_BLOCK , pindex - > GetBlockHash ( ) ) ;
// returns true if wasn't already contained in the set
if ( pfrom - > setInventoryKnown2 . insert ( inv ) . second )
{
pfrom - > setInventoryKnown . erase ( inv ) ;
pfrom - > vInventoryToSend . push_back ( inv ) ;
}
}
}
}
else if ( strCommand = = " tx " )
{
vector < uint256 > vWorkQueue ;
CDataStream vMsg ( vRecv ) ;
CTransaction tx ;
vRecv > > tx ;
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
bool fMissingInputs = false ;
if ( tx . AcceptTransaction ( true , & fMissingInputs ) )
{
AddToWalletIfMine ( tx , NULL ) ;
RelayMessage ( inv , vMsg ) ;
mapAlreadyAskedFor . erase ( inv ) ;
vWorkQueue . push_back ( inv . hash ) ;
// Recursively process any orphan transactions that depended on this one
for ( int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
{
uint256 hashPrev = vWorkQueue [ i ] ;
for ( multimap < uint256 , CDataStream * > : : iterator mi = mapOrphanTransactionsByPrev . lower_bound ( hashPrev ) ;
mi ! = mapOrphanTransactionsByPrev . upper_bound ( hashPrev ) ;
+ + mi )
{
const CDataStream & vMsg = * ( ( * mi ) . second ) ;
CTransaction tx ;
CDataStream ( vMsg ) > > tx ;
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
if ( tx . AcceptTransaction ( true ) )
{
printf ( " accepted orphan tx %s \n " , inv . hash . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) ) ;
AddToWalletIfMine ( tx , NULL ) ;
RelayMessage ( inv , vMsg ) ;
mapAlreadyAskedFor . erase ( inv ) ;
vWorkQueue . push_back ( inv . hash ) ;
}
}
}
foreach ( uint256 hash , vWorkQueue )
EraseOrphanTx ( hash ) ;
}
else if ( fMissingInputs )
{
printf ( " storing orphan tx %s \n " , inv . hash . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) ) ;
AddOrphanTx ( vMsg ) ;
}
}
else if ( strCommand = = " review " )
{
CDataStream vMsg ( vRecv ) ;
CReview review ;
vRecv > > review ;
CInv inv ( MSG_REVIEW , review . GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
if ( review . AcceptReview ( ) )
{
// Relay the original message as-is in case it's a higher version than we know how to parse
RelayMessage ( inv , vMsg ) ;
mapAlreadyAskedFor . erase ( inv ) ;
}
}
else if ( strCommand = = " block " )
{
auto_ptr < CBlock > pblock ( new CBlock ) ;
vRecv > > * pblock ;
//// debug print
printf ( " received block: \n " ) ; pblock - > print ( ) ;
CInv inv ( MSG_BLOCK , pblock - > GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
if ( ProcessBlock ( pfrom , pblock . release ( ) ) )
mapAlreadyAskedFor . erase ( inv ) ;
}
else if ( strCommand = = " getaddr " )
{
pfrom - > vAddrToSend . clear ( ) ;
int64 nSince = GetAdjustedTime ( ) - 5 * 24 * 60 * 60 ; // in the last 5 days
CRITICAL_BLOCK ( cs_mapAddresses )
{
unsigned int nSize = mapAddresses . size ( ) ;
foreach ( const PAIRTYPE ( vector < unsigned char > , CAddress ) & item , mapAddresses )
{
if ( fShutdown )
return true ;
const CAddress & addr = item . second ;
if ( addr . nTime > nSince )
pfrom - > PushAddress ( addr ) ;
}
}
}
else if ( strCommand = = " checkorder " )
{
uint256 hashReply ;
CWalletTx order ;
vRecv > > hashReply > > order ;
/// we have a chance to check the order here
// Keep giving the same key to the same ip until they use it
if ( ! mapReuseKey . count ( pfrom - > addr . ip ) )
mapReuseKey [ pfrom - > addr . ip ] = GenerateNewKey ( ) ;
// Send back approval of order and pubkey to use
CScript scriptPubKey ;
scriptPubKey < < mapReuseKey [ pfrom - > addr . ip ] < < OP_CHECKSIG ;
pfrom - > PushMessage ( " reply " , hashReply , ( int ) 0 , scriptPubKey ) ;
}
else if ( strCommand = = " submitorder " )
{
uint256 hashReply ;
CWalletTx wtxNew ;
vRecv > > hashReply > > wtxNew ;
// Broadcast
if ( ! wtxNew . AcceptWalletTransaction ( ) )
{
pfrom - > PushMessage ( " reply " , hashReply , ( int ) 1 ) ;
return error ( " submitorder AcceptWalletTransaction() failed , returning error 1 " ) ;
}
wtxNew . fTimeReceivedIsTxTime = true ;
AddToWallet ( wtxNew ) ;
wtxNew . RelayWalletTransaction ( ) ;
mapReuseKey . erase ( pfrom - > addr . ip ) ;
// Send back confirmation
pfrom - > PushMessage ( " reply " , hashReply , ( int ) 0 ) ;
}
else if ( strCommand = = " reply " )
{
uint256 hashReply ;
vRecv > > hashReply ;
CRequestTracker tracker ;
CRITICAL_BLOCK ( pfrom - > cs_mapRequests )
{
map < uint256 , CRequestTracker > : : iterator mi = pfrom - > mapRequests . find ( hashReply ) ;
if ( mi ! = pfrom - > mapRequests . end ( ) )
{
tracker = ( * mi ) . second ;
pfrom - > mapRequests . erase ( mi ) ;
}
}
if ( ! tracker . IsNull ( ) )
tracker . fn ( tracker . param1 , vRecv ) ;
}
else
{
// Ignore unknown commands for extensibility
}
return true ;
}
bool SendMessages ( CNode * pto )
{
CheckForShutdown ( 2 ) ;
CRITICAL_BLOCK ( cs_main )
{
// Don't send anything until we get their version message
if ( pto - > nVersion = = 0 )
return true ;
//
// Message: addr
//
vector < CAddress > vAddrToSend ;
vAddrToSend . reserve ( pto - > vAddrToSend . size ( ) ) ;
foreach ( const CAddress & addr , pto - > vAddrToSend )
{
// returns true if wasn't already contained in the set
if ( pto - > setAddrKnown . insert ( addr ) . second )
vAddrToSend . push_back ( addr ) ;
}
pto - > vAddrToSend . clear ( ) ;
if ( ! vAddrToSend . empty ( ) )
pto - > PushMessage ( " addr " , vAddrToSend ) ;
//
// Message: inventory
//
vector < CInv > vInventoryToSend ;
CRITICAL_BLOCK ( pto - > cs_inventory )
{
vInventoryToSend . reserve ( pto - > vInventoryToSend . size ( ) ) ;
foreach ( const CInv & inv , pto - > vInventoryToSend )
{
// returns true if wasn't already contained in the set
if ( pto - > setInventoryKnown . insert ( inv ) . second )
vInventoryToSend . push_back ( inv ) ;
}
pto - > vInventoryToSend . clear ( ) ;
pto - > setInventoryKnown2 . clear ( ) ;
}
if ( ! vInventoryToSend . empty ( ) )
pto - > PushMessage ( " inv " , vInventoryToSend ) ;
//
// Message: getdata
//
vector < CInv > vAskFor ;
int64 nNow = GetTime ( ) * 1000000 ;
CTxDB txdb ( " r " ) ;
while ( ! pto - > mapAskFor . empty ( ) & & ( * pto - > mapAskFor . begin ( ) ) . first < = nNow )
{
const CInv & inv = ( * pto - > mapAskFor . begin ( ) ) . second ;
if ( ! AlreadyHave ( txdb , inv ) )
{
printf ( " sending getdata: %s \n " , inv . ToString ( ) . c_str ( ) ) ;
vAskFor . push_back ( inv ) ;
}
pto - > mapAskFor . erase ( pto - > mapAskFor . begin ( ) ) ;
}
if ( ! vAskFor . empty ( ) )
pto - > PushMessage ( " getdata " , vAskFor ) ;
}
return true ;
}
//////////////////////////////////////////////////////////////////////////////
//
// BitcoinMiner
//
void GenerateBitcoins ( bool fGenerate )
{
if ( fGenerateBitcoins ! = fGenerate )
{
fGenerateBitcoins = fGenerate ;
CWalletDB ( ) . WriteSetting ( " fGenerateBitcoins " , fGenerateBitcoins ) ;
MainFrameRepaint ( ) ;
}
if ( fGenerateBitcoins )
{
int nProcessors = atoi ( getenv ( " NUMBER_OF_PROCESSORS " ) ) ;
printf ( " %d processors \n " , nProcessors ) ;
if ( nProcessors < 1 )
nProcessors = 1 ;
if ( fLimitProcessors & & nProcessors > nLimitProcessors )
nProcessors = nLimitProcessors ;
int nAddThreads = nProcessors - vnThreadsRunning [ 3 ] ;
printf ( " Starting %d BitcoinMiner threads \n " , nAddThreads ) ;
for ( int i = 0 ; i < nAddThreads ; i + + )
if ( _beginthread ( ThreadBitcoinMiner , 0 , NULL ) = = - 1 )
printf ( " Error: _beginthread(ThreadBitcoinMiner) failed \n " ) ;
}
}
void ThreadBitcoinMiner ( void * parg )
{
vnThreadsRunning [ 3 ] + + ;
CheckForShutdown ( 3 ) ;
try
{
bool fRet = BitcoinMiner ( ) ;
printf ( " BitcoinMiner returned %s \n " , fRet ? " true " : " false " ) ;
vnThreadsRunning [ 3 ] - - ;
}
catch ( std : : exception & e ) {
vnThreadsRunning [ 3 ] - - ;
PrintException ( & e , " ThreadBitcoinMiner() " ) ;
} catch ( . . . ) {
vnThreadsRunning [ 3 ] - - ;
PrintException ( NULL , " ThreadBitcoinMiner() " ) ;
}
}
int FormatHashBlocks ( void * pbuffer , unsigned int len )
{
unsigned char * pdata = ( unsigned char * ) pbuffer ;
unsigned int blocks = 1 + ( ( len + 8 ) / 64 ) ;
unsigned char * pend = pdata + 64 * blocks ;
memset ( pdata + len , 0 , 64 * blocks - len ) ;
pdata [ len ] = 0x80 ;
unsigned int bits = len * 8 ;
pend [ - 1 ] = ( bits > > 0 ) & 0xff ;
pend [ - 2 ] = ( bits > > 8 ) & 0xff ;
pend [ - 3 ] = ( bits > > 16 ) & 0xff ;
pend [ - 4 ] = ( bits > > 24 ) & 0xff ;
return blocks ;
}
using CryptoPP : : ByteReverse ;
static int detectlittleendian = 1 ;
void BlockSHA256 ( const void * pin , unsigned int nBlocks , void * pout )
{
unsigned int * pinput = ( unsigned int * ) pin ;
unsigned int * pstate = ( unsigned int * ) pout ;
CryptoPP : : SHA256 : : InitState ( pstate ) ;
if ( * ( char * ) & detectlittleendian ! = 0 )
{
for ( int n = 0 ; n < nBlocks ; n + + )
{
unsigned int pbuf [ 16 ] ;
for ( int i = 0 ; i < 16 ; i + + )
pbuf [ i ] = ByteReverse ( pinput [ n * 16 + i ] ) ;
CryptoPP : : SHA256 : : Transform ( pstate , pbuf ) ;
}
for ( int i = 0 ; i < 8 ; i + + )
pstate [ i ] = ByteReverse ( pstate [ i ] ) ;
}
else
{
for ( int n = 0 ; n < nBlocks ; n + + )
CryptoPP : : SHA256 : : Transform ( pstate , pinput + n * 16 ) ;
}
}
bool BitcoinMiner ( )
{
printf ( " BitcoinMiner started \n " ) ;
CKey key ;
key . MakeNewKey ( ) ;
CBigNum bnExtraNonce = 0 ;
while ( fGenerateBitcoins )
{
SetThreadPriority ( GetCurrentThread ( ) , THREAD_PRIORITY_LOWEST ) ;
Sleep ( 50 ) ;
CheckForShutdown ( 3 ) ;
while ( vNodes . empty ( ) )
{
Sleep ( 1000 ) ;
CheckForShutdown ( 3 ) ;
}
unsigned int nTransactionsUpdatedLast = nTransactionsUpdated ;
CBlockIndex * pindexPrev = pindexBest ;
unsigned int nBits = GetNextWorkRequired ( pindexPrev ) ;
//
// Create coinbase tx
//
CTransaction txNew ;
txNew . vin . resize ( 1 ) ;
txNew . vin [ 0 ] . prevout . SetNull ( ) ;
txNew . vin [ 0 ] . scriptSig < < nBits < < + + bnExtraNonce ;
txNew . vout . resize ( 1 ) ;
txNew . vout [ 0 ] . scriptPubKey < < key . GetPubKey ( ) < < OP_CHECKSIG ;
//
// Create new block
//
auto_ptr < CBlock > pblock ( new CBlock ( ) ) ;
if ( ! pblock . get ( ) )
return false ;
// Add our coinbase tx as first transaction
pblock - > vtx . push_back ( txNew ) ;
// Collect the latest transactions into the block
int64 nFees = 0 ;
CRITICAL_BLOCK ( cs_main )
CRITICAL_BLOCK ( cs_mapTransactions )
{
CTxDB txdb ( " r " ) ;
map < uint256 , CTxIndex > mapTestPool ;
vector < char > vfAlreadyAdded ( mapTransactions . size ( ) ) ;
bool fFoundSomething = true ;
unsigned int nBlockSize = 0 ;
while ( fFoundSomething & & nBlockSize < MAX_SIZE / 2 )
{
fFoundSomething = false ;
unsigned int n = 0 ;
for ( map < uint256 , CTransaction > : : iterator mi = mapTransactions . begin ( ) ; mi ! = mapTransactions . end ( ) ; + + mi , + + n )
{
if ( vfAlreadyAdded [ n ] )
continue ;
CTransaction & tx = ( * mi ) . second ;
if ( tx . IsCoinBase ( ) | | ! tx . IsFinal ( ) )
continue ;
// Transaction fee requirements, mainly only needed for flood control
// Under 10K (about 80 inputs) is free for first 100 transactions
// Base rate is 0.01 per KB
int64 nMinFee = tx . GetMinFee ( pblock - > vtx . size ( ) < 100 ) ;
map < uint256 , CTxIndex > mapTestPoolTmp ( mapTestPool ) ;
if ( ! tx . ConnectInputs ( txdb , mapTestPoolTmp , CDiskTxPos ( 1 , 1 , 1 ) , 0 , nFees , false , true , nMinFee ) )
continue ;
swap ( mapTestPool , mapTestPoolTmp ) ;
pblock - > vtx . push_back ( tx ) ;
nBlockSize + = : : GetSerializeSize ( tx , SER_NETWORK ) ;
vfAlreadyAdded [ n ] = true ;
fFoundSomething = true ;
}
}
}
pblock - > nBits = nBits ;
pblock - > vtx [ 0 ] . vout [ 0 ] . nValue = pblock - > GetBlockValue ( nFees ) ;
printf ( " Running BitcoinMiner with %d transactions in block \n " , pblock - > vtx . size ( ) ) ;
//
// Prebuild hash buffer
//
struct unnamed1
{
struct unnamed2
{
int nVersion ;
uint256 hashPrevBlock ;
uint256 hashMerkleRoot ;
unsigned int nTime ;
unsigned int nBits ;
unsigned int nNonce ;
}
block ;
unsigned char pchPadding0 [ 64 ] ;
uint256 hash1 ;
unsigned char pchPadding1 [ 64 ] ;
}
tmp ;
tmp . block . nVersion = pblock - > nVersion ;
tmp . block . hashPrevBlock = pblock - > hashPrevBlock = ( pindexPrev ? pindexPrev - > GetBlockHash ( ) : 0 ) ;
tmp . block . hashMerkleRoot = pblock - > hashMerkleRoot = pblock - > BuildMerkleTree ( ) ;
tmp . block . nTime = pblock - > nTime = max ( ( pindexPrev ? pindexPrev - > GetMedianTimePast ( ) + 1 : 0 ) , GetAdjustedTime ( ) ) ;
tmp . block . nBits = pblock - > nBits = nBits ;
tmp . block . nNonce = pblock - > nNonce = 1 ;
unsigned int nBlocks0 = FormatHashBlocks ( & tmp . block , sizeof ( tmp . block ) ) ;
unsigned int nBlocks1 = FormatHashBlocks ( & tmp . hash1 , sizeof ( tmp . hash1 ) ) ;
//
// Search
//
unsigned int nStart = GetTime ( ) ;
uint256 hashTarget = CBigNum ( ) . SetCompact ( pblock - > nBits ) . getuint256 ( ) ;
uint256 hash ;
loop
{
BlockSHA256 ( & tmp . block , nBlocks0 , & tmp . hash1 ) ;
BlockSHA256 ( & tmp . hash1 , nBlocks1 , & hash ) ;
if ( hash < = hashTarget )
{
pblock - > nNonce = tmp . block . nNonce ;
assert ( hash = = pblock - > GetHash ( ) ) ;
//// debug print
printf ( " BitcoinMiner: \n " ) ;
printf ( " proof-of-work found \n hash: %s \n target: %s \n " , hash . GetHex ( ) . c_str ( ) , hashTarget . GetHex ( ) . c_str ( ) ) ;
pblock - > print ( ) ;
SetThreadPriority ( GetCurrentThread ( ) , THREAD_PRIORITY_NORMAL ) ;
CRITICAL_BLOCK ( cs_main )
{
if ( pindexPrev = = pindexBest )
{
// Save key
if ( ! AddKey ( key ) )
return false ;
key . MakeNewKey ( ) ;
// Process this block the same as if we had received it from another node
if ( ! ProcessBlock ( NULL , pblock . release ( ) ) )
printf ( " ERROR in BitcoinMiner, ProcessBlock, block not accepted \n " ) ;
}
}
SetThreadPriority ( GetCurrentThread ( ) , THREAD_PRIORITY_LOWEST ) ;
Sleep ( 500 ) ;
break ;
}
// Update nTime every few seconds
if ( ( + + tmp . block . nNonce & 0xffff ) = = 0 )
{
CheckForShutdown ( 3 ) ;
if ( tmp . block . nNonce = = 0 )
break ;
if ( pindexPrev ! = pindexBest )
break ;
if ( nTransactionsUpdated ! = nTransactionsUpdatedLast & & GetTime ( ) - nStart > 60 )
break ;
if ( vNodes . empty ( ) )
break ;
if ( ! fGenerateBitcoins )
return true ;
if ( fLimitProcessors & & vnThreadsRunning [ 3 ] > nLimitProcessors )
return true ;
tmp . block . nTime = pblock - > nTime = max ( pindexPrev - > GetMedianTimePast ( ) + 1 , GetAdjustedTime ( ) ) ;
}
}
}
return true ;
}
//////////////////////////////////////////////////////////////////////////////
//
// Actions
//
int64 GetBalance ( )
{
int64 nStart = PerformanceCounter ( ) ;
int64 nTotal = 0 ;
CRITICAL_BLOCK ( cs_mapWallet )
{
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
CWalletTx * pcoin = & ( * it ) . second ;
if ( ! pcoin - > IsFinal ( ) | | pcoin - > fSpent )
continue ;
nTotal + = pcoin - > GetCredit ( ) ;
}
}
///printf(" GetBalance() time = %15"PRI64d"\n", PerformanceCounter() - nStart);
return nTotal ;
}
bool SelectCoins ( int64 nTargetValue , set < CWalletTx * > & setCoinsRet )
{
setCoinsRet . clear ( ) ;
// List of values less than target
int64 nLowestLarger = _I64_MAX ;
CWalletTx * pcoinLowestLarger = NULL ;
vector < pair < int64 , CWalletTx * > > vValue ;
int64 nTotalLower = 0 ;
CRITICAL_BLOCK ( cs_mapWallet )
{
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
CWalletTx * pcoin = & ( * it ) . second ;
if ( ! pcoin - > IsFinal ( ) | | pcoin - > fSpent )
continue ;
int64 n = pcoin - > GetCredit ( ) ;
if ( n < = 0 )
continue ;
if ( n < nTargetValue )
{
vValue . push_back ( make_pair ( n , pcoin ) ) ;
nTotalLower + = n ;
}
else if ( n = = nTargetValue )
{
setCoinsRet . insert ( pcoin ) ;
return true ;
}
else if ( n < nLowestLarger )
{
nLowestLarger = n ;
pcoinLowestLarger = pcoin ;
}
}
}
if ( nTotalLower < nTargetValue )
{
if ( pcoinLowestLarger = = NULL )
return false ;
setCoinsRet . insert ( pcoinLowestLarger ) ;
return true ;
}
// Solve subset sum by stochastic approximation
sort ( vValue . rbegin ( ) , vValue . rend ( ) ) ;
vector < char > vfIncluded ;
vector < char > vfBest ( vValue . size ( ) , true ) ;
int64 nBest = nTotalLower ;
for ( int nRep = 0 ; nRep < 1000 & & nBest ! = nTargetValue ; nRep + + )
{
vfIncluded . assign ( vValue . size ( ) , false ) ;
int64 nTotal = 0 ;
bool fReachedTarget = false ;
for ( int nPass = 0 ; nPass < 2 & & ! fReachedTarget ; nPass + + )
{
for ( int i = 0 ; i < vValue . size ( ) ; i + + )
{
if ( nPass = = 0 ? rand ( ) % 2 : ! vfIncluded [ i ] )
{
nTotal + = vValue [ i ] . first ;
vfIncluded [ i ] = true ;
if ( nTotal > = nTargetValue )
{
fReachedTarget = true ;
if ( nTotal < nBest )
{
nBest = nTotal ;
vfBest = vfIncluded ;
}
nTotal - = vValue [ i ] . first ;
vfIncluded [ i ] = false ;
}
}
}
}
}
// If the next larger is still closer, return it
if ( pcoinLowestLarger & & nLowestLarger - nTargetValue < = nBest - nTargetValue )
setCoinsRet . insert ( pcoinLowestLarger ) ;
else
{
for ( int i = 0 ; i < vValue . size ( ) ; i + + )
if ( vfBest [ i ] )
setCoinsRet . insert ( vValue [ i ] . second ) ;
//// debug print
printf ( " SelectCoins() best subset: " ) ;
for ( int i = 0 ; i < vValue . size ( ) ; i + + )
if ( vfBest [ i ] )
printf ( " %s " , FormatMoney ( vValue [ i ] . first ) . c_str ( ) ) ;
printf ( " total %s \n " , FormatMoney ( nBest ) . c_str ( ) ) ;
}
return true ;
}
bool CreateTransaction ( CScript scriptPubKey , int64 nValue , CWalletTx & wtxNew , CKey & keyRet , int64 & nFeeRequiredRet )
{
nFeeRequiredRet = 0 ;
CRITICAL_BLOCK ( cs_main )
{
// txdb must be opened before the mapWallet lock
CTxDB txdb ( " r " ) ;
CRITICAL_BLOCK ( cs_mapWallet )
{
int64 nFee = nTransactionFee ;
loop
{
wtxNew . vin . clear ( ) ;
wtxNew . vout . clear ( ) ;
if ( nValue < 0 )
return false ;
int64 nValueOut = nValue ;
nValue + = nFee ;
// Choose coins to use
set < CWalletTx * > setCoins ;
if ( ! SelectCoins ( nValue , setCoins ) )
return false ;
int64 nValueIn = 0 ;
foreach ( CWalletTx * pcoin , setCoins )
nValueIn + = pcoin - > GetCredit ( ) ;
// Fill a vout to the payee
bool fChangeFirst = GetRand ( 2 ) ;
if ( ! fChangeFirst )
wtxNew . vout . push_back ( CTxOut ( nValueOut , scriptPubKey ) ) ;
// Fill a vout back to self with any change
if ( nValueIn > nValue )
{
// New private key
if ( keyRet . IsNull ( ) )
keyRet . MakeNewKey ( ) ;
// Fill a vout to ourself
CScript scriptPubKey ;
scriptPubKey < < keyRet . GetPubKey ( ) < < OP_CHECKSIG ;
wtxNew . vout . push_back ( CTxOut ( nValueIn - nValue , scriptPubKey ) ) ;
}
// Fill a vout to the payee
if ( fChangeFirst )
wtxNew . vout . push_back ( CTxOut ( nValueOut , scriptPubKey ) ) ;
// Fill vin
foreach ( CWalletTx * pcoin , setCoins )
for ( int nOut = 0 ; nOut < pcoin - > vout . size ( ) ; nOut + + )
if ( pcoin - > vout [ nOut ] . IsMine ( ) )
wtxNew . vin . push_back ( CTxIn ( pcoin - > GetHash ( ) , nOut ) ) ;
// Sign
int nIn = 0 ;
foreach ( CWalletTx * pcoin , setCoins )
for ( int nOut = 0 ; nOut < pcoin - > vout . size ( ) ; nOut + + )
if ( pcoin - > vout [ nOut ] . IsMine ( ) )
SignSignature ( * pcoin , wtxNew , nIn + + ) ;
// Check that enough fee is included
if ( nFee < wtxNew . GetMinFee ( true ) )
{
nFee = nFeeRequiredRet = wtxNew . GetMinFee ( true ) ;
continue ;
}
// Fill vtxPrev by copying from previous transactions vtxPrev
wtxNew . AddSupportingTransactions ( txdb ) ;
wtxNew . fTimeReceivedIsTxTime = true ;
break ;
}
}
}
return true ;
}
// Call after CreateTransaction unless you want to abort
bool CommitTransactionSpent ( const CWalletTx & wtxNew , const CKey & key )
{
CRITICAL_BLOCK ( cs_main )
CRITICAL_BLOCK ( cs_mapWallet )
{
//// todo: eventually should make this transactional, never want to add a
//// transaction without marking spent transactions, although the risk of
//// interruption during this step is remote.
// This is only to keep the database open to defeat the auto-flush for the
// duration of this scope. This is the only place where this optimization
// maybe makes sense; please don't do it anywhere else. Keeping databases
// open longer than necessary can create deadlocks.
CWalletDB walletdb ( " r " ) ;
// Add the change's private key to wallet
if ( ! key . IsNull ( ) & & ! AddKey ( key ) )
throw runtime_error ( " CommitTransactionSpent() : AddKey failed \ n " ) ;
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
AddToWallet ( wtxNew ) ;
// Mark old coins as spent
set < CWalletTx * > setCoins ;
foreach ( const CTxIn & txin , wtxNew . vin )
setCoins . insert ( & mapWallet [ txin . prevout . hash ] ) ;
foreach ( CWalletTx * pcoin , setCoins )
{
pcoin - > fSpent = true ;
pcoin - > WriteToDisk ( ) ;
vWalletUpdated . push_back ( pcoin - > GetHash ( ) ) ;
}
}
MainFrameRepaint ( ) ;
return true ;
}
bool SendMoney ( CScript scriptPubKey , int64 nValue , CWalletTx & wtxNew )
{
CRITICAL_BLOCK ( cs_main )
{
CKey key ;
int64 nFeeRequired ;
if ( ! CreateTransaction ( scriptPubKey , nValue , wtxNew , key , nFeeRequired ) )
{
string strError ;
if ( nValue + nFeeRequired > GetBalance ( ) )
strError = strprintf ( " Error: This is an oversized transaction that requires a transaction fee of %s " , FormatMoney ( nFeeRequired ) . c_str ( ) ) ;
else
strError = " Error: Transaction creation failed " ;
wxMessageBox ( strError , " Sending... " ) ;
return error ( " SendMoney() : % s " , strError.c_str()) ;
}
if ( ! CommitTransactionSpent ( wtxNew , key ) )
{
wxMessageBox ( " Error finalizing transaction " , " Sending... " ) ;
return error ( " SendMoney() : Error finalizing transaction " ) ;
}
printf ( " SendMoney: %s \n " , wtxNew . GetHash ( ) . ToString ( ) . substr ( 0 , 6 ) . c_str ( ) ) ;
// Broadcast
if ( ! wtxNew . AcceptTransaction ( ) )
{
// This must not fail. The transaction has already been signed and recorded.
throw runtime_error ( " SendMoney() : wtxNew . AcceptTransaction ( ) failed \ n " ) ;
wxMessageBox ( " Error: Transaction not valid " , " Sending... " ) ;
return error ( " SendMoney() : Error : Transaction not valid " ) ;
}
wtxNew . RelayWalletTransaction ( ) ;
}
MainFrameRepaint ( ) ;
return true ;
}