以太坊C++源碼解析(八)交易隊(duì)列(二)

交易隊(duì)列的輸入

交易隊(duì)列的輸入有兩個(gè)鹦筹,分別是接收到其他節(jié)點(diǎn)的廣播交易和自身節(jié)點(diǎn)提交的交易懂鸵。
分別來看這兩種輸入方式:

  • 接收廣播交易
    在前面區(qū)塊鏈同步章節(jié)中提到過,接收到交易后會(huì)通過調(diào)用TransactionQueue::enqueue()來將新交易放入交易隊(duì)列中预明,這個(gè)函數(shù)代碼非常簡(jiǎn)單:

      void TransactionQueue::enqueue(RLP const& _data, h512 const& _nodeId)
      {
          bool queued = false;
          {
              Guard l(x_queue);
              unsigned itemCount = _data.itemCount();
              for (unsigned i = 0; i < itemCount; ++i)
              {
                  if (m_unverified.size() >= c_maxVerificationQueueSize)
                  {
                      LOG(m_logger) << "Transaction verification queue is full. Dropping "
                                  << itemCount - i << " transactions";
                      break;
                  }
                  m_unverified.emplace_back(UnverifiedTransaction(_data[i].data(), _nodeId));
                  queued = true;
              }
          }
          if (queued)
              m_queueReady.notify_all();
      }
    

只是將交易放入m_unverified中役耕,然后通知校驗(yàn)線程來校驗(yàn)采转。
再來看校驗(yàn)線程:

    void TransactionQueue::verifierBody()
    {
        while (!m_aborting)
        {
            UnverifiedTransaction work;

            {
                unique_lock<Mutex> l(x_queue);
                m_queueReady.wait(l, [&](){ return !m_unverified.empty() || m_aborting; });
                if (m_aborting)
                    return;
                work = move(m_unverified.front());
                m_unverified.pop_front();
            }

            try
            {
                Transaction t(work.transaction, CheckTransaction::Cheap); //Signature will be checked later
                ImportResult ir = import(t);
                m_onImport(ir, t.sha3(), work.nodeId);
            }
            catch (...)
            {
                // should not happen as exceptions are handled in import.
                cwarn << "Bad transaction:" << boost::current_exception_diagnostic_information();
            }
        }
    }

這里是一個(gè)簡(jiǎn)單的生產(chǎn)消費(fèi)者隊(duì)列,先將UnverifiedTransaction取出瞬痘,然后調(diào)用import()函數(shù)進(jìn)行校驗(yàn)故慈。由于使用了線程,校驗(yàn)過程是異步的框全。

  • 自身提交交易
    節(jié)點(diǎn)自身提交的交易與上面的交易不同察绷,是同步的,也就是直接會(huì)調(diào)用import()函數(shù)來進(jìn)行校驗(yàn)竣况。

      ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, IfDropped _ik)
      {
          try
          {
              Transaction t = Transaction(_transactionRLP, CheckTransaction::Everything);
              return import(t, _ik);
          }
          catch (Exception const&)
          {
              return ImportResult::Malformed;
          }
      }
    

交易的校驗(yàn)

我們來看這個(gè)校驗(yàn)的過程,也就是TransactionQueue::import()函數(shù)筒严。

ImportResult TransactionQueue::import(Transaction const& _transaction, IfDropped _ik)
{
    if (_transaction.hasZeroSignature())
        return ImportResult::ZeroSignature;
    // Check if we already know this transaction.
    h256 h = _transaction.sha3(WithSignature);

    ImportResult ret;
    {
        UpgradableGuard l(m_lock);
        auto ir = check_WITH_LOCK(h, _ik);
        if (ir != ImportResult::Success)
            return ir;

        {
            _transaction.safeSender();  // Perform EC recovery outside of the write lock
            UpgradeGuard ul(l);
            ret = manageImport_WITH_LOCK(h, _transaction);
        }
    }
    return ret;
}

可以看到先是調(diào)用TransactionQueue::check_WITH_LOCK()函數(shù)來做一個(gè)簡(jiǎn)單檢查丹泉。檢查的過程是看這個(gè)交易是否是已經(jīng)校驗(yàn)過的,是否是之前被刪除的鸭蛙。
接著調(diào)用_transaction.safeSender()摹恨,這個(gè)函數(shù)是通過簽名反推sender,在交易那一節(jié)已經(jīng)說過娶视。最后調(diào)用manageImport_WITH_LOCK()函數(shù)來處理交易晒哄。
manageImport_WITH_LOCK()函數(shù)過程稍稍復(fù)雜睁宰,我們可以一步一步來分析。
第一步:

