예제 #1
0
TER
CancelTicket::doApply ()
{
    uint256 const ticketId = ctx_.tx.getFieldH256 (sfTicketID);

    // VFALCO This is highly suspicious, we're requiring that the
    //        transaction provide the return value of getTicketIndex?
    SLE::pointer sleTicket = view().peek (keylet::ticket(ticketId));

    if (!sleTicket)
        return tecNO_ENTRY;

    auto const ticket_owner =
        sleTicket->getAccountID (sfAccount);

    bool authorized =
        account_ == ticket_owner;

    // The target can also always remove a ticket
    if (!authorized && sleTicket->isFieldPresent (sfTarget))
        authorized = (account_ == sleTicket->getAccountID (sfTarget));

    // And finally, anyone can remove an expired ticket
    if (!authorized && sleTicket->isFieldPresent (sfExpiration))
    {
        using tp = NetClock::time_point;
        using d = tp::duration;
        auto const expiration = tp{d{sleTicket->getFieldU32(sfExpiration)}};

        if (view().parentCloseTime() >= expiration)
            authorized = true;
    }

    if (!authorized)
        return tecNO_PERMISSION;

    std::uint64_t const hint (sleTicket->getFieldU64 (sfOwnerNode));

    if (! ctx_.view().dirRemove(
            keylet::ownerDir(ticket_owner), hint, ticketId, false))
    {
        return tefBAD_LEDGER;
    }

    auto viewJ = ctx_.app.journal ("View");
    adjustOwnerCount(view(), view().peek(
        keylet::account(ticket_owner)), -1, viewJ);
    ctx_.view ().erase (sleTicket);

    return tesSUCCESS;
}
예제 #2
0
void AccountItems::fillItems (const uint160& accountID, Ledger::ref ledger)
{
    uint256 const rootIndex = Ledger::getOwnerDirIndex (accountID);
    uint256 currentIndex    = rootIndex;

    // VFALCO TODO Rewrite all infinite loops to have clear terminating
    //             conditions defined in one location.
    //
    while (1)
    {
        SLE::pointer ownerDir   = ledger->getDirNode (currentIndex);

        // VFALCO TODO Rewrite to not return from the middle of the function
        if (!ownerDir)
            return;

        BOOST_FOREACH (uint256 const & uNode, ownerDir->getFieldV256 (sfIndexes).peekValue ())
        {
            // VFALCO TODO rename getSLEi() to something legible.
            SLE::pointer sleCur = ledger->getSLEi (uNode);

            if (!sleCur)
            {
                // item in directory not in ledger
            }
            else
            {
                AccountItem::pointer item = mOfType->makeItem (accountID, sleCur);

                // VFALCO NOTE Under what conditions would makeItem() return nullptr?
                // DJS NOTE If the item wasn't one this particular AccountItems was interested in
                // (For example, if the owner is only interested in ripple lines and this is an offer)
                if (item)
                {
                    mItems.push_back (item);
                }
            }
        }

        std::uint64_t uNodeNext    = ownerDir->getFieldU64 (sfIndexNext);

        // VFALCO TODO Rewrite to not return from the middle of the function
        if (!uNodeNext)
            return;

        currentIndex = Ledger::getDirNodeIndex (rootIndex, uNodeNext);
    }
}
예제 #3
0
void AccountItems::fillItems (Account const& accountID, Ledger::ref ledger)
{
    uint256 const rootIndex = Ledger::getOwnerDirIndex (accountID);
    uint256 currentIndex    = rootIndex;

    // VFALCO TODO Rewrite all infinite loops to have clear terminating
    //             conditions defined in one location.
    //
    while (1)
    {
        SLE::pointer ownerDir   = ledger->getDirNode (currentIndex);

        // VFALCO TODO Rewrite to not return from the middle of the function
        if (!ownerDir)
            return;

        for (auto const& uNode: ownerDir->getFieldV256 (sfIndexes).peekValue ())
        {
            // VFALCO TODO rename getSLEi() to something legible.
            SLE::pointer sleCur = ledger->getSLEi (uNode);

            if (sleCur)
            {
                // The item in the directory is in ledger
                auto item = mOfType->makeItem (accountID, sleCur);

                // makeItem() returns nullptr if the item wasn't one this
                // particular AccountItems was interested in - for example, if
                // the owner is only interested in ripple lines and this is an
                // offer.
                if (item)
                    mItems.push_back (item);
            }
        }

        std::uint64_t uNodeNext    = ownerDir->getFieldU64 (sfIndexNext);

        if (!uNodeNext)
            return;

        currentIndex = Ledger::getDirNodeIndex (rootIndex, uNodeNext);
    }
}
예제 #4
0
    TER doApply () override
    {
        assert (mTxnAccount);

        uint256 const ticketId = mTxn.getFieldH256 (sfTicketID);

        SLE::pointer sleTicket = mEngine->view ().entryCache (ltTICKET, ticketId);

        if (!sleTicket)
            return tecNO_ENTRY;

        Account const ticket_owner (sleTicket->getFieldAccount160 (sfAccount));

        bool authorized (mTxnAccountID == ticket_owner);

        // The target can also always remove a ticket
        if (!authorized && sleTicket->isFieldPresent (sfTarget))
            authorized = (mTxnAccountID == sleTicket->getFieldAccount160 (sfTarget));

        // And finally, anyone can remove an expired ticket
        if (!authorized && sleTicket->isFieldPresent (sfExpiration))
        {
            std::uint32_t const expiration = sleTicket->getFieldU32 (sfExpiration);

            if (mEngine->getLedger ()->getParentCloseTimeNC () >= expiration)
                authorized = true;
        }

        if (!authorized)
            return tecNO_PERMISSION;

        std::uint64_t const hint (sleTicket->getFieldU64 (sfOwnerNode));

        TER const result = mEngine->view ().dirDelete (false, hint,
            getOwnerDirIndex (ticket_owner), ticketId, false, (hint == 0));

        mEngine->view ().decrementOwnerCount (mTxnAccount);
        mEngine->view ().entryDelete (sleTicket);

        return result;
    }
