比特币 RPC 命令「generate」
$ bitcoin-cli help generate generate numblocks 立刻挖出区块(在 RPC 调用返回前) 注意:此功能只用于回归测试网 参数: 1. numblocks(数字,必备)立刻生成多少区块。 结果: [ blockhashes ](数组)生成区块的哈希 例子: 生成 11 个区块 > bitcoin-cli -regtest generate 11
源码剖析
generate
对应的函数在文件 rpcserver.h
中被引用。
extern UniValue generate(const UniValue& params, bool fHelp);
实现在文件 rpcmining.cpp
中。
UniValue generate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
"generate numblocks\n"
"\nMine blocks immediately (before the RPC call returns)\n"
"\nNote: this function can only be used on the regtest network\n"
"\nArguments:\n"
"1. numblocks (numeric, required) How many blocks are generated immediately.\n"
"\nResult\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks\n"
+ HelpExampleCli("generate", "11")
); // 1. 帮助内容
if (!Params().MineBlocksOnDemand()) // 2.检测网络,只有回归测试网返回 true
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); // 提示
int nHeightStart = 0; // 产生块前的高度
int nHeightEnd = 0; // 产生块后的高度
int nHeight = 0; // 当前区块链高度
int nGenerate = params[0].get_int(); // 3.获取要产生区块的数目
boost::shared_ptr<CReserveScript> coinbaseScript; // 4.创建创币交易脚本
GetMainSignals().ScriptForMining(coinbaseScript);
// If the keypool is exhausted, no script is returned at all. Catch this.
if (!coinbaseScript) // 5.若密钥池耗尽,根本不会返回脚本。抓住它。
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
//throw an error if no script was provided
if (coinbaseScript->reserveScript.empty()) // 6.如果脚本为空,未被提供,则抛出一个错误
throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
{ // Don't keep cs_main locked
LOCK(cs_main); // 缩小加锁的范围
nHeightStart = chainActive.Height(); // 7.获取当前激活链高度
nHeight = nHeightStart; // 记录当前高度
nHeightEnd = nHeightStart+nGenerate; // 得到产生指定块数后的高度
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR); // 数组类型的区块哈希对象
while (nHeight < nHeightEnd)
{ // 8.循环产生指定数目的区块
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); // 8.1.创建区块模板
if (!pblocktemplate.get()) // 8.2.验证是否创建成功
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block; // 获取区块指针
{
LOCK(cs_main);
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); // 8.3.增加额外的随机数
}
while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { // 8.4.检测区块是否满足工作量证明
// Yes, there is a chance every nonce could fail to satisfy the -regtest
// target -- 1 in 2^(2^32). That ain't gonna happen. // 每个随机数都有可能无法满足 -regtest 目标值 -- 2^(2^32) 分之 1。这不会发生的。
++pblock->nNonce; // 区块头内随机数加 1
}
CValidationState state;
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) // 8.5.
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight; // 增加当前高度
blockHashes.push_back(pblock->GetHash().GetHex()); // 8.6.追加区块哈希
//mark script as important because it was used at least for one coinbase output
coinbaseScript->KeepScript(); // 8.7.标记该脚本为重要,因为它至少用作一个创币输出
}
return blockHashes; // 9.返回产生所有区块的哈希
}
1. 帮助内容
参考比特币 RPC 命令「getbestblockhash」1. 帮助内容。
基本流程:
- 处理命令帮助和参数个数。
- 检测当前网络类型,是否为回归测试网。
- 获取指定的要生成区块的数目。
- 创建创币脚本,每个区块必有一笔交易(创币交易)。
- 检测密钥池中密钥数量。
- 检测产生的脚本是否为空。
- 获取当前链高度并计算生成区块后的链高度,为生成区块做准备。
- 循环生成指定数目的区块,并记录每个上链区块的哈希。
- 返回打包好的区块哈希。
第二步,首先调用 Params().MineBlocksOnDemand() 函数获取挖矿需求标志。 该标志一般可以表示当前的网络,回归测试网下该标志为 true。
函数 Params() 声明在“chainparams.h”文件中。
/**
* Return the currently selected parameters. This won't change after app
* startup, except for unit tests.
*/ // 返回当前选择的链参数。除了单元测试,在应用程序启动后不会改变。
const CChainParams &Params();
实现在“chainparams.cpp”文件中,用于获取当前区块链的参数。
static CChainParams *pCurrentParams = 0;
const CChainParams &Params() { // 获取链参数,在 3.5.SelectParams() 初始化后,才能调用
assert(pCurrentParams);
return *pCurrentParams;
}
然后调用 MineBlocksOnDemand() 函数返回挖矿需求标志。该函数声明在“chainparams.h”文件的 CChainParams 类中。
/**
* CChainParams defines various tweakable parameters of a given instance of the
* Bitcoin system. There are three: the main network on which people trade goods
* and services, the public test network which gets reset from time to time and
* a regression test mode which is intended for private networks only. It has
* minimal difficulty to ensure that blocks can be found instantly.
*/ // 类 CChainParams 定义了比特币系统给定实例的各种可调用参数。有三种:人们交易商品和服务的主网,不时重置的公共测试网和仅限私有网络的回归测试模式。它有确保立刻找到块的最小难度。
class CChainParams
{
public:
...
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } // 返回挖矿需求标志
...
bool fMineBlocksOnDemand; // 挖矿需求标志,只有回归测试网中为 true
};
关于 fMineBlocksOnDemand 变量的初始化,详见比特币核心服务启动过程。
第四步,通过 GetMainSignals().ScriptForMining(coinbaseScript) 信号处理函数获取创币交易的脚本。 函数 GetMainSignals() 声明在“validationinterface.h”文件中。
CMainSignals& GetMainSignals();
实现在“validationinterface.cpp”文件中。
static CMainSignals g_signals; // 静态全局信号对象
CMainSignals& GetMainSignals() // 获取主信号对象的引用
{
return g_signals;
}
类 CMainSignals 定义在“validationinterface.h”文件中。
struct CMainSignals { // 主信号类
...
/** Notifies listeners that a key for mining is required (coinbase) */
boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining;
...
};
信号 ScriptForMining 通过函数 RegisterValidationInterface(…) 进行注册。 该函数声明在“validationinterface.h”文件中。
/** Register a wallet to receive updates from core */
void RegisterValidationInterface(CValidationInterface* pwalletIn); // 注册一个用来接收内核升级的钱包
实现在“validationinterface.cpp”文件中。
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); // 这里进行的注册
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
}
该函数的调用是在“init.cpp”文件的 AppInit2(…) 函数的 Step 8 中。
/** Initialize bitcoin.
* @pre Parameters should be parsed and config file should be read.
*/
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // [P]3.11.程序初始化,共 12 步
{
...
// ********************************************************* Step 8: load wallet // 若启用钱包功能,则加载钱包
...
RegisterValidationInterface(pwalletMain); // 注册一个钱包用于接收 bitcoin core 的升级
...
};
注册的 CValidationInterface::GetScriptForMining 函数是一个虚函数,在“”文件的 CValidationInterface 类中。
class CValidationInterface { // 验证接口
protected:
...
virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
...
};
其具体实现在该类的派生类 CWallet 中,该函数声明在“wallet.h”文件的 CWallet 类中。
**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/ // CWallet 是密钥库的扩展,可以维持一组交易和余额,并提供创建新交易的能力。
class CWallet : public CCryptoKeyStore, public CValidationInterface
{
...
void GetScriptForMining(boost::shared_ptr<CReserveScript> &script);
...
};
具体实现在“wallet.cpp”文件中。
void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
{
boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this)); // 1.新建一个派生类对象
CPubKey pubkey;
if (!rKey->GetReservedKey(pubkey)) // 2.从密钥池中取一个公钥
return;
script = rKey; // 3.把派生类对象赋值给基类对象(派生类 -> 基类)
script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; // 把公钥加入脚本
}
这里的流程:
- 新建对象。
- 通过该对象从密钥池获取一个公钥。
- 获取脚本。
1.创建一个从密钥池中分配的密钥 CReserveKey 对象,该类定义在“wallet.h”文件中。
/** A key allocated from the key pool. */
class CReserveKey : public CReserveScript // 一个从密钥池分配的密钥
{
protected:
CWallet* pwallet; // 钱包指针,指向主钱包
int64_t nIndex; // 密钥池中密钥的索引,初始化为 -1
CPubKey vchPubKey; // 对应公钥
public:
CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn; // 主钱包
}
...
bool GetReservedKey(CPubKey &pubkey); // 从密钥池中获取一个公钥
...
};
2.调用 rKey->GetReservedKey(pubkey) 函数从密钥池中获取一个公钥,该函数实现在“wallet.cpp”文件中。
bool CReserveKey::GetReservedKey(CPubKey& pubkey) // 从密钥池中取一个公钥
{
if (nIndex == -1) // 初始化为 -1
{
CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex != -1)
vchPubKey = keypool.vchPubKey;
else {
return false;
}
}
assert(vchPubKey.IsValid()); // 检测公钥的有效性
pubkey = vchPubKey;
return true;
}
调用 pwallet->ReserveKeyFromKeyPool(nIndex, keypool) 函数真正实现从密钥池中取出一个密钥并获取其公钥。 其实现也在“wallet.cpp”文件中。
void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
{
LOCK(cs_wallet); // 钱包上锁
if (!IsLocked()) // 若钱包未被加密
TopUpKeyPool(); // 再次填充密钥池
// Get the oldest key // 获取时间上最早的密钥
if(setKeyPool.empty()) // 若密钥池集合为空
return; // 直接返回
CWalletDB walletdb(strWalletFile); // 根据钱包文件构造钱包数据库对象
nIndex = *(setKeyPool.begin()); // 获取最先创建的密钥的索引,大于 0,最小为 1
setKeyPool.erase(setKeyPool.begin()); // 从密钥池集合中擦除该密钥的索引
if (!walletdb.ReadPool(nIndex, keypool)) // 根据密钥索引从钱包数据库中读取一个密钥池条目
throw runtime_error("ReserveKeyFromKeyPool(): read failed");
if (!HaveKey(keypool.vchPubKey.GetID())) // 通过获取的公钥 ID 检测对应的密钥是否存在
throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
assert(keypool.vchPubKey.IsValid()); // 检查公钥是否有效
LogPrintf("keypool reserve %d\n", nIndex);
}
}
3.把公钥导入脚本。脚本类 CScript 定义在“script.h”文件中。
typedef prevector<28, unsigned char> CScriptBase;
/** Serialized script, used inside transaction inputs and outputs */
class CScript : public CScriptBase
{
...
public:
CScript() { }
...
CScript& operator<<(opcodetype opcode)
{
if (opcode < 0 || opcode > 0xff)
throw std::runtime_error("CScript::operator<<(): invalid opcode");
insert(end(), (unsigned char)opcode);
return *this;
}
...
CScript& operator<<(const std::vector<unsigned char>& b)
{
if (b.size() < OP_PUSHDATA1) // 4 中导入方式
{
insert(end(), (unsigned char)b.size());
}
else if (b.size() <= 0xff)
{
insert(end(), OP_PUSHDATA1);
insert(end(), (unsigned char)b.size());
}
else if (b.size() <= 0xffff)
{
insert(end(), OP_PUSHDATA2);
uint8_t data[2];
WriteLE16(data, b.size());
insert(end(), data, data + sizeof(data));
}
else
{
insert(end(), OP_PUSHDATA4);
uint8_t data[4];
WriteLE32(data, b.size());
insert(end(), data, data + sizeof(data));
}
insert(end(), b.begin(), b.end());
return *this;
}
...
};
函数模板 ToByteVector(pubkey) 和 OP_CHECKSIG 均定义在“script.h”文件中。
template <typename T>
std::vector<unsigned char> ToByteVector(const T& in)
{
return std::vector<unsigned char>(in.begin(), in.end());
}
/** Script opcodes */
enum opcodetype
{
...
// crypto
...
OP_CHECKSIG = 0xac,
...
};
第六步,调用 coinbaseScript->reserveScript.empty() 函数判断脚本是否创建成功。 该函数定义在“prevector.h”文件的 prevector 类模板中。
** Implements a drop-in replacement for std::vector<T> which stores up to N
* elements directly (without heap allocation). The types Size and Diff are
* used to store element counts, and can be any unsigned + signed type.
*
* Storage layout is either:
* - Direct allocation:
* - Size _size: the number of used elements (between 0 and N)
* - T direct[N]: an array of N elements of type T
* (only the first _size are initialized).
* - Indirect allocation:
* - Size _size: the number of used elements plus N + 1
* - Size capacity: the number of allocated elements
* - T* indirect: a pointer to an array of capacity elements of type T
* (only the first _size are initialized).
*
* The data type T must be movable by memmove/realloc(). Once we switch to C++,
* move constructors can be used instead.
*/
template<unsigned int N, typename T, typename Size = uint32_t, typename Diff = int32_t>
class prevector {
public:
typedef Size size_type; // uint32_t
...
private:
size_type _size; // 4 bytes
...
bool is_direct() const { return _size <= N; } // N 为 28
...
size_type size() const {
return is_direct() ? _size : _size - N - 1;
}
bool empty() const { // _size == 29 为空
return size() == 0;
}
...
};
第八步,终于进入正题,开始生成区块了。
8.1.通过调用 CreateNewBlock(Params(), coinbaseScript->reserveScript) 函数把创建的创币脚本传入生成一个区块模板。 该函数声明在“miner.h”文件中。
struct CBlockTemplate // 区块模板类
{
CBlock block; // 区块对象
std::vector<CAmount> vTxFees; // 交易手续费
std::vector<int64_t> vTxSigOps; // 交易签名操作
};
...
/** Generate a new block, without valid proof-of-work */
CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn);
实现在“miner.cpp”文件中。
CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn)
{
// Create new block
auto_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:
unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // 你希望创建的最大区块大小,默认 750,000(不到 1M)
// 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)); // 获取真正区块大小的最大限制
// 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); // 默认区块优先级大小,默认为 0
nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); // 用于包含高优先级的交易
// 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:
unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); // 默认区块大小最小限制,默认为 0
nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
// Collect memory pool transactions into the block
CTxMemPool::setEntries inBlock;
CTxMemPool::setEntries waitSet;
// This vector will be sorted into a priority queue:
vector<TxCoinAgePriority> vecPriority;
TxCoinAgePriorityCompare pricomparer;
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;
bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); // 打印优先级标志,默认关闭
uint64_t nBlockSize = 1000;
uint64_t nBlockTx = 0;
unsigned int nBlockSigOps = 100;
int lastFewTxs = 0;
CAmount nFees = 0;
{
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
pblock->nTime = GetAdjustedTime();
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
// -regtest only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios
if (chainparams.MineBlocksOnDemand())
pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
? nMedianTimePast
: pblock->GetBlockTime();
bool fPriorityBlock = nBlockPrioritySize > 0;
if (fPriorityBlock) {
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::nth_index<3>::type::iterator mi = mempool.mapTx.get<3>().begin();
CTxMemPool::txiter iter;
while (mi != mempool.mapTx.get<3>().end() || !clearedTxs.empty())
{
bool priorityTx = false;
if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize
priorityTx = true;
iter = vecPriority.front().second;
actualPriority = vecPriority.front().first;
std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
vecPriority.pop_back();
}
else if (clearedTxs.empty()) { // add tx with next highest score
iter = mempool.mapTx.project<0>(mi);
mi++;
}
else { // try to add a previously postponed child tx
iter = clearedTxs.top();
clearedTxs.pop();
}
if (inBlock.count(iter))
continue; // could have been added to the priorityBlock
const CTransaction& tx = iter->GetTx();
bool fOrphan = false;
BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter))
{
if (!inBlock.count(parent)) {
fOrphan = true;
break;
}
}
if (fOrphan) {
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))) {
fPriorityBlock = false;
waitPriMap.clear();
}
if (!priorityTx &&
(iter->GetModifiedFee() < ::minRelayTxFee.GetFee(nTxSize) && nBlockSize >= nBlockMinSize)) {
break;
}
if (nBlockSize + nTxSize >= nBlockMaxSize) {
if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) {
break;
}
// Once we're within 1000 bytes of a full block, only look at 50 more txs
// to try to fill the remaining space.
if (nBlockSize > nBlockMaxSize - 1000) {
lastFewTxs++;
}
continue;
}
if (!IsFinalTx(tx, nHeight, nLockTimeCutoff))
continue;
unsigned int nTxSigOps = iter->GetSigOpCount();
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) {
if (nBlockSigOps > MAX_BLOCK_SIGOPS - 2) {
break;
}
continue;
}
CAmount nTxFees = iter->GetFee();
// Added
pblock->vtx.push_back(tx);
pblocktemplate->vTxFees.push_back(nTxFees);
pblocktemplate->vTxSigOps.push_back(nTxSigOps);
nBlockSize += nTxSize;
++nBlockTx;
nBlockSigOps += nTxSigOps;
nFees += nTxFees;
if (fPrintPriority) // 打印优先级
{
double dPriority = iter->GetPriority(nHeight);
CAmount dummy;
mempool.ApplyDeltas(tx.GetHash(), dPriority, dummy);
LogPrintf("priority %.1f fee %s txid %s\n",
dPriority , CFeeRate(iter->GetModifiedFee(), nTxSize).ToString(), tx.GetHash().ToString());
}
inBlock.insert(iter);
// Add transactions that depend on this one to the priority queue
BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter))
{
if (fPriorityBlock) {
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);
}
}
else {
if (waitSet.count(child)) {
clearedTxs.push(child);
waitSet.erase(child);
}
}
}
}
nLastBlockTx = nBlockTx;
nLastBlockSize = nBlockSize;
LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps);
// Compute final coinbase transaction.
txNew.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); // 计算创币交易输出值(区块奖励),通过当前区块高度和共识
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; // 导入该交易输入的签名脚本,新区快的高度,OP_0 表示一个字节空串被推入栈
pblock->vtx[0] = txNew; // 放入创币交易
pblocktemplate->vTxFees[0] = -nFees; // 计算交易手续费,为 0
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash(); // 获取父区块哈希
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); // 获取难度对应值
pblock->nNonce = 0; // 随机数置 0,即从 0 开始找块
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); // 获取创币交易签名操作数
CValidationState state;
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
}
}
return pblocktemplate.release();
}
参考链接
- bitcoin/rpcserver.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/rpcserver.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/rpcmining.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/chainparams.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/chainparams.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/validationinterface.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/validationinterface.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/init.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/wallet.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/wallet.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/script.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/prevector.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/miner.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/miner.cpp at v0.12.1 · bitcoin/bitcoin