1. 程式人生 > >比特幣程式碼分析5 挖礦程式碼分析

比特幣程式碼分析5 挖礦程式碼分析

本文描述礦工處理執行緒,通過本文學習,可以瞭解礦工挖礦的大致流程。
主要包含挖礦費用交易的產生、當前交易池的打包處理,工作量證明等相關內容。流程圖(參考網路)如下所示:。
比特幣程式碼分析5 挖礦程式碼分析

礦工處理函式
1.void ThreadBitcoinMiner(void* parg)
2.{

  1. vfThreadRunning[3] = true;
  2. CheckForShutdown(3);
  3. try
  4. {
  5. bool fRet = BitcoinMiner();
  6. printf("BitcoinMiner returned %s\n\n\n", fRet ? "true" : "false");
  7. }
  8. CATCH_PRINT_EXCEPTION("BitcoinMiner()")
  9. vfThreadRunning[3] = false;
    12.}

生成公鑰和私鑰
利用openssl庫生成
1.CKey key;
2.key.MakeNewKey();
3.
4.void MakeNewKey()
5.{

  1. if (!EC_KEY_generate_key(pkey))
  2. throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
    8.}

建立挖礦費用,用於挖礦後的獎勵
1.CTransaction txNew;
2.txNew.vin.resize(1);
3.txNew.vin[0].prevout.SetNull();
4.txNew.vin[0].scriptSig << nBits << ++bnExtraNonce;
5.txNew.vout.resize(1);
6.txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG;

建立新塊並儲存挖礦費用交易
1.auto_ptr<CBlock> pblock(new CBlock());
2.if (!pblock.get())
3.return false;
4.
5.// Add our coinbase tx as first transaction
pblock->vtx.push_back(txNew);

收集最新的驗證通過的交易,主要是交易池裡的交易
結束條件是:
(1)mapTransactions中所有交易處理完
(2)區塊大小達到 MAX_SIZE/2才結束。
1.CTxDB txdb("r");
2.map<uint256, CTxIndex> mapTestPool;
3.vector<char> vfAlreadyAdded(mapTransactions.size());
4.bool fFoundSomething = true;
5.unsigned int nBlockSize = 0;
6.while (fFoundSomething && nBlockSize < MAX_SIZE/2)
7.{

  1. fFoundSomething = false;
  2. unsigned int n = 0;
  3. for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n)
  4. {
  5. if (vfAlreadyAdded[n])
  6. continue;
  7. CTransaction& tx = (*mi).second;
  8. if (tx.IsCoinBase() || !tx.IsFinal())
  9. continue;
  10. // Transaction fee requirements, mainly only needed for flood control
  11. // Under 10K (about 80 inputs) is free for first 100 transactions
  12. // Base rate is 0.01 per KB
  13. int64 nMinFee = tx.GetMinFee(pblock->vtx.size() < 100);
  14. map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
  15. if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), 0, nFees, false, true, nMinFee))
  16. continue;
  17. swap(mapTestPool, mapTestPoolTmp);
  18. pblock->vtx.push_back(tx);
  19. nBlockSize += ::GetSerializeSize(tx, SER_NETWORK);
  20. vfAlreadyAdded[n] = true;
  21. fFoundSomething = true;
  22. }
    33.}

儲存輸出的位元組數、挖礦交易以及繳費到新塊中
1.pblock->nBits = nBits;
2.pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nFees);

計算交易的Merkle值
1.tmp.block.nVersion = pblock->nVersion;
2.tmp.block.hashPrevBlock = pblock->hashPrevBlock = (pindexPrev ? pindexPrev->GetBlockHash() : 0);
3.tmp.block.hashMerkleRoot = pblock->hashMerkleRoot = pblock->BuildMerkleTree();
4.tmp.block.nTime = pblock->nTime = max((pindexPrev ? pindexPrev->GetMedianTimePast()+1 : 0), GetAdjustedTime());
5.tmp.block.nBits = pblock->nBits = nBits;
6.tmp.block.nNonce = pblock->nNonce = 1;

獲取目標難度
1.uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();

獲取隨機生成的難度
1.unsigned int nBlocks0 = FormatHashBlocks(&tmp.block, sizeof(tmp.block));
2.unsigned int nBlocks1 = FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
3.... ...
4.BlockSHA256(&tmp.block, nBlocks0, &tmp.hash1);
5.BlockSHA256(&tmp.hash1, nBlocks1, &hash);

工作量證明
如果當前隨機hash小於等於目標hash值,表示該區塊滿足難度要求,則處理該區塊
1.if (hash <= hashTarget)
2.{

  1. pblock->nNonce = tmp.block.nNonce;
  2. ... ...
  3. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  4. CRITICAL_BLOCK(cs_main)
  5. {
  6. // Save key
  7. if (!AddKey(key))
  8. return false;
  9. key.MakeNewKey();
  10. // Process this block the same as if we had received it from another node
  11. if (!ProcessBlock(NULL, pblock.release()))
  12. printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n");
  13. }
  14. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
  15. Sleep(500);
  16. break;
    21.}