예제 #5
0
// {
//   account: <account>|<account_public_key>
//   account_index: <number>        // optional, defaults to 0.
//   ledger_hash : <ledger>
//   ledger_index : <ledger_index>
//   limit: integer                 // optional
//   marker: opaque                 // optional, resume previous query
// }
Json::Value doAccountOffers (RPC::Context& context)
{
    auto const& params (context.params_);

    Ledger::pointer ledger;
    Json::Value result (RPC::lookupLedger (params, ledger, context.netOps_));

    if (! ledger)
        return result;

    if (! params.isMember (jss::account))
        return RPC::missing_field_error ("account");

    std::string strIdent (params[jss::account].asString ());
    bool bIndex (params.isMember (jss::account_index));
    int const iIndex (bIndex ? params[jss::account_index].asUInt () : 0);

    RippleAddress rippleAddress;

    result = RPC::accountFromString (ledger, rippleAddress, bIndex, strIdent,
        iIndex, false, context.netOps_);

    if (! result.empty ())
        return result;

    // Get info on account.
    result[jss::account] = rippleAddress.humanAccountID ();

    if (bIndex)
        result[jss::account_index] = iIndex;

    if (! ledger->hasAccount (rippleAddress))
        return rpcError (rpcACT_NOT_FOUND);

    unsigned int limit;
    if (params.isMember (jss::limit))
    {
        limit = std::max (RPC::Tuning::minOffersPerRequest,
            std::min (params[jss::limit].asUInt (),
            RPC::Tuning::maxOffersPerRequest));
    }
    else
    {
        limit = RPC::Tuning::defaultOffersPerRequest;
    }
    
    Account const& raAccount (rippleAddress.getAccountID ());
    Json::Value& jsonOffers (result[jss::offers] = Json::arrayValue); 
    std::vector <SLE::pointer> offers;
    unsigned int reserve (limit);
    uint256 startAfter;
    std::uint64_t startHint;

    if (params.isMember(jss::marker))
    {
        // We have a start point. Use limit - 1 from the result and use the
        // very last one for the resume.        
        Json::Value const& marker (params[jss::marker]);

        if (! marker.isString ())
            return rpcError (rpcACT_MALFORMED);

        startAfter.SetHex (marker.asString ());
        SLE::pointer sleOffer (ledger->getSLEi (startAfter));

        if (sleOffer == nullptr ||
            sleOffer->getType () != ltOFFER ||
            raAccount != sleOffer->getFieldAccount160 (sfAccount))
        {
            return rpcError (rpcINVALID_PARAMS);
        }

        startHint = sleOffer->getFieldU64(sfOwnerNode);

        // Caller provided the first offer (startAfter), add it as first result
        Json::Value& obj (jsonOffers.append (Json::objectValue));
        sleOffer->getFieldAmount (sfTakerPays).setJson (obj[jss::taker_pays]);
        sleOffer->getFieldAmount (sfTakerGets).setJson (obj[jss::taker_gets]);
        obj[jss::seq] = sleOffer->getFieldU32 (sfSequence);
        obj[jss::flags] = sleOffer->getFieldU32 (sfFlags);            

        offers.reserve (reserve);
    }
    else
    {
        startHint = 0;
        // We have no start point, limit should be one higher than requested.            
        offers.reserve (++reserve);
    }

    if (! ledger->visitAccountItems (raAccount, startAfter, startHint, reserve,
        [&offers](SLE::ref offer)
        {
            if (offer->getType () == ltOFFER)
            {
                offers.emplace_back (offer);
                return true;
            }

            return false;
        }))
    {
        return rpcError (rpcINVALID_PARAMS);
    }

    if (offers.size () == reserve)
    {
        result[jss::limit] = limit;

        result[jss::marker] = to_string (offers.back ()->getIndex ());        
        offers.pop_back ();
    }

    for (auto const& offer : offers)
    {
        Json::Value& obj (jsonOffers.append (Json::objectValue));
        offer->getFieldAmount (sfTakerPays).setJson (obj[jss::taker_pays]);
        offer->getFieldAmount (sfTakerGets).setJson (obj[jss::taker_gets]);
        obj[jss::seq] = offer->getFieldU32 (sfSequence);
        obj[jss::flags] = offer->getFieldU32 (sfFlags);            
    }

    context.loadType_ = Resource::feeMediumBurdenRPC;
    return result;
}