比特幣原始碼解讀之執行緒處理-礦工執行緒
阿新 • • 發佈:2019-01-07
(本文使用的是比特幣v0.1.0版本 點選下載原始碼)
比特幣原始碼解讀之執行緒處理分為兩篇,礦工執行緒處理和其他執行緒處理兩篇,本文描述礦工執行緒處理,主要包含創幣交易的產生、當前交易的打包處理,工作量等相關內容。流程圖如下所示:
新建礦工執行緒
if(_beginthread(ThreadBitcoinMiner,0, NULL)==-1)
printf("Error: _beginthread(ThreadBitcoinMiner) failed\n");
執行礦工處理函式
voidThreadBitcoinMiner(void* parg)
{
vfThreadRunning
[3]=true;CheckForShutdown(3);
try
{
bool fRet =BitcoinMiner();
printf("BitcoinMiner returned %s\n\n\n", fRet ?"true":"false");
}
CATCH_PRINT_EXCEPTION("BitcoinMiner()")
vfThreadRunning[3]=false;
}
生成公鑰和私鑰
利用openssl庫生成
CKey key;
key.MakeNewKey();
voidMakeNewKey()
{
if(!EC_KEY_generate_key(
pkey))throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
}
建立創幣交易
輸入為NULL,輸出為本節點地址
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;
建立新塊並儲存創幣交易
auto_ptr<CBlock> pblock(newCBlock());
if(!pblock.get())
returnfalse;
// Add our coinbase tx as first transaction
pblock->vtx.push_back(txNew);
收集最新的驗證通過的交易
結束條件是:
(1)mapTransactions中所有交易處理完
(2)區塊大小達到 MAX_SIZE/2才結束。
CTxDB txdb("r");
map<uint256,CTxIndex> mapTestPool;
vector<char> vfAlreadyAdded(mapTransactions.size());
bool fFoundSomething =true;
unsignedint nBlockSize =0;
while(fFoundSomething && nBlockSize < MAX_SIZE/2)
{
fFoundSomething =false;
unsignedint 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);
計算交易的Merkle值
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 =