// { // account: [<account>|<account_public_key>] // peer: [<account>|<account_public_key>] // currency: <currency> // ledger_hash : <ledger> // ledger_index : <ledger_index> // } json::value doaccountasset (rpc::context& context) { auto const& params(context.params); if (!params.ismember(jss::account)) return rpc::missing_field_error("account"); if (!params.ismember(jss::peer)) return rpc::missing_field_error("peer"); if (!params.ismember(jss::currency)) return rpc::missing_field_error("currency"); 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); rippleaddress rippleaddress; json::value const jv(rpc::accountfromstring(ledger, rippleaddress, bindex, strident, iindex, false, context.netops)); if (!jv.empty()) { for (json::value::const_iterator it(jv.begin()); it != jv.end(); ++it) result[it.membername()] = it.key(); return result; } if (!ledger->hasaccount(rippleaddress)) 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); rippleaddress rippleaddresspeer; json::value const jvpeer(rpc::accountfromstring(ledger, rippleaddresspeer, bpeerindex, strpeer, ipeerindex, false, context.netops)); if (!jvpeer.empty()) { return result; } if (!ledger->hasaccount(rippleaddresspeer)) return rpcerror(rpcact_not_found); currency ucurrency; if (!to_currency(ucurrency, params[jss::currency].asstring())) return rpc::make_error(rpcsrc_cur_malformed, "invalid field 'currency', bad currency."); account const& raaccount(rippleaddress.getaccountid()); account const& rapeeraccount(rippleaddresspeer.getaccountid()); uint256 unodeindex = getripplestateindex(raaccount, rapeeraccount, ucurrency); auto slenode = context.netops.getslei(ledger, unodeindex); auto const line(ripplestate::makeitem(raaccount, slenode)); if (line == nullptr || raaccount != line->getaccountid() || rapeeraccount != line->getaccountidpeer()) return result; json::value jsonlines(json::arrayvalue); addline(jsonlines, *line, ledger); result[jss::lines] = jsonlines[0u]; json::value& jsonassetstates(result[jss::states] = json::arrayvalue); // get asset_states for currency asset. if (assetcurrency() == line->getbalance().getcurrency()) { auto lpledger = std::make_shared<ledger> (std::ref (*ledger), false); ledgerentryset les(lpledger, tapnone); auto sleripplestate = les.entrycache(ltripple_state, getripplestateindex(raaccount, rapeeraccount, assetcurrency())); les.assetrelease(raaccount, rapeeraccount, assetcurrency(), sleripplestate); uint256 baseindex = getassetstateindex(line->getaccountid(), line->getaccountidpeer(), assetcurrency()); uint256 assetstateindex = getqualityindex(baseindex); uint256 assetstateend = getqualitynext(assetstateindex); for (;;) { auto const& sle = les.entrycache(ltasset_state, assetstateindex); if (sle) { stamount amount = sle->getfieldamount(sfamount); stamount released = sle->getfieldamount(sfdeliveredamount); if (sle->getfieldaccount160(sfaccount) == line->getaccountidpeer()) { amount.negate(); released.negate(); } auto reserved = released ? amount - released : amount; json::value& state(jsonassetstates.append(json::objectvalue)); state[jss::date] = static_cast<json::uint>(getquality(assetstateindex)); state[jss::amount] = amount.gettext(); state[jss::reserve] = reserved.gettext(); } auto const nextassetstate( les.getnextledgerindex(assetstateindex, assetstateend)); if (nextassetstate.iszero()) break; assetstateindex = nextassetstate; } } 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 ("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); rippleaddress rippleaddress; json::value const jv (rpc::accountfromstring (ledger, rippleaddress, bindex, strident, iindex, false, context.netops)); if (! jv.empty ()) { for (json::value::const_iterator it (jv.begin ()); it != jv.end (); ++it) result[it.membername ()] = it.key (); return result; } if (! ledger->hasaccount (rippleaddress)) 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); rippleaddress rippleaddresspeer; if (! strpeer.empty ()) { result[jss::peer] = rippleaddress.humanaccountid (); if (bpeerindex) result[jss::peer_index] = ipeerindex; result = rpc::accountfromstring (ledger, rippleaddresspeer, bpeerindex, strpeer, ipeerindex, false, context.netops); if (! result.empty ()) return result; } account rapeeraccount; if (rippleaddresspeer.isvalid ()) rapeeraccount = rippleaddresspeer.getaccountid (); unsigned int limit; if (params.ismember (jss::limit)) { auto const& jvlimit (params[jss::limit]); if (! jvlimit.isintegral ()) return rpc::expected_field_error ("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); account const& raaccount(rippleaddress.getaccountid ()); visitdata visitdata = { {}, raaccount, rippleaddresspeer, 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 ("marker", "string"); startafter.sethex (marker.asstring ()); sle::pointer sleline (ledger->getslei (startafter)); 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 (ripplestate::makeitem (raaccount, sleline)); if (line == nullptr) return rpcerror (rpcinvalid_params); addline (jsonlines, *line, ledger); visitdata.items.reserve (reserve); } else { starthint = 0; // we have no start point, limit should be one higher than requested. visitdata.items.reserve (++reserve); } if (! ledger->visitaccountitems (raaccount, startafter, starthint, reserve, [&visitdata](sle::ref slecur) { auto const line (ripplestate::makeitem (visitdata.accountid, slecur)); if (line != nullptr && (! visitdata.rippleaddresspeer.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; ripplestate::pointer line (visitdata.items.back ()); result[jss::marker] = to_string (line->peeksle ().getindex ()); visitdata.items.pop_back (); } result[jss::account] = rippleaddress.humanaccountid (); for (auto const& item : visitdata.items) addline (jsonlines, *item.get (), ledger); 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 ("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); rippleaddress rippleaddress; json::value const jv (rpc::accountfromstring (ledger, rippleaddress, bindex, strident, iindex, false, context.netops)); 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] = 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)) { auto const& jvlimit (params[jss::limit]); if (! jvlimit.isintegral ()) return rpc::expected_field_error ("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; } 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 rpc::expected_field_error ("marker", "string"); 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; }