Example #1
0
Json::Value accounts (
    Ledger::ref lrLedger,
    RippleAddress const& naMasterGenerator,
    NetworkOPs& netOps)
{
    Json::Value jsonAccounts (Json::arrayValue);

    // YYY Don't want to leak to thin server that these accounts are related.
    // YYY Would be best to alternate requests to servers and to cache results.
    unsigned int    uIndex  = 0;

    do
    {
        RippleAddress       naAccount;

        naAccount.setAccountPublic (naMasterGenerator, uIndex++);

        AccountState::pointer as    = netOps.getAccountState (lrLedger, naAccount);

        if (as)
        {
            Json::Value jsonAccount (Json::objectValue);

            as->addJson (jsonAccount);

            jsonAccounts.append (jsonAccount);
        }
        else
        {
            uIndex  = 0;
        }
    }
    while (uIndex);

    return jsonAccounts;
}
Example #2
0
// 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;
}
bool PathRequest::isValid (RippleLineCache::ref crCache)
{
    ScopedLockType sl (mLock);
    bValid = raSrcAccount.isSet () && raDstAccount.isSet () && saDstAmount > zero;
    Ledger::pointer lrLedger = crCache->getLedger ();

    if (bValid)
    {
        AccountState::pointer asSrc = getApp().getOPs ().getAccountState (crCache->getLedger(), raSrcAccount);

        if (!asSrc)
        {
            // no source account
            bValid = false;
            jvStatus = rpcError (rpcSRC_ACT_NOT_FOUND);
        }
        else
        {
            AccountState::pointer asDst = getApp().getOPs ().getAccountState (lrLedger, raDstAccount);

            Json::Value& jvDestCur = (jvStatus["destination_currencies"] = Json::arrayValue);

            if (!asDst)
            {
                // no destination account
                jvDestCur.append (Json::Value ("XRP"));

                if (!saDstAmount.isNative ())
                {
                    // only XRP can be send to a non-existent account
                    bValid = false;
                    jvStatus = rpcError (rpcACT_NOT_FOUND);
                }
                else if (saDstAmount < STAmount (lrLedger->getReserve (0)))
                {
                    // payment must meet reserve
                    bValid = false;
                    jvStatus = rpcError (rpcDST_AMT_MALFORMED);
                }
            }
            else
            {
                bool const disallowXRP (
                    asDst->peekSLE ().getFlags() & lsfDisallowXRP);

                CurrencySet usDestCurrID =
                    usAccountDestCurrencies (raDstAccount, crCache, !disallowXRP);

                for (auto const& currency : usDestCurrID)
                    jvDestCur.append (to_string (currency));

                jvStatus["destination_tag"] = (asDst->peekSLE ().getFlags () & lsfRequireDestTag) != 0;
            }
        }
    }

    if (bValid)
    {
        jvStatus["ledger_hash"] = to_string (lrLedger->getHash ());
        jvStatus["ledger_index"] = lrLedger->getLedgerSeq ();
    }
    return bValid;
}
// 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.");
    }
}