Clean up and restructure sources

This commit is contained in:
Vinnie Falco
2014-09-16 14:03:58 -07:00
parent 1dcd06a1c1
commit 4239880acb
522 changed files with 3264 additions and 3400 deletions

View File

@@ -0,0 +1,236 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
#include <beast/module/core/diagnostic/FatalError.h>
#include <beast/module/core/diagnostic/SemanticVersion.h>
namespace ripple {
char const* BuildInfo::getRawVersionString ()
{
static char const* const rawText =
//--------------------------------------------------------------------------
//
// The build version number (edit this for each release)
//
"0.26.4-alpha"
//
// 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
//
//------------------------------------------------------------------------------
beast::String const& BuildInfo::getVersionString ()
{
struct SanityChecker
{
SanityChecker ()
{
beast::SemanticVersion v;
char const* const rawText = getRawVersionString ();
if (! v.parse (rawText) || v.print () != rawText)
beast::FatalError ("Bad server version string", __FILE__, __LINE__);
versionString = rawText;
}
beast::String versionString;
};
static SanityChecker value;
return value.versionString;
}
char const* BuildInfo::getFullVersionString ()
{
struct PrettyPrinter
{
PrettyPrinter ()
{
beast::String s;
s << "rippled-" << 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
{
beast::String s;
s << beast::String (vmajor) << "." << beast::String (vminor);
return s.toStdString ();
}
//------------------------------------------------------------------------------
class BuildInfo_test : public beast::unit_test::suite
{
public:
void testVersion ()
{
testcase ("version");
beast::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;
testcase ("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 ()
{
testcase ("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 run ()
{
testVersion ();
testProtocol ();
testValues ();
log <<
" Ripple version: " <<
BuildInfo::getVersionString().toStdString();
}
};
BEAST_DEFINE_TESTSUITE(BuildInfo,ripple_data,ripple);
} // ripple

View File

@@ -0,0 +1,87 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BUILDINFO_H_INCLUDED
#define RIPPLE_BUILDINFO_H_INCLUDED
namespace ripple {
/** Versioning information for this build. */
struct BuildInfo
{
/** Server version.
Follows the Semantic Versioning Specification:
http://semver.org/
*/
static beast::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 std::uint32_t 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 ();
static char const* getRawVersionString ();
};
} // ripple
#endif

View File

@@ -0,0 +1,34 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
// The prefix codes are part of the Ripple protocol and existing codes cannot be
// arbitrarily changed.
HashPrefix const HashPrefix::transactionID ('T', 'X', 'N');
HashPrefix const HashPrefix::txNode ('S', 'N', 'D');
HashPrefix const HashPrefix::leafNode ('M', 'L', 'N');
HashPrefix const HashPrefix::innerNode ('M', 'I', 'N');
HashPrefix const HashPrefix::ledgerMaster ('L', 'W', 'R');
HashPrefix const HashPrefix::txSign ('S', 'T', 'X');
HashPrefix const HashPrefix::validation ('V', 'A', 'L');
HashPrefix const HashPrefix::proposal ('P', 'R', 'P');
} // ripple

View File

@@ -0,0 +1,91 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_HASHPREFIX_H
#define RIPPLE_HASHPREFIX_H
namespace ripple {
/** 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
*/
class HashPrefix
{
private:
std::uint32_t m_prefix;
public:
HashPrefix (char a, char b, char c)
: m_prefix (0)
{
m_prefix = a;
m_prefix = (m_prefix << 8) + b;
m_prefix = (m_prefix << 8) + c;
m_prefix = m_prefix << 8;
}
/** Returns the hash prefix associated with this object */
operator std::uint32_t () const
{
return m_prefix;
}
// VFALCO TODO Expand the description to complete, concise sentences.
//
/** transaction plus signature to give transaction ID */
static HashPrefix const transactionID;
/** transaction plus metadata */
static HashPrefix const txNode;
/** account state */
static HashPrefix const leafNode;
/** inner node in tree */
static HashPrefix const innerNode;
/** ledger master data for signing */
static HashPrefix const ledgerMaster;
/** inner transaction to sign */
static HashPrefix const txSign;
/** validation for signing */
static HashPrefix const validation;
/** proposal for signing */
static HashPrefix const proposal;
};
} // ripple
#endif

View File

@@ -0,0 +1,192 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_KNOWNFORMATS_H_INCLUDED
#define RIPPLE_KNOWNFORMATS_H_INCLUDED
#include <beast/cxx14/memory.h> // <memory>
namespace ripple {
/** 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:
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)
{
m_formats.emplace_back (
std::make_unique <Item> (name, type));
auto& item (*m_formats.back());
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:
std::vector <std::unique_ptr <Item>> m_formats;
NameMap m_names;
TypeMap m_types;
};
} // ripple
#endif

View File

@@ -0,0 +1,127 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/core/memory/SharedSingleton.h>
namespace ripple {
LedgerFormats::LedgerFormats ()
{
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 (sfAccountTxnID, SOE_OPTIONAL)
<< 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 ("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 ("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 ("EnabledAmendments", ltAMENDMENTS)
<< SOElement (sfAmendments, SOE_REQUIRED)
;
add ("FeeSettings", ltFEE_SETTINGS)
<< SOElement (sfBaseFee, SOE_REQUIRED)
<< SOElement (sfReferenceFeeUnits, SOE_REQUIRED)
<< SOElement (sfReserveBase, SOE_REQUIRED)
<< SOElement (sfReserveIncrement, SOE_REQUIRED)
;
add ("Ticket", ltTICKET)
<< SOElement (sfAccount, SOE_REQUIRED)
<< SOElement (sfSequence, SOE_REQUIRED)
<< SOElement (sfOwnerNode, SOE_REQUIRED)
<< SOElement (sfTarget, SOE_OPTIONAL)
<< SOElement (sfExpiration, SOE_OPTIONAL)
;
}
void LedgerFormats::addCommonFields (Item& item)
{
item
<< SOElement(sfLedgerIndex, SOE_OPTIONAL)
<< SOElement(sfLedgerEntryType, SOE_REQUIRED)
<< SOElement(sfFlags, SOE_REQUIRED)
;
}
LedgerFormats* LedgerFormats::getInstance ()
{
return beast::SharedSingleton <LedgerFormats>::getInstance ();
}
} // ripple

View File

@@ -0,0 +1,145 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_LEDGERFORMATS_H_INCLUDED
#define RIPPLE_LEDGERFORMATS_H_INCLUDED
namespace ripple {
/** 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.
*/
ltRIPPLE_STATE = 'r',
ltTICKET = 'T',
/* Deprecated. */
ltOFFER = 'o',
ltLEDGER_HASHES = 'h',
ltAMENDMENTS = 'f',
ltFEE_SETTINGS = 's',
// No longer used or supported. Left here to prevent accidental
// reassignment of the ledger type.
ltNICKNAME = 'n',
ltNotUsed01 = 'c',
};
/**
@ingroup protocol
*/
// Used as a prefix for computing ledger indexes (keys).
enum LedgerNameSpace
{
spaceAccount = 'a',
spaceDirNode = 'd',
spaceGenerator = 'g',
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',
spaceAmendment = 'f',
spaceFee = 'e',
spaceTicket = 'T',
// No longer used or supported. Left here to reserve the space and
// avoid accidental reuse of the space.
spaceNickname = 'n',
};
/**
@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
lsfNoFreeze = 0x00200000, // True, cannot freeze ripple states
lsfGlobalFreeze = 0x00400000, // True, all assets frozen
// 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,
lsfLowNoRipple = 0x00100000,
lsfHighNoRipple = 0x00200000,
lsfLowFreeze = 0x00400000, // True, low side has set freeze flag
lsfHighFreeze = 0x00800000, // True, high side has set freeze flag
};
//------------------------------------------------------------------------------
/** Holds the list of known ledger entry formats.
*/
class LedgerFormats : public KnownFormats <LedgerEntryType>
{
public:
LedgerFormats ();
static LedgerFormats* getInstance ();
private:
void addCommonFields (Item& item);
};
} // ripple
#endif

View File

@@ -0,0 +1,67 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_PROTOCOL_H
#define RIPPLE_PROTOCOL_H
#include <ripple/types/base_uint.h>
#include <cstdint>
namespace ripple {
/** 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
};
/** A ledger index.
*/
// VFALCO TODO pick one. I like Index since its not an abbreviation
typedef std::uint32_t LedgerIndex;
// VFALCO NOTE "LedgerSeq" appears in some SQL statement text
typedef std::uint32_t LedgerSeq;
/** A transaction identifier.
*/
// VFALCO TODO maybe rename to TxHash
typedef uint256 TxID;
/** A transaction index.
*/
typedef std::uint32_t TxSeq; // VFALCO NOTE Should read TxIndex or TxNum
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,304 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_RIPPLEADDRESS_H
#define RIPPLE_RIPPLEADDRESS_H
#include <ripple/data/crypto/Base58Data.h>
#include <ripple/types/UInt160.h>
#include <ripple/types/UintTypes.h>
#include <ripple/types/RippleAccountID.h>
#include <ripple/types/RippleAccountPrivateKey.h>
#include <ripple/types/RippleAccountPublicKey.h>
#include <ripple/types/RipplePrivateKey.h>
#include <ripple/types/RipplePublicKey.h>
#include <ripple/types/RipplePublicKeyHash.h>
#include <ripple/sslutil/ECDSACanonical.h>
namespace ripple {
//
// 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 only 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
//
NodeID getNodeID () const;
Blob const& getNodePublic () const;
std::string humanNodePublic () const;
bool setNodePublic (std::string const& strPublic);
void setNodePublic (Blob const& vPublic);
bool verifyNodePublic (uint256 const& hash, Blob const& vchSig,
ECDSA mustBeFullyCanonical) const;
bool verifyNodePublic (uint256 const& hash, std::string const& strSig,
ECDSA mustBeFullyCanonical) const;
static RippleAddress createNodePublic (RippleAddress const& naSeed);
static RippleAddress createNodePublic (Blob const& vPublic);
static RippleAddress createNodePublic (std::string const& strPublic);
//
// Node Private
//
Blob const& getNodePrivateData () const;
uint256 getNodePrivate () const;
std::string humanNodePrivate () const;
bool setNodePrivate (std::string const& strPrivate);
void setNodePrivate (Blob const& vPrivate);
void setNodePrivate (uint256 hash256);
void signNodePrivate (uint256 const& hash, Blob& vchSig) const;
static RippleAddress createNodePrivate (RippleAddress const& naSeed);
//
// Accounts IDs
//
Account getAccountID () const;
std::string humanAccountID () const;
bool setAccountID (
std::string const& strAccountID,
Base58::Alphabet const& alphabet = Base58::getRippleAlphabet());
void setAccountID (Account const& hash160In);
#if 0
static RippleAddress createAccountID (std::string const& strAccountID)
{
RippleAddress na;
na.setAccountID (strAccountID);
return na;
}
#endif
static RippleAddress createAccountID (Account const& uiAccountID);
//
// Accounts Public
//
Blob const& getAccountPublic () const;
std::string humanAccountPublic () const;
bool setAccountPublic (std::string const& strPublic);
void setAccountPublic (Blob const& vPublic);
void setAccountPublic (RippleAddress const& generator, int seq);
bool accountPublicVerify (uint256 const& uHash, Blob const& vucSig,
ECDSA mustBeFullyCanonical) 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 (
RippleAddress const& naGenerator, int iSeq);
//
// Accounts Private
//
uint256 getAccountPrivate () const;
std::string humanAccountPrivate () const;
bool setAccountPrivate (std::string const& strPrivate);
void setAccountPrivate (Blob const& vPrivate);
void setAccountPrivate (uint256 hash256);
void setAccountPrivate (RippleAddress const& naGenerator,
RippleAddress const& naSeed, int seq);
bool accountPrivateSign (uint256 const& uHash, Blob& vucSig) const;
// Encrypt a message.
Blob accountPrivateEncrypt (
RippleAddress const& naPublicTo, Blob const& vucPlainText) const;
// Decrypt a message.
Blob accountPrivateDecrypt (
RippleAddress const& naPublicFrom, Blob const& vucCipherText) const;
static RippleAddress createAccountPrivate (
RippleAddress const& generator, RippleAddress const& seed, 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.
//
Blob const& getGenerator () const;
std::string humanGenerator () const;
bool setGenerator (std::string const& strGenerator);
void setGenerator (Blob const& vPublic);
// void setGenerator(RippleAddress const& seed);
// Create generator for making public deterministic keys.
static RippleAddress createGeneratorPublic (RippleAddress const& naSeed);
//
// Seeds
// Clients must disallow reconizable entries from being seeds.
uint128 getSeed () const;
std::string humanSeed () const;
std::string humanSeed1751 () const;
bool setSeed (std::string const& strSeed);
int setSeed1751 (std::string const& strHuman1751);
bool setSeedGeneric (std::string const& strText);
void setSeed (uint128 hash128);
void setSeedRandom ();
static RippleAddress createSeedRandom ();
static RippleAddress createSeedGeneric (std::string const& strText);
};
//------------------------------------------------------------------------------
/** RipplePublicKey */
template <>
struct RipplePublicKeyTraits::assign <RippleAddress>
{
void operator() (value_type& value, RippleAddress const& v) const
{
Blob const& b (v.getNodePublic ());
construct (&b.front(), &b.back()+1, value);
}
};
/** RipplePublicKeyHash */
template <>
struct RipplePublicKeyHashTraits::assign <RippleAddress>
{
void operator() (value_type& value, RippleAddress const& v) const
{
auto const ui (v.getNodeID ());
construct (ui.begin(), ui.end(), value);
}
};
/** RipplePrivateKey */
template <>
struct RipplePrivateKeyTraits::assign <RippleAddress>
{
void operator() (value_type& value, RippleAddress const& v) const
{
uint256 const ui (v.getNodePrivate ());
construct (ui.begin(), ui.end(), value);
}
};
/** RippleAccountID */
template <>
struct RippleAccountIDTraits::assign <RippleAddress>
{
void operator() (value_type& value, RippleAddress const& v) const
{
auto const ui (v.getAccountID ());
construct (ui.begin(), ui.end(), value);
}
};
/** RippleAccountPublicKey */
template <>
struct RippleAccountPublicKeyTraits::assign <RippleAddress>
{
void operator() (value_type& value, RippleAddress const& v) const
{
Blob const& b (v.getAccountPublic ());
construct (&b.front(), &b.back()+1, value);
}
};
/** RippleAccountPrivateKey */
template <>
struct RippleAccountPrivateKeyTraits::assign <RippleAddress>
{
void operator() (value_type& value, RippleAddress const& v) const
{
uint256 const ui (v.getAccountPrivate ());
construct (ui.begin(), ui.end(), value);
}
};
} // ripple
#endif

View File

@@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_RIPPLESYSTEM_H
#define RIPPLE_RIPPLESYSTEM_H
namespace ripple {
/** 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_PRECISION 6
} // ripple
#endif

View File

@@ -0,0 +1,399 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/data/protocol/SField.h>
namespace ripple {
// These must stay at the top of this file, and in this order
// Files-cope statics are preferred here because the SFields must be
// file-scope. The following 3 objects must have scope prior to
// the file-scope SFields.
static std::mutex SField_mutex;
static std::map<int, SField::ptr> knownCodeToField;
static std::map<int, std::unique_ptr<SField const>> unknownCodeToField;
int SField::num = 0;
typedef std::lock_guard <std::mutex> StaticScopedLockType;
// Give this translation unit only, permission to construct SFields
struct SField::make
{
#ifndef _MSC_VER
template <class ...Args>
static SField one(SField const* p, Args&& ...args)
{
SField result(std::forward<Args>(args)...);
knownCodeToField[result.fieldCode] = p;
return result;
}
#else // remove this when VS gets variadic templates
template <class A0>
static SField one(SField const* p, A0&& arg0)
{
SField result(std::forward<A0>(arg0));
knownCodeToField[result.fieldCode] = p;
return result;
}
template <class A0, class A1, class A2>
static SField one(SField const* p, A0&& arg0, A1&& arg1, A2&& arg2)
{
SField result(std::forward<A0>(arg0), std::forward<A1>(arg1),
std::forward<A2>(arg2));
knownCodeToField[result.fieldCode] = p;
return result;
}
template <class A0, class A1, class A2, class A3>
static SField one(SField const* p, A0&& arg0, A1&& arg1, A2&& arg2,
A3&& arg3)
{
SField result(std::forward<A0>(arg0), std::forward<A1>(arg1),
std::forward<A2>(arg2), std::forward<A3>(arg3));
knownCodeToField[result.fieldCode] = p;
return result;
}
template <class A0, class A1, class A2, class A3, class A4>
static SField one(SField const* p, A0&& arg0, A1&& arg1, A2&& arg2,
A3&& arg3, A4&& arg4)
{
SField result(std::forward<A0>(arg0), std::forward<A1>(arg1),
std::forward<A2>(arg2), std::forward<A3>(arg3),
std::forward<A4>(arg4));
knownCodeToField[result.fieldCode] = p;
return result;
}
#endif
};
using make = SField::make;
// Construct all compile-time SFields, and register them in the knownCodeToField
// database:
SField const sfInvalid = make::one(&sfInvalid, -1);
SField const sfGeneric = make::one(&sfGeneric, 0);
SField const sfLedgerEntry = make::one(&sfLedgerEntry, STI_LEDGERENTRY, 257, "LedgerEntry");
SField const sfTransaction = make::one(&sfTransaction, STI_TRANSACTION, 257, "Transaction");
SField const sfValidation = make::one(&sfValidation, STI_VALIDATION, 257, "Validation");
SField const sfMetadata = make::one(&sfMetadata, STI_METADATA, 257, "Metadata");
SField const sfHash = make::one(&sfHash, STI_HASH256, 257, "hash");
SField const sfIndex = make::one(&sfIndex, STI_HASH256, 258, "index");
// 8-bit integers
SField const sfCloseResolution = make::one(&sfCloseResolution, STI_UINT8, 1, "CloseResolution");
SField const sfTemplateEntryType = make::one(&sfTemplateEntryType, STI_UINT8, 2, "TemplateEntryType");
SField const sfTransactionResult = make::one(&sfTransactionResult, STI_UINT8, 3, "TransactionResult");
// 16-bit integers
SField const sfLedgerEntryType = make::one(&sfLedgerEntryType, STI_UINT16, 1, "LedgerEntryType", SField::sMD_Never);
SField const sfTransactionType = make::one(&sfTransactionType, STI_UINT16, 2, "TransactionType");
// 32-bit integers (common)
SField const sfFlags = make::one(&sfFlags, STI_UINT32, 2, "Flags");
SField const sfSourceTag = make::one(&sfSourceTag, STI_UINT32, 3, "SourceTag");
SField const sfSequence = make::one(&sfSequence, STI_UINT32, 4, "Sequence");
SField const sfPreviousTxnLgrSeq = make::one(&sfPreviousTxnLgrSeq, STI_UINT32, 5, "PreviousTxnLgrSeq", SField::sMD_DeleteFinal);
SField const sfLedgerSequence = make::one(&sfLedgerSequence, STI_UINT32, 6, "LedgerSequence");
SField const sfCloseTime = make::one(&sfCloseTime, STI_UINT32, 7, "CloseTime");
SField const sfParentCloseTime = make::one(&sfParentCloseTime, STI_UINT32, 8, "ParentCloseTime");
SField const sfSigningTime = make::one(&sfSigningTime, STI_UINT32, 9, "SigningTime");
SField const sfExpiration = make::one(&sfExpiration, STI_UINT32, 10, "Expiration");
SField const sfTransferRate = make::one(&sfTransferRate, STI_UINT32, 11, "TransferRate");
SField const sfWalletSize = make::one(&sfWalletSize, STI_UINT32, 12, "WalletSize");
SField const sfOwnerCount = make::one(&sfOwnerCount, STI_UINT32, 13, "OwnerCount");
SField const sfDestinationTag = make::one(&sfDestinationTag, STI_UINT32, 14, "DestinationTag");
// 32-bit integers (uncommon)
SField const sfHighQualityIn = make::one(&sfHighQualityIn, STI_UINT32, 16, "HighQualityIn");
SField const sfHighQualityOut = make::one(&sfHighQualityOut, STI_UINT32, 17, "HighQualityOut");
SField const sfLowQualityIn = make::one(&sfLowQualityIn, STI_UINT32, 18, "LowQualityIn");
SField const sfLowQualityOut = make::one(&sfLowQualityOut, STI_UINT32, 19, "LowQualityOut");
SField const sfQualityIn = make::one(&sfQualityIn, STI_UINT32, 20, "QualityIn");
SField const sfQualityOut = make::one(&sfQualityOut, STI_UINT32, 21, "QualityOut");
SField const sfStampEscrow = make::one(&sfStampEscrow, STI_UINT32, 22, "StampEscrow");
SField const sfBondAmount = make::one(&sfBondAmount, STI_UINT32, 23, "BondAmount");
SField const sfLoadFee = make::one(&sfLoadFee, STI_UINT32, 24, "LoadFee");
SField const sfOfferSequence = make::one(&sfOfferSequence, STI_UINT32, 25, "OfferSequence");
SField const sfFirstLedgerSequence = make::one(&sfFirstLedgerSequence, STI_UINT32, 26, "FirstLedgerSequence"); // Deprecated: do not use
SField const sfLastLedgerSequence = make::one(&sfLastLedgerSequence, STI_UINT32, 27, "LastLedgerSequence");
SField const sfTransactionIndex = make::one(&sfTransactionIndex, STI_UINT32, 28, "TransactionIndex");
SField const sfOperationLimit = make::one(&sfOperationLimit, STI_UINT32, 29, "OperationLimit");
SField const sfReferenceFeeUnits = make::one(&sfReferenceFeeUnits, STI_UINT32, 30, "ReferenceFeeUnits");
SField const sfReserveBase = make::one(&sfReserveBase, STI_UINT32, 31, "ReserveBase");
SField const sfReserveIncrement = make::one(&sfReserveIncrement, STI_UINT32, 32, "ReserveIncrement");
SField const sfSetFlag = make::one(&sfSetFlag, STI_UINT32, 33, "SetFlag");
SField const sfClearFlag = make::one(&sfClearFlag, STI_UINT32, 34, "ClearFlag");
// 64-bit integers
SField const sfIndexNext = make::one(&sfIndexNext, STI_UINT64, 1, "IndexNext");
SField const sfIndexPrevious = make::one(&sfIndexPrevious, STI_UINT64, 2, "IndexPrevious");
SField const sfBookNode = make::one(&sfBookNode, STI_UINT64, 3, "BookNode");
SField const sfOwnerNode = make::one(&sfOwnerNode, STI_UINT64, 4, "OwnerNode");
SField const sfBaseFee = make::one(&sfBaseFee, STI_UINT64, 5, "BaseFee");
SField const sfExchangeRate = make::one(&sfExchangeRate, STI_UINT64, 6, "ExchangeRate");
SField const sfLowNode = make::one(&sfLowNode, STI_UINT64, 7, "LowNode");
SField const sfHighNode = make::one(&sfHighNode, STI_UINT64, 8, "HighNode");
// 128-bit
SField const sfEmailHash = make::one(&sfEmailHash, STI_HASH128, 1, "EmailHash");
// 256-bit (common)
SField const sfLedgerHash = make::one(&sfLedgerHash, STI_HASH256, 1, "LedgerHash");
SField const sfParentHash = make::one(&sfParentHash, STI_HASH256, 2, "ParentHash");
SField const sfTransactionHash = make::one(&sfTransactionHash, STI_HASH256, 3, "TransactionHash");
SField const sfAccountHash = make::one(&sfAccountHash, STI_HASH256, 4, "AccountHash");
SField const sfPreviousTxnID = make::one(&sfPreviousTxnID, STI_HASH256, 5, "PreviousTxnID", SField::sMD_DeleteFinal);
SField const sfLedgerIndex = make::one(&sfLedgerIndex, STI_HASH256, 6, "LedgerIndex");
SField const sfWalletLocator = make::one(&sfWalletLocator, STI_HASH256, 7, "WalletLocator");
SField const sfRootIndex = make::one(&sfRootIndex, STI_HASH256, 8, "RootIndex", SField::sMD_Always);
SField const sfAccountTxnID = make::one(&sfAccountTxnID, STI_HASH256, 9, "AccountTxnID");
// 256-bit (uncommon)
SField const sfBookDirectory = make::one(&sfBookDirectory, STI_HASH256, 16, "BookDirectory");
SField const sfInvoiceID = make::one(&sfInvoiceID, STI_HASH256, 17, "InvoiceID");
SField const sfNickname = make::one(&sfNickname, STI_HASH256, 18, "Nickname");
SField const sfAmendment = make::one(&sfAmendment, STI_HASH256, 19, "Amendment");
SField const sfTicketID = make::one(&sfTicketID, STI_HASH256, 20, "TicketID");
// 160-bit (common)
SField const sfTakerPaysCurrency = make::one(&sfTakerPaysCurrency, STI_HASH160, 1, "TakerPaysCurrency");
SField const sfTakerPaysIssuer = make::one(&sfTakerPaysIssuer, STI_HASH160, 2, "TakerPaysIssuer");
SField const sfTakerGetsCurrency = make::one(&sfTakerGetsCurrency, STI_HASH160, 3, "TakerGetsCurrency");
SField const sfTakerGetsIssuer = make::one(&sfTakerGetsIssuer, STI_HASH160, 4, "TakerGetsIssuer");
// currency amount (common)
SField const sfAmount = make::one(&sfAmount, STI_AMOUNT, 1, "Amount");
SField const sfBalance = make::one(&sfBalance, STI_AMOUNT, 2, "Balance");
SField const sfLimitAmount = make::one(&sfLimitAmount, STI_AMOUNT, 3, "LimitAmount");
SField const sfTakerPays = make::one(&sfTakerPays, STI_AMOUNT, 4, "TakerPays");
SField const sfTakerGets = make::one(&sfTakerGets, STI_AMOUNT, 5, "TakerGets");
SField const sfLowLimit = make::one(&sfLowLimit, STI_AMOUNT, 6, "LowLimit");
SField const sfHighLimit = make::one(&sfHighLimit, STI_AMOUNT, 7, "HighLimit");
SField const sfFee = make::one(&sfFee, STI_AMOUNT, 8, "Fee");
SField const sfSendMax = make::one(&sfSendMax, STI_AMOUNT, 9, "SendMax");
// currency amount (uncommon)
SField const sfMinimumOffer = make::one(&sfMinimumOffer, STI_AMOUNT, 16, "MinimumOffer");
SField const sfRippleEscrow = make::one(&sfRippleEscrow, STI_AMOUNT, 17, "RippleEscrow");
SField const sfDeliveredAmount = make::one(&sfDeliveredAmount, STI_AMOUNT, 18, "DeliveredAmount");
// variable length
SField const sfPublicKey = make::one(&sfPublicKey, STI_VL, 1, "PublicKey");
SField const sfMessageKey = make::one(&sfMessageKey, STI_VL, 2, "MessageKey");
SField const sfSigningPubKey = make::one(&sfSigningPubKey, STI_VL, 3, "SigningPubKey");
SField const sfTxnSignature = make::one(&sfTxnSignature, STI_VL, 4, "TxnSignature", SField::sMD_Default, false);
SField const sfGenerator = make::one(&sfGenerator, STI_VL, 5, "Generator");
SField const sfSignature = make::one(&sfSignature, STI_VL, 6, "Signature", SField::sMD_Default, false);
SField const sfDomain = make::one(&sfDomain, STI_VL, 7, "Domain");
SField const sfFundCode = make::one(&sfFundCode, STI_VL, 8, "FundCode");
SField const sfRemoveCode = make::one(&sfRemoveCode, STI_VL, 9, "RemoveCode");
SField const sfExpireCode = make::one(&sfExpireCode, STI_VL, 10, "ExpireCode");
SField const sfCreateCode = make::one(&sfCreateCode, STI_VL, 11, "CreateCode");
SField const sfMemoType = make::one(&sfMemoType, STI_VL, 12, "MemoType");
SField const sfMemoData = make::one(&sfMemoData, STI_VL, 13, "MemoData");
SField const sfMemoFormat = make::one(&sfMemoFormat, STI_VL, 14, "MemoFormat");
// account
SField const sfAccount = make::one(&sfAccount, STI_ACCOUNT, 1, "Account");
SField const sfOwner = make::one(&sfOwner, STI_ACCOUNT, 2, "Owner");
SField const sfDestination = make::one(&sfDestination, STI_ACCOUNT, 3, "Destination");
SField const sfIssuer = make::one(&sfIssuer, STI_ACCOUNT, 4, "Issuer");
SField const sfTarget = make::one(&sfTarget, STI_ACCOUNT, 7, "Target");
SField const sfRegularKey = make::one(&sfRegularKey, STI_ACCOUNT, 8, "RegularKey");
// path set
SField const sfPaths = make::one(&sfPaths, STI_PATHSET, 1, "Paths");
// vector of 256-bit
SField const sfIndexes = make::one(&sfIndexes, STI_VECTOR256, 1, "Indexes", SField::sMD_Never);
SField const sfHashes = make::one(&sfHashes, STI_VECTOR256, 2, "Hashes");
SField const sfAmendments = make::one(&sfAmendments, STI_VECTOR256, 3, "Amendments");
// inner object
// OBJECT/1 is reserved for end of object
SField const sfTransactionMetaData = make::one(&sfTransactionMetaData, STI_OBJECT, 2, "TransactionMetaData");
SField const sfCreatedNode = make::one(&sfCreatedNode, STI_OBJECT, 3, "CreatedNode");
SField const sfDeletedNode = make::one(&sfDeletedNode, STI_OBJECT, 4, "DeletedNode");
SField const sfModifiedNode = make::one(&sfModifiedNode, STI_OBJECT, 5, "ModifiedNode");
SField const sfPreviousFields = make::one(&sfPreviousFields, STI_OBJECT, 6, "PreviousFields");
SField const sfFinalFields = make::one(&sfFinalFields, STI_OBJECT, 7, "FinalFields");
SField const sfNewFields = make::one(&sfNewFields, STI_OBJECT, 8, "NewFields");
SField const sfTemplateEntry = make::one(&sfTemplateEntry, STI_OBJECT, 9, "TemplateEntry");
SField const sfMemo = make::one(&sfMemo, STI_OBJECT, 10, "Memo");
// array of objects
// ARRAY/1 is reserved for end of array
SField const sfSigningAccounts = make::one(&sfSigningAccounts, STI_ARRAY, 2, "SigningAccounts");
SField const sfTxnSignatures = make::one(&sfTxnSignatures, STI_ARRAY, 3, "TxnSignatures", SField::sMD_Default, false);
SField const sfSignatures = make::one(&sfSignatures, STI_ARRAY, 4, "Signatures");
SField const sfTemplate = make::one(&sfTemplate, STI_ARRAY, 5, "Template");
SField const sfNecessary = make::one(&sfNecessary, STI_ARRAY, 6, "Necessary");
SField const sfSufficient = make::one(&sfSufficient, STI_ARRAY, 7, "Sufficient");
SField const sfAffectedNodes = make::one(&sfAffectedNodes, STI_ARRAY, 8, "AffectedNodes");
SField const sfMemos = make::one(&sfMemos, STI_ARRAY, 9, "Memos");
SField::SField (SerializedTypeID tid, int fv, const char* fn,
int meta, bool signing)
: fieldCode (field_code (tid, fv))
, fieldType (tid)
, fieldValue (fv)
, fieldName (fn)
, fieldMeta (meta)
, fieldNum (++num)
, signingField (signing)
, rawJsonName (getName ())
, jsonName (rawJsonName.c_str ())
{
}
SField::SField (int fc)
: fieldCode (fc)
, fieldType (STI_UNKNOWN)
, fieldValue (0)
, fieldMeta (sMD_Never)
, fieldNum (++num)
, signingField (true)
, rawJsonName (getName ())
, jsonName (rawJsonName.c_str ())
{
}
// call with the map mutex to protect num.
// This is naturally done with no extra expense
// from getField(int code).
SField::SField (SerializedTypeID tid, int fv)
: fieldCode (field_code (tid, fv)), fieldType (tid), fieldValue (fv),
fieldMeta (sMD_Default),
fieldNum (++num),
signingField (true),
jsonName (nullptr)
{
fieldName = std::to_string (tid) + '/' + std::to_string (fv);
rawJsonName = getName ();
jsonName = Json::StaticString (rawJsonName.c_str ());
assert ((fv != 1) || ((tid != STI_ARRAY) && (tid != STI_OBJECT)));
}
SField::ref SField::getField (int code)
{
auto it = knownCodeToField.find (code);
if (it != knownCodeToField.end ())
{
// 99+% of the time, it will be a valid, known field
return * (it->second);
}
int type = code >> 16;
int field = code & 0xffff;
// Don't dynamically extend types that have no binary encoding.
if ((field > 255) || (code < 0))
return sfInvalid;
switch (type)
{
// Types we are willing to dynamically extend
// types (common)
case STI_UINT16:
case STI_UINT32:
case STI_UINT64:
case STI_HASH128:
case STI_HASH256:
case STI_AMOUNT:
case STI_VL:
case STI_ACCOUNT:
case STI_OBJECT:
case STI_ARRAY:
// types (uncommon)
case STI_UINT8:
case STI_HASH160:
case STI_PATHSET:
case STI_VECTOR256:
break;
default:
return sfInvalid;
}
{
// Lookup in the run-time data base, and create if it does not
// yet exist.
StaticScopedLockType sl (SField_mutex);
auto it = unknownCodeToField.find (code);
if (it != unknownCodeToField.end ())
return * (it->second);
return *(unknownCodeToField[code] = std::unique_ptr<SField const>(
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 std::to_string(static_cast<int> (fieldType)) + "/" +
std::to_string(fieldValue);
}
SField::ref SField::getField (std::string const& fieldName)
{
for (auto const & fieldPair : knownCodeToField)
{
if (fieldPair.second->fieldName == fieldName)
return * (fieldPair.second);
}
{
StaticScopedLockType sl (SField_mutex);
for (auto const & fieldPair : unknownCodeToField)
{
if (fieldPair.second->fieldName == fieldName)
return * (fieldPair.second);
}
}
return sfInvalid;
}
} // ripple

View File

@@ -0,0 +1,417 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_FIELDNAMES_H
#define RIPPLE_FIELDNAMES_H
#include <ripple/basics/BasicTypes.h>
namespace ripple {
enum SerializedTypeID
{
// special types
STI_UNKNOWN = -2,
STI_DONE = -1,
STI_NOTPRESENT = 0,
// // types (common)
STI_UINT16 = 1,
STI_UINT32 = 2,
STI_UINT64 = 3,
STI_HASH128 = 4,
STI_HASH256 = 5,
STI_AMOUNT = 6,
STI_VL = 7,
STI_ACCOUNT = 8,
// 9-13 are reserved
STI_OBJECT = 14,
STI_ARRAY = 15,
// types (uncommon)
STI_UINT8 = 16,
STI_HASH160 = 17,
STI_PATHSET = 18,
STI_VECTOR256 = 19,
// high level types
// cannot be serialized inside other types
STI_TRANSACTION = 10001,
STI_LEDGERENTRY = 10002,
STI_VALIDATION = 10003,
STI_METADATA = 10004,
};
// constexpr
inline
int
field_code(SerializedTypeID id, int index)
{
return (static_cast<int>(id) << 16) | index;
}
// constexpr
inline
int
field_code(int id, int index)
{
return (id << 16) | index;
}
/** Identifies fields.
Fields are necessary to tag data in signed transactions so that
the binary format of the transaction can be canonicalized.
There are two categories of these fields:
1. Those that are created at compile time.
2. Those that are created at run time.
Both are always const. Category 1 can only be created in FieldNames.cpp.
This is enforced at compile time. Category 2 can only be created by
calling getField with an as yet unused fieldType and fieldValue (or the
equivalent fieldCode).
Each SField, once constructed, lives until program termination, and there
is only one instance per fieldType/fieldValue pair which serves the entire
application.
*/
class SField
{
public:
typedef const SField& ref;
typedef SField const* ptr;
enum
{
sMD_Never = 0x00,
sMD_ChangeOrig = 0x01, // original value when it changes
sMD_ChangeNew = 0x02, // new value when it changes
sMD_DeleteFinal = 0x04, // final value when it is deleted
sMD_Create = 0x08, // value when it's created
sMD_Always = 0x10, // value when node containing it is affected at all
sMD_Default = sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create
};
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;
std::string rawJsonName;
Json::StaticString jsonName;
SField(SField const&) = delete;
SField& operator=(SField const&) = delete;
#ifndef _MSC_VER
SField(SField&&) = default;
#else // remove this when VS gets defaulted move members
SField(SField&& sf)
: fieldCode (std::move(sf.fieldCode))
, fieldType (std::move(sf.fieldType))
, fieldValue (std::move(sf.fieldValue))
, fieldName (std::move(sf.fieldName))
, fieldMeta (std::move(sf.fieldMeta))
, fieldNum (std::move(sf.fieldNum))
, signingField (std::move(sf.signingField))
, rawJsonName (std::move(sf.rawJsonName))
, jsonName (rawJsonName.c_str ())
{}
#endif
private:
// These constructors can only be called from FieldNames.cpp
SField (SerializedTypeID tid, int fv, const char* fn,
int meta = sMD_Default, bool signing = true);
explicit SField (int fc);
SField (SerializedTypeID id, int val);
public:
// getField will dynamically construct a new SField if necessary
static SField::ref getField (int fieldCode);
static SField::ref getField (std::string const& 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 ();
}
Json::StaticString const& getJsonName () const
{
return jsonName;
}
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;
}
// A discardable field is one that cannot be serialized, and
// should be discarded during serialization,like 'hash'.
// You cannot serialize an object's hash inside that object,
// but you can have it in the JSON representation.
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);
struct make; // public, but still an implementation detail
private:
static int num;
};
extern SField const sfInvalid;
extern SField const sfGeneric;
extern SField const sfLedgerEntry;
extern SField const sfTransaction;
extern SField const sfValidation;
extern SField const sfMetadata;
// 8-bit integers
extern SField const sfCloseResolution;
extern SField const sfTemplateEntryType;
extern SField const sfTransactionResult;
// 16-bit integers
extern SField const sfLedgerEntryType;
extern SField const sfTransactionType;
// 32-bit integers (common)
extern SField const sfFlags;
extern SField const sfSourceTag;
extern SField const sfSequence;
extern SField const sfPreviousTxnLgrSeq;
extern SField const sfLedgerSequence;
extern SField const sfCloseTime;
extern SField const sfParentCloseTime;
extern SField const sfSigningTime;
extern SField const sfExpiration;
extern SField const sfTransferRate;
extern SField const sfWalletSize;
extern SField const sfOwnerCount;
extern SField const sfDestinationTag;
// 32-bit integers (uncommon)
extern SField const sfHighQualityIn;
extern SField const sfHighQualityOut;
extern SField const sfLowQualityIn;
extern SField const sfLowQualityOut;
extern SField const sfQualityIn;
extern SField const sfQualityOut;
extern SField const sfStampEscrow;
extern SField const sfBondAmount;
extern SField const sfLoadFee;
extern SField const sfOfferSequence;
extern SField const sfFirstLedgerSequence; // Deprecated: do not use
extern SField const sfLastLedgerSequence;
extern SField const sfTransactionIndex;
extern SField const sfOperationLimit;
extern SField const sfReferenceFeeUnits;
extern SField const sfReserveBase;
extern SField const sfReserveIncrement;
extern SField const sfSetFlag;
extern SField const sfClearFlag;
// 64-bit integers
extern SField const sfIndexNext;
extern SField const sfIndexPrevious;
extern SField const sfBookNode;
extern SField const sfOwnerNode;
extern SField const sfBaseFee;
extern SField const sfExchangeRate;
extern SField const sfLowNode;
extern SField const sfHighNode;
// 128-bit
extern SField const sfEmailHash;
// 256-bit (common)
extern SField const sfLedgerHash;
extern SField const sfParentHash;
extern SField const sfTransactionHash;
extern SField const sfAccountHash;
extern SField const sfPreviousTxnID;
extern SField const sfLedgerIndex;
extern SField const sfWalletLocator;
extern SField const sfRootIndex;
extern SField const sfAccountTxnID;
// 256-bit (uncommon)
extern SField const sfBookDirectory;
extern SField const sfInvoiceID;
extern SField const sfNickname;
extern SField const sfAmendment;
extern SField const sfTicketID;
// 160-bit (common)
extern SField const sfTakerPaysCurrency;
extern SField const sfTakerPaysIssuer;
extern SField const sfTakerGetsCurrency;
extern SField const sfTakerGetsIssuer;
// currency amount (common)
extern SField const sfAmount;
extern SField const sfBalance;
extern SField const sfLimitAmount;
extern SField const sfTakerPays;
extern SField const sfTakerGets;
extern SField const sfLowLimit;
extern SField const sfHighLimit;
extern SField const sfFee;
extern SField const sfSendMax;
// currency amount (uncommon)
extern SField const sfMinimumOffer;
extern SField const sfRippleEscrow;
extern SField const sfDeliveredAmount;
// variable length
extern SField const sfPublicKey;
extern SField const sfMessageKey;
extern SField const sfSigningPubKey;
extern SField const sfTxnSignature;
extern SField const sfGenerator;
extern SField const sfSignature;
extern SField const sfDomain;
extern SField const sfFundCode;
extern SField const sfRemoveCode;
extern SField const sfExpireCode;
extern SField const sfCreateCode;
extern SField const sfMemoType;
extern SField const sfMemoData;
extern SField const sfMemoFormat;
// account
extern SField const sfAccount;
extern SField const sfOwner;
extern SField const sfDestination;
extern SField const sfIssuer;
extern SField const sfTarget;
extern SField const sfRegularKey;
// path set
extern SField const sfPaths;
// vector of 256-bit
extern SField const sfIndexes;
extern SField const sfHashes;
extern SField const sfAmendments;
// inner object
// OBJECT/1 is reserved for end of object
extern SField const sfTransactionMetaData;
extern SField const sfCreatedNode;
extern SField const sfDeletedNode;
extern SField const sfModifiedNode;
extern SField const sfPreviousFields;
extern SField const sfFinalFields;
extern SField const sfNewFields;
extern SField const sfTemplateEntry;
extern SField const sfMemo;
// array of objects
// ARRAY/1 is reserved for end of array
extern SField const sfSigningAccounts;
extern SField const sfTxnSignatures;
extern SField const sfSignatures;
extern SField const sfTemplate;
extern SField const sfNecessary;
extern SField const sfSufficient;
extern SField const sfAffectedNodes;
extern SField const sfMemos;
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,473 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_STAMOUNT_H
#define RIPPLE_STAMOUNT_H
#include <ripple/data/protocol/SField.h>
#include <ripple/data/protocol/Serializer.h>
#include <ripple/data/protocol/SerializedType.h>
#include <beast/cxx14/memory.h> // <memory>
namespace ripple {
// Internal form:
// 1: If amount is zero, then value is zero and offset is -100
// 2: Otherwise:
// legal offset range is -96 to +80 inclusive
// value range is 10^15 to (10^16 - 1) inclusive
// amount = value * [10 ^ offset]
// Wire form:
// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
class STAmount : public SerializedType
{
public:
typedef std::uint64_t mantissa_type;
typedef int exponent_type;
typedef std::pair <mantissa_type, exponent_type> rep;
private:
Issue mIssue;
mantissa_type mValue;
exponent_type mOffset;
bool mIsNative; // A shorthand for isXRP(mIssue).
bool mIsNegative;
public:
static const int cMinOffset = -96;
static const int cMaxOffset = 80;
static const std::uint64_t cMinValue = 1000000000000000ull;
static const std::uint64_t cMaxValue = 9999999999999999ull;
static const std::uint64_t cMaxNative = 9000000000000000000ull;
// Max native value on network.
static const std::uint64_t cMaxNativeN = 100000000000000000ull;
static const std::uint64_t cNotNative = 0x8000000000000000ull;
static const std::uint64_t cPosNative = 0x4000000000000000ull;
static std::uint64_t uRateOne;
//--------------------------------------------------------------------------
struct unchecked { };
// Calls canonicalize
STAmount (SField::ref name, Issue const& issue,
mantissa_type mantissa, exponent_type exponent,
bool native, bool negative);
// Does not call canonicalize
STAmount (SField::ref name, Issue const& issue,
mantissa_type mantissa, exponent_type exponent,
bool native, bool negative, unchecked);
STAmount (SField::ref name, std::int64_t mantissa);
STAmount (SField::ref name,
std::uint64_t mantissa = 0, bool negative = false);
STAmount (SField::ref name, Issue const& issue,
std::uint64_t mantissa = 0, int exponent = 0, bool negative = false);
STAmount (std::uint64_t mantissa = 0, bool negative = false);
STAmount (Issue const& issue,
std::uint64_t mantissa = 0, int exponent = 0, bool negative = false);
// VFALCO Is this needed when we have the previous signature?
STAmount (Issue const& issue,
std::uint32_t mantissa, int exponent = 0, bool negative = false);
STAmount (Issue const& issue, std::int64_t mantissa, int exponent = 0);
STAmount (Issue const& issue, int mantissa, int exponent = 0);
//--------------------------------------------------------------------------
private:
static
std::unique_ptr<STAmount>
construct (SerializerIterator&, SField::ref name);
public:
static
STAmount
createFromInt64 (SField::ref n, std::int64_t v);
static
std::unique_ptr <SerializedType>
deserialize (
SerializerIterator& sit, SField::ref name)
{
return construct (sit, name);
}
static
STAmount
saFromRate (std::uint64_t uRate = 0)
{
return STAmount (noIssue(), uRate, -9, false);
}
static
STAmount
deserialize (SerializerIterator&);
//--------------------------------------------------------------------------
//
// Observers
//
//--------------------------------------------------------------------------
int exponent() const noexcept { return mOffset; }
bool native() const noexcept { return mIsNative; }
bool negative() const noexcept { return mIsNegative; }
std::uint64_t mantissa() const noexcept { return mValue; }
Issue const& issue() const { return mIssue; }
// These three are deprecated
Currency const& getCurrency() const { return mIssue.currency; }
Account const& getIssuer() const { return mIssue.account; }
bool isNative() const { return mIsNative; }
int
signum() const noexcept
{
return mValue ? (mIsNegative ? -1 : 1) : 0;
}
/** Returns a zero value with the same issuer and currency. */
STAmount
zeroed() const
{
// TODO(tom): what does this next comment mean here?
// See https://ripplelabs.atlassian.net/browse/WC-1847?jql=
return STAmount (mIssue);
}
// When the currency is XRP, the value in raw unsigned units.
std::uint64_t
getNValue() const;
// When the currency is XRP, the value in raw signed units.
std::int64_t
getSNValue() const;
// VFALCO TODO This can be a free function or just call the
// member on the issue.
std::string
getHumanCurrency() const;
void
setJson (Json::Value&) const;
//--------------------------------------------------------------------------
//
// Operators
//
//--------------------------------------------------------------------------
explicit operator bool() const noexcept
{
return *this != zero;
}
bool isComparable (STAmount const&) const;
void throwComparable (STAmount const&) const;
STAmount& operator+= (STAmount const&);
STAmount& operator-= (STAmount const&);
STAmount& operator+= (std::uint64_t);
STAmount& operator-= (std::uint64_t);
STAmount& operator= (std::uint64_t);
STAmount& operator= (beast::Zero)
{
clear();
return *this;
}
friend STAmount operator+ (STAmount const& v1, STAmount const& v2);
friend STAmount operator- (STAmount const& v1, STAmount const& v2);
//--------------------------------------------------------------------------
//
// Modification
//
//--------------------------------------------------------------------------
// VFALCO TODO Remove this, it is only called from the unit test
void roundSelf();
void setNValue (std::uint64_t v);
void setSNValue (std::int64_t);
void negate()
{
if (*this != zero)
mIsNegative = !mIsNegative;
}
void clear()
{
// VFALCO: Why -100?
mOffset = mIsNative ? 0 : -100;
mValue = 0;
mIsNegative = false;
}
// Zero while copying currency and issuer.
void clear (STAmount const& saTmpl)
{
clear (saTmpl.mIssue);
}
void clear (Issue const& issue)
{
setIssue(issue);
clear();
}
void setIssuer (Account const& uIssuer)
{
mIssue.account = uIssuer;
setIssue(mIssue);
}
/** Set the Issue for this amount and update mIsNative. */
void setIssue (Issue const& issue);
// VFALCO TODO Rename to setValueOnly (it only sets mantissa and exponent)
// Make this private
bool setValue (std::string const& sAmount);
bool setFullValue (std::string const& sAmount,
std::string const& sCurrency = "", std::string const& sIssuer = "");
//--------------------------------------------------------------------------
//
// SerializedType
//
//--------------------------------------------------------------------------
SerializedTypeID
getSType() const override
{
return STI_AMOUNT;
}
std::string
getFullText() const override;
std::string
getText() const override;
Json::Value
getJson (int) const override;
void
add (Serializer& s) const override;
bool
isEquivalent (const SerializedType& t) const override;
bool
isDefault() const override
{
return (mValue == 0) && mIsNative;
}
private:
STAmount*
duplicate() const override;
void canonicalize();
void set (std::int64_t v);
};
//------------------------------------------------------------------------------
//
// Creation
//
//------------------------------------------------------------------------------
// VFALCO TODO The parameter type should be Quality not uint64_t
STAmount
amountFromQuality (std::uint64_t rate);
STAmount
amountFromJson (SField::ref name, Json::Value const& v);
bool
amountFromJsonNoThrow (STAmount& result, Json::Value const& jvSource);
//------------------------------------------------------------------------------
//
// Observers
//
//------------------------------------------------------------------------------
inline
bool
isLegalNet (STAmount const& value)
{
return ! value.native() || (value.mantissa() <= STAmount::cMaxNativeN);
}
//------------------------------------------------------------------------------
//
// Operators
//
//------------------------------------------------------------------------------
bool operator== (STAmount const& lhs, STAmount const& rhs);
bool operator!= (STAmount const& lhs, STAmount const& rhs);
bool operator< (STAmount const& lhs, STAmount const& rhs);
bool operator> (STAmount const& lhs, STAmount const& rhs);
bool operator<= (STAmount const& lhs, STAmount const& rhs);
bool operator>= (STAmount const& lhs, STAmount const& rhs);
// native currency only
bool operator< (STAmount const& lhs, std::uint64_t rhs);
bool operator> (STAmount const& lhs, std::uint64_t rhs);
bool operator<= (STAmount const& lhs, std::uint64_t rhs);
bool operator>= (STAmount const& lhs, std::uint64_t rhs);
STAmount operator+ (STAmount const& lhs, std::uint64_t rhs);
STAmount operator- (STAmount const& lhs, std::uint64_t rhs);
STAmount operator- (STAmount const& value);
//------------------------------------------------------------------------------
//
// Arithmetic
//
//------------------------------------------------------------------------------
STAmount
divide (STAmount const& v1, STAmount const& v2, Issue const& issue);
inline
STAmount
divide (STAmount const& v1, STAmount const& v2, STAmount const& saUnit)
{
return divide (v1, v2, saUnit.issue());
}
inline
STAmount
divide (STAmount const& v1, STAmount const& v2)
{
return divide (v1, v2, v1);
}
STAmount
multiply (STAmount const& v1, STAmount const& v2, Issue const& issue);
inline
STAmount
multiply (STAmount const& v1, STAmount const& v2, STAmount const& saUnit)
{
return multiply (v1, v2, saUnit.issue());
}
inline
STAmount
multiply (STAmount const& v1, STAmount const& v2)
{
return multiply (v1, v2, v1);
}
void
canonicalizeRound (bool native, std::uint64_t& mantissa,
int& exponent, bool roundUp);
/* addRound, subRound can end up rounding if the amount subtracted is too small
to make a change. Consder (X-d) where d is very small relative to X.
If you ask to round down, then (X-d) should not be X unless d is zero.
If you ask to round up, (X+d) should never be X unless d is zero. (Assuming X and d are positive).
*/
// Add, subtract, multiply, or divide rounding result in specified direction
STAmount
addRound (STAmount const& v1, STAmount const& v2, bool roundUp);
STAmount
subRound (STAmount const& v1, STAmount const& v2, bool roundUp);
STAmount
mulRound (STAmount const& v1, STAmount const& v2,
Issue const& issue, bool roundUp);
inline
STAmount
mulRound (STAmount const& v1, STAmount const& v2,
STAmount const& saUnit, bool roundUp)
{
return mulRound (v1, v2, saUnit.issue(), roundUp);
}
inline
STAmount
mulRound (STAmount const& v1, STAmount const& v2, bool roundUp)
{
return mulRound (v1, v2, v1.issue(), roundUp);
}
STAmount
divRound (STAmount const& v1, STAmount const& v2,
Issue const& issue, bool roundUp);
inline
STAmount
divRound (STAmount const& v1, STAmount const& v2,
STAmount const& saUnit, bool roundUp)
{
return divRound (v1, v2, saUnit.issue(), roundUp);
}
inline
STAmount
divRound (STAmount const& v1, STAmount const& v2, bool roundUp)
{
return divRound (v1, v2, v1.issue(), roundUp);
}
// Someone is offering X for Y, what is the rate?
// Rate: smaller is better, the taker wants the most out: in/out
// VFALCO TODO Return a Quality object
std::uint64_t
getRate (STAmount const& offerOut, STAmount const& offerIn);
//------------------------------------------------------------------------------
inline bool isXRP(STAmount const& amount)
{
return isXRP (amount.issue().currency);
}
// VFALCO TODO Make static member accessors for these in STAmount
extern const STAmount saZero;
extern const STAmount saOne;
} // ripple
#endif

View File

@@ -0,0 +1,528 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/data/protocol/STAmount.h>
#include <beast/unit_test/suite.h>
namespace ripple {
class STAmount_test : public beast::unit_test::suite
{
public:
static STAmount serializeAndDeserialize (STAmount const& s)
{
Serializer ser;
s.add (ser);
SerializerIterator sit (ser);
return STAmount::deserialize (sit);
}
//--------------------------------------------------------------------------
bool roundTest (int n, int d, int m)
{
// check STAmount rounding
STAmount num (noIssue(), n);
STAmount den (noIssue(), d);
STAmount mul (noIssue(), m);
STAmount quot = divide (n, d, noIssue());
STAmount res = multiply (quot, mul, noIssue());
expect (! res.isNative (), "Product should not be native");
res.roundSelf ();
STAmount cmp (noIssue(), (n * m) / d);
expect (! cmp.isNative (), "Comparison amount should not be native");
if (res != cmp)
{
cmp.throwComparable (res);
WriteLog (lsWARNING, STAmount) << "(" << num.getText () << "/" << den.getText () << ") X " << mul.getText () << " = "
<< res.getText () << " not " << cmp.getText ();
fail ("Rounding");
return false;
}
else
{
pass ();
}
return true;
}
void mulTest (int a, int b)
{
STAmount aa (noIssue(), a);
STAmount bb (noIssue(), b);
STAmount prod1 (multiply (aa, bb, noIssue()));
expect (! prod1.isNative ());
STAmount prod2 (noIssue(), static_cast<std::uint64_t> (a) * static_cast<std::uint64_t> (b));
if (prod1 != prod2)
{
WriteLog (lsWARNING, STAmount) << "nn(" << aa.getFullText () << " * " << bb.getFullText () << ") = " << prod1.getFullText ()
<< " not " << prod2.getFullText ();
fail ("Multiplication result is not exact");
}
else
{
pass ();
}
aa = a;
prod1 = multiply (aa, bb, noIssue());
if (prod1 != prod2)
{
WriteLog (lsWARNING, STAmount) << "n(" << aa.getFullText () << " * " << bb.getFullText () << ") = " << prod1.getFullText ()
<< " not " << prod2.getFullText ();
fail ("Multiplication result is not exact");
}
else
{
pass ();
}
}
//--------------------------------------------------------------------------
void testSetValue ()
{
testcase ("set value");
STAmount saTmp;
#if 0
// Check native floats
saTmp.setFullValue ("1^0");
BOOST_CHECK_MESSAGE (SYSTEM_CURRENCY_PARTS == saTmp.getNValue (), "float integer failed");
saTmp.setFullValue ("0^1");
BOOST_CHECK_MESSAGE (SYSTEM_CURRENCY_PARTS / 10 == saTmp.getNValue (), "float fraction failed");
saTmp.setFullValue ("0^12");
BOOST_CHECK_MESSAGE (12 * SYSTEM_CURRENCY_PARTS / 100 == saTmp.getNValue (), "float fraction failed");
saTmp.setFullValue ("1^2");
BOOST_CHECK_MESSAGE (SYSTEM_CURRENCY_PARTS + (2 * SYSTEM_CURRENCY_PARTS / 10) == saTmp.getNValue (), "float combined failed");
#endif
// Check native integer
saTmp.setFullValue ("1");
expect (1 == saTmp.getNValue (), "should be equal");
}
//--------------------------------------------------------------------------
void testNativeCurrency ()
{
testcase ("native currency");
STAmount zeroSt, one (1), hundred (100);
// VFALCO NOTE Why repeat "STAmount fail" so many times??
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
unexpected (!zeroSt.isNative (), "STAmount fail");
unexpected (!hundred.isNative (), "STAmount fail");
unexpected (zeroSt != zero, "STAmount fail");
unexpected (one == zero, "STAmount fail");
unexpected (hundred == zero, "STAmount fail");
unexpected ((zeroSt < zeroSt), "STAmount fail");
unexpected (! (zeroSt < one), "STAmount fail");
unexpected (! (zeroSt < hundred), "STAmount fail");
unexpected ((one < zeroSt), "STAmount fail");
unexpected ((one < one), "STAmount fail");
unexpected (! (one < hundred), "STAmount fail");
unexpected ((hundred < zeroSt), "STAmount fail");
unexpected ((hundred < one), "STAmount fail");
unexpected ((hundred < hundred), "STAmount fail");
unexpected ((zeroSt > zeroSt), "STAmount fail");
unexpected ((zeroSt > one), "STAmount fail");
unexpected ((zeroSt > hundred), "STAmount fail");
unexpected (! (one > zeroSt), "STAmount fail");
unexpected ((one > one), "STAmount fail");
unexpected ((one > hundred), "STAmount fail");
unexpected (! (hundred > zeroSt), "STAmount fail");
unexpected (! (hundred > one), "STAmount fail");
unexpected ((hundred > hundred), "STAmount fail");
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
unexpected (! (zeroSt <= one), "STAmount fail");
unexpected (! (zeroSt <= hundred), "STAmount fail");
unexpected ((one <= zeroSt), "STAmount fail");
unexpected (! (one <= one), "STAmount fail");
unexpected (! (one <= hundred), "STAmount fail");
unexpected ((hundred <= zeroSt), "STAmount fail");
unexpected ((hundred <= one), "STAmount fail");
unexpected (! (hundred <= hundred), "STAmount fail");
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
unexpected ((zeroSt >= one), "STAmount fail");
unexpected ((zeroSt >= hundred), "STAmount fail");
unexpected (! (one >= zeroSt), "STAmount fail");
unexpected (! (one >= one), "STAmount fail");
unexpected ((one >= hundred), "STAmount fail");
unexpected (! (hundred >= zeroSt), "STAmount fail");
unexpected (! (hundred >= one), "STAmount fail");
unexpected (! (hundred >= hundred), "STAmount fail");
unexpected (! (zeroSt == zeroSt), "STAmount fail");
unexpected ((zeroSt == one), "STAmount fail");
unexpected ((zeroSt == hundred), "STAmount fail");
unexpected ((one == zeroSt), "STAmount fail");
unexpected (! (one == one), "STAmount fail");
unexpected ((one == hundred), "STAmount fail");
unexpected ((hundred == zeroSt), "STAmount fail");
unexpected ((hundred == one), "STAmount fail");
unexpected (! (hundred == hundred), "STAmount fail");
unexpected ((zeroSt != zeroSt), "STAmount fail");
unexpected (! (zeroSt != one), "STAmount fail");
unexpected (! (zeroSt != hundred), "STAmount fail");
unexpected (! (one != zeroSt), "STAmount fail");
unexpected ((one != one), "STAmount fail");
unexpected (! (one != hundred), "STAmount fail");
unexpected (! (hundred != zeroSt), "STAmount fail");
unexpected (! (hundred != one), "STAmount fail");
unexpected ((hundred != hundred), "STAmount fail");
unexpected (STAmount ().getText () != "0", "STAmount fail");
unexpected (STAmount (31).getText () != "31", "STAmount fail");
unexpected (STAmount (310).getText () != "310", "STAmount fail");
unexpected (to_string (Currency ()) != "XRP", "cHC(XRP)");
Currency c;
unexpected (!to_currency (c, "USD"), "create USD currency");
unexpected (to_string (c) != "USD", "check USD currency");
const std::string cur = "015841551A748AD2C1F76FF6ECB0CCCD00000000";
unexpected (!to_currency (c, cur), "create custom currency");
unexpected (to_string (c) != cur, "check custom currency");
unexpected (c != Currency (cur), "check custom currency");
}
//--------------------------------------------------------------------------
void testCustomCurrency ()
{
testcase ("custom currency");
STAmount zeroSt (noIssue()), one (noIssue(), 1), hundred (noIssue(), 100);
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
unexpected (zeroSt.isNative (), "STAmount fail");
unexpected (hundred.isNative (), "STAmount fail");
unexpected (zeroSt != zero, "STAmount fail");
unexpected (one == zero, "STAmount fail");
unexpected (hundred == zero, "STAmount fail");
unexpected ((zeroSt < zeroSt), "STAmount fail");
unexpected (! (zeroSt < one), "STAmount fail");
unexpected (! (zeroSt < hundred), "STAmount fail");
unexpected ((one < zeroSt), "STAmount fail");
unexpected ((one < one), "STAmount fail");
unexpected (! (one < hundred), "STAmount fail");
unexpected ((hundred < zeroSt), "STAmount fail");
unexpected ((hundred < one), "STAmount fail");
unexpected ((hundred < hundred), "STAmount fail");
unexpected ((zeroSt > zeroSt), "STAmount fail");
unexpected ((zeroSt > one), "STAmount fail");
unexpected ((zeroSt > hundred), "STAmount fail");
unexpected (! (one > zeroSt), "STAmount fail");
unexpected ((one > one), "STAmount fail");
unexpected ((one > hundred), "STAmount fail");
unexpected (! (hundred > zeroSt), "STAmount fail");
unexpected (! (hundred > one), "STAmount fail");
unexpected ((hundred > hundred), "STAmount fail");
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
unexpected (! (zeroSt <= one), "STAmount fail");
unexpected (! (zeroSt <= hundred), "STAmount fail");
unexpected ((one <= zeroSt), "STAmount fail");
unexpected (! (one <= one), "STAmount fail");
unexpected (! (one <= hundred), "STAmount fail");
unexpected ((hundred <= zeroSt), "STAmount fail");
unexpected ((hundred <= one), "STAmount fail");
unexpected (! (hundred <= hundred), "STAmount fail");
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
unexpected ((zeroSt >= one), "STAmount fail");
unexpected ((zeroSt >= hundred), "STAmount fail");
unexpected (! (one >= zeroSt), "STAmount fail");
unexpected (! (one >= one), "STAmount fail");
unexpected ((one >= hundred), "STAmount fail");
unexpected (! (hundred >= zeroSt), "STAmount fail");
unexpected (! (hundred >= one), "STAmount fail");
unexpected (! (hundred >= hundred), "STAmount fail");
unexpected (! (zeroSt == zeroSt), "STAmount fail");
unexpected ((zeroSt == one), "STAmount fail");
unexpected ((zeroSt == hundred), "STAmount fail");
unexpected ((one == zeroSt), "STAmount fail");
unexpected (! (one == one), "STAmount fail");
unexpected ((one == hundred), "STAmount fail");
unexpected ((hundred == zeroSt), "STAmount fail");
unexpected ((hundred == one), "STAmount fail");
unexpected (! (hundred == hundred), "STAmount fail");
unexpected ((zeroSt != zeroSt), "STAmount fail");
unexpected (! (zeroSt != one), "STAmount fail");
unexpected (! (zeroSt != hundred), "STAmount fail");
unexpected (! (one != zeroSt), "STAmount fail");
unexpected ((one != one), "STAmount fail");
unexpected (! (one != hundred), "STAmount fail");
unexpected (! (hundred != zeroSt), "STAmount fail");
unexpected (! (hundred != one), "STAmount fail");
unexpected ((hundred != hundred), "STAmount fail");
unexpected (STAmount (noIssue()).getText () != "0", "STAmount fail");
unexpected (STAmount (noIssue(), 31).getText () != "31", "STAmount fail");
unexpected (STAmount (noIssue(), 31, 1).getText () != "310", "STAmount fail");
unexpected (STAmount (noIssue(), 31, -1).getText () != "3.1", "STAmount fail");
unexpected (STAmount (noIssue(), 31, -2).getText () != "0.31", "STAmount fail");
unexpected (multiply (STAmount (noIssue(), 20), STAmount (3), noIssue()).getText () != "60",
"STAmount multiply fail 1");
unexpected (multiply (STAmount (noIssue(), 20), STAmount (3), xrpIssue ()).getText () != "60",
"STAmount multiply fail 2");
unexpected (multiply (STAmount (20), STAmount (3), noIssue()).getText () != "60",
"STAmount multiply fail 3");
unexpected (multiply (STAmount (20), STAmount (3), xrpIssue ()).getText () != "60",
"STAmount multiply fail 4");
if (divide (STAmount (noIssue(), 60), STAmount (3), noIssue()).getText () != "20")
{
WriteLog (lsFATAL, STAmount) << "60/3 = " <<
divide (STAmount (noIssue(), 60),
STAmount (3), noIssue()).getText ();
fail ("STAmount divide fail");
}
else
{
pass ();
}
unexpected (divide (STAmount (noIssue(), 60), STAmount (3), xrpIssue ()).getText () != "20",
"STAmount divide fail");
unexpected (divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), noIssue()).getText () != "20",
"STAmount divide fail");
unexpected (divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), xrpIssue ()).getText () != "20",
"STAmount divide fail");
STAmount a1 (noIssue(), 60), a2 (noIssue(), 10, -1);
unexpected (divide (a2, a1, noIssue()) != amountFromQuality (getRate (a1, a2)),
"STAmount setRate(getRate) fail");
unexpected (divide (a1, a2, noIssue()) != amountFromQuality (getRate (a2, a1)),
"STAmount setRate(getRate) fail");
}
//--------------------------------------------------------------------------
void testArithmetic ()
{
testcase ("arithmetic");
CBigNum b;
for (int i = 0; i < 16; ++i)
{
std::uint64_t r = rand ();
r <<= 32;
r |= rand ();
b.setuint64 (r);
if (b.getuint64 () != r)
{
WriteLog (lsFATAL, STAmount) << r << " != " << b.getuint64 () << " " << b.ToString (16);
fail ("setull64/getull64 failure");
}
else
{
pass ();
}
}
// Test currency multiplication and division operations such as
// convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded
unexpected (getRate (STAmount (1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 1");
unexpected (getRate (STAmount (10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 2");
unexpected (getRate (STAmount (noIssue(), 1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 3");
unexpected (getRate (STAmount (noIssue(), 10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 4");
unexpected (getRate (STAmount (noIssue(), 1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 5");
unexpected (getRate (STAmount (noIssue(), 10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 6");
unexpected (getRate (STAmount (1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 7");
unexpected (getRate (STAmount (10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 8");
roundTest (1, 3, 3);
roundTest (2, 3, 9);
roundTest (1, 7, 21);
roundTest (1, 2, 4);
roundTest (3, 9, 18);
roundTest (7, 11, 44);
for (int i = 0; i <= 100000; ++i)
mulTest (rand () % 10000000, rand () % 10000000);
}
//--------------------------------------------------------------------------
template <class Cond>
bool
expect (Cond cond, beast::String const& s)
{
return suite::expect (cond, s.toStdString());
}
template <class Cond>
bool
expect (Cond cond)
{
return suite::expect (cond);
}
void testUnderflow ()
{
testcase ("underflow");
STAmount bigNative (STAmount::cMaxNative / 2);
STAmount bigValue (noIssue(),
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMaxOffset - 1);
STAmount smallValue (noIssue(),
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMinOffset + 1);
STAmount zeroSt (noIssue(), 0);
STAmount smallXsmall = multiply (smallValue, smallValue, noIssue());
expect (smallXsmall == zero, "smallXsmall != 0");
STAmount bigDsmall = divide (smallValue, bigValue, noIssue());
expect (bigDsmall == zero, beast::String ("small/big != 0: ") + bigDsmall.getText ());
#if 0
// TODO(tom): this test makes no sense - we should have no way to have
// the currency not be XRP while the account is XRP.
bigDsmall = divide (smallValue, bigNative, noCurrency(), xrpAccount ());
#endif
expect (bigDsmall == zero, beast::String ("small/bigNative != 0: ") + bigDsmall.getText ());
bigDsmall = divide (smallValue, bigValue, xrpIssue ());
expect (bigDsmall == zero, beast::String ("(small/big)->N != 0: ") + bigDsmall.getText ());
bigDsmall = divide (smallValue, bigNative, xrpIssue ());
expect (bigDsmall == zero, beast::String ("(small/bigNative)->N != 0: ") + bigDsmall.getText ());
// very bad offer
std::uint64_t r = getRate (smallValue, bigValue);
expect (r == 0, "getRate(smallOut/bigIn) != 0");
// very good offer
r = getRate (bigValue, smallValue);
expect (r == 0, "getRate(smallIn/bigOUt) != 0");
}
//--------------------------------------------------------------------------
void testRounding ()
{
// VFALCO TODO There are no actual tests here, just printed output?
// Change this to actually do something.
#if 0
beginTestCase ("rounding ");
std::uint64_t value = 25000000000000000ull;
int offset = -14;
canonicalizeRound (false, value, offset, true);
STAmount one (noIssue(), 1);
STAmount two (noIssue(), 2);
STAmount three (noIssue(), 3);
STAmount oneThird1 = divRound (one, three, noIssue(), false);
STAmount oneThird2 = divide (one, three, noIssue());
STAmount oneThird3 = divRound (one, three, noIssue(), true);
WriteLog (lsINFO, STAmount) << oneThird1;
WriteLog (lsINFO, STAmount) << oneThird2;
WriteLog (lsINFO, STAmount) << oneThird3;
STAmount twoThird1 = divRound (two, three, noIssue(), false);
STAmount twoThird2 = divide (two, three, noIssue());
STAmount twoThird3 = divRound (two, three, noIssue(), true);
WriteLog (lsINFO, STAmount) << twoThird1;
WriteLog (lsINFO, STAmount) << twoThird2;
WriteLog (lsINFO, STAmount) << twoThird3;
STAmount oneA = mulRound (oneThird1, three, noIssue(), false);
STAmount oneB = multiply (oneThird2, three, noIssue());
STAmount oneC = mulRound (oneThird3, three, noIssue(), true);
WriteLog (lsINFO, STAmount) << oneA;
WriteLog (lsINFO, STAmount) << oneB;
WriteLog (lsINFO, STAmount) << oneC;
STAmount fourThirdsA = addRound (twoThird2, twoThird2, false);
STAmount fourThirdsB = twoThird2 + twoThird2;
STAmount fourThirdsC = addRound (twoThird2, twoThird2, true);
WriteLog (lsINFO, STAmount) << fourThirdsA;
WriteLog (lsINFO, STAmount) << fourThirdsB;
WriteLog (lsINFO, STAmount) << fourThirdsC;
STAmount dripTest1 = mulRound (twoThird2, two, xrpIssue (), false);
STAmount dripTest2 = multiply (twoThird2, two, xrpIssue ());
STAmount dripTest3 = mulRound (twoThird2, two, xrpIssue (), true);
WriteLog (lsINFO, STAmount) << dripTest1;
WriteLog (lsINFO, STAmount) << dripTest2;
WriteLog (lsINFO, STAmount) << dripTest3;
#endif
}
//--------------------------------------------------------------------------
void run ()
{
testSetValue ();
testNativeCurrency ();
testCustomCurrency ();
testArithmetic ();
testUnderflow ();
testRounding ();
}
};
BEAST_DEFINE_TESTSUITE(STAmount,ripple_data,ripple);
} // ripple

View File

@@ -0,0 +1,150 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/Log.h>
namespace ripple {
std::unique_ptr<SerializedType>
STArray::deserialize (SerializerIterator& sit, SField::ref field)
{
std::unique_ptr <STArray> ret (std::make_unique <STArray> (field));
vector& value (ret->getValue ());
while (!sit.empty ())
{
int type, field;
sit.getFieldID (type, field);
if ((type == STI_ARRAY) && (field == 1))
break;
if ((type == STI_OBJECT) && (field == 1))
{
WriteLog (lsWARNING, STObject) <<
"Encountered array with end of object marker";
throw std::runtime_error ("Illegal terminator in array");
}
SField::ref fn = SField::getField (type, field);
if (fn.isInvalid ())
{
WriteLog (lsTRACE, STObject) <<
"Unknown field: " << type << "/" << field;
throw std::runtime_error ("Unknown field");
}
if (fn.fieldType != STI_OBJECT)
{
WriteLog (lsTRACE, STObject) << "Array contains non-object";
throw std::runtime_error ("Non-object in array");
}
value.push_back (new STObject (fn));
value.rbegin ()->set (sit, 1);
}
return std::move (ret);
}
std::string STArray::getFullText () const
{
std::string r = "[";
bool first = true;
for (STObject const& o : value)
{
if (!first)
r += ",";
r += o.getFullText ();
first = false;
}
r += "]";
return r;
}
std::string STArray::getText () const
{
std::string r = "[";
bool first = true;
for (STObject const& o : value)
{
if (!first)
r += ",";
r += o.getText ();
first = false;
}
r += "]";
return r;
}
Json::Value STArray::getJson (int p) const
{
Json::Value v = Json::arrayValue;
int index = 1;
for (auto const& object: value)
{
if (object.getSType () != STI_NOTPRESENT)
{
Json::Value inner = Json::objectValue;
auto const& fname = object.getFName ();
auto k = fname.hasName () ? fname.fieldName : std::to_string(index);
inner[k] = object.getJson (p);
v.append (inner);
index++;
}
}
return v;
}
void STArray::add (Serializer& s) const
{
for (STObject const& object : value)
{
object.addFieldID (s);
object.add (s);
s.addFieldID (STI_OBJECT, 1);
}
}
bool STArray::isEquivalent (const SerializedType& t) const
{
const STArray* v = dynamic_cast<const STArray*> (&t);
if (!v)
{
WriteLog (lsDEBUG, STObject) <<
"notEquiv " << getFullText() << " not array";
return false;
}
return value == v->value;
}
void STArray::sort (bool (*compare) (const STObject&, const STObject&))
{
value.sort (compare);
}
} // ripple

View File

@@ -0,0 +1,212 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_STARRAY_H
#define RIPPLE_STARRAY_H
#include <ripple/basics/CountedObject.h>
#include <ripple/data/protocol/STObject.h>
#include <boost/ptr_container/ptr_vector.hpp>
namespace ripple {
class STArray final
: public SerializedType
, public CountedObject <STArray>
{
public:
static char const* getCountedObjectName () { return "STArray"; }
typedef boost::ptr_vector<STObject> vector;
typedef vector::iterator iterator;
typedef vector::const_iterator const_iterator;
typedef vector::reverse_iterator reverse_iterator;
typedef vector::const_reverse_iterator const_reverse_iterator;
typedef vector::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)
{
;
}
virtual ~STArray () { }
static std::unique_ptr<SerializedType>
deserialize (SerializerIterator & sit, SField::ref 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 override;
virtual std::string getText () const override;
virtual Json::Value getJson (int index) const override;
virtual void add (Serializer & s) const override;
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 override
{
return STI_ARRAY;
}
virtual bool isEquivalent (const SerializedType & t) const override;
virtual bool isDefault () const override
{
return value.empty ();
}
private:
virtual STArray* duplicate () const override
{
return new STArray (*this);
}
private:
vector value;
};
} // ripple
#endif

View File

@@ -0,0 +1,137 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_STBITS_H
#define RIPPLE_STBITS_H
#include <ripple/data/protocol/SerializedType.h>
namespace ripple {
template <std::size_t Bits>
class STBitString : public SerializedType
{
public:
typedef base_uint<Bits> BitString;
STBitString () {}
STBitString (SField::ref n) : SerializedType (n) {}
STBitString (const BitString& v) : bitString_ (v) {}
STBitString (SField::ref n, const BitString& v)
: SerializedType (n), bitString_ (v)
{
}
STBitString (SField::ref n, const char* v) : SerializedType (n)
{
bitString_.SetHex (v);
}
STBitString (SField::ref n, std::string const& v) : SerializedType (n)
{
bitString_.SetHex (v);
}
static std::unique_ptr<SerializedType> deserialize (
SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
SerializedTypeID getSType () const;
std::string getText () const
{
return to_string (bitString_);
}
bool isEquivalent (const SerializedType& t) const
{
const STBitString* v = dynamic_cast<const STBitString*> (&t);
return v && (bitString_ == v->bitString_);
}
void add (Serializer& s) const
{
assert (fName->isBinary ());
assert (fName->fieldType == getSType());
s.addBitString<Bits> (bitString_);
}
const BitString& getValue () const
{
return bitString_;
}
template <typename Tag>
void setValue (base_uint<Bits, Tag> const& v)
{
bitString_.copyFrom(v);
}
operator BitString () const
{
return bitString_;
}
virtual bool isDefault () const
{
return bitString_ == zero;
}
private:
BitString bitString_;
STBitString* duplicate () const
{
return new STBitString (*this);
}
static STBitString* construct (SerializerIterator& u, SField::ref name)
{
return new STBitString (name, u.getBitString<Bits> ());
}
};
template <>
inline SerializedTypeID STBitString<128>::getSType () const
{
return STI_HASH128;
}
template <>
inline SerializedTypeID STBitString<160>::getSType () const
{
return STI_HASH160;
}
template <>
inline SerializedTypeID STBitString<256>::getSType () const
{
return STI_HASH256;
}
using STHash128 = STBitString<128>;
using STHash160 = STBitString<160>;
using STHash256 = STBitString<256>;
} // ripple
#endif

View File

@@ -0,0 +1,181 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/Log.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/data/protocol/STInteger.h>
namespace ripple {
template <>
SerializedTypeID STUInt8::getSType () const
{
return STI_UINT8;
}
template <>
STUInt8* STUInt8::construct (SerializerIterator& u, SField::ref name)
{
return new STUInt8 (name, u.get8 ());
}
template <>
std::string STUInt8::getText () const
{
if (getFName () == sfTransactionResult)
{
std::string token, human;
if (transResultInfo (static_cast<TER> (value_), token, human))
return human;
}
return beast::lexicalCastThrow <std::string> (value_);
}
template <>
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_;
}
//------------------------------------------------------------------------------
template <>
SerializedTypeID STUInt16::getSType () const
{
return STI_UINT16;
}
template <>
STUInt16* STUInt16::construct (SerializerIterator& u, SField::ref name)
{
return new STUInt16 (name, u.get16 ());
}
template <>
std::string STUInt16::getText () const
{
if (getFName () == sfLedgerEntryType)
{
auto 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 beast::lexicalCastThrow <std::string> (value_);
}
template <>
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_;
}
//------------------------------------------------------------------------------
template <>
SerializedTypeID STUInt32::getSType () const
{
return STI_UINT32;
}
template <>
STUInt32* STUInt32::construct (SerializerIterator& u, SField::ref name)
{
return new STUInt32 (name, u.get32 ());
}
template <>
std::string STUInt32::getText () const
{
return beast::lexicalCastThrow <std::string> (value_);
}
template <>
Json::Value STUInt32::getJson (int) const
{
return value_;
}
template <>
SerializedTypeID STUInt64::getSType () const
{
return STI_UINT64;
}
template <>
STUInt64* STUInt64::construct (SerializerIterator& u, SField::ref name)
{
return new STUInt64 (name, u.get64 ());
}
template <>
std::string STUInt64::getText () const
{
return beast::lexicalCastThrow <std::string> (value_);
}
template <>
Json::Value STUInt64::getJson (int) const
{
return strHex (value_);
}
} // ripple

View File

@@ -0,0 +1,101 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_STINTEGER_H
#define RIPPLE_STINTEGER_H
#include <ripple/data/protocol/SerializedType.h>
namespace ripple {
template <typename Integer>
class STInteger : public SerializedType
{
public:
explicit STInteger (Integer v) : value_ (v)
{
}
STInteger (SField::ref n, Integer v = 0) : SerializedType (n), value_ (v)
{
}
static std::unique_ptr<SerializedType> deserialize (
SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
SerializedTypeID getSType () const
{
return STI_UINT8;
}
Json::Value getJson (int) const;
std::string getText () const;
void add (Serializer& s) const
{
assert (fName->isBinary ());
assert (fName->fieldType == getSType ());
s.addInteger (value_);
}
Integer getValue () const
{
return value_;
}
void setValue (Integer v)
{
value_ = v;
}
operator Integer () const
{
return value_;
}
virtual bool isDefault () const
{
return value_ == 0;
}
bool isEquivalent (const SerializedType& t) const
{
const STInteger* v = dynamic_cast<const STInteger*> (&t);
return v && (value_ == v->value_);
}
private:
Integer value_;
STInteger* duplicate () const
{
return new STInteger (*this);
}
static STInteger* construct (SerializerIterator&, SField::ref f);
};
using STUInt8 = STInteger<unsigned char>;
using STUInt16 = STInteger<std::uint16_t>;
using STUInt32 = STInteger<std::uint32_t>;
using STUInt64 = STInteger<std::uint64_t>;
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,423 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_STOBJECT_H
#define RIPPLE_STOBJECT_H
#include <ripple/basics/CountedObject.h>
#include <boost/ptr_container/ptr_vector.hpp>
namespace ripple {
class STArray;
class STObject
: public SerializedType
, public CountedObject <STObject>
{
public:
static char const* getCountedObjectName () { return "STObject"; }
STObject () : mType (nullptr)
{
;
}
explicit STObject (SField::ref name)
: SerializedType (name), mType (nullptr)
{
;
}
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);
}
STObject (SField::ref name, boost::ptr_vector<SerializedType>& data)
: SerializedType (name), mType (nullptr)
{
mData.swap (data);
}
std::unique_ptr <STObject> oClone () const
{
return std::make_unique <STObject> (*this);
}
virtual ~STObject () { }
static std::unique_ptr<SerializedType>
deserialize (SerializerIterator & sit, SField::ref name);
bool setType (const SOTemplate & type);
bool isValidForType ();
bool isFieldAllowed (SField::ref);
bool isFree () const
{
return mType == nullptr;
}
void set (const SOTemplate&);
bool set (SerializerIterator & u, int depth = 0);
virtual SerializedTypeID getSType () const override
{
return STI_OBJECT;
}
virtual bool isEquivalent (const SerializedType & t) const override;
virtual bool isDefault () const override
{
return mData.empty ();
}
virtual void add (Serializer & s) const override
{
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;
}
virtual std::string getFullText () const override;
virtual std::string getText () const override;
// TODO(tom): options should be an enum.
virtual Json::Value getJson (int options) const override;
int addObject (const SerializedType & t)
{
mData.push_back (t.clone ().release ());
return mData.size () - 1;
}
int giveObject (std::unique_ptr<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 (std::uint32_t);
bool clearFlag (std::uint32_t);
bool isFlag(std::uint32_t) const;
std::uint32_t getFlags () const;
uint256 getHash (std::uint32_t prefix) const;
uint256 getSigningHash (std::uint32_t 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;
std::uint16_t getFieldU16 (SField::ref field) const;
std::uint32_t getFieldU32 (SField::ref field) const;
std::uint64_t 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;
Account getFieldAccount160 (SField::ref field) const;
Blob getFieldVL (SField::ref field) const;
STAmount const& getFieldAmount (SField::ref field) const;
STPathSet const& getFieldPathSet (SField::ref field) const;
const STVector256& getFieldV256 (SField::ref field) const;
const STArray& getFieldArray (SField::ref field) const;
void setFieldU8 (SField::ref field, unsigned char);
void setFieldU16 (SField::ref field, std::uint16_t);
void setFieldU32 (SField::ref field, std::uint32_t);
void setFieldU64 (SField::ref field, std::uint64_t);
void setFieldH128 (SField::ref field, uint128 const&);
void setFieldH256 (SField::ref field, uint256 const& );
void setFieldVL (SField::ref field, Blob const&);
void setFieldAccount (SField::ref field, Account const&);
void setFieldAccount (SField::ref field, RippleAddress const& addr)
{
setFieldAccount (field, addr.getAccountID ());
}
void setFieldAmount (SField::ref field, STAmount const&);
void setFieldPathSet (SField::ref field, STPathSet const&);
void setFieldV256 (SField::ref field, STVector256 const& v);
void setFieldArray (SField::ref field, STArray const& v);
template <class Tag>
void setFieldH160 (SField::ref field, base_uint<160, Tag> const& v)
{
SerializedType* rf = getPField (field, true);
if (!rf)
throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT)
rf = makeFieldPresent (field);
using Bits = STBitString<160>;
if (auto cf = dynamic_cast<Bits*> (rf))
cf->setValue (v);
else
throw std::runtime_error ("Wrong field type");
}
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 std::unique_ptr <SerializedType>
makeDefaultObject (SerializedTypeID id, SField::ref name);
// VFALCO TODO remove the 'depth' parameter
static std::unique_ptr<SerializedType> makeDeserializedObject (
SerializedTypeID id,
SField::ref name,
SerializerIterator&,
int depth);
static std::unique_ptr<SerializedType>
makeNonPresentObject (SField::ref name)
{
return makeDefaultObject (STI_NOTPRESENT, name);
}
static std::unique_ptr<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:
virtual STObject* duplicate () const override
{
return new STObject (*this);
}
// Implementation for getting (most) fields that return by value.
//
// The remove_cv and remove_reference are necessitated by the STBitString
// types. Their getValue returns by const ref. We return those types
// by value.
template <typename T, typename V =
typename std::remove_cv < typename std::remove_reference <
decltype (std::declval <T> ().getValue ())>::type >::type >
V getFieldByValue (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf)
throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT)
return V (); // optional field not present
const T* cf = dynamic_cast<const T*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
// Implementations for getting (most) fields that return by const reference.
//
// If an absent optional field is deserialized we don't have anything
// obvious to return. So we insist on having the call provide an
// 'empty' value we return in that circumstance.
template <typename T, typename V>
V const& getFieldByConstRef (SField::ref field, V const& empty) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf)
throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT)
return empty; // optional field not present
const T* cf = dynamic_cast<const T*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
return *cf;
}
// Implementation for setting most fields with a setValue() method.
template <typename T, typename V>
void setFieldUsingSetValue (SField::ref field, V value)
{
SerializedType* rf = getPField (field, true);
if (!rf)
throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT)
rf = makeFieldPresent (field);
T* cf = dynamic_cast<T*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
cf->setValue (value);
}
// Implementation for setting fields using assignment
template <typename T>
void setFieldUsingAssignment (SField::ref field, T const& value)
{
SerializedType* rf = getPField (field, true);
if (!rf)
throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT)
rf = makeFieldPresent (field);
T* cf = dynamic_cast<T*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
(*cf) = value;
}
private:
boost::ptr_vector<SerializedType> mData;
const SOTemplate* mType;
};
} // ripple
#endif

View File

@@ -0,0 +1,744 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/StringUtilities.h>
#include <ripple/data/protocol/STInteger.h>
#include <beast/module/core/text/LexicalCast.h>
#include <cassert>
namespace ripple {
template <typename T, typename U>
static T range_check_cast (U value, T minimum, T maximum)
{
if ((value < minimum) || (value > maximum))
throw std::runtime_error ("Value out of range");
return static_cast<T> (value);
}
//------------------------------------------------------------------------------
STParsedJSON::STParsedJSON (std::string const& name, Json::Value const& json)
{
parse (name, json, sfGeneric, 0, object);
}
//------------------------------------------------------------------------------
std::string STParsedJSON::make_name (std::string const& object,
std::string const& field)
{
if (field.empty ())
return object;
return object + "." + field;
}
Json::Value STParsedJSON::not_an_object (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' is not a JSON object.");
}
Json::Value STParsedJSON::unknown_field (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' is unknown.");
}
Json::Value STParsedJSON::out_of_range (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' is out of range.");
}
Json::Value STParsedJSON::bad_type (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' has bad type.");
}
Json::Value STParsedJSON::invalid_data (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' has invalid data.");
}
Json::Value STParsedJSON::array_expected (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' must be a JSON array.");
}
Json::Value STParsedJSON::string_expected (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' must be a string.");
}
Json::Value STParsedJSON::too_deep (std::string const& object,
std::string const& field)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + make_name (object, field) + "' exceeds nesting depth limit.");
}
Json::Value STParsedJSON::singleton_expected (std::string const& object)
{
return RPC::make_error (rpcINVALID_PARAMS,
"Field '" + object +
"' must be an object with a single key/object value.");
}
//------------------------------------------------------------------------------
bool STParsedJSON::parse (std::string const& json_name,
Json::Value const& json, SField::ref inName, int depth,
std::unique_ptr <STObject>& sub_object)
{
if (! json.isObject ())
{
error = not_an_object (json_name);
return false;
}
SField::ptr name (&inName);
boost::ptr_vector<SerializedType> data;
Json::Value::Members members (json.getMemberNames ());
for (Json::Value::Members::iterator it (members.begin ());
it != members.end (); ++it)
{
std::string const& fieldName = *it;
Json::Value const& value = json [fieldName];
SField::ref field = SField::getField (fieldName);
if (field == sfInvalid)
{
error = unknown_field (json_name, fieldName);
return false;
}
switch (field.fieldType)
{
case STI_UINT8:
try
{
if (value.isString ())
{
// VFALCO TODO wtf?
}
else if (value.isInt ())
{
if (value.asInt () < 0 || value.asInt () > 255)
{
error = out_of_range (json_name, fieldName);
return false;
}
data.push_back (new STUInt8 (field,
range_check_cast <unsigned char> (
value.asInt (), 0, 255)));
}
else if (value.isUInt ())
{
if (value.asUInt () > 255)
{
error = out_of_range (json_name, fieldName);
return false;
}
data.push_back (new STUInt8 (field,
range_check_cast <unsigned char> (
value.asUInt (), 0, 255)));
}
else
{
error = bad_type (json_name, fieldName);
return false;
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_UINT16:
try
{
if (value.isString ())
{
std::string strValue = value.asString ();
if (! strValue.empty () &&
((strValue[0] < '0') || (strValue[0] > '9')))
{
if (field == sfTransactionType)
{
TxType const txType (TxFormats::getInstance()->
findTypeByName (strValue));
data.push_back (new STUInt16 (field,
static_cast <std::uint16_t> (txType)));
if (*name == sfGeneric)
name = &sfTransaction;
}
else if (field == sfLedgerEntryType)
{
LedgerEntryType const type (LedgerFormats::getInstance()->
findTypeByName (strValue));
data.push_back (new STUInt16 (field,
static_cast <std::uint16_t> (type)));
if (*name == sfGeneric)
name = &sfLedgerEntry;
}
else
{
error = invalid_data (json_name, fieldName);
return false;
}
}
else
{
data.push_back (new STUInt16 (field,
beast::lexicalCastThrow <std::uint16_t> (strValue)));
}
}
else if (value.isInt ())
{
data.push_back (new STUInt16 (field,
range_check_cast <std::uint16_t> (
value.asInt (), 0, 65535)));
}
else if (value.isUInt ())
{
data.push_back (new STUInt16 (field,
range_check_cast <std::uint16_t> (
value.asUInt (), 0, 65535)));
}
else
{
error = bad_type (json_name, fieldName);
return false;
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_UINT32:
try
{
if (value.isString ())
{
data.push_back (new STUInt32 (field,
beast::lexicalCastThrow <std::uint32_t> (value.asString ())));
}
else if (value.isInt ())
{
data.push_back (new STUInt32 (field,
range_check_cast <std::uint32_t> (value.asInt (), 0u, 4294967295u)));
}
else if (value.isUInt ())
{
data.push_back (new STUInt32 (field,
static_cast <std::uint32_t> (value.asUInt ())));
}
else
{
error = bad_type (json_name, fieldName);
return false;
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_UINT64:
try
{
if (value.isString ())
{
data.push_back (new STUInt64 (field,
uintFromHex (value.asString ())));
}
else if (value.isInt ())
{
data.push_back (new STUInt64 (field,
range_check_cast<std::uint64_t> (
value.asInt (), 0, 18446744073709551615ull)));
}
else if (value.isUInt ())
{
data.push_back (new STUInt64 (field,
static_cast <std::uint64_t> (value.asUInt ())));
}
else
{
error = bad_type (json_name, fieldName);
return false;
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_HASH128:
try
{
if (value.isString ())
{
data.push_back (new STHash128 (field, value.asString ()));
}
else
{
error = bad_type (json_name, fieldName);
return false;
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_HASH160:
try
{
if (value.isString ())
{
data.push_back (new STHash160 (field, value.asString ()));
}
else
{
error = bad_type (json_name, fieldName);
return false;
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_HASH256:
try
{
if (value.isString ())
{
data.push_back (new STHash256 (field, value.asString ()));
}
else
{
error = bad_type (json_name, fieldName);
return false;
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_VL:
if (! value.isString ())
{
error = bad_type (json_name, fieldName);
return false;
}
try
{
std::pair<Blob, bool> ret(strUnHex (value.asString ()));
if (!ret.second)
throw std::invalid_argument ("invalid data");
data.push_back (new STVariableLength (field, ret.first));
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_AMOUNT:
try
{
data.push_back (new STAmount (amountFromJson (field, value)));
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_VECTOR256:
if (! value.isArray ())
{
error = array_expected (json_name, fieldName);
return false;
}
try
{
data.push_back (new STVector256 (field));
STVector256* tail (dynamic_cast <STVector256*> (&data.back ()));
assert (tail);
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
{
uint256 s;
s.SetHex (value[i].asString ());
tail->addValue (s);
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_PATHSET:
if (!value.isArray ())
{
error = array_expected (json_name, fieldName);
return false;
}
try
{
data.push_back (new STPathSet (field));
STPathSet* tail = dynamic_cast <STPathSet*> (&data.back ());
assert (tail);
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
{
STPath p;
if (!value[i].isArray ())
{
std::stringstream ss;
ss << fieldName << "[" << i << "]";
error = array_expected (json_name, ss.str ());
return false;
}
for (Json::UInt j = 0; value[i].isValidIndex (j); ++j)
{
std::stringstream ss;
ss << fieldName << "[" << i << "][" << j << "]";
std::string const element_name (
json_name + "." + ss.str());
// each element in this path has some combination of account,
// currency, or issuer
Json::Value pathEl = value[i][j];
if (!pathEl.isObject ())
{
error = not_an_object (element_name);
return false;
}
Json::Value const& account = pathEl["account"];
Json::Value const& currency = pathEl["currency"];
Json::Value const& issuer = pathEl["issuer"];
bool hasCurrency = false;
Account uAccount, uIssuer;
Currency uCurrency;
if (! account.isNull ())
{
// human account id
if (! account.isString ())
{
error = string_expected (element_name, "account");
return false;
}
std::string const strValue (account.asString ());
if (value.size () == 40) // 160-bit hex account value
uAccount.SetHex (strValue);
{
RippleAddress a;
if (! a.setAccountID (strValue))
{
error = invalid_data (element_name, "account");
return false;
}
uAccount = a.getAccountID ();
}
}
if (!currency.isNull ())
{
// human currency
if (!currency.isString ())
{
error = string_expected (element_name, "currency");
return false;
}
hasCurrency = true;
if (currency.asString ().size () == 40)
{
uCurrency.SetHex (currency.asString ());
}
else if (!to_currency (uCurrency, currency.asString ()))
{
error = invalid_data (element_name, "currency");
return false;
}
}
if (!issuer.isNull ())
{
// human account id
if (!issuer.isString ())
{
error = string_expected (element_name, "issuer");
return false;
}
if (issuer.asString ().size () == 40)
{
uIssuer.SetHex (issuer.asString ());
}
else
{
RippleAddress a;
if (!a.setAccountID (issuer.asString ()))
{
error = invalid_data (element_name, "issuer");
return false;
}
uIssuer = a.getAccountID ();
}
}
p.addElement (STPathElement (uAccount, uCurrency, uIssuer, hasCurrency));
}
tail->addPath (p);
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_ACCOUNT:
{
if (! value.isString ())
{
error = bad_type (json_name, fieldName);
return false;
}
std::string strValue = value.asString ();
try
{
if (value.size () == 40) // 160-bit hex account value
{
Account account;
account.SetHex (strValue);
data.push_back (new STAccount (field, account));
}
else
{
// ripple address
RippleAddress a;
if (!a.setAccountID (strValue))
{
error = invalid_data (json_name, fieldName);
return false;
}
data.push_back (new STAccount (field, a.getAccountID ()));
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
}
break;
case STI_OBJECT:
case STI_TRANSACTION:
case STI_LEDGERENTRY:
case STI_VALIDATION:
if (! value.isObject ())
{
error = not_an_object (json_name, fieldName);
return false;
}
if (depth > 64)
{
error = too_deep (json_name, fieldName);
return false;
}
try
{
std::unique_ptr <STObject> sub_object_;
bool const success (parse (json_name + "." + fieldName,
value, field, depth + 1, sub_object_));
if (! success)
return false;
data.push_back (sub_object_.release ());
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
case STI_ARRAY:
if (! value.isArray ())
{
error = array_expected (json_name, fieldName);
return false;
}
try
{
data.push_back (new STArray (field));
STArray* tail = dynamic_cast<STArray*> (&data.back ());
assert (tail);
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
{
bool const isObject (value[i].isObject());
bool const singleKey (isObject
? value [i].size() == 1
: true);
if (!isObject || !singleKey)
{
std::stringstream ss;
ss << json_name << "." << fieldName << "[" << i << "]";
error = singleton_expected (ss.str ());
return false;
}
// TODO: There doesn't seem to be a nice way to get just the
// first/only key in an object without copying all keys into
// a vector
std::string const objectName (value[i].getMemberNames()[0]);;
SField::ref nameField (SField::getField(objectName));
if (nameField == sfInvalid)
{
error = unknown_field (json_name, objectName);
return false;
}
Json::Value const objectFields (value[i][objectName]);
std::unique_ptr <STObject> sub_object_;
{
std::stringstream ss;
ss << json_name << "." << fieldName <<
"[" << i << "]." << objectName;
bool const success (parse (ss.str (), objectFields,
nameField, depth + 1, sub_object_));
if (! success || (sub_object_->getFName().fieldType != STI_OBJECT))
return false;
}
tail->push_back (*sub_object_);
}
}
catch (...)
{
error = invalid_data (json_name, fieldName);
return false;
}
break;
default:
error = bad_type (json_name, fieldName);
return false;
}
}
sub_object.reset (new STObject (*name, data));
return true;
}
} // ripple

View File

@@ -0,0 +1,84 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_DATA_STPARSEDJSON_H
#define RIPPLE_DATA_STPARSEDJSON_H
namespace ripple {
/** Holds the serialized result of parsing input JSON.
This does validation and checking on the provided JSON.
*/
class STParsedJSON
{
public:
/** Parses and creates an STParsedJSON object.
The result of the parsing is stored in object and error.
Exceptions:
Does not throw.
@param name The name of the JSON field, used in diagnostics.
@param json The JSON-RPC to parse.
*/
STParsedJSON (std::string const& name,
Json::Value const& json);
/** The STObject if the parse was successful. */
std::unique_ptr <STObject> object;
/** On failure, an appropriate set of error values. */
Json::Value error;
private:
static std::string make_name (std::string const& object,
std::string const& field);
static Json::Value not_an_object (std::string const& object,
std::string const& field = std::string());
static Json::Value unknown_field (std::string const& object,
std::string const& field = std::string());
static Json::Value out_of_range (std::string const& object,
std::string const& field = std::string());
static Json::Value bad_type (std::string const& object,
std::string const& field = std::string());
static Json::Value invalid_data (std::string const& object,
std::string const& field = std::string());
static Json::Value array_expected (std::string const& object,
std::string const& field = std::string());
static Json::Value string_expected (std::string const& object,
std::string const& field = std::string());
static Json::Value too_deep (std::string const& object,
std::string const& field = std::string());
static Json::Value singleton_expected (
std::string const& object);
bool parse (std::string const& json_name, Json::Value const& json,
SField::ref inName, int depth, std::unique_ptr <STObject>& sub_object);
};
} // ripple
#endif

View File

@@ -0,0 +1,64 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
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 (value_type (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 ()];
}
} // ripple

View File

@@ -0,0 +1,94 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZEDOBJECTTEMPLATE_H
#define RIPPLE_SERIALIZEDOBJECTTEMPLATE_H
namespace ripple {
/** 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 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:
typedef std::unique_ptr <SOElement const> value_type;
typedef std::vector <value_type> list_type;
/** 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?
//
list_type 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:
list_type mTypes;
std::vector <int> mIndex; // field num -> index
};
} // ripple
#endif

View File

@@ -0,0 +1,236 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZEDTYPE_H
#define RIPPLE_SERIALIZEDTYPE_H
#include <ripple/data/protocol/SField.h>
#include <ripple/data/protocol/Serializer.h>
namespace ripple {
// VFALCO TODO fix this restriction on copy assignment.
//
// CAUTION: Do not create a vector (or similar container) of any object derived
// from SerializedType. Use Boost ptr_* containers. The copy assignment operator
// of SerializedType has semantics that will cause contained types to change
// their names when an object is deleted because copy assignment is used to
// "slide down" the remaining types and this will not copy the field
// name. Changing the copy assignment operator to copy the field name breaks the
// use of copy assignment just to copy values, which is used in the transaction
// engine code.
// VFALCO TODO Remove this unused enum
/*
enum PathFlags
{
PF_END = 0x00, // End of current path & path list.
PF_BOUNDARY = 0xFF, // End of current path & new path follows.
PF_ACCOUNT = 0x01,
PF_OFFER = 0x02,
PF_WANTED_CURRENCY = 0x10,
PF_WANTED_ISSUER = 0x20,
PF_REDEEM = 0x40,
PF_ISSUE = 0x80,
};
*/
//------------------------------------------------------------------------------
/** A type which can be exported to a well known binary format.
A SerializedType:
- Always a field
- Can always go inside an eligible enclosing SerializedType
(such as STArray)
- Has a field name
Like JSON, a SerializedObject is a basket which has rules
on what it can hold.
*/
// VFALCO TODO Document this as it looks like a central class.
// STObject is derived from it
//
class SerializedType
{
public:
SerializedType () : fName (&sfGeneric)
{
;
}
explicit SerializedType (SField::ref n) : fName (&n)
{
assert (fName);
}
virtual ~SerializedType () = default;
//
// overridables
//
virtual
SerializedTypeID
getSType () const
{
return STI_NOTPRESENT;
}
virtual
std::string
getFullText() const;
// just the value
virtual
std::string
getText() const
{
return std::string();
}
virtual
Json::Value getJson (int /*options*/) const
{
return getText();
}
virtual
void
add (Serializer& s) const
{
// VFALCO Why not just make this pure virtual?
assert (false);
}
virtual
bool
isEquivalent (SerializedType const& t) const;
virtual
bool
isDefault () const
{
return true;
}
private:
// VFALCO TODO Return std::unique_ptr <SerializedType>
virtual
SerializedType*
duplicate () const
{
return new SerializedType (*fName);
}
public:
//
// members
//
static
std::unique_ptr <SerializedType>
deserialize (SField::ref name)
{
return std::unique_ptr<SerializedType> (new SerializedType (name));
}
/** A SerializedType is a field.
This sets the name.
*/
void setFName (SField::ref n)
{
fName = &n;
assert (fName);
}
SField::ref getFName () const
{
return *fName;
}
std::unique_ptr<SerializedType> clone () const
{
return std::unique_ptr<SerializedType> (duplicate ());
}
void addFieldID (Serializer& s) const
{
assert (fName->isBinary ());
s.addFieldID (fName->fieldType, fName->fieldValue);
}
SerializedType& operator= (const SerializedType& t);
bool operator== (const SerializedType& t) const
{
return (getSType () == t.getSType ()) && isEquivalent (t);
}
bool operator!= (const SerializedType& t) const
{
return (getSType () != t.getSType ()) || !isEquivalent (t);
}
template <class D>
D& downcast()
{
D* ptr = dynamic_cast<D*> (this);
if (ptr == nullptr)
throw std::runtime_error ("type mismatch");
return *ptr;
}
template <class D>
D const& downcast() const
{
D const * ptr = dynamic_cast<D const*> (this);
if (ptr == nullptr)
throw std::runtime_error ("type mismatch");
return *ptr;
}
protected:
// VFALCO TODO make accessors for this
SField::ptr fName;
};
//------------------------------------------------------------------------------
inline SerializedType* new_clone (const SerializedType& s)
{
SerializedType* const copy (s.clone ().release ());
assert (typeid (*copy) == typeid (s));
return copy;
}
inline void delete_clone (const SerializedType* s)
{
boost::checked_delete (s);
}
inline std::ostream& operator<< (std::ostream& out, const SerializedType& t)
{
return out << t.getFullText ();
}
} // ripple
#endif

View File

@@ -0,0 +1,403 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/Log.h>
#include <ripple/basics/StringUtilities.h>
namespace ripple {
const STAmount saZero (noIssue(), 0u);
const STAmount saOne (noIssue(), 1u);
SerializedType& SerializedType::operator= (const SerializedType& t)
{
if ((t.fName != fName) && fName->isUseful () && t.fName->isUseful ())
{
WriteLog ((t.getSType () == STI_AMOUNT) ? lsTRACE : 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;
}
std::string SerializedType::getFullText () const
{
std::string ret;
if (getSType () != STI_NOTPRESENT)
{
if (fName->hasName ())
{
ret = fName->fieldName;
ret += " = ";
}
ret += getText ();
}
return ret;
}
//
// STVariableLength
//
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
{
Account 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 ();
std::unique_ptr<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
{
assert (fName->isBinary ());
assert (fName->fieldType == STI_VECTOR256);
s.addVL (mValue.empty () ? nullptr : 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, Account const& v) : STVariableLength (n)
{
peekValue ().insert (peekValue ().end (), v.begin (), v.end ());
}
bool STAccount::isValueH160 () const
{
return peekValue ().size () == (160 / 8);
}
RippleAddress STAccount::getValueNCA () const
{
RippleAddress a;
Account account;
if (getValueH160 (account))
a.setAccountID (account);
return a;
}
void STAccount::setValueNCA (RippleAddress const& nca)
{
setValueH160 (nca.getAccountID ());
}
std::size_t
STPathElement::get_hash (STPathElement const& element)
{
std::size_t hash_account = 2654435761;
std::size_t hash_currency = 2654435761;
std::size_t hash_issuer = 2654435761;
// NIKB NOTE: This doesn't have to be a secure hash as speed is more
// important. We don't even really need to fully hash the whole
// base_uint here, as a few bytes would do for our use.
for (auto const x : element.getAccountID ())
hash_account += (hash_account * 257) ^ x;
for (auto const x : element.getCurrency ())
hash_currency += (hash_currency * 509) ^ x;
for (auto const x : element.getIssuerID ())
hash_issuer += (hash_issuer * 911) ^ x;
return (hash_account ^ hash_currency ^ hash_issuer);
}
STPathSet* STPathSet::construct (SerializerIterator& s, SField::ref name)
{
std::vector<STPath> paths;
std::vector<STPathElement> path;
do
{
int iType = s.get8 ();
if (iType == STPathElement::typeNone ||
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::typeNone)
{
return new STPathSet (name, paths);
}
}
else if (iType & ~STPathElement::typeAll)
{
WriteLog (lsINFO, SerializedType)
<< "STPathSet: Bad path element: " << iType;
throw std::runtime_error ("bad path element");
}
else
{
auto hasAccount = iType & STPathElement::typeAccount;
auto hasCurrency = iType & STPathElement::typeCurrency;
auto hasIssuer = iType & STPathElement::typeIssuer;
Account account;
Currency currency;
Account issuer;
if (hasAccount)
account.copyFrom (s.get160 ());
if (hasCurrency)
currency.copyFrom (s.get160 ());
if (hasIssuer)
issuer.copyFrom (s.get160 ());
path.emplace_back (account, currency, issuer, hasCurrency);
}
}
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 (
Account const& account, Currency const& currency,
Account const& issuer) const
{
for (auto& p: mPath)
{
if (p.getAccountID () == account
&& p.getCurrency () == currency
&& p.getIssuerID () == issuer)
return true;
}
return false;
}
Json::Value STPath::getJson (int) const
{
Json::Value ret (Json::arrayValue);
for (auto it: mPath)
{
Json::Value elem (Json::objectValue);
int iType = it.getNodeType ();
elem[jss::type] = iType;
elem[jss::type_hex] = strHex (iType);
if (iType & STPathElement::typeAccount)
elem[jss::account] = to_string (it.getAccountID ());
if (iType & STPathElement::typeCurrency)
elem[jss::currency] = to_string (it.getCurrency ());
if (iType & STPathElement::typeIssuer)
elem[jss::issuer] = to_string (it.getIssuerID ());
ret.append (elem);
}
return ret;
}
Json::Value STPathSet::getJson (int options) const
{
Json::Value ret (Json::arrayValue);
for (auto 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 += to_string (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
void STPathSet::add (Serializer& s) const
{
assert (fName->isBinary ());
assert (fName->fieldType == STI_PATHSET);
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::typeNone);
}
} // ripple

View File

@@ -0,0 +1,614 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZEDTYPES_H
#define RIPPLE_SERIALIZEDTYPES_H
#include <ripple/data/protocol/SField.h>
#include <ripple/data/protocol/Serializer.h>
#include <ripple/data/protocol/STBitString.h>
#include <ripple/data/protocol/STInteger.h>
#include <ripple/data/protocol/SerializedType.h>
#include <ripple/data/protocol/STAmount.h>
namespace ripple {
//------------------------------------------------------------------------------
// variable length byte string
class STVariableLength : public SerializedType
{
public:
STVariableLength (Blob const& v) : value (v)
{
;
}
STVariableLength (SField::ref n, Blob const& v) : SerializedType (n), value (v)
{
;
}
STVariableLength (SField::ref n) : SerializedType (n)
{
;
}
STVariableLength (SerializerIterator&, SField::ref name = sfGeneric);
STVariableLength ()
{
;
}
static std::unique_ptr<SerializedType> deserialize (SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
virtual SerializedTypeID getSType () const
{
return STI_VL;
}
virtual std::string getText () const;
void add (Serializer& s) const
{
assert (fName->isBinary ());
assert ((fName->fieldType == STI_VL) ||
(fName->fieldType == STI_ACCOUNT));
s.addVL (value);
}
Blob const& peekValue () const
{
return value;
}
Blob& peekValue ()
{
return value;
}
Blob getValue () const
{
return value;
}
void setValue (Blob const& v)
{
value = v;
}
operator Blob () const
{
return value;
}
virtual bool isEquivalent (const SerializedType& t) const;
virtual bool isDefault () const
{
return value.empty ();
}
private:
Blob value;
virtual STVariableLength* duplicate () const
{
return new STVariableLength (*this);
}
static STVariableLength* construct (SerializerIterator&, SField::ref);
};
//------------------------------------------------------------------------------
class STAccount : public STVariableLength
{
public:
STAccount (Blob const& v) : STVariableLength (v)
{
;
}
STAccount (SField::ref n, Blob const& v) : STVariableLength (n, v)
{
;
}
STAccount (SField::ref n, Account const& v);
STAccount (SField::ref n) : STVariableLength (n)
{
;
}
STAccount ()
{
;
}
static std::unique_ptr<SerializedType> deserialize (SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
SerializedTypeID getSType () const
{
return STI_ACCOUNT;
}
std::string getText () const;
RippleAddress getValueNCA () const;
void setValueNCA (RippleAddress const& nca);
template <typename Tag>
void setValueH160 (base_uint<160, Tag> const& v)
{
peekValue ().clear ();
peekValue ().insert (peekValue ().end (), v.begin (), v.end ());
assert (peekValue ().size () == (160 / 8));
}
template <typename Tag>
bool getValueH160 (base_uint<160, Tag>& v) const
{
auto success = isValueH160 ();
if (success)
memcpy (v.begin (), & (peekValue ().front ()), (160 / 8));
return success;
}
bool isValueH160 () const;
private:
virtual STAccount* duplicate () const
{
return new STAccount (*this);
}
static STAccount* construct (SerializerIterator&, SField::ref);
};
//------------------------------------------------------------------------------
class STPathElement
{
private:
// VFALCO Remove these friend declarations
friend class STPathSet;
friend class STPath;
friend class Pathfinder;
public:
enum Type
{
typeNone = 0x00,
typeAccount = 0x01, // Rippling through an account (vs taking an offer).
typeCurrency = 0x10, // Currency follows.
typeIssuer = 0x20, // Issuer follows.
typeBoundary = 0xFF, // Boundary between alternate paths.
typeAll = typeAccount | typeCurrency | typeIssuer,
// Combination of all types.
};
private:
static
std::size_t
get_hash (STPathElement const& element);
public:
STPathElement (
Account const& account, Currency const& currency,
Account const& issuer, bool forceCurrency = false)
: mType (typeNone), mAccountID (account), mCurrencyID (currency)
, mIssuerID (issuer), is_offer_ (isXRP(mAccountID))
{
if (!is_offer_)
mType |= typeAccount;
if (forceCurrency || !isXRP(currency))
mType |= typeCurrency;
if (!isXRP(issuer))
mType |= typeIssuer;
hash_value_ = get_hash (*this);
}
STPathElement (
unsigned int uType, Account const& account, Currency const& currency,
Account const& issuer)
: mType (uType), mAccountID (account), mCurrencyID (currency)
, mIssuerID (issuer), is_offer_ (isXRP(mAccountID))
{
hash_value_ = get_hash (*this);
}
STPathElement ()
: mType (typeNone), is_offer_ (true)
{
hash_value_ = get_hash (*this);
}
int getNodeType () const
{
return mType;
}
bool isOffer () const
{
return is_offer_;
}
bool isAccount () const
{
return !isOffer ();
}
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a
// class of offers.
Account const& getAccountID () const
{
return mAccountID;
}
Currency const& getCurrency () const
{
return mCurrencyID;
}
Account const& getIssuerID () const
{
return mIssuerID;
}
bool operator== (const STPathElement& t) const
{
return (mType & typeAccount) == (t.mType & typeAccount) &&
hash_value_ == t.hash_value_ &&
mAccountID == t.mAccountID &&
mCurrencyID == t.mCurrencyID &&
mIssuerID == t.mIssuerID;
}
private:
unsigned int mType;
Account mAccountID;
Currency mCurrencyID;
Account mIssuerID;
bool is_offer_;
std::size_t hash_value_;
};
//------------------------------------------------------------------------------
class STPath
{
public:
STPath ()
{
;
}
STPath (const std::vector<STPathElement>& p) : mPath (p)
{
;
}
int size () const
{
return mPath.size ();
}
void reserve (size_t n)
{
mPath.reserve(n);
}
bool isEmpty () const
{
return mPath.empty ();
}
bool empty() const
{
return mPath.empty ();
}
const STPathElement& getElement (int offset) const
{
return mPath[offset];
}
const STPathElement& getElement (int offset)
{
return mPath[offset];
}
void addElement (const STPathElement& e)
{
mPath.push_back (e);
}
void clear ()
{
mPath.clear ();
}
bool hasSeen (Account const& account, Currency const& currency,
Account const& issuer) const;
Json::Value getJson (int) const;
std::vector<STPathElement>::iterator begin ()
{
return mPath.begin ();
}
std::vector<STPathElement>::iterator end ()
{
return mPath.end ();
}
std::vector<STPathElement>::const_iterator begin () const
{
return mPath.begin ();
}
std::vector<STPathElement>::const_iterator end () const
{
return mPath.end ();
}
bool operator== (STPath const& t) const
{
return mPath == t.mPath;
}
void setCanonical (STPath const& spExpanded);
private:
friend class STPathSet;
friend class Pathfinder;
std::vector<STPathElement> mPath;
};
//------------------------------------------------------------------------------
// A set of zero or more payment paths
class STPathSet : public SerializedType
{
public:
STPathSet ()
{
;
}
explicit STPathSet (SField::ref n) : SerializedType (n)
{
;
}
explicit STPathSet (const std::vector<STPath>& v) : value (v)
{
;
}
STPathSet (SField::ref n, const std::vector<STPath>& v) : SerializedType (n), value (v)
{
;
}
static std::unique_ptr<SerializedType> deserialize (SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
// std::string getText() const;
void add (Serializer& s) const;
virtual Json::Value getJson (int) const;
SerializedTypeID getSType () const
{
return STI_PATHSET;
}
int size () const
{
return value.size ();
}
void reserve (size_t n)
{
value.reserve(n);
}
STPath const& getPath (int off) const
{
return value[off];
}
STPath& peekPath (int off)
{
return value[off];
}
bool isEmpty () const
{
return value.empty ();
}
void clear ()
{
value.clear ();
}
void addPath (STPath const& e)
{
value.push_back (e);
}
void addUniquePath (STPath const& e)
{
for (auto const& p: value)
{
if (p == e)
return;
}
value.push_back (e);
}
bool assembleAdd(STPath const& base, STPathElement const& tail)
{ // assemble base+tail and add it to the set if it's not a duplicate
value.push_back (base);
std::vector<STPath>::reverse_iterator it = value.rbegin ();
STPath& newPath = *it;
newPath.mPath.push_back (tail);
while (++it != value.rend ())
{
if (it->mPath == newPath.mPath)
{
value.pop_back ();
return false;
}
}
return true;
}
virtual bool isEquivalent (const SerializedType& t) const;
virtual bool isDefault () const
{
return value.empty ();
}
STPath& operator[](size_t n)
{
return value[n];
}
STPath const& operator[](size_t n) const
{
return value[n];
}
std::vector<STPath>::iterator begin ()
{
return value.begin ();
}
std::vector<STPath>::iterator end ()
{
return value.end ();
}
std::vector<STPath>::const_iterator begin () const
{
return value.begin ();
}
std::vector<STPath>::const_iterator end () const
{
return value.end ();
}
private:
std::vector<STPath> value;
STPathSet* duplicate () const
{
return new STPathSet (*this);
}
static STPathSet* construct (SerializerIterator&, SField::ref);
};
//------------------------------------------------------------------------------
class STVector256 : public SerializedType
{
public:
STVector256 ()
{
;
}
STVector256 (SField::ref n) : SerializedType (n)
{
;
}
STVector256 (SField::ref n, const std::vector<uint256>& v) : SerializedType (n), mValue (v)
{
;
}
STVector256 (const std::vector<uint256>& vector) : mValue (vector)
{
;
}
SerializedTypeID getSType () const
{
return STI_VECTOR256;
}
void add (Serializer& s) const;
static std::unique_ptr<SerializedType> deserialize (SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
const std::vector<uint256>& peekValue () const
{
return mValue;
}
std::vector<uint256>& peekValue ()
{
return mValue;
}
virtual bool isEquivalent (const SerializedType& t) const;
virtual bool isDefault () const
{
return mValue.empty ();
}
std::vector<uint256> getValue () const
{
return mValue;
}
int size () const
{
return mValue.size ();
}
bool isEmpty () const
{
return mValue.empty ();
}
uint256 const& at (int i) const
{
assert ((i >= 0) && (i < size ()));
return mValue.at (i);
}
uint256& at (int i)
{
assert ((i >= 0) && (i < size ()));
return mValue.at (i);
}
void setValue (const STVector256& v)
{
mValue = v.mValue;
}
void setValue (const std::vector<uint256>& v)
{
mValue = v;
}
void addValue (uint256 const& v)
{
mValue.push_back (v);
}
bool hasValue (uint256 const& v) const;
void sort ()
{
std::sort (mValue.begin (), mValue.end ());
}
Json::Value getJson (int) const;
std::vector<uint256>::const_iterator begin() const
{
return mValue.begin ();
}
std::vector<uint256>::const_iterator end() const
{
return mValue.end ();
}
private:
std::vector<uint256> mValue;
STVector256* duplicate () const
{
return new STVector256 (*this);
}
static STVector256* construct (SerializerIterator&, SField::ref);
};
} // ripple
#endif

View File

@@ -0,0 +1,669 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/Log.h>
#include <beast/unit_test/suite.h>
namespace ripple {
int Serializer::addZeros (size_t uBytes)
{
int ret = mData.size ();
while (uBytes--)
mData.push_back (0);
return ret;
}
int Serializer::add16 (std::uint16_t 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 (std::uint32_t 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 (std::uint64_t 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;
}
template <> int Serializer::addInteger(unsigned char i) { return add8(i); }
template <> int Serializer::addInteger(std::uint16_t i) { return add16(i); }
template <> int Serializer::addInteger(std::uint32_t i) { return add32(i); }
template <> int Serializer::addInteger(std::uint64_t i) { return add64(i); }
int Serializer::add128 (const uint128& 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 (std::uint16_t& 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 (std::uint32_t& 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 (std::uint64_t& 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::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
{
assert (size != 0);
if (size == 0)
return uint256();
if (size < 0 || size > mData.size())
return getSHA512Half (mData);
return getSHA512Half (const_byte_view (
mData.data(), mData.data() + size));
}
uint256 Serializer::getSHA512Half (const_byte_view v)
{
uint256 j[2];
SHA512 (v.data(), v.size(),
reinterpret_cast<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::getPrefixHash (std::uint32_t 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];
}
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 (std::string const& 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;
}
std::uint16_t SerializerIterator::get16 ()
{
std::uint16_t val;
if (!mSerializer.get16 (val, mPos)) throw std::runtime_error ("invalid serializer get16");
mPos += 16 / 8;
return val;
}
std::uint32_t SerializerIterator::get32 ()
{
std::uint32_t val;
if (!mSerializer.get32 (val, mPos)) throw std::runtime_error ("invalid serializer get32");
mPos += 32 / 8;
return val;
}
std::uint64_t SerializerIterator::get64 ()
{
std::uint64_t val;
if (!mSerializer.get64 (val, mPos)) throw std::runtime_error ("invalid serializer get64");
mPos += 64 / 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 Serializer_test : public beast::unit_test::suite
{
public:
void run ()
{
Serializer s1;
s1.add32 (3);
s1.add256 (uint256 ());
Serializer s2;
s2.add32 (0x12345600);
s2.addRaw (s1.peekData ());
expect (s1.getPrefixHash (0x12345600) == s2.getSHA512Half ());
}
};
BEAST_DEFINE_TESTSUITE(Serializer,ripple_data,ripple);
} // ripple

View File

@@ -0,0 +1,377 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZER_H
#define RIPPLE_SERIALIZER_H
#include <iomanip>
#include <ripple/common/byte_view.h>
namespace ripple {
class CKey; // forward declaration
class Serializer
{
public:
typedef std::shared_ptr<Serializer> pointer;
protected:
Blob mData;
public:
Serializer (int n = 256)
{
mData.reserve (n);
}
Serializer (Blob const& data) : mData (data)
{
;
}
Serializer (std::string const& 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 (std::uint16_t);
int add32 (std::uint32_t); // ledger indexes, account sequence, timestamps
int add64 (std::uint64_t); // native currency amounts
int add128 (const uint128&); // private key generators
int add256 (uint256 const& ); // transaction and ledger hashes
template <typename Integer>
int addInteger(Integer);
template <int Bits, class Tag>
int addBitString(base_uint<Bits, Tag> const& v) {
int ret = mData.size ();
mData.insert (mData.end (), v.begin (), v.end ());
return ret;
}
// TODO(tom): merge with add128 and add256.
template <class Tag>
int add160 (base_uint<160, Tag> const& i)
{
return addBitString<160, Tag>(i);
}
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 (std::string const& 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 (std::uint16_t&, int offset) const;
bool get32 (std::uint32_t&, int offset) const;
bool get64 (std::uint64_t&, int offset) const;
bool get128 (uint128&, int offset) const;
bool get256 (uint256&, int offset) const;
template <typename Integer>
bool getInteger(Integer& number, int offset) {
static const auto bytes = sizeof(Integer);
if ((offset + bytes) > mData.size ())
return false;
number = 0;
auto ptr = &mData[offset];
for (auto i = 0; i < bytes; ++i)
{
if (i)
number <<= 8;
number |= *ptr++;
}
return true;
}
template <int Bits, typename Tag = void>
bool getBitString(base_uint<Bits, Tag>& data, int offset) const {
auto success = (offset + (Bits / 8)) <= mData.size ();
if (success)
memcpy (data.begin (), & (mData.front ()) + offset, (Bits / 8));
return success;
}
uint256 get256 (int offset) const;
// TODO(tom): merge with get128 and get256.
template <class Tag>
bool get160 (base_uint<160, Tag>& o, int offset) const
{
return getBitString<160, Tag>(o, offset);
}
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 (const_byte_view v);
static uint256 getSHA512Half (const unsigned char* data, int len);
// prefix hash functions
static uint256 getPrefixHash (std::uint32_t prefix, const unsigned char* data, int len);
uint256 getPrefixHash (std::uint32_t prefix) const
{
return getPrefixHash (prefix, & (mData.front ()), mData.size ());
}
static uint256 getPrefixHash (std::uint32_t prefix, Blob const& data)
{
return getPrefixHash (prefix, & (data.front ()), data.size ());
}
static uint256 getPrefixHash (std::uint32_t prefix, std::string const& 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;
}
std::string getHex () const
{
std::stringstream h;
for (unsigned char const& element : mData)
{
h <<
std::setw (2) <<
std::hex <<
std::setfill ('0') <<
static_cast<unsigned int>(element);
}
return h.str ();
}
// 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 ();
std::uint16_t get16 ();
std::uint32_t get32 ();
std::uint64_t get64 ();
uint128 get128 () { return getBitString<128>(); }
uint160 get160 () { return getBitString<160>(); }
uint256 get256 () { return getBitString<256>(); }
template <std::size_t Bits, typename Tag = void>
void getBitString (base_uint<Bits, Tag>& bits) {
if (!mSerializer.getBitString<Bits> (bits, mPos))
throw std::runtime_error ("invalid serializer getBitString");
mPos += Bits / 8;
}
template <std::size_t Bits, typename Tag = void>
base_uint<Bits, Tag> getBitString () {
base_uint<Bits, Tag> bits;
getBitString(bits);
return bits;
}
void getFieldID (int& type, int& field);
Blob getRaw (int iLength);
Blob getVL ();
};
} // ripple
#endif

View File

@@ -0,0 +1,159 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/ArraySize.h>
namespace ripple {
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-existent 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, "tecMASTER_DISABLED", "Master key is disabled." },
{ tecNO_REGULAR_KEY, "tecNO_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." },
{ tecNO_ISSUER, "tecNO_ISSUER", "Issuer account does not exist." },
{ tecNO_AUTH, "tecNO_AUTH", "Not authorized to hold asset." },
{ tecNO_LINE, "tecNO_LINE", "No such line." },
{ tecINSUFF_FEE, "tecINSUFF_FEE", "Insufficient balance to pay fee." },
{ tecFROZEN, "tecFROZEN", "Asset is frozen." },
{ tecNO_TARGET, "tecNO_TARGET", "Target account does not exist." },
{ tecNO_PERMISSION, "tecNO_PERMISSION", "No permission to perform requested operation." },
{ tecNO_ENTRY, "tecNO_ENTRY", "No matching entry found." },
{ tecINSUFFICIENT_RESERVE,"tecINSUFFICIENT_RESERVE", "Insufficient reserve to complete requested operation." },
{ 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_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." },
{ tefCREATED, "tefCREATED", "Can't add an already created account." },
{ tefDST_TAG_NEEDED, "tefDST_TAG_NEEDED", "Destination tag required." },
{ tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." },
{ tefFAILURE, "tefFAILURE", "Failed to apply." },
{ tefINTERNAL, "tefINTERNAL", "Internal error." },
{ tefMASTER_DISABLED, "tefMASTER_DISABLED", "Master key is disabled." },
{ tefMAX_LEDGER, "tefMAX_LEDGER", "Ledger sequence too high." },
{ 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." },
{ 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_EXPIRATION, "temBAD_EXPIRATION", "Malformed: Bad expiration." },
{ temBAD_FEE, "temBAD_FEE", "Invalid fee, negative or not XRP." },
{ 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_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." },
{ temBAD_SEQUENCE, "temBAD_SEQUENCE", "Malformed: Sequence is not in the past." },
{ 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" },
{ 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_RIPPLE, "terNO_RIPPLE", "Path does not permit rippling." },
{ 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 = RIPPLE_ARRAYSIZE (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 : "-";
}
} // ripple

View File

@@ -0,0 +1,231 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_TER_H
#define RIPPLE_TER_H
namespace ripple {
// See https://ripple.com/wiki/Transaction_errors
// 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,
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_EXPIRATION,
temBAD_FEE,
temBAD_ISSUER,
temBAD_LIMIT,
temBAD_OFFER,
temBAD_PATH,
temBAD_PATH_LOOP,
temBAD_SEND_XRP_LIMIT,
temBAD_SEND_XRP_MAX,
temBAD_SEND_XRP_NO_DIRECT,
temBAD_SEND_XRP_PARTIAL,
temBAD_SEND_XRP_PATHS,
temBAD_SEQUENCE,
temBAD_SIGNATURE,
temBAD_SRC_ACCOUNT,
temBAD_TRANSFER_RATE,
temDST_IS_SRC,
temDST_NEEDED,
temINVALID,
temINVALID_FLAG,
temREDUNDANT,
temREDUNDANT_SEND_MAX,
temRIPPLE_EMPTY,
// An intermediate result used internally, should never be returned.
temUNCERTAIN,
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_LEDGER,
tefCREATED,
tefDST_TAG_NEEDED,
tefEXCEPTION,
tefINTERNAL,
tefNO_AUTH_REQUIRED, // Can't set auth if auth is not required.
tefPAST_SEQ,
tefWRONG_PRIOR,
tefMASTER_DISABLED,
tefMAX_LEDGER,
// -99 .. -1: R Retry
// sequence too high, no funds for txn fee, originating -account
// non-existent
//
// Cause:
// Prior application of another, possibly non-existent, 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, so 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, so don't
// burden network.
terLAST, // Process after all other transactions
terNO_RIPPLE, // Rippling not allowed
// 0: S Success (success)
// Causes:
// - Success.
// Implications:
// - Applied
// - Forwarded
tesSUCCESS = 0,
// 100 .. 159 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,
tecNO_ISSUER = 133,
tecNO_AUTH = 134,
tecNO_LINE = 135,
tecINSUFF_FEE = 136,
tecFROZEN = 137,
tecNO_TARGET = 138,
tecNO_PERMISSION = 139,
tecNO_ENTRY = 140,
tecINSUFFICIENT_RESERVE = 141,
};
inline bool isTelLocal(TER x)
{
return ((x) >= telLOCAL_ERROR && (x) < temMALFORMED);
}
inline bool isTemMalformed(TER x)
{
return ((x) >= temMALFORMED && (x) < tefFAILURE);
}
inline bool isTefFailure(TER x)
{
return ((x) >= tefFAILURE && (x) < terRETRY);
}
inline bool isTerRetry(TER x)
{
return ((x) >= terRETRY && (x) < tesSUCCESS);
}
inline bool isTesSuccess(TER x)
{
return ((x) == tesSUCCESS);
}
inline bool isTecClaim(TER x)
{
return ((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);
} // ripple
#endif

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_TXFLAGS_H
#define RIPPLE_TXFLAGS_H
namespace ripple {
//
// 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 std::uint32_t const requireDestTag = 0x00010000;
};
// VFALCO TODO Move all flags into this container after some study.
// Universal Transaction flags:
const std::uint32_t tfFullyCanonicalSig = 0x80000000;
const std::uint32_t tfUniversal = tfFullyCanonicalSig;
const std::uint32_t tfUniversalMask = ~ tfUniversal;
// AccountSet flags:
// VFALCO TODO Javadoc comment every one of these constants
//const std::uint32_t TxFlag::requireDestTag = 0x00010000;
const std::uint32_t tfOptionalDestTag = 0x00020000;
const std::uint32_t tfRequireAuth = 0x00040000;
const std::uint32_t tfOptionalAuth = 0x00080000;
const std::uint32_t tfDisallowXRP = 0x00100000;
const std::uint32_t tfAllowXRP = 0x00200000;
const std::uint32_t tfAccountSetMask = ~ (tfUniversal | TxFlag::requireDestTag | tfOptionalDestTag
| tfRequireAuth | tfOptionalAuth
| tfDisallowXRP | tfAllowXRP);
// AccountSet SetFlag/ClearFlag values
const std::uint32_t asfRequireDest = 1;
const std::uint32_t asfRequireAuth = 2;
const std::uint32_t asfDisallowXRP = 3;
const std::uint32_t asfDisableMaster = 4;
const std::uint32_t asfAccountTxnID = 5;
const std::uint32_t asfNoFreeze = 6;
const std::uint32_t asfGlobalFreeze = 7;
// OfferCreate flags:
const std::uint32_t tfPassive = 0x00010000;
const std::uint32_t tfImmediateOrCancel = 0x00020000;
const std::uint32_t tfFillOrKill = 0x00040000;
const std::uint32_t tfSell = 0x00080000;
const std::uint32_t tfOfferCreateMask = ~ (tfUniversal | tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
// Payment flags:
const std::uint32_t tfNoRippleDirect = 0x00010000;
const std::uint32_t tfPartialPayment = 0x00020000;
const std::uint32_t tfLimitQuality = 0x00040000;
const std::uint32_t tfPaymentMask = ~ (tfUniversal | tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
// TrustSet flags:
const std::uint32_t tfSetfAuth = 0x00010000;
const std::uint32_t tfSetNoRipple = 0x00020000;
const std::uint32_t tfClearNoRipple = 0x00040000;
const std::uint32_t tfSetFreeze = 0x00100000;
const std::uint32_t tfClearFreeze = 0x00200000;
const std::uint32_t tfTrustSetMask = ~ (tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple
| tfSetFreeze | tfClearFreeze);
} // ripple
#endif

View File

@@ -0,0 +1,112 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
TxFormats::TxFormats ()
{
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 ("EnableAmendment", ttAMENDMENT)
<< SOElement (sfAmendment, SOE_REQUIRED)
;
add ("SetFee", ttFEE)
<< SOElement (sfBaseFee, SOE_REQUIRED)
<< SOElement (sfReferenceFeeUnits, SOE_REQUIRED)
<< SOElement (sfReserveBase, SOE_REQUIRED)
<< SOElement (sfReserveIncrement, SOE_REQUIRED)
;
add ("TicketCreate", ttTICKET_CREATE)
<< SOElement (sfTarget, SOE_OPTIONAL)
<< SOElement (sfExpiration, SOE_OPTIONAL)
;
add ("TicketCancel", ttTICKET_CANCEL)
<< SOElement (sfTicketID, 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) // Deprecated: Do not use
<< SOElement(sfLastLedgerSequence, SOE_OPTIONAL)
<< SOElement(sfAccountTxnID, SOE_OPTIONAL)
<< SOElement(sfFee, SOE_REQUIRED)
<< SOElement(sfOperationLimit, SOE_OPTIONAL)
<< SOElement(sfMemos, SOE_OPTIONAL)
<< SOElement(sfSigningPubKey, SOE_REQUIRED)
<< SOElement(sfTxnSignature, SOE_OPTIONAL)
;
}
TxFormats* TxFormats::getInstance ()
{
static TxFormats instance;
//return SharedSingleton <TxFormats>::getInstance ();
return &instance;
}
} // ripple

View File

@@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_TXFORMATS_H_INCLUDED
#define RIPPLE_TXFORMATS_H_INCLUDED
namespace ripple {
/** 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,
no_longer_used = 9,
ttTICKET_CREATE = 10,
ttTICKET_CANCEL = 11,
ttTRUST_SET = 20,
ttAMENDMENT = 100,
ttFEE = 101,
};
/** Manages the list of known transaction formats.
*/
class TxFormats : public KnownFormats <TxType>
{
private:
void addCommonFields (Item& item);
public:
/** Create the object.
This will load the object will all the known transaction formats.
*/
TxFormats ();
static TxFormats* getInstance ();
};
} // ripple
#endif