void
AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
    SHAMap::ref initialPosition)
{

    // LCL must be flag ledger
    assert((lastClosedLedger->getLedgerSeq () % 256) == 0);

    AmendmentSet amendmentSet (lastClosedLedger->getParentCloseTimeNC ());

    // get validations for ledger before flag ledger
    ValidationSet valSet = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
    for (auto const& entry : valSet)
    {
        auto const& val = *entry.second;

        if (val.isTrusted ())
        {
            amendmentSet.addVoter ();
            if (val.isFieldPresent (sfAmendments))
            {
                for (auto const& amendment : val.getFieldV256 (sfAmendments))
                {
                    amendmentSet.addVote (amendment);
                }
            }
        }
    }
    reportValidations (amendmentSet);

    amendmentList_t lAmendments = getToEnable (lastClosedLedger->getCloseTimeNC ());
    for (auto const& uAmendment : lAmendments)
    {
        if (m_journal.warning) m_journal.warning <<
            "Voting for amendment: " << uAmendment;

        // Create the transaction to enable the amendment
        STTx trans (ttAMENDMENT);
        trans.setFieldAccount (sfAccount, Account ());
        trans.setFieldH256 (sfAmendment, uAmendment);
        uint256 txID = trans.getTransactionID ();

        if (m_journal.warning) m_journal.warning <<
            "Vote ID: " << txID;

        // Inject the transaction into our initial proposal
        Serializer s;
        trans.add (s, true);
#if RIPPLE_PROPOSE_AMENDMENTS
        SHAMapItem::pointer tItem = std::make_shared<SHAMapItem> (txID, s.peekData ());
        if (!initialPosition->addGiveItem (tItem, true, false))
        {
            if (m_journal.warning) m_journal.warning <<
                "Ledger already had amendment transaction";
        }
#endif
    }
}
Exemple #2
0
static Blob getSigningData (STTx const& that)
{
    Serializer s;
    s.add32 (HashPrefix::txSign);
    that.addWithoutSigningFields (s);
    return s.getData();
}
Exemple #3
0
std::tuple<TER, std::uint32_t,
    std::vector<SignerEntries::SignerEntry>,
        SetSignerList::Operation>
