mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Move ./modules to ./src
This commit is contained in:
188
src/ripple_data/crypto/ripple_Base58.cpp
Normal file
188
src/ripple_data/crypto/ripple_Base58.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
char const* Base58::s_currentAlphabet = Base58::getRippleAlphabet ();
|
||||
|
||||
char const* Base58::getCurrentAlphabet ()
|
||||
{
|
||||
return s_currentAlphabet;
|
||||
}
|
||||
|
||||
void Base58::setCurrentAlphabet (char const* alphabet)
|
||||
{
|
||||
s_currentAlphabet = alphabet;
|
||||
}
|
||||
|
||||
char const* Base58::getBitcoinAlphabet ()
|
||||
{
|
||||
return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
}
|
||||
|
||||
char const* Base58::getRippleAlphabet ()
|
||||
{
|
||||
return "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz";
|
||||
}
|
||||
|
||||
char const* Base58::getTestnetAlphabet ()
|
||||
{
|
||||
return "RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz";
|
||||
}
|
||||
|
||||
std::string Base58::encode (const unsigned char* pbegin, const unsigned char* pend)
|
||||
{
|
||||
char const* alphabet = getCurrentAlphabet ();
|
||||
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum bn58 = 58;
|
||||
CBigNum bn0 = 0;
|
||||
|
||||
// Convert big endian data to little endian
|
||||
// Extra zero at the end make sure bignum will interpret as a positive number
|
||||
Blob vchTmp (pend - pbegin + 1, 0);
|
||||
std::reverse_copy (pbegin, pend, vchTmp.begin ());
|
||||
|
||||
// Convert little endian data to bignum
|
||||
CBigNum bn (vchTmp);
|
||||
|
||||
// Convert bignum to std::string
|
||||
std::string str;
|
||||
// Expected size increase from base58 conversion is approximately 137%
|
||||
// use 138% to be safe
|
||||
str.reserve ((pend - pbegin) * 138 / 100 + 1);
|
||||
CBigNum dv;
|
||||
CBigNum rem;
|
||||
|
||||
while (bn > bn0)
|
||||
{
|
||||
if (!BN_div (&dv, &rem, &bn, &bn58, pctx))
|
||||
throw bignum_error ("EncodeBase58 : BN_div failed");
|
||||
|
||||
bn = dv;
|
||||
unsigned int c = rem.getuint ();
|
||||
str += alphabet [c];
|
||||
}
|
||||
|
||||
// Leading zeroes encoded as base58 zeros
|
||||
for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
|
||||
str += alphabet [0];
|
||||
|
||||
// Convert little endian std::string to big endian
|
||||
reverse (str.begin (), str.end ());
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string Base58::encode (Blob const& vch)
|
||||
{
|
||||
return encode (&vch[0], &vch[0] + vch.size ());
|
||||
}
|
||||
|
||||
std::string Base58::encodeWithCheck (Blob const& vchIn)
|
||||
{
|
||||
// add 4-byte hash check to the end
|
||||
Blob vch (vchIn);
|
||||
uint256 hash = SHA256Hash (vch.begin (), vch.end ());
|
||||
vch.insert (vch.end (), (unsigned char*)&hash, (unsigned char*)&hash + 4);
|
||||
return encode (vch);
|
||||
}
|
||||
|
||||
bool Base58::decode (const char* psz, Blob& vchRet, const char* pAlpha)
|
||||
{
|
||||
assert (pAlpha != 0);
|
||||
|
||||
CAutoBN_CTX pctx;
|
||||
vchRet.clear ();
|
||||
CBigNum bn58 = 58;
|
||||
CBigNum bn = 0;
|
||||
CBigNum bnChar;
|
||||
|
||||
while (isspace (*psz))
|
||||
psz++;
|
||||
|
||||
// Convert big endian string to bignum
|
||||
for (const char* p = psz; *p; p++)
|
||||
{
|
||||
const char* p1 = strchr (pAlpha, *p);
|
||||
|
||||
if (p1 == NULL)
|
||||
{
|
||||
while (isspace (*p))
|
||||
p++;
|
||||
|
||||
if (*p != '\0')
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
bnChar.setuint (p1 - pAlpha);
|
||||
|
||||
if (!BN_mul (&bn, &bn, &bn58, pctx))
|
||||
throw bignum_error ("DecodeBase58 : BN_mul failed");
|
||||
|
||||
bn += bnChar;
|
||||
}
|
||||
|
||||
// Get bignum as little endian data
|
||||
Blob vchTmp = bn.getvch ();
|
||||
|
||||
// Trim off sign byte if present
|
||||
if (vchTmp.size () >= 2 && vchTmp.end ()[-1] == 0 && vchTmp.end ()[-2] >= 0x80)
|
||||
vchTmp.erase (vchTmp.end () - 1);
|
||||
|
||||
// Restore leading zeros
|
||||
int nLeadingZeros = 0;
|
||||
|
||||
for (const char* p = psz; *p == pAlpha[0]; p++)
|
||||
nLeadingZeros++;
|
||||
|
||||
vchRet.assign (nLeadingZeros + vchTmp.size (), 0);
|
||||
|
||||
// Convert little endian data to big endian
|
||||
std::reverse_copy (vchTmp.begin (), vchTmp.end (), vchRet.end () - vchTmp.size ());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Base58::decode (const std::string& str, Blob& vchRet)
|
||||
{
|
||||
return decode (str.c_str (), vchRet);
|
||||
}
|
||||
|
||||
bool Base58::decodeWithCheck (const char* psz, Blob& vchRet, const char* pAlphabet)
|
||||
{
|
||||
assert (pAlphabet != NULL);
|
||||
|
||||
if (!decode (psz, vchRet, pAlphabet))
|
||||
return false;
|
||||
|
||||
if (vchRet.size () < 4)
|
||||
{
|
||||
vchRet.clear ();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 hash = SHA256Hash (vchRet.begin (), vchRet.end () - 4);
|
||||
|
||||
if (memcmp (&hash, &vchRet.end ()[-4], 4) != 0)
|
||||
{
|
||||
vchRet.clear ();
|
||||
return false;
|
||||
}
|
||||
|
||||
vchRet.resize (vchRet.size () - 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Base58::decodeWithCheck (const std::string& str, Blob& vchRet, const char* pAlphabet)
|
||||
{
|
||||
return decodeWithCheck (str.c_str (), vchRet, pAlphabet);
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
49
src/ripple_data/crypto/ripple_Base58.h
Normal file
49
src/ripple_data/crypto/ripple_Base58.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// Why base-58 instead of standard base-64 encoding?
|
||||
// - Don't want 0OIl characters that look the same in some fonts and
|
||||
// could be used to create visually identical looking account numbers.
|
||||
// - A string with non-alphanumeric characters is not as easily accepted as an account number.
|
||||
// - E-mail usually won't line-break if there's no punctuation to break at.
|
||||
// - Doubleclicking selects the whole number as one word if it's all alphanumeric.
|
||||
//
|
||||
#ifndef RIPPLE_BASE58_H
|
||||
#define RIPPLE_BASE58_H
|
||||
|
||||
/** Performs Base 58 encoding and decoding.
|
||||
*/
|
||||
class Base58
|
||||
{
|
||||
public:
|
||||
// VFALCO TODO clean up this poor API
|
||||
static char const* getCurrentAlphabet ();
|
||||
static void setCurrentAlphabet (char const* alphabet);
|
||||
|
||||
static char const* getBitcoinAlphabet ();
|
||||
static char const* getRippleAlphabet ();
|
||||
static char const* getTestnetAlphabet ();
|
||||
|
||||
static std::string encode (const unsigned char* pbegin, const unsigned char* pend);
|
||||
static std::string encode (Blob const& vch);
|
||||
static std::string encodeWithCheck (Blob const& vchIn);
|
||||
|
||||
static bool decode (const char* psz, Blob& vchRet, const char* pAlphabet = getCurrentAlphabet ());
|
||||
static bool decode (const std::string& str, Blob& vchRet);
|
||||
static bool decodeWithCheck (const char* psz, Blob& vchRet, const char* pAlphabet = getCurrentAlphabet ());
|
||||
static bool decodeWithCheck (const std::string& str, Blob& vchRet, const char* pAlphabet);
|
||||
|
||||
private:
|
||||
static char const* s_currentAlphabet;
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
135
src/ripple_data/crypto/ripple_Base58Data.cpp
Normal file
135
src/ripple_data/crypto/ripple_Base58Data.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// Why base-58 instead of standard base-64 encoding?
|
||||
// - Don't want 0OIl characters that look the same in some fonts and
|
||||
// could be used to create visually identical looking account numbers.
|
||||
// - A string with non-alphanumeric characters is not as easily accepted as an account number.
|
||||
// - E-mail usually won't line-break if there's no punctuation to break at.
|
||||
// - Doubleclicking selects the whole number as one word if it's all alphanumeric.
|
||||
//
|
||||
|
||||
CBase58Data::CBase58Data ()
|
||||
: nVersion (1)
|
||||
{
|
||||
}
|
||||
|
||||
CBase58Data::~CBase58Data ()
|
||||
{
|
||||
if (!vchData.empty ())
|
||||
memset (&vchData[0], 0, vchData.size ());
|
||||
}
|
||||
|
||||
void CBase58Data::SetData (int nVersionIn, Blob const& vchDataIn)
|
||||
{
|
||||
nVersion = nVersionIn;
|
||||
vchData = vchDataIn;
|
||||
}
|
||||
|
||||
void CBase58Data::SetData (int nVersionIn, const void* pdata, size_t nSize)
|
||||
{
|
||||
nVersion = nVersionIn;
|
||||
vchData.resize (nSize);
|
||||
|
||||
if (nSize)
|
||||
memcpy (&vchData[0], pdata, nSize);
|
||||
}
|
||||
|
||||
void CBase58Data::SetData (int nVersionIn, const unsigned char* pbegin, const unsigned char* pend)
|
||||
{
|
||||
SetData (nVersionIn, (void*)pbegin, pend - pbegin);
|
||||
}
|
||||
|
||||
bool CBase58Data::SetString (const char* psz, unsigned char version, const char* pAlphabet)
|
||||
{
|
||||
Blob vchTemp;
|
||||
Base58::decodeWithCheck (psz, vchTemp, pAlphabet);
|
||||
|
||||
if (vchTemp.empty () || vchTemp[0] != version)
|
||||
{
|
||||
vchData.clear ();
|
||||
nVersion = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
nVersion = vchTemp[0];
|
||||
vchData.resize (vchTemp.size () - 1);
|
||||
|
||||
if (!vchData.empty ())
|
||||
memcpy (&vchData[0], &vchTemp[1], vchData.size ());
|
||||
|
||||
memset (&vchTemp[0], 0, vchTemp.size ());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBase58Data::SetString (const std::string& str, unsigned char version)
|
||||
{
|
||||
return SetString (str.c_str (), version);
|
||||
}
|
||||
|
||||
std::string CBase58Data::ToString () const
|
||||
{
|
||||
Blob vch (1, nVersion);
|
||||
|
||||
vch.insert (vch.end (), vchData.begin (), vchData.end ());
|
||||
|
||||
return Base58::encodeWithCheck (vch);
|
||||
}
|
||||
|
||||
int CBase58Data::CompareTo (const CBase58Data& b58) const
|
||||
{
|
||||
if (nVersion < b58.nVersion) return -1;
|
||||
|
||||
if (nVersion > b58.nVersion) return 1;
|
||||
|
||||
if (vchData < b58.vchData) return -1;
|
||||
|
||||
if (vchData > b58.vchData) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CBase58Data::operator== (const CBase58Data& b58) const
|
||||
{
|
||||
return CompareTo (b58) == 0;
|
||||
}
|
||||
bool CBase58Data::operator!= (const CBase58Data& b58) const
|
||||
{
|
||||
return CompareTo (b58) != 0;
|
||||
}
|
||||
bool CBase58Data::operator<= (const CBase58Data& b58) const
|
||||
{
|
||||
return CompareTo (b58) <= 0;
|
||||
}
|
||||
bool CBase58Data::operator>= (const CBase58Data& b58) const
|
||||
{
|
||||
return CompareTo (b58) >= 0;
|
||||
}
|
||||
bool CBase58Data::operator< (const CBase58Data& b58) const
|
||||
{
|
||||
return CompareTo (b58) < 0;
|
||||
}
|
||||
bool CBase58Data::operator> (const CBase58Data& b58) const
|
||||
{
|
||||
return CompareTo (b58) > 0;
|
||||
}
|
||||
|
||||
std::size_t hash_value (const CBase58Data& b58)
|
||||
{
|
||||
std::size_t seed = HashMaps::getInstance ().getNonce <size_t> ()
|
||||
+ (b58.nVersion * HashMaps::goldenRatio);
|
||||
|
||||
boost::hash_combine (seed, b58.vchData);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
55
src/ripple_data/crypto/ripple_Base58Data.h
Normal file
55
src/ripple_data/crypto/ripple_Base58Data.h
Normal file
@@ -0,0 +1,55 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// Why base-58 instead of standard base-64 encoding?
|
||||
// - Don't want 0OIl characters that look the same in some fonts and
|
||||
// could be used to create visually identical looking account numbers.
|
||||
// - A string with non-alphanumeric characters is not as easily accepted as an account number.
|
||||
// - E-mail usually won't line-break if there's no punctuation to break at.
|
||||
// - Doubleclicking selects the whole number as one word if it's all alphanumeric.
|
||||
//
|
||||
#ifndef RIPPLE_BASE58DATA_H
|
||||
#define RIPPLE_BASE58DATA_H
|
||||
|
||||
class CBase58Data
|
||||
{
|
||||
protected:
|
||||
unsigned char nVersion;
|
||||
Blob vchData;
|
||||
|
||||
CBase58Data ();
|
||||
~CBase58Data ();
|
||||
|
||||
void SetData (int nVersionIn, Blob const& vchDataIn);
|
||||
void SetData (int nVersionIn, const void* pdata, size_t nSize);
|
||||
void SetData (int nVersionIn, const unsigned char* pbegin, const unsigned char* pend);
|
||||
|
||||
public:
|
||||
bool SetString (const char* psz, unsigned char version, const char* pAlphabet = Base58::getCurrentAlphabet ());
|
||||
bool SetString (const std::string& str, unsigned char version);
|
||||
|
||||
std::string ToString () const;
|
||||
int CompareTo (const CBase58Data& b58) const;
|
||||
|
||||
bool operator== (const CBase58Data& b58) const;
|
||||
bool operator!= (const CBase58Data& b58) const;
|
||||
bool operator<= (const CBase58Data& b58) const;
|
||||
bool operator>= (const CBase58Data& b58) const;
|
||||
bool operator< (const CBase58Data& b58) const;
|
||||
bool operator> (const CBase58Data& b58) const;
|
||||
|
||||
friend std::size_t hash_value (const CBase58Data& b58);
|
||||
};
|
||||
|
||||
extern std::size_t hash_value (const CBase58Data& b58);
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
643
src/ripple_data/crypto/ripple_CBigNum.cpp
Normal file
643
src/ripple_data/crypto/ripple_CBigNum.cpp
Normal file
@@ -0,0 +1,643 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
CBigNum::CBigNum ()
|
||||
{
|
||||
BN_init (this);
|
||||
}
|
||||
|
||||
CBigNum::CBigNum (const CBigNum& b)
|
||||
{
|
||||
BN_init (this);
|
||||
|
||||
if (!BN_copy (this, &b))
|
||||
{
|
||||
BN_clear_free (this);
|
||||
throw bignum_error ("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
|
||||
}
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator= (const CBigNum& b)
|
||||
{
|
||||
if (!BN_copy (this, &b))
|
||||
throw bignum_error ("CBigNum::operator= : BN_copy failed");
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
CBigNum::~CBigNum ()
|
||||
{
|
||||
BN_clear_free (this);
|
||||
}
|
||||
|
||||
CBigNum::CBigNum (char n)
|
||||
{
|
||||
BN_init (this);
|
||||
|
||||
if (n >= 0) setulong (n);
|
||||
else setint64 (n);
|
||||
}
|
||||
CBigNum::CBigNum (short n)
|
||||
{
|
||||
BN_init (this);
|
||||
|
||||
if (n >= 0) setulong (n);
|
||||
else setint64 (n);
|
||||
}
|
||||
CBigNum::CBigNum (int n)
|
||||
{
|
||||
BN_init (this);
|
||||
|
||||
if (n >= 0) setulong (n);
|
||||
else setint64 (n);
|
||||
}
|
||||
CBigNum::CBigNum (long n)
|
||||
{
|
||||
BN_init (this);
|
||||
|
||||
if (n >= 0) setulong (n);
|
||||
else setint64 (n);
|
||||
}
|
||||
CBigNum::CBigNum (int64 n)
|
||||
{
|
||||
BN_init (this);
|
||||
setint64 (n);
|
||||
}
|
||||
CBigNum::CBigNum (unsigned char n)
|
||||
{
|
||||
BN_init (this);
|
||||
setulong (n);
|
||||
}
|
||||
CBigNum::CBigNum (unsigned short n)
|
||||
{
|
||||
BN_init (this);
|
||||
setulong (n);
|
||||
}
|
||||
CBigNum::CBigNum (unsigned int n)
|
||||
{
|
||||
BN_init (this);
|
||||
setulong (n);
|
||||
}
|
||||
CBigNum::CBigNum (uint64 n)
|
||||
{
|
||||
BN_init (this);
|
||||
setuint64 (n);
|
||||
}
|
||||
CBigNum::CBigNum (uint256 n)
|
||||
{
|
||||
BN_init (this);
|
||||
setuint256 (n);
|
||||
}
|
||||
|
||||
CBigNum::CBigNum (Blob const& vch)
|
||||
{
|
||||
BN_init (this);
|
||||
setvch (vch);
|
||||
}
|
||||
|
||||
void CBigNum::setuint (unsigned int n)
|
||||
{
|
||||
setulong (static_cast<unsigned long> (n));
|
||||
}
|
||||
|
||||
unsigned int CBigNum::getuint () const
|
||||
{
|
||||
return BN_get_word (this);
|
||||
}
|
||||
|
||||
int CBigNum::getint () const
|
||||
{
|
||||
unsigned long n = BN_get_word (this);
|
||||
|
||||
if (!BN_is_negative (this))
|
||||
return (n > INT_MAX ? INT_MAX : n);
|
||||
else
|
||||
return (n > INT_MAX ? INT_MIN : - (int)n);
|
||||
}
|
||||
|
||||
void CBigNum::setint64 (int64 n)
|
||||
{
|
||||
unsigned char pch[sizeof (n) + 6];
|
||||
unsigned char* p = pch + 4;
|
||||
bool fNegative = false;
|
||||
|
||||
if (n < (int64)0)
|
||||
{
|
||||
n = -n;
|
||||
fNegative = true;
|
||||
}
|
||||
|
||||
bool fLeadingZeroes = true;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
unsigned char c = (n >> 56) & 0xff;
|
||||
n <<= 8;
|
||||
|
||||
if (fLeadingZeroes)
|
||||
{
|
||||
if (c == 0)
|
||||
continue;
|
||||
|
||||
if (c & 0x80)
|
||||
*p++ = (fNegative ? 0x80 : 0);
|
||||
else if (fNegative)
|
||||
c |= 0x80;
|
||||
|
||||
fLeadingZeroes = false;
|
||||
}
|
||||
|
||||
*p++ = c;
|
||||
}
|
||||
|
||||
unsigned int nSize = p - (pch + 4);
|
||||
pch[0] = (nSize >> 24) & 0xff;
|
||||
pch[1] = (nSize >> 16) & 0xff;
|
||||
pch[2] = (nSize >> 8) & 0xff;
|
||||
pch[3] = (nSize) & 0xff;
|
||||
BN_mpi2bn (pch, p - pch, this);
|
||||
}
|
||||
|
||||
uint64 CBigNum::getuint64 () const
|
||||
{
|
||||
#if (ULONG_MAX > UINT_MAX)
|
||||
return static_cast<uint64> (getulong ());
|
||||
#else
|
||||
int len = BN_num_bytes (this);
|
||||
|
||||
if (len > 8)
|
||||
throw std::runtime_error ("BN getuint64 overflow");
|
||||
|
||||
unsigned char buf[8];
|
||||
memset (buf, 0, sizeof (buf));
|
||||
BN_bn2bin (this, buf + 8 - len);
|
||||
return
|
||||
static_cast<uint64> (buf[0]) << 56 | static_cast<uint64> (buf[1]) << 48 |
|
||||
static_cast<uint64> (buf[2]) << 40 | static_cast<uint64> (buf[3]) << 32 |
|
||||
static_cast<uint64> (buf[4]) << 24 | static_cast<uint64> (buf[5]) << 16 |
|
||||
static_cast<uint64> (buf[6]) << 8 | static_cast<uint64> (buf[7]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CBigNum::setuint64 (uint64 n)
|
||||
{
|
||||
#if (ULONG_MAX > UINT_MAX)
|
||||
setulong (static_cast<unsigned long> (n));
|
||||
#else
|
||||
unsigned char buf[8];
|
||||
buf[0] = static_cast<unsigned char> ((n >> 56) & 0xff);
|
||||
buf[1] = static_cast<unsigned char> ((n >> 48) & 0xff);
|
||||
buf[2] = static_cast<unsigned char> ((n >> 40) & 0xff);
|
||||
buf[3] = static_cast<unsigned char> ((n >> 32) & 0xff);
|
||||
buf[4] = static_cast<unsigned char> ((n >> 24) & 0xff);
|
||||
buf[5] = static_cast<unsigned char> ((n >> 16) & 0xff);
|
||||
buf[6] = static_cast<unsigned char> ((n >> 8) & 0xff);
|
||||
buf[7] = static_cast<unsigned char> ((n) & 0xff);
|
||||
BN_bin2bn (buf, 8, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CBigNum::setuint256 (uint256 const& n)
|
||||
{
|
||||
BN_bin2bn (n.begin (), n.size (), NULL);
|
||||
}
|
||||
|
||||
uint256 CBigNum::getuint256 ()
|
||||
{
|
||||
uint256 ret;
|
||||
unsigned int size = BN_num_bytes (this);
|
||||
|
||||
if (size > ret.size ())
|
||||
return ret;
|
||||
|
||||
BN_bn2bin (this, ret.begin () + (ret.size () - BN_num_bytes (this)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CBigNum::setvch (Blob const& vch)
|
||||
{
|
||||
Blob vch2 (vch.size () + 4);
|
||||
unsigned int nSize = vch.size ();
|
||||
// BIGNUM's byte stream format expects 4 bytes of
|
||||
// big endian size data info at the front
|
||||
vch2[0] = (nSize >> 24) & 0xff;
|
||||
vch2[1] = (nSize >> 16) & 0xff;
|
||||
vch2[2] = (nSize >> 8) & 0xff;
|
||||
vch2[3] = (nSize >> 0) & 0xff;
|
||||
// swap data to big endian
|
||||
std::reverse_copy (vch.begin (), vch.end (), vch2.begin () + 4);
|
||||
BN_mpi2bn (&vch2[0], vch2.size (), this);
|
||||
}
|
||||
|
||||
Blob CBigNum::getvch () const
|
||||
{
|
||||
unsigned int nSize = BN_bn2mpi (this, NULL);
|
||||
|
||||
if (nSize < 4)
|
||||
return Blob ();
|
||||
|
||||
Blob vch (nSize);
|
||||
BN_bn2mpi (this, &vch[0]);
|
||||
vch.erase (vch.begin (), vch.begin () + 4);
|
||||
reverse (vch.begin (), vch.end ());
|
||||
return vch;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::SetCompact (unsigned int nCompact)
|
||||
{
|
||||
unsigned int nSize = nCompact >> 24;
|
||||
Blob vch (4 + nSize);
|
||||
vch[3] = nSize;
|
||||
|
||||
if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff;
|
||||
|
||||
if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff;
|
||||
|
||||
if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff;
|
||||
|
||||
BN_mpi2bn (&vch[0], vch.size (), this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int CBigNum::GetCompact () const
|
||||
{
|
||||
unsigned int nSize = BN_bn2mpi (this, NULL);
|
||||
Blob vch (nSize);
|
||||
nSize -= 4;
|
||||
BN_bn2mpi (this, &vch[0]);
|
||||
unsigned int nCompact = nSize << 24;
|
||||
|
||||
if (nSize >= 1) nCompact |= (vch[4] << 16);
|
||||
|
||||
if (nSize >= 2) nCompact |= (vch[5] << 8);
|
||||
|
||||
if (nSize >= 3) nCompact |= (vch[6] << 0);
|
||||
|
||||
return nCompact;
|
||||
}
|
||||
|
||||
void CBigNum::SetHex (const std::string& str)
|
||||
{
|
||||
// skip 0x
|
||||
const char* psz = str.c_str ();
|
||||
|
||||
while (isspace (*psz))
|
||||
psz++;
|
||||
|
||||
bool fNegative = false;
|
||||
|
||||
if (*psz == '-')
|
||||
{
|
||||
fNegative = true;
|
||||
psz++;
|
||||
}
|
||||
|
||||
if (psz[0] == '0' && tolower (psz[1]) == 'x')
|
||||
psz += 2;
|
||||
|
||||
while (isspace (*psz))
|
||||
psz++;
|
||||
|
||||
// hex string to bignum
|
||||
static char phexdigit[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
|
||||
0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
*this = 0;
|
||||
|
||||
while (isxdigit (*psz))
|
||||
{
|
||||
*this <<= 4;
|
||||
int n = phexdigit[ (int) * psz++];
|
||||
*this += n;
|
||||
}
|
||||
|
||||
if (fNegative)
|
||||
*this = 0 - *this;
|
||||
}
|
||||
|
||||
std::string CBigNum::ToString (int nBase) const
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum bnBase = nBase;
|
||||
CBigNum bn0 = 0;
|
||||
std::string str;
|
||||
CBigNum bn = *this;
|
||||
BN_set_negative (&bn, false);
|
||||
CBigNum dv;
|
||||
CBigNum rem;
|
||||
|
||||
if (BN_cmp (&bn, &bn0) == 0)
|
||||
return "0";
|
||||
|
||||
while (BN_cmp (&bn, &bn0) > 0)
|
||||
{
|
||||
if (!BN_div (&dv, &rem, &bn, &bnBase, pctx))
|
||||
throw bignum_error ("CBigNum::ToString() : BN_div failed");
|
||||
|
||||
bn = dv;
|
||||
unsigned int c = rem.getuint ();
|
||||
str += "0123456789abcdef"[c];
|
||||
}
|
||||
|
||||
if (BN_is_negative (this))
|
||||
str += "-";
|
||||
|
||||
reverse (str.begin (), str.end ());
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string CBigNum::GetHex () const
|
||||
{
|
||||
return ToString (16);
|
||||
}
|
||||
|
||||
bool CBigNum::operator! () const
|
||||
{
|
||||
return BN_is_zero (this);
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator+= (const CBigNum& b)
|
||||
{
|
||||
if (!BN_add (this, this, &b))
|
||||
throw bignum_error ("CBigNum::operator+= : BN_add failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator-= (const CBigNum& b)
|
||||
{
|
||||
*this = *this - b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator*= (const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
|
||||
if (!BN_mul (this, this, &b, pctx))
|
||||
throw bignum_error ("CBigNum::operator*= : BN_mul failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator/= (const CBigNum& b)
|
||||
{
|
||||
*this = *this / b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator%= (const CBigNum& b)
|
||||
{
|
||||
*this = *this % b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator<<= (unsigned int shift)
|
||||
{
|
||||
if (!BN_lshift (this, this, shift))
|
||||
throw bignum_error ("CBigNum:operator<<= : BN_lshift failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator>>= (unsigned int shift)
|
||||
{
|
||||
// Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
|
||||
// if built on ubuntu 9.04 or 9.10, probably depends on version of openssl
|
||||
CBigNum a = 1;
|
||||
a <<= shift;
|
||||
|
||||
if (BN_cmp (&a, this) > 0)
|
||||
{
|
||||
*this = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!BN_rshift (this, this, shift))
|
||||
throw bignum_error ("CBigNum:operator>>= : BN_rshift failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
CBigNum& CBigNum::operator++ ()
|
||||
{
|
||||
// prefix operator
|
||||
if (!BN_add (this, this, BN_value_one ()))
|
||||
throw bignum_error ("CBigNum::operator++ : BN_add failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CBigNum CBigNum::operator++ (int)
|
||||
{
|
||||
// postfix operator
|
||||
const CBigNum ret = *this;
|
||||
++ (*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator-- ()
|
||||
{
|
||||
// prefix operator
|
||||
CBigNum r;
|
||||
|
||||
if (!BN_sub (&r, this, BN_value_one ()))
|
||||
throw bignum_error ("CBigNum::operator-- : BN_sub failed");
|
||||
|
||||
*this = r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CBigNum CBigNum::operator-- (int)
|
||||
{
|
||||
// postfix operator
|
||||
const CBigNum ret = *this;
|
||||
-- (*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CBigNum::setulong (unsigned long n)
|
||||
{
|
||||
if (!BN_set_word (this, n))
|
||||
throw bignum_error ("CBigNum conversion from unsigned long : BN_set_word failed");
|
||||
}
|
||||
|
||||
unsigned long CBigNum::getulong () const
|
||||
{
|
||||
return BN_get_word (this);
|
||||
}
|
||||
|
||||
const CBigNum operator+ (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CBigNum r;
|
||||
|
||||
if (!BN_add (&r, &a, &b))
|
||||
throw bignum_error ("CBigNum::operator+ : BN_add failed");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const CBigNum operator- (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CBigNum r;
|
||||
|
||||
if (!BN_sub (&r, &a, &b))
|
||||
throw bignum_error ("CBigNum::operator- : BN_sub failed");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const CBigNum operator- (const CBigNum& a)
|
||||
{
|
||||
CBigNum r (a);
|
||||
BN_set_negative (&r, !BN_is_negative (&r));
|
||||
return r;
|
||||
}
|
||||
|
||||
const CBigNum operator* (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum r;
|
||||
|
||||
if (!BN_mul (&r, &a, &b, pctx))
|
||||
throw bignum_error ("CBigNum::operator* : BN_mul failed");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const CBigNum operator/ (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum r;
|
||||
|
||||
if (!BN_div (&r, NULL, &a, &b, pctx))
|
||||
throw bignum_error ("CBigNum::operator/ : BN_div failed");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const CBigNum operator% (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum r;
|
||||
|
||||
if (!BN_mod (&r, &a, &b, pctx))
|
||||
throw bignum_error ("CBigNum::operator% : BN_div failed");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const CBigNum operator<< (const CBigNum& a, unsigned int shift)
|
||||
{
|
||||
CBigNum r;
|
||||
|
||||
if (!BN_lshift (&r, &a, shift))
|
||||
throw bignum_error ("CBigNum:operator<< : BN_lshift failed");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const CBigNum operator>> (const CBigNum& a, unsigned int shift)
|
||||
{
|
||||
CBigNum r = a;
|
||||
r >>= shift;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool operator== (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
return (BN_cmp (&a, &b) == 0);
|
||||
}
|
||||
|
||||
bool operator!= (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
return (BN_cmp (&a, &b) != 0);
|
||||
}
|
||||
|
||||
bool operator<= (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
return (BN_cmp (&a, &b) <= 0);
|
||||
}
|
||||
|
||||
bool operator>= (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
return (BN_cmp (&a, &b) >= 0);
|
||||
}
|
||||
|
||||
bool operator< (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
return (BN_cmp (&a, &b) < 0);
|
||||
}
|
||||
|
||||
bool operator> (const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
return (BN_cmp (&a, &b) > 0);
|
||||
}
|
||||
|
||||
#if (ULONG_MAX > UINT_MAX)
|
||||
|
||||
int BN_add_word64 (BIGNUM* bn, uint64 word)
|
||||
{
|
||||
return BN_add_word (bn, word);
|
||||
}
|
||||
|
||||
int BN_sub_word64 (BIGNUM* bn, uint64 word)
|
||||
{
|
||||
return BN_sub_word (bn, word);
|
||||
}
|
||||
|
||||
int BN_mul_word64 (BIGNUM* bn, uint64 word)
|
||||
{
|
||||
return BN_mul_word (bn, word);
|
||||
}
|
||||
|
||||
uint64 BN_div_word64 (BIGNUM* bn, uint64 word)
|
||||
{
|
||||
return BN_div_word (bn, word);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int BN_add_word64 (BIGNUM* a, uint64 w)
|
||||
{
|
||||
CBigNum bn (w);
|
||||
return BN_add (a, &bn, a);
|
||||
}
|
||||
|
||||
int BN_sub_word64 (BIGNUM* a, uint64 w)
|
||||
{
|
||||
CBigNum bn (w);
|
||||
return BN_sub (a, &bn, a);
|
||||
}
|
||||
|
||||
int BN_mul_word64 (BIGNUM* a, uint64 w)
|
||||
{
|
||||
CBigNum bn (w);
|
||||
CAutoBN_CTX ctx;
|
||||
return BN_mul (a, &bn, a, ctx);
|
||||
}
|
||||
|
||||
uint64 BN_div_word64 (BIGNUM* a, uint64 w)
|
||||
{
|
||||
CBigNum bn (w);
|
||||
CAutoBN_CTX ctx;
|
||||
return (BN_div (a, NULL, a, &bn, ctx) == 1) ? 0 : ((uint64) - 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
171
src/ripple_data/crypto/ripple_CBigNum.h
Normal file
171
src/ripple_data/crypto/ripple_CBigNum.h
Normal file
@@ -0,0 +1,171 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef RIPPLE_CBIGNUM_H
|
||||
#define RIPPLE_CBIGNUM_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class bignum_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit bignum_error (const std::string& str) : std::runtime_error (str) {}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class CAutoBN_CTX
|
||||
{
|
||||
private:
|
||||
CAutoBN_CTX (const CAutoBN_CTX&); // no implementation
|
||||
CAutoBN_CTX& operator= (const CAutoBN_CTX&); // no implementation
|
||||
|
||||
protected:
|
||||
BN_CTX* pctx;
|
||||
CAutoBN_CTX& operator= (BN_CTX* pnew)
|
||||
{
|
||||
pctx = pnew;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
CAutoBN_CTX ()
|
||||
{
|
||||
pctx = BN_CTX_new ();
|
||||
|
||||
if (pctx == NULL)
|
||||
throw bignum_error ("CAutoBN_CTX : BN_CTX_new() returned NULL");
|
||||
}
|
||||
|
||||
~CAutoBN_CTX ()
|
||||
{
|
||||
if (pctx != NULL)
|
||||
BN_CTX_free (pctx);
|
||||
}
|
||||
|
||||
operator BN_CTX* ()
|
||||
{
|
||||
return pctx;
|
||||
}
|
||||
BN_CTX& operator* ()
|
||||
{
|
||||
return *pctx;
|
||||
}
|
||||
BN_CTX** operator& ()
|
||||
{
|
||||
return &pctx;
|
||||
}
|
||||
bool operator! ()
|
||||
{
|
||||
return (pctx == NULL);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// VFALCO TODO figure out a way to remove the dependency on openssl in the
|
||||
// header. Maybe rewrite this to use cryptopp.
|
||||
|
||||
class CBigNum : public BIGNUM
|
||||
{
|
||||
public:
|
||||
CBigNum ();
|
||||
CBigNum (const CBigNum& b);
|
||||
CBigNum& operator= (const CBigNum& b);
|
||||
CBigNum (char n);
|
||||
CBigNum (short n);
|
||||
CBigNum (int n);
|
||||
CBigNum (long n);
|
||||
CBigNum (int64 n);
|
||||
CBigNum (unsigned char n);
|
||||
CBigNum (unsigned short n);
|
||||
CBigNum (unsigned int n);
|
||||
CBigNum (uint64 n);
|
||||
explicit CBigNum (uint256 n);
|
||||
explicit CBigNum (Blob const& vch);
|
||||
~CBigNum ();
|
||||
|
||||
void setuint (unsigned int n);
|
||||
unsigned int getuint () const;
|
||||
int getint () const;
|
||||
void setint64 (int64 n);
|
||||
uint64 getuint64 () const;
|
||||
void setuint64 (uint64 n);
|
||||
void setuint256 (uint256 const& n);
|
||||
uint256 getuint256 ();
|
||||
void setvch (Blob const& vch);
|
||||
Blob getvch () const;
|
||||
CBigNum& SetCompact (unsigned int nCompact);
|
||||
unsigned int GetCompact () const;
|
||||
void SetHex (const std::string& str);
|
||||
std::string ToString (int nBase = 10) const;
|
||||
std::string GetHex () const;
|
||||
bool operator! () const;
|
||||
CBigNum& operator+= (const CBigNum& b);
|
||||
CBigNum& operator-= (const CBigNum& b);
|
||||
CBigNum& operator*= (const CBigNum& b);
|
||||
CBigNum& operator/= (const CBigNum& b);
|
||||
CBigNum& operator%= (const CBigNum& b);
|
||||
CBigNum& operator<<= (unsigned int shift);
|
||||
CBigNum& operator>>= (unsigned int shift);
|
||||
CBigNum& operator++ ();
|
||||
CBigNum& operator-- ();
|
||||
const CBigNum operator++ (int);
|
||||
const CBigNum operator-- (int);
|
||||
|
||||
friend inline const CBigNum operator- (const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator/ (const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator% (const CBigNum& a, const CBigNum& b);
|
||||
|
||||
private:
|
||||
// private because the size of an unsigned long varies by platform
|
||||
|
||||
void setulong (unsigned long n);
|
||||
unsigned long getulong () const;
|
||||
};
|
||||
|
||||
const CBigNum operator+ (const CBigNum& a, const CBigNum& b);
|
||||
const CBigNum operator- (const CBigNum& a, const CBigNum& b);
|
||||
const CBigNum operator- (const CBigNum& a);
|
||||
const CBigNum operator* (const CBigNum& a, const CBigNum& b);
|
||||
const CBigNum operator/ (const CBigNum& a, const CBigNum& b);
|
||||
const CBigNum operator% (const CBigNum& a, const CBigNum& b);
|
||||
const CBigNum operator<< (const CBigNum& a, unsigned int shift);
|
||||
const CBigNum operator>> (const CBigNum& a, unsigned int shift);
|
||||
|
||||
bool operator== (const CBigNum& a, const CBigNum& b);
|
||||
bool operator!= (const CBigNum& a, const CBigNum& b);
|
||||
bool operator<= (const CBigNum& a, const CBigNum& b);
|
||||
bool operator>= (const CBigNum& a, const CBigNum& b);
|
||||
bool operator< (const CBigNum& a, const CBigNum& b);
|
||||
bool operator> (const CBigNum& a, const CBigNum& b);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// VFALCO NOTE this seems as good a place as any for this.
|
||||
|
||||
// Here's the old implementation using macros, in case something broke
|
||||
//#if (ULONG_MAX > UINT_MAX)
|
||||
//#define BN_add_word64(bn, word) BN_add_word(bn, word)
|
||||
//#define BN_sub_word64(bn, word) BN_sub_word(bn, word)
|
||||
//#define BN_mul_word64(bn, word) BN_mul_word(bn, word)
|
||||
//#define BN_div_word64(bn, word) BN_div_word(bn, word)
|
||||
//#endif
|
||||
|
||||
// VFALCO I believe only STAmount uses these
|
||||
extern int BN_add_word64 (BIGNUM* a, uint64 w);
|
||||
extern int BN_sub_word64 (BIGNUM* a, uint64 w);
|
||||
extern int BN_mul_word64 (BIGNUM* a, uint64 w);
|
||||
extern uint64 BN_div_word64 (BIGNUM* a, uint64 w);
|
||||
|
||||
#endif
|
||||
|
||||
// vim:ts=4
|
||||
52
src/ripple_data/crypto/ripple_CKey.cpp
Normal file
52
src/ripple_data/crypto/ripple_CKey.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
// VFALCO TODO move inlined stuff from CKey into here
|
||||
|
||||
class CKeyTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
CKeyTests () : UnitTest ("CKey", "ripple")
|
||||
{
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
beginTestCase ("determinism");
|
||||
|
||||
uint128 seed1, seed2;
|
||||
seed1.SetHex ("71ED064155FFADFA38782C5E0158CB26");
|
||||
seed2.SetHex ("CF0C3BE4485961858C4198515AE5B965");
|
||||
CKey root1 (seed1), root2 (seed2);
|
||||
|
||||
uint256 priv1, priv2;
|
||||
root1.GetPrivateKeyU (priv1);
|
||||
root2.GetPrivateKeyU (priv2);
|
||||
|
||||
unexpected (priv1.GetHex () != "7CFBA64F771E93E817E15039215430B53F7401C34931D111EAB3510B22DBB0D8",
|
||||
"Incorrect private key for generator");
|
||||
|
||||
unexpected (priv2.GetHex () != "98BC2EACB26EB021D1A6293C044D88BA2F0B6729A2772DEEBF2E21A263C1740B",
|
||||
"Incorrect private key for generator");
|
||||
|
||||
RippleAddress nSeed;
|
||||
nSeed.setSeed (seed1);
|
||||
|
||||
unexpected (nSeed.humanSeed () != "shHM53KPZ87Gwdqarm1bAmPeXg8Tn",
|
||||
"Incorrect human seed");
|
||||
|
||||
unexpected (nSeed.humanSeed1751 () != "MAD BODY ACE MINT OKAY HUB WHAT DATA SACK FLAT DANA MATH",
|
||||
"Incorrect 1751 seed");
|
||||
}
|
||||
};
|
||||
|
||||
static CKeyTests cKeyTests;
|
||||
304
src/ripple_data/crypto/ripple_CKey.h
Normal file
304
src/ripple_data/crypto/ripple_CKey.h
Normal file
@@ -0,0 +1,304 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef RIPPLE_CKEY_H
|
||||
#define RIPPLE_CKEY_H
|
||||
|
||||
// secp256k1:
|
||||
// const unsigned int PRIVATE_KEY_SIZE = 279;
|
||||
// const unsigned int PUBLIC_KEY_SIZE = 65; // but we don't use full keys
|
||||
// const unsigned int COMPUB_KEY_SIZE = 33;
|
||||
// const unsigned int SIGNATURE_SIZE = 72;
|
||||
//
|
||||
// see www.keylength.com
|
||||
// script supports up to 75 for single byte push
|
||||
|
||||
// VFALCO NOTE this is unused
|
||||
/*
|
||||
int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
|
||||
{
|
||||
int okay = 0;
|
||||
BN_CTX *ctx = NULL;
|
||||
EC_POINT *pub_key = NULL;
|
||||
|
||||
if (!eckey) return 0;
|
||||
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
|
||||
if ((ctx = BN_CTX_new()) == NULL)
|
||||
goto err;
|
||||
|
||||
pub_key = EC_POINT_new(group);
|
||||
|
||||
if (pub_key == NULL)
|
||||
goto err;
|
||||
|
||||
if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
|
||||
goto err;
|
||||
|
||||
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
|
||||
EC_KEY_set_private_key(eckey, priv_key);
|
||||
EC_KEY_set_public_key(eckey, pub_key);
|
||||
|
||||
okay = 1;
|
||||
|
||||
err:
|
||||
|
||||
if (pub_key)
|
||||
EC_POINT_free(pub_key);
|
||||
if (ctx != NULL)
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
return (okay);
|
||||
}
|
||||
*/
|
||||
|
||||
class key_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit key_error (const std::string& str) : std::runtime_error (str) {}
|
||||
};
|
||||
|
||||
class CKey
|
||||
{
|
||||
protected:
|
||||
EC_KEY* pkey;
|
||||
bool fSet;
|
||||
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<CKey> pointer;
|
||||
|
||||
CKey ()
|
||||
{
|
||||
pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
if (pkey == NULL)
|
||||
throw key_error ("CKey::CKey() : EC_KEY_new_by_curve_name failed");
|
||||
|
||||
fSet = false;
|
||||
}
|
||||
|
||||
CKey (const CKey& b)
|
||||
{
|
||||
pkey = EC_KEY_dup (b.pkey);
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
if (pkey == NULL)
|
||||
throw key_error ("CKey::CKey(const CKey&) : EC_KEY_dup failed");
|
||||
|
||||
fSet = b.fSet;
|
||||
}
|
||||
|
||||
CKey& operator= (const CKey& b)
|
||||
{
|
||||
if (!EC_KEY_copy (pkey, b.pkey))
|
||||
throw key_error ("CKey::operator=(const CKey&) : EC_KEY_copy failed");
|
||||
|
||||
fSet = b.fSet;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
|
||||
~CKey ()
|
||||
{
|
||||
EC_KEY_free (pkey);
|
||||
}
|
||||
|
||||
|
||||
static uint128 PassPhraseToKey (const std::string& passPhrase);
|
||||
static EC_KEY* GenerateRootDeterministicKey (const uint128& passPhrase);
|
||||
static EC_KEY* GenerateRootPubKey (BIGNUM* pubGenerator);
|
||||
static EC_KEY* GeneratePublicDeterministicKey (const RippleAddress& generator, int n);
|
||||
static EC_KEY* GeneratePrivateDeterministicKey (const RippleAddress& family, const BIGNUM* rootPriv, int n);
|
||||
static EC_KEY* GeneratePrivateDeterministicKey (const RippleAddress& family, uint256 const& rootPriv, int n);
|
||||
|
||||
CKey (const uint128& passPhrase) : fSet (false)
|
||||
{
|
||||
pkey = GenerateRootDeterministicKey (passPhrase);
|
||||
fSet = true;
|
||||
assert (pkey);
|
||||
}
|
||||
|
||||
CKey (const RippleAddress& generator, int n) : fSet (false)
|
||||
{
|
||||
// public deterministic key
|
||||
pkey = GeneratePublicDeterministicKey (generator, n);
|
||||
fSet = true;
|
||||
assert (pkey);
|
||||
}
|
||||
|
||||
CKey (const RippleAddress& base, const BIGNUM* rootPrivKey, int n) : fSet (false)
|
||||
{
|
||||
// private deterministic key
|
||||
pkey = GeneratePrivateDeterministicKey (base, rootPrivKey, n);
|
||||
fSet = true;
|
||||
assert (pkey);
|
||||
}
|
||||
|
||||
CKey (uint256 const& privateKey) : pkey (NULL), fSet (false)
|
||||
{
|
||||
// XXX Broken pkey is null.
|
||||
SetPrivateKeyU (privateKey);
|
||||
}
|
||||
|
||||
#if 0
|
||||
CKey (const RippleAddress& masterKey, int keyNum, bool isPublic) : pkey (NULL), fSet (false)
|
||||
{
|
||||
if (isPublic)
|
||||
SetPubSeq (masterKey, keyNum);
|
||||
else
|
||||
SetPrivSeq (masterKey, keyNum); // broken, need seed
|
||||
|
||||
fSet = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsNull () const
|
||||
{
|
||||
return !fSet;
|
||||
}
|
||||
|
||||
void MakeNewKey ()
|
||||
{
|
||||
if (!EC_KEY_generate_key (pkey))
|
||||
throw key_error ("CKey::MakeNewKey() : EC_KEY_generate_key failed");
|
||||
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
fSet = true;
|
||||
}
|
||||
|
||||
// XXX Still used!
|
||||
BIGNUM* GetSecretBN () const
|
||||
{
|
||||
// DEPRECATED
|
||||
return BN_dup (EC_KEY_get0_private_key (pkey));
|
||||
}
|
||||
|
||||
void GetPrivateKeyU (uint256& privKey)
|
||||
{
|
||||
const BIGNUM* bn = EC_KEY_get0_private_key (pkey);
|
||||
|
||||
if (bn == NULL)
|
||||
throw key_error ("CKey::GetPrivateKeyU: EC_KEY_get0_private_key failed");
|
||||
|
||||
privKey.zero ();
|
||||
BN_bn2bin (bn, privKey.begin () + (privKey.size () - BN_num_bytes (bn)));
|
||||
}
|
||||
|
||||
bool SetPrivateKeyU (uint256 const& key, bool bThrow = false)
|
||||
{
|
||||
// XXX Broken if pkey is not set.
|
||||
BIGNUM* bn = BN_bin2bn (key.begin (), key.size (), NULL);
|
||||
bool bSuccess = !!EC_KEY_set_private_key (pkey, bn);
|
||||
|
||||
BN_clear_free (bn);
|
||||
|
||||
if (bSuccess)
|
||||
{
|
||||
fSet = true;
|
||||
}
|
||||
else if (bThrow)
|
||||
{
|
||||
throw key_error ("CKey::SetPrivateKeyU: EC_KEY_set_private_key failed");
|
||||
}
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
bool SetPubKey (const void* ptr, size_t len)
|
||||
{
|
||||
const unsigned char* pbegin = static_cast<const unsigned char*> (ptr);
|
||||
|
||||
if (!o2i_ECPublicKey (&pkey, &pbegin, len))
|
||||
return false;
|
||||
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
fSet = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetPubKey (Blob const& vchPubKey)
|
||||
{
|
||||
return SetPubKey (&vchPubKey[0], vchPubKey.size ());
|
||||
}
|
||||
|
||||
bool SetPubKey (const std::string& pubKey)
|
||||
{
|
||||
return SetPubKey (pubKey.data (), pubKey.size ());
|
||||
}
|
||||
|
||||
Blob GetPubKey () const
|
||||
{
|
||||
unsigned int nSize = i2o_ECPublicKey (pkey, NULL);
|
||||
assert (nSize <= 33);
|
||||
|
||||
if (!nSize)
|
||||
throw key_error ("CKey::GetPubKey() : i2o_ECPublicKey failed");
|
||||
|
||||
Blob vchPubKey (33, 0);
|
||||
unsigned char* pbegin = &vchPubKey[0];
|
||||
|
||||
if (i2o_ECPublicKey (pkey, &pbegin) != nSize)
|
||||
throw key_error ("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
|
||||
|
||||
assert (vchPubKey.size () <= 33);
|
||||
return vchPubKey;
|
||||
}
|
||||
|
||||
bool Sign (uint256 const& hash, Blob& vchSig)
|
||||
{
|
||||
unsigned char pchSig[10000];
|
||||
unsigned int nSize = 0;
|
||||
|
||||
vchSig.clear ();
|
||||
|
||||
if (!ECDSA_sign (0, (unsigned char*)hash.begin (), hash.size (), pchSig, &nSize, pkey))
|
||||
return false;
|
||||
|
||||
vchSig.resize (nSize);
|
||||
memcpy (&vchSig[0], pchSig, nSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verify (uint256 const& hash, const void* sig, size_t sigLen) const
|
||||
{
|
||||
// -1 = error, 0 = bad sig, 1 = good
|
||||
if (ECDSA_verify (0, hash.begin (), hash.size (), (const unsigned char*) sig, sigLen, pkey) != 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verify (uint256 const& hash, Blob const& vchSig) const
|
||||
{
|
||||
return Verify (hash, &vchSig[0], vchSig.size ());
|
||||
}
|
||||
|
||||
bool Verify (uint256 const& hash, const std::string& sig) const
|
||||
{
|
||||
return Verify (hash, sig.data (), sig.size ());
|
||||
}
|
||||
|
||||
// ECIES functions. These throw on failure
|
||||
|
||||
// returns a 32-byte secret unique to these two keys. At least one private key must be known.
|
||||
void getECIESSecret (CKey& otherKey, uint256& enc_key, uint256& hmac_key);
|
||||
|
||||
// encrypt/decrypt functions with integrity checking.
|
||||
// Note that the other side must somehow know what keys to use
|
||||
Blob encryptECIES (CKey& otherKey, Blob const& plaintext);
|
||||
Blob decryptECIES (CKey& otherKey, Blob const& ciphertext);
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
348
src/ripple_data/crypto/ripple_CKeyDeterministic.cpp
Normal file
348
src/ripple_data/crypto/ripple_CKeyDeterministic.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// #define EC_DEBUG
|
||||
|
||||
// Functions to add CKey support for deterministic EC keys
|
||||
|
||||
// <-- seed
|
||||
uint128 CKey::PassPhraseToKey (const std::string& passPhrase)
|
||||
{
|
||||
Serializer s;
|
||||
|
||||
s.addRaw (passPhrase);
|
||||
uint256 hash256 = s.getSHA512Half ();
|
||||
uint128 ret (hash256);
|
||||
|
||||
s.secureErase ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// --> seed
|
||||
// <-- private root generator + public root generator
|
||||
EC_KEY* CKey::GenerateRootDeterministicKey (const uint128& seed)
|
||||
{
|
||||
BN_CTX* ctx = BN_CTX_new ();
|
||||
|
||||
if (!ctx) return NULL;
|
||||
|
||||
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
|
||||
|
||||
if (!pkey)
|
||||
{
|
||||
BN_CTX_free (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
BIGNUM* order = BN_new ();
|
||||
|
||||
if (!order)
|
||||
{
|
||||
BN_CTX_free (ctx);
|
||||
EC_KEY_free (pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!EC_GROUP_get_order (EC_KEY_get0_group (pkey), order, ctx))
|
||||
{
|
||||
assert (false);
|
||||
BN_free (order);
|
||||
EC_KEY_free (pkey);
|
||||
BN_CTX_free (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BIGNUM* privKey = NULL;
|
||||
int seq = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// private key must be non-zero and less than the curve's order
|
||||
Serializer s ((128 + 32) / 8);
|
||||
s.add128 (seed);
|
||||
s.add32 (seq++);
|
||||
uint256 root = s.getSHA512Half ();
|
||||
s.secureErase ();
|
||||
privKey = BN_bin2bn ((const unsigned char*) &root, sizeof (root), privKey);
|
||||
|
||||
if (privKey == NULL)
|
||||
{
|
||||
EC_KEY_free (pkey);
|
||||
BN_free (order);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
root.zero ();
|
||||
}
|
||||
while (BN_is_zero (privKey) || (BN_cmp (privKey, order) >= 0));
|
||||
|
||||
BN_free (order);
|
||||
|
||||
if (!EC_KEY_set_private_key (pkey, privKey))
|
||||
{
|
||||
// set the random point as the private key
|
||||
assert (false);
|
||||
EC_KEY_free (pkey);
|
||||
BN_clear_free (privKey);
|
||||
BN_CTX_free (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_POINT* pubKey = EC_POINT_new (EC_KEY_get0_group (pkey));
|
||||
|
||||
if (!EC_POINT_mul (EC_KEY_get0_group (pkey), pubKey, privKey, NULL, NULL, ctx))
|
||||
{
|
||||
// compute the corresponding public key point
|
||||
assert (false);
|
||||
BN_clear_free (privKey);
|
||||
EC_POINT_free (pubKey);
|
||||
EC_KEY_free (pkey);
|
||||
BN_CTX_free (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BN_clear_free (privKey);
|
||||
|
||||
if (!EC_KEY_set_public_key (pkey, pubKey))
|
||||
{
|
||||
assert (false);
|
||||
EC_POINT_free (pubKey);
|
||||
EC_KEY_free (pkey);
|
||||
BN_CTX_free (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_POINT_free (pubKey);
|
||||
|
||||
BN_CTX_free (ctx);
|
||||
|
||||
#ifdef EC_DEBUG
|
||||
assert (EC_KEY_check_key (pkey) == 1); // CAUTION: This check is *very* expensive
|
||||
#endif
|
||||
return pkey;
|
||||
}
|
||||
|
||||
// Take ripple address.
|
||||
// --> root public generator (consumes)
|
||||
// <-- root public generator in EC format
|
||||
EC_KEY* CKey::GenerateRootPubKey (BIGNUM* pubGenerator)
|
||||
{
|
||||
if (pubGenerator == NULL)
|
||||
{
|
||||
assert (false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
|
||||
|
||||
if (!pkey)
|
||||
{
|
||||
BN_free (pubGenerator);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
EC_POINT* pubPoint = EC_POINT_bn2point (EC_KEY_get0_group (pkey), pubGenerator, NULL, NULL);
|
||||
BN_free (pubGenerator);
|
||||
|
||||
if (!pubPoint)
|
||||
{
|
||||
assert (false);
|
||||
EC_KEY_free (pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!EC_KEY_set_public_key (pkey, pubPoint))
|
||||
{
|
||||
assert (false);
|
||||
EC_POINT_free (pubPoint);
|
||||
EC_KEY_free (pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_POINT_free (pubPoint);
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
// --> public generator
|
||||
static BIGNUM* makeHash (const RippleAddress& pubGen, int seq, BIGNUM* order)
|
||||
{
|
||||
int subSeq = 0;
|
||||
BIGNUM* ret = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
Serializer s ((33 * 8 + 32 + 32) / 8);
|
||||
s.addRaw (pubGen.getGenerator ());
|
||||
s.add32 (seq);
|
||||
s.add32 (subSeq++);
|
||||
uint256 root = s.getSHA512Half ();
|
||||
s.secureErase ();
|
||||
ret = BN_bin2bn ((const unsigned char*) &root, sizeof (root), ret);
|
||||
|
||||
if (!ret) return NULL;
|
||||
}
|
||||
while (BN_is_zero (ret) || (BN_cmp (ret, order) >= 0));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// --> public generator
|
||||
EC_KEY* CKey::GeneratePublicDeterministicKey (const RippleAddress& pubGen, int seq)
|
||||
{
|
||||
// publicKey(n) = rootPublicKey EC_POINT_+ Hash(pubHash|seq)*point
|
||||
EC_KEY* rootKey = CKey::GenerateRootPubKey (pubGen.getGeneratorBN ());
|
||||
const EC_POINT* rootPubKey = EC_KEY_get0_public_key (rootKey);
|
||||
BN_CTX* ctx = BN_CTX_new ();
|
||||
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
|
||||
EC_POINT* newPoint = 0;
|
||||
BIGNUM* order = 0;
|
||||
BIGNUM* hash = 0;
|
||||
bool success = true;
|
||||
|
||||
if (!ctx || !pkey) success = false;
|
||||
|
||||
if (success)
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
if (success)
|
||||
{
|
||||
newPoint = EC_POINT_new (EC_KEY_get0_group (pkey));
|
||||
|
||||
if (!newPoint) success = false;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
order = BN_new ();
|
||||
|
||||
if (!order || !EC_GROUP_get_order (EC_KEY_get0_group (pkey), order, ctx))
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Calculate the private additional key.
|
||||
if (success)
|
||||
{
|
||||
hash = makeHash (pubGen, seq, order);
|
||||
|
||||
if (!hash) success = false;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Calculate the corresponding public key.
|
||||
EC_POINT_mul (EC_KEY_get0_group (pkey), newPoint, hash, NULL, NULL, ctx);
|
||||
|
||||
// Add the master public key and set.
|
||||
EC_POINT_add (EC_KEY_get0_group (pkey), newPoint, newPoint, rootPubKey, ctx);
|
||||
EC_KEY_set_public_key (pkey, newPoint);
|
||||
}
|
||||
|
||||
if (order) BN_free (order);
|
||||
|
||||
if (hash) BN_free (hash);
|
||||
|
||||
if (newPoint) EC_POINT_free (newPoint);
|
||||
|
||||
if (ctx) BN_CTX_free (ctx);
|
||||
|
||||
if (rootKey) EC_KEY_free (rootKey);
|
||||
|
||||
if (pkey && !success) EC_KEY_free (pkey);
|
||||
|
||||
return success ? pkey : NULL;
|
||||
}
|
||||
|
||||
EC_KEY* CKey::GeneratePrivateDeterministicKey (const RippleAddress& pubGen, uint256 const& u, int seq)
|
||||
{
|
||||
CBigNum bn (u);
|
||||
return GeneratePrivateDeterministicKey (pubGen, static_cast<BIGNUM*> (&bn), seq);
|
||||
}
|
||||
|
||||
// --> root private key
|
||||
EC_KEY* CKey::GeneratePrivateDeterministicKey (const RippleAddress& pubGen, const BIGNUM* rootPrivKey, int seq)
|
||||
{
|
||||
// privateKey(n) = (rootPrivateKey + Hash(pubHash|seq)) % order
|
||||
BN_CTX* ctx = BN_CTX_new ();
|
||||
|
||||
if (ctx == NULL) return NULL;
|
||||
|
||||
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
|
||||
|
||||
if (pkey == NULL)
|
||||
{
|
||||
BN_CTX_free (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
BIGNUM* order = BN_new ();
|
||||
|
||||
if (order == NULL)
|
||||
{
|
||||
BN_CTX_free (ctx);
|
||||
EC_KEY_free (pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!EC_GROUP_get_order (EC_KEY_get0_group (pkey), order, ctx))
|
||||
{
|
||||
BN_free (order);
|
||||
BN_CTX_free (ctx);
|
||||
EC_KEY_free (pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// calculate the private additional key
|
||||
BIGNUM* privKey = makeHash (pubGen, seq, order);
|
||||
|
||||
if (privKey == NULL)
|
||||
{
|
||||
BN_free (order);
|
||||
BN_CTX_free (ctx);
|
||||
EC_KEY_free (pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// calculate the final private key
|
||||
BN_mod_add (privKey, privKey, rootPrivKey, order, ctx);
|
||||
BN_free (order);
|
||||
EC_KEY_set_private_key (pkey, privKey);
|
||||
|
||||
// compute the corresponding public key
|
||||
EC_POINT* pubKey = EC_POINT_new (EC_KEY_get0_group (pkey));
|
||||
|
||||
if (!pubKey)
|
||||
{
|
||||
BN_clear_free (privKey);
|
||||
BN_CTX_free (ctx);
|
||||
EC_KEY_free (pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (EC_POINT_mul (EC_KEY_get0_group (pkey), pubKey, privKey, NULL, NULL, ctx) == 0)
|
||||
{
|
||||
BN_clear_free (privKey);
|
||||
EC_POINT_free (pubKey);
|
||||
EC_KEY_free (pkey);
|
||||
BN_CTX_free (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BN_clear_free (privKey);
|
||||
EC_KEY_set_public_key (pkey, pubKey);
|
||||
|
||||
EC_POINT_free (pubKey);
|
||||
BN_CTX_free (ctx);
|
||||
|
||||
return pkey;
|
||||
}
|
||||
316
src/ripple_data/crypto/ripple_CKeyECIES.cpp
Normal file
316
src/ripple_data/crypto/ripple_CKeyECIES.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// ECIES uses elliptic curve keys to send an encrypted message.
|
||||
|
||||
// A shared secret is generated from one public key and one private key.
|
||||
// The same key results regardless of which key is public and which private.
|
||||
|
||||
// Anonymous messages can be sent by generating an ephemeral public/private
|
||||
// key pair, using that private key with the recipient's public key to
|
||||
// encrypt and publishing the ephemeral public key. Non-anonymous messages
|
||||
// can be sent by using your own private key with the recipient's public key.
|
||||
|
||||
// A random IV is used to encrypt the message and an HMAC is used to ensure
|
||||
// message integrity. If you need timestamps or need to tell the recipient
|
||||
// which key to use (his, yours, or ephemeral) you must add that data.
|
||||
// (Obviously, key information can't go in the encrypted portion anyway.)
|
||||
|
||||
// Our ciphertext is all encrypted except the IV. The encrypted data decodes as follows:
|
||||
// 1) IV (unencrypted)
|
||||
// 2) Encrypted: HMAC of original plaintext
|
||||
// 3) Encrypted: Original plaintext
|
||||
// 4) Encrypted: Rest of block/padding
|
||||
|
||||
// ECIES operations throw on any error such as a corrupt message or incorrect
|
||||
// key. They *must* be called in try/catch blocks.
|
||||
|
||||
// Algorithmic choices:
|
||||
#define ECIES_KEY_HASH SHA512 // Hash used to expand shared secret
|
||||
#define ECIES_KEY_LENGTH (512/8) // Size of expanded shared secret
|
||||
#define ECIES_MIN_SEC (128/8) // The minimum equivalent security
|
||||
#define ECIES_ENC_ALGO EVP_aes_256_cbc() // Encryption algorithm
|
||||
#define ECIES_ENC_KEY_TYPE uint256 // Type used to hold shared secret
|
||||
#define ECIES_ENC_KEY_SIZE (256/8) // Encryption key size
|
||||
#define ECIES_ENC_BLK_SIZE (128/8) // Encryption block size
|
||||
#define ECIES_ENC_IV_TYPE uint128 // Type used to hold IV
|
||||
#define ECIES_HMAC_ALGO EVP_sha256() // HMAC algorithm
|
||||
#define ECIES_HMAC_KEY_TYPE uint256 // Type used to hold HMAC key
|
||||
#define ECIES_HMAC_KEY_SIZE (256/8) // Size of HMAC key
|
||||
#define ECIES_HMAC_TYPE uint256 // Type used to hold HMAC value
|
||||
#define ECIES_HMAC_SIZE (256/8) // Size of HMAC value
|
||||
|
||||
void CKey::getECIESSecret (CKey& otherKey, ECIES_ENC_KEY_TYPE& enc_key, ECIES_HMAC_KEY_TYPE& hmac_key)
|
||||
{
|
||||
// Retrieve a secret generated from an EC key pair. At least one private key must be known.
|
||||
if (!pkey || !otherKey.pkey)
|
||||
throw std::runtime_error ("missing key");
|
||||
|
||||
EC_KEY* pubkey, *privkey;
|
||||
|
||||
if (EC_KEY_get0_private_key (pkey))
|
||||
{
|
||||
privkey = pkey;
|
||||
pubkey = otherKey.pkey;
|
||||
}
|
||||
else if (EC_KEY_get0_private_key (otherKey.pkey))
|
||||
{
|
||||
privkey = otherKey.pkey;
|
||||
pubkey = pkey;
|
||||
}
|
||||
else throw std::runtime_error ("no private key");
|
||||
|
||||
unsigned char rawbuf[512];
|
||||
int buflen = ECDH_compute_key (rawbuf, 512, EC_KEY_get0_public_key (pubkey), privkey, NULL);
|
||||
|
||||
if (buflen < ECIES_MIN_SEC)
|
||||
throw std::runtime_error ("ecdh key failed");
|
||||
|
||||
unsigned char hbuf[ECIES_KEY_LENGTH];
|
||||
ECIES_KEY_HASH (rawbuf, buflen, hbuf);
|
||||
memset (rawbuf, 0, ECIES_HMAC_KEY_SIZE);
|
||||
|
||||
assert ((ECIES_ENC_KEY_SIZE + ECIES_HMAC_KEY_SIZE) >= ECIES_KEY_LENGTH);
|
||||
memcpy (enc_key.begin (), hbuf, ECIES_ENC_KEY_SIZE);
|
||||
memcpy (hmac_key.begin (), hbuf + ECIES_ENC_KEY_SIZE, ECIES_HMAC_KEY_SIZE);
|
||||
memset (hbuf, 0, ECIES_KEY_LENGTH);
|
||||
}
|
||||
|
||||
static ECIES_HMAC_TYPE makeHMAC (const ECIES_HMAC_KEY_TYPE& secret, Blob const& data)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init (&ctx);
|
||||
|
||||
if (HMAC_Init_ex (&ctx, secret.begin (), ECIES_HMAC_KEY_SIZE, ECIES_HMAC_ALGO, NULL) != 1)
|
||||
{
|
||||
HMAC_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("init hmac");
|
||||
}
|
||||
|
||||
if (HMAC_Update (&ctx, & (data.front ()), data.size ()) != 1)
|
||||
{
|
||||
HMAC_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("update hmac");
|
||||
}
|
||||
|
||||
ECIES_HMAC_TYPE ret;
|
||||
unsigned int ml = ECIES_HMAC_SIZE;
|
||||
|
||||
if (HMAC_Final (&ctx, ret.begin (), &ml) != 1)
|
||||
{
|
||||
HMAC_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("finalize hmac");
|
||||
}
|
||||
|
||||
assert (ml == ECIES_HMAC_SIZE);
|
||||
HMAC_CTX_cleanup (&ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Blob CKey::encryptECIES (CKey& otherKey, Blob const& plaintext)
|
||||
{
|
||||
|
||||
ECIES_ENC_IV_TYPE iv;
|
||||
RandomNumbers::getInstance ().fillBytes (iv.begin (), ECIES_ENC_BLK_SIZE);
|
||||
|
||||
ECIES_ENC_KEY_TYPE secret;
|
||||
ECIES_HMAC_KEY_TYPE hmacKey;
|
||||
|
||||
getECIESSecret (otherKey, secret, hmacKey);
|
||||
ECIES_HMAC_TYPE hmac = makeHMAC (hmacKey, plaintext);
|
||||
hmacKey.zero ();
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init (&ctx);
|
||||
|
||||
if (EVP_EncryptInit_ex (&ctx, ECIES_ENC_ALGO, NULL, secret.begin (), iv.begin ()) != 1)
|
||||
{
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
secret.zero ();
|
||||
throw std::runtime_error ("init cipher ctx");
|
||||
}
|
||||
|
||||
secret.zero ();
|
||||
|
||||
Blob out (plaintext.size () + ECIES_HMAC_SIZE + ECIES_ENC_KEY_SIZE + ECIES_ENC_BLK_SIZE, 0);
|
||||
int len = 0, bytesWritten;
|
||||
|
||||
// output IV
|
||||
memcpy (& (out.front ()), iv.begin (), ECIES_ENC_BLK_SIZE);
|
||||
len = ECIES_ENC_BLK_SIZE;
|
||||
|
||||
// Encrypt/output HMAC
|
||||
bytesWritten = out.capacity () - len;
|
||||
assert (bytesWritten > 0);
|
||||
|
||||
if (EVP_EncryptUpdate (&ctx, & (out.front ()) + len, &bytesWritten, hmac.begin (), ECIES_HMAC_SIZE) < 0)
|
||||
{
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("");
|
||||
}
|
||||
|
||||
len += bytesWritten;
|
||||
|
||||
// encrypt/output plaintext
|
||||
bytesWritten = out.capacity () - len;
|
||||
assert (bytesWritten > 0);
|
||||
|
||||
if (EVP_EncryptUpdate (&ctx, & (out.front ()) + len, &bytesWritten, & (plaintext.front ()), plaintext.size ()) < 0)
|
||||
{
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("");
|
||||
}
|
||||
|
||||
len += bytesWritten;
|
||||
|
||||
// finalize
|
||||
bytesWritten = out.capacity () - len;
|
||||
|
||||
if (EVP_EncryptFinal_ex (&ctx, & (out.front ()) + len, &bytesWritten) < 0)
|
||||
{
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("encryption error");
|
||||
}
|
||||
|
||||
len += bytesWritten;
|
||||
|
||||
// Output contains: IV, encrypted HMAC, encrypted data, encrypted padding
|
||||
assert (len <= (plaintext.size () + ECIES_HMAC_SIZE + (2 * ECIES_ENC_BLK_SIZE)));
|
||||
assert (len >= (plaintext.size () + ECIES_HMAC_SIZE + ECIES_ENC_BLK_SIZE)); // IV, HMAC, data
|
||||
out.resize (len);
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
return out;
|
||||
}
|
||||
|
||||
Blob CKey::decryptECIES (CKey& otherKey, Blob const& ciphertext)
|
||||
{
|
||||
// minimum ciphertext = IV + HMAC + 1 block
|
||||
if (ciphertext.size () < ((2 * ECIES_ENC_BLK_SIZE) + ECIES_HMAC_SIZE) )
|
||||
throw std::runtime_error ("ciphertext too short");
|
||||
|
||||
// extract IV
|
||||
ECIES_ENC_IV_TYPE iv;
|
||||
memcpy (iv.begin (), & (ciphertext.front ()), ECIES_ENC_BLK_SIZE);
|
||||
|
||||
// begin decrypting
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init (&ctx);
|
||||
|
||||
ECIES_ENC_KEY_TYPE secret;
|
||||
ECIES_HMAC_KEY_TYPE hmacKey;
|
||||
getECIESSecret (otherKey, secret, hmacKey);
|
||||
|
||||
if (EVP_DecryptInit_ex (&ctx, ECIES_ENC_ALGO, NULL, secret.begin (), iv.begin ()) != 1)
|
||||
{
|
||||
secret.zero ();
|
||||
hmacKey.zero ();
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("unable to init cipher");
|
||||
}
|
||||
|
||||
// decrypt mac
|
||||
ECIES_HMAC_TYPE hmac;
|
||||
int outlen = ECIES_HMAC_SIZE;
|
||||
|
||||
if ( (EVP_DecryptUpdate (&ctx, hmac.begin (), &outlen,
|
||||
& (ciphertext.front ()) + ECIES_ENC_BLK_SIZE, ECIES_HMAC_SIZE + 1) != 1) || (outlen != ECIES_HMAC_SIZE) )
|
||||
{
|
||||
secret.zero ();
|
||||
hmacKey.zero ();
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("unable to extract hmac");
|
||||
}
|
||||
|
||||
// decrypt plaintext (after IV and encrypted mac)
|
||||
Blob plaintext (ciphertext.size () - ECIES_HMAC_SIZE - ECIES_ENC_BLK_SIZE);
|
||||
outlen = plaintext.size ();
|
||||
|
||||
if (EVP_DecryptUpdate (&ctx, & (plaintext.front ()), &outlen,
|
||||
& (ciphertext.front ()) + ECIES_ENC_BLK_SIZE + ECIES_HMAC_SIZE + 1,
|
||||
ciphertext.size () - ECIES_ENC_BLK_SIZE - ECIES_HMAC_SIZE - 1) != 1)
|
||||
{
|
||||
secret.zero ();
|
||||
hmacKey.zero ();
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("unable to extract plaintext");
|
||||
}
|
||||
|
||||
// decrypt padding
|
||||
int flen = 0;
|
||||
|
||||
if (EVP_DecryptFinal (&ctx, & (plaintext.front ()) + outlen, &flen) != 1)
|
||||
{
|
||||
secret.zero ();
|
||||
hmacKey.zero ();
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("plaintext had bad padding");
|
||||
}
|
||||
|
||||
plaintext.resize (flen + outlen);
|
||||
|
||||
// verify integrity
|
||||
if (hmac != makeHMAC (hmacKey, plaintext))
|
||||
{
|
||||
secret.zero ();
|
||||
hmacKey.zero ();
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
throw std::runtime_error ("plaintext had bad hmac");
|
||||
}
|
||||
|
||||
secret.zero ();
|
||||
hmacKey.zero ();
|
||||
|
||||
EVP_CIPHER_CTX_cleanup (&ctx);
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
bool checkECIES (void)
|
||||
{
|
||||
CKey senderPriv, recipientPriv, senderPub, recipientPub;
|
||||
|
||||
for (int i = 0; i < 30000; ++i)
|
||||
{
|
||||
if ((i % 100) == 0)
|
||||
{
|
||||
// generate new keys every 100 times
|
||||
// Log::out() << "new keys";
|
||||
senderPriv.MakeNewKey ();
|
||||
recipientPriv.MakeNewKey ();
|
||||
|
||||
if (!senderPub.SetPubKey (senderPriv.GetPubKey ()))
|
||||
throw std::runtime_error ("key error");
|
||||
|
||||
if (!recipientPub.SetPubKey (recipientPriv.GetPubKey ()))
|
||||
throw std::runtime_error ("key error");
|
||||
}
|
||||
|
||||
// generate message
|
||||
Blob message (4096);
|
||||
int msglen = i % 3000;
|
||||
|
||||
RandomNumbers::getInstance ().fillBytes (&message.front (), msglen);
|
||||
message.resize (msglen);
|
||||
|
||||
// encrypt message with sender's private key and recipient's public key
|
||||
Blob ciphertext = senderPriv.encryptECIES (recipientPub, message);
|
||||
|
||||
// decrypt message with recipient's private key and sender's public key
|
||||
Blob decrypt = recipientPriv.decryptECIES (senderPub, ciphertext);
|
||||
|
||||
if (decrypt != message)
|
||||
{
|
||||
assert (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Log::out() << "Msg(" << msglen << ") ok " << ciphertext.size();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
481
src/ripple_data/crypto/ripple_RFC1751.cpp
Normal file
481
src/ripple_data/crypto/ripple_RFC1751.cpp
Normal file
@@ -0,0 +1,481 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
//
|
||||
// RFC 1751 code converted to C++/Boost.
|
||||
//
|
||||
|
||||
char const* RFC1751::s_dictionary [2048] =
|
||||
{
|
||||
"A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
|
||||
"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA",
|
||||
"AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK",
|
||||
"ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE",
|
||||
"AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
|
||||
"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET",
|
||||
"BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO",
|
||||
"BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT",
|
||||
"BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
|
||||
"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY",
|
||||
"CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN",
|
||||
"DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG",
|
||||
"DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
|
||||
"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO",
|
||||
"ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE",
|
||||
"EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW",
|
||||
"FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
|
||||
"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP",
|
||||
"GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO",
|
||||
"GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD",
|
||||
"HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
|
||||
"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT",
|
||||
"HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE",
|
||||
"HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL",
|
||||
"INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", "ITS",
|
||||
"IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET", "JIG",
|
||||
"JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT", "KAY",
|
||||
"KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC",
|
||||
"LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", "LEG",
|
||||
"LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT", "LO",
|
||||
"LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG", "LYE",
|
||||
"MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY",
|
||||
"ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", "MOB",
|
||||
"MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG", "MUM",
|
||||
"MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED", "NEE",
|
||||
"NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON",
|
||||
"NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", "OAK",
|
||||
"OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", "OK",
|
||||
"OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", "OUR",
|
||||
"OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL",
|
||||
"PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", "PEN",
|
||||
"PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT", "PLY",
|
||||
"PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB", "PUG",
|
||||
"PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW",
|
||||
"RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", "RIO",
|
||||
"RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", "RUE",
|
||||
"RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM", "SAN",
|
||||
"SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW",
|
||||
"SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", "SLY",
|
||||
"SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY", "SUB",
|
||||
"SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN", "TAP",
|
||||
"TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM",
|
||||
"TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", "TOW",
|
||||
"TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP", "US",
|
||||
"USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS", "WAY",
|
||||
"WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK",
|
||||
"WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", "YEA",
|
||||
"YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT", "ACHE",
|
||||
"ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", "ADEN", "AFAR",
|
||||
"AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE", "AIDS", "AIRY", "AJAR",
|
||||
"AKIN", "ALAN", "ALEC", "ALGA", "ALIA", "ALLY", "ALMA", "ALOE", "ALSO",
|
||||
"ALTO", "ALUM", "ALVA", "AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS",
|
||||
"AMRA", "ANDY", "ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB",
|
||||
"ARCH", "AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS",
|
||||
"ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW",
|
||||
"AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL", "BAIT",
|
||||
"BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", "BAND", "BANE",
|
||||
"BANG", "BANK", "BARB", "BARD", "BARE", "BARK", "BARN", "BARR", "BASE",
|
||||
"BASH", "BASK", "BASS", "BATE", "BATH", "BAWD", "BAWL", "BEAD", "BEAK",
|
||||
"BEAM", "BEAN", "BEAR", "BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER",
|
||||
"BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT",
|
||||
"BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE",
|
||||
"BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB", "BLAT",
|
||||
"BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE", "BLUM", "BLUR",
|
||||
"BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY", "BOGY", "BOHR", "BOIL",
|
||||
"BOLD", "BOLO", "BOLT", "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN",
|
||||
"BONY", "BOOK", "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE",
|
||||
"BOSS", "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN",
|
||||
"BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF",
|
||||
"BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN",
|
||||
"BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE", "CADY",
|
||||
"CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", "CAME", "CANE",
|
||||
"CANT", "CARD", "CARE", "CARL", "CARR", "CART", "CASE", "CASH", "CASK",
|
||||
"CAST", "CAVE", "CEIL", "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT",
|
||||
"CHAW", "CHEF", "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB",
|
||||
"CHUG", "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY",
|
||||
"CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK",
|
||||
"COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA",
|
||||
"COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON", "COOT",
|
||||
"CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL", "CRAB", "CRAG",
|
||||
"CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD", "CUBA", "CUBE", "CUFF",
|
||||
"CULL", "CULT", "CUNY", "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS",
|
||||
"DADE", "DALE", "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK",
|
||||
"DARN", "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS",
|
||||
"DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM",
|
||||
"DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE",
|
||||
"DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT", "DISC",
|
||||
"DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL", "DOLT", "DOME",
|
||||
"DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE", "DOUG", "DOUR", "DOVE",
|
||||
"DOWN", "DRAB", "DRAG", "DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM",
|
||||
"DUAL", "DUCK", "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE",
|
||||
"DUNK", "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST",
|
||||
"EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA",
|
||||
"EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS",
|
||||
"ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT", "FADE",
|
||||
"FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG", "FARM", "FAST",
|
||||
"FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", "FEET", "FELL", "FELT",
|
||||
"FEND", "FERN", "FEST", "FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM",
|
||||
"FIND", "FINE", "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS",
|
||||
"FIVE", "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW",
|
||||
"FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY",
|
||||
"FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD",
|
||||
"FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", "FRAU",
|
||||
"FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM", "FUEL", "FULL",
|
||||
"FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS", "GAFF", "GAGE", "GAIL",
|
||||
"GAIN", "GAIT", "GALA", "GALE", "GALL", "GALT", "GAME", "GANG", "GARB",
|
||||
"GARY", "GASH", "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD",
|
||||
"GENE", "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT",
|
||||
"GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB",
|
||||
"GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT",
|
||||
"GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF", "GORE",
|
||||
"GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY", "GREG", "GREW",
|
||||
"GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW", "GRUB", "GULF", "GULL",
|
||||
"GUNK", "GURU", "GUSH", "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK",
|
||||
"HAIL", "HAIR", "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG",
|
||||
"HANK", "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE",
|
||||
"HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT",
|
||||
"HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB",
|
||||
"HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE", "HIGH",
|
||||
"HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS", "HIVE", "HOBO",
|
||||
"HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", "HOME", "HONE", "HONK",
|
||||
"HOOD", "HOOF", "HOOK", "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE",
|
||||
"HOWE", "HOWL", "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO",
|
||||
"HULK", "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE",
|
||||
"HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO",
|
||||
"IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM",
|
||||
"IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN", "JEFF",
|
||||
"JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", "JOAN", "JOBS",
|
||||
"JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE", "JOLT", "JOVE", "JUDD",
|
||||
"JUDE", "JUDO", "JUDY", "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO",
|
||||
"JURY", "JUST", "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE",
|
||||
"KEEL", "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL",
|
||||
"KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT",
|
||||
"KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE",
|
||||
"LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE", "LAMB",
|
||||
"LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS", "LAST", "LATE",
|
||||
"LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD", "LEAF", "LEAK", "LEAN",
|
||||
"LEAR", "LEEK", "LEER", "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK",
|
||||
"LESS", "LEST", "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES",
|
||||
"LIEU", "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB",
|
||||
"LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE",
|
||||
"LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA",
|
||||
"LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE", "LOSS",
|
||||
"LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE", "LUKE", "LULU",
|
||||
"LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH", "LUST", "LYLE", "LYNN",
|
||||
"LYON", "LYRA", "MACE", "MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE",
|
||||
"MALE", "MALI", "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE",
|
||||
"MARK", "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE",
|
||||
"MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET",
|
||||
"MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE",
|
||||
"MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND", "MINE",
|
||||
"MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE", "MITT", "MOAN",
|
||||
"MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", "MOLT", "MONA", "MONK",
|
||||
"MONT", "MOOD", "MOON", "MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS",
|
||||
"MOST", "MOTH", "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL",
|
||||
"MURK", "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL",
|
||||
"NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT",
|
||||
"NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS",
|
||||
"NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", "NODE",
|
||||
"NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE", "NOTE", "NOUN",
|
||||
"NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY", "OBOE", "ODIN", "OHIO",
|
||||
"OILY", "OINT", "OKAY", "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN",
|
||||
"OMIT", "ONCE", "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO",
|
||||
"OTIS", "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY",
|
||||
"OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE",
|
||||
"RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE",
|
||||
"RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED", "REEF",
|
||||
"REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT", "REST", "RICE",
|
||||
"RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME", "RING", "RINK", "RISE",
|
||||
"RISK", "RITE", "ROAD", "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL",
|
||||
"ROLL", "ROME", "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE",
|
||||
"ROSS", "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY",
|
||||
"RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH",
|
||||
"RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL",
|
||||
"SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK", "SARA",
|
||||
"SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT", "SEAL", "SEAM",
|
||||
"SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN", "SEES", "SELF", "SELL",
|
||||
"SEND", "SENT", "SETS", "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED",
|
||||
"SHIM", "SHIN", "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK",
|
||||
"SIDE", "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE",
|
||||
"SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID",
|
||||
"SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW",
|
||||
"SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", "SLUM",
|
||||
"SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", "SNUG", "SOAK",
|
||||
"SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL", "SOLD", "SOME", "SONG",
|
||||
"SOON", "SOOT", "SORE", "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG",
|
||||
"STAN", "STAR", "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN",
|
||||
"SUCH", "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF",
|
||||
"SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK",
|
||||
"TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE",
|
||||
"TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET", "TELL",
|
||||
"TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN", "THAT", "THEE",
|
||||
"THEM", "THEN", "THEY", "THIN", "THIS", "THUD", "THUG", "TICK", "TIDE",
|
||||
"TIDY", "TIED", "TIER", "TILE", "TILL", "TILT", "TIME", "TINA", "TINE",
|
||||
"TINT", "TINY", "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE",
|
||||
"TONG", "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR",
|
||||
"TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM",
|
||||
"TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT",
|
||||
"TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN", "TWIT",
|
||||
"ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH", "VAIL", "VAIN",
|
||||
"VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA", "VEIL", "VEIN", "VEND",
|
||||
"VENT", "VERB", "VERY", "VETO", "VICE", "VIEW", "VINE", "VISE", "VOID",
|
||||
"VOLT", "VOTE", "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE",
|
||||
"WALK", "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM",
|
||||
"WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS",
|
||||
"WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL",
|
||||
"WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE", "WHEN",
|
||||
"WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL", "WIND", "WINE",
|
||||
"WING", "WINK", "WINO", "WIRE", "WISE", "WISH", "WITH", "WOLF", "WONT",
|
||||
"WOOD", "WOOL", "WORD", "WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT",
|
||||
"WYNN", "YALE", "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH",
|
||||
"YEAR", "YELL", "YOGA", "YOKE"
|
||||
};
|
||||
|
||||
/* Extract 'length' bits from the char array 's'
|
||||
starting with bit 'start' */
|
||||
unsigned long RFC1751::extract (char* s, int start, int length)
|
||||
{
|
||||
unsigned char cl;
|
||||
unsigned char cc;
|
||||
unsigned char cr;
|
||||
unsigned long x;
|
||||
|
||||
assert (length <= 11);
|
||||
assert (start >= 0);
|
||||
assert (length >= 0);
|
||||
assert (start + length <= 66);
|
||||
|
||||
cl = s[start / 8]; // get components
|
||||
cc = s[start / 8 + 1];
|
||||
cr = s[start / 8 + 2];
|
||||
|
||||
x = ((long) (cl << 8 | cc) << 8 | cr) ; // Put bits together
|
||||
x = x >> (24 - (length + (start % 8))); // Right justify number
|
||||
x = ( x & (0xffff >> (16 - length) ) ); // Trim extra bits.
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Encode 8 bytes in 'c' as a string of English words.
|
||||
// Returns a pointer to a static buffer
|
||||
void RFC1751::btoe (std::string& strHuman, const std::string& strData)
|
||||
{
|
||||
char caBuffer[9]; /* add in room for the parity 2 bits*/
|
||||
int p, i;
|
||||
|
||||
memcpy (caBuffer, strData.c_str (), 8);
|
||||
|
||||
// compute parity: merely add groups of two bits.
|
||||
for (p = 0, i = 0; i < 64; i += 2)
|
||||
p += extract (caBuffer, i, 2);
|
||||
|
||||
caBuffer[8] = char (p) << 6;
|
||||
|
||||
strHuman = std::string ()
|
||||
+ s_dictionary[extract (caBuffer, 0, 11)] + " "
|
||||
+ s_dictionary[extract (caBuffer, 11, 11)] + " "
|
||||
+ s_dictionary[extract (caBuffer, 22, 11)] + " "
|
||||
+ s_dictionary[extract (caBuffer, 33, 11)] + " "
|
||||
+ s_dictionary[extract (caBuffer, 44, 11)] + " "
|
||||
+ s_dictionary[extract (caBuffer, 55, 11)];
|
||||
}
|
||||
|
||||
void RFC1751::insert (char* s, int x, int start, int length)
|
||||
{
|
||||
unsigned char cl;
|
||||
unsigned char cc;
|
||||
unsigned char cr;
|
||||
unsigned long y;
|
||||
int shift;
|
||||
|
||||
assert (length <= 11);
|
||||
assert (start >= 0);
|
||||
assert (length >= 0);
|
||||
assert (start + length <= 66);
|
||||
|
||||
shift = ((8 - (( start + length) % 8)) % 8);
|
||||
y = (long) x << shift;
|
||||
cl = (y >> 16) & 0xff;
|
||||
cc = (y >> 8) & 0xff;
|
||||
cr = y & 0xff;
|
||||
|
||||
if (shift + length > 16)
|
||||
{
|
||||
s[start / 8] |= cl;
|
||||
s[start / 8 + 1] |= cc;
|
||||
s[start / 8 + 2] |= cr;
|
||||
}
|
||||
else if (shift + length > 8)
|
||||
{
|
||||
s[start / 8] |= cc;
|
||||
s[start / 8 + 1] |= cr;
|
||||
}
|
||||
else
|
||||
{
|
||||
s[start / 8] |= cr;
|
||||
}
|
||||
}
|
||||
|
||||
void RFC1751::standard (std::string& strWord)
|
||||
{
|
||||
BOOST_FOREACH (char cLetter, strWord)
|
||||
{
|
||||
if (!isascii (cLetter))
|
||||
{
|
||||
; // nothing
|
||||
}
|
||||
else if (islower (cLetter))
|
||||
{
|
||||
cLetter = toupper (cLetter);
|
||||
}
|
||||
else if (cLetter == '1')
|
||||
{
|
||||
cLetter = 'L';
|
||||
}
|
||||
else if (cLetter == '0')
|
||||
{
|
||||
cLetter = 'O';
|
||||
}
|
||||
else if (cLetter == '5')
|
||||
{
|
||||
cLetter = 'S';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Binary search of dictionary.
|
||||
int RFC1751::wsrch (const std::string& strWord, int iMin, int iMax)
|
||||
{
|
||||
int iResult = -1;
|
||||
|
||||
while (iResult < 0 && iMin != iMax)
|
||||
{
|
||||
// Have a range to search.
|
||||
int iMid = iMin + (iMax - iMin) / 2;
|
||||
int iDir = strWord.compare (s_dictionary[iMid]);
|
||||
|
||||
if (!iDir)
|
||||
{
|
||||
iResult = iMid; // Found it.
|
||||
}
|
||||
else if (iDir < 0)
|
||||
{
|
||||
iMax = iMid; // key < middle, middle is new max.
|
||||
}
|
||||
else
|
||||
{
|
||||
iMin = iMid + 1; // key > middle, new min is past the middle.
|
||||
}
|
||||
}
|
||||
|
||||
return iResult;
|
||||
}
|
||||
|
||||
// Convert 6 words to binary.
|
||||
//
|
||||
// Returns 1 OK - all good words and parity is OK
|
||||
// 0 word not in data base
|
||||
// -1 badly formed in put ie > 4 char word
|
||||
// -2 words OK but parity is wrong
|
||||
int RFC1751::etob (std::string& strData, std::vector<std::string> vsHuman)
|
||||
{
|
||||
int i, p, v, l;
|
||||
char b[9];
|
||||
|
||||
if (6 != vsHuman.size ())
|
||||
return -1;
|
||||
|
||||
memset (b, 0, sizeof (b));
|
||||
|
||||
p = 0;
|
||||
BOOST_FOREACH (std::string & strWord, vsHuman)
|
||||
{
|
||||
l = strWord.length ();
|
||||
|
||||
if (l > 4 || l < 1)
|
||||
return -1;
|
||||
|
||||
standard (strWord);
|
||||
|
||||
v = wsrch (strWord,
|
||||
l < 4 ? 0 : 571,
|
||||
l < 4 ? 570 : 2048);
|
||||
|
||||
if (v < 0 )
|
||||
return 0;
|
||||
|
||||
insert (b, v, p, 11);
|
||||
p += 11;
|
||||
}
|
||||
|
||||
/* now check the parity of what we got */
|
||||
for (p = 0, i = 0; i < 64; i += 2)
|
||||
p += extract (b, i, 2);
|
||||
|
||||
if ( (p & 3) != extract (b, 64, 2) )
|
||||
return -2;
|
||||
|
||||
strData.assign (b, 8);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Convert words seperated by spaces into a 128 bit key in big-endian format.
|
||||
|
||||
@return
|
||||
1 if succeeded
|
||||
0 if word not in dictionary
|
||||
-1 if badly formed string
|
||||
-2 if words are okay but parity is wrong.
|
||||
*/
|
||||
int RFC1751::getKeyFromEnglish (std::string& strKey, const std::string& strHuman)
|
||||
{
|
||||
std::vector<std::string> vWords;
|
||||
std::string strFirst, strSecond;
|
||||
int rc = 0;
|
||||
|
||||
std::string strTrimmed (strHuman);
|
||||
|
||||
boost::algorithm::trim (strTrimmed);
|
||||
|
||||
boost::algorithm::split (vWords, strTrimmed,
|
||||
boost::algorithm::is_space (), boost::algorithm::token_compress_on);
|
||||
|
||||
rc = 12 == vWords.size () ? 1 : -1;
|
||||
|
||||
if (1 == rc)
|
||||
rc = etob (strFirst, vWords | boost::adaptors::copied (0, 6));
|
||||
|
||||
if (1 == rc)
|
||||
rc = etob (strSecond, vWords | boost::adaptors::copied (6, 12));
|
||||
|
||||
if (1 == rc)
|
||||
strKey = strFirst + strSecond;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Convert to human from a 128 bit key in big-endian format
|
||||
*/
|
||||
void RFC1751::getEnglishFromKey (std::string& strHuman, const std::string& strKey)
|
||||
{
|
||||
std::string strFirst, strSecond;
|
||||
|
||||
btoe (strFirst, strKey.substr (0, 8));
|
||||
btoe (strSecond, strKey.substr (8, 8));
|
||||
|
||||
strHuman = strFirst + " " + strSecond;
|
||||
}
|
||||
|
||||
String RFC1751::getWordFromBlob (void const* data, size_t bytes)
|
||||
{
|
||||
uint32 hash;
|
||||
|
||||
Murmur::Hash (data, bytes, 0, &hash);
|
||||
|
||||
return s_dictionary [hash % (sizeof (s_dictionary) / sizeof (s_dictionary [0]))];
|
||||
}
|
||||
|
||||
37
src/ripple_data/crypto/ripple_RFC1751.h
Normal file
37
src/ripple_data/crypto/ripple_RFC1751.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RFC1751_H
|
||||
#define RIPPLE_RFC1751_H
|
||||
|
||||
class RFC1751
|
||||
{
|
||||
public:
|
||||
static int getKeyFromEnglish (std::string& strKey, const std::string& strHuman);
|
||||
|
||||
static void getEnglishFromKey (std::string& strHuman, const std::string& strKey);
|
||||
|
||||
/** Chooses a single dictionary word from the data.
|
||||
|
||||
This is not particularly secure but it can be useful to provide
|
||||
a unique name for something given a GUID or fixed data. We use
|
||||
it to turn the pubkey_node into an easily remembered and identified
|
||||
4 character string.
|
||||
*/
|
||||
static String getWordFromBlob (void const* data, size_t bytes);
|
||||
|
||||
private:
|
||||
static unsigned long extract (char* s, int start, int length);
|
||||
static void btoe (std::string& strHuman, const std::string& strData);
|
||||
static void insert (char* s, int x, int start, int length);
|
||||
static void standard (std::string& strWord);
|
||||
static int wsrch (const std::string& strWord, int iMin, int iMax);
|
||||
static int etob (std::string& strData, std::vector<std::string> vsHuman);
|
||||
|
||||
static char const* s_dictionary [];
|
||||
};
|
||||
|
||||
#endif
|
||||
215
src/ripple_data/protocol/BuildInfo.cpp
Normal file
215
src/ripple_data/protocol/BuildInfo.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
char const* BuildInfo::getRawVersionString ()
|
||||
{
|
||||
static char const* const rawText =
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// The build version number (edit this for each release)
|
||||
//
|
||||
"0.12.1-alpha.1"
|
||||
//
|
||||
// Must follow the format described here:
|
||||
//
|
||||
// http://semver.org/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
;
|
||||
|
||||
return rawText;
|
||||
}
|
||||
|
||||
BuildInfo::Protocol const& BuildInfo::getCurrentProtocol ()
|
||||
{
|
||||
static Protocol currentProtocol (
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// The protocol version we speak and prefer (edit this if necessary)
|
||||
//
|
||||
1, // major
|
||||
2 // minor
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
);
|
||||
|
||||
return currentProtocol;
|
||||
}
|
||||
|
||||
BuildInfo::Protocol const& BuildInfo::getMinimumProtocol ()
|
||||
{
|
||||
static Protocol minimumProtocol (
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// The oldest protocol version we will accept. (edit this if necessary)
|
||||
//
|
||||
1, // major
|
||||
2 // minor
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
);
|
||||
|
||||
return minimumProtocol;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Don't touch anything below this line
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
String const& BuildInfo::getVersionString ()
|
||||
{
|
||||
struct SanityChecker
|
||||
{
|
||||
SanityChecker ()
|
||||
{
|
||||
SemanticVersion v;
|
||||
|
||||
char const* const rawText = getRawVersionString ();
|
||||
|
||||
if (! v.parse (rawText) || v.print () != rawText)
|
||||
FatalError ("Bad server version string", __FILE__, __LINE__);
|
||||
|
||||
versionString = rawText;
|
||||
}
|
||||
|
||||
String versionString;
|
||||
};
|
||||
|
||||
static SanityChecker value;
|
||||
|
||||
return value.versionString;
|
||||
}
|
||||
|
||||
char const* BuildInfo::getFullVersionString ()
|
||||
{
|
||||
struct PrettyPrinter
|
||||
{
|
||||
PrettyPrinter ()
|
||||
{
|
||||
String s;
|
||||
|
||||
s << "Ripple-" << getVersionString ();
|
||||
|
||||
fullVersionString = s.toStdString ();
|
||||
}
|
||||
|
||||
std::string fullVersionString;
|
||||
};
|
||||
|
||||
static PrettyPrinter value;
|
||||
|
||||
return value.fullVersionString.c_str ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
BuildInfo::Protocol::Protocol ()
|
||||
: vmajor (0)
|
||||
, vminor (0)
|
||||
{
|
||||
}
|
||||
|
||||
BuildInfo::Protocol::Protocol (unsigned short major_, unsigned short minor_)
|
||||
: vmajor (major_)
|
||||
, vminor (minor_)
|
||||
{
|
||||
}
|
||||
|
||||
BuildInfo::Protocol::Protocol (PackedFormat packedVersion)
|
||||
{
|
||||
vmajor = (packedVersion >> 16) & 0xffff;
|
||||
vminor = (packedVersion & 0xffff);
|
||||
}
|
||||
|
||||
BuildInfo::Protocol::PackedFormat BuildInfo::Protocol::toPacked () const noexcept
|
||||
{
|
||||
return ((vmajor << 16) & 0xffff0000) | (vminor & 0xffff);
|
||||
}
|
||||
|
||||
std::string BuildInfo::Protocol::toStdString () const noexcept
|
||||
{
|
||||
String s;
|
||||
|
||||
s << String (vmajor) << "." << String (vminor);
|
||||
|
||||
return s.toStdString ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BuildInfoTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
BuildInfoTests () : UnitTest ("BuildInfo", "ripple", runStartup)
|
||||
{
|
||||
}
|
||||
|
||||
void testVersion ()
|
||||
{
|
||||
beginTestCase ("version");
|
||||
|
||||
SemanticVersion v;
|
||||
|
||||
expect (v.parse (BuildInfo::getRawVersionString ()));
|
||||
}
|
||||
|
||||
void checkProtcol (unsigned short vmajor, unsigned short vminor)
|
||||
{
|
||||
typedef BuildInfo::Protocol P;
|
||||
|
||||
expect (P (P (vmajor, vminor).toPacked ()) == P (vmajor, vminor));
|
||||
}
|
||||
|
||||
void testProtocol ()
|
||||
{
|
||||
typedef BuildInfo::Protocol P;
|
||||
|
||||
beginTestCase ("protocol");
|
||||
|
||||
expect (P (0, 0).toPacked () == 0);
|
||||
expect (P (0, 1).toPacked () == 1);
|
||||
expect (P (0, 65535).toPacked () == 65535);
|
||||
|
||||
checkProtcol (0, 0);
|
||||
checkProtcol (0, 1);
|
||||
checkProtcol (0, 255);
|
||||
checkProtcol (0, 65535);
|
||||
checkProtcol (1, 0);
|
||||
checkProtcol (1, 65535);
|
||||
checkProtcol (65535, 65535);
|
||||
}
|
||||
|
||||
void testValues ()
|
||||
{
|
||||
beginTestCase ("comparison");
|
||||
|
||||
typedef BuildInfo::Protocol P;
|
||||
|
||||
expect (P(1,2) == P(1,2));
|
||||
expect (P(3,4) >= P(3,4));
|
||||
expect (P(5,6) <= P(5,6));
|
||||
expect (P(7,8) > P(6,7));
|
||||
expect (P(7,8) < P(8,9));
|
||||
expect (P(65535,0) < P(65535,65535));
|
||||
expect (P(65535,65535) >= P(65535,65535));
|
||||
|
||||
expect (BuildInfo::getCurrentProtocol () >= BuildInfo::getMinimumProtocol ());
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
testVersion ();
|
||||
testProtocol ();
|
||||
testValues ();
|
||||
}
|
||||
};
|
||||
|
||||
static BuildInfoTests buildInfoTests;
|
||||
73
src/ripple_data/protocol/BuildInfo.h
Normal file
73
src/ripple_data/protocol/BuildInfo.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_BUILDINFO_H_INCLUDED
|
||||
#define RIPPLE_BUILDINFO_H_INCLUDED
|
||||
|
||||
/** Versioning information for this build. */
|
||||
struct BuildInfo
|
||||
{
|
||||
/** Server version.
|
||||
|
||||
Follows the Semantic Versioning Specification:
|
||||
|
||||
http://semver.org/
|
||||
*/
|
||||
static String const& getVersionString ();
|
||||
|
||||
/** Full server version string.
|
||||
|
||||
This includes the name of the server. It is used in the peer
|
||||
protocol hello message and also the headers of some HTTP replies.
|
||||
*/
|
||||
static char const* getFullVersionString ();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** The wire protocol version.
|
||||
|
||||
The version consists of two unsigned 16 bit integers representing
|
||||
major and minor version numbers. All values are permissible.
|
||||
*/
|
||||
struct Protocol
|
||||
{
|
||||
unsigned short vmajor;
|
||||
unsigned short vminor;
|
||||
|
||||
//----
|
||||
|
||||
/** The serialized format of the protocol version. */
|
||||
typedef uint32 PackedFormat;
|
||||
|
||||
Protocol ();
|
||||
Protocol (unsigned short vmajor, unsigned short vminor);
|
||||
explicit Protocol (PackedFormat packedVersion);
|
||||
|
||||
PackedFormat toPacked () const noexcept;
|
||||
|
||||
std::string toStdString () const noexcept;
|
||||
|
||||
bool operator== (Protocol const& other) const noexcept { return toPacked () == other.toPacked (); }
|
||||
bool operator!= (Protocol const& other) const noexcept { return toPacked () != other.toPacked (); }
|
||||
bool operator>= (Protocol const& other) const noexcept { return toPacked () >= other.toPacked (); }
|
||||
bool operator<= (Protocol const& other) const noexcept { return toPacked () <= other.toPacked (); }
|
||||
bool operator> (Protocol const& other) const noexcept { return toPacked () > other.toPacked (); }
|
||||
bool operator< (Protocol const& other) const noexcept { return toPacked () < other.toPacked (); }
|
||||
};
|
||||
|
||||
/** The protocol version we speak and prefer. */
|
||||
static Protocol const& getCurrentProtocol ();
|
||||
|
||||
/** The oldest protocol version we will accept. */
|
||||
static Protocol const& getMinimumProtocol ();
|
||||
|
||||
private:
|
||||
friend class BuildInfoTests;
|
||||
|
||||
static char const* getRawVersionString ();
|
||||
};
|
||||
|
||||
#endif
|
||||
362
src/ripple_data/protocol/ripple.proto
Normal file
362
src/ripple_data/protocol/ripple.proto
Normal file
@@ -0,0 +1,362 @@
|
||||
package protocol;
|
||||
|
||||
enum MessageType
|
||||
{
|
||||
// core
|
||||
mtHELLO = 1;
|
||||
mtERROR_MSG = 2;
|
||||
mtPING = 3;
|
||||
mtPROOFOFWORK = 4;
|
||||
mtCLUSTER = 5;
|
||||
|
||||
// network presence detection
|
||||
mtGET_CONTACTS = 10;
|
||||
mtCONTACT = 11;
|
||||
mtGET_PEERS = 12;
|
||||
mtPEERS = 13;
|
||||
|
||||
// operations for 'small' nodes
|
||||
mtSEARCH_TRANSACTION = 20;
|
||||
mtGET_ACCOUNT = 21;
|
||||
mtACCOUNT = 22;
|
||||
|
||||
// transaction and ledger processing
|
||||
mtTRANSACTION = 30;
|
||||
mtGET_LEDGER = 31;
|
||||
mtLEDGER_DATA = 32;
|
||||
mtPROPOSE_LEDGER = 33;
|
||||
mtSTATUS_CHANGE = 34;
|
||||
mtHAVE_SET = 35;
|
||||
|
||||
// data replication and synchronization
|
||||
mtGET_VALIDATIONS = 40;
|
||||
mtVALIDATION = 41;
|
||||
mtGET_OBJECTS = 42;
|
||||
}
|
||||
|
||||
|
||||
// token, iterations, target, challenge = issue demand for proof of work
|
||||
// token, response = give solution to proof of work
|
||||
// token, result = report result of pow
|
||||
|
||||
message TMProofWork
|
||||
{
|
||||
required string token = 1;
|
||||
optional uint32 iterations = 2;
|
||||
optional bytes target = 3;
|
||||
optional bytes challenge = 4;
|
||||
optional bytes response = 5;
|
||||
|
||||
enum PowResult
|
||||
{
|
||||
powrOK = 0;
|
||||
powrREUSED = 1;
|
||||
powrEXPIRED = 2; // You took too long solving
|
||||
powrTOOEASY = 3; // Difficulty went way up, sorry
|
||||
powrINVALID = 4;
|
||||
powrDISCONNECT = 5; // We are disconnecting
|
||||
}
|
||||
optional PowResult result = 6;
|
||||
}
|
||||
|
||||
// Sent on connect
|
||||
message TMHello
|
||||
{
|
||||
required uint32 protoVersion = 1;
|
||||
required uint32 protoVersionMin = 2;
|
||||
required bytes nodePublic = 3;
|
||||
required bytes nodeProof = 4;
|
||||
optional string fullVersion = 5;
|
||||
optional uint64 netTime = 6;
|
||||
optional uint32 ipv4Port = 7;
|
||||
optional uint32 ledgerIndex = 8;
|
||||
optional bytes ledgerClosed = 9; // our last closed ledger
|
||||
optional bytes ledgerPrevious = 10; // the ledger before the last closed ledger
|
||||
optional bool nodePrivate = 11; // Request to not forward IP.
|
||||
optional TMProofWork proofOfWork = 12; // request/provide proof of work
|
||||
optional bool testNet = 13; // Running as testnet.
|
||||
}
|
||||
|
||||
// The status of a node in our cluster
|
||||
message TMClusterNode
|
||||
{
|
||||
required string publicKey = 1;
|
||||
required uint32 reportTime = 2;
|
||||
required uint32 nodeLoad = 3;
|
||||
optional string nodeName = 4;
|
||||
optional string address = 5;
|
||||
}
|
||||
|
||||
// The status of all nodes in the cluster
|
||||
message TMCluster
|
||||
{
|
||||
repeated TMClusterNode clusterNodes = 1;
|
||||
}
|
||||
|
||||
|
||||
// A transaction can have only one input and one output.
|
||||
// If you want to send an amount that is greater than any single address of yours
|
||||
// you must first combine coins from one address to another.
|
||||
|
||||
enum TransactionStatus
|
||||
{
|
||||
tsNEW = 1; // origin node did/could not validate
|
||||
tsCURRENT = 2; // scheduled to go in this ledger
|
||||
tsCOMMITED = 3; // in a closed ledger
|
||||
tsREJECT_CONFLICT = 4;
|
||||
tsREJECT_INVALID = 5;
|
||||
tsREJECT_FUNDS = 6;
|
||||
tsHELD_SEQ = 7;
|
||||
tsHELD_LEDGER = 8; // held for future ledger
|
||||
}
|
||||
|
||||
message TMTransaction
|
||||
{
|
||||
required bytes rawTransaction = 1;
|
||||
required TransactionStatus status = 2;
|
||||
optional uint64 receiveTimestamp = 3;
|
||||
optional bool checkedSignature = 4; // no vouches for signature being correct
|
||||
}
|
||||
|
||||
|
||||
enum NodeStatus
|
||||
{
|
||||
nsCONNECTING = 1; // acquiring connections
|
||||
nsCONNECTED = 2; // convinced we are connected to the real network
|
||||
nsMONITORING = 3; // we know what the previous ledger is
|
||||
nsVALIDATING = 4; // we have the full ledger contents
|
||||
nsSHUTTING = 5; // node is shutting down
|
||||
}
|
||||
|
||||
enum NodeEvent
|
||||
{
|
||||
neCLOSING_LEDGER = 1; // closing a ledger because its close time has come
|
||||
neACCEPTED_LEDGER = 2; // accepting a closed ledger, we have finished computing it
|
||||
neSWITCHED_LEDGER = 3; // changing due to network consensus
|
||||
neLOST_SYNC = 4;
|
||||
}
|
||||
|
||||
message TMStatusChange
|
||||
{
|
||||
optional NodeStatus newStatus = 1;
|
||||
optional NodeEvent newEvent = 2;
|
||||
optional uint32 ledgerSeq = 3;
|
||||
optional bytes ledgerHash = 4;
|
||||
optional bytes ledgerHashPrevious = 5;
|
||||
optional uint64 networkTime = 6;
|
||||
optional uint32 firstSeq = 7;
|
||||
optional uint32 lastSeq = 8;
|
||||
}
|
||||
|
||||
|
||||
// Announce to the network our position on a closing ledger
|
||||
message TMProposeSet
|
||||
{
|
||||
required uint32 proposeSeq = 1;
|
||||
required bytes currentTxHash = 2; // the hash of the ledger we are proposing
|
||||
required bytes nodePubKey = 3;
|
||||
required uint32 closeTime = 4;
|
||||
required bytes signature = 5; // signature of above fields
|
||||
optional bytes previousledger = 6;
|
||||
optional bool checkedSignature = 7; // node vouches signature is correct
|
||||
repeated bytes addedTransactions = 10; // not required if number is large
|
||||
repeated bytes removedTransactions = 11; // not required if number is large
|
||||
}
|
||||
|
||||
enum TxSetStatus
|
||||
{
|
||||
tsHAVE = 1; // We have this set locally
|
||||
tsCAN_GET = 2; // We have a peer with this set
|
||||
tsNEED = 3; // We need this set and can't get it
|
||||
}
|
||||
|
||||
message TMHaveTransactionSet
|
||||
{
|
||||
required TxSetStatus status = 1;
|
||||
required bytes hash = 2;
|
||||
}
|
||||
|
||||
|
||||
// Used to sign a final closed ledger after reprocessing
|
||||
message TMValidation
|
||||
{
|
||||
required bytes validation = 1; // in SerializedValidation signed form
|
||||
optional bool checkedSignature = 2; // node vouches signature is correct
|
||||
}
|
||||
|
||||
|
||||
message TMGetValidations
|
||||
{
|
||||
required uint32 ledgerIndex = 1;
|
||||
repeated bytes hanko = 2;
|
||||
optional uint32 count = 3; // get random validations
|
||||
}
|
||||
|
||||
|
||||
|
||||
message TMContact
|
||||
{
|
||||
required bytes pubKey = 1;
|
||||
required uint32 softwareVersion = 2;
|
||||
required uint32 protoVersion = 3;
|
||||
required uint64 nodeFlags = 4;
|
||||
required uint64 timestamp = 5;
|
||||
repeated bytes nodeInfo = 6;
|
||||
required bytes signature = 7;
|
||||
}
|
||||
|
||||
// request node information
|
||||
message TMGetContacts
|
||||
{
|
||||
repeated bytes nodeIDs = 1; // specific nodes we want
|
||||
optional uint32 nodeCount = 2; // get some random nodes
|
||||
}
|
||||
|
||||
message TMGetPeers
|
||||
{
|
||||
required uint32 doWeNeedThis = 1; // yes since you are asserting that the packet size isn't 0 in PackedMessage
|
||||
}
|
||||
|
||||
message TMIPv4EndPoint
|
||||
{
|
||||
required uint32 ipv4 = 1;
|
||||
required uint32 ipv4Port = 2;
|
||||
}
|
||||
|
||||
message TMPeers
|
||||
{
|
||||
repeated TMIPv4EndPoint nodes = 1;
|
||||
}
|
||||
|
||||
|
||||
message TMSearchTransaction
|
||||
{
|
||||
required uint32 maxTrans = 1;
|
||||
optional bytes toAccount = 2;
|
||||
optional bytes fromAccount = 3;
|
||||
optional uint32 minLedger = 4;
|
||||
optional bytes fromAcctSeq = 5;
|
||||
repeated bytes transID = 6;
|
||||
}
|
||||
|
||||
message TMGetAccount
|
||||
{
|
||||
repeated bytes acctID = 1;
|
||||
optional uint32 seq = 2;
|
||||
}
|
||||
|
||||
message Account
|
||||
{
|
||||
required bytes accountID = 1;
|
||||
required uint64 balance = 2;
|
||||
required uint32 accountSeq = 3;
|
||||
required uint32 ledgerSeq = 4;
|
||||
}
|
||||
|
||||
message TMAccount
|
||||
{
|
||||
repeated Account accounts = 1;
|
||||
optional uint32 seq = 2;
|
||||
}
|
||||
|
||||
message TMIndexedObject
|
||||
{
|
||||
optional bytes hash = 1;
|
||||
optional bytes nodeID = 2;
|
||||
optional bytes index = 3;
|
||||
optional bytes data = 4;
|
||||
optional uint32 ledgerSeq = 5;
|
||||
}
|
||||
|
||||
message TMGetObjectByHash
|
||||
{
|
||||
enum ObjectType {
|
||||
otUNKNOWN = 0;
|
||||
otLEDGER = 1;
|
||||
otTRANSACTION = 2;
|
||||
otTRANSACTION_NODE = 3;
|
||||
otSTATE_NODE = 4;
|
||||
otCAS_OBJECT = 5;
|
||||
otFETCH_PACK = 6;
|
||||
}
|
||||
|
||||
required ObjectType type = 1;
|
||||
required bool query = 2; // is this a query or a reply?
|
||||
optional uint32 seq = 3; // used to match replies to queries
|
||||
optional bytes ledgerHash = 4; // the hash of the ledger these queries are for
|
||||
optional bool fat = 5; // return related nodes
|
||||
repeated TMIndexedObject objects = 6; // the specific objects requested
|
||||
}
|
||||
|
||||
|
||||
message TMLedgerNode
|
||||
{
|
||||
required bytes nodedata = 1;
|
||||
optional bytes nodeid = 2; // missing for ledger base data
|
||||
}
|
||||
|
||||
enum TMLedgerInfoType
|
||||
{
|
||||
liBASE = 0; // basic ledger info
|
||||
liTX_NODE = 1; // transaction node
|
||||
liAS_NODE = 2; // account state node
|
||||
liTS_CANDIDATE = 3; // candidate transaction set
|
||||
}
|
||||
|
||||
enum TMLedgerType
|
||||
{
|
||||
ltACCEPTED = 0;
|
||||
ltCURRENT = 1;
|
||||
ltCLOSED = 2;
|
||||
}
|
||||
|
||||
enum TMQueryType
|
||||
{
|
||||
qtINDIRECT = 0;
|
||||
}
|
||||
|
||||
message TMGetLedger
|
||||
{
|
||||
required TMLedgerInfoType itype = 1;
|
||||
optional TMLedgerType ltype = 2;
|
||||
optional bytes ledgerHash = 3; // Can also be the transaction set hash if liTS_CANDIDATE
|
||||
optional uint32 ledgerSeq = 4;
|
||||
repeated bytes nodeIDs = 5;
|
||||
optional uint64 requestCookie = 6;
|
||||
optional TMQueryType queryType = 7;
|
||||
}
|
||||
|
||||
enum TMReplyError
|
||||
{
|
||||
reNO_LEDGER = 1; // We don't have the ledger you are asking about
|
||||
reNO_NODE = 2; // We don't have any of the nodes you are asking for
|
||||
}
|
||||
|
||||
message TMLedgerData
|
||||
{
|
||||
required bytes ledgerHash = 1;
|
||||
required uint32 ledgerSeq = 2;
|
||||
required TMLedgerInfoType type = 3;
|
||||
repeated TMLedgerNode nodes = 4;
|
||||
optional uint32 requestCookie = 5;
|
||||
optional TMReplyError error = 6;
|
||||
}
|
||||
|
||||
message TMPing
|
||||
{
|
||||
enum pingType {
|
||||
ptPING = 0; // we want a reply
|
||||
ptPONG = 1; // this is a reply
|
||||
}
|
||||
required pingType type = 1;
|
||||
optional uint32 seq = 2; // detect stale replies, ensure other side is reading
|
||||
optional uint64 pingTime = 3; // know when we think we sent the ping
|
||||
optional uint64 netTime = 4;
|
||||
}
|
||||
|
||||
|
||||
message TMErrorMsg
|
||||
{
|
||||
optional int32 errorCode = 1;
|
||||
optional string message = 2;
|
||||
}
|
||||
144
src/ripple_data/protocol/ripple_FieldNames.cpp
Normal file
144
src/ripple_data/protocol/ripple_FieldNames.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// These must stay at the top of this file
|
||||
std::map<int, SField::ptr> SField::codeToField;
|
||||
int SField::num = 0;
|
||||
|
||||
|
||||
// Solve construction issues for objects with static storage duration.
|
||||
SField::StaticLockType& SField::getMutex ()
|
||||
{
|
||||
static StaticLockType mutex ("SField", __FILE__, __LINE__);
|
||||
return mutex;
|
||||
}
|
||||
|
||||
SField sfInvalid (-1), sfGeneric (0);
|
||||
SField sfLedgerEntry (STI_LEDGERENTRY, 1, "LedgerEntry");
|
||||
SField sfTransaction (STI_TRANSACTION, 1, "Transaction");
|
||||
SField sfValidation (STI_VALIDATION, 1, "Validation");
|
||||
SField sfHash (STI_HASH256, 257, "hash");
|
||||
SField sfIndex (STI_HASH256, 258, "index");
|
||||
|
||||
#define FIELD(name, type, index) SField sf##name(FIELD_CODE(STI_##type, index), STI_##type, index, #name);
|
||||
#define TYPE(name, type, index)
|
||||
#include "../protocol/ripple_SerializeDeclarations.h"
|
||||
#undef FIELD
|
||||
#undef TYPE
|
||||
|
||||
static int initFields ()
|
||||
{
|
||||
sfTxnSignature.notSigningField ();
|
||||
sfTxnSignatures.notSigningField ();
|
||||
sfSignature.notSigningField ();
|
||||
|
||||
sfIndexes.setMeta (SField::sMD_Never);
|
||||
sfPreviousTxnID.setMeta (SField::sMD_DeleteFinal);
|
||||
sfPreviousTxnLgrSeq.setMeta (SField::sMD_DeleteFinal);
|
||||
sfLedgerEntryType.setMeta (SField::sMD_Never);
|
||||
sfRootIndex.setMeta (SField::sMD_Always);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const int f = initFields ();
|
||||
|
||||
|
||||
SField::SField (SerializedTypeID tid, int fv) : fieldCode (FIELD_CODE (tid, fv)), fieldType (tid), fieldValue (fv),
|
||||
fieldMeta (sMD_Default), fieldNum (++num), signingField (true)
|
||||
{
|
||||
// call with the map mutex
|
||||
fieldName = lexicalCast <std::string> (tid) + "/" + lexicalCast <std::string> (fv);
|
||||
codeToField[fieldCode] = this;
|
||||
assert ((fv != 1) || ((tid != STI_ARRAY) && (tid != STI_OBJECT)));
|
||||
}
|
||||
|
||||
SField::ref SField::getField (int code)
|
||||
{
|
||||
int type = code >> 16;
|
||||
int field = code % 0xffff;
|
||||
|
||||
if ((type <= 0) || (field <= 0))
|
||||
return sfInvalid;
|
||||
|
||||
StaticScopedLockType sl (getMutex (), __FILE__, __LINE__);
|
||||
|
||||
std::map<int, SField::ptr>::iterator it = codeToField.find (code);
|
||||
|
||||
if (it != codeToField.end ())
|
||||
return * (it->second);
|
||||
|
||||
if (field > 255) // don't dynamically extend types that have no binary encoding
|
||||
return sfInvalid;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
// types we are willing to dynamically extend
|
||||
|
||||
#define FIELD(name, type, index)
|
||||
#define TYPE(name, type, index) case STI_##type:
|
||||
#include "../protocol/ripple_SerializeDeclarations.h"
|
||||
#undef FIELD
|
||||
#undef TYPE
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return sfInvalid;
|
||||
}
|
||||
|
||||
return * (new SField (static_cast<SerializedTypeID> (type), field));
|
||||
}
|
||||
|
||||
int SField::compare (SField::ref f1, SField::ref f2)
|
||||
{
|
||||
// -1 = f1 comes before f2, 0 = illegal combination, 1 = f1 comes after f2
|
||||
if ((f1.fieldCode <= 0) || (f2.fieldCode <= 0))
|
||||
return 0;
|
||||
|
||||
if (f1.fieldCode < f2.fieldCode)
|
||||
return -1;
|
||||
|
||||
if (f2.fieldCode < f1.fieldCode)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string SField::getName () const
|
||||
{
|
||||
if (!fieldName.empty ())
|
||||
return fieldName;
|
||||
|
||||
if (fieldValue == 0)
|
||||
return "";
|
||||
|
||||
return lexicalCastThrow <std::string> (static_cast<int> (fieldType)) + "/" +
|
||||
lexicalCastThrow <std::string> (fieldValue);
|
||||
}
|
||||
|
||||
SField::ref SField::getField (const std::string& fieldName)
|
||||
{
|
||||
// OPTIMIZEME me with a map. CHECKME this is case sensitive
|
||||
StaticScopedLockType sl (getMutex (), __FILE__, __LINE__);
|
||||
typedef std::map<int, SField::ptr>::value_type int_sfref_pair;
|
||||
BOOST_FOREACH (const int_sfref_pair & fieldPair, codeToField)
|
||||
{
|
||||
if (fieldPair.second->fieldName == fieldName)
|
||||
return * (fieldPair.second);
|
||||
}
|
||||
return sfInvalid;
|
||||
}
|
||||
|
||||
SField::~SField ()
|
||||
{
|
||||
StaticScopedLockType sl (getMutex (), __FILE__, __LINE__);
|
||||
std::map<int, ptr>::iterator it = codeToField.find (fieldCode);
|
||||
|
||||
if ((it != codeToField.end ()) && (it->second == this))
|
||||
codeToField.erase (it);
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
219
src/ripple_data/protocol/ripple_FieldNames.h
Normal file
219
src/ripple_data/protocol/ripple_FieldNames.h
Normal file
@@ -0,0 +1,219 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_FIELDNAMES_H
|
||||
#define RIPPLE_FIELDNAMES_H
|
||||
|
||||
// VFALCO TODO lose the macro.
|
||||
#define FIELD_CODE(type, index) ((static_cast<int>(type) << 16) | index)
|
||||
|
||||
enum SerializedTypeID
|
||||
{
|
||||
// special types
|
||||
STI_UNKNOWN = -2,
|
||||
STI_DONE = -1,
|
||||
STI_NOTPRESENT = 0,
|
||||
|
||||
#define TYPE(name, field, value) STI_##field = value,
|
||||
#define FIELD(name, field, value)
|
||||
#include "../protocol/ripple_SerializeDeclarations.h"
|
||||
#undef TYPE
|
||||
#undef FIELD
|
||||
|
||||
// high level types
|
||||
STI_TRANSACTION = 10001,
|
||||
STI_LEDGERENTRY = 10002,
|
||||
STI_VALIDATION = 10003,
|
||||
};
|
||||
|
||||
/** Identifies fields.
|
||||
|
||||
Fields are necessary to tag data in signed transactions so that
|
||||
the binary format of the transaction can be canonicalized.
|
||||
*/
|
||||
// VFALCO TODO rename this to NamedField
|
||||
class SField
|
||||
{
|
||||
public:
|
||||
typedef const SField& ref;
|
||||
typedef SField const* ptr;
|
||||
|
||||
static const int sMD_Never = 0x00;
|
||||
static const int sMD_ChangeOrig = 0x01; // original value when it changes
|
||||
static const int sMD_ChangeNew = 0x02; // new value when it changes
|
||||
static const int sMD_DeleteFinal = 0x04; // final value when it is deleted
|
||||
static const int sMD_Create = 0x08; // value when it's created
|
||||
static const int sMD_Always = 0x10; // value when node containing it is affected at all
|
||||
static const int sMD_Default = sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create;
|
||||
|
||||
public:
|
||||
|
||||
const int fieldCode; // (type<<16)|index
|
||||
const SerializedTypeID fieldType; // STI_*
|
||||
const int fieldValue; // Code number for protocol
|
||||
std::string fieldName;
|
||||
int fieldMeta;
|
||||
int fieldNum;
|
||||
bool signingField;
|
||||
|
||||
SField (int fc, SerializedTypeID tid, int fv, const char* fn)
|
||||
: fieldCode (fc)
|
||||
, fieldType (tid)
|
||||
, fieldValue (fv)
|
||||
, fieldName (fn)
|
||||
, fieldMeta (sMD_Default)
|
||||
, signingField (true)
|
||||
{
|
||||
StaticScopedLockType sl (getMutex (), __FILE__, __LINE__);
|
||||
|
||||
codeToField[fieldCode] = this;
|
||||
|
||||
fieldNum = ++num;
|
||||
}
|
||||
|
||||
SField (SerializedTypeID tid, int fv, const char* fn)
|
||||
: fieldCode (FIELD_CODE (tid, fv))
|
||||
, fieldType (tid)
|
||||
, fieldValue (fv)
|
||||
, fieldName (fn)
|
||||
, fieldMeta (sMD_Default)
|
||||
, signingField (true)
|
||||
{
|
||||
StaticScopedLockType sl (getMutex (), __FILE__, __LINE__);
|
||||
|
||||
codeToField[fieldCode] = this;
|
||||
|
||||
fieldNum = ++num;
|
||||
}
|
||||
|
||||
explicit SField (int fc)
|
||||
: fieldCode (fc)
|
||||
, fieldType (STI_UNKNOWN)
|
||||
, fieldValue (0)
|
||||
, fieldMeta (sMD_Never)
|
||||
, signingField (true)
|
||||
{
|
||||
StaticScopedLockType sl (getMutex (), __FILE__, __LINE__);
|
||||
fieldNum = ++num;
|
||||
}
|
||||
|
||||
~SField ();
|
||||
|
||||
static SField::ref getField (int fieldCode);
|
||||
static SField::ref getField (const std::string& fieldName);
|
||||
static SField::ref getField (int type, int value)
|
||||
{
|
||||
return getField (FIELD_CODE (type, value));
|
||||
}
|
||||
static SField::ref getField (SerializedTypeID type, int value)
|
||||
{
|
||||
return getField (FIELD_CODE (type, value));
|
||||
}
|
||||
|
||||
std::string getName () const;
|
||||
bool hasName () const
|
||||
{
|
||||
return !fieldName.empty ();
|
||||
}
|
||||
|
||||
bool isGeneric () const
|
||||
{
|
||||
return fieldCode == 0;
|
||||
}
|
||||
bool isInvalid () const
|
||||
{
|
||||
return fieldCode == -1;
|
||||
}
|
||||
bool isUseful () const
|
||||
{
|
||||
return fieldCode > 0;
|
||||
}
|
||||
bool isKnown () const
|
||||
{
|
||||
return fieldType != STI_UNKNOWN;
|
||||
}
|
||||
bool isBinary () const
|
||||
{
|
||||
return fieldValue < 256;
|
||||
}
|
||||
|
||||
// VFALCO NOTE What is a discardable field?
|
||||
bool isDiscardable () const
|
||||
{
|
||||
return fieldValue > 256;
|
||||
}
|
||||
|
||||
int getCode () const
|
||||
{
|
||||
return fieldCode;
|
||||
}
|
||||
int getNum () const
|
||||
{
|
||||
return fieldNum;
|
||||
}
|
||||
static int getNumFields ()
|
||||
{
|
||||
return num;
|
||||
}
|
||||
|
||||
bool isSigningField () const
|
||||
{
|
||||
return signingField;
|
||||
}
|
||||
void notSigningField ()
|
||||
{
|
||||
signingField = false;
|
||||
}
|
||||
bool shouldMeta (int c) const
|
||||
{
|
||||
return (fieldMeta & c) != 0;
|
||||
}
|
||||
void setMeta (int c)
|
||||
{
|
||||
fieldMeta = c;
|
||||
}
|
||||
|
||||
bool shouldInclude (bool withSigningField) const
|
||||
{
|
||||
return (fieldValue < 256) && (withSigningField || signingField);
|
||||
}
|
||||
|
||||
bool operator== (const SField& f) const
|
||||
{
|
||||
return fieldCode == f.fieldCode;
|
||||
}
|
||||
|
||||
bool operator!= (const SField& f) const
|
||||
{
|
||||
return fieldCode != f.fieldCode;
|
||||
}
|
||||
|
||||
static int compare (SField::ref f1, SField::ref f2);
|
||||
|
||||
// VFALCO TODO make these private
|
||||
protected:
|
||||
static std::map<int, ptr> codeToField;
|
||||
|
||||
typedef RippleMutex StaticLockType;
|
||||
typedef StaticLockType::ScopedLockType StaticScopedLockType;
|
||||
|
||||
static StaticLockType& getMutex ();
|
||||
|
||||
// VFALCO NOTE can this be replaced with an atomic int???!
|
||||
static int num;
|
||||
|
||||
SField (SerializedTypeID id, int val);
|
||||
};
|
||||
|
||||
extern SField sfInvalid, sfGeneric, sfLedgerEntry, sfTransaction, sfValidation;
|
||||
|
||||
#define FIELD(name, type, index) extern SField sf##name;
|
||||
#define TYPE(name, type, index)
|
||||
#include "../protocol/ripple_SerializeDeclarations.h"
|
||||
#undef FIELD
|
||||
#undef TYPE
|
||||
|
||||
#endif
|
||||
69
src/ripple_data/protocol/ripple_HashPrefix.h
Normal file
69
src/ripple_data/protocol/ripple_HashPrefix.h
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HASHPREFIX_H
|
||||
#define RIPPLE_HASHPREFIX_H
|
||||
|
||||
/** Prefix for hashing functions.
|
||||
|
||||
These prefixes are inserted before the source material used to
|
||||
generate various hashes. This is done to put each hash in its own
|
||||
"space." This way, two different types of objects with the
|
||||
same binary data will produce different hashes.
|
||||
|
||||
Each prefix is a 4-byte value with the last byte set to zero
|
||||
and the first three bytes formed from the ASCII equivalent of
|
||||
some arbitrary string. For example "TXN".
|
||||
|
||||
@note Hash prefixes are part of the Ripple protocol.
|
||||
|
||||
@ingroup protocol
|
||||
*/
|
||||
// VFALCO NOTE there are ledger entry prefixes too but they are only
|
||||
// 1 byte, find out why they are different. Maybe we should
|
||||
// group them all together?
|
||||
//
|
||||
struct HashPrefix
|
||||
{
|
||||
// VFALCO TODO Make these Doxygen comments and expand the
|
||||
// description to complete, concise sentences.
|
||||
//
|
||||
|
||||
// transaction plus signature to give transaction ID
|
||||
static uint32 const transactionID = 0x54584E00; // 'TXN'
|
||||
|
||||
// transaction plus metadata
|
||||
static uint32 const txNode = 0x534E4400; // 'TND'
|
||||
|
||||
// account state
|
||||
static uint32 const leafNode = 0x4D4C4E00; // 'MLN'
|
||||
|
||||
// inner node in tree
|
||||
static uint32 const innerNode = 0x4D494E00; // 'MIN'
|
||||
|
||||
// ledger master data for signing
|
||||
static uint32 const ledgerMaster = 0x4C575200; // 'LGR'
|
||||
|
||||
// inner transaction to sign
|
||||
static uint32 const txSign = 0x53545800; // 'STX'
|
||||
|
||||
// validation for signing
|
||||
static uint32 const validation = 0x56414C00; // 'VAL'
|
||||
|
||||
// proposal for signing
|
||||
static uint32 const proposal = 0x50525000; // 'PRP'
|
||||
|
||||
// inner transaction to sign (TESTNET)
|
||||
static uint32 const txSignTestnet = 0x73747800; // 'stx'
|
||||
|
||||
// validation for signing (TESTNET)
|
||||
static uint32 const validationTestnet = 0x76616C00; // 'val'
|
||||
|
||||
// proposal for signing (TESTNET)
|
||||
static uint32 const proposalTestnet = 0x70727000; // 'prp'
|
||||
};
|
||||
|
||||
#endif
|
||||
172
src/ripple_data/protocol/ripple_KnownFormats.h
Normal file
172
src/ripple_data/protocol/ripple_KnownFormats.h
Normal file
@@ -0,0 +1,172 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_KNOWNFORMATS_H_INCLUDED
|
||||
#define RIPPLE_KNOWNFORMATS_H_INCLUDED
|
||||
|
||||
/** Manages a list of known formats.
|
||||
|
||||
Each format has a name, an associated KeyType (typically an enumeration),
|
||||
and a predefined @ref SOElement.
|
||||
|
||||
@tparam KeyType The type of key identifying the format.
|
||||
*/
|
||||
template <class KeyType>
|
||||
class KnownFormats
|
||||
{
|
||||
public:
|
||||
/** A known format.
|
||||
*/
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
Item (char const* name, KeyType type)
|
||||
: m_name (name)
|
||||
, m_type (type)
|
||||
{
|
||||
}
|
||||
|
||||
Item& operator<< (SOElement const& el)
|
||||
{
|
||||
elements.push_back (el);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Retrieve the name of the format.
|
||||
*/
|
||||
std::string const& getName () const noexcept
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/** Retrieve the transaction type this format represents.
|
||||
*/
|
||||
KeyType getType () const noexcept
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
public:
|
||||
// VFALCO TODO make an accessor for this
|
||||
SOTemplate elements;
|
||||
|
||||
private:
|
||||
std::string const m_name;
|
||||
KeyType const m_type;
|
||||
};
|
||||
|
||||
private:
|
||||
// VFALCO TODO use String instead of std::string
|
||||
typedef std::map <std::string, Item*> NameMap;
|
||||
typedef std::map <KeyType, Item*> TypeMap;
|
||||
|
||||
public:
|
||||
/** Create the known formats object.
|
||||
|
||||
Derived classes will load the object will all the known formats.
|
||||
*/
|
||||
KnownFormats ()
|
||||
{
|
||||
}
|
||||
|
||||
/** Destroy the known formats object.
|
||||
|
||||
The defined formats are deleted.
|
||||
*/
|
||||
~KnownFormats ()
|
||||
{
|
||||
}
|
||||
|
||||
/** Retrieve the type for a format specified by name.
|
||||
|
||||
If the format name is unknown, an exception is thrown.
|
||||
|
||||
@param name The name of the type.
|
||||
@return The type.
|
||||
*/
|
||||
KeyType findTypeByName (std::string const name) const
|
||||
{
|
||||
Item const* const result = findByName (name);
|
||||
|
||||
if (result != nullptr)
|
||||
{
|
||||
return result->getType ();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error ("Unknown format name");
|
||||
}
|
||||
}
|
||||
|
||||
/** Retrieve a format based on its type.
|
||||
*/
|
||||
// VFALCO TODO Can we just return the SOElement& ?
|
||||
Item const* findByType (KeyType type) const noexcept
|
||||
{
|
||||
Item* result = nullptr;
|
||||
|
||||
typename TypeMap::const_iterator const iter = m_types.find (type);
|
||||
|
||||
if (iter != m_types.end ())
|
||||
{
|
||||
result = iter->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Retrieve a format based on its name.
|
||||
*/
|
||||
Item const* findByName (std::string const& name) const noexcept
|
||||
{
|
||||
Item* result = nullptr;
|
||||
|
||||
typename NameMap::const_iterator const iter = m_names.find (name);
|
||||
|
||||
if (iter != m_names.end ())
|
||||
{
|
||||
result = iter->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Add a new format.
|
||||
|
||||
The new format has the set of common fields already added.
|
||||
|
||||
@param name The name of this format.
|
||||
@param type The type of this format.
|
||||
|
||||
@return The created format.
|
||||
*/
|
||||
Item& add (char const* name, KeyType type)
|
||||
{
|
||||
Item& item = *m_formats.add (new Item (name, type));
|
||||
|
||||
addCommonFields (item);
|
||||
|
||||
m_types [item.getType ()] = &item;
|
||||
m_names [item.getName ()] = &item;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/** Adds common fields.
|
||||
|
||||
This is called for every new item.
|
||||
*/
|
||||
virtual void addCommonFields (Item& item) = 0;
|
||||
|
||||
private:
|
||||
OwnedArray <Item> m_formats;
|
||||
NameMap m_names;
|
||||
TypeMap m_types;
|
||||
};
|
||||
|
||||
#endif
|
||||
120
src/ripple_data/protocol/ripple_LedgerFormats.cpp
Normal file
120
src/ripple_data/protocol/ripple_LedgerFormats.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
LedgerFormats::LedgerFormats ()
|
||||
: SharedSingleton <LedgerFormats> (SingletonLifetime::persistAfterCreation)
|
||||
{
|
||||
add ("AccountRoot", ltACCOUNT_ROOT)
|
||||
<< SOElement (sfAccount, SOE_REQUIRED)
|
||||
<< SOElement (sfSequence, SOE_REQUIRED)
|
||||
<< SOElement (sfBalance, SOE_REQUIRED)
|
||||
<< SOElement (sfOwnerCount, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement (sfRegularKey, SOE_OPTIONAL)
|
||||
<< SOElement (sfEmailHash, SOE_OPTIONAL)
|
||||
<< SOElement (sfWalletLocator, SOE_OPTIONAL)
|
||||
<< SOElement (sfWalletSize, SOE_OPTIONAL)
|
||||
<< SOElement (sfMessageKey, SOE_OPTIONAL)
|
||||
<< SOElement (sfTransferRate, SOE_OPTIONAL)
|
||||
<< SOElement (sfDomain, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("Contract", ltCONTRACT)
|
||||
<< SOElement (sfAccount, SOE_REQUIRED)
|
||||
<< SOElement (sfBalance, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement (sfIssuer, SOE_REQUIRED)
|
||||
<< SOElement (sfOwner, SOE_REQUIRED)
|
||||
<< SOElement (sfExpiration, SOE_REQUIRED)
|
||||
<< SOElement (sfBondAmount, SOE_REQUIRED)
|
||||
<< SOElement (sfCreateCode, SOE_OPTIONAL)
|
||||
<< SOElement (sfFundCode, SOE_OPTIONAL)
|
||||
<< SOElement (sfRemoveCode, SOE_OPTIONAL)
|
||||
<< SOElement (sfExpireCode, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("DirectoryNode", ltDIR_NODE)
|
||||
<< SOElement (sfOwner, SOE_OPTIONAL) // for owner directories
|
||||
<< SOElement (sfTakerPaysCurrency, SOE_OPTIONAL) // for order book directories
|
||||
<< SOElement (sfTakerPaysIssuer, SOE_OPTIONAL) // for order book directories
|
||||
<< SOElement (sfTakerGetsCurrency, SOE_OPTIONAL) // for order book directories
|
||||
<< SOElement (sfTakerGetsIssuer, SOE_OPTIONAL) // for order book directories
|
||||
<< SOElement (sfExchangeRate, SOE_OPTIONAL) // for order book directories
|
||||
<< SOElement (sfIndexes, SOE_REQUIRED)
|
||||
<< SOElement (sfRootIndex, SOE_REQUIRED)
|
||||
<< SOElement (sfIndexNext, SOE_OPTIONAL)
|
||||
<< SOElement (sfIndexPrevious, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("GeneratorMap", ltGENERATOR_MAP)
|
||||
<< SOElement (sfGenerator, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("Nickname", ltNICKNAME)
|
||||
<< SOElement (sfAccount, SOE_REQUIRED)
|
||||
<< SOElement (sfMinimumOffer, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("Offer", ltOFFER)
|
||||
<< SOElement (sfAccount, SOE_REQUIRED)
|
||||
<< SOElement (sfSequence, SOE_REQUIRED)
|
||||
<< SOElement (sfTakerPays, SOE_REQUIRED)
|
||||
<< SOElement (sfTakerGets, SOE_REQUIRED)
|
||||
<< SOElement (sfBookDirectory, SOE_REQUIRED)
|
||||
<< SOElement (sfBookNode, SOE_REQUIRED)
|
||||
<< SOElement (sfOwnerNode, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement (sfExpiration, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("RippleState", ltRIPPLE_STATE)
|
||||
<< SOElement (sfBalance, SOE_REQUIRED)
|
||||
<< SOElement (sfLowLimit, SOE_REQUIRED)
|
||||
<< SOElement (sfHighLimit, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement (sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement (sfLowNode, SOE_OPTIONAL)
|
||||
<< SOElement (sfLowQualityIn, SOE_OPTIONAL)
|
||||
<< SOElement (sfLowQualityOut, SOE_OPTIONAL)
|
||||
<< SOElement (sfHighNode, SOE_OPTIONAL)
|
||||
<< SOElement (sfHighQualityIn, SOE_OPTIONAL)
|
||||
<< SOElement (sfHighQualityOut, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("LedgerHashes", ltLEDGER_HASHES)
|
||||
<< SOElement (sfFirstLedgerSequence, SOE_OPTIONAL) // Remove if we do a ledger restart
|
||||
<< SOElement (sfLastLedgerSequence, SOE_OPTIONAL)
|
||||
<< SOElement (sfHashes, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("EnabledFeatures", ltFEATURES)
|
||||
<< SOElement (sfFeatures, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("FeeSettings", ltFEE_SETTINGS)
|
||||
<< SOElement (sfBaseFee, SOE_REQUIRED)
|
||||
<< SOElement (sfReferenceFeeUnits, SOE_REQUIRED)
|
||||
<< SOElement (sfReserveBase, SOE_REQUIRED)
|
||||
<< SOElement (sfReserveIncrement, SOE_REQUIRED)
|
||||
;
|
||||
}
|
||||
|
||||
LedgerFormats* LedgerFormats::createInstance ()
|
||||
{
|
||||
return new LedgerFormats;
|
||||
}
|
||||
|
||||
void LedgerFormats::addCommonFields (Item& item)
|
||||
{
|
||||
item
|
||||
<< SOElement(sfLedgerIndex, SOE_OPTIONAL)
|
||||
<< SOElement(sfLedgerEntryType, SOE_REQUIRED)
|
||||
<< SOElement(sfFlags, SOE_REQUIRED)
|
||||
;
|
||||
}
|
||||
121
src/ripple_data/protocol/ripple_LedgerFormats.h
Normal file
121
src/ripple_data/protocol/ripple_LedgerFormats.h
Normal file
@@ -0,0 +1,121 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_LEDGERFORMATS_H_INCLUDED
|
||||
#define RIPPLE_LEDGERFORMATS_H_INCLUDED
|
||||
|
||||
/** Ledger entry types.
|
||||
|
||||
These are stored in serialized data.
|
||||
|
||||
@note Changing these values results in a hard fork.
|
||||
|
||||
@ingroup protocol
|
||||
*/
|
||||
// Used as the type of a transaction or the type of a ledger entry.
|
||||
enum LedgerEntryType
|
||||
{
|
||||
ltINVALID = -1,
|
||||
|
||||
ltACCOUNT_ROOT = 'a',
|
||||
|
||||
/** Directory node.
|
||||
|
||||
A directory is a vector 256-bit values. Usually they represent
|
||||
hashes of other objects in the ledger.
|
||||
|
||||
Used in an append-only fashion.
|
||||
|
||||
(There's a little more information than this, see the template)
|
||||
*/
|
||||
ltDIR_NODE = 'd',
|
||||
|
||||
ltGENERATOR_MAP = 'g',
|
||||
|
||||
/** Describes a trust line.
|
||||
*/
|
||||
// VFALCO TODO Rename to TrustLine or something similar.
|
||||
ltRIPPLE_STATE = 'r',
|
||||
|
||||
/** Deprecated.
|
||||
*/
|
||||
ltNICKNAME = 'n',
|
||||
|
||||
ltOFFER = 'o',
|
||||
|
||||
ltCONTRACT = 'c',
|
||||
|
||||
ltLEDGER_HASHES = 'h',
|
||||
|
||||
ltFEATURES = 'f',
|
||||
|
||||
ltFEE_SETTINGS = 's',
|
||||
};
|
||||
|
||||
/**
|
||||
@ingroup protocol
|
||||
*/
|
||||
// Used as a prefix for computing ledger indexes (keys).
|
||||
// VFALCO TODO Why are there a separate set of prefixes? i.e. class HashPrefix
|
||||
enum LedgerNameSpace
|
||||
{
|
||||
spaceAccount = 'a',
|
||||
spaceDirNode = 'd',
|
||||
spaceGenerator = 'g',
|
||||
spaceNickname = 'n',
|
||||
spaceRipple = 'r',
|
||||
spaceOffer = 'o', // Entry for an offer.
|
||||
spaceOwnerDir = 'O', // Directory of things owned by an account.
|
||||
spaceBookDir = 'B', // Directory of order books.
|
||||
spaceContract = 'c',
|
||||
spaceSkipList = 's',
|
||||
spaceFeature = 'f',
|
||||
spaceFee = 'e',
|
||||
};
|
||||
|
||||
/**
|
||||
@ingroup protocol
|
||||
*/
|
||||
enum LedgerSpecificFlags
|
||||
{
|
||||
// ltACCOUNT_ROOT
|
||||
lsfPasswordSpent = 0x00010000, // True, if password set fee is spent.
|
||||
lsfRequireDestTag = 0x00020000, // True, to require a DestinationTag for payments.
|
||||
lsfRequireAuth = 0x00040000, // True, to require a authorization to hold IOUs.
|
||||
lsfDisallowXRP = 0x00080000, // True, to disallow sending XRP.
|
||||
lsfDisableMaster = 0x00100000, // True, force regular key
|
||||
|
||||
// ltOFFER
|
||||
lsfPassive = 0x00010000,
|
||||
lsfSell = 0x00020000, // True, offer was placed as a sell.
|
||||
|
||||
// ltRIPPLE_STATE
|
||||
lsfLowReserve = 0x00010000, // True, if entry counts toward reserve.
|
||||
lsfHighReserve = 0x00020000,
|
||||
lsfLowAuth = 0x00040000,
|
||||
lsfHighAuth = 0x00080000,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Holds the list of known ledger entry formats.
|
||||
*/
|
||||
class LedgerFormats
|
||||
: public KnownFormats <LedgerEntryType>
|
||||
, public SharedSingleton <LedgerFormats>
|
||||
{
|
||||
private:
|
||||
LedgerFormats ();
|
||||
|
||||
public:
|
||||
static LedgerFormats* createInstance ();
|
||||
|
||||
private:
|
||||
void addCommonFields (Item& item);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
74
src/ripple_data/protocol/ripple_PackedMessage.cpp
Normal file
74
src/ripple_data/protocol/ripple_PackedMessage.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
PackedMessage::PackedMessage (::google::protobuf::Message const& message, int type)
|
||||
{
|
||||
unsigned const messageBytes = message.ByteSize ();
|
||||
|
||||
assert (messageBytes != 0);
|
||||
|
||||
mBuffer.resize (kHeaderBytes + messageBytes);
|
||||
|
||||
encodeHeader (messageBytes, type);
|
||||
|
||||
if (messageBytes != 0)
|
||||
{
|
||||
message.SerializeToArray (&mBuffer [PackedMessage::kHeaderBytes], messageBytes);
|
||||
|
||||
#ifdef BEAST_DEBUG
|
||||
//Log::out() << "PackedMessage: type=" << type << ", datalen=" << msg_size;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool PackedMessage::operator== (PackedMessage const& other) const
|
||||
{
|
||||
return mBuffer == other.mBuffer;
|
||||
}
|
||||
|
||||
unsigned PackedMessage::getLength (std::vector <uint8_t> const& buf)
|
||||
{
|
||||
unsigned result;
|
||||
|
||||
if (buf.size () >= PackedMessage::kHeaderBytes)
|
||||
{
|
||||
result = buf [0];
|
||||
result <<= 8;
|
||||
result |= buf [1];
|
||||
result <<= 8;
|
||||
result |= buf [2];
|
||||
result <<= 8;
|
||||
result |= buf [3];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int PackedMessage::getType (std::vector<uint8_t> const& buf)
|
||||
{
|
||||
if (buf.size () < PackedMessage::kHeaderBytes)
|
||||
return 0;
|
||||
|
||||
int ret = buf[4];
|
||||
ret <<= 8;
|
||||
ret |= buf[5];
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PackedMessage::encodeHeader (unsigned size, int type)
|
||||
{
|
||||
assert (mBuffer.size () >= PackedMessage::kHeaderBytes);
|
||||
mBuffer[0] = static_cast<boost::uint8_t> ((size >> 24) & 0xFF);
|
||||
mBuffer[1] = static_cast<boost::uint8_t> ((size >> 16) & 0xFF);
|
||||
mBuffer[2] = static_cast<boost::uint8_t> ((size >> 8) & 0xFF);
|
||||
mBuffer[3] = static_cast<boost::uint8_t> (size & 0xFF);
|
||||
mBuffer[4] = static_cast<boost::uint8_t> ((type >> 8) & 0xFF);
|
||||
mBuffer[5] = static_cast<boost::uint8_t> (type & 0xFF);
|
||||
}
|
||||
60
src/ripple_data/protocol/ripple_PackedMessage.h
Normal file
60
src/ripple_data/protocol/ripple_PackedMessage.h
Normal file
@@ -0,0 +1,60 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
//
|
||||
// packaging of messages into length/type-prepended buffers
|
||||
// ready for transmission.
|
||||
|
||||
#ifndef RIPPLE_PACKEDMESSAGE_H
|
||||
#define RIPPLE_PACKEDMESSAGE_H
|
||||
|
||||
// PackedMessage implements simple "packing" of protocol buffers Messages into
|
||||
// a string prepended by a header specifying the message length.
|
||||
// MessageType should be a Message class generated by the protobuf compiler.
|
||||
//
|
||||
|
||||
class PackedMessage : public boost::enable_shared_from_this <PackedMessage>
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr< ::google::protobuf::Message > MessagePointer;
|
||||
typedef boost::shared_ptr<PackedMessage> pointer;
|
||||
|
||||
public:
|
||||
/** Number of bytes in a message header.
|
||||
*/
|
||||
static unsigned const kHeaderBytes = 6;
|
||||
|
||||
PackedMessage (::google::protobuf::Message const& message, int type);
|
||||
|
||||
/** Retrieve the packed message data.
|
||||
*/
|
||||
// VFALCO TODO shouldn't this be const?
|
||||
std::vector <uint8_t>& getBuffer ()
|
||||
{
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
/** Determine bytewise equality.
|
||||
*/
|
||||
bool operator == (PackedMessage const& other) const;
|
||||
|
||||
/** Calculate the length of a packed message.
|
||||
*/
|
||||
static unsigned getLength (std::vector <uint8_t> const& buf);
|
||||
|
||||
/** Determine the type of a packed message.
|
||||
*/
|
||||
static int getType (std::vector <uint8_t> const& buf);
|
||||
|
||||
private:
|
||||
// Encodes the size and type into a header at the beginning of buf
|
||||
//
|
||||
void encodeHeader (unsigned size, int type);
|
||||
|
||||
std::vector <uint8_t> mBuffer;
|
||||
};
|
||||
|
||||
#endif /* PACKEDMESSAGE_H */
|
||||
|
||||
72
src/ripple_data/protocol/ripple_Protocol.h
Normal file
72
src/ripple_data/protocol/ripple_Protocol.h
Normal file
@@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROTOCOL_H
|
||||
#define RIPPLE_PROTOCOL_H
|
||||
|
||||
/** Protocol specific constants, types, and data.
|
||||
|
||||
This information is part of the Ripple protocol. Specifically,
|
||||
it is required for peers to be able to communicate with each other.
|
||||
|
||||
@note Changing these will create a hard fork.
|
||||
|
||||
@ingroup protocol
|
||||
@defgroup protocol
|
||||
*/
|
||||
struct Protocol
|
||||
{
|
||||
/** Smallest legal byte size of a transaction.
|
||||
*/
|
||||
static int const txMinSizeBytes = 32;
|
||||
|
||||
/** Largest legal byte size of a transaction.
|
||||
*/
|
||||
static int const txMaxSizeBytes = 1024 * 1024; // 1048576
|
||||
};
|
||||
|
||||
/*
|
||||
Hashes are used to uniquely identify objects like
|
||||
transactions, peers, validators, and accounts.
|
||||
|
||||
For historical reasons, some hashes are 256 bits and some are 160.
|
||||
|
||||
David:
|
||||
"The theory is that you may need to communicate public keys
|
||||
to others, so having them be shorter is a good idea. plus,
|
||||
you can't arbitrarily tweak them because you wouldn't know
|
||||
the corresponding private key anyway. So the security
|
||||
requirements aren't as great."
|
||||
*/
|
||||
|
||||
/** A ledger hash.
|
||||
*/
|
||||
typedef uint256 LedgerHash;
|
||||
|
||||
/** A ledger index.
|
||||
*/
|
||||
// VFALCO TODO pick one. I like Index since its not an abbreviation
|
||||
typedef uint32 LedgerIndex;
|
||||
// VFALCO NOTE "LedgerSeq" appears in some SQL statement text
|
||||
typedef uint32 LedgerSeq;
|
||||
|
||||
/** A transaction identifier.
|
||||
*/
|
||||
// VFALCO TODO maybe rename to TxHash
|
||||
typedef uint256 TxID;
|
||||
|
||||
/** A transaction index.
|
||||
*/
|
||||
typedef uint32 TxSeq; // VFALCO NOTE Should read TxIndex or TxNum
|
||||
|
||||
/** An account hash.
|
||||
|
||||
The hash is used to uniquely identify the account.
|
||||
*/
|
||||
//typedef uint160 AccountHash;
|
||||
//typedef uint260 ValidatorID;
|
||||
|
||||
#endif
|
||||
946
src/ripple_data/protocol/ripple_RippleAddress.cpp
Normal file
946
src/ripple_data/protocol/ripple_RippleAddress.cpp
Normal file
@@ -0,0 +1,946 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SETUP_LOG (RippleAddress)
|
||||
|
||||
RippleAddress::RippleAddress ()
|
||||
: mIsValid (false)
|
||||
{
|
||||
nVersion = VER_NONE;
|
||||
}
|
||||
|
||||
void RippleAddress::clear ()
|
||||
{
|
||||
nVersion = VER_NONE;
|
||||
vchData.clear ();
|
||||
}
|
||||
|
||||
bool RippleAddress::isSet () const
|
||||
{
|
||||
return nVersion != VER_NONE;
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanAddressType () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
return "VER_NONE";
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
return "VER_NODE_PUBLIC";
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
return "VER_NODE_PRIVATE";
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
return "VER_ACCOUNT_ID";
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
return "VER_ACCOUNT_PUBLIC";
|
||||
|
||||
case VER_ACCOUNT_PRIVATE:
|
||||
return "VER_ACCOUNT_PRIVATE";
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
return "VER_FAMILY_GENERATOR";
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
return "VER_FAMILY_SEED";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
//
|
||||
// NodePublic
|
||||
//
|
||||
|
||||
RippleAddress RippleAddress::createNodePublic (const RippleAddress& naSeed)
|
||||
{
|
||||
CKey ckSeed (naSeed.getSeed ());
|
||||
RippleAddress naNew;
|
||||
|
||||
// YYY Should there be a GetPubKey() equiv that returns a uint256?
|
||||
naNew.setNodePublic (ckSeed.GetPubKey ());
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createNodePublic (Blob const& vPublic)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setNodePublic (vPublic);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createNodePublic (const std::string& strPublic)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setNodePublic (strPublic);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
uint160 RippleAddress::getNodeID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getNodeID");
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
// Note, we are encoding the left.
|
||||
return Hash160 (vchData);
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
Blob const& RippleAddress::getNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getNodePublic");
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanNodePublic");
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setNodePublic (const std::string& strPublic)
|
||||
{
|
||||
mIsValid = SetString (strPublic.c_str (), VER_NODE_PUBLIC);
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
bool RippleAddress::verifyNodePublic (uint256 const& hash, Blob const& vchSig) const
|
||||
{
|
||||
CKey pubkey = CKey ();
|
||||
bool bVerified;
|
||||
|
||||
if (!pubkey.SetPubKey (getNodePublic ()))
|
||||
{
|
||||
// Failed to set public key.
|
||||
bVerified = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bVerified = pubkey.Verify (hash, vchSig);
|
||||
}
|
||||
|
||||
return bVerified;
|
||||
}
|
||||
|
||||
bool RippleAddress::verifyNodePublic (uint256 const& hash, const std::string& strSig) const
|
||||
{
|
||||
Blob vchSig (strSig.begin (), strSig.end ());
|
||||
|
||||
return verifyNodePublic (hash, vchSig);
|
||||
}
|
||||
|
||||
//
|
||||
// NodePrivate
|
||||
//
|
||||
|
||||
RippleAddress RippleAddress::createNodePrivate (const RippleAddress& naSeed)
|
||||
{
|
||||
uint256 uPrivKey;
|
||||
RippleAddress naNew;
|
||||
CKey ckSeed (naSeed.getSeed ());
|
||||
|
||||
ckSeed.GetPrivateKeyU (uPrivKey);
|
||||
|
||||
naNew.setNodePrivate (uPrivKey);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
Blob const& RippleAddress::getNodePrivateData () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getNodePrivateData");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
uint256 RippleAddress::getNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source = getNodePrivate");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
return uint256 (vchData);
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanNodePrivate");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setNodePrivate (const std::string& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (strPrivate.c_str (), VER_NODE_PRIVATE);
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PRIVATE, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PRIVATE, hash256.begin (), 32);
|
||||
}
|
||||
|
||||
void RippleAddress::signNodePrivate (uint256 const& hash, Blob& vchSig) const
|
||||
{
|
||||
CKey ckPrivKey;
|
||||
|
||||
ckPrivKey.SetPrivateKeyU (getNodePrivate ());
|
||||
|
||||
if (!ckPrivKey.Sign (hash, vchSig))
|
||||
throw std::runtime_error ("Signing failed.");
|
||||
}
|
||||
|
||||
//
|
||||
// AccountID
|
||||
//
|
||||
|
||||
uint160 RippleAddress::getAccountID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountID");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
return uint160 (vchData);
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
// Note, we are encoding the left.
|
||||
return Hash160 (vchData);
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
typedef RippleMutex StaticLockType;
|
||||
typedef StaticLockType::ScopedLockType StaticScopedLockType;
|
||||
static StaticLockType s_lock ("RippleAddress", __FILE__, __LINE__);
|
||||
|
||||
static boost::unordered_map< Blob , std::string > rncMap;
|
||||
|
||||
std::string RippleAddress::humanAccountID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanAccountID");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
{
|
||||
StaticScopedLockType sl (s_lock, __FILE__, __LINE__);
|
||||
boost::unordered_map< Blob , std::string >::iterator it = rncMap.find (vchData);
|
||||
|
||||
if (it != rncMap.end ())
|
||||
return it->second;
|
||||
|
||||
if (rncMap.size () > 10000)
|
||||
rncMap.clear ();
|
||||
|
||||
return rncMap[vchData] = ToString ();
|
||||
}
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
{
|
||||
RippleAddress accountID;
|
||||
|
||||
(void) accountID.setAccountID (getAccountID ());
|
||||
|
||||
return accountID.ToString ();
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setAccountID (const std::string& strAccountID, const char* pAlphabet)
|
||||
{
|
||||
if (strAccountID.empty ())
|
||||
{
|
||||
setAccountID (uint160 ());
|
||||
|
||||
mIsValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsValid = SetString (strAccountID.c_str (), VER_ACCOUNT_ID, pAlphabet);
|
||||
}
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountID (const uint160& hash160)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_ACCOUNT_ID, hash160.begin (), 20);
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPublic
|
||||
//
|
||||
|
||||
RippleAddress RippleAddress::createAccountPublic (const RippleAddress& naGenerator, int iSeq)
|
||||
{
|
||||
CKey ckPub (naGenerator, iSeq);
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setAccountPublic (ckPub.GetPubKey ());
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
Blob const& RippleAddress::getAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountPublic");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
throw std::runtime_error ("public not available from account id");
|
||||
break;
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanAccountPublic");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
throw std::runtime_error ("public not available from account id");
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setAccountPublic (const std::string& strPublic)
|
||||
{
|
||||
mIsValid = SetString (strPublic.c_str (), VER_ACCOUNT_PUBLIC);
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_ACCOUNT_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPublic (const RippleAddress& generator, int seq)
|
||||
{
|
||||
CKey pubkey = CKey (generator, seq);
|
||||
|
||||
setAccountPublic (pubkey.GetPubKey ());
|
||||
}
|
||||
|
||||
bool RippleAddress::accountPublicVerify (uint256 const& uHash, Blob const& vucSig) const
|
||||
{
|
||||
CKey ckPublic;
|
||||
bool bVerified;
|
||||
|
||||
if (!ckPublic.SetPubKey (getAccountPublic ()))
|
||||
{
|
||||
// Bad private key.
|
||||
WriteLog (lsWARNING, RippleAddress) << "accountPublicVerify: Bad private key.";
|
||||
bVerified = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bVerified = ckPublic.Verify (uHash, vucSig);
|
||||
}
|
||||
|
||||
return bVerified;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createAccountID (const uint160& uiAccountID)
|
||||
{
|
||||
RippleAddress na;
|
||||
|
||||
na.setAccountID (uiAccountID);
|
||||
|
||||
return na;
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPrivate
|
||||
//
|
||||
|
||||
RippleAddress RippleAddress::createAccountPrivate (const RippleAddress& naGenerator, const RippleAddress& naSeed, int iSeq)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setAccountPrivate (naGenerator, naSeed, iSeq);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
uint256 RippleAddress::getAccountPrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountPrivate");
|
||||
|
||||
case VER_ACCOUNT_PRIVATE:
|
||||
return uint256 (vchData);
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanAccountPrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanAccountPrivate");
|
||||
|
||||
case VER_ACCOUNT_PRIVATE:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setAccountPrivate (const std::string& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (strPrivate.c_str (), VER_ACCOUNT_PRIVATE);
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_ACCOUNT_PRIVATE, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_ACCOUNT_PRIVATE, hash256.begin (), 32);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (const RippleAddress& naGenerator, const RippleAddress& naSeed, int seq)
|
||||
{
|
||||
CKey ckPubkey = CKey (naSeed.getSeed ());
|
||||
CKey ckPrivkey = CKey (naGenerator, ckPubkey.GetSecretBN (), seq);
|
||||
uint256 uPrivKey;
|
||||
|
||||
ckPrivkey.GetPrivateKeyU (uPrivKey);
|
||||
|
||||
setAccountPrivate (uPrivKey);
|
||||
}
|
||||
|
||||
bool RippleAddress::accountPrivateSign (uint256 const& uHash, Blob& vucSig) const
|
||||
{
|
||||
CKey ckPrivate;
|
||||
bool bResult;
|
||||
|
||||
if (!ckPrivate.SetPrivateKeyU (getAccountPrivate ()))
|
||||
{
|
||||
// Bad private key.
|
||||
WriteLog (lsWARNING, RippleAddress) << "accountPrivateSign: Bad private key.";
|
||||
bResult = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bResult = ckPrivate.Sign (uHash, vucSig);
|
||||
CondLog (!bResult, lsWARNING, RippleAddress) << "accountPrivateSign: Signing failed.";
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool RippleAddress::accountPrivateVerify (uint256 const& uHash, Blob const& vucSig) const
|
||||
{
|
||||
CKey ckPrivate;
|
||||
bool bVerified;
|
||||
|
||||
if (!ckPrivate.SetPrivateKeyU (getAccountPrivate ()))
|
||||
{
|
||||
// Bad private key.
|
||||
WriteLog (lsWARNING, RippleAddress) << "accountPrivateVerify: Bad private key.";
|
||||
bVerified = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bVerified = ckPrivate.Verify (uHash, vucSig);
|
||||
}
|
||||
|
||||
return bVerified;
|
||||
}
|
||||
#endif
|
||||
|
||||
Blob RippleAddress::accountPrivateEncrypt (const RippleAddress& naPublicTo, Blob const& vucPlainText) const
|
||||
{
|
||||
CKey ckPrivate;
|
||||
CKey ckPublic;
|
||||
Blob vucCipherText;
|
||||
|
||||
if (!ckPublic.SetPubKey (naPublicTo.getAccountPublic ()))
|
||||
{
|
||||
// Bad public key.
|
||||
WriteLog (lsWARNING, RippleAddress) << "accountPrivateEncrypt: Bad public key.";
|
||||
}
|
||||
else if (!ckPrivate.SetPrivateKeyU (getAccountPrivate ()))
|
||||
{
|
||||
// Bad private key.
|
||||
WriteLog (lsWARNING, RippleAddress) << "accountPrivateEncrypt: Bad private key.";
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
vucCipherText = ckPrivate.encryptECIES (ckPublic, vucPlainText);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
nothing ();
|
||||
}
|
||||
}
|
||||
|
||||
return vucCipherText;
|
||||
}
|
||||
|
||||
Blob RippleAddress::accountPrivateDecrypt (const RippleAddress& naPublicFrom, Blob const& vucCipherText) const
|
||||
{
|
||||
CKey ckPrivate;
|
||||
CKey ckPublic;
|
||||
Blob vucPlainText;
|
||||
|
||||
if (!ckPublic.SetPubKey (naPublicFrom.getAccountPublic ()))
|
||||
{
|
||||
// Bad public key.
|
||||
WriteLog (lsWARNING, RippleAddress) << "accountPrivateDecrypt: Bad public key.";
|
||||
}
|
||||
else if (!ckPrivate.SetPrivateKeyU (getAccountPrivate ()))
|
||||
{
|
||||
// Bad private key.
|
||||
WriteLog (lsWARNING, RippleAddress) << "accountPrivateDecrypt: Bad private key.";
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
vucPlainText = ckPrivate.decryptECIES (ckPublic, vucCipherText);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
nothing ();
|
||||
}
|
||||
}
|
||||
|
||||
return vucPlainText;
|
||||
}
|
||||
|
||||
//
|
||||
// Generators
|
||||
//
|
||||
|
||||
BIGNUM* RippleAddress::getGeneratorBN () const
|
||||
{
|
||||
// returns the public generator
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getGeneratorBN");
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
|
||||
BIGNUM* ret = BN_bin2bn (&vchData[0], vchData.size (), NULL);
|
||||
assert (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Blob const& RippleAddress::getGenerator () const
|
||||
{
|
||||
// returns the public generator
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getGenerator");
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
// Do nothing.
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanGenerator () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanGenerator");
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setGenerator (const std::string& strGenerator)
|
||||
{
|
||||
mIsValid = SetString (strGenerator.c_str (), VER_FAMILY_GENERATOR);
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setGenerator (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_FAMILY_GENERATOR, vPublic);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createGeneratorPublic (const RippleAddress& naSeed)
|
||||
{
|
||||
CKey ckSeed (naSeed.getSeed ());
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setGenerator (ckSeed.GetPubKey ());
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
//
|
||||
// Seed
|
||||
//
|
||||
|
||||
uint128 RippleAddress::getSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getSeed");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
return uint128 (vchData);
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanSeed1751 () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanSeed1751");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
{
|
||||
std::string strHuman;
|
||||
std::string strLittle;
|
||||
std::string strBig;
|
||||
uint128 uSeed = getSeed ();
|
||||
|
||||
strLittle.assign (uSeed.begin (), uSeed.end ());
|
||||
|
||||
strBig.assign (strLittle.rbegin (), strLittle.rend ());
|
||||
|
||||
RFC1751::getEnglishFromKey (strHuman, strBig);
|
||||
|
||||
return strHuman;
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanSeed");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
throw std::runtime_error (str (boost::format ("bad source: %d") % int (nVersion)));
|
||||
}
|
||||
}
|
||||
|
||||
int RippleAddress::setSeed1751 (const std::string& strHuman1751)
|
||||
{
|
||||
std::string strKey;
|
||||
int iResult = RFC1751::getKeyFromEnglish (strKey, strHuman1751);
|
||||
|
||||
if (1 == iResult)
|
||||
{
|
||||
Blob vchLittle (strKey.rbegin (), strKey.rend ());
|
||||
uint128 uSeed (vchLittle);
|
||||
|
||||
setSeed (uSeed);
|
||||
}
|
||||
|
||||
return iResult;
|
||||
}
|
||||
|
||||
bool RippleAddress::setSeed (const std::string& strSeed)
|
||||
{
|
||||
mIsValid = SetString (strSeed.c_str (), VER_FAMILY_SEED);
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
bool RippleAddress::setSeedGeneric (const std::string& strText)
|
||||
{
|
||||
RippleAddress naTemp;
|
||||
bool bResult = true;
|
||||
uint128 uSeed;
|
||||
|
||||
if (strText.empty ()
|
||||
|| naTemp.setAccountID (strText)
|
||||
|| naTemp.setAccountPublic (strText)
|
||||
|| naTemp.setAccountPrivate (strText)
|
||||
|| naTemp.setNodePublic (strText)
|
||||
|| naTemp.setNodePrivate (strText))
|
||||
{
|
||||
bResult = false;
|
||||
}
|
||||
else if (strText.length () == 32 && uSeed.SetHex (strText, true))
|
||||
{
|
||||
setSeed (uSeed);
|
||||
}
|
||||
else if (setSeed (strText))
|
||||
{
|
||||
// Log::out() << "Recognized seed.";
|
||||
nothing ();
|
||||
}
|
||||
else if (1 == setSeed1751 (strText))
|
||||
{
|
||||
// Log::out() << "Recognized 1751 seed.";
|
||||
nothing ();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log::out() << "Creating seed from pass phrase.";
|
||||
setSeed (CKey::PassPhraseToKey (strText));
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
void RippleAddress::setSeed (uint128 hash128)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_FAMILY_SEED, hash128.begin (), 16);
|
||||
}
|
||||
|
||||
void RippleAddress::setSeedRandom ()
|
||||
{
|
||||
// XXX Maybe we should call MakeNewKey
|
||||
uint128 key;
|
||||
|
||||
RandomNumbers::getInstance ().fillBytes (key.begin (), key.size ());
|
||||
|
||||
RippleAddress::setSeed (key);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createSeedRandom ()
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setSeedRandom ();
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createSeedGeneric (const std::string& strText)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setSeedGeneric (strText);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class RippleAddressTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
RippleAddressTests () : UnitTest ("RippleAddress", "ripple")
|
||||
{
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
beginTestCase ("public/private");
|
||||
|
||||
// Construct a seed.
|
||||
RippleAddress naSeed;
|
||||
|
||||
expect (naSeed.setSeedGeneric ("masterpassphrase"));
|
||||
expect (naSeed.humanSeed () == "snoPBrXtMeMyMHUVTgbuqAfg1SUTb", naSeed.humanSeed ());
|
||||
|
||||
// Create node public/private key pair
|
||||
RippleAddress naNodePublic = RippleAddress::createNodePublic (naSeed);
|
||||
RippleAddress naNodePrivate = RippleAddress::createNodePrivate (naSeed);
|
||||
|
||||
expect (naNodePublic.humanNodePublic () == "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9", naNodePublic.humanNodePublic ());
|
||||
expect (naNodePrivate.humanNodePrivate () == "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe", naNodePrivate.humanNodePrivate ());
|
||||
|
||||
// Check node signing.
|
||||
Blob vucTextSrc = strCopy ("Hello, nurse!");
|
||||
uint256 uHash = Serializer::getSHA512Half (vucTextSrc);
|
||||
Blob vucTextSig;
|
||||
|
||||
naNodePrivate.signNodePrivate (uHash, vucTextSig);
|
||||
expect (naNodePublic.verifyNodePublic (uHash, vucTextSig), "Verify failed.");
|
||||
|
||||
// Construct a public generator from the seed.
|
||||
RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed);
|
||||
|
||||
expect (naGenerator.humanGenerator () == "fhuJKrhSDzV2SkjLn9qbwm5AaRmrxDPfFsHDCP6yfDZWcxDFz4mt", naGenerator.humanGenerator ());
|
||||
|
||||
// Create account #0 public/private key pair.
|
||||
RippleAddress naAccountPublic0 = RippleAddress::createAccountPublic (naGenerator, 0);
|
||||
RippleAddress naAccountPrivate0 = RippleAddress::createAccountPrivate (naGenerator, naSeed, 0);
|
||||
|
||||
expect (naAccountPublic0.humanAccountID () == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", naAccountPublic0.humanAccountID ());
|
||||
expect (naAccountPublic0.humanAccountPublic () == "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw", naAccountPublic0.humanAccountPublic ());
|
||||
expect (naAccountPrivate0.humanAccountPrivate () == "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh", naAccountPrivate0.humanAccountPrivate ());
|
||||
|
||||
// Create account #1 public/private key pair.
|
||||
RippleAddress naAccountPublic1 = RippleAddress::createAccountPublic (naGenerator, 1);
|
||||
RippleAddress naAccountPrivate1 = RippleAddress::createAccountPrivate (naGenerator, naSeed, 1);
|
||||
|
||||
expect (naAccountPublic1.humanAccountID () == "r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP", naAccountPublic1.humanAccountID ());
|
||||
expect (naAccountPublic1.humanAccountPublic () == "aBPXpTfuLy1Bhk3HnGTTAqnovpKWQ23NpFMNkAF6F1Atg5vDyPrw", naAccountPublic1.humanAccountPublic ());
|
||||
expect (naAccountPrivate1.humanAccountPrivate () == "p9JEm822LMrzJii1k7TvdphfENTp6G5jr253Xa5rkzUWVr8ogQt", naAccountPrivate1.humanAccountPrivate ());
|
||||
|
||||
// Check account signing.
|
||||
expect (naAccountPrivate0.accountPrivateSign (uHash, vucTextSig), "Signing failed.");
|
||||
expect (naAccountPublic0.accountPublicVerify (uHash, vucTextSig), "Verify failed.");
|
||||
expect (!naAccountPublic1.accountPublicVerify (uHash, vucTextSig), "Anti-verify failed.");
|
||||
|
||||
expect (naAccountPrivate1.accountPrivateSign (uHash, vucTextSig), "Signing failed.");
|
||||
expect (naAccountPublic1.accountPublicVerify (uHash, vucTextSig), "Verify failed.");
|
||||
expect (!naAccountPublic0.accountPublicVerify (uHash, vucTextSig), "Anti-verify failed.");
|
||||
|
||||
// Check account encryption.
|
||||
Blob vucTextCipher
|
||||
= naAccountPrivate0.accountPrivateEncrypt (naAccountPublic1, vucTextSrc);
|
||||
Blob vucTextRecovered
|
||||
= naAccountPrivate1.accountPrivateDecrypt (naAccountPublic0, vucTextCipher);
|
||||
|
||||
expect (vucTextSrc == vucTextRecovered, "Encrypt-decrypt failed.");
|
||||
}
|
||||
};
|
||||
|
||||
static RippleAddressTests rippleAddressTests;
|
||||
208
src/ripple_data/protocol/ripple_RippleAddress.h
Normal file
208
src/ripple_data/protocol/ripple_RippleAddress.h
Normal file
@@ -0,0 +1,208 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RIPPLEADDRESS_H
|
||||
#define RIPPLE_RIPPLEADDRESS_H
|
||||
|
||||
//
|
||||
// Used to hold addresses and parse and produce human formats.
|
||||
//
|
||||
// XXX This needs to be reworked to store data in uint160 and uint256. Conversion to CBase58Data should happen as needed.
|
||||
class RippleAddress : public CBase58Data
|
||||
{
|
||||
private:
|
||||
typedef enum
|
||||
{
|
||||
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,
|
||||
} VersionEncoding;
|
||||
|
||||
bool mIsValid;
|
||||
|
||||
public:
|
||||
RippleAddress ();
|
||||
|
||||
// For public and private key, checks if they are legal.
|
||||
bool isValid () const
|
||||
{
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void clear ();
|
||||
bool isSet () const;
|
||||
|
||||
std::string humanAddressType () const;
|
||||
|
||||
//
|
||||
// Node Public - Also used for Validators
|
||||
//
|
||||
uint160 getNodeID () const;
|
||||
Blob const& getNodePublic () const;
|
||||
|
||||
std::string humanNodePublic () const;
|
||||
|
||||
bool setNodePublic (const std::string& strPublic);
|
||||
void setNodePublic (Blob const& vPublic);
|
||||
bool verifyNodePublic (uint256 const& hash, Blob const& vchSig) const;
|
||||
bool verifyNodePublic (uint256 const& hash, const std::string& strSig) const;
|
||||
|
||||
static RippleAddress createNodePublic (const RippleAddress& naSeed);
|
||||
static RippleAddress createNodePublic (Blob const& vPublic);
|
||||
static RippleAddress createNodePublic (const std::string& strPublic);
|
||||
|
||||
//
|
||||
// Node Private
|
||||
//
|
||||
Blob const& getNodePrivateData () const;
|
||||
uint256 getNodePrivate () const;
|
||||
|
||||
std::string humanNodePrivate () const;
|
||||
|
||||
bool setNodePrivate (const std::string& strPrivate);
|
||||
void setNodePrivate (Blob const& vPrivate);
|
||||
void setNodePrivate (uint256 hash256);
|
||||
void signNodePrivate (uint256 const& hash, Blob& vchSig) const;
|
||||
|
||||
static RippleAddress createNodePrivate (const RippleAddress& naSeed);
|
||||
|
||||
//
|
||||
// Accounts IDs
|
||||
//
|
||||
uint160 getAccountID () const;
|
||||
|
||||
std::string humanAccountID () const;
|
||||
|
||||
bool setAccountID (const std::string& strAccountID, const char* pAlphabet = Base58::getCurrentAlphabet ());
|
||||
void setAccountID (const uint160& hash160In);
|
||||
|
||||
static RippleAddress createAccountID (const std::string& strAccountID)
|
||||
{
|
||||
RippleAddress na;
|
||||
na.setAccountID (strAccountID);
|
||||
return na;
|
||||
}
|
||||
|
||||
static RippleAddress createAccountID (const uint160& uiAccountID);
|
||||
|
||||
static std::string createHumanAccountID (const uint160& uiAccountID)
|
||||
{
|
||||
return createAccountID (uiAccountID).humanAccountID ();
|
||||
}
|
||||
|
||||
static std::string createHumanAccountID (Blob const& vPrivate)
|
||||
{
|
||||
return createAccountPrivate (vPrivate).humanAccountID ();
|
||||
}
|
||||
|
||||
//
|
||||
// Accounts Public
|
||||
//
|
||||
Blob const& getAccountPublic () const;
|
||||
|
||||
std::string humanAccountPublic () const;
|
||||
|
||||
bool setAccountPublic (const std::string& strPublic);
|
||||
void setAccountPublic (Blob const& vPublic);
|
||||
void setAccountPublic (const RippleAddress& generator, int seq);
|
||||
|
||||
bool accountPublicVerify (uint256 const& uHash, Blob const& vucSig) const;
|
||||
|
||||
static RippleAddress createAccountPublic (Blob const& vPublic)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setAccountPublic (vPublic);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
static std::string createHumanAccountPublic (Blob const& vPublic)
|
||||
{
|
||||
return createAccountPublic (vPublic).humanAccountPublic ();
|
||||
}
|
||||
|
||||
// Create a deterministic public key from a public generator.
|
||||
static RippleAddress createAccountPublic (const RippleAddress& naGenerator, int iSeq);
|
||||
|
||||
//
|
||||
// Accounts Private
|
||||
//
|
||||
uint256 getAccountPrivate () const;
|
||||
|
||||
std::string humanAccountPrivate () const;
|
||||
|
||||
bool setAccountPrivate (const std::string& strPrivate);
|
||||
void setAccountPrivate (Blob const& vPrivate);
|
||||
void setAccountPrivate (uint256 hash256);
|
||||
void setAccountPrivate (const RippleAddress& naGenerator, const RippleAddress& naSeed, int seq);
|
||||
|
||||
bool accountPrivateSign (uint256 const& uHash, Blob& vucSig) const;
|
||||
// bool accountPrivateVerify(uint256 const& uHash, Blob const& vucSig) const;
|
||||
|
||||
// Encrypt a message.
|
||||
Blob accountPrivateEncrypt (const RippleAddress& naPublicTo, Blob const& vucPlainText) const;
|
||||
|
||||
// Decrypt a message.
|
||||
Blob accountPrivateDecrypt (const RippleAddress& naPublicFrom, Blob const& vucCipherText) const;
|
||||
|
||||
static RippleAddress createAccountPrivate (const RippleAddress& naGenerator, const RippleAddress& naSeed, int iSeq);
|
||||
|
||||
static RippleAddress createAccountPrivate (Blob const& vPrivate)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setAccountPrivate (vPrivate);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
static std::string createHumanAccountPrivate (Blob const& vPrivate)
|
||||
{
|
||||
return createAccountPrivate (vPrivate).humanAccountPrivate ();
|
||||
}
|
||||
|
||||
//
|
||||
// Generators
|
||||
// Use to generate a master or regular family.
|
||||
//
|
||||
BIGNUM* getGeneratorBN () const; // DEPRECATED
|
||||
Blob const& getGenerator () const;
|
||||
|
||||
std::string humanGenerator () const;
|
||||
|
||||
bool setGenerator (const std::string& strGenerator);
|
||||
void setGenerator (Blob const& vPublic);
|
||||
// void setGenerator(const RippleAddress& seed);
|
||||
|
||||
// Create generator for making public deterministic keys.
|
||||
static RippleAddress createGeneratorPublic (const RippleAddress& naSeed);
|
||||
|
||||
//
|
||||
// Seeds
|
||||
// Clients must disallow reconizable entries from being seeds.
|
||||
uint128 getSeed () const;
|
||||
|
||||
std::string humanSeed () const;
|
||||
std::string humanSeed1751 () const;
|
||||
|
||||
bool setSeed (const std::string& strSeed);
|
||||
int setSeed1751 (const std::string& strHuman1751);
|
||||
bool setSeedGeneric (const std::string& strText);
|
||||
void setSeed (uint128 hash128);
|
||||
void setSeedRandom ();
|
||||
|
||||
static RippleAddress createSeedRandom ();
|
||||
static RippleAddress createSeedGeneric (const std::string& strText);
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
47
src/ripple_data/protocol/ripple_RippleSystem.h
Normal file
47
src/ripple_data/protocol/ripple_RippleSystem.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RIPPLESYSTEM_H
|
||||
#define RIPPLE_RIPPLESYSTEM_H
|
||||
|
||||
/** Protocol specific constant globals.
|
||||
*/
|
||||
// VFALCO NOTE use these from now on instead of the macros!!
|
||||
class RippleSystem
|
||||
{
|
||||
public:
|
||||
static inline char const* getSystemName ()
|
||||
{
|
||||
return "ripple";
|
||||
}
|
||||
|
||||
static char const* getCurrencyCode ()
|
||||
{
|
||||
return "XRP";
|
||||
}
|
||||
|
||||
static char const* getCurrencyCodeRipple ()
|
||||
{
|
||||
return "XRR";
|
||||
}
|
||||
|
||||
static int getCurrencyPrecision ()
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
};
|
||||
|
||||
// VFALCO TODO I would love to replace these macros with the language
|
||||
// constructs above. The problem is the way they are used at
|
||||
// the point of call, i.e. "User-agent:" SYSTEM_NAME
|
||||
// It will be necessary to rewrite some of them to use string streams.
|
||||
//
|
||||
#define SYSTEM_NAME "ripple"
|
||||
#define SYSTEM_CURRENCY_CODE "XRP"
|
||||
#define SYSTEM_CURRENCY_PRECISION 6
|
||||
#define SYSTEM_CURRENCY_CODE_RIPPLE "XRR"
|
||||
|
||||
#endif
|
||||
1924
src/ripple_data/protocol/ripple_STAmount.cpp
Normal file
1924
src/ripple_data/protocol/ripple_STAmount.cpp
Normal file
File diff suppressed because it is too large
Load Diff
300
src/ripple_data/protocol/ripple_STAmountRound.cpp
Normal file
300
src/ripple_data/protocol/ripple_STAmountRound.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
void STAmount::canonicalizeRound (bool isNative, uint64& value, int& offset, bool roundUp)
|
||||
{
|
||||
if (!roundUp) // canonicalize already rounds down
|
||||
return;
|
||||
|
||||
WriteLog (lsTRACE, STAmount) << "canonicalize< " << value << ":" << offset << (roundUp ? " up" : " down");
|
||||
|
||||
if (isNative)
|
||||
{
|
||||
if (offset < 0)
|
||||
{
|
||||
int loops = 0;
|
||||
|
||||
while (offset < -1)
|
||||
{
|
||||
value /= 10;
|
||||
++offset;
|
||||
++loops;
|
||||
}
|
||||
|
||||
value += (loops >= 2) ? 9 : 10; // add before last divide
|
||||
value /= 10;
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
else if (value > STAmount::cMaxValue)
|
||||
{
|
||||
while (value > (10 * STAmount::cMaxValue))
|
||||
{
|
||||
value /= 10;
|
||||
++offset;
|
||||
}
|
||||
|
||||
value += 9; // add before last divide
|
||||
value /= 10;
|
||||
++offset;
|
||||
}
|
||||
|
||||
WriteLog (lsTRACE, STAmount) << "canonicalize> " << value << ":" << offset << (roundUp ? " up" : " down");
|
||||
}
|
||||
|
||||
STAmount STAmount::addRound (const STAmount& v1, const STAmount& v2, bool roundUp)
|
||||
{
|
||||
v1.throwComparable (v2);
|
||||
|
||||
if (v2.mValue == 0)
|
||||
return v1;
|
||||
|
||||
if (v1.mValue == 0)
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue, v2.mOffset, v2.mIsNegative);
|
||||
|
||||
if (v1.mIsNative)
|
||||
return STAmount (v1.getFName (), v1.getSNValue () + v2.getSNValue ());
|
||||
|
||||
int ov1 = v1.mOffset, ov2 = v2.mOffset;
|
||||
int64 vv1 = static_cast<int64> (v1.mValue), vv2 = static_cast<uint64> (v2.mValue);
|
||||
|
||||
if (v1.mIsNegative)
|
||||
vv1 = -vv1;
|
||||
|
||||
if (v2.mIsNegative)
|
||||
vv2 = -vv2;
|
||||
|
||||
if (ov1 < ov2)
|
||||
{
|
||||
while (ov1 < (ov2 - 1))
|
||||
{
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv1 += 9;
|
||||
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (ov2 < ov1)
|
||||
{
|
||||
while (ov2 < (ov1 - 1))
|
||||
{
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv2 += 9;
|
||||
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
int64 fv = vv1 + vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
|
||||
else if (fv >= 0)
|
||||
{
|
||||
uint64 v = static_cast<uint64> (fv);
|
||||
canonicalizeRound (false, v, ov1, roundUp);
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64 v = static_cast<uint64> (-fv);
|
||||
canonicalizeRound (false, v, ov1, !roundUp);
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, true);
|
||||
}
|
||||
}
|
||||
|
||||
STAmount STAmount::subRound (const STAmount& v1, const STAmount& v2, bool roundUp)
|
||||
{
|
||||
v1.throwComparable (v2);
|
||||
|
||||
if (v2.mValue == 0)
|
||||
return v1;
|
||||
|
||||
if (v1.mValue == 0)
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue, v2.mOffset, !v2.mIsNegative);
|
||||
|
||||
if (v1.mIsNative)
|
||||
return STAmount (v1.getFName (), v1.getSNValue () - v2.getSNValue ());
|
||||
|
||||
int ov1 = v1.mOffset, ov2 = v2.mOffset;
|
||||
int64 vv1 = static_cast<int64> (v1.mValue), vv2 = static_cast<uint64> (v2.mValue);
|
||||
|
||||
if (v1.mIsNegative)
|
||||
vv1 = -vv1;
|
||||
|
||||
if (!v2.mIsNegative)
|
||||
vv2 = -vv2;
|
||||
|
||||
if (ov1 < ov2)
|
||||
{
|
||||
while (ov1 < (ov2 - 1))
|
||||
{
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv1 += 9;
|
||||
|
||||
vv1 /= 10;
|
||||
++ov1;
|
||||
}
|
||||
|
||||
if (ov2 < ov1)
|
||||
{
|
||||
while (ov2 < (ov1 - 1))
|
||||
{
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
if (roundUp)
|
||||
vv2 += 9;
|
||||
|
||||
vv2 /= 10;
|
||||
++ov2;
|
||||
}
|
||||
|
||||
int64 fv = vv1 + vv2;
|
||||
|
||||
if ((fv >= -10) && (fv <= 10))
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
|
||||
else if (fv >= 0)
|
||||
{
|
||||
uint64 v = static_cast<uint64> (fv);
|
||||
canonicalizeRound (false, v, ov1, roundUp);
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64 v = static_cast<uint64> (-fv);
|
||||
canonicalizeRound (false, v, ov1, !roundUp);
|
||||
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, true);
|
||||
}
|
||||
}
|
||||
|
||||
STAmount STAmount::mulRound (const STAmount& v1, const STAmount& v2,
|
||||
const uint160& uCurrencyID, const uint160& uIssuerID, bool roundUp)
|
||||
{
|
||||
if (v1.isZero () || v2.isZero ())
|
||||
return STAmount (uCurrencyID, uIssuerID);
|
||||
|
||||
if (v1.mIsNative && v2.mIsNative && uCurrencyID.isZero ())
|
||||
{
|
||||
uint64 minV = (v1.getSNValue () < v2.getSNValue ()) ? v1.getSNValue () : v2.getSNValue ();
|
||||
uint64 maxV = (v1.getSNValue () < v2.getSNValue ()) ? v2.getSNValue () : v1.getSNValue ();
|
||||
|
||||
if (minV > 3000000000ull) // sqrt(cMaxNative)
|
||||
throw std::runtime_error ("Native value overflow");
|
||||
|
||||
if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
|
||||
throw std::runtime_error ("Native value overflow");
|
||||
|
||||
return STAmount (v1.getFName (), minV * maxV);
|
||||
}
|
||||
|
||||
uint64 value1 = v1.mValue, value2 = v2.mValue;
|
||||
int offset1 = v1.mOffset, offset2 = v2.mOffset;
|
||||
|
||||
if (v1.mIsNative)
|
||||
{
|
||||
while (value1 < STAmount::cMinValue)
|
||||
{
|
||||
value1 *= 10;
|
||||
--offset1;
|
||||
}
|
||||
}
|
||||
|
||||
if (v2.mIsNative)
|
||||
{
|
||||
while (value2 < STAmount::cMinValue)
|
||||
{
|
||||
value2 *= 10;
|
||||
--offset2;
|
||||
}
|
||||
}
|
||||
|
||||
bool resultNegative = v1.mIsNegative != v2.mIsNegative;
|
||||
// Compute (numerator * denominator) / 10^14 with rounding
|
||||
// 10^16 <= result <= 10^18
|
||||
CBigNum v;
|
||||
|
||||
if ((BN_add_word64 (&v, value1) != 1) || (BN_mul_word64 (&v, value2) != 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
if (resultNegative != roundUp) // rounding down is automatic when we divide
|
||||
BN_add_word64 (&v, tenTo14m1);
|
||||
|
||||
if (BN_div_word64 (&v, tenTo14) == ((uint64) - 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
// 10^16 <= product <= 10^18
|
||||
assert (BN_num_bytes (&v) <= 64);
|
||||
|
||||
uint64 amount = v.getuint64 ();
|
||||
int offset = offset1 + offset2 + 14;
|
||||
canonicalizeRound (uCurrencyID.isZero (), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (uCurrencyID, uIssuerID, amount, offset, resultNegative);
|
||||
}
|
||||
|
||||
STAmount STAmount::divRound (const STAmount& num, const STAmount& den,
|
||||
const uint160& uCurrencyID, const uint160& uIssuerID, bool roundUp)
|
||||
{
|
||||
if (den.isZero ())
|
||||
throw std::runtime_error ("division by zero");
|
||||
|
||||
if (num.isZero ())
|
||||
return STAmount (uCurrencyID, uIssuerID);
|
||||
|
||||
uint64 numVal = num.mValue, denVal = den.mValue;
|
||||
int numOffset = num.mOffset, denOffset = den.mOffset;
|
||||
|
||||
if (num.mIsNative)
|
||||
while (numVal < STAmount::cMinValue)
|
||||
{
|
||||
// Need to bring into range
|
||||
numVal *= 10;
|
||||
--numOffset;
|
||||
}
|
||||
|
||||
if (den.mIsNative)
|
||||
while (denVal < STAmount::cMinValue)
|
||||
{
|
||||
denVal *= 10;
|
||||
--denOffset;
|
||||
}
|
||||
|
||||
bool resultNegative = num.mIsNegative != den.mIsNegative;
|
||||
// Compute (numerator * 10^17) / denominator
|
||||
CBigNum v;
|
||||
|
||||
if ((BN_add_word64 (&v, numVal) != 1) || (BN_mul_word64 (&v, tenTo17) != 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
if (resultNegative != roundUp) // Rounding down is automatic when we divide
|
||||
BN_add_word64 (&v, denVal - 1);
|
||||
|
||||
if (BN_div_word64 (&v, denVal) == ((uint64) - 1))
|
||||
throw std::runtime_error ("internal bn error");
|
||||
|
||||
// 10^16 <= quotient <= 10^18
|
||||
assert (BN_num_bytes (&v) <= 64);
|
||||
|
||||
uint64 amount = v.getuint64 ();
|
||||
int offset = numOffset - denOffset - 17;
|
||||
canonicalizeRound (uCurrencyID.isZero (), amount, offset, resultNegative != roundUp);
|
||||
return STAmount (uCurrencyID, uIssuerID, amount, offset, resultNegative);
|
||||
}
|
||||
|
||||
186
src/ripple_data/protocol/ripple_SerializeDeclarations.h
Normal file
186
src/ripple_data/protocol/ripple_SerializeDeclarations.h
Normal file
@@ -0,0 +1,186 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// This is not really a header file, but it can be used as one with
|
||||
// appropriate #define statements.
|
||||
|
||||
/*
|
||||
Common type common field - 1 byte
|
||||
Common type uncommon field - 2 bytes
|
||||
...
|
||||
|
||||
Rarity of fields determines the number of bytes.
|
||||
This is done to reduce the average size of the messages.
|
||||
*/
|
||||
|
||||
// types (common)
|
||||
TYPE (Int16, UINT16, 1)
|
||||
TYPE (Int32, UINT32, 2)
|
||||
TYPE (Int64, UINT64, 3)
|
||||
TYPE (Hash128, HASH128, 4)
|
||||
TYPE (Hash256, HASH256, 5)
|
||||
TYPE (Amount, AMOUNT, 6)
|
||||
TYPE (VariableLength, VL, 7)
|
||||
TYPE (Account, ACCOUNT, 8)
|
||||
// 9-13 are reserved
|
||||
TYPE (Object, OBJECT, 14)
|
||||
TYPE (Array, ARRAY, 15)
|
||||
|
||||
// types (uncommon)
|
||||
TYPE (Int8, UINT8, 16)
|
||||
TYPE (Hash160, HASH160, 17)
|
||||
TYPE (PathSet, PATHSET, 18)
|
||||
TYPE (Vector256, VECTOR256, 19)
|
||||
|
||||
|
||||
|
||||
// 8-bit integers
|
||||
FIELD (CloseResolution, UINT8, 1)
|
||||
FIELD (TemplateEntryType, UINT8, 2)
|
||||
FIELD (TransactionResult, UINT8, 3)
|
||||
|
||||
// 16-bit integers
|
||||
FIELD (LedgerEntryType, UINT16, 1)
|
||||
FIELD (TransactionType, UINT16, 2)
|
||||
|
||||
// 32-bit integers (common)
|
||||
FIELD (Flags, UINT32, 2)
|
||||
FIELD (SourceTag, UINT32, 3)
|
||||
FIELD (Sequence, UINT32, 4)
|
||||
FIELD (PreviousTxnLgrSeq, UINT32, 5)
|
||||
FIELD (LedgerSequence, UINT32, 6)
|
||||
FIELD (CloseTime, UINT32, 7)
|
||||
FIELD (ParentCloseTime, UINT32, 8)
|
||||
FIELD (SigningTime, UINT32, 9)
|
||||
FIELD (Expiration, UINT32, 10)
|
||||
FIELD (TransferRate, UINT32, 11)
|
||||
FIELD (WalletSize, UINT32, 12)
|
||||
FIELD (OwnerCount, UINT32, 13)
|
||||
FIELD (DestinationTag, UINT32, 14)
|
||||
|
||||
// 32-bit integers (uncommon)
|
||||
FIELD (HighQualityIn, UINT32, 16)
|
||||
FIELD (HighQualityOut, UINT32, 17)
|
||||
FIELD (LowQualityIn, UINT32, 18)
|
||||
FIELD (LowQualityOut, UINT32, 19)
|
||||
FIELD (QualityIn, UINT32, 20)
|
||||
FIELD (QualityOut, UINT32, 21)
|
||||
FIELD (StampEscrow, UINT32, 22)
|
||||
FIELD (BondAmount, UINT32, 23)
|
||||
FIELD (LoadFee, UINT32, 24)
|
||||
FIELD (OfferSequence, UINT32, 25)
|
||||
FIELD (FirstLedgerSequence, UINT32, 26) // Deprecated: do not use
|
||||
FIELD (LastLedgerSequence, UINT32, 27)
|
||||
FIELD (TransactionIndex, UINT32, 28)
|
||||
FIELD (OperationLimit, UINT32, 29)
|
||||
FIELD (ReferenceFeeUnits, UINT32, 30)
|
||||
FIELD (ReserveBase, UINT32, 31)
|
||||
FIELD (ReserveIncrement, UINT32, 32)
|
||||
FIELD (SetFlag, UINT32, 33)
|
||||
FIELD (ClearFlag, UINT32, 34)
|
||||
|
||||
// 64-bit integers
|
||||
FIELD (IndexNext, UINT64, 1)
|
||||
FIELD (IndexPrevious, UINT64, 2)
|
||||
FIELD (BookNode, UINT64, 3)
|
||||
FIELD (OwnerNode, UINT64, 4)
|
||||
FIELD (BaseFee, UINT64, 5)
|
||||
FIELD (ExchangeRate, UINT64, 6)
|
||||
FIELD (LowNode, UINT64, 7)
|
||||
FIELD (HighNode, UINT64, 8)
|
||||
|
||||
|
||||
// 128-bit
|
||||
FIELD (EmailHash, HASH128, 1)
|
||||
|
||||
// 256-bit (common)
|
||||
FIELD (LedgerHash, HASH256, 1)
|
||||
FIELD (ParentHash, HASH256, 2)
|
||||
FIELD (TransactionHash, HASH256, 3)
|
||||
FIELD (AccountHash, HASH256, 4)
|
||||
FIELD (PreviousTxnID, HASH256, 5)
|
||||
FIELD (LedgerIndex, HASH256, 6)
|
||||
FIELD (WalletLocator, HASH256, 7)
|
||||
FIELD (RootIndex, HASH256, 8)
|
||||
|
||||
// 256-bit (uncommon)
|
||||
FIELD (BookDirectory, HASH256, 16)
|
||||
FIELD (InvoiceID, HASH256, 17)
|
||||
FIELD (Nickname, HASH256, 18)
|
||||
FIELD (Feature, HASH256, 19)
|
||||
|
||||
// 160-bit (common)
|
||||
FIELD (TakerPaysCurrency, HASH160, 1)
|
||||
FIELD (TakerPaysIssuer, HASH160, 2)
|
||||
FIELD (TakerGetsCurrency, HASH160, 3)
|
||||
FIELD (TakerGetsIssuer, HASH160, 4)
|
||||
|
||||
// currency amount (common)
|
||||
FIELD (Amount, AMOUNT, 1)
|
||||
FIELD (Balance, AMOUNT, 2)
|
||||
FIELD (LimitAmount, AMOUNT, 3)
|
||||
FIELD (TakerPays, AMOUNT, 4)
|
||||
FIELD (TakerGets, AMOUNT, 5)
|
||||
FIELD (LowLimit, AMOUNT, 6)
|
||||
FIELD (HighLimit, AMOUNT, 7)
|
||||
FIELD (Fee, AMOUNT, 8)
|
||||
FIELD (SendMax, AMOUNT, 9)
|
||||
|
||||
// currency amount (uncommon)
|
||||
FIELD (MinimumOffer, AMOUNT, 16)
|
||||
FIELD (RippleEscrow, AMOUNT, 17)
|
||||
|
||||
// variable length
|
||||
FIELD (PublicKey, VL, 1)
|
||||
FIELD (MessageKey, VL, 2)
|
||||
FIELD (SigningPubKey, VL, 3)
|
||||
FIELD (TxnSignature, VL, 4)
|
||||
FIELD (Generator, VL, 5)
|
||||
FIELD (Signature, VL, 6)
|
||||
FIELD (Domain, VL, 7)
|
||||
FIELD (FundCode, VL, 8)
|
||||
FIELD (RemoveCode, VL, 9)
|
||||
FIELD (ExpireCode, VL, 10)
|
||||
FIELD (CreateCode, VL, 11)
|
||||
|
||||
// account
|
||||
FIELD (Account, ACCOUNT, 1)
|
||||
FIELD (Owner, ACCOUNT, 2)
|
||||
FIELD (Destination, ACCOUNT, 3)
|
||||
FIELD (Issuer, ACCOUNT, 4)
|
||||
FIELD (Target, ACCOUNT, 7)
|
||||
FIELD (RegularKey, ACCOUNT, 8)
|
||||
|
||||
// path set
|
||||
FIELD (Paths, PATHSET, 1)
|
||||
|
||||
// vector of 256-bit
|
||||
FIELD (Indexes, VECTOR256, 1)
|
||||
FIELD (Hashes, VECTOR256, 2)
|
||||
FIELD (Features, VECTOR256, 3)
|
||||
|
||||
// inner object
|
||||
// OBJECT/1 is reserved for end of object
|
||||
FIELD (TransactionMetaData, OBJECT, 2)
|
||||
FIELD (CreatedNode, OBJECT, 3)
|
||||
FIELD (DeletedNode, OBJECT, 4)
|
||||
FIELD (ModifiedNode, OBJECT, 5)
|
||||
FIELD (PreviousFields, OBJECT, 6)
|
||||
FIELD (FinalFields, OBJECT, 7)
|
||||
FIELD (NewFields, OBJECT, 8)
|
||||
FIELD (TemplateEntry, OBJECT, 9)
|
||||
|
||||
// array of objects
|
||||
// ARRAY/1 is reserved for end of array
|
||||
FIELD (SigningAccounts, ARRAY, 2)
|
||||
FIELD (TxnSignatures, ARRAY, 3)
|
||||
FIELD (Signatures, ARRAY, 4)
|
||||
FIELD (Template, ARRAY, 5)
|
||||
FIELD (Necessary, ARRAY, 6)
|
||||
FIELD (Sufficient, ARRAY, 7)
|
||||
FIELD (AffectedNodes, ARRAY, 8)
|
||||
|
||||
// vim:ts=4
|
||||
1654
src/ripple_data/protocol/ripple_SerializedObject.cpp
Normal file
1654
src/ripple_data/protocol/ripple_SerializedObject.cpp
Normal file
File diff suppressed because it is too large
Load Diff
510
src/ripple_data/protocol/ripple_SerializedObject.h
Normal file
510
src/ripple_data/protocol/ripple_SerializedObject.h
Normal file
@@ -0,0 +1,510 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_SERIALIZEDOBJECT_H
|
||||
#define RIPPLE_SERIALIZEDOBJECT_H
|
||||
|
||||
class STObject
|
||||
: public SerializedType
|
||||
, public CountedObject <STObject>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "STObject"; }
|
||||
|
||||
STObject () : mType (NULL)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
explicit STObject (SField::ref name) : SerializedType (name), mType (NULL)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
STObject (const SOTemplate & type, SField::ref name) : SerializedType (name)
|
||||
{
|
||||
set (type);
|
||||
}
|
||||
|
||||
STObject (const SOTemplate & type, SerializerIterator & sit, SField::ref name) : SerializedType (name)
|
||||
{
|
||||
set (sit);
|
||||
setType (type);
|
||||
}
|
||||
|
||||
UPTR_T<STObject> oClone () const
|
||||
{
|
||||
return UPTR_T<STObject> (new STObject (*this));
|
||||
}
|
||||
|
||||
static UPTR_T<STObject> parseJson (const Json::Value & value, SField::ref name = sfGeneric, int depth = 0);
|
||||
|
||||
virtual ~STObject ()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static UPTR_T<SerializedType> deserialize (SerializerIterator & sit, SField::ref name);
|
||||
|
||||
bool setType (const SOTemplate & type);
|
||||
bool isValidForType ();
|
||||
bool isFieldAllowed (SField::ref);
|
||||
bool isFree () const
|
||||
{
|
||||
return mType == NULL;
|
||||
}
|
||||
|
||||
void set (const SOTemplate&);
|
||||
bool set (SerializerIterator & u, int depth = 0);
|
||||
|
||||
virtual SerializedTypeID getSType () const
|
||||
{
|
||||
return STI_OBJECT;
|
||||
}
|
||||
virtual bool isEquivalent (const SerializedType & t) const;
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
return mData.empty ();
|
||||
}
|
||||
|
||||
virtual void add (Serializer & s) const
|
||||
{
|
||||
add (s, true); // just inner elements
|
||||
}
|
||||
|
||||
void add (Serializer & s, bool withSignature) const;
|
||||
|
||||
// VFALCO NOTE does this return an expensive copy of an object with a dynamic buffer?
|
||||
// VFALCO TODO Remove this function and fix the few callers.
|
||||
Serializer getSerializer () const
|
||||
{
|
||||
Serializer s;
|
||||
add (s);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string getFullText () const;
|
||||
std::string getText () const;
|
||||
virtual Json::Value getJson (int options) const;
|
||||
|
||||
int addObject (const SerializedType & t)
|
||||
{
|
||||
mData.push_back (t.clone ().release ());
|
||||
return mData.size () - 1;
|
||||
}
|
||||
int giveObject (UPTR_T<SerializedType> t)
|
||||
{
|
||||
mData.push_back (t.release ());
|
||||
return mData.size () - 1;
|
||||
}
|
||||
int giveObject (SerializedType * t)
|
||||
{
|
||||
mData.push_back (t);
|
||||
return mData.size () - 1;
|
||||
}
|
||||
const boost::ptr_vector<SerializedType>& peekData () const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
boost::ptr_vector<SerializedType>& peekData ()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
SerializedType& front ()
|
||||
{
|
||||
return mData.front ();
|
||||
}
|
||||
const SerializedType& front () const
|
||||
{
|
||||
return mData.front ();
|
||||
}
|
||||
SerializedType& back ()
|
||||
{
|
||||
return mData.back ();
|
||||
}
|
||||
const SerializedType& back () const
|
||||
{
|
||||
return mData.back ();
|
||||
}
|
||||
|
||||
int getCount () const
|
||||
{
|
||||
return mData.size ();
|
||||
}
|
||||
|
||||
bool setFlag (uint32);
|
||||
bool clearFlag (uint32);
|
||||
bool isFlag(uint32);
|
||||
uint32 getFlags () const;
|
||||
|
||||
uint256 getHash (uint32 prefix) const;
|
||||
uint256 getSigningHash (uint32 prefix) const;
|
||||
|
||||
const SerializedType& peekAtIndex (int offset) const
|
||||
{
|
||||
return mData[offset];
|
||||
}
|
||||
SerializedType& getIndex (int offset)
|
||||
{
|
||||
return mData[offset];
|
||||
}
|
||||
const SerializedType* peekAtPIndex (int offset) const
|
||||
{
|
||||
return & (mData[offset]);
|
||||
}
|
||||
SerializedType* getPIndex (int offset)
|
||||
{
|
||||
return & (mData[offset]);
|
||||
}
|
||||
|
||||
int getFieldIndex (SField::ref field) const;
|
||||
SField::ref getFieldSType (int index) const;
|
||||
|
||||
const SerializedType& peekAtField (SField::ref field) const;
|
||||
SerializedType& getField (SField::ref field);
|
||||
const SerializedType* peekAtPField (SField::ref field) const;
|
||||
SerializedType* getPField (SField::ref field, bool createOkay = false);
|
||||
|
||||
// these throw if the field type doesn't match, or return default values if the
|
||||
// field is optional but not present
|
||||
std::string getFieldString (SField::ref field) const;
|
||||
unsigned char getFieldU8 (SField::ref field) const;
|
||||
uint16 getFieldU16 (SField::ref field) const;
|
||||
uint32 getFieldU32 (SField::ref field) const;
|
||||
uint64 getFieldU64 (SField::ref field) const;
|
||||
uint128 getFieldH128 (SField::ref field) const;
|
||||
uint160 getFieldH160 (SField::ref field) const;
|
||||
uint256 getFieldH256 (SField::ref field) const;
|
||||
RippleAddress getFieldAccount (SField::ref field) const;
|
||||
uint160 getFieldAccount160 (SField::ref field) const;
|
||||
Blob getFieldVL (SField::ref field) const;
|
||||
const STAmount& getFieldAmount (SField::ref field) const;
|
||||
const STPathSet& getFieldPathSet (SField::ref field) const;
|
||||
const STVector256& getFieldV256 (SField::ref field) const;
|
||||
|
||||
void setFieldU8 (SField::ref field, unsigned char);
|
||||
void setFieldU16 (SField::ref field, uint16);
|
||||
void setFieldU32 (SField::ref field, uint32);
|
||||
void setFieldU64 (SField::ref field, uint64);
|
||||
void setFieldH128 (SField::ref field, const uint128&);
|
||||
void setFieldH160 (SField::ref field, const uint160&);
|
||||
void setFieldH256 (SField::ref field, uint256 const& );
|
||||
void setFieldVL (SField::ref field, Blob const&);
|
||||
void setFieldAccount (SField::ref field, const uint160&);
|
||||
void setFieldAccount (SField::ref field, const RippleAddress & addr)
|
||||
{
|
||||
setFieldAccount (field, addr.getAccountID ());
|
||||
}
|
||||
void setFieldAmount (SField::ref field, const STAmount&);
|
||||
void setFieldPathSet (SField::ref field, const STPathSet&);
|
||||
void setFieldV256 (SField::ref field, const STVector256 & v);
|
||||
|
||||
STObject& peekFieldObject (SField::ref field);
|
||||
|
||||
bool isFieldPresent (SField::ref field) const;
|
||||
SerializedType* makeFieldPresent (SField::ref field);
|
||||
void makeFieldAbsent (SField::ref field);
|
||||
bool delField (SField::ref field);
|
||||
void delField (int index);
|
||||
|
||||
static UPTR_T <SerializedType> makeDefaultObject (SerializedTypeID id, SField::ref name);
|
||||
|
||||
// VFALCO TODO remove the 'depth' parameter
|
||||
static UPTR_T<SerializedType> makeDeserializedObject (
|
||||
SerializedTypeID id,
|
||||
SField::ref name,
|
||||
SerializerIterator&,
|
||||
int depth);
|
||||
|
||||
static UPTR_T<SerializedType> makeNonPresentObject (SField::ref name)
|
||||
{
|
||||
return makeDefaultObject (STI_NOTPRESENT, name);
|
||||
}
|
||||
|
||||
static UPTR_T<SerializedType> makeDefaultObject (SField::ref name)
|
||||
{
|
||||
return makeDefaultObject (name.fieldType, name);
|
||||
}
|
||||
|
||||
// field iterator stuff
|
||||
typedef boost::ptr_vector<SerializedType>::iterator iterator;
|
||||
typedef boost::ptr_vector<SerializedType>::const_iterator const_iterator;
|
||||
iterator begin ()
|
||||
{
|
||||
return mData.begin ();
|
||||
}
|
||||
iterator end ()
|
||||
{
|
||||
return mData.end ();
|
||||
}
|
||||
const_iterator begin () const
|
||||
{
|
||||
return mData.begin ();
|
||||
}
|
||||
const_iterator end () const
|
||||
{
|
||||
return mData.end ();
|
||||
}
|
||||
bool empty () const
|
||||
{
|
||||
return mData.empty ();
|
||||
}
|
||||
|
||||
bool hasMatchingEntry (const SerializedType&);
|
||||
|
||||
bool operator== (const STObject & o) const;
|
||||
bool operator!= (const STObject & o) const
|
||||
{
|
||||
return ! (*this == o);
|
||||
}
|
||||
|
||||
private:
|
||||
/** Returns a value or throws if out of range.
|
||||
|
||||
This will throw if the source value cannot be represented
|
||||
within the destination type.
|
||||
*/
|
||||
// VFALCO NOTE This won't work right
|
||||
/*
|
||||
template <class T, class U>
|
||||
static T getWithRangeCheck (U v)
|
||||
{
|
||||
if (v < std::numeric_limits <T>::min ()) ||
|
||||
v > std::numeric_limits <T>::max ())
|
||||
{
|
||||
throw std::runtime_error ("Value out of range");
|
||||
}
|
||||
|
||||
return static_cast <T> (v);
|
||||
}
|
||||
*/
|
||||
|
||||
// VFALCO TODO these parameters should not be const references.
|
||||
template <typename T, typename U>
|
||||
static T range_check_cast (const U& value, const T& minimum, const T& maximum)
|
||||
{
|
||||
if ((value < minimum) || (value > maximum))
|
||||
throw std::runtime_error ("Value out of range");
|
||||
|
||||
return static_cast<T> (value);
|
||||
}
|
||||
|
||||
STObject* duplicate () const
|
||||
{
|
||||
return new STObject (*this);
|
||||
}
|
||||
|
||||
STObject (SField::ref name, boost::ptr_vector<SerializedType>& data) : SerializedType (name), mType (NULL)
|
||||
{
|
||||
mData.swap (data);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::ptr_vector<SerializedType> mData;
|
||||
const SOTemplate* mType;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline STObject::iterator range_begin (STObject& x)
|
||||
{
|
||||
return x.begin ();
|
||||
}
|
||||
inline STObject::iterator range_end (STObject& x)
|
||||
{
|
||||
return x.end ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class STArray
|
||||
: public SerializedType
|
||||
, public CountedObject <STArray>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "STArray"; }
|
||||
|
||||
typedef boost::ptr_vector<STObject> vector;
|
||||
typedef boost::ptr_vector<STObject>::iterator iterator;
|
||||
typedef boost::ptr_vector<STObject>::const_iterator const_iterator;
|
||||
typedef boost::ptr_vector<STObject>::reverse_iterator reverse_iterator;
|
||||
typedef boost::ptr_vector<STObject>::const_reverse_iterator const_reverse_iterator;
|
||||
typedef boost::ptr_vector<STObject>::size_type size_type;
|
||||
|
||||
public:
|
||||
STArray ()
|
||||
{
|
||||
;
|
||||
}
|
||||
explicit STArray (int n)
|
||||
{
|
||||
value.reserve (n);
|
||||
}
|
||||
explicit STArray (SField::ref f) : SerializedType (f)
|
||||
{
|
||||
;
|
||||
}
|
||||
STArray (SField::ref f, int n) : SerializedType (f)
|
||||
{
|
||||
value.reserve (n);
|
||||
}
|
||||
STArray (SField::ref f, const vector & v) : SerializedType (f), value (v)
|
||||
{
|
||||
;
|
||||
}
|
||||
explicit STArray (vector & v) : value (v)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static UPTR_T<SerializedType> deserialize (SerializerIterator & sit, SField::ref name)
|
||||
{
|
||||
return UPTR_T<SerializedType> (construct (sit, name));
|
||||
}
|
||||
|
||||
const vector& getValue () const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
vector& getValue ()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
// VFALCO NOTE as long as we're married to boost why not use boost::iterator_facade?
|
||||
//
|
||||
// vector-like functions
|
||||
void push_back (const STObject & object)
|
||||
{
|
||||
value.push_back (object.oClone ().release ());
|
||||
}
|
||||
STObject& operator[] (int j)
|
||||
{
|
||||
return value[j];
|
||||
}
|
||||
const STObject& operator[] (int j) const
|
||||
{
|
||||
return value[j];
|
||||
}
|
||||
iterator begin ()
|
||||
{
|
||||
return value.begin ();
|
||||
}
|
||||
const_iterator begin () const
|
||||
{
|
||||
return value.begin ();
|
||||
}
|
||||
iterator end ()
|
||||
{
|
||||
return value.end ();
|
||||
}
|
||||
const_iterator end () const
|
||||
{
|
||||
return value.end ();
|
||||
}
|
||||
size_type size () const
|
||||
{
|
||||
return value.size ();
|
||||
}
|
||||
reverse_iterator rbegin ()
|
||||
{
|
||||
return value.rbegin ();
|
||||
}
|
||||
const_reverse_iterator rbegin () const
|
||||
{
|
||||
return value.rbegin ();
|
||||
}
|
||||
reverse_iterator rend ()
|
||||
{
|
||||
return value.rend ();
|
||||
}
|
||||
const_reverse_iterator rend () const
|
||||
{
|
||||
return value.rend ();
|
||||
}
|
||||
iterator erase (iterator pos)
|
||||
{
|
||||
return value.erase (pos);
|
||||
}
|
||||
STObject& front ()
|
||||
{
|
||||
return value.front ();
|
||||
}
|
||||
const STObject& front () const
|
||||
{
|
||||
return value.front ();
|
||||
}
|
||||
STObject& back ()
|
||||
{
|
||||
return value.back ();
|
||||
}
|
||||
const STObject& back () const
|
||||
{
|
||||
return value.back ();
|
||||
}
|
||||
void pop_back ()
|
||||
{
|
||||
value.pop_back ();
|
||||
}
|
||||
bool empty () const
|
||||
{
|
||||
return value.empty ();
|
||||
}
|
||||
void clear ()
|
||||
{
|
||||
value.clear ();
|
||||
}
|
||||
void swap (STArray & a)
|
||||
{
|
||||
value.swap (a.value);
|
||||
}
|
||||
|
||||
virtual std::string getFullText () const;
|
||||
virtual std::string getText () const;
|
||||
virtual Json::Value getJson (int) const;
|
||||
virtual void add (Serializer & s) const;
|
||||
|
||||
void sort (bool (*compare) (const STObject & o1, const STObject & o2));
|
||||
|
||||
bool operator== (const STArray & s)
|
||||
{
|
||||
return value == s.value;
|
||||
}
|
||||
bool operator!= (const STArray & s)
|
||||
{
|
||||
return value != s.value;
|
||||
}
|
||||
|
||||
virtual SerializedTypeID getSType () const
|
||||
{
|
||||
return STI_ARRAY;
|
||||
}
|
||||
virtual bool isEquivalent (const SerializedType & t) const;
|
||||
virtual bool isDefault () const
|
||||
{
|
||||
return value.empty ();
|
||||
}
|
||||
|
||||
private:
|
||||
vector value;
|
||||
|
||||
STArray* duplicate () const
|
||||
{
|
||||
return new STArray (*this);
|
||||
}
|
||||
static STArray* construct (SerializerIterator&, SField::ref);
|
||||
};
|
||||
|
||||
inline STArray::iterator range_begin (STArray& x)
|
||||
{
|
||||
return x.begin ();
|
||||
}
|
||||
inline STArray::iterator range_end (STArray& x)
|
||||
{
|
||||
return x.end ();
|
||||
}
|
||||
|
||||
#endif
|
||||
47
src/ripple_data/protocol/ripple_SerializedObjectTemplate.cpp
Normal file
47
src/ripple_data/protocol/ripple_SerializedObjectTemplate.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SOTemplate::SOTemplate ()
|
||||
{
|
||||
}
|
||||
|
||||
void SOTemplate::push_back (SOElement const& r)
|
||||
{
|
||||
// Ensure there is the enough space in the index mapping
|
||||
// table for all possible fields.
|
||||
//
|
||||
if (mIndex.empty ())
|
||||
{
|
||||
// Unmapped indices will be set to -1
|
||||
//
|
||||
mIndex.resize (SField::getNumFields () + 1, -1);
|
||||
}
|
||||
|
||||
// Make sure the field's index is in range
|
||||
//
|
||||
assert (r.e_field.getNum () < mIndex.size ());
|
||||
|
||||
// Make sure that this field hasn't already been assigned
|
||||
//
|
||||
assert (getIndex (r.e_field) == -1);
|
||||
|
||||
// Add the field to the index mapping table
|
||||
//
|
||||
mIndex [r.e_field.getNum ()] = mTypes.size ();
|
||||
|
||||
// Append the new element.
|
||||
//
|
||||
mTypes.push_back (new SOElement (r));
|
||||
}
|
||||
|
||||
int SOTemplate::getIndex (SField::ref f) const
|
||||
{
|
||||
// The mapping table should be large enough for any possible field
|
||||
//
|
||||
assert (f.getNum () < mIndex.size ());
|
||||
|
||||
return mIndex[f.getNum ()];
|
||||
}
|
||||
81
src/ripple_data/protocol/ripple_SerializedObjectTemplate.h
Normal file
81
src/ripple_data/protocol/ripple_SerializedObjectTemplate.h
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_SERIALIZEDOBJECTTEMPLATE_H
|
||||
#define RIPPLE_SERIALIZEDOBJECTTEMPLATE_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Flags for elements in a SerializedObjectTemplate.
|
||||
*/
|
||||
// VFALCO NOTE these don't look like bit-flags...
|
||||
enum SOE_Flags
|
||||
{
|
||||
SOE_INVALID = -1,
|
||||
SOE_REQUIRED = 0, // required
|
||||
SOE_OPTIONAL = 1, // optional, may be present with default value
|
||||
SOE_DEFAULT = 2, // optional, if present, must not have default value
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** An element in a SerializedObjectTemplate.
|
||||
*/
|
||||
class SOElement
|
||||
{
|
||||
public:
|
||||
SField::ref const e_field;
|
||||
SOE_Flags const flags;
|
||||
|
||||
SOElement (SField::ref fieldName, SOE_Flags flags)
|
||||
: e_field (fieldName)
|
||||
, flags (flags)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Defines the fields and their attributes within a SerializedObject.
|
||||
|
||||
Each subclass of SerializedObject will provide its own template
|
||||
describing the available fields and their metadata attributes.
|
||||
*/
|
||||
class SOTemplate
|
||||
{
|
||||
public:
|
||||
/** Create an empty template.
|
||||
|
||||
After creating the template, call @ref push_back with the
|
||||
desired fields.
|
||||
|
||||
@see push_back
|
||||
*/
|
||||
SOTemplate ();
|
||||
|
||||
// VFALCO NOTE Why do we even bother with the 'private' keyword if
|
||||
// this function is present?
|
||||
//
|
||||
std::vector <SOElement const*> const& peek () const
|
||||
{
|
||||
return mTypes;
|
||||
}
|
||||
|
||||
/** Add an element to the template.
|
||||
*/
|
||||
void push_back (SOElement const& r);
|
||||
|
||||
/** Retrieve the position of a named field.
|
||||
*/
|
||||
int getIndex (SField::ref) const;
|
||||
|
||||
private:
|
||||
std::vector <SOElement const*> mTypes;
|
||||
|
||||
std::vector <int> mIndex; // field num -> index
|
||||
};
|
||||
|
||||
#endif
|
||||
609
src/ripple_data/protocol/ripple_SerializedTypes.cpp
Normal file
609
src/ripple_data/protocol/ripple_SerializedTypes.cpp
Normal file
@@ -0,0 +1,609 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SETUP_LOG (SerializedType)
|
||||
|
||||
const STAmount saZero (CURRENCY_ONE, ACCOUNT_ONE, 0);
|
||||
const STAmount saOne (CURRENCY_ONE, ACCOUNT_ONE, 1);
|
||||
|
||||
SerializedType& SerializedType::operator= (const SerializedType& t)
|
||||
{
|
||||
if ((t.fName != fName) && fName->isUseful () && t.fName->isUseful ())
|
||||
{
|
||||
WriteLog ((t.getSType () == STI_AMOUNT) ? lsDEBUG : lsWARNING, SerializedType) // This is common for amounts
|
||||
<< "Caution: " << t.fName->getName () << " not replacing " << fName->getName ();
|
||||
}
|
||||
|
||||
if (!fName->isUseful ()) fName = t.fName;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool SerializedType::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
assert (getSType () == STI_NOTPRESENT);
|
||||
if (t.getSType () == STI_NOTPRESENT)
|
||||
return true;
|
||||
WriteLog (lsDEBUG, SerializedType) << "notEquiv " << getFullText() << " not STI_NOTPRESENT";
|
||||
return false;
|
||||
}
|
||||
|
||||
void STPathSet::printDebug ()
|
||||
{
|
||||
// VFALCO NOTE Can't use Log::out() because of std::endl
|
||||
//
|
||||
for (int i = 0; i < value.size (); i++)
|
||||
{
|
||||
std::cerr << i << ": ";
|
||||
|
||||
for (int j = 0; j < value[i].mPath.size (); j++)
|
||||
{
|
||||
//STPathElement pe = value[i].mPath[j];
|
||||
RippleAddress nad;
|
||||
nad.setAccountID (value[i].mPath[j].mAccountID);
|
||||
std::cerr << " " << nad.humanAccountID ();
|
||||
//std::cerr << " " << pe.mAccountID.GetHex();
|
||||
}
|
||||
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void STPath::printDebug ()
|
||||
{
|
||||
Log::out() << "STPath:";
|
||||
|
||||
for (int i = 0; i < mPath.size (); i++)
|
||||
{
|
||||
RippleAddress nad;
|
||||
nad.setAccountID (mPath[i].mAccountID);
|
||||
Log::out() << " " << i << ": " << nad.humanAccountID ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string SerializedType::getFullText () const
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
if (getSType () != STI_NOTPRESENT)
|
||||
{
|
||||
if (fName->hasName ())
|
||||
{
|
||||
ret = fName->fieldName;
|
||||
ret += " = ";
|
||||
}
|
||||
|
||||
ret += getText ();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
STUInt8* STUInt8::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STUInt8 (name, u.get8 ());
|
||||
}
|
||||
|
||||
std::string STUInt8::getText () const
|
||||
{
|
||||
if (getFName () == sfTransactionResult)
|
||||
{
|
||||
std::string token, human;
|
||||
|
||||
if (transResultInfo (static_cast<TER> (value), token, human))
|
||||
return human;
|
||||
}
|
||||
|
||||
return lexicalCastThrow <std::string> (value);
|
||||
}
|
||||
|
||||
Json::Value STUInt8::getJson (int) const
|
||||
{
|
||||
if (getFName () == sfTransactionResult)
|
||||
{
|
||||
std::string token, human;
|
||||
|
||||
if (transResultInfo (static_cast<TER> (value), token, human))
|
||||
return token;
|
||||
else
|
||||
WriteLog (lsWARNING, SerializedType) << "Unknown result code in metadata: " << value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool STUInt8::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STUInt8* v = dynamic_cast<const STUInt8*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
STUInt16* STUInt16::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STUInt16 (name, u.get16 ());
|
||||
}
|
||||
|
||||
std::string STUInt16::getText () const
|
||||
{
|
||||
if (getFName () == sfLedgerEntryType)
|
||||
{
|
||||
LedgerFormats::Item const* const item =
|
||||
LedgerFormats::getInstance ()->findByType (static_cast <LedgerEntryType> (value));
|
||||
|
||||
if (item != nullptr)
|
||||
return item->getName ();
|
||||
}
|
||||
|
||||
if (getFName () == sfTransactionType)
|
||||
{
|
||||
TxFormats::Item const* const item =
|
||||
TxFormats::getInstance()->findByType (static_cast <TxType> (value));
|
||||
|
||||
if (item != nullptr)
|
||||
return item->getName ();
|
||||
}
|
||||
|
||||
return lexicalCastThrow <std::string> (value);
|
||||
}
|
||||
|
||||
Json::Value STUInt16::getJson (int) const
|
||||
{
|
||||
if (getFName () == sfLedgerEntryType)
|
||||
{
|
||||
LedgerFormats::Item const* const item =
|
||||
LedgerFormats::getInstance ()->findByType (static_cast <LedgerEntryType> (value));
|
||||
|
||||
if (item != nullptr)
|
||||
return item->getName ();
|
||||
}
|
||||
|
||||
if (getFName () == sfTransactionType)
|
||||
{
|
||||
TxFormats::Item const* const item =
|
||||
TxFormats::getInstance()->findByType (static_cast <TxType> (value));
|
||||
|
||||
if (item != nullptr)
|
||||
return item->getName ();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool STUInt16::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STUInt16* v = dynamic_cast<const STUInt16*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
STUInt32* STUInt32::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STUInt32 (name, u.get32 ());
|
||||
}
|
||||
|
||||
std::string STUInt32::getText () const
|
||||
{
|
||||
return lexicalCastThrow <std::string> (value);
|
||||
}
|
||||
|
||||
Json::Value STUInt32::getJson (int) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
bool STUInt32::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STUInt32* v = dynamic_cast<const STUInt32*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
STUInt64* STUInt64::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STUInt64 (name, u.get64 ());
|
||||
}
|
||||
|
||||
std::string STUInt64::getText () const
|
||||
{
|
||||
return lexicalCastThrow <std::string> (value);
|
||||
}
|
||||
|
||||
Json::Value STUInt64::getJson (int) const
|
||||
{
|
||||
return strHex (value);
|
||||
}
|
||||
|
||||
bool STUInt64::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STUInt64* v = dynamic_cast<const STUInt64*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
STHash128* STHash128::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STHash128 (name, u.get128 ());
|
||||
}
|
||||
|
||||
std::string STHash128::getText () const
|
||||
{
|
||||
return value.GetHex ();
|
||||
}
|
||||
|
||||
bool STHash128::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STHash128* v = dynamic_cast<const STHash128*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
STHash160* STHash160::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STHash160 (name, u.get160 ());
|
||||
}
|
||||
|
||||
std::string STHash160::getText () const
|
||||
{
|
||||
return value.GetHex ();
|
||||
}
|
||||
|
||||
bool STHash160::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STHash160* v = dynamic_cast<const STHash160*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
STHash256* STHash256::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STHash256 (name, u.get256 ());
|
||||
}
|
||||
|
||||
std::string STHash256::getText () const
|
||||
{
|
||||
return value.GetHex ();
|
||||
}
|
||||
|
||||
bool STHash256::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STHash256* v = dynamic_cast<const STHash256*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
STVariableLength::STVariableLength (SerializerIterator& st, SField::ref name) : SerializedType (name)
|
||||
{
|
||||
value = st.getVL ();
|
||||
}
|
||||
|
||||
std::string STVariableLength::getText () const
|
||||
{
|
||||
return strHex (value);
|
||||
}
|
||||
|
||||
STVariableLength* STVariableLength::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STVariableLength (name, u.getVL ());
|
||||
}
|
||||
|
||||
bool STVariableLength::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STVariableLength* v = dynamic_cast<const STVariableLength*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
std::string STAccount::getText () const
|
||||
{
|
||||
uint160 u;
|
||||
RippleAddress a;
|
||||
|
||||
if (!getValueH160 (u))
|
||||
return STVariableLength::getText ();
|
||||
|
||||
a.setAccountID (u);
|
||||
return a.humanAccountID ();
|
||||
}
|
||||
|
||||
STAccount* STAccount::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
return new STAccount (name, u.getVL ());
|
||||
}
|
||||
|
||||
//
|
||||
// STVector256
|
||||
//
|
||||
|
||||
// Return a new object from a SerializerIterator.
|
||||
STVector256* STVector256::construct (SerializerIterator& u, SField::ref name)
|
||||
{
|
||||
Blob data = u.getVL ();
|
||||
Blob ::iterator begin = data.begin ();
|
||||
|
||||
UPTR_T<STVector256> vec (new STVector256 (name));
|
||||
|
||||
int count = data.size () / (256 / 8);
|
||||
vec->mValue.reserve (count);
|
||||
|
||||
unsigned int uStart = 0;
|
||||
|
||||
for (unsigned int i = 0; i != count; i++)
|
||||
{
|
||||
unsigned int uEnd = uStart + (256 / 8);
|
||||
|
||||
// This next line could be optimized to construct a default uint256 in the vector and then copy into it
|
||||
vec->mValue.push_back (uint256 (Blob (begin + uStart, begin + uEnd)));
|
||||
uStart = uEnd;
|
||||
}
|
||||
|
||||
return vec.release ();
|
||||
}
|
||||
|
||||
void STVector256::add (Serializer& s) const
|
||||
{
|
||||
s.addVL (mValue.empty () ? NULL : mValue[0].begin (), mValue.size () * (256 / 8));
|
||||
}
|
||||
|
||||
bool STVector256::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STVector256* v = dynamic_cast<const STVector256*> (&t);
|
||||
return v && (mValue == v->mValue);
|
||||
}
|
||||
|
||||
bool STVector256::hasValue (uint256 const& v) const
|
||||
{
|
||||
BOOST_FOREACH (uint256 const & hash, mValue)
|
||||
{
|
||||
if (hash == v)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// STAccount
|
||||
//
|
||||
|
||||
STAccount::STAccount (SField::ref n, const uint160& v) : STVariableLength (n)
|
||||
{
|
||||
peekValue ().insert (peekValue ().end (), v.begin (), v.end ());
|
||||
}
|
||||
|
||||
bool STAccount::isValueH160 () const
|
||||
{
|
||||
return peekValue ().size () == (160 / 8);
|
||||
}
|
||||
|
||||
void STAccount::setValueH160 (const uint160& v)
|
||||
{
|
||||
peekValue ().clear ();
|
||||
peekValue ().insert (peekValue ().end (), v.begin (), v.end ());
|
||||
assert (peekValue ().size () == (160 / 8));
|
||||
}
|
||||
|
||||
bool STAccount::getValueH160 (uint160& v) const
|
||||
{
|
||||
if (!isValueH160 ()) return false;
|
||||
|
||||
memcpy (v.begin (), & (peekValue ().front ()), (160 / 8));
|
||||
return true;
|
||||
}
|
||||
|
||||
RippleAddress STAccount::getValueNCA () const
|
||||
{
|
||||
RippleAddress a;
|
||||
uint160 v;
|
||||
|
||||
if (getValueH160 (v))
|
||||
a.setAccountID (v);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void STAccount::setValueNCA (const RippleAddress& nca)
|
||||
{
|
||||
setValueH160 (nca.getAccountID ());
|
||||
}
|
||||
|
||||
STPathSet* STPathSet::construct (SerializerIterator& s, SField::ref name)
|
||||
{
|
||||
std::vector<STPath> paths;
|
||||
std::vector<STPathElement> path;
|
||||
|
||||
do
|
||||
{
|
||||
int iType = s.get8 ();
|
||||
|
||||
if (iType == STPathElement::typeEnd || iType == STPathElement::typeBoundary)
|
||||
{
|
||||
if (path.empty ())
|
||||
{
|
||||
WriteLog (lsINFO, SerializedType) << "STPathSet: Empty path.";
|
||||
|
||||
throw std::runtime_error ("empty path");
|
||||
}
|
||||
|
||||
paths.push_back (path);
|
||||
path.clear ();
|
||||
|
||||
if (iType == STPathElement::typeEnd)
|
||||
{
|
||||
return new STPathSet (name, paths);
|
||||
}
|
||||
}
|
||||
else if (iType & ~STPathElement::typeValidBits)
|
||||
{
|
||||
WriteLog (lsINFO, SerializedType) << "STPathSet: Bad path element: " << iType;
|
||||
|
||||
throw std::runtime_error ("bad path element");
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool bAccount = !! (iType & STPathElement::typeAccount);
|
||||
const bool bCurrency = !! (iType & STPathElement::typeCurrency);
|
||||
const bool bIssuer = !! (iType & STPathElement::typeIssuer);
|
||||
|
||||
uint160 uAccountID;
|
||||
uint160 uCurrency;
|
||||
uint160 uIssuerID;
|
||||
|
||||
if (bAccount)
|
||||
uAccountID = s.get160 ();
|
||||
|
||||
if (bCurrency)
|
||||
uCurrency = s.get160 ();
|
||||
|
||||
if (bIssuer)
|
||||
uIssuerID = s.get160 ();
|
||||
|
||||
path.push_back (STPathElement (uAccountID, uCurrency, uIssuerID, bCurrency));
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
}
|
||||
|
||||
bool STPathSet::isEquivalent (const SerializedType& t) const
|
||||
{
|
||||
const STPathSet* v = dynamic_cast<const STPathSet*> (&t);
|
||||
return v && (value == v->value);
|
||||
}
|
||||
|
||||
bool STPath::hasSeen (const uint160& uAccountId, const uint160& uCurrencyID, const uint160& uIssuerID) const
|
||||
{
|
||||
for (int i = 0; i < mPath.size (); ++i)
|
||||
{
|
||||
const STPathElement& ele = getElement (i);
|
||||
|
||||
if (ele.getAccountID () == uAccountId
|
||||
&& ele.getCurrency () == uCurrencyID
|
||||
&& ele.getIssuerID () == uIssuerID)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value STPathSet::getJson (int options) const
|
||||
{
|
||||
Json::Value ret (Json::arrayValue);
|
||||
|
||||
BOOST_FOREACH (std::vector<STPath>::const_iterator::value_type it, value)
|
||||
ret.append (it.getJson (options));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
std::string STPath::getText () const
|
||||
{
|
||||
std::string ret ("[");
|
||||
bool first = true;
|
||||
|
||||
BOOST_FOREACH (const STPathElement & it, mPath)
|
||||
{
|
||||
if (!first) ret += ", ";
|
||||
|
||||
switch (it.getNodeType ())
|
||||
{
|
||||
case STPathElement::typeAccount:
|
||||
{
|
||||
ret += RippleAddress::createHumanAccountID (it.getNode ());
|
||||
break;
|
||||
}
|
||||
|
||||
case STPathElement::typeOffer:
|
||||
{
|
||||
ret += "Offer(";
|
||||
ret += it.getNode ().GetHex ();
|
||||
ret += ")";
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error ("Unknown path element");
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
return ret + "]";
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
std::string STPathSet::getText () const
|
||||
{
|
||||
std::string ret ("{");
|
||||
bool firstPath = true;
|
||||
|
||||
BOOST_FOREACH (std::vector<STPath>::const_iterator::value_type it, value)
|
||||
{
|
||||
if (!firstPath)
|
||||
{
|
||||
ret += ", ";
|
||||
firstPath = false;
|
||||
}
|
||||
|
||||
ret += it.getText ();
|
||||
}
|
||||
return ret + "}";
|
||||
}
|
||||
#endif
|
||||
|
||||
void STPathSet::add (Serializer& s) const
|
||||
{
|
||||
bool bFirst = true;
|
||||
|
||||
BOOST_FOREACH (const STPath & spPath, value)
|
||||
{
|
||||
if (!bFirst)
|
||||
{
|
||||
s.add8 (STPathElement::typeBoundary);
|
||||
}
|
||||
|
||||
BOOST_FOREACH (const STPathElement & speElement, spPath)
|
||||
{
|
||||
int iType = speElement.getNodeType ();
|
||||
|
||||
s.add8 (iType);
|
||||
|
||||
if (iType & STPathElement::typeAccount)
|
||||
s.add160 (speElement.getAccountID ());
|
||||
|
||||
if (iType & STPathElement::typeCurrency)
|
||||
s.add160 (speElement.getCurrency ());
|
||||
|
||||
if (iType & STPathElement::typeIssuer)
|
||||
s.add160 (speElement.getIssuerID ());
|
||||
}
|
||||
|
||||
bFirst = false;
|
||||
}
|
||||
s.add8 (STPathElement::typeEnd);
|
||||
}
|
||||
// vim:ts=4
|
||||
1572
src/ripple_data/protocol/ripple_SerializedTypes.h
Normal file
1572
src/ripple_data/protocol/ripple_SerializedTypes.h
Normal file
File diff suppressed because it is too large
Load Diff
735
src/ripple_data/protocol/ripple_Serializer.cpp
Normal file
735
src/ripple_data/protocol/ripple_Serializer.cpp
Normal file
@@ -0,0 +1,735 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SETUP_LOG (Serializer)
|
||||
|
||||
int Serializer::addZeros (size_t uBytes)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
|
||||
while (uBytes--)
|
||||
mData.push_back (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::add16 (uint16 i)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.push_back (static_cast<unsigned char> (i >> 8));
|
||||
mData.push_back (static_cast<unsigned char> (i & 0xff));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::add32 (uint32 i)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.push_back (static_cast<unsigned char> (i >> 24));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 16) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 8) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> (i & 0xff));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::add64 (uint64 i)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.push_back (static_cast<unsigned char> (i >> 56));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 48) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 40) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 32) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 24) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 16) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> ((i >> 8) & 0xff));
|
||||
mData.push_back (static_cast<unsigned char> (i & 0xff));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::add128 (const uint128& i)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.insert (mData.end (), i.begin (), i.end ());
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::add160 (const uint160& i)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.insert (mData.end (), i.begin (), i.end ());
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::add256 (uint256 const& i)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.insert (mData.end (), i.begin (), i.end ());
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addRaw (Blob const& vector)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.insert (mData.end (), vector.begin (), vector.end ());
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addRaw (const Serializer& s)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.insert (mData.end (), s.begin (), s.end ());
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addRaw (const void* ptr, int len)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.insert (mData.end (), (const char*) ptr, ((const char*)ptr) + len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Serializer::get16 (uint16& o, int offset) const
|
||||
{
|
||||
if ((offset + 2) > mData.size ()) return false;
|
||||
|
||||
const unsigned char* ptr = &mData[offset];
|
||||
o = *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::get32 (uint32& o, int offset) const
|
||||
{
|
||||
if ((offset + 4) > mData.size ()) return false;
|
||||
|
||||
const unsigned char* ptr = &mData[offset];
|
||||
o = *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::get64 (uint64& o, int offset) const
|
||||
{
|
||||
if ((offset + 8) > mData.size ()) return false;
|
||||
|
||||
const unsigned char* ptr = &mData[offset];
|
||||
o = *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr++;
|
||||
o <<= 8;
|
||||
o |= *ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::get128 (uint128& o, int offset) const
|
||||
{
|
||||
if ((offset + (128 / 8)) > mData.size ()) return false;
|
||||
|
||||
memcpy (o.begin (), & (mData.front ()) + offset, (128 / 8));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::get160 (uint160& o, int offset) const
|
||||
{
|
||||
if ((offset + (160 / 8)) > mData.size ()) return false;
|
||||
|
||||
memcpy (o.begin (), & (mData.front ()) + offset, (160 / 8));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::get256 (uint256& o, int offset) const
|
||||
{
|
||||
if ((offset + (256 / 8)) > mData.size ()) return false;
|
||||
|
||||
memcpy (o.begin (), & (mData.front ()) + offset, (256 / 8));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint256 Serializer::get256 (int offset) const
|
||||
{
|
||||
uint256 ret;
|
||||
|
||||
if ((offset + (256 / 8)) > mData.size ()) return ret;
|
||||
|
||||
memcpy (ret.begin (), & (mData.front ()) + offset, (256 / 8));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addFieldID (int type, int name)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
assert ((type > 0) && (type < 256) && (name > 0) && (name < 256));
|
||||
|
||||
if (type < 16)
|
||||
{
|
||||
if (name < 16) // common type, common name
|
||||
mData.push_back (static_cast<unsigned char> ((type << 4) | name));
|
||||
else
|
||||
{
|
||||
// common type, uncommon name
|
||||
mData.push_back (static_cast<unsigned char> (type << 4));
|
||||
mData.push_back (static_cast<unsigned char> (name));
|
||||
}
|
||||
}
|
||||
else if (name < 16)
|
||||
{
|
||||
// uncommon type, common name
|
||||
mData.push_back (static_cast<unsigned char> (name));
|
||||
mData.push_back (static_cast<unsigned char> (type));
|
||||
}
|
||||
else
|
||||
{
|
||||
// uncommon type, uncommon name
|
||||
mData.push_back (static_cast<unsigned char> (0));
|
||||
mData.push_back (static_cast<unsigned char> (type));
|
||||
mData.push_back (static_cast<unsigned char> (name));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Serializer::getFieldID (int& type, int& name, int offset) const
|
||||
{
|
||||
if (!get8 (type, offset))
|
||||
{
|
||||
WriteLog (lsWARNING, Serializer) << "gFID: unable to get type";
|
||||
return false;
|
||||
}
|
||||
|
||||
name = type & 15;
|
||||
type >>= 4;
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
// uncommon type
|
||||
if (!get8 (type, ++offset))
|
||||
return false;
|
||||
|
||||
if ((type == 0) || (type < 16))
|
||||
{
|
||||
WriteLog (lsWARNING, Serializer) << "gFID: uncommon type out of range " << type;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (name == 0)
|
||||
{
|
||||
// uncommon name
|
||||
if (!get8 (name, ++offset))
|
||||
return false;
|
||||
|
||||
if ((name == 0) || (name < 16))
|
||||
{
|
||||
WriteLog (lsWARNING, Serializer) << "gFID: uncommon name out of range " << name;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Serializer::add8 (unsigned char byte)
|
||||
{
|
||||
int ret = mData.size ();
|
||||
mData.push_back (byte);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Serializer::get8 (int& byte, int offset) const
|
||||
{
|
||||
if (offset >= mData.size ()) return false;
|
||||
|
||||
byte = mData[offset];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::chop (int bytes)
|
||||
{
|
||||
if (bytes > mData.size ()) return false;
|
||||
|
||||
mData.resize (mData.size () - bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
int Serializer::removeLastByte ()
|
||||
{
|
||||
int size = mData.size () - 1;
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
assert (false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = mData[size];
|
||||
mData.resize (size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Serializer::getRaw (Blob& o, int offset, int length) const
|
||||
{
|
||||
if ((offset + length) > mData.size ()) return false;
|
||||
|
||||
o.assign (mData.begin () + offset, mData.begin () + offset + length);
|
||||
return true;
|
||||
}
|
||||
|
||||
Blob Serializer::getRaw (int offset, int length) const
|
||||
{
|
||||
Blob o;
|
||||
|
||||
if ((offset + length) > mData.size ()) return o;
|
||||
|
||||
o.assign (mData.begin () + offset, mData.begin () + offset + length);
|
||||
return o;
|
||||
}
|
||||
|
||||
uint160 Serializer::getRIPEMD160 (int size) const
|
||||
{
|
||||
uint160 ret;
|
||||
|
||||
if ((size < 0) || (size > mData.size ())) size = mData.size ();
|
||||
|
||||
RIPEMD160 (& (mData.front ()), size, (unsigned char*) &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint256 Serializer::getSHA256 (int size) const
|
||||
{
|
||||
uint256 ret;
|
||||
|
||||
if ((size < 0) || (size > mData.size ())) size = mData.size ();
|
||||
|
||||
SHA256 (& (mData.front ()), size, (unsigned char*) &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint256 Serializer::getSHA512Half (int size) const
|
||||
{
|
||||
return getSHA512Half (mData, size);
|
||||
}
|
||||
|
||||
uint256 Serializer::getSHA512Half (Blob const& data, int size)
|
||||
{
|
||||
uint256 j[2];
|
||||
|
||||
if ((size < 0) || (size > data.size ())) size = data.size ();
|
||||
|
||||
SHA512 (& (data.front ()), size, (unsigned char*) j);
|
||||
return j[0];
|
||||
}
|
||||
|
||||
uint256 Serializer::getSHA512Half (const unsigned char* data, int len)
|
||||
{
|
||||
uint256 j[2];
|
||||
SHA512 (data, len, (unsigned char*) j);
|
||||
return j[0];
|
||||
}
|
||||
|
||||
uint256 Serializer::getSHA512Half (const std::string& strData)
|
||||
{
|
||||
return getSHA512Half (reinterpret_cast<const unsigned char*> (strData.data ()), strData.size ());
|
||||
}
|
||||
|
||||
uint256 Serializer::getPrefixHash (uint32 prefix, const unsigned char* data, int len)
|
||||
{
|
||||
char be_prefix[4];
|
||||
be_prefix[0] = static_cast<unsigned char> (prefix >> 24);
|
||||
be_prefix[1] = static_cast<unsigned char> ((prefix >> 16) & 0xff);
|
||||
be_prefix[2] = static_cast<unsigned char> ((prefix >> 8) & 0xff);
|
||||
be_prefix[3] = static_cast<unsigned char> (prefix & 0xff);
|
||||
|
||||
uint256 j[2];
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, &be_prefix[0], 4);
|
||||
SHA512_Update (&ctx, data, len);
|
||||
SHA512_Final (reinterpret_cast<unsigned char*> (&j[0]), &ctx);
|
||||
|
||||
return j[0];
|
||||
}
|
||||
|
||||
bool Serializer::checkSignature (int pubkeyOffset, int signatureOffset) const
|
||||
{
|
||||
Blob pubkey, signature;
|
||||
|
||||
if (!getRaw (pubkey, pubkeyOffset, 65)) return false;
|
||||
|
||||
if (!getRaw (signature, signatureOffset, 72)) return false;
|
||||
|
||||
CKey pubCKey;
|
||||
|
||||
if (!pubCKey.SetPubKey (pubkey)) return false;
|
||||
|
||||
return pubCKey.Verify (getSHA512Half (signatureOffset), signature);
|
||||
}
|
||||
|
||||
bool Serializer::checkSignature (Blob const& signature, CKey& key) const
|
||||
{
|
||||
return key.Verify (getSHA512Half (), signature);
|
||||
}
|
||||
|
||||
bool Serializer::makeSignature (Blob& signature, CKey& key) const
|
||||
{
|
||||
return key.Sign (getSHA512Half (), signature);
|
||||
}
|
||||
|
||||
bool Serializer::addSignature (CKey& key)
|
||||
{
|
||||
Blob signature;
|
||||
|
||||
if (!key.Sign (getSHA512Half (), signature)) return false;
|
||||
|
||||
assert (signature.size () == 72);
|
||||
addRaw (signature);
|
||||
return true;
|
||||
}
|
||||
|
||||
int Serializer::addVL (Blob const& vector)
|
||||
{
|
||||
int ret = addRaw (encodeVL (vector.size ()));
|
||||
addRaw (vector);
|
||||
assert (mData.size () == (ret + vector.size () + encodeLengthLength (vector.size ())));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addVL (const void* ptr, int len)
|
||||
{
|
||||
int ret = addRaw (encodeVL (len));
|
||||
|
||||
if (len)
|
||||
addRaw (ptr, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addVL (const std::string& string)
|
||||
{
|
||||
int ret = addRaw (string.size ());
|
||||
|
||||
if (!string.empty ())
|
||||
addRaw (string.data (), string.size ());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Serializer::getVL (Blob& objectVL, int offset, int& length) const
|
||||
{
|
||||
int b1;
|
||||
|
||||
if (!get8 (b1, offset++)) return false;
|
||||
|
||||
int datLen, lenLen = decodeLengthLength (b1);
|
||||
|
||||
try
|
||||
{
|
||||
if (lenLen == 1)
|
||||
datLen = decodeVLLength (b1);
|
||||
else if (lenLen == 2)
|
||||
{
|
||||
int b2;
|
||||
|
||||
if (!get8 (b2, offset++)) return false;
|
||||
|
||||
datLen = decodeVLLength (b1, b2);
|
||||
}
|
||||
else if (lenLen == 3)
|
||||
{
|
||||
int b2, b3;
|
||||
|
||||
if (!get8 (b2, offset++)) return false;
|
||||
|
||||
if (!get8 (b3, offset++)) return false;
|
||||
|
||||
datLen = decodeVLLength (b1, b2, b3);
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
length = lenLen + datLen;
|
||||
return getRaw (objectVL, offset, datLen);
|
||||
}
|
||||
|
||||
bool Serializer::getVLLength (int& length, int offset) const
|
||||
{
|
||||
int b1;
|
||||
|
||||
if (!get8 (b1, offset++)) return false;
|
||||
|
||||
int lenLen = decodeLengthLength (b1);
|
||||
|
||||
try
|
||||
{
|
||||
if (lenLen == 1)
|
||||
length = decodeVLLength (b1);
|
||||
else if (lenLen == 2)
|
||||
{
|
||||
int b2;
|
||||
|
||||
if (!get8 (b2, offset++)) return false;
|
||||
|
||||
length = decodeVLLength (b1, b2);
|
||||
}
|
||||
else if (lenLen == 3)
|
||||
{
|
||||
int b2, b3;
|
||||
|
||||
if (!get8 (b2, offset++)) return false;
|
||||
|
||||
if (!get8 (b3, offset++)) return false;
|
||||
|
||||
length = decodeVLLength (b1, b2, b3);
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Blob Serializer::encodeVL (int length)
|
||||
{
|
||||
unsigned char lenBytes[4];
|
||||
|
||||
if (length <= 192)
|
||||
{
|
||||
lenBytes[0] = static_cast<unsigned char> (length);
|
||||
return Blob (&lenBytes[0], &lenBytes[1]);
|
||||
}
|
||||
else if (length <= 12480)
|
||||
{
|
||||
length -= 193;
|
||||
lenBytes[0] = 193 + static_cast<unsigned char> (length >> 8);
|
||||
lenBytes[1] = static_cast<unsigned char> (length & 0xff);
|
||||
return Blob (&lenBytes[0], &lenBytes[2]);
|
||||
}
|
||||
else if (length <= 918744)
|
||||
{
|
||||
length -= 12481;
|
||||
lenBytes[0] = 241 + static_cast<unsigned char> (length >> 16);
|
||||
lenBytes[1] = static_cast<unsigned char> ((length >> 8) & 0xff);
|
||||
lenBytes[2] = static_cast<unsigned char> (length & 0xff);
|
||||
return Blob (&lenBytes[0], &lenBytes[3]);
|
||||
}
|
||||
else throw std::overflow_error ("lenlen");
|
||||
}
|
||||
|
||||
int Serializer::encodeLengthLength (int length)
|
||||
{
|
||||
if (length < 0) throw std::overflow_error ("len<0");
|
||||
|
||||
if (length <= 192) return 1;
|
||||
|
||||
if (length <= 12480) return 2;
|
||||
|
||||
if (length <= 918744) return 3;
|
||||
|
||||
throw std::overflow_error ("len>918744");
|
||||
}
|
||||
|
||||
int Serializer::decodeLengthLength (int b1)
|
||||
{
|
||||
if (b1 < 0) throw std::overflow_error ("b1<0");
|
||||
|
||||
if (b1 <= 192) return 1;
|
||||
|
||||
if (b1 <= 240) return 2;
|
||||
|
||||
if (b1 <= 254) return 3;
|
||||
|
||||
throw std::overflow_error ("b1>254");
|
||||
}
|
||||
|
||||
int Serializer::decodeVLLength (int b1)
|
||||
{
|
||||
if (b1 < 0) throw std::overflow_error ("b1<0");
|
||||
|
||||
if (b1 > 254) throw std::overflow_error ("b1>254");
|
||||
|
||||
return b1;
|
||||
}
|
||||
|
||||
int Serializer::decodeVLLength (int b1, int b2)
|
||||
{
|
||||
if (b1 < 193) throw std::overflow_error ("b1<193");
|
||||
|
||||
if (b1 > 240) throw std::overflow_error ("b1>240");
|
||||
|
||||
return 193 + (b1 - 193) * 256 + b2;
|
||||
}
|
||||
|
||||
int Serializer::decodeVLLength (int b1, int b2, int b3)
|
||||
{
|
||||
if (b1 < 241) throw std::overflow_error ("b1<241");
|
||||
|
||||
if (b1 > 254) throw std::overflow_error ("b1>254");
|
||||
|
||||
return 12481 + (b1 - 241) * 65536 + b2 * 256 + b3;
|
||||
}
|
||||
|
||||
void Serializer::TestSerializer ()
|
||||
{
|
||||
Serializer s (64);
|
||||
}
|
||||
|
||||
int SerializerIterator::getBytesLeft ()
|
||||
{
|
||||
return mSerializer.size () - mPos;
|
||||
}
|
||||
|
||||
void SerializerIterator::getFieldID (int& type, int& field)
|
||||
{
|
||||
if (!mSerializer.getFieldID (type, field, mPos))
|
||||
throw std::runtime_error ("invalid serializer getFieldID");
|
||||
|
||||
++mPos;
|
||||
|
||||
if (type >= 16)
|
||||
++mPos;
|
||||
|
||||
if (field >= 16)
|
||||
++mPos;
|
||||
}
|
||||
|
||||
unsigned char SerializerIterator::get8 ()
|
||||
{
|
||||
int val;
|
||||
|
||||
if (!mSerializer.get8 (val, mPos)) throw std::runtime_error ("invalid serializer get8");
|
||||
|
||||
++mPos;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16 SerializerIterator::get16 ()
|
||||
{
|
||||
uint16 val;
|
||||
|
||||
if (!mSerializer.get16 (val, mPos)) throw std::runtime_error ("invalid serializer get16");
|
||||
|
||||
mPos += 16 / 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32 SerializerIterator::get32 ()
|
||||
{
|
||||
uint32 val;
|
||||
|
||||
if (!mSerializer.get32 (val, mPos)) throw std::runtime_error ("invalid serializer get32");
|
||||
|
||||
mPos += 32 / 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64 SerializerIterator::get64 ()
|
||||
{
|
||||
uint64 val;
|
||||
|
||||
if (!mSerializer.get64 (val, mPos)) throw std::runtime_error ("invalid serializer get64");
|
||||
|
||||
mPos += 64 / 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint128 SerializerIterator::get128 ()
|
||||
{
|
||||
uint128 val;
|
||||
|
||||
if (!mSerializer.get128 (val, mPos)) throw std::runtime_error ("invalid serializer get128");
|
||||
|
||||
mPos += 128 / 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint160 SerializerIterator::get160 ()
|
||||
{
|
||||
uint160 val;
|
||||
|
||||
if (!mSerializer.get160 (val, mPos)) throw std::runtime_error ("invalid serializer get160");
|
||||
|
||||
mPos += 160 / 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint256 SerializerIterator::get256 ()
|
||||
{
|
||||
uint256 val;
|
||||
|
||||
if (!mSerializer.get256 (val, mPos)) throw std::runtime_error ("invalid serializer get256");
|
||||
|
||||
mPos += 256 / 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
Blob SerializerIterator::getVL ()
|
||||
{
|
||||
int length;
|
||||
Blob vl;
|
||||
|
||||
if (!mSerializer.getVL (vl, mPos, length)) throw std::runtime_error ("invalid serializer getVL");
|
||||
|
||||
mPos += length;
|
||||
return vl;
|
||||
}
|
||||
|
||||
Blob SerializerIterator::getRaw (int iLength)
|
||||
{
|
||||
int iPos = mPos;
|
||||
mPos += iLength;
|
||||
|
||||
return mSerializer.getRaw (iPos, iLength);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SerializerTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
SerializerTests () : UnitTest ("Serializer", "ripple")
|
||||
{
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
beginTestCase ("hash");
|
||||
|
||||
Serializer s1;
|
||||
s1.add32 (3);
|
||||
s1.add256 (uint256 ());
|
||||
|
||||
Serializer s2;
|
||||
s2.add32 (0x12345600);
|
||||
s2.addRaw (s1.peekData ());
|
||||
|
||||
expect (s1.getPrefixHash (0x12345600) == s2.getSHA512Half ());
|
||||
}
|
||||
};
|
||||
|
||||
static SerializerTests serializerTests;
|
||||
|
||||
|
||||
282
src/ripple_data/protocol/ripple_Serializer.h
Normal file
282
src/ripple_data/protocol/ripple_Serializer.h
Normal file
@@ -0,0 +1,282 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_SERIALIZER_H
|
||||
#define RIPPLE_SERIALIZER_H
|
||||
|
||||
class CKey; // forward declaration
|
||||
|
||||
class Serializer
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<Serializer> pointer;
|
||||
|
||||
protected:
|
||||
Blob mData;
|
||||
|
||||
public:
|
||||
Serializer (int n = 256)
|
||||
{
|
||||
mData.reserve (n);
|
||||
}
|
||||
Serializer (Blob const& data) : mData (data)
|
||||
{
|
||||
;
|
||||
}
|
||||
Serializer (const std::string& data) : mData (data.data (), (data.data ()) + data.size ())
|
||||
{
|
||||
;
|
||||
}
|
||||
Serializer (Blob ::iterator begin, Blob ::iterator end) :
|
||||
mData (begin, end)
|
||||
{
|
||||
;
|
||||
}
|
||||
Serializer (Blob ::const_iterator begin, Blob ::const_iterator end) :
|
||||
mData (begin, end)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// assemble functions
|
||||
int add8 (unsigned char byte);
|
||||
int add16 (uint16);
|
||||
int add32 (uint32); // ledger indexes, account sequence, timestamps
|
||||
int add64 (uint64); // native currency amounts
|
||||
int add128 (const uint128&); // private key generators
|
||||
int add160 (const uint160&); // account names, hankos
|
||||
int add256 (uint256 const& ); // transaction and ledger hashes
|
||||
int addRaw (Blob const& vector);
|
||||
int addRaw (const void* ptr, int len);
|
||||
int addRaw (const Serializer& s);
|
||||
int addZeros (size_t uBytes);
|
||||
|
||||
int addVL (Blob const& vector);
|
||||
int addVL (const std::string& string);
|
||||
int addVL (const void* ptr, int len);
|
||||
|
||||
// disassemble functions
|
||||
bool get8 (int&, int offset) const;
|
||||
bool get8 (unsigned char&, int offset) const;
|
||||
bool get16 (uint16&, int offset) const;
|
||||
bool get32 (uint32&, int offset) const;
|
||||
bool get64 (uint64&, int offset) const;
|
||||
bool get128 (uint128&, int offset) const;
|
||||
bool get160 (uint160&, int offset) const;
|
||||
bool get256 (uint256&, int offset) const;
|
||||
uint256 get256 (int offset) const;
|
||||
bool getRaw (Blob&, int offset, int length) const;
|
||||
Blob getRaw (int offset, int length) const;
|
||||
|
||||
bool getVL (Blob& objectVL, int offset, int& length) const;
|
||||
bool getVLLength (int& length, int offset) const;
|
||||
|
||||
bool getFieldID (int& type, int& name, int offset) const;
|
||||
int addFieldID (int type, int name);
|
||||
int addFieldID (SerializedTypeID type, int name)
|
||||
{
|
||||
return addFieldID (static_cast<int> (type), name);
|
||||
}
|
||||
|
||||
// normal hash functions
|
||||
uint160 getRIPEMD160 (int size = -1) const;
|
||||
uint256 getSHA256 (int size = -1) const;
|
||||
uint256 getSHA512Half (int size = -1) const;
|
||||
static uint256 getSHA512Half (Blob const& data, int size = -1);
|
||||
static uint256 getSHA512Half (const unsigned char* data, int len);
|
||||
static uint256 getSHA512Half (const std::string& strData);
|
||||
|
||||
// prefix hash functions
|
||||
static uint256 getPrefixHash (uint32 prefix, const unsigned char* data, int len);
|
||||
uint256 getPrefixHash (uint32 prefix) const
|
||||
{
|
||||
return getPrefixHash (prefix, & (mData.front ()), mData.size ());
|
||||
}
|
||||
static uint256 getPrefixHash (uint32 prefix, Blob const& data)
|
||||
{
|
||||
return getPrefixHash (prefix, & (data.front ()), data.size ());
|
||||
}
|
||||
static uint256 getPrefixHash (uint32 prefix, const std::string& strData)
|
||||
{
|
||||
return getPrefixHash (prefix, reinterpret_cast<const unsigned char*> (strData.data ()), strData.size ());
|
||||
}
|
||||
|
||||
// totality functions
|
||||
Blob const& peekData () const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
Blob getData () const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
Blob& modData ()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
int getCapacity () const
|
||||
{
|
||||
return mData.capacity ();
|
||||
}
|
||||
int getDataLength () const
|
||||
{
|
||||
return mData.size ();
|
||||
}
|
||||
const void* getDataPtr () const
|
||||
{
|
||||
return &mData.front ();
|
||||
}
|
||||
void* getDataPtr ()
|
||||
{
|
||||
return &mData.front ();
|
||||
}
|
||||
int getLength () const
|
||||
{
|
||||
return mData.size ();
|
||||
}
|
||||
std::string getString () const
|
||||
{
|
||||
return std::string (static_cast<const char*> (getDataPtr ()), size ());
|
||||
}
|
||||
void secureErase ()
|
||||
{
|
||||
memset (& (mData.front ()), 0, mData.size ());
|
||||
erase ();
|
||||
}
|
||||
void erase ()
|
||||
{
|
||||
mData.clear ();
|
||||
}
|
||||
int removeLastByte ();
|
||||
bool chop (int num);
|
||||
|
||||
// vector-like functions
|
||||
Blob ::iterator begin ()
|
||||
{
|
||||
return mData.begin ();
|
||||
}
|
||||
Blob ::iterator end ()
|
||||
{
|
||||
return mData.end ();
|
||||
}
|
||||
Blob ::const_iterator begin () const
|
||||
{
|
||||
return mData.begin ();
|
||||
}
|
||||
Blob ::const_iterator end () const
|
||||
{
|
||||
return mData.end ();
|
||||
}
|
||||
Blob ::size_type size () const
|
||||
{
|
||||
return mData.size ();
|
||||
}
|
||||
void reserve (size_t n)
|
||||
{
|
||||
mData.reserve (n);
|
||||
}
|
||||
void resize (size_t n)
|
||||
{
|
||||
mData.resize (n);
|
||||
}
|
||||
size_t capacity () const
|
||||
{
|
||||
return mData.capacity ();
|
||||
}
|
||||
|
||||
bool operator== (Blob const& v)
|
||||
{
|
||||
return v == mData;
|
||||
}
|
||||
bool operator!= (Blob const& v)
|
||||
{
|
||||
return v != mData;
|
||||
}
|
||||
bool operator== (const Serializer& v)
|
||||
{
|
||||
return v.mData == mData;
|
||||
}
|
||||
bool operator!= (const Serializer& v)
|
||||
{
|
||||
return v.mData != mData;
|
||||
}
|
||||
|
||||
// signature functions
|
||||
bool checkSignature (int pubkeyOffset, int signatureOffset) const;
|
||||
bool checkSignature (Blob const& signature, CKey& rkey) const;
|
||||
bool makeSignature (Blob& signature, CKey& rkey) const;
|
||||
bool addSignature (CKey& rkey);
|
||||
|
||||
// low-level VL length encode/decode functions
|
||||
static Blob encodeVL (int length);
|
||||
static int lengthVL (int length)
|
||||
{
|
||||
return length + encodeLengthLength (length);
|
||||
}
|
||||
static int encodeLengthLength (int length); // length to encode length
|
||||
static int decodeLengthLength (int b1);
|
||||
static int decodeVLLength (int b1);
|
||||
static int decodeVLLength (int b1, int b2);
|
||||
static int decodeVLLength (int b1, int b2, int b3);
|
||||
|
||||
static void TestSerializer ();
|
||||
};
|
||||
|
||||
class SerializerIterator
|
||||
{
|
||||
protected:
|
||||
const Serializer& mSerializer;
|
||||
int mPos;
|
||||
|
||||
public:
|
||||
|
||||
// Reference is not const because we don't want to bind to a temporary
|
||||
SerializerIterator (Serializer& s) : mSerializer (s), mPos (0)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
const Serializer& operator* (void)
|
||||
{
|
||||
return mSerializer;
|
||||
}
|
||||
void reset (void)
|
||||
{
|
||||
mPos = 0;
|
||||
}
|
||||
void setPos (int p)
|
||||
{
|
||||
mPos = p;
|
||||
}
|
||||
|
||||
int getPos (void)
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
bool empty ()
|
||||
{
|
||||
return mPos == mSerializer.getLength ();
|
||||
}
|
||||
int getBytesLeft ();
|
||||
|
||||
// get functions throw on error
|
||||
unsigned char get8 ();
|
||||
uint16 get16 ();
|
||||
uint32 get32 ();
|
||||
uint64 get64 ();
|
||||
uint128 get128 ();
|
||||
uint160 get160 ();
|
||||
uint256 get256 ();
|
||||
|
||||
void getFieldID (int& type, int& field);
|
||||
|
||||
Blob getRaw (int iLength);
|
||||
|
||||
Blob getVL ();
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
136
src/ripple_data/protocol/ripple_TER.cpp
Normal file
136
src/ripple_data/protocol/ripple_TER.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
bool transResultInfo (TER terCode, std::string& strToken, std::string& strHuman)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
TER terCode;
|
||||
const char* cpToken;
|
||||
const char* cpHuman;
|
||||
} transResultInfoA[] =
|
||||
{
|
||||
{ tecCLAIM, "tecCLAIM", "Fee claimed. Sequence used. No action." },
|
||||
{ tecDIR_FULL, "tecDIR_FULL", "Can not add entry to full directory." },
|
||||
{ tecFAILED_PROCESSING, "tecFAILED_PROCESSING", "Failed to correctly process transaction." },
|
||||
{ tecINSUF_RESERVE_LINE, "tecINSUF_RESERVE_LINE", "Insufficient reserve to add trust line." },
|
||||
{ tecINSUF_RESERVE_OFFER, "tecINSUF_RESERVE_OFFER", "Insufficient reserve to create offer." },
|
||||
{ tecNO_DST, "tecNO_DST", "Destination does not exist. Send XRP to create it." },
|
||||
{ tecNO_DST_INSUF_XRP, "tecNO_DST_INSUF_XRP", "Destination does not exist. Too little XRP sent to create it." },
|
||||
{ tecNO_LINE_INSUF_RESERVE, "tecNO_LINE_INSUF_RESERVE", "No such line. Too little reserve to create it." },
|
||||
{ tecNO_LINE_REDUNDANT, "tecNO_LINE_REDUNDANT", "Can't set non-existant line to default." },
|
||||
{ tecPATH_DRY, "tecPATH_DRY", "Path could not send partial amount." },
|
||||
{ tecPATH_PARTIAL, "tecPATH_PARTIAL", "Path could not send full amount." },
|
||||
{ tecMASTER_DISABLED, "tefMASTER_DISABLED", "Master key is disabled." },
|
||||
{ tecNO_REGULAR_KEY, "tefNO_REGULAR_KEY", "Regular key is not set." },
|
||||
|
||||
{ tecUNFUNDED, "tecUNFUNDED", "One of _ADD, _OFFER, or _SEND. Deprecated." },
|
||||
{ tecUNFUNDED_ADD, "tecUNFUNDED_ADD", "Insufficient XRP balance for WalletAdd." },
|
||||
{ tecUNFUNDED_OFFER, "tecUNFUNDED_OFFER", "Insufficient balance to fund created offer." },
|
||||
{ tecUNFUNDED_PAYMENT, "tecUNFUNDED_PAYMENT", "Insufficient XRP balance to send." },
|
||||
{ tecOWNERS, "tecOWNERS", "Non-zero owner count." },
|
||||
|
||||
{ tefFAILURE, "tefFAILURE", "Failed to apply." },
|
||||
{ tefALREADY, "tefALREADY", "The exact transaction was already in this ledger." },
|
||||
{ tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." },
|
||||
{ tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." },
|
||||
{ tefBAD_CLAIM_ID, "tefBAD_CLAIM_ID", "Malformed: Bad claim id." },
|
||||
{ tefBAD_GEN_AUTH, "tefBAD_GEN_AUTH", "Not authorized to claim generator." },
|
||||
{ tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." },
|
||||
{ tefCLAIMED, "tefCLAIMED", "Can not claim a previously claimed account." },
|
||||
{ tefCREATED, "tefCREATED", "Can't add an already created account." },
|
||||
{ tefDST_TAG_NEEDED, "tefDST_TAG_NEEDED", "Destination tag required." },
|
||||
{ tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." },
|
||||
{ tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." },
|
||||
{ tefINTERNAL, "tefINTERNAL", "Internal error." },
|
||||
{ tefNO_AUTH_REQUIRED, "tefNO_AUTH_REQUIRED", "Auth is not required." },
|
||||
{ tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past." },
|
||||
{ tefWRONG_PRIOR, "tefWRONG_PRIOR", "This previous transaction does not match." },
|
||||
{ tefMASTER_DISABLED, "tefMASTER_DISABLED", "Master key is disabled." },
|
||||
|
||||
{ telLOCAL_ERROR, "telLOCAL_ERROR", "Local failure." },
|
||||
{ telBAD_DOMAIN, "telBAD_DOMAIN", "Domain too long." },
|
||||
{ telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: Too many paths." },
|
||||
{ telBAD_PUBLIC_KEY, "telBAD_PUBLIC_KEY", "Public key too long." },
|
||||
{ telFAILED_PROCESSING, "telFAILED_PROCESSING", "Failed to correctly process transaction." },
|
||||
{ telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." },
|
||||
{ telNO_DST_PARTIAL, "telNO_DST_PARTIAL", "Partial payment to create account not allowed." },
|
||||
|
||||
{ temMALFORMED, "temMALFORMED", "Malformed transaction." },
|
||||
{ temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." },
|
||||
{ temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." },
|
||||
{ temBAD_CURRENCY, "temBAD_CURRENCY", "Malformed: Bad currency." },
|
||||
{ temBAD_FEE, "temBAD_FEE", "Invalid fee, negative or not XRP." },
|
||||
{ temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed: Bad expiration." },
|
||||
{ temBAD_ISSUER, "temBAD_ISSUER", "Malformed: Bad issuer." },
|
||||
{ temBAD_LIMIT, "temBAD_LIMIT", "Limits must be non-negative." },
|
||||
{ temBAD_OFFER, "temBAD_OFFER", "Malformed: Bad offer." },
|
||||
{ temBAD_PATH, "temBAD_PATH", "Malformed: Bad path." },
|
||||
{ temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed: Loop in path." },
|
||||
{ temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: Bad publish." },
|
||||
{ temBAD_SIGNATURE, "temBAD_SIGNATURE", "Malformed: Bad signature." },
|
||||
{ temBAD_SRC_ACCOUNT, "temBAD_SRC_ACCOUNT", "Malformed: Bad source account." },
|
||||
{ temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: Transfer rate must be >= 1.0" },
|
||||
{ temBAD_SEQUENCE, "temBAD_SEQUENCE", "Malformed: Sequence is not in the past." },
|
||||
{ temBAD_SEND_XRP_LIMIT, "temBAD_SEND_XRP_LIMIT", "Malformed: Limit quality is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_MAX, "temBAD_SEND_XRP_MAX", "Malformed: Send max is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_NO_DIRECT, "temBAD_SEND_XRP_NO_DIRECT", "Malformed: No Ripple direct is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_PARTIAL, "temBAD_SEND_XRP_PARTIAL", "Malformed: Partial payment is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_PATHS, "temBAD_SEND_XRP_PATHS", "Malformed: Paths are not allowed for XRP to XRP." },
|
||||
{ temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." },
|
||||
{ temDST_NEEDED, "temDST_NEEDED", "Destination not specified." },
|
||||
{ temINVALID, "temINVALID", "The transaction is ill-formed." },
|
||||
{ temINVALID_FLAG, "temINVALID_FLAG", "The transaction has an invalid flag." },
|
||||
{ temREDUNDANT, "temREDUNDANT", "Sends same currency to self." },
|
||||
{ temREDUNDANT_SEND_MAX, "temREDUNDANT_SEND_MAX", "Send max is redundant." },
|
||||
{ temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." },
|
||||
{ temUNCERTAIN, "temUNCERTAIN", "In process of determining result. Never returned." },
|
||||
{ temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet." },
|
||||
|
||||
{ terRETRY, "terRETRY", "Retry transaction." },
|
||||
{ terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." },
|
||||
{ terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." },
|
||||
{ terLAST, "terLAST", "Process last." },
|
||||
{ terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." },
|
||||
{ terNO_AUTH, "terNO_AUTH", "Not authorized to hold IOUs." },
|
||||
{ terNO_LINE, "terNO_LINE", "No such line." },
|
||||
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." },
|
||||
{ terOWNERS, "terOWNERS", "Non-zero owner count." },
|
||||
|
||||
{ tesSUCCESS, "tesSUCCESS", "The transaction was applied." },
|
||||
};
|
||||
|
||||
int iIndex = NUMBER (transResultInfoA);
|
||||
|
||||
while (iIndex-- && transResultInfoA[iIndex].terCode != terCode)
|
||||
;
|
||||
|
||||
if (iIndex >= 0)
|
||||
{
|
||||
strToken = transResultInfoA[iIndex].cpToken;
|
||||
strHuman = transResultInfoA[iIndex].cpHuman;
|
||||
}
|
||||
|
||||
return iIndex >= 0;
|
||||
}
|
||||
|
||||
std::string transToken (TER terCode)
|
||||
{
|
||||
std::string strToken;
|
||||
std::string strHuman;
|
||||
|
||||
return transResultInfo (terCode, strToken, strHuman) ? strToken : "-";
|
||||
}
|
||||
|
||||
std::string transHuman (TER terCode)
|
||||
{
|
||||
std::string strToken;
|
||||
std::string strHuman;
|
||||
|
||||
return transResultInfo (terCode, strToken, strHuman) ? strHuman : "-";
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
170
src/ripple_data/protocol/ripple_TER.h
Normal file
170
src/ripple_data/protocol/ripple_TER.h
Normal file
@@ -0,0 +1,170 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TER_H
|
||||
#define RIPPLE_TER_H
|
||||
|
||||
// VFALCO TODO do not use auto-incrementing. Explicitly assign each
|
||||
// constant so there is no possibility of someone coming in
|
||||
// and screwing it up.
|
||||
//
|
||||
// VFALCO TODO consider renaming TER to TxErr or TxResult for clarity.
|
||||
//
|
||||
enum TER // aka TransactionEngineResult
|
||||
{
|
||||
// Note: Range is stable. Exact numbers are currently unstable. Use tokens.
|
||||
|
||||
// -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit)
|
||||
// Only valid during non-consensus processing.
|
||||
// Implications:
|
||||
// - Not forwarded
|
||||
// - No fee check
|
||||
telLOCAL_ERROR = -399,
|
||||
telBAD_DOMAIN, // VFALCO TODO should read "telBAD_DOMAIN = -398," etc...
|
||||
telBAD_PATH_COUNT,
|
||||
telBAD_PUBLIC_KEY,
|
||||
telFAILED_PROCESSING,
|
||||
telINSUF_FEE_P,
|
||||
telNO_DST_PARTIAL,
|
||||
|
||||
// -299 .. -200: M Malformed (bad signature)
|
||||
// Causes:
|
||||
// - Transaction corrupt.
|
||||
// Implications:
|
||||
// - Not applied
|
||||
// - Not forwarded
|
||||
// - Reject
|
||||
// - Can not succeed in any imagined ledger.
|
||||
temMALFORMED = -299,
|
||||
temBAD_AMOUNT,
|
||||
temBAD_AUTH_MASTER,
|
||||
temBAD_CURRENCY,
|
||||
temBAD_FEE,
|
||||
temBAD_EXPIRATION,
|
||||
temBAD_ISSUER,
|
||||
temBAD_LIMIT,
|
||||
temBAD_OFFER,
|
||||
temBAD_PATH,
|
||||
temBAD_PATH_LOOP,
|
||||
temBAD_PUBLISH,
|
||||
temBAD_TRANSFER_RATE,
|
||||
temBAD_SEND_XRP_LIMIT,
|
||||
temBAD_SEND_XRP_MAX,
|
||||
temBAD_SEND_XRP_NO_DIRECT,
|
||||
temBAD_SEND_XRP_PARTIAL,
|
||||
temBAD_SEND_XRP_PATHS,
|
||||
temBAD_SIGNATURE,
|
||||
temBAD_SRC_ACCOUNT,
|
||||
temBAD_SEQUENCE,
|
||||
temDST_IS_SRC,
|
||||
temDST_NEEDED,
|
||||
temINVALID,
|
||||
temINVALID_FLAG,
|
||||
temREDUNDANT,
|
||||
temREDUNDANT_SEND_MAX,
|
||||
temRIPPLE_EMPTY,
|
||||
temUNCERTAIN, // An intermediate result used internally, should never be returned.
|
||||
temUNKNOWN,
|
||||
|
||||
// -199 .. -100: F Failure (sequence number previously used)
|
||||
// Causes:
|
||||
// - Transaction cannot succeed because of ledger state.
|
||||
// - Unexpected ledger state.
|
||||
// - C++ exception.
|
||||
// Implications:
|
||||
// - Not applied
|
||||
// - Not forwarded
|
||||
// - Could succeed in an imagined ledger.
|
||||
tefFAILURE = -199,
|
||||
tefALREADY,
|
||||
tefBAD_ADD_AUTH,
|
||||
tefBAD_AUTH,
|
||||
tefBAD_CLAIM_ID,
|
||||
tefBAD_GEN_AUTH,
|
||||
tefBAD_LEDGER,
|
||||
tefCLAIMED,
|
||||
tefCREATED,
|
||||
tefDST_TAG_NEEDED,
|
||||
tefEXCEPTION,
|
||||
tefGEN_IN_USE,
|
||||
tefINTERNAL,
|
||||
tefNO_AUTH_REQUIRED, // Can't set auth if auth is not required.
|
||||
tefPAST_SEQ,
|
||||
tefWRONG_PRIOR,
|
||||
tefMASTER_DISABLED,
|
||||
|
||||
// -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent)
|
||||
// Causes:
|
||||
// - Prior application of another, possibly non-existant, another transaction could allow this transaction to succeed.
|
||||
// Implications:
|
||||
// - Not applied
|
||||
// - Not forwarded
|
||||
// - Might succeed later
|
||||
// - Hold
|
||||
// - Makes hole in sequence which jams transactions.
|
||||
terRETRY = -99,
|
||||
terFUNDS_SPENT, // This is a free transaction, therefore don't burden network.
|
||||
terINSUF_FEE_B, // Can't pay fee, therefore don't burden network.
|
||||
terNO_ACCOUNT, // Can't pay fee, therefore don't burden network.
|
||||
terNO_AUTH, // Not authorized to hold IOUs.
|
||||
terNO_LINE, // Internal flag.
|
||||
terOWNERS, // Can't succeed with non-zero owner count.
|
||||
terPRE_SEQ, // Can't pay fee, no point in forwarding, therefore don't burden network.
|
||||
terLAST, // Process after all other transactions
|
||||
|
||||
// 0: S Success (success)
|
||||
// Causes:
|
||||
// - Success.
|
||||
// Implications:
|
||||
// - Applied
|
||||
// - Forwarded
|
||||
tesSUCCESS = 0,
|
||||
|
||||
// 100 .. 129 C Claim fee only (ripple transaction with no good paths, pay to non-existent account, no path)
|
||||
// Causes:
|
||||
// - Success, but does not achieve optimal result.
|
||||
// - Invalid transaction or no effect, but claim fee to use the sequence number.
|
||||
// Implications:
|
||||
// - Applied
|
||||
// - Forwarded
|
||||
// Only allowed as a return code of appliedTransaction when !tapRetry. Otherwise, treated as terRETRY.
|
||||
//
|
||||
// DO NOT CHANGE THESE NUMBERS: They appear in ledger meta data.
|
||||
tecCLAIM = 100,
|
||||
tecPATH_PARTIAL = 101,
|
||||
tecUNFUNDED_ADD = 102,
|
||||
tecUNFUNDED_OFFER = 103,
|
||||
tecUNFUNDED_PAYMENT = 104,
|
||||
tecFAILED_PROCESSING = 105,
|
||||
tecDIR_FULL = 121,
|
||||
tecINSUF_RESERVE_LINE = 122,
|
||||
tecINSUF_RESERVE_OFFER = 123,
|
||||
tecNO_DST = 124,
|
||||
tecNO_DST_INSUF_XRP = 125,
|
||||
tecNO_LINE_INSUF_RESERVE = 126,
|
||||
tecNO_LINE_REDUNDANT = 127,
|
||||
tecPATH_DRY = 128,
|
||||
tecUNFUNDED = 129, // Deprecated, old ambiguous unfunded.
|
||||
tecMASTER_DISABLED = 130,
|
||||
tecNO_REGULAR_KEY = 131,
|
||||
tecOWNERS = 132,
|
||||
};
|
||||
|
||||
// VFALCO TODO change these to normal functions.
|
||||
#define isTelLocal(x) ((x) >= telLOCAL_ERROR && (x) < temMALFORMED)
|
||||
#define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE)
|
||||
#define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY)
|
||||
#define isTerRetry(x) ((x) >= terRETRY && (x) < tesSUCCESS)
|
||||
#define isTesSuccess(x) ((x) == tesSUCCESS)
|
||||
#define isTecClaim(x) ((x) >= tecCLAIM)
|
||||
|
||||
// VFALCO TODO group these into a shell class along with the defines above.
|
||||
extern bool transResultInfo (TER terCode, std::string& strToken, std::string& strHuman);
|
||||
extern std::string transToken (TER terCode);
|
||||
extern std::string transHuman (TER terCode);
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
63
src/ripple_data/protocol/ripple_TxFlags.h
Normal file
63
src/ripple_data/protocol/ripple_TxFlags.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TXFLAGS_H
|
||||
#define RIPPLE_TXFLAGS_H
|
||||
|
||||
//
|
||||
// Transaction flags.
|
||||
//
|
||||
|
||||
/** Transaction flags.
|
||||
|
||||
These flags modify the behavior of an operation.
|
||||
|
||||
@note Changing these will create a hard fork
|
||||
@ingroup protocol
|
||||
*/
|
||||
class TxFlag
|
||||
{
|
||||
public:
|
||||
static uint32 const requireDestTag = 0x00010000;
|
||||
};
|
||||
// VFALCO TODO Move all flags into this container after some study.
|
||||
|
||||
// AccountSet flags:
|
||||
// VFALCO TODO Javadoc comment every one of these constants
|
||||
//const uint32 TxFlag::requireDestTag = 0x00010000;
|
||||
const uint32 tfOptionalDestTag = 0x00020000;
|
||||
const uint32 tfRequireAuth = 0x00040000;
|
||||
const uint32 tfOptionalAuth = 0x00080000;
|
||||
const uint32 tfDisallowXRP = 0x00100000;
|
||||
const uint32 tfAllowXRP = 0x00200000;
|
||||
const uint32 tfAccountSetMask = ~ (TxFlag::requireDestTag | tfOptionalDestTag
|
||||
| tfRequireAuth | tfOptionalAuth
|
||||
| tfDisallowXRP | tfAllowXRP);
|
||||
|
||||
// AccountSet SetFlag/ClearFlag values
|
||||
const uint32 asfRequireDest = 1;
|
||||
const uint32 asfRequireAuth = 2;
|
||||
const uint32 asfDisallowXRP = 3;
|
||||
const uint32 asfDisableMaster = 4;
|
||||
|
||||
// OfferCreate flags:
|
||||
const uint32 tfPassive = 0x00010000;
|
||||
const uint32 tfImmediateOrCancel = 0x00020000;
|
||||
const uint32 tfFillOrKill = 0x00040000;
|
||||
const uint32 tfSell = 0x00080000;
|
||||
const uint32 tfOfferCreateMask = ~ (tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
|
||||
|
||||
// Payment flags:
|
||||
const uint32 tfNoRippleDirect = 0x00010000;
|
||||
const uint32 tfPartialPayment = 0x00020000;
|
||||
const uint32 tfLimitQuality = 0x00040000;
|
||||
const uint32 tfPaymentMask = ~ (tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
|
||||
|
||||
// TrustSet flags:
|
||||
const uint32 tfSetfAuth = 0x00010000;
|
||||
const uint32 tfTrustSetMask = ~ (tfSetfAuth);
|
||||
|
||||
#endif
|
||||
97
src/ripple_data/protocol/ripple_TxFormats.cpp
Normal file
97
src/ripple_data/protocol/ripple_TxFormats.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TxFormats::TxFormats ()
|
||||
: SharedSingleton <TxFormats> (SingletonLifetime::persistAfterCreation)
|
||||
{
|
||||
add ("AccountSet", ttACCOUNT_SET)
|
||||
<< SOElement (sfEmailHash, SOE_OPTIONAL)
|
||||
<< SOElement (sfWalletLocator, SOE_OPTIONAL)
|
||||
<< SOElement (sfWalletSize, SOE_OPTIONAL)
|
||||
<< SOElement (sfMessageKey, SOE_OPTIONAL)
|
||||
<< SOElement (sfDomain, SOE_OPTIONAL)
|
||||
<< SOElement (sfTransferRate, SOE_OPTIONAL)
|
||||
<< SOElement (sfSetFlag, SOE_OPTIONAL)
|
||||
<< SOElement (sfClearFlag, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("TrustSet", ttTRUST_SET)
|
||||
<< SOElement (sfLimitAmount, SOE_OPTIONAL)
|
||||
<< SOElement (sfQualityIn, SOE_OPTIONAL)
|
||||
<< SOElement (sfQualityOut, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("OfferCreate", ttOFFER_CREATE)
|
||||
<< SOElement (sfTakerPays, SOE_REQUIRED)
|
||||
<< SOElement (sfTakerGets, SOE_REQUIRED)
|
||||
<< SOElement (sfExpiration, SOE_OPTIONAL)
|
||||
<< SOElement (sfOfferSequence, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("OfferCancel", ttOFFER_CANCEL)
|
||||
<< SOElement (sfOfferSequence, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("SetRegularKey", ttREGULAR_KEY_SET)
|
||||
<< SOElement (sfRegularKey, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("Payment", ttPAYMENT)
|
||||
<< SOElement (sfDestination, SOE_REQUIRED)
|
||||
<< SOElement (sfAmount, SOE_REQUIRED)
|
||||
<< SOElement (sfSendMax, SOE_OPTIONAL)
|
||||
<< SOElement (sfPaths, SOE_DEFAULT)
|
||||
<< SOElement (sfInvoiceID, SOE_OPTIONAL)
|
||||
<< SOElement (sfDestinationTag, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("Contract", ttCONTRACT)
|
||||
<< SOElement (sfExpiration, SOE_REQUIRED)
|
||||
<< SOElement (sfBondAmount, SOE_REQUIRED)
|
||||
<< SOElement (sfStampEscrow, SOE_REQUIRED)
|
||||
<< SOElement (sfRippleEscrow, SOE_REQUIRED)
|
||||
<< SOElement (sfCreateCode, SOE_OPTIONAL)
|
||||
<< SOElement (sfFundCode, SOE_OPTIONAL)
|
||||
<< SOElement (sfRemoveCode, SOE_OPTIONAL)
|
||||
<< SOElement (sfExpireCode, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
add ("RemoveContract", ttCONTRACT_REMOVE)
|
||||
<< SOElement (sfTarget, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("EnableFeature", ttFEATURE)
|
||||
<< SOElement (sfFeature, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("SetFee", ttFEE)
|
||||
<< SOElement (sfBaseFee, SOE_REQUIRED)
|
||||
<< SOElement (sfReferenceFeeUnits, SOE_REQUIRED)
|
||||
<< SOElement (sfReserveBase, SOE_REQUIRED)
|
||||
<< SOElement (sfReserveIncrement, SOE_REQUIRED)
|
||||
;
|
||||
}
|
||||
|
||||
void TxFormats::addCommonFields (Item& item)
|
||||
{
|
||||
item
|
||||
<< SOElement(sfTransactionType, SOE_REQUIRED)
|
||||
<< SOElement(sfFlags, SOE_OPTIONAL)
|
||||
<< SOElement(sfSourceTag, SOE_OPTIONAL)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfSequence, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnID, SOE_OPTIONAL)
|
||||
<< SOElement(sfFee, SOE_REQUIRED)
|
||||
<< SOElement(sfOperationLimit, SOE_OPTIONAL)
|
||||
<< SOElement(sfSigningPubKey, SOE_REQUIRED)
|
||||
<< SOElement(sfTxnSignature, SOE_OPTIONAL)
|
||||
;
|
||||
}
|
||||
|
||||
TxFormats* TxFormats::createInstance ()
|
||||
{
|
||||
return new TxFormats;
|
||||
}
|
||||
57
src/ripple_data/protocol/ripple_TxFormats.h
Normal file
57
src/ripple_data/protocol/ripple_TxFormats.h
Normal file
@@ -0,0 +1,57 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TXFORMATS_H_INCLUDED
|
||||
#define RIPPLE_TXFORMATS_H_INCLUDED
|
||||
|
||||
/** Transaction type identifiers.
|
||||
|
||||
These are part of the binary message format.
|
||||
|
||||
@ingroup protocol
|
||||
*/
|
||||
enum TxType
|
||||
{
|
||||
ttINVALID = -1,
|
||||
|
||||
ttPAYMENT = 0,
|
||||
ttCLAIM = 1, // open
|
||||
ttWALLET_ADD = 2,
|
||||
ttACCOUNT_SET = 3,
|
||||
ttPASSWORD_FUND = 4, // open
|
||||
ttREGULAR_KEY_SET = 5,
|
||||
ttNICKNAME_SET = 6, // open
|
||||
ttOFFER_CREATE = 7,
|
||||
ttOFFER_CANCEL = 8,
|
||||
ttCONTRACT = 9,
|
||||
ttCONTRACT_REMOVE = 10, // can we use the same msg as offer cancel
|
||||
|
||||
ttTRUST_SET = 20,
|
||||
|
||||
ttFEATURE = 100,
|
||||
ttFEE = 101,
|
||||
};
|
||||
|
||||
/** Manages the list of known transaction formats.
|
||||
*/
|
||||
class TxFormats
|
||||
: public KnownFormats <TxType>
|
||||
, public SharedSingleton <TxFormats>
|
||||
{
|
||||
private:
|
||||
/** Create the object.
|
||||
|
||||
This will load the object will all the known transaction formats.
|
||||
*/
|
||||
TxFormats ();
|
||||
|
||||
void addCommonFields (Item& item);
|
||||
|
||||
public:
|
||||
static TxFormats* createInstance ();
|
||||
};
|
||||
|
||||
#endif
|
||||
83
src/ripple_data/ripple_data.cpp
Normal file
83
src/ripple_data/ripple_data.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "BeastConfig.h"
|
||||
|
||||
#include "ripple_data.h"
|
||||
|
||||
//#include <cmath>
|
||||
|
||||
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/range/adaptor/copied.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/hmac.h>
|
||||
//#include <openssl/rand.h> // includes <windows.h> and causes errors due to #define GetMessage
|
||||
#include <openssl/err.h>
|
||||
|
||||
// VFALCO TODO fix these warnings!
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4018) // signed/unsigned mismatch
|
||||
#endif
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
namespace ripple
|
||||
{
|
||||
|
||||
#include "crypto/ripple_Base58.h" // for RippleAddress
|
||||
#include "crypto/ripple_CKey.h" // needs RippleAddress VFALCO TODO remove this dependency cycle
|
||||
#include "crypto/ripple_RFC1751.h"
|
||||
|
||||
#include "crypto/ripple_CBigNum.cpp"
|
||||
#include "crypto/ripple_CKey.cpp"
|
||||
#include "crypto/ripple_CKeyDeterministic.cpp"
|
||||
#include "crypto/ripple_CKeyECIES.cpp"
|
||||
#include "crypto/ripple_Base58.cpp"
|
||||
#include "crypto/ripple_Base58Data.cpp"
|
||||
#include "crypto/ripple_RFC1751.cpp"
|
||||
|
||||
#include "protocol/BuildInfo.cpp"
|
||||
#include "protocol/ripple_FieldNames.cpp"
|
||||
#include "protocol/ripple_LedgerFormats.cpp"
|
||||
#include "protocol/ripple_PackedMessage.cpp"
|
||||
#include "protocol/ripple_RippleAddress.cpp"
|
||||
#include "protocol/ripple_SerializedTypes.cpp"
|
||||
#include "protocol/ripple_Serializer.cpp"
|
||||
#include "protocol/ripple_SerializedObjectTemplate.cpp"
|
||||
#include "protocol/ripple_SerializedObject.cpp"
|
||||
#include "protocol/ripple_TER.cpp"
|
||||
#include "protocol/ripple_TxFormats.cpp"
|
||||
|
||||
// These are for STAmount
|
||||
static const uint64 tenTo14 = 100000000000000ull;
|
||||
static const uint64 tenTo14m1 = tenTo14 - 1;
|
||||
static const uint64 tenTo17 = tenTo14 * 1000;
|
||||
static const uint64 tenTo17m1 = tenTo17 - 1;
|
||||
#include "protocol/ripple_STAmount.cpp"
|
||||
#include "protocol/ripple_STAmountRound.cpp"
|
||||
|
||||
}
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
112
src/ripple_data/ripple_data.h
Normal file
112
src/ripple_data/ripple_data.h
Normal file
@@ -0,0 +1,112 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
/** Include this to get the @ref ripple_data module.
|
||||
|
||||
@file ripple_data.h
|
||||
@ingroup ripple_data
|
||||
*/
|
||||
|
||||
/** Ripple specific data representation and manipulation.
|
||||
|
||||
These form the building blocks of Ripple data.
|
||||
|
||||
@defgroup ripple_data
|
||||
*/
|
||||
|
||||
#ifndef RIPPLE_DATA_RIPPLEHEADER
|
||||
#define RIPPLE_DATA_RIPPLEHEADER
|
||||
|
||||
// VFALCO TODO try to reduce these dependencies
|
||||
#include "../ripple_basics/ripple_basics.h"
|
||||
|
||||
// VFALCO TODO figure out a good place for this file, perhaps give it some
|
||||
// additional hierarchy via directories.
|
||||
#include "ripple.pb.h"
|
||||
|
||||
namespace ripple
|
||||
{
|
||||
|
||||
#include "crypto/ripple_CBigNum.h"
|
||||
#include "crypto/ripple_Base58.h" // VFALCO TODO Can be moved to .cpp if we clean up setAlphabet stuff
|
||||
#include "crypto/ripple_Base58Data.h"
|
||||
#include "crypto/ripple_RFC1751.h"
|
||||
|
||||
#include "protocol/BuildInfo.h"
|
||||
#include "protocol/ripple_FieldNames.h"
|
||||
#include "protocol/ripple_HashPrefix.h"
|
||||
#include "protocol/ripple_PackedMessage.h"
|
||||
#include "protocol/ripple_Protocol.h"
|
||||
#include "protocol/ripple_RippleAddress.h"
|
||||
#include "protocol/ripple_RippleSystem.h"
|
||||
#include "protocol/ripple_Serializer.h" // needs CKey
|
||||
#include "protocol/ripple_TER.h"
|
||||
#include "protocol/ripple_SerializedTypes.h" // needs Serializer, TER
|
||||
#include "protocol/ripple_SerializedObjectTemplate.h"
|
||||
#include "protocol/ripple_KnownFormats.h"
|
||||
#include "protocol/ripple_LedgerFormats.h" // needs SOTemplate from SerializedObjectTemplate
|
||||
#include "protocol/ripple_TxFormats.h"
|
||||
#include "protocol/ripple_SerializedObject.h"
|
||||
#include "protocol/ripple_TxFlags.h"
|
||||
|
||||
#include "utility/ripple_UptimeTimerAdapter.h"
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <>
|
||||
struct range_mutable_iterator <ripple::STPath>
|
||||
{
|
||||
typedef std::vector <ripple::STPathElement>::iterator type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct range_const_iterator <ripple::STPath>
|
||||
{
|
||||
typedef std::vector <ripple::STPathElement>::const_iterator type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct range_mutable_iterator <ripple::STPathSet>
|
||||
{
|
||||
typedef std::vector <ripple::STPath>::iterator type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct range_const_iterator <ripple::STPathSet>
|
||||
{
|
||||
typedef std::vector <ripple::STPath>::const_iterator type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct range_mutable_iterator <ripple::STObject>
|
||||
{
|
||||
typedef ripple::STObject::iterator type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct range_const_iterator <ripple::STObject>
|
||||
{
|
||||
typedef ripple::STObject::const_iterator type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct range_mutable_iterator <ripple::STArray>
|
||||
{
|
||||
typedef ripple::STArray::iterator type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct range_const_iterator <ripple::STArray>
|
||||
{
|
||||
typedef ripple::STArray::const_iterator type;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
20
src/ripple_data/utility/ripple_UptimeTimerAdapter.h
Normal file
20
src/ripple_data/utility/ripple_UptimeTimerAdapter.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_UPTIMETIMERADAPTER_H
|
||||
#define RIPPLE_UPTIMETIMERADAPTER_H
|
||||
|
||||
/** Adapter providing uptime measurements for template classes.
|
||||
*/
|
||||
struct UptimeTimerAdapter
|
||||
{
|
||||
inline static int getElapsedSeconds ()
|
||||
{
|
||||
return UptimeTimer::getInstance ().getElapsedSeconds ();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user