Exemple #1
0
void
msig::operator()(Env& env, JTx& jt) const
{
    auto const mySigners = signers;
    jt.signer = [mySigners, &env](Env&, JTx& jt)
    {
        jt[sfSigningPubKey.getJsonName()] = "";
        boost::optional<STObject> st;
        try
        {
            st = parse(jt.jv);
        }
        catch(parse_error const&)
        {
            env.test.log << pretty(jt.jv) << std::endl;
            Rethrow();
        }
        auto& js = jt[sfSigners.getJsonName()];
        js.resize(mySigners.size());
        for(std::size_t i = 0; i < mySigners.size(); ++i)
        {
            auto const& e = mySigners[i];
            auto& jo = js[i][sfSigner.getJsonName()];
            jo[jss::Account] = e.acct.human();
            jo[jss::SigningPubKey] = strHex(e.sig.pk().slice());

            Serializer ss {buildMultiSigningData (*st, e.acct.id())};
            auto const sig = ripple::sign (
                *publicKeyType(e.sig.pk().slice()), e.sig.sk(), ss.slice());
            jo[sfTxnSignature.getJsonName()] =
                strHex(Slice{ sig.data(), sig.size() });
        }
    };
}
Exemple #2
0
void
msig::operator()(Env const& env, JTx& jt) const
{
    // VFALCO Inefficient pre-C++14
    auto accounts = accounts_;
    std::sort(accounts.begin(), accounts.end(),
        [](Account const& lhs, Account const& rhs)
        {
            return lhs.id() < rhs.id();
        });
    jt.signer = [accounts, &env](Env&, JTx& jt)
    {
        jt["SigningPubKey"] = "";
        boost::optional<STObject> st;
        try
        {
            st = parse(jt.jv);
        }
        catch(parse_error const&)
        {
            env.test.log << pretty(jt.jv);
            throw;
        }
        auto const signFor =
            parseBase58<AccountID>(
                jt.jv[jss::Account].asString());
        if (! signFor)
        {
            env.test.log <<
                "invalid AccountID: '" <<
                    jt.jv[jss::Account].asString() << "'";
            throw parse_error("msig: bad Account");
        }
        auto& jv = jt["MultiSigners"][0u]["SigningFor"];
        jv[jss::Account] = jt[jss::Account];
        auto& js = jv["SigningAccounts"];
        js.resize(accounts.size());
        for(std::size_t i = 0; i < accounts.size(); ++i)
        {
            auto const& e = accounts[i];
            auto& jo = js[i]["SigningAccount"];
            jo[jss::Account] = e.human();
            jo[jss::SigningPubKey] = strHex(e.pk().slice());

            Serializer ss;
            ss.add32 (HashPrefix::txMultiSign);
            st->addWithoutSigningFields(ss);
            ss.add160(*signFor);
            ss.add160(e.id());
            auto const sig = ripple::sign(
                *publicKeyType(e.pk().slice()),
                    e.sk(), ss.slice());
            jo["MultiSignature"] =
                strHex(Slice{ sig.data(), sig.size() });
        }
    };
}
Exemple #3
0
void
memontype::operator()(Env const&, JTx& jt) const
{
    auto& jv = jt.jv;
    auto& ma = jv["Memos"];
    auto& mi = ma[ma.size()];
    auto& m = mi["Memo"];
    m["MemoData"] = strHex(data_);
    m["MemoFormat"] = strHex(format_);
}
Exemple #4
0
void
msig2_t::operator()(Env const& env, JTx& jt) const
{
    // VFALCO Inefficient pre-C++14
    auto const sigs = sigs_;
    jt.signer = [sigs, &env](Env&, JTx& jt)
    {
        jt["SigningPubKey"] = "";
        boost::optional<STObject> st;
        try
        {
            st = parse(jt.jv);
        }
        catch(parse_error const&)
        {
            env.test.log << pretty(jt.jv);
            throw;
        }
        auto& ja = jt["MultiSigners"];
        ja.resize(sigs.size());
        for (auto i = std::make_pair(0, sigs.begin());
            i.first < sigs.size(); ++i.first, ++i.second)
        {
            auto const& sign_for = i.second->first;
            auto const& list = i.second->second;
            auto& ji = ja[i.first]["SigningFor"];
            ji[jss::Account] = sign_for.human();
            auto& js = ji["SigningAccounts"];
            js.resize(list.size());
            for (auto j = std::make_pair(0, list.begin());
                j.first < list.size(); ++j.first, ++j.second)
            {
                auto& jj = js[j.first]["SigningAccount"];
                jj[jss::Account] = j.second->human();
                jj[jss::SigningPubKey] = strHex(
                    j.second->pk().slice());

                Serializer ss;
                ss.add32 (HashPrefix::txMultiSign);
                st->addWithoutSigningFields(ss);
                ss.add160(sign_for.id());
                ss.add160(j.second->id());
                auto const sig = ripple::sign(
                    *publicKeyType(j.second->pk().slice()),
                        j.second->sk(), ss.slice());
                jj["MultiSignature"] =
                    strHex(Slice{ sig.data(), sig.size() });
            }
        }
    };
}
Exemple #5
0
void
sign (Json::Value& jv,
    Account const& account)
{
    jv[jss::SigningPubKey] =
        strHex(account.pk().slice());
    Serializer ss;
    ss.add32 (HashPrefix::txSign);
    parse(jv).add(ss);
    auto const sig = ripple::sign(
        *publicKeyType(account.pk().slice()),
            account.sk(), ss.slice());
    jv[jss::TxnSignature] =
        strHex(Slice{ sig.data(), sig.size() });
}
// {
//  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;
}
Exemple #7
0
Json::Value
STPath::getJson (int) const
{
    Json::Value ret (Json::arrayValue);

    for (auto it: mPath)
    {
        Json::Value elem (Json::objectValue);
        int         iType   = it.getNodeType ();

        elem[jss::type]      = iType;
        elem[jss::type_hex]  = strHex (iType);

        if (iType & STPathElement::typeAccount)
            elem[jss::account]  = to_string (it.getAccountID ());

        if (iType & STPathElement::typeCurrency)
            elem[jss::currency] = to_string (it.getCurrency ());

        if (iType & STPathElement::typeIssuer)
            elem[jss::issuer]   = to_string (it.getIssuerID ());

        ret.append (elem);
    }

    return ret;
}
Exemple #8
0
uint256 ParseHashV(const UniValue& v, std::string strName)
{
    std::string strHex(v.get_str());
    if (64 != strHex.length())
        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
    if (!IsHex(strHex)) // Note: IsHex("") is false
        throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
    return uint256S(strHex);
}
Exemple #9
0
void
memotype::operator()(Env const&, JTx& jt) const
{
    auto& jv = jt.jv;
    auto& ma = jv["Memos"];
    auto& mi = ma[ma.size()];
    auto& m = mi["Memo"];
    m["MemoType"] = strHex(s_);
}
Exemple #10
0
// VFALCO TODO Make this a generic utility function of some container class
//
std::string AccountState::createGravatarUrl (uint128 uEmailHash)
{
    Blob    vucMD5 (uEmailHash.begin (), uEmailHash.end ());
    std::string                 strMD5Lower = strHex (vucMD5);
    boost::to_lower (strMD5Lower);

    // VFALCO TODO Give a name and move this constant to a more visible location.
    //             Also shouldn't this be https?
    return str (boost::format ("http://www.gravatar.com/avatar/%s") % strMD5Lower);
}
Exemple #11
0
Json::Value STTx::getJson (int options, bool binary) const
{
    if (binary)
    {
        Json::Value ret;
        Serializer s = STObject::getSerializer ();
        ret[jss::tx] = strHex (s.peekData ());
        ret[jss::hash] = to_string (getTransactionID ());
        return ret;
    }
    return getJson(options);
}
Exemple #12
0
// {
//   secret_key: <signing_secret_key>
//   channel_id: 256-bit channel id
//   drops: 64-bit uint (as string)
// }
Json::Value doChannelAuthorize (RPC::Context& context)
{
    auto const& params (context.params);
    for (auto const& p : {jss::secret, jss::channel_id, jss::amount})
        if (!params.isMember (p))
            return RPC::missing_field_error (p);

    Json::Value result;
    auto const keypair = RPC::keypairForSignature (params, result);
    if (RPC::contains_error (result))
        return result;

    uint256 channelId;
    if (!channelId.SetHexExact (params[jss::channel_id].asString ()))
        return rpcError (rpcCHANNEL_MALFORMED);

    std::uint64_t drops = 0;
    try
    {
        drops = std::stoul (params[jss::amount].asString ());
    }
    catch (std::exception const&)
    {
        return rpcError (rpcCHANNEL_AMT_MALFORMED);
    }

    Serializer msg;
    serializePayChanAuthorization (msg, channelId, XRPAmount (drops));

    try
    {
        auto const buf = sign (keypair.first, keypair.second, msg.slice ());
        result[jss::signature] = strHex (buf);
    }
    catch (std::exception&)
    {
        result =
            RPC::make_error (rpcINTERNAL, "Exception occurred during signing.");
    }
    return result;
}
Exemple #13
0
std::string to_string(Currency const& currency)
{
    static Currency const sIsoBits ("FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF");

    // Characters we are willing to allow in the ASCII representation of a
    // three-letter currency code.
    static std::string const allowed_characters =
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "0123456789"
        "<>(){}[]|?!@#$%^&*";

    if (currency == zero)
        return systemCurrencyCode();

	if (currency == vbcCurrency())
		return systemCurrencyCodeVBC();

    if (currency == noCurrency())
        return "1";

    if ((currency & sIsoBits).isZero ())
    {
        // The offset of the 3 character ISO code in the currency descriptor
        int const isoOffset = 12;

        std::string const iso(
            currency.data () + isoOffset,
            currency.data () + isoOffset + 3);

        // Specifying the system currency code using ISO-style representation
        // is not allowed.
		if ((iso != systemCurrencyCode()) && (iso != systemCurrencyCodeVBC()) &&
            (iso.find_first_not_of (allowed_characters) == std::string::npos))
        {
            return iso;
        }
    }

    return strHex (currency.begin (), currency.size ());
}
// {
//   ledger_hash : <ledger>
//   ledger_index : <ledger_index>
// }
Json::Value doLedgerHeader (RPC::Context& context)
{
    Ledger::pointer lpLedger;
    Json::Value jvResult = RPC::lookupLedger (
        context.params_, lpLedger, context.netOps_);

    if (!lpLedger)
        return jvResult;

    Serializer  s;

    lpLedger->addRaw (s);

    jvResult["ledger_data"] = strHex (s.peekData ());

    // This information isn't verified: they should only use it if they trust
    // us.
    lpLedger->addJson (jvResult, 0);

    return jvResult;
}
Exemple #15
0
void addChannel (Json::Value& jsonLines, SLE const& line)
{
    Json::Value& jDst (jsonLines.append (Json::objectValue));
    jDst[jss::channel_id] = to_string (line.key ());
    jDst[jss::account] = to_string (line[sfAccount]);
    jDst[jss::destination_account] = to_string (line[sfDestination]);
    jDst[jss::amount] = line[sfAmount].getText ();
    jDst[jss::balance] = line[sfBalance].getText ();
    PublicKey const pk (line[sfPublicKey]);
    jDst[jss::public_key] = toBase58 (TokenType::TOKEN_ACCOUNT_PUBLIC, pk);
    jDst[jss::public_key_hex] = strHex (pk);
    jDst[jss::settle_delay] = line[sfSettleDelay];
    if (auto const& v = line[~sfExpiration])
        jDst[jss::expiration] = *v;
    if (auto const& v = line[~sfCancelAfter])
        jDst[jss::cancel_after] = *v;
    if (auto const& v = line[~sfSourceTag])
        jDst[jss::source_tag] = *v;
    if (auto const& v = line[~sfDestinationTag])
        jDst[jss::destination_tag] = *v;
}
Exemple #16
0
void AcceptedLedgerTx::buildJson ()
{
    mJson = Json::objectValue;
    mJson[jss::transaction] = mTxn->getJson (0);

    if (mMeta)
    {
        mJson[jss::meta] = mMeta->getJson (0);
        mJson[jss::raw_meta] = strHex (mRawMeta);
    }

    mJson[jss::result] = transHuman (mResult);

    if (!mAffected.empty ())
    {
        Json::Value& affected = (mJson[jss::affected] = Json::arrayValue);
        for (auto const& ra : mAffected)
        {
            affected.append (ra.humanAccountID ());
        }
    }

    if (mTxn->getTxnType () == ttOFFER_CREATE)
    {
        auto const account (mTxn->getSourceAccount ().getAccountID ());
        auto const amount (mTxn->getFieldAmount (sfTakerGets));

        // If the offer create is not self funded then add the owner balance
        if (account != amount.issue ().account)
        {
            LedgerEntrySet les (mLedger, tapNONE, true);
            auto const ownerFunds (funds(
                les, account, amount, fhIGNORE_FREEZE));

            mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText ();
        }
    }
}
Exemple #17
0
Json::Value STPath::getJson (int) const
{
    Json::Value ret (Json::arrayValue);

    BOOST_FOREACH (std::vector<STPathElement>::const_iterator::value_type it, mPath)
    {
        Json::Value elem (Json::objectValue);
        int         iType   = it.getNodeType ();

        elem["type"]        = iType;
        elem["type_hex"]    = strHex (iType);

        if (iType & STPathElement::typeAccount)
            elem["account"]     = RippleAddress::createHumanAccountID (it.getAccountID ());

        if (iType & STPathElement::typeCurrency)
            elem["currency"]    = STAmount::createHumanCurrency (it.getCurrency ());

        if (iType & STPathElement::typeIssuer)
            elem["issuer"]      = RippleAddress::createHumanAccountID (it.getIssuerID ());

        ret.append (elem);
    }
std::string STVariableLength::getText() const
{
	return strHex(value);
}
Exemple #19
0
SHAMapTreeNode::SHAMapTreeNode (const SHAMapNode& id, Blob const& rawNode, uint32 seq,
                                SHANodeFormat format, uint256 const& hash, bool hashValid) :
    SHAMapNode (id), mSeq (seq), mType (tnERROR), mIsBranch (0), mFullBelow (false)
{
    if (format == snfWIRE)
    {
        Serializer s (rawNode);
        int type = s.removeLastByte ();
        int len = s.getLength ();

        if ((type < 0) || (type > 4))
        {
#ifdef BEAST_DEBUG
            Log::out() << "Invalid wire format node";
            Log::out() << strHex (rawNode);
            assert (false);
#endif
            throw std::runtime_error ("invalid node AW type");
        }

        if (type == 0)
        {
            // transaction
            mItem = boost::make_shared<SHAMapItem> (s.getPrefixHash (HashPrefix::transactionID), s.peekData ());
            mType = tnTRANSACTION_NM;
        }
        else if (type == 1)
        {
            // account state
            if (len < (256 / 8))
                throw std::runtime_error ("short AS node");

            uint256 u;
            s.get256 (u, len - (256 / 8));
            s.chop (256 / 8);

            if (u.isZero ()) throw std::runtime_error ("invalid AS node");

            mItem = boost::make_shared<SHAMapItem> (u, s.peekData ());
            mType = tnACCOUNT_STATE;
        }
        else if (type == 2)
        {
            // full inner
            if (len != 512)
                throw std::runtime_error ("invalid FI node");

            for (int i = 0; i < 16; ++i)
            {
                s.get256 (mHashes[i], i * 32);

                if (mHashes[i].isNonZero ())
                    mIsBranch |= (1 << i);
            }

            mType = tnINNER;
        }
        else if (type == 3)
        {
            // compressed inner
            for (int i = 0; i < (len / 33); ++i)
            {
                int pos;
                s.get8 (pos, 32 + (i * 33));

                if ((pos < 0) || (pos >= 16)) throw std::runtime_error ("invalid CI node");

                s.get256 (mHashes[pos], i * 33);

                if (mHashes[pos].isNonZero ())
                    mIsBranch |= (1 << pos);
            }

            mType = tnINNER;
        }
        else if (type == 4)
        {
            // transaction with metadata
            if (len < (256 / 8))
                throw std::runtime_error ("short TM node");

            uint256 u;
            s.get256 (u, len - (256 / 8));
            s.chop (256 / 8);

            if (u.isZero ())
                throw std::runtime_error ("invalid TM node");

            mItem = boost::make_shared<SHAMapItem> (u, s.peekData ());
            mType = tnTRANSACTION_MD;
        }
    }

    else if (format == snfPREFIX)
    {
        if (rawNode.size () < 4)
        {
            WriteLog (lsINFO, SHAMapNode) << "size < 4";
            throw std::runtime_error ("invalid P node");
        }

        uint32 prefix = rawNode[0];
        prefix <<= 8;
        prefix |= rawNode[1];
        prefix <<= 8;
        prefix |= rawNode[2];
        prefix <<= 8;
        prefix |= rawNode[3];
        Serializer s (rawNode.begin () + 4, rawNode.end ());

        if (prefix == HashPrefix::transactionID)
        {
            mItem = boost::make_shared<SHAMapItem> (Serializer::getSHA512Half (rawNode), s.peekData ());
            mType = tnTRANSACTION_NM;
        }
        else if (prefix == HashPrefix::leafNode)
        {
            if (s.getLength () < 32)
                throw std::runtime_error ("short PLN node");

            uint256 u;
            s.get256 (u, s.getLength () - 32);
            s.chop (32);

            if (u.isZero ())
            {
                WriteLog (lsINFO, SHAMapNode) << "invalid PLN node";
                throw std::runtime_error ("invalid PLN node");
            }

            mItem = boost::make_shared<SHAMapItem> (u, s.peekData ());
            mType = tnACCOUNT_STATE;
        }
        else if (prefix == HashPrefix::innerNode)
        {
            if (s.getLength () != 512)
                throw std::runtime_error ("invalid PIN node");

            for (int i = 0; i < 16; ++i)
            {
                s.get256 (mHashes[i], i * 32);

                if (mHashes[i].isNonZero ())
                    mIsBranch |= (1 << i);
            }

            mType = tnINNER;
        }
        else if (prefix == HashPrefix::txNode)
        {
            // transaction with metadata
            if (s.getLength () < 32)
                throw std::runtime_error ("short TXN node");

            uint256 txID;
            s.get256 (txID, s.getLength () - 32);
            s.chop (32);
            mItem = boost::make_shared<SHAMapItem> (txID, s.peekData ());
            mType = tnTRANSACTION_MD;
        }
        else
        {
            WriteLog (lsINFO, SHAMapNode) << "Unknown node prefix " << std::hex << prefix << std::dec;
            throw std::runtime_error ("invalid node prefix");
        }
    }

    else
    {
        assert (false);
        throw std::runtime_error ("Unknown format");
    }

    if (hashValid)
    {
        mHash = hash;
#if RIPPLE_VERIFY_NODEOBJECT_KEYS
        updateHash ();
        assert (mHash == hash);
#endif
    }
    else
        updateHash ();
}
Exemple #20
0
Json::Value
ValidatorList::getJson() const
{
    Json::Value res(Json::objectValue);

    boost::shared_lock<boost::shared_mutex> read_lock{mutex_};

    res[jss::validation_quorum] = static_cast<Json::UInt>(quorum());

    if (auto when = expires())
    {
        if (*when == TimeKeeper::time_point::max())
            res[jss::validator_list_expires] = "never";
        else
            res[jss::validator_list_expires] = to_string(*when);
    }
    else
        res[jss::validator_list_expires] = "unknown";

    // Local static keys
    PublicKey local;
    Json::Value& jLocalStaticKeys =
        (res[jss::local_static_keys] = Json::arrayValue);
    auto it = publisherLists_.find(local);
    if (it != publisherLists_.end())
    {
        for (auto const& key : it->second.list)
            jLocalStaticKeys.append(
                toBase58(TokenType::TOKEN_NODE_PUBLIC, key));
    }

    // Publisher lists
    Json::Value& jPublisherLists =
        (res[jss::publisher_lists] = Json::arrayValue);
    for (auto const& p : publisherLists_)
    {
        if(local == p.first)
            continue;
        Json::Value& curr = jPublisherLists.append(Json::objectValue);
        curr[jss::pubkey_publisher] = strHex(p.first);
        curr[jss::available] = p.second.available;
        if(p.second.expiration != TimeKeeper::time_point{})
        {
            curr[jss::seq] = static_cast<Json::UInt>(p.second.sequence);
            curr[jss::expiration] = to_string(p.second.expiration);
            curr[jss::version] = requiredListVersion;
        }
        Json::Value& keys = (curr[jss::list] = Json::arrayValue);
        for (auto const& key : p.second.list)
        {
            keys.append(toBase58(TokenType::TOKEN_NODE_PUBLIC, key));
        }
    }

    // Trusted validator keys
    Json::Value& jValidatorKeys =
        (res[jss::trusted_validator_keys] = Json::arrayValue);
    for (auto const& k : trustedKeys_)
    {
        jValidatorKeys.append(toBase58(TokenType::TOKEN_NODE_PUBLIC, k));
    }

    // signing keys
    Json::Value& jSigningKeys = (res[jss::signing_keys] = Json::objectValue);
    validatorManifests_.for_each_manifest(
        [&jSigningKeys, this](Manifest const& manifest) {

            auto it = keyListings_.find(manifest.masterKey);
            if (it != keyListings_.end())
            {
                jSigningKeys[toBase58(
                    TokenType::TOKEN_NODE_PUBLIC, manifest.masterKey)] =
                    toBase58(TokenType::TOKEN_NODE_PUBLIC, manifest.signingKey);
            }
        });

    return res;
}
Exemple #21
0
// 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.");
    }
}
// Get state nodes from a ledger
//   Inputs:
//     limit:        integer, maximum number of entries
//     marker:       opaque, resume point
//     binary:       boolean, format
//   Outputs:
//     ledger_hash:  chosen ledger's hash
//     ledger_index: chosen ledger's index
//     state:        array of state nodes
//     marker:       resume point, if any
Json::Value doLedgerData (RPC::Context& context)
{
    context.lock_.unlock ();

    int const BINARY_PAGE_LENGTH = 256;
    int const JSON_PAGE_LENGTH = 2048;

    Ledger::pointer lpLedger;

    Json::Value jvResult = RPC::lookupLedger (context.params_, lpLedger, context.netOps_);
    if (!lpLedger)
        return jvResult;

    uint256 resumePoint;
    if (context.params_.isMember ("marker"))
    {
        Json::Value const& jMarker = context.params_["marker"];
        if (!jMarker.isString ())
            return RPC::expected_field_error ("marker", "valid");
        if (!resumePoint.SetHex (jMarker.asString ()))
            return RPC::expected_field_error ("marker", "valid");
    }

    bool isBinary = false;
    if (context.params_.isMember ("binary"))
    {
        Json::Value const& jBinary = context.params_["binary"];
        if (!jBinary.isBool ())
            return RPC::expected_field_error ("binary", "bool");
        isBinary = jBinary.asBool ();
    }

    int limit = -1;
    int maxLimit = isBinary ? BINARY_PAGE_LENGTH : JSON_PAGE_LENGTH;

    if (context.params_.isMember ("limit"))
    {
        Json::Value const& jLimit = context.params_["limit"];
        if (!jLimit.isIntegral ())
            return RPC::expected_field_error ("limit", "integer");

        limit = jLimit.asInt ();
    }

    if ((limit < 0) || ((limit > maxLimit) && (context.role_ != Config::ADMIN)))
        limit = maxLimit;

    Json::Value jvReply = Json::objectValue;

    jvReply["ledger_hash"] = to_string (lpLedger->getHash());
    jvReply["ledger_index"] = beast::lexicalCastThrow <std::string> (lpLedger->getLedgerSeq ());

    Json::Value& nodes = (jvReply["state"] = Json::arrayValue);
    SHAMap& map = *(lpLedger->peekAccountStateMap ());

    for (;;)
    {
       SHAMapItem::pointer item = map.peekNextItem (resumePoint);
       if (!item)
           break;
       resumePoint = item->getTag();

       if (limit-- <= 0)
       {
           --resumePoint;
           jvReply["marker"] = to_string (resumePoint);
           break;
       }

       if (isBinary)
       {
           Json::Value& entry = nodes.append (Json::objectValue);
           entry["data"] = strHex (item->peekData().begin(), item->peekData().size());
           entry["index"] = to_string (item->getTag ());
       }
       else
       {
           SLE sle (item->peekSerializer(), item->getTag ());
           Json::Value& entry = nodes.append (sle.getJson (0));
           entry["index"] = to_string (item->getTag ());
       }
    }

    return jvReply;
}
// 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.");
    }
}
Exemple #24
0
// {
//   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;
}
Exemple #25
0
Json::Value walletPropose (Json::Value const& params)
{
    boost::optional<KeyType> keyType;
    boost::optional<Seed> seed;
    bool rippleLibSeed = false;

    if (params.isMember (jss::key_type))
    {
        if (! params[jss::key_type].isString())
        {
            return RPC::expected_field_error (
                jss::key_type, "string");
        }

        keyType = keyTypeFromString (
            params[jss::key_type].asString());

        if (!keyType)
            return rpcError(rpcINVALID_PARAMS);
    }

    // ripple-lib encodes seed used to generate an Ed25519 wallet in a
    // non-standard way. While we never encode seeds that way, we try
    // to detect such keys to avoid user confusion.
    {
        if (params.isMember(jss::passphrase))
            seed = RPC::parseRippleLibSeed(params[jss::passphrase]);
        else if (params.isMember(jss::seed))
            seed = RPC::parseRippleLibSeed(params[jss::seed]);

        if(seed)
        {
            rippleLibSeed = true;

            // If the user *explicitly* requests a key type other than
            // Ed25519 we return an error.
            if (keyType.value_or(KeyType::ed25519) != KeyType::ed25519)
                return rpcError(rpcBAD_SEED);

            keyType = KeyType::ed25519;
        }
    }

    if (!seed)
    {
        if (params.isMember(jss::passphrase) ||
            params.isMember(jss::seed) ||
            params.isMember(jss::seed_hex))
        {
            Json::Value err;

            seed = RPC::getSeedFromRPC(params, err);

            if (!seed)
                return err;
        }
        else
        {
            seed = randomSeed();
        }
    }

    if (!keyType)
        keyType = KeyType::secp256k1;

    auto const publicKey = generateKeyPair (*keyType, *seed).first;

    Json::Value obj (Json::objectValue);

    auto const seed1751 = seedAs1751 (*seed);
    auto const seedHex = strHex (*seed);
    auto const seedBase58 = toBase58 (*seed);

    obj[jss::master_seed] = seedBase58;
    obj[jss::master_seed_hex] = seedHex;
    obj[jss::master_key] = seed1751;
    obj[jss::account_id] = toBase58(calcAccountID(publicKey));
    obj[jss::public_key] = toBase58(TokenType::AccountPublic, publicKey);
    obj[jss::key_type] = to_string (*keyType);
    obj[jss::public_key_hex] = strHex (publicKey);

    // If a passphrase was specified, and it was hashed and used as a seed
    // run a quick entropy check and add an appropriate warning, because
    // "brain wallets" can be easily attacked.
    if (!rippleLibSeed && params.isMember (jss::passphrase))
    {
        auto const passphrase = params[jss::passphrase].asString();

        if (passphrase != seed1751 &&
            passphrase != seedBase58 &&
            passphrase != seedHex)
        {
            // 80 bits of entropy isn't bad, but it's better to
            // err on the side of caution and be conservative.
            if (estimate_entropy (passphrase) < 80.0)
                obj[jss::warning] =
                    "This wallet was generated using a user-supplied "
                    "passphrase that has low entropy and is vulnerable "
                    "to brute-force attacks.";
            else
                obj[jss::warning] =
                    "This wallet was generated using a user-supplied "
                    "passphrase. It may be vulnerable to brute-force "
                    "attacks.";
        }
    }

    return obj;
}
Exemple #26
0
Json::Value walletPropose (Json::Value const& params)
{
    boost::optional<Seed> seed;

    KeyType keyType = KeyType::secp256k1;

    if (params.isMember (jss::key_type))
    {
        if (! params[jss::key_type].isString())
        {
            return RPC::expected_field_error (
                jss::key_type, "string");
        }

        keyType = keyTypeFromString (
            params[jss::key_type].asString());

        if (keyType == KeyType::invalid)
            return rpcError(rpcINVALID_PARAMS);
    }

    if (params.isMember (jss::passphrase) ||
        params.isMember (jss::seed) ||
        params.isMember (jss::seed_hex))
    {
        Json::Value err;
        seed = RPC::getSeedFromRPC (params, err);
        if (!seed)
            return err;
    }
    else
    {
        seed = randomSeed ();
    }

    auto const publicKey = generateKeyPair (keyType, *seed).first;

    Json::Value obj (Json::objectValue);

    obj[jss::master_seed] = toBase58 (*seed);
    obj[jss::master_seed_hex] = strHex (seed->data(), seed->size());
    obj[jss::master_key] = seedAs1751 (*seed);
    obj[jss::account_id] = toBase58(calcAccountID(publicKey));
    obj[jss::public_key] = toBase58(TOKEN_ACCOUNT_PUBLIC, publicKey);
    obj[jss::key_type] = to_string (keyType);
    obj[jss::public_key_hex] = strHex (publicKey.data(), publicKey.size());

    if (params.isMember (jss::passphrase))
    {
        auto const entropy = estimate_entropy (
            params[jss::passphrase].asString());

        // 80 bits of entropy isn't bad, but it's better to
        // err on the side of caution and be conservative.
        if (entropy < 80.0)
            obj[jss::warning] =
                "This wallet was generated using a user-supplied "
                "passphrase that has low entropy and is vulnerable "
                "to brute-force attacks.";
        else
            obj[jss::warning] =
                "This wallet was generated using a user-supplied "
                "passphrase. It may be vulnerable to brute-force "
                "attacks.";
    }

    return obj;
}
Exemple #27
0
Json::Value STUInt64::getJson (int) const
{
    return strHex (value_);
}
Exemple #28
0
ListDisposition
ValidatorList::applyList (
    std::string const& manifest,
    std::string const& blob,
    std::string const& signature,
    std::uint32_t version)
{
    if (version != requiredListVersion)
        return ListDisposition::unsupported_version;

    boost::unique_lock<boost::shared_mutex> lock{mutex_};

    Json::Value list;
    PublicKey pubKey;
    auto const result = verify (list, pubKey, manifest, blob, signature);
    if (result != ListDisposition::accepted)
        return result;

    // Update publisher's list
    Json::Value const& newList = list["validators"];
    publisherLists_[pubKey].available = true;
    publisherLists_[pubKey].sequence = list["sequence"].asUInt ();
    publisherLists_[pubKey].expiration = TimeKeeper::time_point{
        TimeKeeper::duration{list["expiration"].asUInt()}};
    std::vector<PublicKey>& publisherList = publisherLists_[pubKey].list;

    std::vector<PublicKey> oldList = publisherList;
    publisherList.clear ();
    publisherList.reserve (newList.size ());
    std::vector<std::string> manifests;
    for (auto const& val : newList)
    {
        if (val.isObject () &&
            val.isMember ("validation_public_key") &&
            val["validation_public_key"].isString ())
        {
            std::pair<Blob, bool> ret (strUnHex (
                val["validation_public_key"].asString ()));

            if (! ret.second || ! ret.first.size ())
            {
                JLOG (j_.error()) <<
                    "Invalid node identity: " <<
                    val["validation_public_key"].asString ();
            }
            else
            {
                publisherList.push_back (
                    PublicKey(Slice{ ret.first.data (), ret.first.size() }));
            }

            if (val.isMember ("manifest") && val["manifest"].isString ())
                manifests.push_back(val["manifest"].asString ());
        }
    }

    // Update keyListings_ for added and removed keys
    std::sort (
        publisherList.begin (),
        publisherList.end ());

    auto iNew = publisherList.begin ();
    auto iOld = oldList.begin ();
    while (iNew != publisherList.end () ||
        iOld != oldList.end ())
    {
        if (iOld == oldList.end () ||
            (iNew != publisherList.end () &&
            *iNew < *iOld))
        {
            // Increment list count for added keys
            ++keyListings_[*iNew];
            ++iNew;
        }
        else if (iNew == publisherList.end () ||
            (iOld != oldList.end () && *iOld < *iNew))
        {
            // Decrement list count for removed keys
            if (keyListings_[*iOld] <= 1)
                keyListings_.erase (*iOld);
            else
                --keyListings_[*iOld];
            ++iOld;
        }
        else
        {
            ++iNew;
            ++iOld;
        }
    }

    if (publisherList.empty())
    {
        JLOG (j_.warn()) <<
            "No validator keys included in valid list";
    }

    for (auto const& valManifest : manifests)
    {
        auto m = Manifest::make_Manifest (
            beast::detail::base64_decode(valManifest));

        if (! m || ! keyListings_.count (m->masterKey))
        {
            JLOG (j_.warn()) <<
                "List for " << strHex(pubKey) <<
                " contained untrusted validator manifest";
            continue;
        }

        auto const result = validatorManifests_.applyManifest (std::move(*m));
        if (result == ManifestDisposition::invalid)
        {
            JLOG (j_.warn()) <<
                "List for " << strHex(pubKey) <<
                " contained invalid validator manifest";
        }
    }

    return ListDisposition::accepted;
}
Exemple #29
0
// {
//   tx_json: <object>,
//   secret: <secret>
// }
Json::Value doSubmit (RPC::Context& context)
{
    context.loadType = Resource::feeMediumBurdenRPC;

    if (!context.params.isMember (jss::tx_blob))
    {
        auto const failType = getFailHard (context);

        if (context.role != Role::ADMIN && !context.app.config().canSign())
            return RPC::make_error (rpcNOT_SUPPORTED,
                "Signing is not supported by this server.");

        auto ret = RPC::transactionSubmit (
            context.params, failType, context.role,
            context.ledgerMaster.getValidatedLedgerAge(),
            context.app, RPC::getProcessTxnFn (context.netOps));

        ret[jss::deprecated] = "Signing support in the 'submit' command has been "
                               "deprecated and will be removed in a future version "
                               "of the server. Please migrate to a standalone "
                               "signing tool.";

        return ret;
    }

    Json::Value jvResult;

    std::pair<Blob, bool> ret(strUnHex (context.params[jss::tx_blob].asString ()));

    if (!ret.second || !ret.first.size ())
        return rpcError (rpcINVALID_PARAMS);

    SerialIter sitTrans (makeSlice(ret.first));

    std::shared_ptr<STTx const> stpTrans;

    try
    {
        stpTrans = std::make_shared<STTx const> (std::ref (sitTrans));
    }
    catch (std::exception& e)
    {
        jvResult[jss::error]        = "invalidTransaction";
        jvResult[jss::error_exception] = e.what ();

        return jvResult;
    }


    {
        if (!context.app.checkSigs())
            forceValidity(context.app.getHashRouter(),
                stpTrans->getTransactionID(), Validity::SigGoodOnly);
        auto validity = checkValidity(context.app.getHashRouter(),
            *stpTrans, context.ledgerMaster.getCurrentLedger()->rules(),
                context.app.config());
        if (validity.first != Validity::Valid)
        {
            jvResult[jss::error] = "invalidTransaction";
            jvResult[jss::error_exception] = "fails local checks: " + validity.second;

            return jvResult;
        }
    }

    std::string reason;
    auto tpTrans = std::make_shared<Transaction> (
        stpTrans, reason, context.app);
    if (tpTrans->getStatus() != NEW)
    {
        jvResult[jss::error]            = "invalidTransaction";
        jvResult[jss::error_exception] = "fails local checks: " + reason;

        return jvResult;
    }

    try
    {
        auto const failType = getFailHard (context);

        context.netOps.processTransaction (
            tpTrans, isUnlimited (context.role), true, failType);
    }
    catch (std::exception& e)
    {
        jvResult[jss::error]           = "internalSubmit";
        jvResult[jss::error_exception] = e.what ();

        return jvResult;
    }


    try
    {
        jvResult[jss::tx_json] = tpTrans->getJson (0);
        jvResult[jss::tx_blob] = strHex (
            tpTrans->getSTransaction ()->getSerializer ().peekData ());

        if (temUNCERTAIN != tpTrans->getResult ())
        {
            std::string sToken;
            std::string sHuman;

            transResultInfo (tpTrans->getResult (), sToken, sHuman);

            jvResult[jss::engine_result]           = sToken;
            jvResult[jss::engine_result_code]      = tpTrans->getResult ();
            jvResult[jss::engine_result_message]   = sHuman;
        }

        return jvResult;
    }
    catch (std::exception& e)
    {
        jvResult[jss::error]           = "internalJson";
        jvResult[jss::error_exception] = e.what ();

        return jvResult;
    }
}
Exemple #30
0
Json::Value walletPropose (Json::Value const& params)
{
    DivvyAddress   naSeed;
    DivvyAddress   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)
    {
        DivvyAddress naGenerator = DivvyAddress::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;
}