mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Refactor AccountID (RIPD-953):
All AccountID functionality is removed from RippleAddress and
replaced with free functions. The AccountID to string conversion
cache is factored out as an explicit type with an instance in
the Application object. New base58 conversion functions are used,
with no dependence on OpenSSL.
All types and free functions related to AccountID are consolidated
into one header file. Routines to operate on "tokens" are also
introduced and consolidated into a single header file.
A token one of the cryptographic primitives used in Ripple:
Secret Seed
Server Public Key
Server Secret Key
Account ID
Account Public Key
Account Private Key
and these deprecated primitives:
Account Family Seed
Account Family Generator
This commit is contained in:
194
src/ripple/protocol/AccountID.h
Normal file
194
src/ripple/protocol/AccountID.h
Normal file
@@ -0,0 +1,194 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/tokens.h>
|
||||
// VFALCO Uncomment when the header issues are resolved
|
||||
//#include <ripple/protocol/AnyPublicKey.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO Forward declared due to header issues
|
||||
class AnyPublicKey;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class AccountIDTag { };
|
||||
|
||||
} // detail
|
||||
|
||||
/** A 160-bit unsigned that uniquely identifies an account. */
|
||||
using AccountID = base_uint<
|
||||
160, detail::AccountIDTag>;
|
||||
|
||||
/** Convert AccountID to base58 checked string */
|
||||
std::string
|
||||
toBase58 (AccountID const& v);
|
||||
|
||||
/** Parse AccountID from checked, base58 string.
|
||||
@return boost::none if a parse error occurs
|
||||
*/
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseBase58 (std::string const& s);
|
||||
|
||||
// Parses AccountID using Bitcoin's alphabet
|
||||
// This is to catch user error. Likely not needed
|
||||
// DEPRECATED
|
||||
boost::optional<AccountID>
|
||||
deprecatedParseBitcoinAccountID (std::string const& s);
|
||||
|
||||
// Compatibility with legacy code
|
||||
bool
|
||||
deprecatedParseBase58 (AccountID& account,
|
||||
Json::Value const& jv);
|
||||
|
||||
/** Parse AccountID from hexadecimal string
|
||||
|
||||
If the string is not exactly 40
|
||||
hex digits, boost::none is returned.
|
||||
|
||||
@return boost::none if a parse error occurs
|
||||
*/
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseHex (std::string const& s);
|
||||
|
||||
/** Parse AccountID from hex or checked base58 string.
|
||||
|
||||
@return boost::none if a parse error occurs
|
||||
*/
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseHexOrBase58 (std::string const& s);
|
||||
|
||||
// VFALCO NOTE These help transition away from RippleAddress
|
||||
|
||||
/** Compute AccountID from public key.
|
||||
|
||||
The account ID is computed as the 160-bit hash of the
|
||||
public key data. This excludes the version byte and
|
||||
guard bytes included in the base58 representation.
|
||||
|
||||
*/
|
||||
AccountID
|
||||
calcAccountID (AnyPublicKey const& pk);
|
||||
|
||||
/** A special account that's used as the "issuer" for XRP. */
|
||||
AccountID const&
|
||||
xrpAccount();
|
||||
|
||||
/** A placeholder for empty accounts. */
|
||||
AccountID const&
|
||||
noAccount();
|
||||
|
||||
/** Convert hex or base58 string to AccountID.
|
||||
|
||||
@return `true` if the parsing was successful.
|
||||
*/
|
||||
// DEPRECATED
|
||||
bool
|
||||
to_issuer (AccountID&, std::string const&);
|
||||
|
||||
// DEPRECATED Should be checking the currency or native flag
|
||||
inline
|
||||
bool
|
||||
isXRP(AccountID const& c)
|
||||
{
|
||||
return c == zero;
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
inline
|
||||
std::string
|
||||
to_string (AccountID const& account)
|
||||
{
|
||||
return toBase58(account);
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
inline std::ostream& operator<< (std::ostream& os, AccountID const& x)
|
||||
{
|
||||
os << to_string (x);
|
||||
return os;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Caches the base58 representations of AccountIDs
|
||||
|
||||
This operation occurs with sufficient frequency to
|
||||
justify having a cache. In the future, rippled should
|
||||
require clients to receive "binary" results, where
|
||||
AccountIDs are hex-encoded.
|
||||
*/
|
||||
class AccountIDCache
|
||||
{
|
||||
private:
|
||||
std::mutex mutable mutex_;
|
||||
std::size_t capacity_;
|
||||
hash_map<AccountID,
|
||||
std::string> mutable m0_;
|
||||
hash_map<AccountID,
|
||||
std::string> mutable m1_;
|
||||
|
||||
public:
|
||||
AccountIDCache(AccountIDCache const&) = delete;
|
||||
AccountIDCache& operator= (AccountIDCache const&) = delete;
|
||||
|
||||
explicit
|
||||
AccountIDCache (std::size_t capacity);
|
||||
|
||||
/** Return ripple::toBase58 for the AccountID
|
||||
|
||||
Thread Safety:
|
||||
Safe to call from any thread concurrently
|
||||
|
||||
@note This function intentionally returns a
|
||||
copy for correctness.
|
||||
*/
|
||||
std::string
|
||||
toBase58 (AccountID const&) const;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace std {
|
||||
|
||||
// DEPRECATED
|
||||
// VFALCO Use beast::uhash or a hardened container
|
||||
template <>
|
||||
struct hash <ripple::AccountID> : ripple::AccountID::hasher
|
||||
{
|
||||
};
|
||||
|
||||
} // std
|
||||
|
||||
#endif
|
||||
@@ -53,9 +53,6 @@ getLedgerFeeIndex ();
|
||||
uint256
|
||||
getAccountRootIndex (AccountID const& account);
|
||||
|
||||
uint256
|
||||
getAccountRootIndex (const RippleAddress & account);
|
||||
|
||||
uint256
|
||||
getGeneratorIndex (AccountID const& uGeneratorID);
|
||||
|
||||
@@ -110,9 +107,6 @@ namespace keylet {
|
||||
struct account_t
|
||||
{
|
||||
Keylet operator()(AccountID const& id) const;
|
||||
|
||||
// DEPRECATED
|
||||
Keylet operator()(RippleAddress const& ra) const;
|
||||
};
|
||||
static account_t const account {};
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ JSS ( ClearFlag ); // field.
|
||||
JSS ( Destination ); // in: TransactionSign; field.
|
||||
JSS ( Fee ); // in/out: TransactionSign; field.
|
||||
JSS ( Flags ); // in/out: TransactionSign; field.
|
||||
JSS ( Invalid ); // out: app/misc/AccountState
|
||||
JSS ( Invalid ); //
|
||||
JSS ( LimitAmount ); // field.
|
||||
JSS ( OfferSequence ); // field.
|
||||
JSS ( Paths ); // in/out: TransactionSign
|
||||
@@ -371,7 +371,7 @@ JSS ( uptime ); // out: GetCounts
|
||||
JSS ( url ); // in/out: Subscribe, Unsubscribe
|
||||
JSS ( url_password ); // in: Subscribe
|
||||
JSS ( url_username ); // in: Subscribe
|
||||
JSS ( urlgravatar ); // out: AccountState
|
||||
JSS ( urlgravatar ); //
|
||||
JSS ( username ); // in: Subscribe
|
||||
JSS ( validated ); // out: NetworkOPs, LookupLedger, AccountTx*
|
||||
// Tx
|
||||
|
||||
@@ -26,24 +26,13 @@
|
||||
#include <ripple/crypto/KeyType.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/protocol/RipplePublicKey.h>
|
||||
#include <ripple/protocol/tokens.h>
|
||||
#include <ripple/protocol/UInt160.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <beast/utility/noexcept.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
enum VersionEncoding
|
||||
{
|
||||
VER_NONE = 1,
|
||||
VER_NODE_PUBLIC = 28,
|
||||
VER_NODE_PRIVATE = 32,
|
||||
VER_ACCOUNT_ID = 0,
|
||||
VER_ACCOUNT_PUBLIC = 35,
|
||||
VER_ACCOUNT_PRIVATE = 34,
|
||||
VER_FAMILY_GENERATOR = 41,
|
||||
VER_FAMILY_SEED = 33,
|
||||
};
|
||||
|
||||
//
|
||||
// Used to hold addresses and parse and produce human formats.
|
||||
//
|
||||
@@ -78,10 +67,8 @@ public:
|
||||
void clear ();
|
||||
bool isSet () const;
|
||||
|
||||
static void clearCache ();
|
||||
|
||||
/** Returns the public key.
|
||||
Precondition: version == VER_NODE_PUBLIC
|
||||
Precondition: version == TOKEN_NODE_PUBLIC
|
||||
*/
|
||||
RipplePublicKey
|
||||
toPublicKey() const;
|
||||
@@ -120,20 +107,6 @@ public:
|
||||
|
||||
static RippleAddress createNodePrivate (RippleAddress const& naSeed);
|
||||
|
||||
//
|
||||
// Accounts IDs
|
||||
//
|
||||
AccountID getAccountID () const;
|
||||
|
||||
std::string humanAccountID () const;
|
||||
|
||||
bool setAccountID (
|
||||
std::string const& strAccountID,
|
||||
Base58::Alphabet const& alphabet = Base58::getRippleAlphabet());
|
||||
void setAccountID (AccountID const& hash160In);
|
||||
|
||||
static RippleAddress createAccountID (AccountID const& uiAccountID);
|
||||
|
||||
//
|
||||
// Accounts Public
|
||||
//
|
||||
@@ -300,6 +273,10 @@ RippleAddress getSeedFromRPC (Json::Value const& params);
|
||||
|
||||
KeyPair generateKeysFromSeed (KeyType keyType, RippleAddress const& seed);
|
||||
|
||||
// DEPRECATED
|
||||
AccountID
|
||||
calcAccountID (RippleAddress const& publicKey);
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -65,9 +65,6 @@ public:
|
||||
}
|
||||
std::string getText () const override;
|
||||
|
||||
RippleAddress getValueNCA () const;
|
||||
void setValueNCA (RippleAddress const& nca);
|
||||
|
||||
template <typename Tag>
|
||||
void setValueH160 (base_uint<160, Tag> const& v)
|
||||
{
|
||||
@@ -75,6 +72,10 @@ public:
|
||||
assert (peekValue ().size () == (160 / 8));
|
||||
}
|
||||
|
||||
// VFALCO This is a clumsy interface, it should return
|
||||
// the value. And it should not be possible to
|
||||
// have anything other than a uint160 in here.
|
||||
// The base_uint tag should always be `AccountIDTag`.
|
||||
template <typename Tag>
|
||||
bool getValueH160 (base_uint<160, Tag>& v) const
|
||||
{
|
||||
|
||||
@@ -114,17 +114,7 @@ public:
|
||||
bool isThreadedType() const; // is this a ledger entry that can be threaded
|
||||
|
||||
bool isThreaded () const; // is this ledger entry actually threaded
|
||||
|
||||
bool hasOneOwner () const; // This node has one other node that owns it
|
||||
|
||||
bool hasTwoOwners () const; // This node has two nodes that own it (like ripple balance)
|
||||
|
||||
RippleAddress getOwner () const;
|
||||
|
||||
RippleAddress getFirstOwner () const;
|
||||
|
||||
RippleAddress getSecondOwner () const;
|
||||
|
||||
|
||||
uint256 getThreadedTransaction () const;
|
||||
|
||||
std::uint32_t getThreadedLedger () const;
|
||||
|
||||
@@ -215,13 +215,16 @@ public:
|
||||
// Break the multi-signing hash computation into 2 parts for optimization.
|
||||
Serializer startMultiSigningData () const;
|
||||
void finishMultiSigningData (
|
||||
RippleAddress const& signingForID,
|
||||
RippleAddress const& signingID, Serializer& s) const;
|
||||
AccountID const& signingForID,
|
||||
AccountID const& signingID, Serializer& s) const;
|
||||
|
||||
// VFALCO Get functions are usually simple observers but
|
||||
// this one performs an expensive construction.
|
||||
//
|
||||
// Get data to compute a complete multi-signature.
|
||||
Serializer getMultiSigningData (
|
||||
RippleAddress const& signingForID,
|
||||
RippleAddress const& signingID) const;
|
||||
AccountID const& signingForID,
|
||||
AccountID const& signingID) const;
|
||||
|
||||
const STBase& peekAtIndex (int offset) const
|
||||
{
|
||||
@@ -259,8 +262,7 @@ public:
|
||||
|
||||
uint160 getFieldH160 (SField const& field) const;
|
||||
uint256 getFieldH256 (SField const& field) const;
|
||||
RippleAddress getFieldAccount (SField const& field) const;
|
||||
AccountID getFieldAccount160 (SField const& field) const;
|
||||
AccountID getAccountID (SField const& field) const;
|
||||
|
||||
Blob getFieldVL (SField const& field) const;
|
||||
STAmount const& getFieldAmount (SField const& field) const;
|
||||
@@ -282,11 +284,9 @@ public:
|
||||
void setFieldH128 (SField const& field, uint128 const&);
|
||||
void setFieldH256 (SField const& field, uint256 const& );
|
||||
void setFieldVL (SField const& field, Blob const&);
|
||||
void setFieldAccount (SField const& field, AccountID const&);
|
||||
void setFieldAccount (SField const& field, RippleAddress const& addr)
|
||||
{
|
||||
setFieldAccount (field, addr.getAccountID ());
|
||||
}
|
||||
|
||||
void setAccountID (SField const& field, AccountID const&);
|
||||
|
||||
void setFieldAmount (SField const& field, STAmount const&);
|
||||
void setFieldPathSet (SField const& field, STPathSet const&);
|
||||
void setFieldV256 (SField const& field, STVector256 const& v);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <ripple/protocol/STObject.h>
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
|
||||
namespace ripple {
|
||||
@@ -94,16 +95,11 @@ public:
|
||||
setFieldAmount (sfFee, fee);
|
||||
}
|
||||
|
||||
RippleAddress getSourceAccount () const
|
||||
{
|
||||
return getFieldAccount (sfAccount);
|
||||
}
|
||||
Blob getSigningPubKey () const
|
||||
{
|
||||
return getFieldVL (sfSigningPubKey);
|
||||
}
|
||||
void setSigningPubKey (const RippleAddress & naSignPubKey);
|
||||
void setSourceAccount (const RippleAddress & naSource);
|
||||
|
||||
std::uint32_t getSequence () const
|
||||
{
|
||||
@@ -114,7 +110,8 @@ public:
|
||||
return setFieldU32 (sfSequence, seq);
|
||||
}
|
||||
|
||||
std::vector<RippleAddress> getMentionedAccounts () const;
|
||||
boost::container::flat_set<AccountID>
|
||||
getMentionedAccounts() const;
|
||||
|
||||
uint256 getTransactionID () const;
|
||||
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/protocol/AccountID.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
class AccountIDTag {};
|
||||
class CurrencyTag {};
|
||||
class DirectoryTag {};
|
||||
class NodeIDTag {};
|
||||
@@ -37,33 +37,20 @@ class NodeIDTag {};
|
||||
The last 64 bits of this are the quality. */
|
||||
using Directory = base_uint<256, detail::DirectoryTag>;
|
||||
|
||||
/** AccountID is a hash representing a specific account. */
|
||||
using AccountID = base_uint<160, detail::AccountIDTag>;
|
||||
|
||||
/** Currency is a hash representing a specific currency. */
|
||||
using Currency = base_uint<160, detail::CurrencyTag>;
|
||||
|
||||
/** NodeID is a 160-bit hash representing one node. */
|
||||
using NodeID = base_uint<160, detail::NodeIDTag>;
|
||||
|
||||
using CurrencySet = hash_set<Currency>;
|
||||
|
||||
/** A special account that's used as the "issuer" for XRP. */
|
||||
AccountID const& xrpAccount();
|
||||
|
||||
/** XRP currency. */
|
||||
Currency const& xrpCurrency();
|
||||
|
||||
/** A placeholder for empty accounts. */
|
||||
AccountID const& noAccount();
|
||||
|
||||
/** A placeholder for empty currencies. */
|
||||
Currency const& noCurrency();
|
||||
|
||||
/** We deliberately disallow the currency that looks like "XRP" because too
|
||||
many people were using it instead of the correct XRP currency. */
|
||||
|
||||
|
||||
Currency const& badCurrency();
|
||||
|
||||
inline bool isXRP(Currency const& c)
|
||||
@@ -71,14 +58,6 @@ inline bool isXRP(Currency const& c)
|
||||
return c == zero;
|
||||
}
|
||||
|
||||
inline bool isXRP(AccountID const& c)
|
||||
{
|
||||
return c == zero;
|
||||
}
|
||||
|
||||
/** Returns a human-readable form of the account. */
|
||||
std::string to_string(AccountID const&);
|
||||
|
||||
/** Returns "", "XRP", or three letter ISO code. */
|
||||
std::string to_string(Currency const& c);
|
||||
|
||||
@@ -88,16 +67,6 @@ bool to_currency(Currency&, std::string const&);
|
||||
/** Tries to convert a string to a Currency, returns noCurrency() on failure. */
|
||||
Currency to_currency(std::string const&);
|
||||
|
||||
/** Tries to convert a string to an AccountID representing an issuer, returns true
|
||||
* on success. */
|
||||
bool to_issuer(AccountID&, std::string const&);
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, AccountID const& x)
|
||||
{
|
||||
os << to_string (x);
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, Currency const& x)
|
||||
{
|
||||
os << to_string (x);
|
||||
@@ -108,11 +77,6 @@ inline std::ostream& operator<< (std::ostream& os, Currency const& x)
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash <ripple::AccountID> : ripple::AccountID::hasher
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash <ripple::Currency> : ripple::Currency::hasher
|
||||
{
|
||||
|
||||
239
src/ripple/protocol/impl/AccountID.cpp
Normal file
239
src/ripple/protocol/impl/AccountID.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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 <BeastConfig.h>
|
||||
#include <ripple/protocol/AccountID.h>
|
||||
#include <ripple/protocol/AnyPublicKey.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/tokens.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string
|
||||
toBase58 (AccountID const& v)
|
||||
{
|
||||
return base58EncodeToken(
|
||||
TOKEN_ACCOUNT_ID,
|
||||
v.data(), v.size());
|
||||
}
|
||||
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseBase58 (std::string const& s)
|
||||
{
|
||||
auto const result =
|
||||
decodeBase58Token(
|
||||
s, TOKEN_ACCOUNT_ID);
|
||||
if (result.empty())
|
||||
return boost::none;
|
||||
AccountID id;
|
||||
if (result.size() != id.size())
|
||||
return boost::none;
|
||||
std::memcpy(id.data(),
|
||||
result.data(), result.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
boost::optional<AccountID>
|
||||
deprecatedParseBitcoinAccountID (std::string const& s)
|
||||
{
|
||||
auto const result =
|
||||
decodeBase58TokenBitcoin(
|
||||
s, TOKEN_ACCOUNT_ID);
|
||||
if (result.empty())
|
||||
return boost::none;
|
||||
AccountID id;
|
||||
if (result.size() != id.size())
|
||||
return boost::none;
|
||||
std::memcpy(id.data(),
|
||||
result.data(), result.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
bool
|
||||
deprecatedParseBase58 (AccountID& account,
|
||||
Json::Value const& jv)
|
||||
{
|
||||
if (! jv.isString())
|
||||
return false;
|
||||
auto const result =
|
||||
parseBase58<AccountID>(jv.asString());
|
||||
if (! result)
|
||||
return false;
|
||||
account = *result;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseHex (std::string const& s)
|
||||
{
|
||||
if (s.size() != 40)
|
||||
return boost::none;
|
||||
AccountID id;
|
||||
if (! id.SetHex(s, true))
|
||||
return boost::none;
|
||||
return id;
|
||||
}
|
||||
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseHexOrBase58 (std::string const& s)
|
||||
{
|
||||
auto result =
|
||||
parseHex<AccountID>(s);
|
||||
if (! result)
|
||||
result = parseBase58<AccountID>(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Calculation of the Account ID
|
||||
|
||||
The AccountID is a 160-bit identifier that uniquely
|
||||
distinguishes an account. The account may or may not
|
||||
exist in the ledger. Even for accounts that are not in
|
||||
the ledger, cryptographic operations may be performed
|
||||
which affect the ledger. For example, designating an
|
||||
account not in the ledger as a regular key for an
|
||||
account that is in the ledger.
|
||||
|
||||
Why did we use half of SHA512 for most things but then
|
||||
SHA256 followed by RIPEMD160 for account IDs? Why didn't
|
||||
we do SHA512 half then RIPEMD160? Or even SHA512 then RIPEMD160?
|
||||
For that matter why RIPEMD160 at all why not just SHA512 and keep
|
||||
only 160 bits?
|
||||
|
||||
Answer (David Schwartz):
|
||||
|
||||
The short answer is that we kept Bitcoin's behavior.
|
||||
The longer answer was that:
|
||||
1) Using a single hash could leave ripple
|
||||
vulnerable to length extension attacks.
|
||||
2) Only RIPEMD160 is generally considered safe at 160 bits.
|
||||
|
||||
Any of those schemes would have been acceptable. However,
|
||||
the one chosen avoids any need to defend the scheme chosen.
|
||||
(Against any criticism other than unnecessary complexity.)
|
||||
|
||||
"The historical reason was that in the very early days,
|
||||
we wanted to give people as few ways to argue that we were
|
||||
less secure than Bitcoin. So where there was no good reason
|
||||
to change something, it was not changed."
|
||||
*/
|
||||
|
||||
AccountID
|
||||
calcAccountID (AnyPublicKey const& pk)
|
||||
{
|
||||
ripesha_hasher rsh;
|
||||
rsh(pk.data(), pk.size());
|
||||
auto const d = static_cast<
|
||||
ripesha_hasher::result_type>(rsh);
|
||||
AccountID id;
|
||||
static_assert(sizeof(d) == sizeof(id), "");
|
||||
std::memcpy(id.data(), d.data(), d.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
xrpAccount()
|
||||
{
|
||||
static AccountID const account(0);
|
||||
return account;
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
noAccount()
|
||||
{
|
||||
static AccountID const account(1);
|
||||
return account;
|
||||
}
|
||||
|
||||
bool
|
||||
to_issuer (AccountID& issuer, std::string const& s)
|
||||
{
|
||||
if (s.size () == (160 / 4))
|
||||
{
|
||||
issuer.SetHex (s);
|
||||
return true;
|
||||
}
|
||||
auto const account =
|
||||
parseBase58<AccountID>(s);
|
||||
if (! account)
|
||||
return false;
|
||||
issuer = *account;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* VFALCO NOTE
|
||||
An alternate implementation could use a pair of insert-only
|
||||
hash maps that each use a single large memory allocation
|
||||
to store a fixed size hash table and all of the AccountID/string
|
||||
pairs laid out in memory (wouldn't use std::string here just a
|
||||
length prefixed or zero terminated array). Possibly using
|
||||
boost::intrusive as the basis for the unordered container.
|
||||
This would cut down to one allocate/free cycle per swap of
|
||||
the map.
|
||||
*/
|
||||
|
||||
AccountIDCache::AccountIDCache(
|
||||
std::size_t capacity)
|
||||
: capacity_(capacity)
|
||||
{
|
||||
m1_.reserve(capacity_);
|
||||
}
|
||||
|
||||
std::string
|
||||
AccountIDCache::toBase58(
|
||||
AccountID const& id) const
|
||||
{
|
||||
std::lock_guard<
|
||||
std::mutex> lock(mutex_);
|
||||
auto iter = m1_.find(id);
|
||||
if (iter != m1_.end())
|
||||
return iter->second;
|
||||
iter = m0_.find(id);
|
||||
std::string result;
|
||||
if (iter != m0_.end())
|
||||
{
|
||||
result = iter->second;
|
||||
// Can use insert-only hash maps if
|
||||
// we didn't erase from here.
|
||||
m0_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
result =
|
||||
ripple::toBase58(id);
|
||||
}
|
||||
if (m1_.size() >= capacity_)
|
||||
{
|
||||
m0_ = std::move(m1_);
|
||||
m1_.clear();
|
||||
m1_.reserve(capacity_);
|
||||
}
|
||||
m1_.emplace(id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -95,7 +95,7 @@ toString (AnyPublicKey const& pk)
|
||||
{
|
||||
Blob buffer;
|
||||
buffer.reserve (1 + pk.size ());
|
||||
buffer.push_back (VER_NODE_PUBLIC);
|
||||
buffer.push_back (TOKEN_NODE_PUBLIC);
|
||||
auto const data = pk.data ();
|
||||
buffer.insert (buffer.end (), data, data + pk.size ());
|
||||
return Base58::encodeWithCheck (buffer);
|
||||
|
||||
@@ -64,12 +64,6 @@ getAccountRootIndex (AccountID const& account)
|
||||
account);
|
||||
}
|
||||
|
||||
uint256
|
||||
getAccountRootIndex (const RippleAddress & account)
|
||||
{
|
||||
return getAccountRootIndex (account.getAccountID ());
|
||||
}
|
||||
|
||||
uint256
|
||||
getGeneratorIndex (AccountID const& uGeneratorID)
|
||||
{
|
||||
@@ -203,13 +197,6 @@ Keylet account_t::operator()(
|
||||
getAccountRootIndex(id) };
|
||||
}
|
||||
|
||||
Keylet account_t::operator()(
|
||||
RippleAddress const& ra) const
|
||||
{
|
||||
return { ltACCOUNT_ROOT,
|
||||
getAccountRootIndex(ra.getAccountID()) };
|
||||
}
|
||||
|
||||
Keylet child (uint256 const& key)
|
||||
{
|
||||
return { ltCHILD, key };
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include <ripple/crypto/GenerateDeterministicKey.h>
|
||||
#include <ripple/crypto/RandomNumbers.h>
|
||||
#include <ripple/crypto/RFC1751.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <ripple/protocol/RippleAddress.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/RipplePublicKey.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <ed25519-donna/ed25519.h>
|
||||
#include <openssl/ripemd.h>
|
||||
@@ -83,19 +85,19 @@ bool verifySignature (Blob const& pubkey, uint256 const& hash, Blob const& sig,
|
||||
RippleAddress::RippleAddress ()
|
||||
: mIsValid (false)
|
||||
{
|
||||
nVersion = VER_NONE;
|
||||
nVersion = TOKEN_NONE;
|
||||
}
|
||||
|
||||
void RippleAddress::clear ()
|
||||
{
|
||||
nVersion = VER_NONE;
|
||||
nVersion = TOKEN_NONE;
|
||||
vchData.clear ();
|
||||
mIsValid = false;
|
||||
}
|
||||
|
||||
bool RippleAddress::isSet () const
|
||||
{
|
||||
return nVersion != VER_NONE;
|
||||
return nVersion != TOKEN_NONE;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -145,7 +147,7 @@ RippleAddress RippleAddress::createNodePublic (std::string const& strPublic)
|
||||
RipplePublicKey
|
||||
RippleAddress::toPublicKey() const
|
||||
{
|
||||
assert (nVersion == VER_NODE_PUBLIC);
|
||||
assert (nVersion == TOKEN_NODE_PUBLIC);
|
||||
return RipplePublicKey (vchData.begin(), vchData.end());
|
||||
}
|
||||
|
||||
@@ -159,10 +161,10 @@ NodeID RippleAddress::getNodeID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getNodeID");
|
||||
|
||||
case VER_NODE_PUBLIC: {
|
||||
case TOKEN_NODE_PUBLIC: {
|
||||
// Note, we are encoding the left.
|
||||
NodeID node;
|
||||
node.copyFrom(Hash160 (vchData));
|
||||
@@ -178,10 +180,10 @@ Blob const& RippleAddress::getNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getNodePublic");
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
case TOKEN_NODE_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
@@ -193,10 +195,10 @@ std::string RippleAddress::humanNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanNodePublic");
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
case TOKEN_NODE_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -207,7 +209,7 @@ std::string RippleAddress::humanNodePublic () const
|
||||
bool RippleAddress::setNodePublic (std::string const& strPublic)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPublic, VER_NODE_PUBLIC, Base58::getRippleAlphabet ());
|
||||
strPublic, TOKEN_NODE_PUBLIC, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -216,7 +218,7 @@ void RippleAddress::setNodePublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PUBLIC, vPublic);
|
||||
SetData (TOKEN_NODE_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
bool RippleAddress::verifyNodePublic (
|
||||
@@ -250,10 +252,10 @@ Blob const& RippleAddress::getNodePrivateData () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getNodePrivateData");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
@@ -265,10 +267,10 @@ uint256 RippleAddress::getNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source = getNodePrivate");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return uint256 (vchData);
|
||||
|
||||
default:
|
||||
@@ -280,10 +282,10 @@ std::string RippleAddress::humanNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanNodePrivate");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -294,7 +296,7 @@ std::string RippleAddress::humanNodePrivate () const
|
||||
bool RippleAddress::setNodePrivate (std::string const& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPrivate, VER_NODE_PRIVATE, Base58::getRippleAlphabet ());
|
||||
strPrivate, TOKEN_NODE_PRIVATE, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -303,14 +305,14 @@ void RippleAddress::setNodePrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PRIVATE, vPrivate);
|
||||
SetData (TOKEN_NODE_PRIVATE, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PRIVATE, hash256);
|
||||
SetData (TOKEN_NODE_PRIVATE, hash256);
|
||||
}
|
||||
|
||||
void RippleAddress::signNodePrivate (uint256 const& hash, Blob& vchSig) const
|
||||
@@ -321,131 +323,6 @@ void RippleAddress::signNodePrivate (uint256 const& hash, Blob& vchSig) const
|
||||
throw std::runtime_error ("Signing failed.");
|
||||
}
|
||||
|
||||
//
|
||||
// AccountID
|
||||
//
|
||||
|
||||
AccountID RippleAddress::getAccountID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountID");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
return AccountID(vchData);
|
||||
|
||||
case VER_ACCOUNT_PUBLIC: {
|
||||
// Note, we are encoding the left.
|
||||
// TODO(tom): decipher this comment.
|
||||
AccountID account;
|
||||
account.copyFrom (Hash160 (vchData));
|
||||
return account;
|
||||
}
|
||||
|
||||
default:
|
||||
throw badSourceError (nVersion);
|
||||
}
|
||||
}
|
||||
|
||||
using StaticLockType = std::mutex;
|
||||
using StaticScopedLockType = std::lock_guard <StaticLockType>;
|
||||
|
||||
static StaticLockType s_lock;
|
||||
static hash_map <Blob, std::string> rncMapOld, rncMapNew;
|
||||
|
||||
void RippleAddress::clearCache ()
|
||||
{
|
||||
StaticScopedLockType sl (s_lock);
|
||||
|
||||
rncMapOld.clear ();
|
||||
rncMapNew.clear ();
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanAccountID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanAccountID");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
{
|
||||
StaticScopedLockType sl (s_lock);
|
||||
|
||||
auto it = rncMapNew.find (vchData);
|
||||
|
||||
if (it != rncMapNew.end ())
|
||||
{
|
||||
// Found in new map, nothing to do
|
||||
ret = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = rncMapOld.find (vchData);
|
||||
|
||||
if (it != rncMapOld.end ())
|
||||
{
|
||||
ret = it->second;
|
||||
rncMapOld.erase (it);
|
||||
}
|
||||
else
|
||||
ret = ToString ();
|
||||
|
||||
if (rncMapNew.size () >= 128000)
|
||||
{
|
||||
rncMapOld = std::move (rncMapNew);
|
||||
rncMapNew.clear ();
|
||||
rncMapNew.reserve (128000);
|
||||
}
|
||||
|
||||
rncMapNew[vchData] = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
{
|
||||
RippleAddress accountID;
|
||||
|
||||
(void) accountID.setAccountID (getAccountID ());
|
||||
|
||||
return accountID.ToString ();
|
||||
}
|
||||
|
||||
default:
|
||||
throw badSourceError (nVersion);
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setAccountID (
|
||||
std::string const& strAccountID, Base58::Alphabet const& alphabet)
|
||||
{
|
||||
if (strAccountID.empty ())
|
||||
{
|
||||
setAccountID (AccountID ());
|
||||
|
||||
mIsValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsValid = SetString (strAccountID, VER_ACCOUNT_ID, alphabet);
|
||||
}
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountID (AccountID const& hash160)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_ACCOUNT_ID, hash160);
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPublic
|
||||
//
|
||||
@@ -464,14 +341,14 @@ Blob const& RippleAddress::getAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountPublic");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
case TOKEN_ACCOUNT_ID:
|
||||
throw std::runtime_error ("public not available from account id");
|
||||
break;
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
case TOKEN_ACCOUNT_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
@@ -483,13 +360,13 @@ std::string RippleAddress::humanAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanAccountPublic");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
case TOKEN_ACCOUNT_ID:
|
||||
throw std::runtime_error ("public not available from account id");
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
case TOKEN_ACCOUNT_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -500,7 +377,7 @@ std::string RippleAddress::humanAccountPublic () const
|
||||
bool RippleAddress::setAccountPublic (std::string const& strPublic)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPublic, VER_ACCOUNT_PUBLIC, Base58::getRippleAlphabet ());
|
||||
strPublic, TOKEN_ACCOUNT_PUBLIC, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -509,7 +386,7 @@ void RippleAddress::setAccountPublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_ACCOUNT_PUBLIC, vPublic);
|
||||
SetData (TOKEN_ACCOUNT_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPublic (RippleAddress const& generator, int seq)
|
||||
@@ -541,14 +418,6 @@ bool RippleAddress::accountPublicVerify (
|
||||
fullyCanonical);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createAccountID (AccountID const& account)
|
||||
{
|
||||
RippleAddress na;
|
||||
na.setAccountID (account);
|
||||
|
||||
return na;
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPrivate
|
||||
//
|
||||
@@ -567,10 +436,10 @@ uint256 RippleAddress::getAccountPrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountPrivate");
|
||||
|
||||
case VER_ACCOUNT_PRIVATE:
|
||||
case TOKEN_ACCOUNT_SECRET:
|
||||
return uint256::fromVoid (vchData.data() + (vchData.size() - 32));
|
||||
|
||||
default:
|
||||
@@ -581,7 +450,7 @@ uint256 RippleAddress::getAccountPrivate () const
|
||||
bool RippleAddress::setAccountPrivate (std::string const& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPrivate, VER_ACCOUNT_PRIVATE, Base58::getRippleAlphabet ());
|
||||
strPrivate, TOKEN_ACCOUNT_SECRET, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -589,13 +458,13 @@ bool RippleAddress::setAccountPrivate (std::string const& strPrivate)
|
||||
void RippleAddress::setAccountPrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_ACCOUNT_PRIVATE, vPrivate);
|
||||
SetData (TOKEN_ACCOUNT_SECRET, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_ACCOUNT_PRIVATE, hash256);
|
||||
SetData (TOKEN_ACCOUNT_SECRET, hash256);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (
|
||||
@@ -689,10 +558,10 @@ Blob const& RippleAddress::getGenerator () const
|
||||
// returns the public generator
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getGenerator");
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
case TOKEN_FAMILY_GENERATOR:
|
||||
// Do nothing.
|
||||
return vchData;
|
||||
|
||||
@@ -705,10 +574,10 @@ std::string RippleAddress::humanGenerator () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanGenerator");
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
case TOKEN_FAMILY_GENERATOR:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -719,7 +588,7 @@ std::string RippleAddress::humanGenerator () const
|
||||
void RippleAddress::setGenerator (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_FAMILY_GENERATOR, vPublic);
|
||||
SetData (TOKEN_FAMILY_GENERATOR, vPublic);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createGeneratorPublic (RippleAddress const& naSeed)
|
||||
@@ -737,10 +606,10 @@ uint128 RippleAddress::getSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getSeed");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
case TOKEN_FAMILY_SEED:
|
||||
return uint128 (vchData);
|
||||
|
||||
default:
|
||||
@@ -752,10 +621,10 @@ std::string RippleAddress::humanSeed1751 () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanSeed1751");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
case TOKEN_FAMILY_SEED:
|
||||
{
|
||||
std::string strHuman;
|
||||
std::string strLittle;
|
||||
@@ -780,10 +649,10 @@ std::string RippleAddress::humanSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanSeed");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
case TOKEN_FAMILY_SEED:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -809,7 +678,7 @@ int RippleAddress::setSeed1751 (std::string const& strHuman1751)
|
||||
|
||||
bool RippleAddress::setSeed (std::string const& strSeed)
|
||||
{
|
||||
mIsValid = SetString (strSeed, VER_FAMILY_SEED, Base58::getRippleAlphabet ());
|
||||
mIsValid = SetString (strSeed, TOKEN_FAMILY_SEED, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -820,8 +689,10 @@ bool RippleAddress::setSeedGeneric (std::string const& strText)
|
||||
bool bResult = true;
|
||||
uint128 uSeed;
|
||||
|
||||
if (parseBase58<AccountID>(strText))
|
||||
return false;
|
||||
|
||||
if (strText.empty ()
|
||||
|| naTemp.setAccountID (strText)
|
||||
|| naTemp.setAccountPublic (strText)
|
||||
|| naTemp.setAccountPrivate (strText)
|
||||
|| naTemp.setNodePublic (strText)
|
||||
@@ -853,7 +724,7 @@ void RippleAddress::setSeed (uint128 hash128)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_FAMILY_SEED, hash128);
|
||||
SetData (TOKEN_FAMILY_SEED, hash128);
|
||||
}
|
||||
|
||||
void RippleAddress::setSeedRandom ()
|
||||
@@ -978,4 +849,20 @@ KeyPair generateKeysFromSeed (KeyType type, RippleAddress const& seed)
|
||||
return result;
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
AccountID
|
||||
calcAccountID (RippleAddress const& publicKey)
|
||||
{
|
||||
auto const& pk =
|
||||
publicKey.getAccountPublic();
|
||||
ripesha_hasher rsh;
|
||||
rsh(pk.data(), pk.size());
|
||||
auto const d = static_cast<
|
||||
ripesha_hasher::result_type>(rsh);
|
||||
AccountID id;
|
||||
static_assert(sizeof(d) == sizeof(id), "");
|
||||
std::memcpy(id.data(), d.data(), d.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -31,12 +32,11 @@ std::string STAccount::getText () const
|
||||
{
|
||||
AccountID u;
|
||||
RippleAddress a;
|
||||
|
||||
if (!getValueH160 (u))
|
||||
if (! getValueH160 (u))
|
||||
return STBlob::getText ();
|
||||
|
||||
a.setAccountID (u);
|
||||
return a.humanAccountID ();
|
||||
// VFALCO This should use getApp().accountIDCache()
|
||||
// Maybe pass the cache in?
|
||||
return toBase58(u);
|
||||
}
|
||||
|
||||
STAccount*
|
||||
@@ -55,20 +55,4 @@ bool STAccount::isValueH160 () const
|
||||
return peekValue ().size () == (160 / 8);
|
||||
}
|
||||
|
||||
RippleAddress STAccount::getValueNCA () const
|
||||
{
|
||||
RippleAddress a;
|
||||
AccountID account;
|
||||
|
||||
if (getValueH160 (account))
|
||||
a.setAccountID (account);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void STAccount::setValueNCA (RippleAddress const& nca)
|
||||
{
|
||||
setValueH160 (nca.getAccountID ());
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -123,31 +123,6 @@ bool STLedgerEntry::isThreaded () const
|
||||
return isFieldPresent (sfPreviousTxnID);
|
||||
}
|
||||
|
||||
bool STLedgerEntry::hasOneOwner () const
|
||||
{
|
||||
return (type_ != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1);
|
||||
}
|
||||
|
||||
bool STLedgerEntry::hasTwoOwners () const
|
||||
{
|
||||
return type_ == ltRIPPLE_STATE;
|
||||
}
|
||||
|
||||
RippleAddress STLedgerEntry::getOwner () const
|
||||
{
|
||||
return getFieldAccount (sfAccount);
|
||||
}
|
||||
|
||||
RippleAddress STLedgerEntry::getFirstOwner () const
|
||||
{
|
||||
return RippleAddress::createAccountID (getFieldAmount (sfLowLimit).getIssuer ());
|
||||
}
|
||||
|
||||
RippleAddress STLedgerEntry::getSecondOwner () const
|
||||
{
|
||||
return RippleAddress::createAccountID (getFieldAmount (sfHighLimit).getIssuer ());
|
||||
}
|
||||
|
||||
uint256 STLedgerEntry::getThreadedTransaction () const
|
||||
{
|
||||
return getFieldH256 (sfPreviousTxnID);
|
||||
|
||||
@@ -347,19 +347,21 @@ STObject::startMultiSigningData () const
|
||||
return s;
|
||||
}
|
||||
|
||||
// VFALCO This should not be a member,
|
||||
// and the function shouldn't even exist
|
||||
void
|
||||
STObject::finishMultiSigningData (
|
||||
RippleAddress const& signingForID,
|
||||
RippleAddress const& signingID,
|
||||
AccountID const& signingForID,
|
||||
AccountID const& signingID,
|
||||
Serializer& s) const
|
||||
{
|
||||
s.add160 (signingForID.getAccountID ());
|
||||
s.add160 (signingID.getAccountID ());
|
||||
s.add160 (signingForID);
|
||||
s.add160 (signingID);
|
||||
}
|
||||
|
||||
Serializer
|
||||
STObject::getMultiSigningData (
|
||||
RippleAddress const& signingForID, RippleAddress const& signingID) const
|
||||
AccountID const& signingForID, AccountID const& signingID) const
|
||||
{
|
||||
Serializer s (startMultiSigningData ());
|
||||
finishMultiSigningData (signingForID, signingID, s);
|
||||
@@ -586,26 +588,7 @@ uint256 STObject::getFieldH256 (SField const& field) const
|
||||
return getFieldByValue <STHash256> (field);
|
||||
}
|
||||
|
||||
RippleAddress STObject::getFieldAccount (SField const& field) const
|
||||
{
|
||||
const STBase* rf = peekAtPField (field);
|
||||
|
||||
if (!rf)
|
||||
throw std::runtime_error ("Field not found");
|
||||
|
||||
SerializedTypeID id = rf->getSType ();
|
||||
|
||||
if (id == STI_NOTPRESENT) return RippleAddress ();
|
||||
|
||||
const STAccount* cf = dynamic_cast<const STAccount*> (rf);
|
||||
|
||||
if (!cf)
|
||||
throw std::runtime_error ("Wrong field type");
|
||||
|
||||
return cf->getValueNCA ();
|
||||
}
|
||||
|
||||
AccountID STObject::getFieldAccount160 (SField const& field) const
|
||||
AccountID STObject::getAccountID (SField const& field) const
|
||||
{
|
||||
auto rf = peekAtPField (field);
|
||||
if (!rf)
|
||||
@@ -715,7 +698,7 @@ void STObject::setFieldV256 (SField const& field, STVector256 const& v)
|
||||
setFieldUsingSetValue <STVector256> (field, v);
|
||||
}
|
||||
|
||||
void STObject::setFieldAccount (SField const& field, AccountID const& v)
|
||||
void STObject::setAccountID (SField const& field, AccountID const& v)
|
||||
{
|
||||
STBase* rf = getPField (field, true);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <ripple/protocol/STParsedJSON.h>
|
||||
#include <ripple/protocol/STPathSet.h>
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <ripple/protocol/impl/STVar.h>
|
||||
#include <beast/module/core/text/LexicalCast.h>
|
||||
#include <cassert>
|
||||
@@ -544,13 +545,14 @@ static boost::optional<detail::STVar> parseLeaf (
|
||||
// set it, otherwise, we assume it's an AccountID
|
||||
if (!uAccount.SetHexExact (account.asString ()))
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountID (account.asString ()))
|
||||
auto const a = parseBase58<AccountID>(
|
||||
account.asString());
|
||||
if (! a)
|
||||
{
|
||||
error = invalid_data (element_name, "account");
|
||||
return ret;
|
||||
}
|
||||
uAccount = a.getAccountID ();
|
||||
uAccount = *a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,13 +588,14 @@ static boost::optional<detail::STVar> parseLeaf (
|
||||
|
||||
if (!uIssuer.SetHexExact (issuer.asString ()))
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountID (issuer.asString ()))
|
||||
auto const a = parseBase58<AccountID>(
|
||||
issuer.asString());
|
||||
if (! a)
|
||||
{
|
||||
error = invalid_data (element_name, "issuer");
|
||||
return ret;
|
||||
}
|
||||
uIssuer = a.getAccountID ();
|
||||
uIssuer = *a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,18 +626,17 @@ static boost::optional<detail::STVar> parseLeaf (
|
||||
|
||||
try
|
||||
{
|
||||
AccountID account;
|
||||
if (!account.SetHexExact (strValue))
|
||||
// VFALCO This needs careful auditing
|
||||
auto const account =
|
||||
parseHexOrBase58<AccountID>(
|
||||
strValue);
|
||||
if (! account)
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountID (strValue))
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
account.copyFrom (a.getAccountID ());
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
ret = detail::make_stvar <STAccount> (field, account);
|
||||
ret = detail::make_stvar <STAccount>(
|
||||
field, *account);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/STArray.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
@@ -120,36 +121,29 @@ STTx::getFullText () const
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<RippleAddress>
|
||||
boost::container::flat_set<AccountID>
|
||||
STTx::getMentionedAccounts () const
|
||||
{
|
||||
std::vector<RippleAddress> accounts;
|
||||
boost::container::flat_set<AccountID> list;
|
||||
|
||||
for (auto const& it : *this)
|
||||
{
|
||||
if (auto sa = dynamic_cast<STAccount const*> (&it))
|
||||
{
|
||||
auto const na = sa->getValueNCA ();
|
||||
|
||||
if (std::find (accounts.cbegin (), accounts.cend (), na) == accounts.cend ())
|
||||
accounts.push_back (na);
|
||||
AccountID id;
|
||||
assert(sa->isValueH160());
|
||||
if (sa->getValueH160(id))
|
||||
list.insert(id);
|
||||
}
|
||||
else if (auto sa = dynamic_cast<STAmount const*> (&it))
|
||||
{
|
||||
auto const& issuer = sa->getIssuer ();
|
||||
|
||||
if (isXRP (issuer))
|
||||
continue;
|
||||
|
||||
RippleAddress na;
|
||||
na.setAccountID (issuer);
|
||||
|
||||
if (std::find (accounts.cbegin (), accounts.cend (), na) == accounts.cend ())
|
||||
accounts.push_back (na);
|
||||
if (! isXRP (issuer))
|
||||
list.insert(issuer);
|
||||
}
|
||||
}
|
||||
|
||||
return accounts;
|
||||
return list;
|
||||
}
|
||||
|
||||
static Blob getSigningData (STTx const& that)
|
||||
@@ -226,11 +220,6 @@ void STTx::setSigningPubKey (RippleAddress const& naSignPubKey)
|
||||
setFieldVL (sfSigningPubKey, naSignPubKey.getAccountPublic ());
|
||||
}
|
||||
|
||||
void STTx::setSourceAccount (RippleAddress const& naSource)
|
||||
{
|
||||
setFieldAccount (sfAccount, naSource);
|
||||
}
|
||||
|
||||
Json::Value STTx::getJson (int) const
|
||||
{
|
||||
Json::Value ret = STObject::getJson (0);
|
||||
@@ -269,6 +258,7 @@ std::string STTx::getMetaSQL (std::uint32_t inLedger,
|
||||
return getMetaSQL (s, inLedger, TXN_SQL_VALIDATED, escapedMetaData);
|
||||
}
|
||||
|
||||
// VFALCO This could be a free function elsewhere
|
||||
std::string
|
||||
STTx::getMetaSQL (Serializer rawTxn,
|
||||
std::uint32_t inLedger, char status, std::string const& escapedMetaData) const
|
||||
@@ -281,7 +271,7 @@ STTx::getMetaSQL (Serializer rawTxn,
|
||||
|
||||
return str (boost::format (bfTrans)
|
||||
% to_string (getTransactionID ()) % format->getName ()
|
||||
% getSourceAccount ().humanAccountID ()
|
||||
% toBase58(getAccountID(sfAccount))
|
||||
% getSequence () % inLedger % status % rTxn % escapedMetaData);
|
||||
}
|
||||
|
||||
@@ -338,7 +328,7 @@ STTx::checkMultiSign () const
|
||||
Serializer const dataStart (startMultiSigningData ());
|
||||
|
||||
// We also use the sfAccount field inside the loop. Get it once.
|
||||
RippleAddress const txnAccountID = getFieldAccount (sfAccount);
|
||||
auto const txnAccountID = getAccountID (sfAccount);
|
||||
|
||||
// Determine whether signatures must be full canonical.
|
||||
ECDSA const fullyCanonical = (getFlags() & tfFullyCanonicalSig)
|
||||
@@ -398,17 +388,16 @@ STTx::checkMultiSign () const
|
||||
*/
|
||||
|
||||
// We use this std::set to detect this form of double-signing.
|
||||
std::set<RippleAddress> firstLevelSigners;
|
||||
std::set<AccountID> firstLevelSigners;
|
||||
|
||||
// SigningFors must be in sorted order by AccountID.
|
||||
RippleAddress lastSigningForID;
|
||||
lastSigningForID.setAccountID ("");
|
||||
AccountID lastSigningForID = zero;
|
||||
|
||||
// Every signature must verify or we reject the transaction.
|
||||
for (auto const& signingFor : multiSigners)
|
||||
{
|
||||
RippleAddress const signingForID =
|
||||
signingFor.getFieldAccount (sfAccount);
|
||||
auto const signingForID =
|
||||
signingFor.getAccountID (sfAccount);
|
||||
|
||||
// SigningFors must be in order by account ID. No duplicates allowed.
|
||||
if (lastSigningForID >= signingForID)
|
||||
@@ -440,13 +429,12 @@ STTx::checkMultiSign () const
|
||||
}
|
||||
|
||||
// SingingAccounts must be in sorted order by AccountID.
|
||||
RippleAddress lastSigningAcctID;
|
||||
lastSigningAcctID.setAccountID ("");
|
||||
AccountID lastSigningAcctID = zero;
|
||||
|
||||
for (auto const& signingAcct : signingAccounts)
|
||||
{
|
||||
RippleAddress const signingAcctID =
|
||||
signingAcct.getFieldAccount (sfAccount);
|
||||
auto const signingAcctID =
|
||||
signingAcct.getAccountID (sfAccount);
|
||||
|
||||
// None of the multi-signers may sign for themselves.
|
||||
if (signingForID == signingAcctID)
|
||||
|
||||
@@ -22,15 +22,11 @@
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <ripple/protocol/RippleAddress.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <beast/utility/static_initializer.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string to_string(AccountID const& account)
|
||||
{
|
||||
return RippleAddress::createAccountID (account).humanAccountID ();
|
||||
}
|
||||
|
||||
std::string to_string(Currency const& currency)
|
||||
{
|
||||
// Characters we are willing to allow in the ASCII representation of a
|
||||
@@ -111,38 +107,12 @@ Currency to_currency(std::string const& code)
|
||||
return currency;
|
||||
}
|
||||
|
||||
bool to_issuer(AccountID& issuer, std::string const& s)
|
||||
{
|
||||
if (s.size () == (160 / 4))
|
||||
{
|
||||
issuer.SetHex (s);
|
||||
return true;
|
||||
}
|
||||
RippleAddress address;
|
||||
bool success = address.setAccountID (s);
|
||||
if (success)
|
||||
issuer = address.getAccountID ();
|
||||
return success;
|
||||
}
|
||||
|
||||
AccountID const& xrpAccount()
|
||||
{
|
||||
static AccountID const account(0);
|
||||
return account;
|
||||
}
|
||||
|
||||
Currency const& xrpCurrency()
|
||||
{
|
||||
static Currency const currency(0);
|
||||
return currency;
|
||||
}
|
||||
|
||||
AccountID const& noAccount()
|
||||
{
|
||||
static AccountID const account(1);
|
||||
return account;
|
||||
}
|
||||
|
||||
Currency const& noCurrency()
|
||||
{
|
||||
static Currency const currency(1);
|
||||
|
||||
@@ -25,12 +25,11 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_ripemd160_hasher::ctx_)) ==
|
||||
sizeof(RIPEMD160_CTX), "");
|
||||
|
||||
openssl_ripemd160_hasher::openssl_ripemd160_hasher()
|
||||
{
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_ripemd160_hasher::ctx_)) ==
|
||||
sizeof(RIPEMD160_CTX), "");
|
||||
auto const ctx = reinterpret_cast<
|
||||
RIPEMD160_CTX*>(ctx_);
|
||||
RIPEMD160_Init(ctx);
|
||||
@@ -54,12 +53,11 @@ openssl_ripemd160_hasher::operator result_type() noexcept
|
||||
return digest;
|
||||
}
|
||||
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_sha256_hasher::ctx_)) ==
|
||||
sizeof(SHA256_CTX), "");
|
||||
|
||||
openssl_sha256_hasher::openssl_sha256_hasher()
|
||||
{
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_sha256_hasher::ctx_)) ==
|
||||
sizeof(SHA256_CTX), "");
|
||||
auto const ctx = reinterpret_cast<
|
||||
SHA256_CTX*>(ctx_);
|
||||
SHA256_Init(ctx);
|
||||
|
||||
331
src/ripple/protocol/impl/tokens.cpp
Normal file
331
src/ripple/protocol/impl/tokens.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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 <ripple/protocol/tokens.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static char rippleAlphabet[] =
|
||||
"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz";
|
||||
|
||||
static char bitcoinAlphabet[] =
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Hasher>
|
||||
static
|
||||
typename Hasher::result_type
|
||||
digest (void const* data, std::size_t size) noexcept
|
||||
{
|
||||
Hasher h;
|
||||
h(data, size);
|
||||
return static_cast<
|
||||
typename Hasher::result_type>(h);
|
||||
}
|
||||
|
||||
template <class Hasher, class T, std::size_t N,
|
||||
class = std::enable_if_t<sizeof(T) == 1>>
|
||||
static
|
||||
typename Hasher::result_type
|
||||
digest (std::array<T, N> const& v)
|
||||
{
|
||||
return digest<Hasher>(v.data(), v.size());
|
||||
}
|
||||
|
||||
// Computes a double digest (e.g. digest of the digest)
|
||||
template <class Hasher, class... Args>
|
||||
static
|
||||
typename Hasher::result_type
|
||||
digest2 (Args const&... args)
|
||||
{
|
||||
return digest<Hasher>(
|
||||
digest<Hasher>(args...));
|
||||
}
|
||||
|
||||
/* Calculate a 4-byte checksum of the data
|
||||
|
||||
The checksum is calculated as the first 4 bytes
|
||||
of the SHA256 digest of the message. This is added
|
||||
to the base58 encoding of identifiers to detect
|
||||
user error in data entry.
|
||||
|
||||
@note This checksum algorithm is part of the client API
|
||||
*/
|
||||
void
|
||||
checksum (void* out,
|
||||
void const* message,
|
||||
std::size_t size)
|
||||
{
|
||||
auto const h =
|
||||
digest2<sha256_hasher>(message, size);
|
||||
std::memcpy(out, h.data(), 4);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Code from Bitcoin: https://github.com/bitcoin/bitcoin
|
||||
// Copyright (c) 2014 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// Modified from the original
|
||||
//
|
||||
// WARNING Do not call this directly, use
|
||||
// encodeBase58Token instead since it
|
||||
// calculates the size of buffer needed.
|
||||
static
|
||||
std::string
|
||||
encodeBase58(
|
||||
void const* message, std::size_t size,
|
||||
void *temp, char const* const alphabet)
|
||||
{
|
||||
auto pbegin = reinterpret_cast<
|
||||
unsigned char const*>(message);
|
||||
auto const pend = pbegin + size;
|
||||
// Skip & count leading zeroes.
|
||||
int zeroes = 0;
|
||||
while (pbegin != pend && *pbegin == 0)
|
||||
{
|
||||
pbegin++;
|
||||
zeroes++;
|
||||
}
|
||||
auto const b58begin = reinterpret_cast<
|
||||
unsigned char*>(temp);
|
||||
// log(256) / log(58), rounded up.
|
||||
auto const b58end = b58begin +
|
||||
size * (138 / 100 + 1);
|
||||
std::fill(b58begin, b58end, 0);
|
||||
while (pbegin != pend)
|
||||
{
|
||||
int carry = *pbegin;
|
||||
// Apply "b58 = b58 * 256 + ch".
|
||||
for (auto iter = b58end; iter != b58begin; --iter)
|
||||
{
|
||||
carry += 256 * (iter[-1]);
|
||||
iter[-1] = carry % 58;
|
||||
carry /= 58;
|
||||
}
|
||||
assert(carry == 0);
|
||||
pbegin++;
|
||||
}
|
||||
// Skip leading zeroes in base58 result.
|
||||
auto iter = b58begin;
|
||||
while (iter != b58end && *iter == 0)
|
||||
++iter;
|
||||
// Translate the result into a string.
|
||||
std::string str;
|
||||
str.reserve(zeroes + (b58end - iter));
|
||||
str.assign(zeroes, alphabet[0]);
|
||||
while (iter != b58end)
|
||||
str += alphabet[*(iter++)];
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Base-58 encode a Ripple Token
|
||||
|
||||
Ripple Tokens have a one-byte prefx indicating
|
||||
the type of token, followed by the data for the
|
||||
token, and finally a 4-byte checksum.
|
||||
|
||||
Tokens include the following:
|
||||
|
||||
Wallet Seed
|
||||
Account Public Key
|
||||
Account ID
|
||||
|
||||
@param temp A pointer to storage of not
|
||||
less than 2*(size+6) bytes
|
||||
*/
|
||||
std::string
|
||||
base58EncodeToken (std::uint8_t type,
|
||||
void const* token, std::size_t size)
|
||||
{
|
||||
char buf[1024];
|
||||
// expanded token includes type + checksum
|
||||
auto const expanded = 1 + size + 4;
|
||||
// add scratch, log(256) / log(58), rounded up.
|
||||
auto const needed = expanded +
|
||||
size * (138 / 100 + 1);
|
||||
std::unique_ptr<
|
||||
char[]> pbuf;
|
||||
char* temp;
|
||||
if (needed > sizeof(buf))
|
||||
{
|
||||
pbuf.reset(new char[needed]);
|
||||
temp = pbuf.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = buf;
|
||||
}
|
||||
// Lay the data out as
|
||||
// <type><token><checksum>
|
||||
temp[0] = type;
|
||||
std::memcpy(temp + 1, token, size);
|
||||
checksum(temp + 1 + size, temp, 1 + size);
|
||||
return encodeBase58(temp, expanded,
|
||||
temp + expanded, rippleAlphabet);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Code from Bitcoin: https://github.com/bitcoin/bitcoin
|
||||
// Copyright (c) 2014 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// Modified from the original
|
||||
template <class InverseArray>
|
||||
static
|
||||
std::string
|
||||
decodeBase58 (std::string const& s,
|
||||
InverseArray const& inv)
|
||||
{
|
||||
auto psz = s.c_str();
|
||||
auto remain = s.size();
|
||||
// Skip and count leading zeroes
|
||||
int zeroes = 0;
|
||||
while (remain > 0 && inv[*psz] == 0)
|
||||
{
|
||||
++zeroes;
|
||||
++psz;
|
||||
--remain;
|
||||
}
|
||||
// Allocate enough space in big-endian base256 representation.
|
||||
// log(58) / log(256), rounded up.
|
||||
std::vector<unsigned char> b256(
|
||||
remain * 733 / 1000 + 1);
|
||||
while (remain > 0)
|
||||
{
|
||||
auto carry = inv[*psz];
|
||||
if (carry == -1)
|
||||
return {};
|
||||
// Apply "b256 = b256 * 58 + carry".
|
||||
for (auto iter = b256.rbegin();
|
||||
iter != b256.rend(); ++iter)
|
||||
{
|
||||
carry += 58 * *iter;
|
||||
*iter = carry % 256;
|
||||
carry /= 256;
|
||||
}
|
||||
assert(carry == 0);
|
||||
++psz;
|
||||
--remain;
|
||||
}
|
||||
// Skip leading zeroes in b256.
|
||||
auto iter = std::find_if(
|
||||
b256.begin(), b256.end(),[](unsigned char c)
|
||||
{ return c != 0; });
|
||||
std::string result;
|
||||
result.reserve (zeroes + (b256.end() - iter));
|
||||
result.assign (zeroes, 0x00);
|
||||
while (iter != b256.end())
|
||||
result.push_back(*(iter++));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Base58 decode a Ripple token
|
||||
|
||||
The type and checksum are are checked
|
||||
and removed from the returned result.
|
||||
*/
|
||||
template <class InverseArray>
|
||||
static
|
||||
std::string
|
||||
decodeBase58Token (std::string const& s,
|
||||
int type, InverseArray const& inv)
|
||||
{
|
||||
auto result = decodeBase58(s, inv);
|
||||
if (result.empty())
|
||||
return result;
|
||||
// Reject zero length tokens
|
||||
if (result.size() < 6)
|
||||
return {};
|
||||
if (result[0] != type)
|
||||
return {};
|
||||
std::array<char, 4> guard;
|
||||
checksum(guard.data(),
|
||||
result.data(), result.size() - 4);
|
||||
if (std::memcmp(guard.data(),
|
||||
result.data() +
|
||||
result.size() - 4, 4) != 0)
|
||||
return {};
|
||||
result.resize(result.size() - 4);
|
||||
// Erase the type byte
|
||||
// VFALCO This might cause problems later
|
||||
result.erase(result.begin());
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Maps characters to their base58 digit
|
||||
class InverseAlphabet
|
||||
{
|
||||
private:
|
||||
std::array<int, 256> map_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
InverseAlphabet(std::string const& digits)
|
||||
{
|
||||
map_.fill(-1);
|
||||
int i = 0;
|
||||
for(auto const c : digits)
|
||||
map_[static_cast<
|
||||
unsigned char>(c)] = i++;
|
||||
}
|
||||
|
||||
int
|
||||
operator[](char c) const
|
||||
{
|
||||
return map_[static_cast<
|
||||
unsigned char>(c)];
|
||||
}
|
||||
};
|
||||
|
||||
static InverseAlphabet rippleInverse(rippleAlphabet);
|
||||
|
||||
static InverseAlphabet bitcoinInverse(bitcoinAlphabet);
|
||||
|
||||
std::string
|
||||
decodeBase58Token(
|
||||
std::string const& s, int type)
|
||||
{
|
||||
return decodeBase58Token(
|
||||
s, type, rippleInverse);
|
||||
}
|
||||
|
||||
std::string
|
||||
decodeBase58TokenBitcoin(
|
||||
std::string const& s, int type)
|
||||
{
|
||||
return decodeBase58Token(
|
||||
s, type, bitcoinInverse);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -489,6 +489,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Issue,types,ripple);
|
||||
BEAST_DEFINE_TESTSUITE(Issue,protocol,ripple);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/protocol/RippleAddress.h>
|
||||
#include <ripple/protocol/RipplePublicKey.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -72,14 +73,14 @@ public:
|
||||
RippleAddress naAccountPublic0 = RippleAddress::createAccountPublic (generator, 0);
|
||||
RippleAddress naAccountPrivate0 = RippleAddress::createAccountPrivate (generator, naSeed, 0);
|
||||
|
||||
expect (naAccountPublic0.humanAccountID () == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", naAccountPublic0.humanAccountID ());
|
||||
expect (toBase58(calcAccountID(naAccountPublic0)) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
||||
expect (naAccountPublic0.humanAccountPublic () == "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw", naAccountPublic0.humanAccountPublic ());
|
||||
|
||||
// Create account #1 public/private key pair.
|
||||
RippleAddress naAccountPublic1 = RippleAddress::createAccountPublic (generator, 1);
|
||||
RippleAddress naAccountPrivate1 = RippleAddress::createAccountPrivate (generator, naSeed, 1);
|
||||
|
||||
expect (naAccountPublic1.humanAccountID () == "r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP", naAccountPublic1.humanAccountID ());
|
||||
expect (toBase58(calcAccountID(naAccountPublic1)) == "r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP");
|
||||
expect (naAccountPublic1.humanAccountPublic () == "aBPXpTfuLy1Bhk3HnGTTAqnovpKWQ23NpFMNkAF6F1Atg5vDyPrw", naAccountPublic1.humanAccountPublic ());
|
||||
|
||||
// Check account signing.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/STParsedJSON.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
@@ -37,7 +38,7 @@ public:
|
||||
RippleAddress privateAcct = RippleAddress::createAccountPrivate (generator, seed, 1);
|
||||
|
||||
STTx j (ttACCOUNT_SET);
|
||||
j.setSourceAccount (publicAcct);
|
||||
j.setAccountID (sfAccount, calcAccountID(publicAcct));
|
||||
j.setSigningPubKey (publicAcct);
|
||||
j.setFieldVL (sfMessageKey, publicAcct.getAccountPublic ());
|
||||
j.sign (privateAcct);
|
||||
@@ -85,11 +86,13 @@ public:
|
||||
// Create a transaction
|
||||
RippleAddress txnSeed;
|
||||
txnSeed.setSeedRandom ();
|
||||
// VFALCO Generators are no longer supported
|
||||
RippleAddress txnGenerator = txnSeed.createGeneratorPublic (txnSeed);
|
||||
// VFALCO Use AnyPublicKey here
|
||||
RippleAddress txnPublicAcct = txnSeed.createAccountPublic (txnGenerator, 1);
|
||||
|
||||
STTx txn (ttACCOUNT_SET);
|
||||
txn.setSourceAccount (txnPublicAcct);
|
||||
txn.setAccountID (sfAccount, calcAccountID(txnPublicAcct));
|
||||
txn.setSigningPubKey (txnPublicAcct);
|
||||
txn.setFieldVL (sfMessageKey, txnPublicAcct.getAccountPublic ());
|
||||
Blob const emptyBlob; // Make empty signature for multi-signing
|
||||
@@ -101,16 +104,17 @@ public:
|
||||
RippleAddress const saGenerator = saSeed.createGeneratorPublic (saSeed);
|
||||
RippleAddress const saPublicAcct =
|
||||
saSeed.createAccountPublic (saGenerator, 1);
|
||||
AccountID const saID = saPublicAcct.getAccountID ();
|
||||
AccountID const saID = calcAccountID(saPublicAcct);
|
||||
|
||||
// Create a field for SigningFor
|
||||
AccountID const signingForID = txnPublicAcct.getAccountID ();
|
||||
AccountID const signingForID = calcAccountID(txnPublicAcct);
|
||||
|
||||
RippleAddress saPrivateAcct =
|
||||
saSeed.createAccountPrivate(saGenerator, saSeed, 0);
|
||||
|
||||
// Get the stream of the transaction for use in multi-signing.
|
||||
Serializer s = txn.getMultiSigningData (saPublicAcct, saPublicAcct);
|
||||
Serializer s = txn.getMultiSigningData(
|
||||
calcAccountID(saPublicAcct), calcAccountID(saPublicAcct));
|
||||
|
||||
Blob saMultiSignature =
|
||||
saPrivateAcct.accountPrivateSign (s.getData());
|
||||
@@ -137,7 +141,7 @@ public:
|
||||
|
||||
// Insert SigningAccounts array into SigningFor object.
|
||||
STObject signingFor (sfSigningFor);
|
||||
signingFor.setFieldAccount (sfAccount, signingForID);
|
||||
signingFor.setAccountID (sfAccount, signingForID);
|
||||
signingFor.setFieldArray (sfSigningAccounts, signingAccts);
|
||||
|
||||
// Insert SigningFor into MultiSigners.
|
||||
@@ -169,7 +173,7 @@ public:
|
||||
{
|
||||
// Test case 1. Make a valid SigningAccount object.
|
||||
STObject soTest1 (sfSigningAccount);
|
||||
soTest1.setFieldAccount (sfAccount, saID);
|
||||
soTest1.setAccountID (sfAccount, saID);
|
||||
soTest1.setFieldVL (sfSigningPubKey,
|
||||
txnPublicAcct.getAccountPublic ());
|
||||
soTest1.setFieldVL (sfMultiSignature, saMultiSignature);
|
||||
@@ -178,14 +182,14 @@ public:
|
||||
{
|
||||
// Test case 2. Omit sfSigningPubKey from SigningAccount.
|
||||
STObject soTest2 (sfSigningAccount);
|
||||
soTest2.setFieldAccount (sfAccount, saID);
|
||||
soTest2.setAccountID (sfAccount, saID);
|
||||
soTest2.setFieldVL (sfMultiSignature, saMultiSignature);
|
||||
testMalformedSigningAccount (soTest2, false);
|
||||
}
|
||||
{
|
||||
// Test case 3. Extra sfAmount in SigningAccount.
|
||||
STObject soTest3 (sfSigningAccount);
|
||||
soTest3.setFieldAccount (sfAccount, saID);
|
||||
soTest3.setAccountID (sfAccount, saID);
|
||||
soTest3.setFieldVL (sfSigningPubKey,
|
||||
txnPublicAcct.getAccountPublic ());
|
||||
soTest3.setFieldVL (sfMultiSignature, saMultiSignature);
|
||||
|
||||
47
src/ripple/protocol/tests/types_test.cpp
Normal file
47
src/ripple/protocol/tests/types_test.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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 <BeastConfig.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
struct types_test : public beast::unit_test::suite
|
||||
{
|
||||
void
|
||||
testAccountID()
|
||||
{
|
||||
auto const s =
|
||||
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
|
||||
if (expect(parseBase58<AccountID>(s)))
|
||||
expect(toBase58(
|
||||
*parseBase58<AccountID>(s)) == s);
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testAccountID();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(types,protocol,ripple);
|
||||
|
||||
}
|
||||
100
src/ripple/protocol/tokens.h
Normal file
100
src/ripple/protocol/tokens.h
Normal file
@@ -0,0 +1,100 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROTOCOL_TOKENS_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_TOKENS_H_INCLUDED
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
enum TokenType
|
||||
{
|
||||
TOKEN_NONE = 1,
|
||||
TOKEN_NODE_PUBLIC = 28,
|
||||
TOKEN_NODE_PRIVATE = 32,
|
||||
TOKEN_ACCOUNT_ID = 0,
|
||||
TOKEN_ACCOUNT_PUBLIC = 35,
|
||||
TOKEN_ACCOUNT_SECRET = 34,
|
||||
TOKEN_FAMILY_GENERATOR = 41,
|
||||
TOKEN_FAMILY_SEED = 33
|
||||
};
|
||||
|
||||
template <class T>
|
||||
boost::optional<T>
|
||||
parseBase58 (std::string const& s);
|
||||
|
||||
template <class T>
|
||||
boost::optional<T>
|
||||
parseHex (std::string const& s);
|
||||
|
||||
template <class T>
|
||||
boost::optional<T>
|
||||
parseHexOrBase58 (std::string const& s);
|
||||
|
||||
// Facilities for converting Ripple tokens
|
||||
// to and from their human readable strings
|
||||
|
||||
/* Base-58 encode a Ripple Token
|
||||
|
||||
Ripple Tokens have a one-byte prefx indicating
|
||||
the type of token, followed by the data for the
|
||||
token, and finally a 4-byte checksum.
|
||||
|
||||
Tokens include the following:
|
||||
|
||||
Wallet Seed
|
||||
Account Public Key
|
||||
Account ID
|
||||
|
||||
@param temp A pointer to storage of not
|
||||
less than 2*(size+6) bytes
|
||||
*/
|
||||
std::string
|
||||
base58EncodeToken (std::uint8_t type,
|
||||
void const* token, std::size_t size);
|
||||
|
||||
/** Decode a Base58 token
|
||||
|
||||
The type and checksum must match or an
|
||||
empty string is returned.
|
||||
*/
|
||||
std::string
|
||||
decodeBase58Token(
|
||||
std::string const& s, int type);
|
||||
|
||||
/** Decode a Base58 token using Bitcoin alphabet
|
||||
|
||||
The type and checksum must match or an
|
||||
empty string is returned.
|
||||
|
||||
This is used to detect user error. Specifically,
|
||||
when an AccountID is specified using the wrong
|
||||
base58 alphabet, so that a better error message
|
||||
may be returned.
|
||||
*/
|
||||
std::string
|
||||
decodeBase58TokenBitcoin(
|
||||
std::string const& s, int type);
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
27
src/ripple/protocol/types.h
Normal file
27
src/ripple/protocol/types.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROTOCOL_TYPES_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_TYPES_H_INCLUDED
|
||||
|
||||
// DEPRECATED HEADER
|
||||
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user