void runTest () { beginTestCase ("Seed"); RippleAddress seed; expect (seed.setSeedGeneric ("masterpassphrase")); expect (seed.humanSeed () == "snoPBrXtMeMyMHUVTgbuqAfg1SUTb", seed.humanSeed ()); beginTestCase ("RipplePublicKey"); RippleAddress deprecatedPublicKey (RippleAddress::createNodePublic (seed)); expect (deprecatedPublicKey.humanNodePublic () == "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9", deprecatedPublicKey.humanNodePublic ()); RipplePublicKey publicKey (deprecatedPublicKey); expect (publicKey.to_string() == deprecatedPublicKey.humanNodePublic(), publicKey.to_string()); beginTestCase ("RipplePrivateKey"); RippleAddress deprecatedPrivateKey (RippleAddress::createNodePrivate (seed)); expect (deprecatedPrivateKey.humanNodePrivate () == "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe", deprecatedPrivateKey.humanNodePrivate ()); RipplePrivateKey privateKey (deprecatedPrivateKey); expect (privateKey.to_string() == deprecatedPrivateKey.humanNodePrivate(), privateKey.to_string()); beginTestCase ("Generator"); RippleAddress generator (RippleAddress::createGeneratorPublic (seed)); expect (generator.humanGenerator () == "fhuJKrhSDzV2SkjLn9qbwm5AaRmrxDPfFsHDCP6yfDZWcxDFz4mt", generator.humanGenerator ()); beginTestCase ("RippleAccountID"); RippleAddress deprecatedAccountPublicKey ( RippleAddress::createAccountPublic (generator, 0)); expect (deprecatedAccountPublicKey.humanAccountID () == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", deprecatedAccountPublicKey.humanAccountID ()); RippleAccountID accountID (deprecatedAccountPublicKey); expect (accountID.to_string() == deprecatedAccountPublicKey.humanAccountID(), accountID.to_string()); beginTestCase ("RippleAccountPublicKey"); expect (deprecatedAccountPublicKey.humanAccountPublic () == "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw", deprecatedAccountPublicKey.humanAccountPublic ()); beginTestCase ("RippleAccountPrivateKey"); RippleAddress deprecatedAccountPrivateKey ( RippleAddress::createAccountPrivate (generator, seed, 0)); expect (deprecatedAccountPrivateKey.humanAccountPrivate () == "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh", deprecatedAccountPrivateKey.humanAccountPrivate ()); RippleAccountPrivateKey accountPrivateKey (deprecatedAccountPrivateKey); expect (accountPrivateKey.to_string() == deprecatedAccountPrivateKey.humanAccountPrivate(), privateKey.to_string()); }
// { // passphrase: <string> // } Json::Value doWalletPropose (RPC::Context& context) { context.lock_.unlock (); RippleAddress naSeed; RippleAddress naAccount; if (!context.params_.isMember ("passphrase")) naSeed.setSeedRandom (); else if (!naSeed.setSeedGeneric (context.params_["passphrase"].asString ())) return rpcError(rpcBAD_SEED); RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed); naAccount.setAccountPublic (naGenerator, 0); Json::Value obj (Json::objectValue); obj["master_seed"] = naSeed.humanSeed (); obj["master_seed_hex"] = to_string (naSeed.getSeed ()); obj["master_key"] = naSeed.humanSeed1751(); obj["account_id"] = naAccount.humanAccountID (); obj["public_key"] = naAccount.humanAccountPublic(); auto acct = naAccount.getAccountPublic(); obj["public_key_hex"] = strHex(acct.begin(), acct.size()); return obj; }
void STPath::printDebug() { std::cerr << "STPath:" << std::endl; for(int i =0; i < mPath.size(); i++) { RippleAddress nad; nad.setAccountID(mPath[i].mAccountID); std::cerr << " " << i << ": " << nad.humanAccountID() << std::endl; } }
Transaction::pointer Transaction::findFrom(const RippleAddress& fromID, uint32 seq) { std::string sql = "SELECT LedgerSeq,Status,RawTxn FROM Transactions WHERE FromID='"; sql.append(fromID.humanAccountID()); sql.append("' AND FromSeq='"); sql.append(boost::lexical_cast<std::string>(seq)); sql.append("';"); return transactionFromSQL(sql); }
std::string STAccount::getText() const { uint160 u; RippleAddress a; if (!getValueH160(u)) return STVariableLength::getText(); a.setAccountID(u); return a.humanAccountID(); }
void STPath::printDebug () { Log::out() << "STPath:"; for (int i = 0; i < mPath.size (); i++) { RippleAddress nad; nad.setAccountID (mPath[i].mAccountID); Log::out() << " " << i << ": " << nad.humanAccountID (); } }
std::string rippleGetAddressFromSecret(const std::string& secretkey) { RippleAddress secret; if (!secret.SetString(secretkey, VER_FAMILY_SEED)) return ""; RippleAddress masterGenerator = createGeneratorPublic(secret); RippleAddress masterAccountPublic; masterAccountPublic.setAccountPublic(masterGenerator.getAccountPublic(), 0); return masterAccountPublic.humanAccountID(); }
void STPathSet::printDebug() { for (int i = 0; i < value.size(); i++) { std::cerr << i << ": "; for (int j = 0; j < value[i].mPath.size(); j++) { //STPathElement pe = value[i].mPath[j]; RippleAddress nad; nad.setAccountID(value[i].mPath[j].mAccountID); std::cerr << " " << nad.humanAccountID(); //std::cerr << " " << pe.mAccountID.GetHex(); } std::cerr << std::endl; } }
void rippleGenerateAddress(std::string& address, std::string& secret) { RippleAddress naSeed; RippleAddress naAccount; uint128 key; getRand(key.begin(), key.size()); naSeed.setSeed(key); RippleAddress naGenerator = createGeneratorPublic(naSeed); naAccount.setAccountPublic(naGenerator.getAccountPublic(), 0); secret = naSeed.humanSeed(); address = naAccount.humanAccountID(); }
// { // account: <indent>, // account_index : <index> // optional // strict: <bool> // true, only allow public keys and addresses. false, default. // ledger_hash : <ledger> // ledger_index : <ledger_index> // } Json::Value doAccountInfo (RPC::Context& context) { auto& params = context.params_; Ledger::pointer ledger; Json::Value result = RPC::lookupLedger (params, ledger, context.netOps_); if (!ledger) return result; if (!params.isMember ("account") && !params.isMember ("ident")) return RPC::missing_field_error ("account"); std::string strIdent = params.isMember ("account") ? params["account"].asString () : params["ident"].asString (); bool bIndex; int iIndex = params.isMember ("account_index") ? params["account_index"].asUInt () : 0; bool bStrict = params.isMember ("strict") && params["strict"].asBool (); RippleAddress naAccount; // Get info on account. Json::Value jvAccepted = RPC::accountFromString ( ledger, naAccount, bIndex, strIdent, iIndex, bStrict, context.netOps_); if (!jvAccepted.empty ()) return jvAccepted; auto asAccepted = context.netOps_.getAccountState (ledger, naAccount); if (asAccepted) { asAccepted->addJson (jvAccepted); result["account_data"] = jvAccepted; } else { result["account"] = naAccount.humanAccountID (); result = rpcError (rpcACT_NOT_FOUND, result); } return result; }
// { // account: account, // ledger_index_min: ledger_index, // ledger_index_max: ledger_index, // binary: boolean, // optional, defaults to false // count: boolean, // optional, defaults to false // descending: boolean, // optional, defaults to false // offset: integer, // optional, defaults to 0 // limit: integer // optional // } Json::Value doAccountTxOld (RPC::Context& context) { RippleAddress raAccount; std::uint32_t offset = context.params_.isMember ("offset") ? context.params_["offset"].asUInt () : 0; int limit = context.params_.isMember ("limit") ? context.params_["limit"].asUInt () : -1; bool bBinary = context.params_.isMember ("binary") && context.params_["binary"].asBool (); bool bDescending = context.params_.isMember ("descending") && context.params_["descending"].asBool (); bool bCount = context.params_.isMember ("count") && context.params_["count"].asBool (); std::uint32_t uLedgerMin; std::uint32_t uLedgerMax; std::uint32_t uValidatedMin; std::uint32_t uValidatedMax; bool bValidated = context.netOps_.getValidatedRange ( uValidatedMin, uValidatedMax); if (!context.params_.isMember ("account")) return rpcError (rpcINVALID_PARAMS); if (!raAccount.setAccountID (context.params_["account"].asString ())) return rpcError (rpcACT_MALFORMED); if (offset > 3000) return rpcError (rpcATX_DEPRECATED); context.loadType_ = Resource::feeHighBurdenRPC; // DEPRECATED if (context.params_.isMember ("ledger_min")) { context.params_["ledger_index_min"] = context.params_["ledger_min"]; bDescending = true; } // DEPRECATED if (context.params_.isMember ("ledger_max")) { context.params_["ledger_index_max"] = context.params_["ledger_max"]; bDescending = true; } if (context.params_.isMember ("ledger_index_min") || context.params_.isMember ("ledger_index_max")) { std::int64_t iLedgerMin = context.params_.isMember ("ledger_index_min") ? context.params_["ledger_index_min"].asInt () : -1; std::int64_t iLedgerMax = context.params_.isMember ("ledger_index_max") ? context.params_["ledger_index_max"].asInt () : -1; if (!bValidated && (iLedgerMin == -1 || iLedgerMax == -1)) { // Don't have a validated ledger range. return rpcError (rpcLGR_IDXS_INVALID); } uLedgerMin = iLedgerMin == -1 ? uValidatedMin : iLedgerMin; uLedgerMax = iLedgerMax == -1 ? uValidatedMax : iLedgerMax; if (uLedgerMax < uLedgerMin) { return rpcError (rpcLGR_IDXS_INVALID); } } else { Ledger::pointer l; Json::Value ret = RPC::lookupLedger (context.params_, l, context.netOps_); if (!l) return ret; uLedgerMin = uLedgerMax = l->getLedgerSeq (); } int count = 0; #ifndef BEAST_DEBUG try { #endif Json::Value ret (Json::objectValue); ret["account"] = raAccount.humanAccountID (); Json::Value& jvTxns = (ret["transactions"] = Json::arrayValue); if (bBinary) { auto txns = context.netOps_.getAccountTxsB ( raAccount, uLedgerMin, uLedgerMax, bDescending, offset, limit, context.role_ == Config::ADMIN); for (auto it = txns.begin (), end = txns.end (); it != end; ++it) { ++count; 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["validated"] = bValidated && uValidatedMin <= uLedgerIndex && uValidatedMax >= uLedgerIndex; } } else { auto txns = context.netOps_.getAccountTxs ( raAccount, uLedgerMin, uLedgerMax, bDescending, offset, limit, context.role_ == Config::ADMIN); for (auto it = txns.begin (), end = txns.end (); it != end; ++it) { ++count; Json::Value& jvObj = jvTxns.append (Json::objectValue); if (it->first) jvObj["tx"] = it->first->getJson (1); if (it->second) { std::uint32_t uLedgerIndex = it->second->getLgrSeq (); jvObj["meta"] = it->second->getJson (0); jvObj["validated"] = bValidated && uValidatedMin <= uLedgerIndex && uValidatedMax >= uLedgerIndex; } } } //Add information about the original query ret["ledger_index_min"] = uLedgerMin; ret["ledger_index_max"] = uLedgerMax; ret["validated"] = bValidated && uValidatedMin <= uLedgerMin && uValidatedMax >= uLedgerMax; ret["offset"] = offset; // We no longer return the full count but only the count of returned // transactions. Computing this count was two expensive and this API is // deprecated anyway. if (bCount) ret["count"] = count; if (context.params_.isMember ("limit")) ret["limit"] = limit; return ret; #ifndef BEAST_DEBUG } catch (...) { return rpcError (rpcINTERNAL); } #endif }
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; RippleAddress 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, // 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 }
// VFALCO TODO This function should take a reference to the params, modify it // as needed, and then there should be a separate function to // submit the transaction // Json::Value transactionSign ( Json::Value params, bool bSubmit, bool bFailHard, Application::ScopedLockType& mlh, NetworkOPs& netOps, int role) { Json::Value jvResult; WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << params; if (! params.isMember ("secret")) return RPC::missing_field_error ("secret"); if (! params.isMember ("tx_json")) return RPC::missing_field_error ("tx_json"); RippleAddress naSeed; if (! naSeed.setSeedGeneric (params["secret"].asString ())) return RPC::make_error (rpcBAD_SEED, RPC::invalid_field_message ("secret")); Json::Value& tx_json (params ["tx_json"]); if (! tx_json.isObject ()) return RPC::object_field_error ("tx_json"); if (! tx_json.isMember ("TransactionType")) return RPC::missing_field_error ("tx_json.TransactionType"); std::string const sType = tx_json ["TransactionType"].asString (); if (! tx_json.isMember ("Account")) return RPC::make_error (rpcSRC_ACT_MISSING, RPC::missing_field_message ("tx_json.Account")); RippleAddress raSrcAddressID; if (! raSrcAddressID.setAccountID (tx_json["Account"].asString ())) return RPC::make_error (rpcSRC_ACT_MALFORMED, RPC::invalid_field_message ("tx_json.Account")); bool const verify = !(params.isMember ("offline") && params["offline"].asBool ()); if (!tx_json.isMember ("Sequence") && !verify) return RPC::missing_field_error ("tx_json.Sequence"); // Check for current ledger if (verify && !getConfig ().RUN_STANDALONE && (getApp().getLedgerMaster().getValidatedLedgerAge() > 120)) return rpcError (rpcNO_CURRENT); // Check for load if (getApp().getFeeTrack().isLoadedCluster() && (role != Config::ADMIN)) return rpcError(rpcTOO_BUSY); Ledger::pointer lSnapshot = netOps.getCurrentLedger (); AccountState::pointer asSrc; if (verify) { asSrc = netOps.getAccountState (lSnapshot, raSrcAddressID); if (!asSrc) { // If not offline and did not find account, error. WriteLog (lsDEBUG, RPCHandler) << "transactionSign: Failed to find source account in current ledger: " << raSrcAddressID.humanAccountID (); return rpcError (rpcSRC_ACT_NOT_FOUND); } } autofill_fee (params, lSnapshot, jvResult, role == Config::ADMIN); if (RPC::contains_error (jvResult)) return jvResult; if ("Payment" == sType) { auto e = signPayment(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if ("Genesis" == sType) { auto e = signGenesis(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if ("Transfer" == sType) { auto e = signTransfer(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if ("AccountCreate" == sType) { auto e = signAccountCreate(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if (!tx_json.isMember ("Fee")) { auto const& transactionType = tx_json["TransactionType"].asString (); if ("AccountSet" == transactionType || "OfferCreate" == transactionType || "OfferCancel" == transactionType || "TrustSet" == transactionType) { tx_json["Fee"] = (int) getConfig ().FEE_DEFAULT; } } if (!tx_json.isMember ("Sequence")) tx_json["Sequence"] = asSrc->getSeq (); if (!tx_json.isMember ("Flags")) tx_json["Flags"] = tfFullyCanonicalSig; if (verify) { SLE::pointer sleAccountRoot = netOps.getSLEi (lSnapshot, Ledger::getAccountRootIndex (raSrcAddressID.getAccountID ())); if (!sleAccountRoot) // XXX Ignore transactions for accounts not created. return rpcError (rpcSRC_ACT_NOT_FOUND); } RippleAddress naSecret = RippleAddress::createSeedGeneric (params["secret"].asString ()); RippleAddress masterAccountPublic = RippleAddress::createAccountPublic(naSecret); if (verify) { auto account = masterAccountPublic.getAccountID(); auto const& sle = asSrc->peekSLE(); WriteLog (lsWARNING, RPCHandler) << "verify: " << masterAccountPublic.humanAccountID () << " : " << raSrcAddressID.humanAccountID (); if (raSrcAddressID.getAccountID () == account) { if (sle.isFlag(lsfDisableMaster) && "Inflation" != sType) return rpcError (rpcMASTER_DISABLED); } else if (!sle.isFieldPresent(sfRegularKey) || account != sle.getFieldAccount160 (sfRegularKey)) { return rpcError (rpcBAD_SECRET); } } STParsedJSON parsed ("tx_json", tx_json); if (!parsed.object.get()) { jvResult ["error"] = parsed.error ["error"]; jvResult ["error_code"] = parsed.error ["error_code"]; jvResult ["error_message"] = parsed.error ["error_message"]; return jvResult; } std::unique_ptr<STObject> sopTrans = std::move(parsed.object); sopTrans->setFieldVL (sfSigningPubKey, masterAccountPublic.getAccountPublic ()); SerializedTransaction::pointer stpTrans; try { stpTrans = boost::make_shared<SerializedTransaction> (*sopTrans); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } std::string reason; if (!passesLocalChecks (*stpTrans, reason)) return RPC::make_error (rpcINVALID_PARAMS, reason); if (params.isMember ("debug_signing")) { jvResult["tx_unsigned"] = strHex ( stpTrans->getSerializer ().peekData ()); jvResult["tx_signing_hash"] = to_string (stpTrans->getSigningHash ()); } // FIXME: For performance, transactions should not be signed in this code path. RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate (naSecret); stpTrans->sign (naAccountPrivate); Transaction::pointer tpTrans; tpTrans = getApp().getMasterTransaction().fetch(stpTrans->getTransactionID(), false); if (tpTrans) { TER res = tpTrans->getResult(); if (!(isTelLocal(res) || isTemMalformed(res) || isTefFailure(res))) { tpTrans = Transaction::pointer(); } } if (!tpTrans) { try { tpTrans = boost::make_shared<Transaction> (stpTrans, false); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } try { // FIXME: For performance, should use asynch interface tpTrans = netOps.submitTransactionSync (tpTrans, role == Config::ADMIN, true, bFailHard, bSubmit); if (!tpTrans) { return RPC::make_error (rpcINTERNAL, "Unable to sterilize transaction."); } } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction submission."); } } try { jvResult["tx_json"] = tpTrans->getJson (0); jvResult["tx_blob"] = strHex ( tpTrans->getSTransaction ()->getSerializer ().peekData ()); if (temUNCERTAIN != tpTrans->getResult ()) { std::string sToken; std::string sHuman; transResultInfo (tpTrans->getResult (), sToken, sHuman); jvResult["engine_result"] = sToken; jvResult["engine_result_code"] = tpTrans->getResult (); jvResult["engine_result_message"] = sHuman; } return jvResult; } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during JSON handling."); } }
// TODO(tom): what is that "default"? Json::Value doAccountInfo (RPC::Context& context) { auto& params = context.params; Ledger::pointer ledger; Json::Value result = RPC::lookupLedger (params, ledger, context.netOps); if (!ledger) return result; if (!params.isMember (jss::account) && !params.isMember (jss::ident)) return RPC::missing_field_error (jss::account); std::string strIdent = params.isMember (jss::account) ? params[jss::account].asString () : params[jss::ident].asString (); bool bIndex; int iIndex = params.isMember (jss::account_index) ? params[jss::account_index].asUInt () : 0; bool bStrict = params.isMember (jss::strict) && params[jss::strict].asBool (); RippleAddress naAccount; // Get info on account. auto jvAccepted = RPC::accountFromString ( naAccount, bIndex, strIdent, iIndex, bStrict); if (!jvAccepted.empty ()) return jvAccepted; AccountState::pointer asAccepted = getAccountState(*ledger, naAccount, getApp().getSLECache()); if (asAccepted) { asAccepted->addJson (jvAccepted); // See if there's a SignerEntries for this account. AccountID const account = naAccount.getAccountID (); uint256 const signerListIndex = getSignerListIndex (account); auto const signerList = fetch(*ledger, signerListIndex, getApp().getSLECache()); if (signerList) { // Return multi-signing information if there are multi-signers. static const Json::StaticString multiSignersName("multisigners"); jvAccepted[multiSignersName] = signerList->getJson (0); Json::Value& multiSignerJson = jvAccepted[multiSignersName]; // Remove unwanted fields. multiSignerJson.removeMember (sfFlags.getName ()); multiSignerJson.removeMember (sfLedgerEntryType.getName ()); multiSignerJson.removeMember (sfOwnerNode.getName ()); multiSignerJson.removeMember ("index"); } result[jss::account_data] = jvAccepted; } else { result[jss::account] = naAccount.humanAccountID (); RPC::inject_error (rpcACT_NOT_FOUND, result); } return result; }
// { // 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 doAccountTx (RPC::Context& context) { auto& params = context.params_; 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 = context.netOps_.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); context.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 ? uValidatedMin : 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, context.netOps_); if (!l) return ret; uLedgerMin = 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) { auto txns = context.netOps_.getTxsAccountB ( raAccount, uLedgerMin, uLedgerMax, bForward, resumeToken, limit, context.role_ == Config::ADMIN); for (auto& it: txns) { 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 { auto txns = context.netOps_.getTxsAccount ( raAccount, uLedgerMin, uLedgerMax, bForward, resumeToken, limit, context.role_ == Config::ADMIN); for (auto& it: txns) { 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 }
Json::Value doGatewayBalances (RPC::Context& context) { auto& params = context.params; // Get the current ledger Ledger::pointer ledger; Json::Value result (RPC::lookupLedger (params, ledger, context.netOps)); if (!ledger) return result; if (!(params.isMember (jss::account) || params.isMember (jss::ident))) return RPC::missing_field_error (jss::account); std::string const strIdent (params.isMember (jss::account) ? params[jss::account].asString () : params[jss::ident].asString ()); int iIndex = 0; if (params.isMember (jss::account_index)) { auto const& accountIndex = params[jss::account_index]; if (!accountIndex.isUInt() && !accountIndex.isInt ()) return RPC::invalid_field_message (jss::account_index); iIndex = accountIndex.asUInt (); } bool const bStrict = params.isMember (jss::strict) && params[jss::strict].asBool (); // Get info on account. bool bIndex; // out param RippleAddress naAccount; // out param Json::Value jvAccepted (RPC::accountFromString ( naAccount, bIndex, strIdent, iIndex, bStrict)); if (!jvAccepted.empty ()) return jvAccepted; context.loadType = Resource::feeHighBurdenRPC; result[jss::account] = naAccount.humanAccountID(); auto accountID = naAccount.getAccountID(); // Parse the specified hotwallet(s), if any std::set <AccountID> hotWallets; if (params.isMember ("hotwallet")) { Json::Value const& hw = params["hotwallet"]; bool valid = true; auto addHotWallet = [&valid, &hotWallets](Json::Value const& j) { if (j.isString()) { RippleAddress ra; if (! ra.setAccountPublic (j.asString ()) && ! ra.setAccountID (j.asString())) { valid = false; } else hotWallets.insert (ra.getAccountID ()); } else { valid = false; } }; if (hw.isArray()) { for (unsigned i = 0; i < hw.size(); ++i) addHotWallet (hw[i]); } else if (hw.isString()) { addHotWallet (hw); } else { valid = false; } if (! valid) { result[jss::error] = "invalidHotWallet"; return result; } } std::map <Currency, STAmount> sums; std::map <AccountID, std::vector <STAmount>> hotBalances; std::map <AccountID, std::vector <STAmount>> assets; // Traverse the cold wallet's trust lines forEachItem(*ledger, accountID, getApp().getSLECache(), [&](std::shared_ptr<SLE const> const& sle) { auto rs = RippleState::makeItem (accountID, sle); if (!rs) return; int balSign = rs->getBalance().signum(); if (balSign == 0) return; auto const& peer = rs->getAccountIDPeer(); // Here, a negative balance means the cold wallet owes (normal) // A positive balance means the cold wallet has an asset (unusual) if (hotWallets.count (peer) > 0) { // This is a specified hot wallt hotBalances[peer].push_back (-rs->getBalance ()); } else if (balSign > 0) { // This is a gateway asset assets[peer].push_back (rs->getBalance ()); } else { // normal negative balance, obligation to customer auto& bal = sums[rs->getBalance().getCurrency()]; if (bal == zero) { // This is needed to set the currency code correctly bal = -rs->getBalance(); } else bal -= rs->getBalance(); } }); if (! sums.empty()) { Json::Value& j = (result [jss::obligations] = Json::objectValue); for (auto const& e : sums) { j[to_string (e.first)] = e.second.getText (); } } if (! hotBalances.empty()) { Json::Value& j = (result [jss::balances] = Json::objectValue); for (auto const& account : hotBalances) { Json::Value& balanceArray = (j[to_string (account.first)] = Json::arrayValue); for (auto const& balance : account.second) { Json::Value& entry = balanceArray.append (Json::objectValue); entry[jss::currency] = to_string (balance.issue ().currency); entry[jss::value] = balance.getText(); } } } if (! assets.empty()) { Json::Value& j = (result [jss::assets] = Json::objectValue); for (auto const& account : assets) { Json::Value& balanceArray = (j[to_string (account.first)] = Json::arrayValue); for (auto const& balance : account.second) { Json::Value& entry = balanceArray.append (Json::objectValue); entry[jss::currency] = to_string (balance.issue ().currency); entry[jss::value] = balance.getText(); } } } 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; }
// This interface is deprecated. Json::Value doRipplePathFind (RPC::Context& context) { RPC::LegacyPathFind lpf (context.role == Role::ADMIN); if (!lpf.isOk ()) return rpcError (rpcTOO_BUSY); context.loadType = Resource::feeHighBurdenRPC; RippleAddress raSrc; RippleAddress raDst; STAmount saDstAmount; Ledger::pointer lpLedger; Json::Value jvResult; if (getConfig().RUN_STANDALONE || context.params.isMember(jss::ledger) || context.params.isMember(jss::ledger_index) || context.params.isMember(jss::ledger_hash)) { // The caller specified a ledger jvResult = RPC::lookupLedger ( context.params, lpLedger, context.netOps); if (!lpLedger) return jvResult; } if (!context.params.isMember ("source_account")) { jvResult = rpcError (rpcSRC_ACT_MISSING); } else if (!context.params["source_account"].isString () || !raSrc.setAccountID ( context.params["source_account"].asString ())) { jvResult = rpcError (rpcSRC_ACT_MALFORMED); } else if (!context.params.isMember ("destination_account")) { jvResult = rpcError (rpcDST_ACT_MISSING); } else if (!context.params["destination_account"].isString () || !raDst.setAccountID ( context.params["destination_account"].asString ())) { jvResult = rpcError (rpcDST_ACT_MALFORMED); } else if ( // Parse saDstAmount. !context.params.isMember ("destination_amount") || ! amountFromJsonNoThrow(saDstAmount, context.params["destination_amount"]) || saDstAmount <= zero || (!isXRP(saDstAmount.getCurrency ()) && (!saDstAmount.getIssuer () || noAccount() == saDstAmount.getIssuer ()))) { WriteLog (lsINFO, RPCHandler) << "Bad destination_amount."; jvResult = rpcError (rpcINVALID_PARAMS); } else if ( // Checks on source_currencies. context.params.isMember ("source_currencies") && (!context.params["source_currencies"].isArray () || !context.params["source_currencies"].size ()) // Don't allow empty currencies. ) { WriteLog (lsINFO, RPCHandler) << "Bad source_currencies."; jvResult = rpcError (rpcINVALID_PARAMS); } else { context.loadType = Resource::feeHighBurdenRPC; RippleLineCache::pointer cache; if (lpLedger) { // The caller specified a ledger lpLedger = std::make_shared<Ledger> (std::ref (*lpLedger), false); cache = std::make_shared<RippleLineCache>(lpLedger); } else { // The closed ledger is recent and any nodes made resident // have the best chance to persist lpLedger = context.netOps.getClosedLedger(); cache = getApp().getPathRequests().getLineCache(lpLedger, false); } Json::Value jvSrcCurrencies; if (context.params.isMember ("source_currencies")) { jvSrcCurrencies = context.params["source_currencies"]; } else { auto currencies = accountSourceCurrencies (raSrc, cache, true); jvSrcCurrencies = Json::Value (Json::arrayValue); for (auto const& uCurrency: currencies) { Json::Value jvCurrency (Json::objectValue); jvCurrency["currency"] = to_string(uCurrency); jvSrcCurrencies.append (jvCurrency); } } // Fill in currencies destination will accept Json::Value jvDestCur (Json::arrayValue); // TODO(tom): this could be optimized the same way that // PathRequest::doUpdate() is - if we don't obsolete this code first. auto usDestCurrID = accountDestCurrencies (raDst, cache, true); for (auto const& uCurrency: usDestCurrID) jvDestCur.append (to_string (uCurrency)); jvResult["destination_currencies"] = jvDestCur; jvResult["destination_account"] = raDst.humanAccountID (); Json::Value jvArray (Json::arrayValue); int level = getConfig().PATH_SEARCH_OLD; if ((getConfig().PATH_SEARCH_MAX > level) && !getApp().getFeeTrack().isLoadedLocal()) { ++level; } if (context.params.isMember("search_depth") && context.params["search_depth"].isIntegral()) { int rLev = context.params["search_depth"].asInt (); if ((rLev < level) || (context.role == Role::ADMIN)) level = rLev; } FindPaths fp ( cache, raSrc.getAccountID(), raDst.getAccountID(), saDstAmount, level, 4); // max paths for (unsigned int i = 0; i != jvSrcCurrencies.size (); ++i) { Json::Value jvSource = jvSrcCurrencies[i]; Currency uSrcCurrencyID; Account uSrcIssuerID; if (!jvSource.isObject ()) return rpcError (rpcINVALID_PARAMS); // Parse mandatory currency. if (!jvSource.isMember ("currency") || !to_currency ( uSrcCurrencyID, jvSource["currency"].asString ())) { WriteLog (lsINFO, RPCHandler) << "Bad currency."; return rpcError (rpcSRC_CUR_MALFORMED); } if (uSrcCurrencyID.isNonZero ()) uSrcIssuerID = raSrc.getAccountID (); // Parse optional issuer. if (jvSource.isMember ("issuer") && ((!jvSource["issuer"].isString () || !to_issuer (uSrcIssuerID, jvSource["issuer"].asString ())) || (uSrcIssuerID.isZero () != uSrcCurrencyID.isZero ()) || (noAccount() == uSrcIssuerID))) { WriteLog (lsINFO, RPCHandler) << "Bad issuer."; return rpcError (rpcSRC_ISR_MALFORMED); } STPathSet spsComputed; if (context.params.isMember("paths")) { Json::Value pathSet = Json::objectValue; pathSet["Paths"] = context.params["paths"]; STParsedJSONObject paths ("pathSet", pathSet); if (paths.object.get() == nullptr) return paths.error; else { spsComputed = paths.object.get()->getFieldPathSet (sfPaths); WriteLog (lsTRACE, RPCHandler) << "ripple_path_find: Paths: " << spsComputed.getJson (0); } } STPath fullLiquidityPath; auto valid = fp.findPathsForIssue ( {uSrcCurrencyID, uSrcIssuerID}, spsComputed, fullLiquidityPath); if (!valid) { WriteLog (lsWARNING, RPCHandler) << "ripple_path_find: No paths found."; } else { auto& issuer = isXRP (uSrcIssuerID) ? isXRP (uSrcCurrencyID) ? // Default to source account. xrpAccount() : Account (raSrc.getAccountID ()) : uSrcIssuerID; // Use specifed issuer. STAmount saMaxAmount ({uSrcCurrencyID, issuer}, 1); saMaxAmount.negate (); LedgerEntrySet lesSandbox (lpLedger, tapNONE); auto rc = path::RippleCalc::rippleCalculate ( lesSandbox, saMaxAmount, // --> Amount to send is unlimited // to get an estimate. saDstAmount, // --> Amount to deliver. raDst.getAccountID (), // --> Account to deliver to. raSrc.getAccountID (), // --> Account sending from. spsComputed); // --> Path set. WriteLog (lsWARNING, RPCHandler) << "ripple_path_find:" << " saMaxAmount=" << saMaxAmount << " saDstAmount=" << saDstAmount << " saMaxAmountAct=" << rc.actualAmountIn << " saDstAmountAct=" << rc.actualAmountOut; if (fullLiquidityPath.size() > 0 && (rc.result() == terNO_LINE || rc.result() == tecPATH_PARTIAL)) { WriteLog (lsDEBUG, PathRequest) << "Trying with an extra path element"; spsComputed.push_back (fullLiquidityPath); lesSandbox.clear (); rc = path::RippleCalc::rippleCalculate ( lesSandbox, saMaxAmount, // --> Amount to send is unlimited // to get an estimate. saDstAmount, // --> Amount to deliver. raDst.getAccountID (), // --> Account to deliver to. raSrc.getAccountID (), // --> Account sending from. spsComputed); // --> Path set. WriteLog (lsDEBUG, PathRequest) << "Extra path element gives " << transHuman (rc.result ()); } if (rc.result () == tesSUCCESS) { Json::Value jvEntry (Json::objectValue); STPathSet spsCanonical; // Reuse the expanded as it would need to be calcuated // anyway to produce the canonical. (At least unless we // make a direct canonical.) jvEntry["source_amount"] = rc.actualAmountIn.getJson (0); jvEntry["paths_canonical"] = Json::arrayValue; jvEntry["paths_computed"] = spsComputed.getJson (0); jvArray.append (jvEntry); } else { std::string strToken; std::string strHuman; transResultInfo (rc.result (), strToken, strHuman); WriteLog (lsDEBUG, RPCHandler) << "ripple_path_find: " << strToken << " " << strHuman << " " << spsComputed.getJson (0); } } } // Each alternative differs by source currency. jvResult["alternatives"] = jvArray; } WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("ripple_path_find< %s") % jvResult); return jvResult; }
void LoopThread(unsigned int n, uint64_t eta50, string* ppattern, string* pmaster_seed, string* pmaster_seed_hex, string* paccount_id) { RippleAddress naSeed; RippleAddress naAccount; string pattern = *ppattern; string account_id; uint128 key; getRand(key.begin(), key.size()); uint64_t count = 0; uint64_t last_count = 0; do { naSeed.setSeed(key); RippleAddress naGenerator = createGeneratorPublic(naSeed); naAccount.setAccountPublic(naGenerator.getAccountPublic(), 0); account_id = naAccount.humanAccountID(); count++; if (count % UPDATE_ITERATIONS == 0) { boost::unique_lock<boost::mutex> lock(mutex); total_searched += count - last_count; last_count = count; uint64_t nSecs = time(NULL) - start_time; double speed = (1.0 * total_searched)/nSecs; const char* unit = "seconds"; double eta50f = eta50/speed; if (eta50f > 100) { unit = "minutes"; eta50f /= 60; if (eta50f > 100) { unit = "hours"; eta50f /= 60; if (eta50f > 48) { unit = "days"; eta50f /= 24; } } } cout << "# Thread " << n << ": " << count << " seeds." << endl << "#" << endl << "# Total Speed: " << speed << " seeds/second" << endl << "# Total Searched: " << total_searched << endl << "# Total Time: " << nSecs << " seconds" << endl << "# ETA 50%: " << eta50f << " " << unit << endl << "# Last: " << account_id << endl << "# Pattern: " << pattern << endl << "#" << endl; } key++; boost::this_thread::yield(); } while ((account_id.substr(0, pattern.size()) != pattern) && !fDone); boost::unique_lock<boost::mutex> lock(mutex); if (fDone) return; fDone = true; cout << "# *** Found by thread " << n << ". ***" << endl << "#" << endl; *pmaster_seed = naSeed.humanSeed(); *pmaster_seed_hex = naSeed.getSeed().ToString(); *paccount_id = account_id; }
// This interface is deprecated. Json::Value doRipplePathFind (RPC::Context& context) { RPC::LegacyPathFind lpf (context.role == Role::ADMIN); if (!lpf.isOk ()) return rpcError (rpcTOO_BUSY); context.loadType = Resource::feeHighBurdenRPC; RippleAddress raSrc; RippleAddress raDst; STAmount saDstAmount; Ledger::pointer lpLedger; Json::Value jvResult; if (getConfig().RUN_STANDALONE || context.params.isMember(jss::ledger) || context.params.isMember(jss::ledger_index) || context.params.isMember(jss::ledger_hash)) { // The caller specified a ledger jvResult = RPC::lookupLedger ( context.params, lpLedger, context.netOps); if (!lpLedger) return jvResult; } if (!context.params.isMember (jss::source_account)) { jvResult = rpcError (rpcSRC_ACT_MISSING); } else if (!context.params[jss::source_account].isString () || !raSrc.setAccountID ( context.params[jss::source_account].asString ())) { jvResult = rpcError (rpcSRC_ACT_MALFORMED); } else if (!context.params.isMember (jss::destination_account)) { jvResult = rpcError (rpcDST_ACT_MISSING); } else if (!context.params[jss::destination_account].isString () || !raDst.setAccountID ( context.params[jss::destination_account].asString ())) { jvResult = rpcError (rpcDST_ACT_MALFORMED); } else if ( // Parse saDstAmount. !context.params.isMember (jss::destination_amount) || ! amountFromJsonNoThrow(saDstAmount, context.params[jss::destination_amount]) || saDstAmount <= zero || (!isXRP(saDstAmount.getCurrency ()) && (!saDstAmount.getIssuer () || noAccount() == saDstAmount.getIssuer ()))) { WriteLog (lsINFO, RPCHandler) << "Bad destination_amount."; jvResult = rpcError (rpcINVALID_PARAMS); } else if ( // Checks on source_currencies. context.params.isMember (jss::source_currencies) && (!context.params[jss::source_currencies].isArray () || !context.params[jss::source_currencies].size ()) // Don't allow empty currencies. ) { WriteLog (lsINFO, RPCHandler) << "Bad source_currencies."; jvResult = rpcError (rpcINVALID_PARAMS); } else { context.loadType = Resource::feeHighBurdenRPC; RippleLineCache::pointer cache; if (lpLedger) { // The caller specified a ledger lpLedger = std::make_shared<Ledger> (std::ref (*lpLedger), false); cache = std::make_shared<RippleLineCache>(lpLedger); } else { // The closed ledger is recent and any nodes made resident // have the best chance to persist lpLedger = context.netOps.getClosedLedger(); cache = getApp().getPathRequests().getLineCache(lpLedger, false); } Json::Value jvSrcCurrencies; if (context.params.isMember (jss::source_currencies)) { jvSrcCurrencies = context.params[jss::source_currencies]; } else { jvSrcCurrencies = buildSrcCurrencies(raSrc, cache); } // Fill in currencies destination will accept Json::Value jvDestCur (Json::arrayValue); // TODO(tom): this could be optimized the same way that // PathRequest::doUpdate() is - if we don't obsolete this code first. auto usDestCurrID = accountDestCurrencies (raDst, cache, true); for (auto const& uCurrency: usDestCurrID) jvDestCur.append (to_string (uCurrency)); jvResult[jss::destination_currencies] = jvDestCur; jvResult[jss::destination_account] = raDst.humanAccountID (); int level = getConfig().PATH_SEARCH_OLD; if ((getConfig().PATH_SEARCH_MAX > level) && !getApp().getFeeTrack().isLoadedLocal()) { ++level; } if (context.params.isMember(jss::search_depth) && context.params[jss::search_depth].isIntegral()) { int rLev = context.params[jss::search_depth].asInt (); if ((rLev < level) || (context.role == Role::ADMIN)) level = rLev; } auto contextPaths = context.params.isMember(jss::paths) ? boost::optional<Json::Value>(context.params[jss::paths]) : boost::optional<Json::Value>(boost::none); auto pathFindResult = ripplePathFind(cache, raSrc, raDst, saDstAmount, lpLedger, jvSrcCurrencies, contextPaths, level); if (!pathFindResult.first) return pathFindResult.second; // Each alternative differs by source currency. jvResult[jss::alternatives] = pathFindResult.second; } WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("ripple_path_find< %s") % jvResult); return jvResult; }
// VFALCO TODO This function should take a reference to the params, modify it // as needed, and then there should be a separate function to // submit the transaction. // Json::Value transactionSign ( Json::Value params, bool bSubmit, bool bFailHard, RPCDetail::LedgerFacade& ledgerFacade, Role role) { Json::Value jvResult; WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << params; if (! params.isMember ("secret")) return RPC::missing_field_error ("secret"); if (! params.isMember ("tx_json")) return RPC::missing_field_error ("tx_json"); RippleAddress naSeed; if (! naSeed.setSeedGeneric (params["secret"].asString ())) return RPC::make_error (rpcBAD_SEED, RPC::invalid_field_message ("secret")); Json::Value& tx_json (params ["tx_json"]); if (! tx_json.isObject ()) return RPC::object_field_error ("tx_json"); if (! tx_json.isMember ("TransactionType")) return RPC::missing_field_error ("tx_json.TransactionType"); std::string const sType = tx_json ["TransactionType"].asString (); if (! tx_json.isMember ("Account")) return RPC::make_error (rpcSRC_ACT_MISSING, RPC::missing_field_message ("tx_json.Account")); RippleAddress raSrcAddressID; if (! raSrcAddressID.setAccountID (tx_json["Account"].asString ())) return RPC::make_error (rpcSRC_ACT_MALFORMED, RPC::invalid_field_message ("tx_json.Account")); bool const verify = !(params.isMember ("offline") && params["offline"].asBool ()); if (!tx_json.isMember ("Sequence") && !verify) return RPC::missing_field_error ("tx_json.Sequence"); // Check for current ledger. if (verify && !getConfig ().RUN_STANDALONE && (ledgerFacade.getValidatedLedgerAge () > 120)) return rpcError (rpcNO_CURRENT); // Check for load. if (ledgerFacade.isLoadedCluster () && (role != Role::ADMIN)) return rpcError (rpcTOO_BUSY); ledgerFacade.snapshotAccountState (raSrcAddressID); if (verify) { if (!ledgerFacade.isValidAccount ()) { // If not offline and did not find account, error. WriteLog (lsDEBUG, RPCHandler) << "transactionSign: Failed to find source account " << "in current ledger: " << raSrcAddressID.humanAccountID (); return rpcError (rpcSRC_ACT_NOT_FOUND); } } autofill_fee (params, ledgerFacade, jvResult, role == Role::ADMIN); if (RPC::contains_error (jvResult)) return jvResult; if ("Payment" == sType) { auto e = signPayment( params, tx_json, raSrcAddressID, ledgerFacade, role); if (contains_error(e)) return e; } if (!tx_json.isMember ("Sequence")) tx_json["Sequence"] = ledgerFacade.getSeq (); if (!tx_json.isMember ("Flags")) tx_json["Flags"] = tfFullyCanonicalSig; if (verify) { if (!ledgerFacade.hasAccountRoot ()) // XXX Ignore transactions for accounts not created. return rpcError (rpcSRC_ACT_NOT_FOUND); } RippleAddress secret = RippleAddress::createSeedGeneric ( params["secret"].asString ()); RippleAddress masterGenerator = RippleAddress::createGeneratorPublic ( secret); RippleAddress masterAccountPublic = RippleAddress::createAccountPublic ( masterGenerator, 0); if (verify) { WriteLog (lsTRACE, RPCHandler) << "verify: " << masterAccountPublic.humanAccountID () << " : " << raSrcAddressID.humanAccountID (); auto const secretAccountID = masterAccountPublic.getAccountID(); if (raSrcAddressID.getAccountID () == secretAccountID) { if (ledgerFacade.accountMasterDisabled ()) return rpcError (rpcMASTER_DISABLED); } else if (!ledgerFacade.accountMatchesRegularKey (secretAccountID)) { return rpcError (rpcBAD_SECRET); } } STParsedJSONObject parsed ("tx_json", tx_json); if (!parsed.object.get()) { jvResult ["error"] = parsed.error ["error"]; jvResult ["error_code"] = parsed.error ["error_code"]; jvResult ["error_message"] = parsed.error ["error_message"]; return jvResult; } std::unique_ptr<STObject> sopTrans = std::move(parsed.object); sopTrans->setFieldVL ( sfSigningPubKey, masterAccountPublic.getAccountPublic ()); STTx::pointer stpTrans; try { stpTrans = std::make_shared<STTx> (*sopTrans); //WriteLog(lsINFO, RPCHandler) << "radar: before sign " << stpTrans->getFieldAmount(sfAmount); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } std::string reason; if (!passesLocalChecks (*stpTrans, reason)) return RPC::make_error (rpcINVALID_PARAMS, reason); if (params.isMember ("debug_signing")) { jvResult["tx_unsigned"] = strHex ( stpTrans->getSerializer ().peekData ()); jvResult["tx_signing_hash"] = to_string (stpTrans->getSigningHash ()); } // FIXME: For performance, transactions should not be signed in this code // path. RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate ( masterGenerator, secret, 0); stpTrans->sign (naAccountPrivate); Transaction::pointer tpTrans; try { //WriteLog(lsINFO, RPCHandler) << "radar: after sign " << stpTrans->getFieldAmount(sfAmount); tpTrans = std::make_shared<Transaction>(stpTrans, Validate::NO); //WriteLog(lsINFO, RPCHandler) << "radar: after copy" << tpTrans->getSTransaction()->getFieldAmount(sfAmount); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } try { // FIXME: For performance, should use asynch interface. tpTrans = ledgerFacade.submitTransactionSync (tpTrans, role == Role::ADMIN, true, bFailHard, bSubmit); if (!tpTrans) { return RPC::make_error (rpcINTERNAL, "Unable to sterilize transaction."); } } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction submission."); } try { jvResult["tx_json"] = tpTrans->getJson (0); jvResult["tx_blob"] = strHex ( tpTrans->getSTransaction ()->getSerializer ().peekData ()); if (temUNCERTAIN != tpTrans->getResult ()) { std::string sToken; std::string sHuman; transResultInfo (tpTrans->getResult (), sToken, sHuman); jvResult["engine_result"] = sToken; jvResult["engine_result_code"] = tpTrans->getResult (); jvResult["engine_result_message"] = sHuman; } return jvResult; } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during JSON handling."); } }
void run() { testBase58(RippleAddress::VER_NODE_PUBLIC, 'n'); testBase58(RippleAddress::VER_NODE_PRIVATE, 'h'); testBase58(RippleAddress::VER_ACCOUNT_PUBLIC, 'p'); testBase58(RippleAddress::VER_ACCOUNT_PRIVATE, 'h'); testBase58(RippleAddress::VER_SEED, 's'); // check pass phrase std::string strPass("paysharesmaster"); std::string strBase58Seed("s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN"); std::string strBase58NodePublic("nfbbWHgJqzqfH1cfRpMdPRkJ19cxTsdHkBtz1SLJJQfyf9Ax6vd"); std::string strBase58AccountPublic("pGreoXKYybde1keKZwDCv8m5V1kT6JH37pgnTUVzdMkdygTixG8"); AccountPrivateKey accountPrivateKey; NodePrivateKey nodePrivateKey; accountPrivateKey.fromPassPhrase(strPass); nodePrivateKey.fromPassPhrase(strPass); expect(accountPrivateKey.base58Seed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", accountPrivateKey.base58Seed()); expect(accountPrivateKey.base58AccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", accountPrivateKey.base58AccountID()); expect(accountPrivateKey.base58PublicKey() == strBase58AccountPublic, accountPrivateKey.base58PublicKey()); expect(nodePrivateKey.base58PublicKey() == strBase58NodePublic, nodePrivateKey.base58PublicKey()); Blob sig; uint256 message; accountPrivateKey.sign(message, sig); PaysharesPublicKey publicKey(accountPrivateKey.getPublicKey(), RippleAddress::VER_NODE_PUBLIC); expect(publicKey.verifySignature(message, sig), "Signature didn't verify"); expect(publicKey.getAccountID() == accountPrivateKey.getAccountID(), "Account Id's mis match"); expect(publicKey.base58AccountID() == accountPrivateKey.base58AccountID(), "Account Id's mis match"); Blob nonCanonicalSig(sig); add_l(nonCanonicalSig.data() + 32); expect(sig != nonCanonicalSig, "Non-canonical signature equal to canonical signature"); expect(crypto_sign_verify_detached(nonCanonicalSig.data(), message.data(), message.bytes, publicKey.vchData.data()) == 0, "Non-canonical signature didn't verify (ignoring canonical-ness)"); expect(!publicKey.verifySignature(message, nonCanonicalSig), "Non-canonical signature verified"); AccountPrivateKey privateKey2; privateKey2.fromString(strBase58Seed); // key from base58seed expect(privateKey2.base58Seed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", privateKey2.base58Seed()); expect(privateKey2.base58AccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", privateKey2.base58AccountID()); expect(privateKey2.base58PublicKey() == strBase58AccountPublic, privateKey2.base58PublicKey()); privateKey2.sign(message, sig); expect(publicKey.verifySignature(message, sig), "Signature didn't verify"); // check with the previous pubkey // check random /// ======= OLD ==== // Construct a seed. RippleAddress naSeed; expect(naSeed.setSeedGeneric("masterpassphrase")); expect(naSeed.humanSeed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", naSeed.humanSeed()); // Create node public/private key pair RippleAddress naNodePublic = RippleAddress::createNodePublic(naSeed); expect(naNodePublic.verifySignature(message, sig), "Signature didn't verify"); expect(naNodePublic.humanNodePublic() == strBase58NodePublic, naNodePublic.humanNodePublic()); naNodePublic.setNodePublic(strBase58NodePublic); expect(naNodePublic.verifySignature(message, sig), "Signature didn't verify"); expect(naNodePublic.humanNodePublic() == strBase58NodePublic, naNodePublic.humanNodePublic()); RippleAddress naAccountPublic = RippleAddress::createAccountPublic(naSeed); expect(naAccountPublic.humanAccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", naAccountPublic.humanAccountID()); expect(naAccountPublic.verifySignature(message, sig), "Signature didn't verify"); expect(naAccountPublic.humanAccountPublic() == strBase58AccountPublic, naAccountPublic.humanAccountPublic()); naAccountPublic.setAccountPublic(strBase58AccountPublic); expect(naAccountPublic.humanAccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", naAccountPublic.humanAccountID()); expect(naAccountPublic.verifySignature(message, sig), "Signature didn't verify"); expect(naAccountPublic.humanAccountPublic() == strBase58AccountPublic, naAccountPublic.humanAccountPublic()); Blob rippleSig; RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate(naSeed); naAccountPrivate.sign(message, rippleSig); expect(rippleSig==sig, "Signature don't match"); RippleAddress naNodePrivate = RippleAddress::createNodePrivate(naSeed); naNodePrivate.sign(message, rippleSig); expect(rippleSig == sig, "Signature don't match"); std::string strPrivateKey("ssQMHypYAPSPgniSyvJQccuL1dJUbXJWVgAPV5QcAuBVEWsZTVQwffsnwTY6Mivoy3NRSVR28ZaCW74F67VSq4VRC4zY1XR"); expect(naNodePrivate.humanNodePrivate() == strPrivateKey, naNodePrivate.humanNodePrivate()); expect(naNodePrivate.setNodePrivate(strPrivateKey),"couldn't create private node"); expect(naNodePrivate.humanNodePrivate() == strPrivateKey, naNodePrivate.humanNodePrivate()); naNodePrivate.sign(message, rippleSig); expect(rippleSig == sig, "Signature don't match"); /* RippleAddress naNodePrivate = RippleAddress::createNodePrivate(naSeed); expect(naNodePrivate.humanNodePrivate() == "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe", naNodePrivate.humanNodePrivate()); // Check node signing. Blob vucTextSrc = strCopy("Hello, nurse!"); uint256 uHash = Serializer::getSHA512Half(vucTextSrc); Blob vucTextSig; naNodePrivate.signNodePrivate(uHash, vucTextSig); expect(naNodePublic.verifyNodePublic(uHash, vucTextSig, ECDSA::strict), "Verify failed."); */ }
// tx_account accountID [ledger_min [ledger_max [limit]]]] [binary] [count] [forward] Json::Value parseTxAccount (const Json::Value& jvParams) { Json::Value jvRequest (Json::objectValue); RippleAddress raAccount; unsigned int iParams = jvParams.size (); if (!raAccount.setAccountID (jvParams[0u].asString ())) return rpcError (rpcACT_MALFORMED); jvRequest["account"] = raAccount.humanAccountID (); bool bDone = false; while (!bDone && iParams >= 2) { if (jvParams[iParams - 1].asString () == "binary") { jvRequest["binary"] = true; --iParams; } else if (jvParams[iParams - 1].asString () == "count") { jvRequest["count"] = true; --iParams; } else if (jvParams[iParams - 1].asString () == "forward") { jvRequest["forward"] = true; --iParams; } else { bDone = true; } } if (1 == iParams) { nothing (); } else if (2 == iParams) { if (!jvParseLedger (jvRequest, jvParams[1u].asString ())) return jvRequest; } else { int64 uLedgerMin = jvParams[1u].asInt (); int64 uLedgerMax = jvParams[2u].asInt (); if (uLedgerMax != -1 && uLedgerMax < uLedgerMin) { return rpcError (rpcLGR_IDXS_INVALID); } jvRequest["ledger_index_min"] = jvParams[1u].asInt (); jvRequest["ledger_index_max"] = jvParams[2u].asInt (); if (iParams >= 4) jvRequest["limit"] = jvParams[3u].asInt (); } return jvRequest; }
Json::Value walletPropose (Json::Value const& params) { RippleAddress naSeed; RippleAddress naAccount; KeyType type = KeyType::secp256k1; bool const has_key_type = params.isMember (jss::key_type); bool const has_passphrase = params.isMember (jss::passphrase); if (has_key_type) { // `key_type` must be valid if present. type = keyTypeFromString (params[jss::key_type].asString()); if (type == KeyType::invalid) { return rpcError (rpcBAD_SEED); } naSeed = getSeedFromRPC (params); } else if (has_passphrase) { naSeed.setSeedGeneric (params[jss::passphrase].asString()); } else { naSeed.setSeedRandom(); } if (!naSeed.isSet()) { return rpcError(rpcBAD_SEED); } if (type == KeyType::secp256k1) { RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed); naAccount.setAccountPublic (naGenerator, 0); } else if (type == KeyType::ed25519) { uint256 secretkey = keyFromSeed (naSeed.getSeed()); Blob publickey (33); publickey[0] = 0xED; ed25519_publickey (secretkey.data(), &publickey[1]); secretkey.zero(); // security erase naAccount.setAccountPublic (publickey); } else { assert (false); // not reached } Json::Value obj (Json::objectValue); obj[jss::master_seed] = naSeed.humanSeed (); obj[jss::master_seed_hex] = to_string (naSeed.getSeed ()); obj[jss::master_key] = naSeed.humanSeed1751(); obj[jss::account_id] = naAccount.humanAccountID (); obj[jss::public_key] = naAccount.humanAccountPublic(); obj[jss::key_type] = to_string (type); auto acct = naAccount.getAccountPublic(); obj[jss::public_key_hex] = strHex(acct.begin(), acct.size()); return obj; }