1. 程式人生 > >比特幣原始碼解讀之執行緒處理-礦工執行緒

比特幣原始碼解讀之執行緒處理-礦工執行緒

(本文使用的是比特幣v0.1.0版本 點選下載原始碼)

  比特幣原始碼解讀之執行緒處理分為兩篇,礦工執行緒處理和其他執行緒處理兩篇,本文描述礦工執行緒處理,主要包含創幣交易的產生、當前交易的打包處理,工作量等相關內容。流程圖如下所示:

新建礦工執行緒

  1. if(_beginthread(ThreadBitcoinMiner,0, NULL)==-1)
  2. printf("Error: _beginthread(ThreadBitcoinMiner) failed\n");

執行礦工處理函式

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

生成公鑰和私鑰

利用openssl庫生成

  1. CKey key;
  2. key.MakeNewKey();
  3. voidMakeNewKey()
  4. {
  5. if(!EC_KEY_generate_key(
    pkey))
  6. throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
  7. }

建立創幣交易

輸入為NULL,輸出為本節點地址

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

儲存輸出的位元組數、創幣交易以及繳費到新塊中

  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 =