auto cs = m_currentByAddressAndNonce.find(_transaction.from());
if (cs != m_currentByAddressAndNonce.end())
{
    auto t = cs->second.find(_transaction.nonce());
    if (t != cs->second.end())
    {
        if (_transaction.gasPrice() < (*t->second).transaction.gasPrice())
            return ImportResult::OverbidGasPrice;
        else
        {
            h256 dropped = (*t->second).transaction.sha3();
            remove_WITH_LOCK(dropped);
            m_onReplaced(dropped);
        }
    }
}

這一步是檢查m_currentByAddressAndNonce中是否有重復(fù)項(xiàng)寝凌,判斷標(biāo)準(zhǔn)是sendernonce柒傻,如果存在重復(fù)的則檢查gasPrice,如果新的交易gasPrice更低较木,則校驗(yàn)失敗红符,否則將現(xiàn)有的交易刪除,替換為gasPrice更高的交易伐债。
第二步是檢查m_future预侯,檢查過程與第一步類似。
第三步:

// If valid, append to transactions.
insertCurrent_WITH_LOCK(make_pair(_h, _transaction));
LOG(m_loggerDetail) << "Queued vaguely legit-looking transaction " << _h;

while (m_current.size() > m_limit)
{
    LOG(m_loggerDetail) << "Dropping out of bounds transaction " << _h;
    remove_WITH_LOCK(m_current.rbegin()->transaction.sha3());
}

m_onReady();

這里調(diào)用insertCurrent_WITH_LOCK()插入隊(duì)列峰锁,然后將超出容量m_limit的部分刪除萎馅,并調(diào)用m_onReady()表示目前隊(duì)列有數(shù)據(jù)了,可以來取了虹蒋。
我們?cè)賮砜?code>insertCurrent_WITH_LOCK()函數(shù)是怎么將交易插入隊(duì)列的糜芳。

void TransactionQueue::insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p)
{
    if (m_currentByHash.count(_p.first))
    {
        cwarn << "Transaction hash" << _p.first << "already in current?!";
        return;
    }

    Transaction const& t = _p.second;
    // Insert into current
    auto inserted = m_currentByAddressAndNonce[t.from()].insert(std::make_pair(t.nonce(), PriorityQueue::iterator()));
    PriorityQueue::iterator handle = m_current.emplace(VerifiedTransaction(t));
    inserted.first->second = handle;
    m_currentByHash[_p.first] = handle;

    // Move following transactions from future to current
    makeCurrent_WITH_LOCK(t);
    m_known.insert(_p.first);
}

先還是檢查是否有重復(fù)項(xiàng),然后把交易插入m_current里千诬,并記下插入的位置(迭代器)耍目,再分別加入m_currentByAddressAndNoncem_currentByHash中。
注意到末尾還有個(gè)makeCurrent_WITH_LOCK()的調(diào)用徐绑,這個(gè)是看情況將m_future里的交易移到m_current中邪驮。

交易隊(duì)列的輸出

交易隊(duì)列輸出只有一個(gè),那就是區(qū)塊block傲茄。在Block::sync()中會(huì)調(diào)用TransactionQueue::topTransactions()來取隊(duì)列的前N項(xiàng)數(shù)據(jù)毅访,再加入block中。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盘榨,一起剝皮案震驚了整個(gè)濱河市喻粹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌草巡,老刑警劉巖守呜,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異山憨,居然都是意外死亡查乒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門郁竟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玛迄,“玉大人,你說我怎么就攤上這事棚亩”鸵椋” “怎么了虏杰?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)勒虾。 經(jīng)常有香客問我纺阔,道長(zhǎng),這世上最難降的妖魔是什么从撼? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任州弟,我火速辦了婚禮,結(jié)果婚禮上低零,老公的妹妹穿的比我還像新娘婆翔。我一直安慰自己,他們只是感情好掏婶,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布啃奴。 她就那樣靜靜地躺著,像睡著了一般雄妥。 火紅的嫁衣襯著肌膚如雪最蕾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天老厌,我揣著相機(jī)與錄音瘟则,去河邊找鬼。 笑死枝秤,一個(gè)胖子當(dāng)著我的面吹牛醋拧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淀弹,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼丹壕,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了薇溃?” 一聲冷哼從身側(cè)響起菌赖,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沐序,沒想到半個(gè)月后琉用,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡策幼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年邑时,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垄惧。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刁愿,死狀恐怖绰寞,靈堂內(nèi)的尸體忽然破棺而出到逊,到底是詐尸還是另有隱情铣口,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布觉壶,位于F島的核電站脑题,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏铜靶。R本人自食惡果不足惜叔遂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望争剿。 院中可真熱鬧已艰,春花似錦、人聲如沸蚕苇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涩笤。三九已至嚼吞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹬碧,已是汗流浹背舱禽。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恩沽,地道東北人誊稚。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像飒筑,于是被迫代替她去往敵國(guó)和親片吊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容