@ -71,66 +71,54 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime ;
return nNewTime - nOldTime ;
}
}
CBlockTemplate * CreateNewBlock ( const CChainParams & chainparams , const CScript & scriptPubKeyIn )
BlockAssembler : : BlockAssembler ( const CChainParams & _chainparams )
: chainparams ( _chainparams )
{
{
// Create new block
std : : unique_ptr < CBlockTemplate > pblocktemplate ( new CBlockTemplate ( ) ) ;
if ( ! pblocktemplate . get ( ) )
return NULL ;
CBlock * pblock = & pblocktemplate - > block ; // pointer for convenience
// Create coinbase tx
CMutableTransaction txNew ;
txNew . vin . resize ( 1 ) ;
txNew . vin [ 0 ] . prevout . SetNull ( ) ;
txNew . vout . resize ( 1 ) ;
txNew . vout [ 0 ] . scriptPubKey = scriptPubKeyIn ;
// Add dummy coinbase tx as first transaction
pblock - > vtx . push_back ( CTransaction ( ) ) ;
pblocktemplate - > vTxFees . push_back ( - 1 ) ; // updated at end
pblocktemplate - > vTxSigOps . push_back ( - 1 ) ; // updated at end
// Largest block you're willing to create:
// Largest block you're willing to create:
unsigned int nBlockMaxSize = GetArg ( " -blockmaxsize " , DEFAULT_BLOCK_MAX_SIZE ) ;
nBlockMaxSize = GetArg ( " -blockmaxsize " , DEFAULT_BLOCK_MAX_SIZE ) ;
// Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity:
// Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity:
nBlockMaxSize = std : : max ( ( unsigned int ) 1000 , std : : min ( ( unsigned int ) ( MAX_BLOCK_SIZE - 1000 ) , nBlockMaxSize ) ) ;
nBlockMaxSize = std : : max ( ( unsigned int ) 1000 , std : : min ( ( unsigned int ) ( MAX_BLOCK_SIZE - 1000 ) , nBlockMaxSize ) ) ;
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay
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
// Minimum block size you want to create; block will be filled with free transactions
// until there are no more or the block reaches this size:
// until there are no more or the block reaches this size:
unsigned int nBlockMinSize = GetArg ( " -blockminsize " , DEFAULT_BLOCK_MIN_SIZE ) ;
nBlockMinSize = GetArg ( " -blockminsize " , DEFAULT_BLOCK_MIN_SIZE ) ;
nBlockMinSize = std : : min ( nBlockMaxSize , nBlockMinSize ) ;
nBlockMinSize = std : : min ( nBlockMaxSize , nBlockMinSize ) ;
}
// Collect memory pool transactions into the block
void BlockAssembler : : resetBlock ( )
CTxMemPool : : setEntries inBlock ;
{
CTxMemPool : : setEntries waitSet ;
inBlock . clear ( ) ;
// This vector will be sorted into a priority queue:
// Reserve space for coinbase tx
vector < TxCoinAgePriority > vecPriority ;
nBlockSize = 1000 ;
TxCoinAgePriorityCompare pricomparer ;
nBlockSigOps = 100 ;
std : : map < CTxMemPool : : txiter , double , CTxMemPool : : CompareIteratorByHash > waitPriMap ;
typedef std : : map < CTxMemPool : : txiter , double , CTxMemPool : : CompareIteratorByHash > : : iterator waitPriIter ;
double actualPriority = - 1 ;
std : : priority_queue < CTxMemPool : : txiter , std : : vector < CTxMemPool : : txiter > , ScoreCompare > clearedTxs ;
// These counters do not include coinbase tx
bool fPrintPriority = GetBoolArg ( " -printpriority " , DEFAULT_PRINTPRIORITY ) ;
nBlockTx = 0 ;
uint64_t nBlockSize = 1000 ;
nFees = 0 ;
uint64_t nBlockTx = 0 ;
unsigned int nBlockSigOps = 100 ;
lastFewTxs = 0 ;
int lastFewTxs = 0 ;
blockFinished = false ;
CAmount nFees = 0 ;
}
CBlockTemplate * BlockAssembler : : CreateNewBlock ( const CScript & scriptPubKeyIn )
{
resetBlock ( ) ;
pblocktemplate . reset ( new CBlockTemplate ( ) ) ;
if ( ! pblocktemplate . get ( ) )
return NULL ;
pblock = & pblocktemplate - > block ; // pointer for convenience
// Add dummy coinbase tx as first transaction
pblock - > vtx . push_back ( CTransaction ( ) ) ;
pblocktemplate - > vTxFees . push_back ( - 1 ) ; // updated at end
pblocktemplate - > vTxSigOps . push_back ( - 1 ) ; // updated at end
{
LOCK2 ( cs_main , mempool . cs ) ;
LOCK2 ( cs_main , mempool . cs ) ;
CBlockIndex * pindexPrev = chainActive . Tip ( ) ;
CBlockIndex * pindexPrev = chainActive . Tip ( ) ;
const int nHeight = pindexPrev - > nHeight + 1 ;
nHeight = pindexPrev - > nHeight + 1 ;
pblock - > nTime = GetAdjustedTime ( ) ;
const int64_t nMedianTimePast = pindexPrev - > GetMedianTimePast ( ) ;
pblock - > nVersion = ComputeBlockVersion ( pindexPrev , chainparams . GetConsensus ( ) ) ;
pblock - > nVersion = ComputeBlockVersion ( pindexPrev , chainparams . GetConsensus ( ) ) ;
// -regtest only: allow overriding block.nVersion with
// -regtest only: allow overriding block.nVersion with
@ -138,133 +126,168 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
if ( chainparams . MineBlocksOnDemand ( ) )
if ( chainparams . MineBlocksOnDemand ( ) )
pblock - > nVersion = GetArg ( " -blockversion " , pblock - > nVersion ) ;
pblock - > nVersion = GetArg ( " -blockversion " , pblock - > nVersion ) ;
int64_t nLockTimeCutoff = ( STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST )
pblock - > nTime = GetAdjustedTime ( ) ;
const int64_t nMedianTimePast = pindexPrev - > GetMedianTimePast ( ) ;
nLockTimeCutoff = ( STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST )
? nMedianTimePast
? nMedianTimePast
: pblock - > GetBlockTime ( ) ;
: pblock - > GetBlockTime ( ) ;
bool fPriorityBlock = nBlockPrioritySize > 0 ;
addPriorityTxs ( ) ;
if ( fPriorityBlock ) {
addScoreTxs ( ) ;
vecPriority . reserve ( mempool . mapTx . size ( ) ) ;
for ( CTxMemPool : : indexed_transaction_set : : iterator mi = mempool . mapTx . begin ( ) ;
mi ! = mempool . mapTx . end ( ) ; + + mi )
{
double dPriority = mi - > GetPriority ( nHeight ) ;
CAmount dummy ;
mempool . ApplyDeltas ( mi - > GetTx ( ) . GetHash ( ) , dPriority , dummy ) ;
vecPriority . push_back ( TxCoinAgePriority ( dPriority , mi ) ) ;
}
std : : make_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , pricomparer ) ;
}
CTxMemPool : : indexed_transaction_set : : index < mining_score > : : type : : iterator mi = mempool . mapTx . get < mining_score > ( ) . begin ( ) ;
nLastBlockTx = nBlockTx ;
CTxMemPool : : txiter iter ;
nLastBlockSize = nBlockSize ;
LogPrintf ( " CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d \n " , nBlockSize , nBlockTx , nFees , nBlockSigOps ) ;
while ( mi ! = mempool . mapTx . get < mining_score > ( ) . end ( ) | | ! clearedTxs . empty ( ) )
// Create coinbase transaction.
{
CMutableTransaction coinbaseTx ;
bool priorityTx = false ;
coinbaseTx . vin . resize ( 1 ) ;
if ( fPriorityBlock & & ! vecPriority . empty ( ) ) { // add a tx from priority queue to fill the blockprioritysize
coinbaseTx . vin [ 0 ] . prevout . SetNull ( ) ;
priorityTx = true ;
coinbaseTx . vout . resize ( 1 ) ;
iter = vecPriority . front ( ) . second ;
coinbaseTx . vout [ 0 ] . scriptPubKey = scriptPubKeyIn ;
actualPriority = vecPriority . front ( ) . first ;
coinbaseTx . vout [ 0 ] . nValue = nFees + GetBlockSubsidy ( nHeight , chainparams . GetConsensus ( ) ) ;
std : : pop_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , pricomparer ) ;
coinbaseTx . vin [ 0 ] . scriptSig = CScript ( ) < < nHeight < < OP_0 ;
vecPriority . pop_back ( ) ;
pblock - > vtx [ 0 ] = coinbaseTx ;
}
pblocktemplate - > vTxFees [ 0 ] = - nFees ;
else if ( clearedTxs . empty ( ) ) { // add tx with next highest score
iter = mempool . mapTx . project < 0 > ( mi ) ;
// Fill in header
mi + + ;
pblock - > hashPrevBlock = pindexPrev - > GetBlockHash ( ) ;
}
UpdateTime ( pblock , chainparams . GetConsensus ( ) , pindexPrev ) ;
else { // try to add a previously postponed child tx
pblock - > nBits = GetNextWorkRequired ( pindexPrev , pblock , chainparams . GetConsensus ( ) ) ;
iter = clearedTxs . top ( ) ;
pblock - > nNonce = 0 ;
clearedTxs . pop ( ) ;
pblocktemplate - > vTxSigOps [ 0 ] = GetLegacySigOpCount ( pblock - > vtx [ 0 ] ) ;
}
if ( inBlock . count ( iter ) )
CValidationState state ;
continue ; // could have been added to the priorityBlock
if ( ! TestBlockValidity ( state , chainparams , * pblock , pindexPrev , false , false ) ) {
throw std : : runtime_error ( strprintf ( " %s: TestBlockValidity failed: %s " , __func__ , FormatStateMessage ( state ) ) ) ;
}
const CTransaction & tx = iter - > GetTx ( ) ;
return pblocktemplate . release ( ) ;
}
bool fOrphan = false ;
bool BlockAssembler : : isStillDependent ( CTxMemPool : : txiter iter )
{
BOOST_FOREACH ( CTxMemPool : : txiter parent , mempool . GetMemPoolParents ( iter ) )
BOOST_FOREACH ( CTxMemPool : : txiter parent , mempool . GetMemPoolParents ( iter ) )
{
{
if ( ! inBlock . count ( parent ) ) {
if ( ! inBlock . count ( parent ) ) {
fOrphan = true ;
return true ;
break ;
}
}
}
}
if ( fOrphan ) {
return false ;
if ( priorityTx )
}
waitPriMap . insert ( std : : make_pair ( iter , actualPriority ) ) ;
else
waitSet . insert ( iter ) ;
continue ;
}
unsigned int nTxSize = iter - > GetTxSize ( ) ;
if ( fPriorityBlock & &
( nBlockSize + nTxSize > = nBlockPrioritySize | | ! AllowFree ( actualPriority ) ) ) {
bool BlockAssembler : : TestForBlock ( CTxMemPool : : txiter iter )
fPriorityBlock = false ;
{
waitPriMap . clear ( ) ;
if ( nBlockSize + iter - > GetTxSize ( ) > = nBlockMaxSize ) {
}
// If the block is so close to full that no more txs will fit
if ( ! priorityTx & &
// or if we've tried more than 50 times to fill remaining space
( iter - > GetModifiedFee ( ) < : : minRelayTxFee . GetFee ( nTxSize ) & & nBlockSize > = nBlockMinSize ) ) {
// then flag that the block is finished
break ;
}
if ( nBlockSize + nTxSize > = nBlockMaxSize ) {
if ( nBlockSize > nBlockMaxSize - 100 | | lastFewTxs > 50 ) {
if ( nBlockSize > nBlockMaxSize - 100 | | lastFewTxs > 50 ) {
break ;
blockFinished = true ;
return false ;
}
}
// Once we're within 1000 bytes of a full block, only look at 50 more txs
// Once we're within 1000 bytes of a full block, only look at 50 more txs
// to try to fill the remaining space.
// to try to fill the remaining space.
if ( nBlockSize > nBlockMaxSize - 1000 ) {
if ( nBlockSize > nBlockMaxSize - 1000 ) {
lastFewTxs + + ;
lastFewTxs + + ;
}
}
continu e ;
return fals e;
}
}
if ( ! IsFinalTx ( tx , nHeight , nLockTimeCutoff ) )
if ( nBlockSigOps + iter - > GetSigOpCount ( ) > = MAX_BLOCK_SIGOPS ) {
continue ;
// If the block has room for no more sig ops then
// flag that the block is finished
unsigned int nTxSigOps = iter - > GetSigOpCount ( ) ;
if ( nBlockSigOps + nTxSigOps > = MAX_BLOCK_SIGOPS ) {
if ( nBlockSigOps > MAX_BLOCK_SIGOPS - 2 ) {
if ( nBlockSigOps > MAX_BLOCK_SIGOPS - 2 ) {
break ;
blockFinished = true ;
return false ;
}
}
continue ;
// Otherwise attempt to find another tx with fewer sigops
// to put in the block.
return false ;
}
}
CAmount nTxFees = iter - > GetFee ( ) ;
// Must check that lock times are still valid
// Added
// This can be removed once MTP is always enforced
pblock - > vtx . push_back ( tx ) ;
// as long as reorgs keep the mempool consistent.
pblocktemplate - > vTxFees . push_back ( nTxFees ) ;
if ( ! IsFinalTx ( iter - > GetTx ( ) , nHeight , nLockTimeCutoff ) )
pblocktemplate - > vTxSigOps . push_back ( nTxSigOps ) ;
return false ;
nBlockSize + = nTxSize ;
return true ;
}
void BlockAssembler : : AddToBlock ( CTxMemPool : : txiter iter )
{
pblock - > vtx . push_back ( iter - > GetTx ( ) ) ;
pblocktemplate - > vTxFees . push_back ( iter - > GetFee ( ) ) ;
pblocktemplate - > vTxSigOps . push_back ( iter - > GetSigOpCount ( ) ) ;
nBlockSize + = iter - > GetTxSize ( ) ;
+ + nBlockTx ;
+ + nBlockTx ;
nBlockSigOps + = nTxSigOps ;
nBlockSigOps + = iter - > GetSigOpCount ( ) ;
nFees + = nTxFees ;
nFees + = iter - > GetFee ( ) ;
inBlock . insert ( iter ) ;
if ( fPrintPriority )
bool fPrintPriority = GetBoolArg ( " -printpriority " , DEFAULT_PRINTPRIORITY ) ;
{
if ( fPrintPriority ) {
double dPriority = iter - > GetPriority ( nHeight ) ;
double dPriority = iter - > GetPriority ( nHeight ) ;
CAmount dummy ;
CAmount dummy ;
mempool . ApplyDeltas ( tx . GetHash ( ) , dPriority , dummy ) ;
mempool . ApplyDeltas ( i ter - > GetT x( ) . GetHash ( ) , dPriority , dummy ) ;
LogPrintf ( " priority %.1f fee %s txid %s \n " ,
LogPrintf ( " priority %.1f fee %s txid %s \n " ,
dPriority , CFeeRate ( iter - > GetModifiedFee ( ) , nTxSize ) . ToString ( ) , tx . GetHash ( ) . ToString ( ) ) ;
dPriority ,
CFeeRate ( iter - > GetModifiedFee ( ) , iter - > GetTxSize ( ) ) . ToString ( ) ,
iter - > GetTx ( ) . GetHash ( ) . ToString ( ) ) ;
}
}
}
inBlock . insert ( iter ) ;
void BlockAssembler : : addScoreTxs ( )
{
// Add transactions that depend on this one to the priority queue
std : : priority_queue < CTxMemPool : : txiter , std : : vector < CTxMemPool : : txiter > , ScoreCompare > clearedTxs ;
BOOST_FOREACH ( CTxMemPool : : txiter child , mempool . GetMemPoolChildren ( iter ) )
CTxMemPool : : setEntries waitSet ;
CTxMemPool : : indexed_transaction_set : : index < mining_score > : : type : : iterator mi = mempool . mapTx . get < mining_score > ( ) . begin ( ) ;
CTxMemPool : : txiter iter ;
while ( ! blockFinished & & ( mi ! = mempool . mapTx . get < mining_score > ( ) . end ( ) | | ! clearedTxs . empty ( ) ) )
{
{
if ( fPriorityBlock ) {
// If no txs that were previously postponed are available to try
waitPriIter wpiter = waitPriMap . find ( child ) ;
// again, then try the next highest score tx
if ( wpiter ! = waitPriMap . end ( ) ) {
if ( clearedTxs . empty ( ) ) {
vecPriority . push_back ( TxCoinAgePriority ( wpiter - > second , child ) ) ;
iter = mempool . mapTx . project < 0 > ( mi ) ;
std : : push_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , pricomparer ) ;
mi + + ;
waitPriMap . erase ( wpiter ) ;
}
}
}
// If a previously postponed tx is available to try again, then it
// has higher score than all untried so far txs
else {
else {
iter = clearedTxs . top ( ) ;
clearedTxs . pop ( ) ;
}
// If tx already in block, skip (added by addPriorityTxs)
if ( inBlock . count ( iter ) ) {
continue ;
}
// If tx is dependent on other mempool txs which haven't yet been included
// then put it in the waitSet
if ( isStillDependent ( iter ) ) {
waitSet . insert ( iter ) ;
continue ;
}
// If the fee rate is below the min fee rate for mining, then we're done
// adding txs based on score (fee rate)
if ( iter - > GetModifiedFee ( ) < : : minRelayTxFee . GetFee ( iter - > GetTxSize ( ) ) & & nBlockSize > = nBlockMinSize ) {
return ;
}
// If this tx fits in the block add it, otherwise keep looping
if ( TestForBlock ( iter ) ) {
AddToBlock ( iter ) ;
// This tx was successfully added, so
// add transactions that depend on this one to the priority queue to try again
BOOST_FOREACH ( CTxMemPool : : txiter child , mempool . GetMemPoolChildren ( iter ) )
{
if ( waitSet . count ( child ) ) {
if ( waitSet . count ( child ) ) {
clearedTxs . push ( child ) ;
clearedTxs . push ( child ) ;
waitSet . erase ( child ) ;
waitSet . erase ( child ) ;
@ -272,30 +295,80 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
}
}
}
}
}
}
nLastBlockTx = nBlockTx ;
}
nLastBlockSize = nBlockSize ;
LogPrintf ( " CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d \n " , nBlockSize , nBlockTx , nFees , nBlockSigOps ) ;
// Compute final coinbase transaction.
void BlockAssembler : : addPriorityTxs ( )
txNew . vout [ 0 ] . nValue = nFees + GetBlockSubsidy ( nHeight , chainparams . GetConsensus ( ) ) ;
{
txNew . vin [ 0 ] . scriptSig = CScript ( ) < < nHeight < < OP_0 ;
// How much of the block should be dedicated to high-priority transactions,
pblock - > vtx [ 0 ] = txNew ;
// included regardless of the fees they pay
pblocktemplate - > vTxFees [ 0 ] = - nFees ;
unsigned int nBlockPrioritySize = GetArg ( " -blockprioritysize " , DEFAULT_BLOCK_PRIORITY_SIZE ) ;
nBlockPrioritySize = std : : min ( nBlockMaxSize , nBlockPrioritySize ) ;
// Fill in header
if ( nBlockPrioritySize = = 0 ) {
pblock - > hashPrevBlock = pindexPrev - > GetBlockHash ( ) ;
return ;
UpdateTime ( pblock , chainparams . GetConsensus ( ) , pindexPrev ) ;
}
pblock - > nBits = GetNextWorkRequired ( pindexPrev , pblock , chainparams . GetConsensus ( ) ) ;
pblock - > nNonce = 0 ;
pblocktemplate - > vTxSigOps [ 0 ] = GetLegacySigOpCount ( pblock - > vtx [ 0 ] ) ;
CValidationState state ;
// This vector will be sorted into a priority queue:
if ( ! TestBlockValidity ( state , chainparams , * pblock , pindexPrev , false , false ) ) {
vector < TxCoinAgePriority > vecPriority ;
throw std : : runtime_error ( strprintf ( " %s: TestBlockValidity failed: %s " , __func__ , FormatStateMessage ( state ) ) ) ;
TxCoinAgePriorityCompare pricomparer ;
std : : map < CTxMemPool : : txiter , double , CTxMemPool : : CompareIteratorByHash > waitPriMap ;
typedef std : : map < CTxMemPool : : txiter , double , CTxMemPool : : CompareIteratorByHash > : : iterator waitPriIter ;
double actualPriority = - 1 ;
vecPriority . reserve ( mempool . mapTx . size ( ) ) ;
for ( CTxMemPool : : indexed_transaction_set : : iterator mi = mempool . mapTx . begin ( ) ;
mi ! = mempool . mapTx . end ( ) ; + + mi )
{
double dPriority = mi - > GetPriority ( nHeight ) ;
CAmount dummy ;
mempool . ApplyDeltas ( mi - > GetTx ( ) . GetHash ( ) , dPriority , dummy ) ;
vecPriority . push_back ( TxCoinAgePriority ( dPriority , mi ) ) ;
}
std : : make_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , pricomparer ) ;
CTxMemPool : : txiter iter ;
while ( ! vecPriority . empty ( ) & & ! blockFinished ) { // add a tx from priority queue to fill the blockprioritysize
iter = vecPriority . front ( ) . second ;
actualPriority = vecPriority . front ( ) . first ;
std : : pop_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , pricomparer ) ;
vecPriority . pop_back ( ) ;
// If tx already in block, skip
if ( inBlock . count ( iter ) ) {
assert ( false ) ; // shouldn't happen for priority txs
continue ;
}
}
// If tx is dependent on other mempool txs which haven't yet been included
// then put it in the waitSet
if ( isStillDependent ( iter ) ) {
waitPriMap . insert ( std : : make_pair ( iter , actualPriority ) ) ;
continue ;
}
}
return pblocktemplate . release ( ) ;
// If this tx fits in the block add it, otherwise keep looping
if ( TestForBlock ( iter ) ) {
AddToBlock ( iter ) ;
// If now that this txs is added we've surpassed our desired priority size
// or have dropped below the AllowFreeThreshold, then we're done adding priority txs
if ( nBlockSize > = nBlockPrioritySize | | ! AllowFree ( actualPriority ) ) {
return ;
}
// This tx was successfully added, so
// add transactions that depend on this one to the priority queue to try again
BOOST_FOREACH ( CTxMemPool : : txiter child , mempool . GetMemPoolChildren ( iter ) )
{
waitPriIter wpiter = waitPriMap . find ( child ) ;
if ( wpiter ! = waitPriMap . end ( ) ) {
vecPriority . push_back ( TxCoinAgePriority ( wpiter - > second , child ) ) ;
std : : push_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , pricomparer ) ;
waitPriMap . erase ( wpiter ) ;
}
}
}
}
}
}
void IncrementExtraNonce ( CBlock * pblock , const CBlockIndex * pindexPrev , unsigned int & nExtraNonce )
void IncrementExtraNonce ( CBlock * pblock , const CBlockIndex * pindexPrev , unsigned int & nExtraNonce )