SetSignerList::determineOperation(STTx const& tx,
    ApplyFlags flags, beast::Journal j)
{
    // Check the quorum.  A non-zero quorum means we're creating or replacing
    // the list.  A zero quorum means we're destroying the list.
    auto const quorum = tx[sfSignerQuorum];
    std::vector<SignerEntries::SignerEntry> sign;
    Operation op = unknown;

    bool const hasSignerEntries(tx.isFieldPresent(sfSignerEntries));
    if (quorum && hasSignerEntries)
    {
        auto signers = SignerEntries::deserialize(tx, j, "transaction");

        if (signers.second != tesSUCCESS)
            return std::make_tuple(signers.second, quorum, sign, op);

        std::sort(signers.first.begin(), signers.first.end());

        // Save deserialized list for later.
        sign = std::move(signers.first);
        op = set;
    }
    else if ((quorum == 0) && !hasSignerEntries)
    {
        op = destroy;
    }

    return std::make_tuple(tesSUCCESS, quorum, sign, op);
}
Exemple #4
0
static
TxConsequences
invoke_calculateConsequences(STTx const& tx)
{
    switch (tx.getTxnType())
    {
    case ttACCOUNT_SET:     return invoke_calculateConsequences<SetAccount>(tx);
    case ttOFFER_CANCEL:    return invoke_calculateConsequences<CancelOffer>(tx);
    case ttOFFER_CREATE:    return invoke_calculateConsequences<CreateOffer>(tx);
    case ttPAYMENT:         return invoke_calculateConsequences<Payment>(tx);
    case ttSUSPAY_CREATE:   return invoke_calculateConsequences<SusPayCreate>(tx);
    case ttSUSPAY_FINISH:   return invoke_calculateConsequences<SusPayFinish>(tx);
    case ttSUSPAY_CANCEL:   return invoke_calculateConsequences<SusPayCancel>(tx);
    case ttREGULAR_KEY_SET: return invoke_calculateConsequences<SetRegularKey>(tx);
    case ttSIGNER_LIST_SET: return invoke_calculateConsequences<SetSignerList>(tx);
    case ttTICKET_CANCEL:   return invoke_calculateConsequences<CancelTicket>(tx);
    case ttTICKET_CREATE:   return invoke_calculateConsequences<CreateTicket>(tx);
    case ttTRUST_SET:       return invoke_calculateConsequences<SetTrust>(tx);
    case ttAMENDMENT:
    case ttFEE:
        // fall through to default
    default:
        assert(false);
        return { TxConsequences::blocker, Transactor::calculateFeePaid(tx),
            beast::zero };
    }
}
Exemple #5
0
static Blob getSigningData (STTx const& that)
{
    Serializer s;
    s.add32 (HashPrefix::txSign);
    that.add (s, false);
    return s.getData();
}
Exemple #6
0
std::pair<Validity, std::string>
checkValidity(HashRouter& router,
    STTx const& tx, Rules const& rules,
        Config const& config)
{
    auto const allowMultiSign =
        rules.enabled(featureMultiSign);

    auto const id = tx.getTransactionID();
    auto const flags = router.getFlags(id);
    if (flags & SF_SIGBAD)
        // Signature is known bad
        return {Validity::SigBad, "Transaction has bad signature."};

    if (!(flags & SF_SIGGOOD))
    {
        // Don't know signature state. Check it.
        auto const sigVerify = tx.checkSign(allowMultiSign);
        if (! sigVerify.first)
        {
            router.setFlags(id, SF_SIGBAD);
            return {Validity::SigBad, sigVerify.second};
        }
        router.setFlags(id, SF_SIGGOOD);
    }

    // Signature is now known good
    if (flags & SF_LOCALBAD)
        // ...but the local checks
        // are known bad.
        return {Validity::SigGoodOnly, "Local checks failed."};

    if (flags & SF_LOCALGOOD)
        // ...and the local checks
        // are known good.
        return {Validity::Valid, ""};

    // Do the local checks
    std::string reason;
    if (!passesLocalChecks(tx, reason))
    {
        router.setFlags(id, SF_LOCALBAD);
        return {Validity::SigGoodOnly, reason};
    }
    router.setFlags(id, SF_LOCALGOOD);
    return {Validity::Valid, ""};
}
Exemple #7
0
std::shared_ptr<STTx const>
sterilize (STTx const& stx)
{
    Serializer s;
    stx.add(s);
    SerialIter sit(s.slice());
    return std::make_shared<STTx const>(std::ref(sit));
}
Exemple #8
0
std::uint64_t Transactor::calculateBaseFee (
    ReadView const& view,
    STTx const& tx)
{
    // Returns the fee in fee units.

    // The computation has two parts:
    //  * The base fee, which is the same for most transactions.
    //  * The additional cost of each multisignature on the transaction.
    std::uint64_t baseFee = view.fees().units;

    // Each signer adds one more baseFee to the minimum required fee
    // for the transaction.
    std::uint32_t signerCount = 0;
    if (tx.isFieldPresent (sfSigners))
        signerCount = tx.getFieldArray (sfSigners).size();

    return baseFee + (signerCount * baseFee);
}
Exemple #9
0
ApplyResult
applyTransaction (Application& app, OpenView& view,
    STTx const& txn,
        bool retryAssured, ApplyFlags flags,
            beast::Journal j)
{
    // Returns false if the transaction has need not be retried.
    if (retryAssured)
        flags = flags | tapRETRY;

    JLOG (j.debug()) << "TXN "
        << txn.getTransactionID ()
        //<< (engine.view().open() ? " open" : " closed")
        // because of the optional in engine
        << (retryAssured ? "/retry" : "/final");

    try
    {
        auto const result = apply(app,
            view, txn, flags, j);
        if (result.second)
        {
            JLOG (j.debug())
                << "Transaction applied: " << transHuman (result.first);
            return ApplyResult::Success;
        }

        if (isTefFailure (result.first) || isTemMalformed (result.first) ||
            isTelLocal (result.first))
        {
            // failure
            JLOG (j.debug())
                << "Transaction failure: " << transHuman (result.first);
            return ApplyResult::Fail;
        }

        JLOG (j.debug())
            << "Transaction retry: " << transHuman (result.first);
        return ApplyResult::Retry;
    }
    catch (std::exception const&)
    {
        JLOG (j.warn()) << "Throws";
        return ApplyResult::Fail;
    }
}
Exemple #10
0
std::pair<TER, bool>
apply (OpenView& view,
       STTx const& tx, ApplyFlags flags,
       Config const& config,
       beast::Journal j)
{
    try
    {
        return invoke (tx.getTxnType(),
                       view, tx, flags, config, j);
    }
    catch(std::exception const& e)
    {
        JLOG(j.fatal) <<
                      "Caught exception: " << e.what();
        return { tefEXCEPTION, false };
    }
    catch(...)
    {
        JLOG(j.fatal) <<
                      "Caught unknown exception";
        return { tefEXCEPTION, false };
    }
}
Exemple #11
0
static
std::uint64_t
getFeeLevelPaid(
    STTx const& tx,
    std::uint64_t baseRefLevel,
    std::uint64_t refTxnCostDrops)
{
    // Compute the minimum XRP fee the transaction could pay
    auto requiredFee = getRequiredFeeLevel(tx.getTxnType());

    if (requiredFee == 0 ||
        refTxnCostDrops == 0)
        // If nothing is required, or the cost is 0,
        // the level is effectively infinite.
        return std::numeric_limits<std::uint64_t>::max();

    // TODO: getRequiredFeeLevel(ttREFERENCE)?
    auto referenceFee =
        ripple::getRequiredFeeLevel(ttACCOUNT_SET);
    // Don't care about the overflow flag
    return mulDiv(tx[sfFee].xrp().drops(),
        baseRefLevel * referenceFee,
            refTxnCostDrops * requiredFee).second;
}
Exemple #12
0
void
FeeVoteImpl::doVoting (Ledger::ref lastClosedLedger,
    std::shared_ptr<SHAMap> const& initialPosition)
{
    // LCL must be flag ledger
    assert ((lastClosedLedger->getLedgerSeq () % 256) == 0);

    detail::VotableInteger<std::uint64_t> baseFeeVote (
        lastClosedLedger->getBaseFee (), target_.reference_fee);

    detail::VotableInteger<std::uint32_t> baseReserveVote (
        lastClosedLedger->getReserve (0), target_.account_reserve);

    detail::VotableInteger<std::uint32_t> incReserveVote (
        lastClosedLedger->getReserveInc (), target_.owner_reserve);

    // get validations for ledger before flag
    ValidationSet const set =
        getApp().getValidations ().getValidations (
            lastClosedLedger->getParentHash ());
    for (auto const& e : set)
    {
        STValidation const& val = *e.second;

        if (val.isTrusted ())
        {
            if (val.isFieldPresent (sfBaseFee))
            {
                baseFeeVote.addVote (val.getFieldU64 (sfBaseFee));
            }
            else
            {
                baseFeeVote.noVote ();
            }

            if (val.isFieldPresent (sfReserveBase))
            {
                baseReserveVote.addVote (val.getFieldU32 (sfReserveBase));
            }
            else
            {
                baseReserveVote.noVote ();
            }

            if (val.isFieldPresent (sfReserveIncrement))
            {
                incReserveVote.addVote (val.getFieldU32 (sfReserveIncrement));
            }
            else
            {
                incReserveVote.noVote ();
            }
        }
    }

    // choose our positions
    std::uint64_t const baseFee = baseFeeVote.getVotes ();
    std::uint32_t const baseReserve = baseReserveVote.getVotes ();
    std::uint32_t const incReserve = incReserveVote.getVotes ();

    // add transactions to our position
    if ((baseFee != lastClosedLedger->getBaseFee ()) ||
            (baseReserve != lastClosedLedger->getReserve (0)) ||
            (incReserve != lastClosedLedger->getReserveInc ()))
    {
        if (journal_.warning) journal_.warning <<
            "We are voting for a fee change: " << baseFee <<
            "/" << baseReserve <<
            "/" << incReserve;

        STTx trans (ttFEE);
        trans.setFieldAccount (sfAccount, AccountID ());
        trans.setFieldU64 (sfBaseFee, baseFee);
        trans.setFieldU32 (sfReferenceFeeUnits, 10);
        trans.setFieldU32 (sfReserveBase, baseReserve);
        trans.setFieldU32 (sfReserveIncrement, incReserve);

        uint256 txID = trans.getTransactionID ();

        if (journal_.warning)
            journal_.warning << "Vote: " << txID;

        Serializer s;
        trans.add (s);

        auto tItem = std::make_shared<SHAMapItem> (txID, s.peekData ());

        if (!initialPosition->addGiveItem (tItem, true, false))
        {
            if (journal_.warning) journal_.warning <<
                "Ledger already had fee change";
        }
    }
}
Exemple #13
0
void
FeeVoteImpl::doVoting(
    std::shared_ptr<ReadView const> const& lastClosedLedger,
        ValidationSet const& set,
            std::shared_ptr<SHAMap> const& initialPosition)
{
    // LCL must be flag ledger
    assert ((lastClosedLedger->info().seq % 256) == 0);

    detail::VotableInteger<std::uint64_t> baseFeeVote (
        lastClosedLedger->fees().base, target_.reference_fee);

    detail::VotableInteger<std::uint32_t> baseReserveVote (
        lastClosedLedger->fees().accountReserve(0).drops(), target_.account_reserve);

    detail::VotableInteger<std::uint32_t> incReserveVote (
        lastClosedLedger->fees().increment, target_.owner_reserve);

    for (auto const& e : set)
    {
        STValidation const& val = *e.second;

        if (val.isTrusted ())
        {
            if (val.isFieldPresent (sfBaseFee))
            {
                baseFeeVote.addVote (val.getFieldU64 (sfBaseFee));
            }
            else
            {
                baseFeeVote.noVote ();
            }

            if (val.isFieldPresent (sfReserveBase))
            {
                baseReserveVote.addVote (val.getFieldU32 (sfReserveBase));
            }
            else
            {
                baseReserveVote.noVote ();
            }

            if (val.isFieldPresent (sfReserveIncrement))
            {
                incReserveVote.addVote (val.getFieldU32 (sfReserveIncrement));
            }
            else
            {
                incReserveVote.noVote ();
            }
        }
    }

    // choose our positions
    std::uint64_t const baseFee = baseFeeVote.getVotes ();
    std::uint32_t const baseReserve = baseReserveVote.getVotes ();
    std::uint32_t const incReserve = incReserveVote.getVotes ();
    std::uint32_t const feeUnits = target_.reference_fee_units;
    auto const seq = lastClosedLedger->info().seq + 1;

    // add transactions to our position
    if ((baseFee != lastClosedLedger->fees().base) ||
            (baseReserve != lastClosedLedger->fees().accountReserve(0)) ||
            (incReserve != lastClosedLedger->fees().increment))
    {
        if (journal_.warning) journal_.warning <<
            "We are voting for a fee change: " << baseFee <<
            "/" << baseReserve <<
            "/" << incReserve;

        STTx feeTx (ttFEE,
            [seq,baseFee,baseReserve,incReserve,feeUnits](auto& obj)
            {
                obj[sfAccount] = AccountID();
                obj[sfLedgerSequence] = seq;
                obj[sfBaseFee] = baseFee;
                obj[sfReserveBase] = baseReserve;
                obj[sfReserveIncrement] = incReserve;
                obj[sfReferenceFeeUnits] = feeUnits;
            });

        uint256 txID = feeTx.getTransactionID ();

        if (journal_.warning)
            journal_.warning << "Vote: " << txID;

        Serializer s;
        feeTx.add (s);

        auto tItem = std::make_shared<SHAMapItem> (txID, s.peekData ());

        if (!initialPosition->addGiveItem (tItem, true, false))
        {
            if (journal_.warning) journal_.warning <<
                "Ledger already had fee change";
        }
    }
}
Exemple #14
0
TER TransactionEngine::applyTransaction (
    STTx const& txn,
    TransactionEngineParams params,
    bool& didApply)
{
    WriteLog (lsTRACE, TransactionEngine) << "applyTransaction>";
    didApply = false;
    assert (mLedger);
    uint256 const& txID = txn.getTransactionID ();
    mNodes.init (mLedger, txID, mLedger->getLedgerSeq (), params);

#ifdef BEAST_DEBUG
    if (1)
    {
        Serializer ser;
        txn.add (ser);
        SerializerIterator sit (ser);
        STTx s2 (sit);

        if (!s2.isEquivalent (txn))
        {
            WriteLog (lsFATAL, TransactionEngine) <<
                "Transaction serdes mismatch";
            WriteLog (lsINFO, TransactionEngine) << txn.getJson (0);
            WriteLog (lsFATAL, TransactionEngine) << s2.getJson (0);
            assert (false);
        }
    }
#endif

    if (!txID)
    {
        WriteLog (lsWARNING, TransactionEngine) <<
            "applyTransaction: invalid transaction id";
        return temINVALID;
    }

    TER terResult = Transactor::transact (txn, params, this);

    if (terResult == temUNKNOWN)
    {
        WriteLog (lsWARNING, TransactionEngine) <<
            "applyTransaction: Invalid transaction: unknown transaction type";
        return temUNKNOWN;
    }

    if (ShouldLog (lsDEBUG, TransactionEngine))
    {
        std::string strToken;
        std::string strHuman;

        transResultInfo (terResult, strToken, strHuman);

        WriteLog (lsDEBUG, TransactionEngine) <<
            "applyTransaction: terResult=" << strToken <<
            " : " << terResult <<
            " : " << strHuman;
    }

    if (isTesSuccess (terResult))
        didApply = true;
    else if (isTecClaim (terResult) && !(params & tapRETRY))
    {
        // only claim the transaction fee
        WriteLog (lsDEBUG, TransactionEngine) << "Reprocessing to only claim fee";
        mNodes.clear ();

        SLE::pointer txnAcct = entryCache (ltACCOUNT_ROOT,
            getAccountRootIndex (txn.getSourceAccount ()));

        if (!txnAcct)
            terResult = terNO_ACCOUNT;
        else
        {
            std::uint32_t t_seq = txn.getSequence ();
            std::uint32_t a_seq = txnAcct->getFieldU32 (sfSequence);

            if (a_seq < t_seq)
                terResult = terPRE_SEQ;
            else if (a_seq > t_seq)
                terResult = tefPAST_SEQ;
            else
            {
                STAmount fee        = txn.getTransactionFee ();
                STAmount balance    = txnAcct->getFieldAmount (sfBalance);
                STAmount balanceVBC = txnAcct->getFieldAmount(sfBalanceVBC);

                // We retry/reject the transaction if the account
                // balance is zero or we're applying against an open
                // ledger and the balance is less than the fee
                if ((balance == zero) || (balanceVBC.getNValue() == 0) ||
                    ((params & tapOPEN_LEDGER) && (balance < fee)))
                {
                    // Account has no funds or ledger is open
                    terResult = terINSUF_FEE_B;
                }
                else
                {
                    if (fee > balance)
                        fee = balance;
                    txnAcct->setFieldAmount (sfBalance, balance - fee);
                    txnAcct->setFieldAmount(sfBalanceVBC, balanceVBC);
                    txnAcct->setFieldU32 (sfSequence, t_seq + 1);
                    entryModify (txnAcct);
                    didApply = true;
                }
            }
        }
    }
    else
        WriteLog (lsDEBUG, TransactionEngine) << "Not applying transaction " << txID;

    if (didApply)
    {
        if (!checkInvariants (terResult, txn, params))
        {
            WriteLog (lsFATAL, TransactionEngine) <<
                "Transaction violates invariants";
            WriteLog (lsFATAL, TransactionEngine) <<
                txn.getJson (0);
            WriteLog (lsFATAL, TransactionEngine) <<
                transToken (terResult) << ": " << transHuman (terResult);
            WriteLog (lsFATAL, TransactionEngine) <<
                mNodes.getJson (0);
            didApply = false;
            terResult = tefINTERNAL;
        }
        else
        {
            // Transaction succeeded fully or (retries are not allowed and the
            // transaction could claim a fee)
            Serializer m;
            mNodes.calcRawMeta (m, terResult, mTxnSeq++);

            txnWrite ();

            Serializer s;
            txn.add (s);

            if (params & tapOPEN_LEDGER)
            {
                if (!mLedger->addTransaction (txID, s))
                {
                    WriteLog (lsFATAL, TransactionEngine) <<
                        "Tried to add transaction to open ledger that already had it";
                    assert (false);
                    throw std::runtime_error ("Duplicate transaction applied");
                }
            }
            else
            {
                if (!mLedger->addTransaction (txID, s, m))
                {
                    WriteLog (lsFATAL, TransactionEngine) <<
                        "Tried to add transaction to ledger that already had it";
                    assert (false);
                    throw std::runtime_error ("Duplicate transaction applied to closed ledger");
                }

                // Charge whatever fee they specified.
                STAmount saPaid = txn.getTransactionFee ();
                mLedger->destroyCoins (saPaid.getNValue ());
            }
        }
    }

    mTxnAccount.reset ();
    mNodes.clear ();

    if (!(params & tapOPEN_LEDGER) && isTemMalformed (terResult))
    {
        // XXX Malformed or failed transaction in closed ledger must bow out.
    }

    return terResult;
}
Exemple #15
0
    void run()
    {
        RippleAddress seed;
        seed.setSeedRandom ();
        RippleAddress generator = RippleAddress::createGeneratorPublic (seed);
        RippleAddress publicAcct = RippleAddress::createAccountPublic (generator, 1);
        RippleAddress privateAcct = RippleAddress::createAccountPrivate (generator, seed, 1);

        STTx j (ttACCOUNT_SET);
        j.setSourceAccount (publicAcct);
        j.setSigningPubKey (publicAcct);
        j.setFieldVL (sfMessageKey, publicAcct.getAccountPublic ());
        j.sign (privateAcct);

        unexpected (!j.checkSign (), "Transaction fails signature test");

        Serializer rawTxn;
        j.add (rawTxn);
        SerialIter sit (rawTxn);
        STTx copy (sit);

        if (copy != j)
        {
            log << j.getJson (0);
            log << copy.getJson (0);
            fail ("Transaction fails serialize/deserialize test");
        }
        else
        {
            pass ();
        }

        STParsedJSONObject parsed ("test", j.getJson (0));
        if (!parsed.object)
            fail ("Unable to build object from json");

        if (STObject (j) != parsed.object)
        {
            log << "ORIG: " << j.getJson (0);
            log << "BUILT " << parsed.object->getJson (0);
            fail ("Built a different transaction");
        }
        else
        {
            pass ();
        }
    }