diff --git a/src/ripple/rpc/handlers/Handlers.h b/src/ripple/rpc/handlers/Handlers.h index fbac3665c..0f0fb3b5c 100644 --- a/src/ripple/rpc/handlers/Handlers.h +++ b/src/ripple/rpc/handlers/Handlers.h @@ -48,6 +48,7 @@ Json::Value doLedgerHeader (RPC::Context&); Json::Value doLedgerRequest (RPC::Context&); Json::Value doLogLevel (RPC::Context&); Json::Value doLogRotate (RPC::Context&); +Json::Value doNoRippleCheck (RPC::Context&); Json::Value doOwnerInfo (RPC::Context&); Json::Value doPathFind (RPC::Context&); Json::Value doPeers (RPC::Context&); diff --git a/src/ripple/rpc/handlers/NoRippleCheck.cpp b/src/ripple/rpc/handlers/NoRippleCheck.cpp new file mode 100644 index 000000000..5deca1972 --- /dev/null +++ b/src/ripple/rpc/handlers/NoRippleCheck.cpp @@ -0,0 +1,186 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012-2014 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include + +namespace ripple { + +static void fillTransaction ( + Json::Value& txArray, + RippleAddress const& account, + std::uint32_t& sequence, + Ledger::ref ledger) +{ + txArray["Sequence"] = Json::UInt (sequence++); + txArray["Account"] = account.humanAccountID (); + txArray["Fee"] = Json::UInt (ledger->scaleFeeLoad (10, false)); +} + +// { +// account: | +// account_index: // optional, defaults to 0. +// ledger_hash : +// ledger_index : +// limit: integer // optional, number of problems +// role: gateway|user // account role to assume +// transactions: true // optional, reccommend transactions +// } +Json::Value doNoRippleCheck (RPC::Context& context) +{ + auto const& params (context.params); + if (! params.isMember (jss::account)) + return RPC::missing_field_error ("account"); + + if (! params.isMember ("role")) + return RPC::missing_field_error ("role"); + bool roleGateway = false; + { + std::string const role = params["role"].asString(); + if (role == "gateway") + roleGateway = true; + else if (role != "user") + return RPC::invalid_field_message ("role"); + } + + unsigned int limit = 300; + 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)); + } + } + + bool transactions = false; + if (params.isMember (jss::transactions)) + transactions = params["transactions"].asBool(); + + Ledger::pointer ledger; + Json::Value result (RPC::lookupLedger (params, ledger, context.netOps)); + if (! ledger) + return result; + + Json::Value dummy; + Json::Value& jvTransactions = + transactions ? (result[jss::transactions] = Json::arrayValue) : dummy; + + 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; + } + + AccountState::pointer accountState = ledger->getAccountState (rippleAddress); + if (! accountState) + return rpcError (rpcACT_NOT_FOUND); + + std::uint32_t seq = accountState->peekSLE().getFieldU32 (sfSequence); + + Json::Value& problems = (result["problems"] = Json::arrayValue); + + bool bDefaultRipple = accountState->peekSLE().getFieldU32 (sfFlags) & lsfDefaultRipple; + + if (bDefaultRipple & ! roleGateway) + { + problems.append ("You appear to have set your default ripple flag even though you " + "are not a gateway. This is not recommended unless you are experimenting"); + } + else if (roleGateway & ! bDefaultRipple) + { + problems.append ("You should immediately set your default ripple flag"); + if (transactions) + { + Json::Value& tx = jvTransactions.append (Json::objectValue); + tx["TransactionType"] = "AccountSet"; + tx["SetFlag"] = 8; + fillTransaction (tx, rippleAddress, seq, ledger); + } + } + + auto const accountID = rippleAddress.getAccountID (); + + ledger->visitAccountItems (accountID, uint256(), 0, limit, + [&](SLE::ref ownedItem) + { + if (ownedItem->getType() == ltRIPPLE_STATE) + { + bool const bLow = accountID == ownedItem->getFieldAmount(sfLowLimit).getIssuer(); + + bool const bNoRipple = ownedItem->getFieldU32(sfFlags) & + (bLow ? lsfLowNoRipple : lsfHighNoRipple); + + std::string problem; + bool needFix = false; + if (bNoRipple & roleGateway) + { + problem = "You should clear the no ripple flag on your "; + needFix = true; + } + else if (! roleGateway & ! bNoRipple) + { + problem = "You should probably set the no ripple flag on your "; + needFix = true; + } + if (needFix) + { + Account peer = + ownedItem->getFieldAmount (bLow ? sfHighLimit : sfLowLimit).getIssuer(); + STAmount peerLimit = ownedItem->getFieldAmount (bLow ? sfHighLimit : sfLowLimit); + problem += to_string (peerLimit.getCurrency()); + problem += " line to "; + problem += to_string (peerLimit.getIssuer()); + problems.append (problem); + + STAmount limitAmount (ownedItem->getFieldAmount (bLow ? sfLowLimit : sfHighLimit)); + limitAmount.setIssuer (peer); + + Json::Value& tx = jvTransactions.append (Json::objectValue); + tx["TransactionType"] = "TrustSet"; + tx["LimitAmount"] = limitAmount.getJson (0); + tx["Flags"] = bNoRipple ? tfClearNoRipple : tfSetNoRipple; + fillTransaction(tx, rippleAddress, seq, ledger); + + return true; + } + } + return false; + }); + + return result; +} + +} // ripple diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index 1e6ef9b14..b7df51eaf 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -121,6 +121,7 @@ HandlerTable HANDLERS({ { "ledger_request", byRef (&doLedgerRequest), Role::ADMIN, NO_CONDITION }, { "log_level", byRef (&doLogLevel), Role::ADMIN, NO_CONDITION }, { "logrotate", byRef (&doLogRotate), Role::ADMIN, NO_CONDITION }, + { "noripple_check", byRef (&doNoRippleCheck), Role::USER, NEEDS_CURRENT_LEDGER }, { "owner_info", byRef (&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER }, { "peers", byRef (&doPeers), Role::ADMIN, NO_CONDITION }, { "path_find", byRef (&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER }, diff --git a/src/ripple/unity/rpcx.cpp b/src/ripple/unity/rpcx.cpp index 71968f462..dcc835402 100644 --- a/src/ripple/unity/rpcx.cpp +++ b/src/ripple/unity/rpcx.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include