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; }
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); } }
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); } }
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; }
// { // 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; }