区块链 Ripple

Ripple中的Amendment与FeeVote

2018-02-24  本文已影响20人  SwordShield

1. Amendment

Amendment是为了在XRP这种去中心化的网络中引用新特性而产生的,Amendments需要得到整个网络中80%的支持并且持续两周才能生效。Amendments一旦生效,后面的区块中会一直生效,要想禁用某一已经生效的Amendment,需要引入新的Amendment才能实现。

代码中设置两周生效

bool ApplicationImp::setup()
{
  ...
    // Configure the amendments the server supports
    {
        Section supportedAmendments ("Supported Amendments");
        supportedAmendments.append (detail::supportedAmendments ());

        Section enabledAmendments = config_->section (SECTION_AMENDMENTS);
        enabledAmendments.append (detail::preEnabledAmendments ());

      //若要修改生效时间,可修改weeks{2},例如:std::chrono::minutes{10}
        m_amendmentTable = make_AmendmentTable (
            weeks{2},
            MAJORITY_FRACTION,
            supportedAmendments,
            enabledAmendments,
            config_->section (SECTION_VETO_AMENDMENTS),
            logs_->journal("Amendments"));
    }
    ...
}

使用方式

  1. 在验证节点中配置Amendment
1). 强制生效(一般用于开发测试,在单机模式下使用),这里只是配置当前节点启用特性
[features]
MultiSign
TrustSetAuth

2).投票设置(这个用处不大,即使不配置,节点程序会自动给它识别的特性投赞成票)
[amendments]
4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373 MultiSign
42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE FeeEscalation

3).投反对票
[veto_amendments]
C1B8D934087225F509BEB5A8EC24447854713EE447D277F69545ABFA0E0FD490 Tickets
DA1BD556B42D85EA9C84066D028D355B52416734D3283F85E216EA5DA6DB7E13 SusPay

  1. 不做配置,在第一个标志区块(256的整数倍),会自动给识别的特性投赞成票,超过80%的赞成票且维持两周则在链中永久生效

Amendment的生效过程

每256个区块是一个标志(Flag)区块,在第一个Flag区块,进行投票

//第255个区块
template <class Traits>
void LedgerConsensusImp<Traits>::accept (TxSet_t const& set)
{
    ...
    ...
    if (((sharedLCL->info().seq + 1) % 256) == 0)
    // next ledger is flag ledger
    {
        // Suggest fee changes and new features
        feeVote_.doValidation (sharedLCL, *v);
        app_.getAmendmentTable ().doValidation (sharedLCL, *v);
    }
}

第256个区块对投票结果进行统计,并添加虚拟交易:

//Callstack
timerEntry ->
statePreClose ->
closeLedger ->
takeInitialPosition ->
makeInitialPosition ->
LedgerConsensusImp<Traits>::makeInitialPosition () ->
    std::pair <TxSet_t, Pos_t>
{
    ...
    // Add pseudo-transactions to the set
    if ((app_.config().standalone() || (proposing_ && haveCorrectLCL_))
            && ((previousLedger_->info().seq % 256) == 0))
    {
        // previous ledger was flag ledger, add pseudo-transactions
        auto const validations =
            app_.getValidations().getValidations (
                previousLedger_->info().parentHash);

        std::size_t const count = std::count_if (
            validations.begin(), validations.end(),
            [](auto const& v)
            {
                return v.second->isTrusted();
            });
        
        if (count >= app_.validators ().quorum ())
        {
            feeVote_.doVoting (
                previousLedger_,
                validations,
                initialSet);
            app_.getAmendmentTable ().doVoting (
                previousLedger_,
                validations,
                initialSet);
        }
    }
}

doVoting函数中会调用一个重载的doVoting函数会为投票计数(注意第三个参数,后面会用到):

    // Ask implementation what to do
    auto actions = doVoting (
        lastClosedLedger->parentCloseTime(),
        getEnabledAmendments(*lastClosedLedger),
        getMajorityAmendments(*lastClosedLedger),
        parentValidations);

超过80%的Amendment会加入到一个变量名为actions的map中,value值为tfGotMajority

{
    else  if (hasValMajority &&
    (majorityTime == NetClock::time_point{}) &&
    ! entry.second.vetoed)
    {
        // Ledger says no majority, validators say yes
        JLOG (j_.debug()) <<
            entry.first << ": amendment got majority";
        actions[entry.first] = tfGotMajority;
    }
}

