Bitcoinビットコインのソースコードの解読-取引のライフサイクル

3562 ワード

1、取引を作成する.
財布にビットコインがあることを前提に、テストポイントを起動して、自分で鉱山を掘ることができます.RPC`getnewaddressでアドレス`,`sendtoaddress`を取得してトランザクションを作成します.次のようになります.
      > bitcoin-cli getnewaddress
      1LXVDTasMALkmkLRw7J35pzSdN38VG1Fvp
       >bitcoin-cli sendtoaddress 1LXVDTasMALkmkLRw7J35pzSdN38VG1Fvp 1
       txid
sendtoaddressはSendMoneyに呼び出され、CWallet::CreateTransactionに呼び出されます.CWallet::CreateTransactionは次のことをします.
AvailableCoinsを呼び出して財布で使用可能な通貨(UTXO)を取得します.
CScript scriptChangeルックアップスクリプトを初期化します.
その後、while(true)のサイクルで適切な通貨(取引の入力)を見つけて、出力と取引費を満たす.
次にselected_を入力します.coinsはProduceSignatureに1つずつ署名します(署名をスキップして、後で話します).CreateTransactionが完了しました.
次にCWallet::CommitTransactionを呼び出してトランザクションをメモリプールに格納します.AcceptToMemoryPoolがAcceptToMemoryPoolWorkerに呼び出されます.このWorkerは取引の出力値範囲が妥当かどうか、入力が重複しているかどうか、(費用がかかっていない)、手数料が妥当かどうか、CheckInputsは入力した署名が正しいかどうかをチェックします.accepttomemorypoolの後、CWalletTx::RelayWalletTransactionを呼び出します.さいよびだし
    void relayTransaction(const uint256& txid) override
    {
        CInv inv(MSG_TX, txid);
        g_connman->ForEachNode([&inv](CNode* node) { node->PushInventory(inv); });
    }

MSG経由でTXは、この取引のidを隣接ノードにブロードキャストする.
2、インターネット放送取引.
PushInventoryはトランザクションIDをセットsetInventory TxToSendに入れてnet_processing.cpp中
            // Determine transactions to relay
            if (fSendTrickle) {
                // Produce a vector with all candidates for sending
                 ....
                    if (vInv.size() == MAX_INV_SZ) {
                        connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
                        vInv.clear();
                    }
                 ....

送信間隔を満たすとトランザクションidが配列で送信される.隣接ノードはnet_で受信しましたprocessing.cppでの処理
bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic& interruptMsgProc, bool enable_bip61)
{
...
    if (strCommand == NetMsgType::INV) {
...
        for (CInv &inv : vInv)
        {
...
            else
            {
                pfrom->AddInventoryKnown(inv);
                if (fBlocksOnly) {
                    LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d
", inv.hash.ToString(), pfrom->GetId()); } else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) { RequestTx(State(pfrom->GetId()), inv.hash, nNow); } } }

RequestTxに呼び出し、取引idをpeer_に配置download_state.m_tx_announced.insert(txid);とpeer_download_state.m_tx_process_time.emplace(process_time, txid);で行ないます.
処理時間が満たされたらconnman->PushMessage(pto,msgMaker.Make(NetMsgType::GETDATA,vGetData);この取引idを放送する隣接ノードに取引の具体的なデータを要求する.
隣接ノードは、GETDATAを処理する際に、NetMsgType::TXを介してリクエスト側に取引を返信する.
ノードがNetMsgType::TXを受信した場合、処理ロジックはnet_processing.cpp
bool static ProcessMessage(...
...
    if (strCommand == NetMsgType::TX) {

主にAcceptToMemoryPool(このプロセスは上と同じ)ですが、入力が存在しないことに気づき、取引を独児プールに置き、すべての入力が揃ってから再AcceptToMemoryPoolにします.
3.ブロックに梱包する.
RPCコマンドによるブロックの作成
    >bitcoin-cli generatetoaddress 1LXVDTasMALkmkLRw7J35pzSdN38VG1Fvp
次にBlockAssembler::CreateNewBlockに実行し、ブロックの初期化とcoinbaseの作成を担当します.
次にBlockAssembler::addPackagetTxsを実行し、メモリプールのトランザクションをブロックに格納します.
これで、取引が完了し、ネットワークに記録されます.