Json::Value doAccountObjects (RPC::Context& context) { auto const& params = context.params; if (! params.isMember (jss::account)) return RPC::missing_field_error (jss::account); Ledger::pointer ledger; auto result = RPC::lookupLedger (params, ledger, context.netOps); if (ledger == nullptr) return result; DivvyAddress raAccount; { bool bIndex; auto const strIdent = params[jss::account].asString (); auto iIndex = context.params.isMember (jss::account_index) ? context.params[jss::account_index].asUInt () : 0; auto jv = RPC::accountFromString ( raAccount, bIndex, strIdent, iIndex, false); if (! jv.empty ()) { for (auto it = jv.begin (); it != jv.end (); ++it) result[it.memberName ()] = it.key (); return result; } } if (! ledger->exists(getAccountRootIndex( raAccount.getAccountID()))) return rpcError (rpcACT_NOT_FOUND); auto type = ltINVALID; if (params.isMember (jss::type)) { using filter_types = std::vector <std::pair <std::string, LedgerEntryType>>; static beast::static_initializer <filter_types> const types ([]() -> filter_types { return { { "account", ltACCOUNT_ROOT }, { "amendments", ltAMENDMENTS }, { "directory", ltDIR_NODE }, { "fee", ltFEE_SETTINGS }, { "hashes", ltLEDGER_HASHES }, { "offer", ltOFFER }, { "state", ltRIPPLE_STATE }, { "ticket", ltTICKET } }; }()); auto const& p = params[jss::type]; if (! p.isString ()) return RPC::expected_field_error (jss::type, "string"); auto const filter = p.asString (); auto iter = std::find_if (types->begin (), types->end (), [&filter](decltype (types->front ())& t) { return t.first == filter; }); if (iter == types->end ()) return RPC::invalid_field_error (jss::type); type = iter->second; } auto limit = RPC::Tuning::defaultObjectsPerRequest; if (params.isMember (jss::limit)) { auto const& jvLimit = params[jss::limit]; if (! jvLimit.isIntegral ()) return RPC::expected_field_error (jss::limit, "unsigned integer"); limit = jvLimit.isUInt () ? jvLimit.asUInt () : std::max (0, jvLimit.asInt ()); if (context.role != Role::ADMIN) { limit = std::max (RPC::Tuning::minObjectsPerRequest, std::min (limit, RPC::Tuning::maxObjectsPerRequest)); } } uint256 dirIndex; uint256 entryIndex; if (params.isMember (jss::marker)) { auto const& marker = params[jss::marker]; if (! marker.isString ()) return RPC::expected_field_error (jss::marker, "string"); std::stringstream ss (marker.asString ()); std::string s; if (!std::getline(ss, s, ',')) return RPC::invalid_field_error (jss::marker); if (! dirIndex.SetHex (s)) return RPC::invalid_field_error (jss::marker); if (! std::getline (ss, s, ',')) return RPC::invalid_field_error (jss::marker); if (! entryIndex.SetHex (s)) return RPC::invalid_field_error (jss::marker); } if (! RPC::getAccountObjects (*ledger, raAccount.getAccountID (), type, dirIndex, entryIndex, limit, result)) { return RPC::invalid_field_error (jss::marker); } result[jss::account] = raAccount.humanAccountID (); context.loadType = Resource::feeMediumBurdenRPC; 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 doAccountLines (RPC::Context& context) { auto const& params (context.params); if (! params.isMember (jss::account)) return RPC::missing_field_error (jss::account); Ledger::pointer ledger; Json::Value result (RPC::lookupLedger (params, ledger, context.netOps)); if (! ledger) return result; std::string strIdent (params[jss::account].asString ()); bool bIndex (params.isMember (jss::account_index)); int iIndex (bIndex ? params[jss::account_index].asUInt () : 0); DivvyAddress divvyAddress; auto jv = RPC::accountFromString ( divvyAddress, bIndex, strIdent, iIndex, false); if (! jv.empty ()) { for (auto it = jv.begin (); it != jv.end (); ++it) result[it.memberName ()] = it.key (); return result; } if (! ledger->exists(getAccountRootIndex( divvyAddress.getAccountID()))) return rpcError (rpcACT_NOT_FOUND); std::string strPeer (params.isMember (jss::peer) ? params[jss::peer].asString () : ""); bool bPeerIndex (params.isMember (jss::peer_index)); int iPeerIndex (bIndex ? params[jss::peer_index].asUInt () : 0); DivvyAddress divvyAddressPeer; if (! strPeer.empty ()) { result[jss::peer] = divvyAddress.humanAccountID (); if (bPeerIndex) result[jss::peer_index] = iPeerIndex; result = RPC::accountFromString ( divvyAddressPeer, bPeerIndex, strPeer, iPeerIndex, false); if (! result.empty ()) return result; } AccountID raPeerAccount; if (divvyAddressPeer.isValid ()) raPeerAccount = divvyAddressPeer.getAccountID (); unsigned int limit; if (params.isMember (jss::limit)) { auto const& jvLimit (params[jss::limit]); if (! jvLimit.isIntegral ()) return RPC::expected_field_error (jss::limit, "unsigned integer"); limit = jvLimit.isUInt () ? jvLimit.asUInt () : std::max (0, jvLimit.asInt ()); if (context.role != Role::ADMIN) { limit = std::max (RPC::Tuning::minLinesPerRequest, std::min (limit, RPC::Tuning::maxLinesPerRequest)); } } else { limit = RPC::Tuning::defaultLinesPerRequest; } Json::Value& jsonLines (result[jss::lines] = Json::arrayValue); AccountID const& raAccount(divvyAddress.getAccountID ()); VisitData visitData = { {}, raAccount, divvyAddressPeer, raPeerAccount }; 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 RPC::expected_field_error (jss::marker, "string"); startAfter.SetHex (marker.asString ()); auto const sleLine = fetch(*ledger, startAfter, getApp().getSLECache()); if (sleLine == nullptr || sleLine->getType () != ltRIPPLE_STATE) return rpcError (rpcINVALID_PARAMS); if (sleLine->getFieldAmount (sfLowLimit).getIssuer () == raAccount) startHint = sleLine->getFieldU64 (sfLowNode); else if (sleLine->getFieldAmount (sfHighLimit).getIssuer () == raAccount) startHint = sleLine->getFieldU64 (sfHighNode); else return rpcError (rpcINVALID_PARAMS); // Caller provided the first line (startAfter), add it as first result auto const line = DivvyState::makeItem (raAccount, sleLine); if (line == nullptr) return rpcError (rpcINVALID_PARAMS); addLine (jsonLines, *line); visitData.items.reserve (reserve); } else { startHint = 0; // We have no start point, limit should be one higher than requested. visitData.items.reserve (++reserve); } if (! forEachItemAfter(*ledger, raAccount, getApp().getSLECache(), startAfter, startHint, reserve, [&visitData](std::shared_ptr<SLE const> const& sleCur) { auto const line = DivvyState::makeItem (visitData.accountID, sleCur); if (line != nullptr && (! visitData.divvyAddressPeer.isValid () || visitData.raPeerAccount == line->getAccountIDPeer ())) { visitData.items.emplace_back (line); return true; } return false; })) { return rpcError (rpcINVALID_PARAMS); } if (visitData.items.size () == reserve) { result[jss::limit] = limit; DivvyState::pointer line (visitData.items.back ()); result[jss::marker] = to_string (line->key()); visitData.items.pop_back (); } result[jss::account] = divvyAddress.humanAccountID (); for (auto const& item : visitData.items) addLine (jsonLines, *item.get ()); context.loadType = Resource::feeMediumBurdenRPC; 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); if (! params.isMember (jss::account)) return RPC::missing_field_error (jss::account); Ledger::pointer ledger; Json::Value result (RPC::lookupLedger (params, ledger, context.netOps)); if (! ledger) return result; std::string strIdent (params[jss::account].asString ()); bool bIndex (params.isMember (jss::account_index)); int const iIndex (bIndex ? params[jss::account_index].asUInt () : 0); DivvyAddress divvyAddress; Json::Value const jv = RPC::accountFromString ( divvyAddress, bIndex, strIdent, iIndex, false); if (! jv.empty ()) { for (Json::Value::const_iterator it (jv.begin ()); it != jv.end (); ++it) result[it.memberName ()] = it.key (); return result; } // Get info on account. result[jss::account] = divvyAddress.humanAccountID (); if (bIndex) result[jss::account_index] = iIndex; if (! ledger->exists(getAccountRootIndex( divvyAddress.getAccountID()))) return rpcError (rpcACT_NOT_FOUND); unsigned int limit; if (params.isMember (jss::limit)) { auto const& jvLimit (params[jss::limit]); if (! jvLimit.isIntegral ()) return RPC::expected_field_error (jss::limit, "unsigned integer"); limit = jvLimit.isUInt () ? jvLimit.asUInt () : std::max (0, jvLimit.asInt ()); if (context.role != Role::ADMIN) { limit = std::max (RPC::Tuning::minOffersPerRequest, std::min (limit, RPC::Tuning::maxOffersPerRequest)); } } else { limit = RPC::Tuning::defaultOffersPerRequest; } AccountID const& raAccount (divvyAddress.getAccountID ()); Json::Value& jsonOffers (result[jss::offers] = Json::arrayValue); std::vector <std::shared_ptr<SLE const>> 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 RPC::expected_field_error (jss::marker, "string"); startAfter.SetHex (marker.asString ()); auto const sleOffer = fetch (*ledger, startAfter, getApp().getSLECache()); 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 (! forEachItemAfter(*ledger, raAccount, getApp().getSLECache(), startAfter, startHint, reserve, [&offers](std::shared_ptr<SLE const> const& 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; }