actions返回后,在外层的doVoting函数中会在当前区块中注入 ttAMENDMENT 类型的交易:

// Inject appropriate pseudo-transactions
for (auto const& it : actions)
{
    STTx amendTx (ttAMENDMENT,
        [&it, seq = lastClosedLedger->seq() + 1](auto& obj)
        {
            obj.setAccountID (sfAccount, AccountID());
            obj.setFieldH256 (sfAmendment, it.first);
            obj.setFieldU32 (sfLedgerSequence, seq);

            if (it.second != 0)
                obj.setFieldU32 (sfFlags, it.second);
        });

    Serializer s;
    amendTx.add (s);

    initialPosition->addGiveItem (
        std::make_shared <SHAMapItem> (
            amendTx.getTransactionID(),
            s.peekData()),
        true,
        false);
}

在下一区块中进行共识:

TER
Change::doApply()
{
    if (ctx_.tx.getTxnType () == ttAMENDMENT)
        return applyAmendment ();

    assert(ctx_.tx.getTxnType() == ttFEE);
    return applyFee ();
}

共识过程主要是将 gotMajority 的amendment加入到key为amendments的SLE中,并将上一区块的closetime设置到sfCloseTime字段中,两周后生效就是靠它来判断的

TER
Change::applyAmendment()
{
    auto const k = keylet::amendments();

    SLE::pointer amendmentObject =
        view().peek (k);
    
        if (gotMajority)
    {
        // This amendment now has a majority
        newMajorities.push_back (STObject (sfMajority));
        auto& entry = newMajorities.back ();
        entry.emplace_back (STHash256 (sfAmendment, amendment));
        // closetime set
        entry.emplace_back (STUInt32 (sfCloseTime,
            view().parentCloseTime().time_since_epoch().count()));
    }
    ...
    
    if (newMajorities.empty ())
        amendmentObject->makeFieldAbsent (sfMajorities);
    else
        amendmentObject->setFieldArray (sfMajorities, newMajorities);

    view().update (amendmentObject);
}

再后面,每256个区块同样会进行doVoting操作,但是内层doVoting中因为sfCloseTime字段的时间没满足两周,不会再添加到actions中,也就不会有pseudotransaction产生:

    //获取到时间
    {
        auto const it = majorityAmendments.find (entry.first);
        if (it != majorityAmendments.end ())
            majorityTime = it->second;
    }

直到两周后:

    else if ((majorityTime != NetClock::time_point{}) &&
        ((majorityTime + majorityTime_) <= closeTime) &&
        ! entry.second.vetoed)
    {
        // Ledger says majority held
        JLOG (j_.debug()) <<
            entry.first << ": amendment majority held";
        actions[entry.first] = 0;
    }

满足两周的时间,actions的value值为设为0,这时注入交易中的flag不进行设置

    // Inject appropriate pseudo-transactions
    for (auto const& it : actions)
    {
        STTx amendTx (ttAMENDMENT,
            [&it, seq = lastClosedLedger->seq() + 1](auto& obj)
            {
                obj.setAccountID (sfAccount, AccountID());
                obj.setFieldH256 (sfAmendment, it.first);
                obj.setFieldU32 (sfLedgerSequence, seq);

                if (it.second != 0)
                    obj.setFieldU32 (sfFlags, it.second);
            });

共识时,发现没有设置Flag字段,并且满足80%投票,则应用特性:

TER
Change::applyAmendment()
{
       else if (!lostMajority)
    {
        // No flags, enable amendment
        amendments.push_back (amendment);
        amendmentObject->setFieldV256 (sfAmendments, amendments);

        //重点
        ctx_.app.getAmendmentTable ().enable (amendment);

        if (!ctx_.app.getAmendmentTable ().isSupported (amendment))
        {
            JLOG (j_.error()) <<
                "Unsupported amendment " << amendment <<
                " activated: server blocked.";
            ctx_.app.getOPs ().setAmendmentBlocked ();
        }
    }
}

2.FeeVoting

FeeVoting设置账户的预留费用及基础交易费用,这个配置不需要等两周,只需要在第一个256区块就会产生交易,第257个区块共识生效

可在配置文件中修改FeeVoting参数

[voting]
account_reserve = 3000000
owner_reserve = 1000000
reference_fee = 10
上一篇 下一篇

猜你喜欢

热点阅读