Json::Value RPCHandler::doPrint (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { masterLockHolder.unlock (); JsonPropertyStream stream; if (params.isObject() && params["params"].isArray() && params["params"][0u].isString ()) getApp().write (stream, params["params"][0u].asString()); else getApp().write (stream); return stream.top(); }
// { // // if either of these parameters is set, a custom generator is used // difficulty: <number> // optional // secret: <secret> // optional // } Json::Value RPCHandler::doProofCreate (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { masterLockHolder.unlock (); // XXX: Add ability to create proof with arbitrary time Json::Value jvResult (Json::objectValue); if (params.isMember ("difficulty") || params.isMember ("secret")) { // VFALCO TODO why aren't we using the app's factory? std::unique_ptr <ProofOfWorkFactory> pgGen (ProofOfWorkFactory::New ()); if (params.isMember ("difficulty")) { if (!params["difficulty"].isIntegral ()) return RPC::invalid_field_error ("difficulty"); int const iDifficulty (params["difficulty"].asInt ()); if (iDifficulty < 0 || iDifficulty > ProofOfWorkFactory::kMaxDifficulty) return RPC::invalid_field_error ("difficulty"); pgGen->setDifficulty (iDifficulty); } if (params.isMember ("secret")) { uint256 uSecret (params["secret"].asString ()); pgGen->setSecret (uSecret); } jvResult["token"] = pgGen->getProof ().getToken (); jvResult["secret"] = pgGen->getSecret ().GetHex (); } else { jvResult["token"] = getApp().getProofOfWorkFactory ().getProof ().getToken (); } return jvResult; }
// { // transaction: <hex> // } Json::Value RPCHandler::doTx (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { masterLockHolder.unlock (); if (!params.isMember ("transaction")) return rpcError (rpcINVALID_PARAMS); bool binary = params.isMember ("binary") && params["binary"].asBool (); std::string strTransaction = params["transaction"].asString (); if (Transaction::isHexTxID (strTransaction)) { // transaction by ID uint256 txid (strTransaction); Transaction::pointer txn = getApp().getMasterTransaction ().fetch (txid, true); if (!txn) return rpcError (rpcTXN_NOT_FOUND); #ifdef READY_FOR_NEW_TX_FORMAT Json::Value ret; ret["transaction"] = txn->getJson (0, binary); #else Json::Value ret = txn->getJson (0, binary); #endif if (txn->getLedger () != 0) { Ledger::pointer lgr = mNetOps->getLedgerBySeq (txn->getLedger ()); if (lgr) { bool okay = false; if (binary) { std::string meta; if (lgr->getMetaHex (txid, meta)) { ret["meta"] = meta; okay = true; } } else { TransactionMetaSet::pointer set; if (lgr->getTransactionMeta (txid, set)) { okay = true; ret["meta"] = set->getJson (0); } } if (okay) ret["validated"] = mNetOps->isValidated (lgr); } } return ret; } return rpcError (rpcNOT_IMPL); }
// { // ledger_hash : <ledger> // ledger_index : <ledger_index> // ... // } Json::Value RPCHandler::doLedgerEntry (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { masterLockHolder.unlock (); Ledger::pointer lpLedger; Json::Value jvResult = RPC::lookupLedger (params, lpLedger, *mNetOps); if (!lpLedger) return jvResult; uint256 uNodeIndex; bool bNodeBinary = false; if (params.isMember ("index")) { // XXX Needs to provide proof. uNodeIndex.SetHex (params["index"].asString ()); bNodeBinary = true; } else if (params.isMember ("account_root")) { RippleAddress naAccount; if (!naAccount.setAccountID (params["account_root"].asString ()) || !naAccount.getAccountID ()) { jvResult["error"] = "malformedAddress"; } else { uNodeIndex = Ledger::getAccountRootIndex (naAccount.getAccountID ()); } } else if (params.isMember ("directory")) { if (!params["directory"].isObject ()) { uNodeIndex.SetHex (params["directory"].asString ()); } else if (params["directory"].isMember ("sub_index") && !params["directory"]["sub_index"].isIntegral ()) { jvResult["error"] = "malformedRequest"; } else { std::uint64_t uSubIndex = params["directory"].isMember ("sub_index") ? params["directory"]["sub_index"].asUInt () : 0; if (params["directory"].isMember ("dir_root")) { uint256 uDirRoot; uDirRoot.SetHex (params["dir_root"].asString ()); uNodeIndex = Ledger::getDirNodeIndex (uDirRoot, uSubIndex); } else if (params["directory"].isMember ("owner")) { RippleAddress naOwnerID; if (!naOwnerID.setAccountID (params["directory"]["owner"].asString ())) { jvResult["error"] = "malformedAddress"; } else { uint256 uDirRoot = Ledger::getOwnerDirIndex (naOwnerID.getAccountID ()); uNodeIndex = Ledger::getDirNodeIndex (uDirRoot, uSubIndex); } } else { jvResult["error"] = "malformedRequest"; } } } else if (params.isMember ("generator")) { RippleAddress naGeneratorID; if (!params["generator"].isObject ()) { uNodeIndex.SetHex (params["generator"].asString ()); } else if (!params["generator"].isMember ("regular_seed")) { jvResult["error"] = "malformedRequest"; } else if (!naGeneratorID.setSeedGeneric (params["generator"]["regular_seed"].asString ())) { jvResult["error"] = "malformedAddress"; } else { RippleAddress na0Public; // To find the generator's index. RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naGeneratorID); na0Public.setAccountPublic (naGenerator, 0); uNodeIndex = Ledger::getGeneratorIndex (na0Public.getAccountID ()); } } else if (params.isMember ("offer")) { RippleAddress naAccountID; if (!params["offer"].isObject ()) { uNodeIndex.SetHex (params["offer"].asString ()); } else if (!params["offer"].isMember ("account") || !params["offer"].isMember ("seq") || !params["offer"]["seq"].isIntegral ()) { jvResult["error"] = "malformedRequest"; } else if (!naAccountID.setAccountID (params["offer"]["account"].asString ())) { jvResult["error"] = "malformedAddress"; } else { std::uint32_t uSequence = params["offer"]["seq"].asUInt (); uNodeIndex = Ledger::getOfferIndex (naAccountID.getAccountID (), uSequence); } } else if (params.isMember ("ripple_state")) { RippleAddress naA; RippleAddress naB; uint160 uCurrency; Json::Value jvRippleState = params["ripple_state"]; if (!jvRippleState.isObject () || !jvRippleState.isMember ("currency") || !jvRippleState.isMember ("accounts") || !jvRippleState["accounts"].isArray () || 2 != jvRippleState["accounts"].size () || !jvRippleState["accounts"][0u].isString () || !jvRippleState["accounts"][1u].isString () || jvRippleState["accounts"][0u].asString () == jvRippleState["accounts"][1u].asString () ) { jvResult["error"] = "malformedRequest"; } else if (!naA.setAccountID (jvRippleState["accounts"][0u].asString ()) || !naB.setAccountID (jvRippleState["accounts"][1u].asString ())) { jvResult["error"] = "malformedAddress"; } else if (!STAmount::currencyFromString (uCurrency, jvRippleState["currency"].asString ())) { jvResult["error"] = "malformedCurrency"; } else { uNodeIndex = Ledger::getRippleStateIndex (naA, naB, uCurrency); } } else { jvResult["error"] = "unknownOption"; } if (uNodeIndex.isNonZero ()) { SLE::pointer sleNode = mNetOps->getSLEi (lpLedger, uNodeIndex); if (params.isMember("binary")) bNodeBinary = params["binary"].asBool(); if (!sleNode) { // Not found. // XXX Should also provide proof. jvResult["error"] = "entryNotFound"; } else if (bNodeBinary) { // XXX Should also provide proof. Serializer s; sleNode->add (s); jvResult["node_binary"] = strHex (s.peekData ()); jvResult["index"] = uNodeIndex.ToString (); } else { jvResult["node"] = sleNode->getJson (0); jvResult["index"] = uNodeIndex.ToString (); } } return jvResult; }
Json::Value RPCHandler::doLogRotate (Json::Value, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { masterLockHolder.unlock (); return LogSink::get()->rotateLog (); }
Json::Value RPCHandler::doSubscribe (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { // FIXME: This needs to release the master lock immediately // Subscriptions need to be protected by their own lock InfoSub::pointer ispSub; Json::Value jvResult (Json::objectValue); std::uint32_t uLedgerIndex = params.isMember (jss::ledger_index) && params[jss::ledger_index].isNumeric () ? params[jss::ledger_index].asUInt () : 0; if (!mInfoSub && !params.isMember ("url")) { // Must be a JSON-RPC call. WriteLog (lsINFO, RPCHandler) << boost::str (boost::format ("doSubscribe: RPC subscribe requires a url")); return rpcError (rpcINVALID_PARAMS); } if (params.isMember ("url")) { if (mRole != Config::ADMIN) return rpcError (rpcNO_PERMISSION); std::string strUrl = params["url"].asString (); std::string strUsername = params.isMember ("url_username") ? params["url_username"].asString () : ""; std::string strPassword = params.isMember ("url_password") ? params["url_password"].asString () : ""; // DEPRECATED if (params.isMember ("username")) strUsername = params["username"].asString (); // DEPRECATED if (params.isMember ("password")) strPassword = params["password"].asString (); ispSub = mNetOps->findRpcSub (strUrl); if (!ispSub) { WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("doSubscribe: building: %s") % strUrl); RPCSub::pointer rspSub = RPCSub::New (getApp ().getOPs (), getApp ().getIOService (), getApp ().getJobQueue (), strUrl, strUsername, strPassword); ispSub = mNetOps->addRpcSub (strUrl, boost::dynamic_pointer_cast<InfoSub> (rspSub)); } else { WriteLog (lsTRACE, RPCHandler) << boost::str (boost::format ("doSubscribe: reusing: %s") % strUrl); if (params.isMember ("username")) dynamic_cast<RPCSub*> (&*ispSub)->setUsername (strUsername); if (params.isMember ("password")) dynamic_cast<RPCSub*> (&*ispSub)->setPassword (strPassword); } } else { ispSub = mInfoSub; } if (!params.isMember ("streams")) { nothing (); } else if (!params["streams"].isArray ()) { WriteLog (lsINFO, RPCHandler) << boost::str (boost::format ("doSubscribe: streams requires an array.")); return rpcError (rpcINVALID_PARAMS); } else { for (Json::Value::iterator it = params["streams"].begin (); it != params["streams"].end (); it++) { if ((*it).isString ()) { std::string streamName = (*it).asString (); if (streamName == "server") { mNetOps->subServer (ispSub, jvResult); } else if (streamName == "ledger") { mNetOps->subLedger (ispSub, jvResult); } else if (streamName == "transactions") { mNetOps->subTransactions (ispSub); } else if (streamName == "transactions_rt" ) { mNetOps->subRTTransactions (ispSub); } else { jvResult[jss::error] = "unknownStream"; } } else { jvResult[jss::error] = "malformedStream"; } } } std::string strAccountsProposed = params.isMember ("accounts_rt") ? "accounts_proposed" : "rt_accounts"; // DEPRECATED if (!params.isMember (strAccountsProposed)) { nothing (); } else if (!params[strAccountsProposed].isArray ()) { return rpcError (rpcINVALID_PARAMS); } else { boost::unordered_set<RippleAddress> usnaAccoundIds = RPC::parseAccountIds (params[strAccountsProposed]); if (usnaAccoundIds.empty ()) { jvResult[jss::error] = "malformedAccount"; } else { mNetOps->subAccount (ispSub, usnaAccoundIds, uLedgerIndex, true); } } if (!params.isMember ("accounts")) { nothing (); } else if (!params["accounts"].isArray ()) { return rpcError (rpcINVALID_PARAMS); } else { boost::unordered_set<RippleAddress> usnaAccoundIds = RPC::parseAccountIds (params["accounts"]); if (usnaAccoundIds.empty ()) { jvResult[jss::error] = "malformedAccount"; } else { mNetOps->subAccount (ispSub, usnaAccoundIds, uLedgerIndex, false); WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("doSubscribe: accounts: %d") % usnaAccoundIds.size ()); } } bool bHaveMasterLock = true; if (!params.isMember ("books")) { nothing (); } else if (!params["books"].isArray ()) { return rpcError (rpcINVALID_PARAMS); } else { for (Json::Value::iterator it = params["books"].begin (); it != params["books"].end (); it++) { Json::Value& jvSubRequest = *it; if (!jvSubRequest.isObject () || !jvSubRequest.isMember (jss::taker_pays) || !jvSubRequest.isMember (jss::taker_gets) || !jvSubRequest[jss::taker_pays].isObject () || !jvSubRequest[jss::taker_gets].isObject ()) return rpcError (rpcINVALID_PARAMS); // VFALCO TODO Use RippleAsset here RippleCurrency pay_currency; RippleIssuer pay_issuer; RippleCurrency get_currency; RippleIssuer get_issuer; bool bBoth = (jvSubRequest.isMember ("both") && jvSubRequest["both"].asBool ()) || (jvSubRequest.isMember ("both_sides") && jvSubRequest["both_sides"].asBool ()); // DEPRECATED bool bSnapshot = (jvSubRequest.isMember ("snapshot") && jvSubRequest["snapshot"].asBool ()) || (jvSubRequest.isMember ("state_now") && jvSubRequest["state_now"].asBool ()); // DEPRECATED Json::Value taker_pays = jvSubRequest[jss::taker_pays]; Json::Value taker_gets = jvSubRequest[jss::taker_gets]; // Parse mandatory currency. if (!taker_pays.isMember (jss::currency) || !STAmount::currencyFromString (pay_currency, taker_pays[jss::currency].asString ())) { WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency."; return rpcError (rpcSRC_CUR_MALFORMED); } // Parse optional issuer. else if (((taker_pays.isMember (jss::issuer)) && (!taker_pays[jss::issuer].isString () || !STAmount::issuerFromString (pay_issuer, taker_pays[jss::issuer].asString ()))) // Don't allow illegal issuers. || (!pay_currency != !pay_issuer) || ACCOUNT_ONE == pay_issuer) { WriteLog (lsINFO, RPCHandler) << "Bad taker_pays issuer."; return rpcError (rpcSRC_ISR_MALFORMED); } // Parse mandatory currency. if (!taker_gets.isMember (jss::currency) || !STAmount::currencyFromString (get_currency, taker_gets[jss::currency].asString ())) { WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency."; return rpcError (rpcSRC_CUR_MALFORMED); } // Parse optional issuer. else if (((taker_gets.isMember (jss::issuer)) && (!taker_gets[jss::issuer].isString () || !STAmount::issuerFromString (get_issuer, taker_gets[jss::issuer].asString ()))) // Don't allow illegal issuers. || (!get_currency != !get_issuer) || ACCOUNT_ONE == get_issuer) { WriteLog (lsINFO, RPCHandler) << "Bad taker_gets issuer."; return rpcError (rpcDST_ISR_MALFORMED); } if (pay_currency == get_currency && pay_issuer == get_issuer) { WriteLog (lsINFO, RPCHandler) << "taker_gets same as taker_pays."; return rpcError (rpcBAD_MARKET); } RippleAddress raTakerID; if (!jvSubRequest.isMember ("taker")) { raTakerID.setAccountID (ACCOUNT_ONE); } else if (!raTakerID.setAccountID (jvSubRequest["taker"].asString ())) { return rpcError (rpcBAD_ISSUER); } if (!Ledger::isValidBook (pay_currency, pay_issuer, get_currency, get_issuer)) { WriteLog (lsWARNING, RPCHandler) << "Bad market: " << pay_currency << ":" << pay_issuer << " -> " << get_currency << ":" << get_issuer; return rpcError (rpcBAD_MARKET); } mNetOps->subBook (ispSub, pay_currency, get_currency, pay_issuer, get_issuer); if (bBoth) mNetOps->subBook (ispSub, get_currency, pay_currency, get_issuer, pay_issuer); if (bSnapshot) { if (bHaveMasterLock) { masterLockHolder.unlock (); bHaveMasterLock = false; } bool verbose = false; if (jvSubRequest.isMember("verbose")) verbose = true; loadType = Resource::feeMediumBurdenRPC; Ledger::pointer lpLedger = getApp().getLedgerMaster ().getPublishedLedger (); if (lpLedger) { const Json::Value jvMarker = Json::Value (Json::nullValue); if (bBoth) { Json::Value jvBids (Json::objectValue); Json::Value jvAsks (Json::objectValue); mNetOps->getBookPage (lpLedger, pay_currency, pay_issuer, get_currency, get_issuer, raTakerID.getAccountID (), false, verbose, 0, jvMarker, jvBids); if (jvBids.isMember (jss::offers)) jvResult[jss::bids] = jvBids[jss::offers]; mNetOps->getBookPage(lpLedger, get_currency, get_issuer, pay_currency, pay_issuer, raTakerID.getAccountID(), false, verbose, 0, jvMarker, jvAsks); if (jvAsks.isMember (jss::offers)) jvResult[jss::asks] = jvAsks[jss::offers]; } else { mNetOps->getBookPage(lpLedger, pay_currency, pay_issuer, get_currency, get_issuer, raTakerID.getAccountID(), false, verbose, 0, jvMarker, jvResult); } } } } } return jvResult; }
// { // account: account, // ledger_index_min: ledger_index // optional, defaults to earliest // ledger_index_max: ledger_index, // optional, defaults to latest // binary: boolean, // optional, defaults to false // forward: boolean, // optional, defaults to false // limit: integer, // optional // marker: opaque // optional, resume previous query // } Json::Value RPCHandler::doAccountTx (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { masterLockHolder.unlock (); RippleAddress raAccount; int limit = params.isMember (jss::limit) ? params[jss::limit].asUInt () : -1; bool bBinary = params.isMember ("binary") && params["binary"].asBool (); bool bForward = params.isMember ("forward") && params["forward"].asBool (); std::uint32_t uLedgerMin; std::uint32_t uLedgerMax; std::uint32_t uValidatedMin; std::uint32_t uValidatedMax; bool bValidated = mNetOps->getValidatedRange (uValidatedMin, uValidatedMax); if (!bValidated) { // Don't have a validated ledger range. return rpcError (rpcLGR_IDXS_INVALID); } if (!params.isMember ("account")) return rpcError (rpcINVALID_PARAMS); if (!raAccount.setAccountID (params["account"].asString ())) return rpcError (rpcACT_MALFORMED); loadType = Resource::feeMediumBurdenRPC; if (params.isMember ("ledger_index_min") || params.isMember ("ledger_index_max")) { std::int64_t iLedgerMin = params.isMember ("ledger_index_min") ? params["ledger_index_min"].asInt () : -1; std::int64_t iLedgerMax = params.isMember ("ledger_index_max") ? params["ledger_index_max"].asInt () : -1; uLedgerMin = iLedgerMin == -1 ? 0 : iLedgerMin; uLedgerMax = iLedgerMax == -1 ? uValidatedMax : iLedgerMax; if (uLedgerMax < uLedgerMin) { return rpcError (rpcLGR_IDXS_INVALID); } } else { Ledger::pointer l; Json::Value ret = RPC::lookupLedger (params, l, *mNetOps); if (!l) return ret; uLedgerMin = 0; uLedgerMax = l->getLedgerSeq (); } Json::Value resumeToken; if (params.isMember(jss::marker)) { resumeToken = params[jss::marker]; } #ifndef BEAST_DEBUG try { #endif Json::Value ret (Json::objectValue); ret["account"] = raAccount.humanAccountID (); Json::Value& jvTxns = (ret["transactions"] = Json::arrayValue); if (bBinary) { std::vector<NetworkOPs::txnMetaLedgerType> txns = mNetOps->getTxsAccountB (raAccount, uLedgerMin, uLedgerMax, bForward, resumeToken, limit, mRole == Config::ADMIN); for (std::vector<NetworkOPs::txnMetaLedgerType>::const_iterator it = txns.begin (), end = txns.end (); it != end; ++it) { Json::Value& jvObj = jvTxns.append (Json::objectValue); std::uint32_t uLedgerIndex = std::get<2> (*it); jvObj["tx_blob"] = std::get<0> (*it); jvObj["meta"] = std::get<1> (*it); jvObj["ledger_index"] = uLedgerIndex; jvObj[jss::validated] = bValidated && uValidatedMin <= uLedgerIndex && uValidatedMax >= uLedgerIndex; } } else { std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > txns = mNetOps->getTxsAccount (raAccount, uLedgerMin, uLedgerMax, bForward, resumeToken, limit, mRole == Config::ADMIN); for (std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >::iterator it = txns.begin (), end = txns.end (); it != end; ++it) { Json::Value& jvObj = jvTxns.append (Json::objectValue); if (it->first) jvObj[jss::tx] = it->first->getJson (1); if (it->second) { std::uint32_t uLedgerIndex = it->second->getLgrSeq (); jvObj[jss::meta] = it->second->getJson (0); jvObj[jss::validated] = bValidated && uValidatedMin <= uLedgerIndex && uValidatedMax >= uLedgerIndex; } } } //Add information about the original query ret[jss::ledger_index_min] = uLedgerMin; ret[jss::ledger_index_max] = uLedgerMax; if (params.isMember (jss::limit)) ret[jss::limit] = limit; if (!resumeToken.isNull()) ret[jss::marker] = resumeToken; return ret; #ifndef BEAST_DEBUG } catch (...) { return rpcError (rpcINTERNAL); } #endif }