Reorganize source file hierarchy:

* Rename unity files
* Move some modules to new subdirectories
* Remove obsolete Visual Studio project files
* Remove obsolete coding style and TODO list
This commit is contained in:
Vinnie Falco
2014-06-03 14:48:34 -07:00
parent 39a387b54c
commit 4f1d1d2a8a
774 changed files with 6924 additions and 10355 deletions

View File

@@ -22,7 +22,7 @@
#include <beast/asio/abstract_socket.h>
#include <beast/net/IPEndpoint.h>
#include <modules/beast_asio/protocol/HandshakeDetectLogicPROXY.h>
#include <beast/module/asio/protocol/HandshakeDetectLogicPROXY.h>
#include <boost/asio/ip/tcp.hpp>

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_COMMON_SSLCONTEXT_H_INCLUDED
#define RIPPLE_COMMON_SSLCONTEXT_H_INCLUDED
#include <modules/beast_asio/basics/SSLContext.h>
#include <beast/module/asio/basics/SSLContext.h>
#include <string>

View File

@@ -17,7 +17,7 @@
*/
//==============================================================================
#include <modules/beast_asio/beast_asio.h>
#include <beast/module/asio/asio.h>
#include <beast/asio/IPAddressConversion.h>
#include <atomic>

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_COMMON_JSONRPC_FIELDS_H_INCLUDED
#define RIPPLE_COMMON_JSONRPC_FIELDS_H_INCLUDED
#include <ripple/json/ripple_json.h>
#include <ripple/unity/json.h>
namespace ripple {
namespace jss {

View File

@@ -21,7 +21,7 @@
#define RIPPLE_HTTP_PORT_H_INCLUDED
#include <beast/net/IPEndpoint.h>
#include <modules/beast_asio/basics/SSLContext.h>
#include <beast/module/asio/basics/SSLContext.h>
#include <cstdint>

View File

@@ -23,7 +23,7 @@
#include <beast/smart_ptr/SharedPtr.h>
#include <beast/net/IPEndpoint.h>
#include <beast/utility/Journal.h>
#include <modules/beast_asio/http/HTTPRequest.h>
#include <beast/module/asio/http/HTTPRequest.h>
#include <ostream>

View File

@@ -23,9 +23,9 @@
#include <ripple/http/api/Session.h>
#include <ripple/common/MultiSocket.h>
#include <modules/beast_asio/async/AsyncObject.h>
#include <modules/beast_asio/basics/SharedArg.h>
#include <modules/beast_asio/http/HTTPRequestParser.h>
#include <beast/module/asio/async/AsyncObject.h>
#include <beast/module/asio/basics/SharedArg.h>
#include <beast/module/asio/http/HTTPRequestParser.h>
#include <memory>

View File

@@ -21,7 +21,7 @@
#define RIPPLE_HTTP_SERVERIMPL_H_INCLUDED
#include <beast/threads/Thread.h>
#include <modules/beast_asio/basics/SharedArg.h>
#include <beast/module/asio/basics/SharedArg.h>
namespace ripple {
namespace HTTP {

View File

@@ -17,7 +17,7 @@
*/
//==============================================================================
#include <modules/beast_core/text/LexicalCast.h>
#include <beast/module/core/text/LexicalCast.h>
namespace Json {

View File

@@ -0,0 +1,29 @@
# ripple_app
## LedgerMaster.cpp
- Change getLedgerByHash() to not use "all bits zero" to mean
"return the current ledger"
- replace uint32 with LedgerIndex and choose appropriate names
## IHashRouter.h
- Rename to HashRouter.h
## HashRouter.cpp
- Rename HashRouter to HashRouterImp
- Inline functions
- Comment appropriately
- Determine the semantics of the uint256, replace it with an appropriate
typedef like RipplePublicKey or whatever is appropriate.
- Provide good symbolic names for the config tunables.
## Beast
- Change Stoppable to not require a constructor with parameters

View File

@@ -0,0 +1,213 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_AMOUNT_H_INCLUDED
#define RIPPLE_CORE_AMOUNT_H_INCLUDED
#include <ripple/module/data/protocol/SerializedObject.h>
#include <beast/utility/noexcept.h>
#include <beast/cxx14/type_traits.h> // <type_traits>
namespace ripple {
namespace core {
/** Custom floating point asset amount.
The "representation" may be integral or non-integral. For integral
representations, the exponent is always zero and the value held in the
mantissa is an exact quantity.
*/
class AmountType
{
private:
std::uint64_t m_mantissa;
int m_exponent;
bool m_negative;
bool m_integral;
AmountType (std::uint64_t mantissa,
int exponent, bool negative, bool integral)
: m_mantissa (mantissa)
, m_exponent (exponent)
, m_negative (negative)
, m_integral (integral)
{
}
public:
/** Default construction.
The value is uninitialized.
*/
AmountType() noexcept
{
}
/** Construct from an integer.
The representation is set to integral.
*/
/** @{ */
template <class Integer>
AmountType (Integer value,
std::enable_if_t <std::is_signed <Integer>::value>* = 0) noexcept
: m_mantissa (value)
, m_exponent (0)
, m_negative (value < 0)
, m_integral (true)
{
static_assert (std::is_integral<Integer>::value,
"Cannot construct from non-integral type.");
}
template <class Integer>
AmountType (Integer value,
std::enable_if_t <! std::is_signed <Integer>::value>* = 0) noexcept
: m_mantissa (value)
, m_exponent (0)
, m_negative (false)
{
static_assert (std::is_integral<Integer>::value,
"Cannot construct from non-integral type.");
}
/** @} */
/** Assign the value zero.
The representation is preserved.
*/
AmountType&
operator= (Zero) noexcept
{
m_mantissa = 0;
// VFALCO Why -100?
// "We have to use something in range."
// "This makes zero the smallest value."
m_exponent = m_integral ? 0 : -100;
m_exponent = 0;
m_negative = false;
return *this;
}
/** Returns the value in canonical format. */
AmountType
normal() const noexcept
{
if (m_integral)
{
AmountType result;
if (m_mantissa == 0)
{
result.m_exponent = 0;
result.m_negative = false;
}
return result;
}
return AmountType();
}
//
// Comparison
//
int
signum() const noexcept
{
if (m_mantissa == 0)
return 0;
return m_negative ? -1 : 1;
}
bool
operator== (AmountType const& other) const noexcept
{
return
m_negative == other.m_negative &&
m_mantissa == other.m_mantissa &&
m_exponent == other.m_exponent;
}
bool
operator!= (AmountType const& other) const noexcept
{
return ! (*this == other);
}
bool
operator< (AmountType const& other) const noexcept
{
return false;
}
bool
operator>= (AmountType const& other) const noexcept
{
return ! (*this < other);
}
bool
operator> (AmountType const& other) const noexcept
{
return other < *this;
}
bool
operator<= (AmountType const& other) const noexcept
{
return ! (other < *this);
}
//
// Arithmetic
//
AmountType
operator-() const noexcept
{
return AmountType (m_mantissa, m_exponent, ! m_negative, m_integral);
}
//
// Output
//
std::ostream&
operator<< (std::ostream& os)
{
int const sig (signum());
if (sig == 0)
return os << "0";
if (sig < 0)
os << "-";
if (m_integral)
return os << m_mantissa;
if (m_exponent != 0 && (m_exponent < -25 || m_exponent > -5))
return os << m_mantissa << "e" << m_exponent;
return os;
}
};
//------------------------------------------------------------------------------
typedef STAmount Amount;
}
}
#endif

View File

@@ -0,0 +1,68 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_AMOUNTS_H_INCLUDED
#define RIPPLE_CORE_AMOUNTS_H_INCLUDED
#include <ripple/module/app/book/Amount.h>
#include <beast/utility/noexcept.h>
namespace ripple {
namespace core {
struct Amounts
{
Amounts() = default;
Amounts (Amount const& in_, Amount const& out_)
: in (in_)
, out (out_)
{
}
/** Returns `true` if either quantity is not positive. */
bool
empty() const noexcept
{
return in <= zero || out <= zero;
}
Amount in;
Amount out;
};
inline
bool
operator== (Amounts const& lhs, Amounts const& rhs) noexcept
{
return lhs.in == rhs.in && lhs.out == rhs.out;
}
inline
bool
operator!= (Amounts const& lhs, Amounts const& rhs) noexcept
{
return ! (lhs == rhs);
}
}
}
#endif

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_BOOKTIP_H_INCLUDED
#define RIPPLE_CORE_BOOKTIP_H_INCLUDED
#include <ripple/module/app/book/Quality.h>
#include <ripple/module/app/book/Types.h>
#include <beast/utility/noexcept.h>
#include <functional>
namespace ripple {
namespace core {
/** Iterates and consumes raw offers in an order book.
Offers are presented from highest quality to lowest quality. This will
return all offers present including missing, invalid, unfunded, etc.
*/
class BookTip
{
private:
std::reference_wrapper <LedgerView> m_view;
bool m_valid;
uint256 m_book;
uint256 m_end;
uint256 m_dir;
uint256 m_index;
SLE::pointer m_entry;
LedgerView&
view() const noexcept
{
return m_view;
}
public:
/** Create the iterator. */
BookTip (LedgerView& view, BookRef book);
uint256 const&
dir() const noexcept
{
return m_dir;
}
uint256 const&
index() const noexcept
{
return m_index;
}
Quality const
quality() const noexcept
{
return Quality (Ledger::getQuality (m_dir));
}
SLE::pointer const&
entry() const noexcept
{
return m_entry;
}
/** Erases the current offer and advance to the next offer.
Complexity: Constant
@return `true` if there is a next offer
*/
bool
step ();
};
}
}
#endif

View File

@@ -0,0 +1,117 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_OFFER_H_INCLUDED
#define RIPPLE_CORE_OFFER_H_INCLUDED
#include <ripple/module/app/book/Amounts.h>
#include <ripple/module/app/book/Quality.h>
#include <ripple/module/app/book/Types.h>
#include <ripple/module/app/misc/SerializedLedger.h>
#include <ripple/module/data/protocol/FieldNames.h>
#include <beast/utility/noexcept.h>
#include <ostream>
namespace ripple {
namespace core {
class Offer
{
public:
typedef Amount amount_type;
private:
SLE::pointer m_entry;
Quality m_quality;
public:
Offer() = default;
Offer (SLE::pointer const& entry, Quality quality)
: m_entry (entry)
, m_quality (quality)
{
}
/** Returns the quality of the offer.
Conceptually, the quality is the ratio of output to input currency.
The implementation calculates it as the ratio of input to output
currency (so it sorts ascending). The quality is computed at the time
the offer is placed, and never changes for the lifetime of the offer.
This is an important business rule that maintains accuracy when an
offer is partially filled; Subsequent partial fills will use the
original quality.
*/
Quality const
quality() const noexcept
{
return m_quality;
}
/** Returns the account id of the offer's owner. */
Account const
account() const
{
return m_entry->getFieldAccount160 (sfAccount);
}
/** Returns the in and out amounts.
Some or all of the out amount may be unfunded.
*/
Amounts const
amount() const
{
return Amounts (m_entry->getFieldAmount (sfTakerPays),
m_entry->getFieldAmount (sfTakerGets));
}
/** Returns `true` if no more funds can flow through this offer. */
bool
fully_consumed() const
{
if (m_entry->getFieldAmount (sfTakerPays) <= zero)
return true;
if (m_entry->getFieldAmount (sfTakerGets) <= zero)
return true;
return false;
}
/** Returns the ledger entry underlying the offer. */
// AVOID USING THIS
SLE::pointer
entry() const noexcept
{
return m_entry;
}
};
inline
std::ostream&
operator<< (std::ostream& os, Offer const& offer)
{
return os << offer.entry()->getIndex();
}
}
}
#endif

View File

@@ -0,0 +1,124 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_OFFERSTREAM_H_INCLUDED
#define RIPPLE_CORE_OFFERSTREAM_H_INCLUDED
#include <ripple/module/app/book/BookTip.h>
#include <ripple/module/app/book/Offer.h>
#include <ripple/module/app/book/Quality.h>
#include <ripple/module/app/book/Types.h>
#include <beast/utility/noexcept.h>
#include <functional>
namespace ripple {
namespace core {
/** Presents and consumes the offers in an order book.
Two `LedgerView` objects accumulate changes to the ledger. `view`
is applied when the calling transaction succeeds. If the calling
transaction fails, then `view_cancel` is applied.
Certain invalid offers are automatically removed:
- Offers with missing ledger entries
- Offers that expired
- Offers found unfunded:
An offer is found unfunded when the corresponding balance is zero
and the caller has not modified the balance. This is accomplished
by also looking up the balance in the cancel view.
When an offer is removed, it is removed from both views. This grooms the
order book regardless of whether or not the transaction is successful.
*/
class OfferStream
{
private:
beast::Journal m_journal;
std::reference_wrapper <LedgerView> m_view;
std::reference_wrapper <LedgerView> m_view_cancel;
Book m_book;
Clock::time_point m_when;
BookTip m_tip;
Offer m_offer;
void
erase (LedgerView& view);
public:
OfferStream (LedgerView& view, LedgerView& view_cancel, BookRef book,
Clock::time_point when, beast::Journal journal);
LedgerView&
view () noexcept
{
return m_view;
}
LedgerView&
view_cancel () noexcept
{
return m_view_cancel;
}
Book const&
book () const noexcept
{
return m_book;
}
/** Returns the offer at the tip of the order book.
Offers are always presented in decreasing quality.
Only valid if step() returned `true`.
*/
Offer const&
tip () const
{
return m_offer;
}
/** Advance to the next valid offer.
This automatically removes:
- Offers with missing ledger entries
- Offers found unfunded
- expired offers
@return `true` if there is a valid offer.
*/
bool
step ();
/** Advance to the next valid offer that is not from the specified account.
This automatically removes:
- Offers with missing ledger entries
- Offers found unfunded
- Offers from the same account
- Expired offers
@return `true` if there is a valid offer.
*/
bool
step_account (Account const& account);
};
}
}
#endif

View File

@@ -0,0 +1,141 @@
//------------------------------------------------------------------------------
/*
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_CORE_QUALITY_H_INCLUDED
#define RIPPLE_CORE_QUALITY_H_INCLUDED
#include <ripple/module/app/book/Amount.h>
#include <ripple/module/app/book/Amounts.h>
#include <cstdint>
#include <ostream>
namespace ripple {
namespace core {
/** Represents the logical ratio of output currency to input currency.
Internally this is stored using a custom floating point representation,
as the inverse of the ratio, so that quality will be descending in
a sequence of actual values that represent qualities.
*/
class Quality
{
public:
// Type of the internal representation. Higher qualities
// have lower unsigned integer representations.
typedef std::uint64_t value_type;
private:
value_type m_value;
public:
Quality() = default;
/** Create a quality from the integer encoding of an Amount */
explicit
Quality (std::uint64_t value);
/** Create a quality from the ratio of two amounts. */
explicit
Quality (Amounts const& amount);
/** Advances to the next higher quality level. */
/** @{ */
Quality&
operator++();
Quality
operator++ (int);
/** @} */
/** Advances to the next lower quality level. */
/** @{ */
Quality&
operator--();
Quality
operator-- (int);
/** @} */
/** Returns the quality as Amount. */
Amount
rate () const
{
return Amount::setRate (m_value);
}
/** Returns the scaled amount with in capped.
Math is avoided if the result is exact. The output is clamped
to prevent money creation.
*/
Amounts
ceil_in (Amounts const& amount, Amount const& limit) const;
/** Returns the scaled amount with out capped.
Math is avoided if the result is exact. The input is clamped
to prevent money creation.
*/
Amounts
ceil_out (Amounts const& amount, Amount const& limit) const;
/** Returns `true` if lhs is lower quality than `rhs`.
Lower quality means the taker receives a worse deal.
Higher quality is better for the taker.
*/
friend
bool
operator< (Quality const& lhs, Quality const& rhs) noexcept
{
return lhs.m_value > rhs.m_value;
}
friend
bool
operator== (Quality const& lhs, Quality const& rhs) noexcept
{
return lhs.m_value == rhs.m_value;
}
friend
bool
operator!= (Quality const& lhs, Quality const& rhs) noexcept
{
return ! (lhs == rhs);
}
friend
std::ostream&
operator<< (std::ostream& os, Quality const& quality)
{
os << quality.m_value;
return os;
}
};
/** Calculate the quality of a two-hop path given the two hops.
@param lhs The first leg of the path: input to intermediate.
@param rhs The second leg of the path: intermediate to output.
*/
Quality
composed_quality (Quality const& lhs, Quality const& rhs);
}
}
#endif

View File

@@ -0,0 +1,147 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_TAKER_H_INCLUDED
#define RIPPLE_CORE_TAKER_H_INCLUDED
#include <ripple/module/app/book/Amounts.h>
#include <ripple/module/app/book/Quality.h>
#include <ripple/module/app/book/Offer.h>
#include <ripple/module/app/book/Types.h>
#include <beast/streams/debug_ostream.h>
#include <beast/utility/noexcept.h>
#include <functional>
//#include <utility>
namespace ripple {
namespace core {
/** State for the active party during order book or payment operations. */
class Taker
{
public:
struct Options
{
Options() = delete;
explicit
Options (std::uint32_t tx_flags)
: sell (is_bit_set (tx_flags, tfSell))
, passive (is_bit_set (tx_flags, tfPassive))
, fill_or_kill (is_bit_set (tx_flags, tfFillOrKill))
, immediate_or_cancel (is_bit_set (tx_flags, tfImmediateOrCancel))
{
}
bool const sell;
bool const passive;
bool const fill_or_kill;
bool const immediate_or_cancel;
};
private:
std::reference_wrapper <LedgerView> m_view;
Account m_account;
Options m_options;
Quality m_quality;
Quality m_threshold;
// The original in and out quantities.
Amounts const m_amount;
// The amounts still left over for us to try and take.
Amounts m_remain;
private:
Amounts
flow (Amounts amount, Offer const& offer, Account const& taker);
TER
fill (Offer const& offer, Amounts const& amount);
TER
fill (Offer const& leg1, Amounts const& amount1,
Offer const& leg2, Amounts const& amount2);
public:
Taker (LedgerView& view, Account const& account,
Amounts const& amount, Options const& options);
LedgerView&
view () const noexcept
{
return m_view;
}
/** Returns the amount remaining on the offer.
This is the amount at which the offer should be placed. It may either
be for the full amount when there were no crossing offers, or for zero
when the offer fully crossed, or any amount in between.
It is always at the original offer quality (m_quality)
*/
Amounts
remaining_offer () const;
/** Returns the account identifier of the taker. */
Account const&
account () const noexcept
{
return m_account;
}
/** Returns `true` if the quality does not meet the taker's requirements. */
bool
reject (Quality const& quality) const noexcept
{
return quality < m_threshold;
}
/** Returns `true` if order crossing should not continue.
Order processing is stopped if the taker's order quantities have
been reached, or if the taker has run out of input funds.
*/
bool
done () const;
/** Perform direct crossing through given offer.
@return tesSUCCESS on success, error code otherwise.
*/
TER
cross (Offer const& offer);
/** Perform bridged crossing through given offers.
@return tesSUCCESS on success, error code otherwise.
*/
TER
cross (Offer const& leg1, Offer const& leg2);
};
inline
std::ostream&
operator<< (std::ostream& os, Taker const& taker)
{
return os << taker.account();
}
}
}
#endif

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CORE_TYPES_H_INCLUDED
#define RIPPLE_CORE_TYPES_H_INCLUDED
#include <ripple/module/app/ledger/LedgerEntrySet.h>
#include <ripple/types/api/RippleAssets.h>
#include <ripple/types/api/base_uint.h>
#include <chrono>
#include <cstdint>
namespace ripple {
namespace core {
/** A mutable view that overlays an immutable ledger to track changes. */
typedef LedgerEntrySet LedgerView;
/** Identifies an account. */
typedef uint160 Account;
/** Asset identifiers. */
typedef RippleCurrency Currency;
typedef RippleIssuer Issuer;
typedef RippleAsset Asset;
typedef RippleAssetRef AssetRef;
/** Uniquely identifies an order book. */
typedef RippleBook Book;
typedef RippleBookRef BookRef;
/** A clock representing network time.
This measures seconds since the Ripple epoch as seen
by the ledger close clock.
*/
class Clock // : public abstract_clock <std::chrono::seconds>
{
public:
typedef std::uint32_t time_point;
typedef std::chrono::seconds duration;
};
}
}
#endif

View File

@@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/module/app/book/BookTip.h>
namespace ripple {
namespace core {
BookTip::BookTip (LedgerView& view, BookRef book)
: m_view (view)
, m_valid (false)
, m_book (Ledger::getBookBase (
book.in.currency, book.in.issuer,
book.out.currency, book.out.issuer))
, m_end (Ledger::getQualityNext (m_book))
{
}
bool
BookTip::step ()
{
if (m_valid)
{
if (m_entry)
{
view().offerDelete (m_index);
m_entry = nullptr;
}
}
for(;;)
{
// See if there's an entry at or worse than current quality.
auto const page (
view().getNextLedgerIndex (m_book, m_end));
if (page.isZero())
return false;
unsigned int di (0);
SLE::pointer dir;
if (view().dirFirst (page, dir, di, m_index))
{
m_dir = dir->getIndex();
m_entry = view().entryCache (ltOFFER, m_index);
m_valid = true;
// Next query should start before this directory
m_book = page;
// The quality immediately before the next quality
--m_book;
break;
}
// There should never be an empty directory but just in case,
// we handle that case by advancing to the next directory.
m_book = page;
}
return true;
}
}
}

View File

@@ -0,0 +1,170 @@
//------------------------------------------------------------------------------
/*
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/module/app/book/OfferStream.h>
namespace ripple {
namespace core {
OfferStream::OfferStream (LedgerView& view, LedgerView& view_cancel,
BookRef book, Clock::time_point when, beast::Journal journal)
: m_journal (journal)
, m_view (view)
, m_view_cancel (view_cancel)
, m_book (book)
, m_when (when)
, m_tip (view, book)
{
}
// Handle the case where a directory item with no corresponding ledger entry
// is found. This shouldn't happen but if it does we clean it up.
void
OfferStream::erase (LedgerView& view)
{
// NIKB NOTE This should be using LedgerView::dirDelete, which would
// correctly remove the directory if its the last entry.
// Unfortunately this is a protocol breaking change.
auto p (view.entryCache (ltDIR_NODE, m_tip.dir()));
if (p == nullptr)
{
if (m_journal.error) m_journal.error <<
"Missing directory " << m_tip.dir() <<
" for offer " << m_tip.index();
return;
}
auto v (p->getFieldV256 (sfIndexes));
auto& x (v.peekValue());
auto it (std::find (x.begin(), x.end(), m_tip.index()));
if (it == x.end())
{
if (m_journal.error) m_journal.error <<
"Missing offer " << m_tip.index() <<
" for directory " << m_tip.dir();
return;
}
x.erase (it);
p->setFieldV256 (sfIndexes, v);
view.entryModify (p);
if (m_journal.trace) m_journal.trace <<
"Missing offer " << m_tip.index() <<
" removed from directory " << m_tip.dir();
}
bool
OfferStream::step ()
{
// Modifying the order or logic of these
// operations causes a protocol breaking change.
for(;;)
{
// BookTip::step deletes the current offer from the view before
// advancing to the next (unless the ledger entry is missing).
if (! m_tip.step())
return false;
SLE::pointer const& entry (m_tip.entry());
// Remove if missing
if (! entry)
{
erase (view());
erase (view_cancel());
continue;
}
// Remove if expired
if (entry->isFieldPresent (sfExpiration) &&
entry->getFieldU32 (sfExpiration) <= m_when)
{
view_cancel().offerDelete (entry->getIndex());
if (m_journal.trace) m_journal.trace <<
"Removing expired offer " << entry->getIndex();
continue;
}
m_offer = Offer (entry, m_tip.quality());
Amounts const amount (m_offer.amount());
// Remove if either amount is zero
if (amount.empty())
{
view_cancel().offerDelete (entry->getIndex());
if (m_journal.warning) m_journal.warning <<
"Removing bad offer " << entry->getIndex();
m_offer = Offer{};
continue;
}
// Calculate owner funds
// NIKB NOTE The calling code also checks the funds, how expensive is
// looking up the funds twice?
Amount const owner_funds (view().accountFunds (
m_offer.account(), m_offer.amount().out));
// Check for unfunded offer
if (owner_funds <= zero)
{
// If the owner's balance in the pristine view is the same,
// we haven't modified the balance and therefore the
// offer is "found unfunded" versus "became unfunded"
if (view_cancel().accountFunds (m_offer.account(),
m_offer.amount().out) == owner_funds)
{
view_cancel().offerDelete (entry->getIndex());
if (m_journal.trace) m_journal.trace <<
"Removing unfunded offer " << entry->getIndex();
}
else
{
if (m_journal.trace) m_journal.trace <<
"Removing became unfunded offer " << entry->getIndex();
}
m_offer = Offer{};
continue;
}
break;
}
return true;
}
bool
OfferStream::step_account (Account const& account)
{
while (step ())
{
if (tip ().account () != account)
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,120 @@
//------------------------------------------------------------------------------
/*
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/module/app/book/Quality.h>
#include <cassert>
#include <limits>
namespace ripple {
namespace core {
Quality::Quality (std::uint64_t value)
: m_value (value)
{
}
Quality::Quality (Amounts const& amount)
: m_value (Amount::getRate (amount.out, amount.in))
{
}
Quality&
Quality::operator++()
{
assert (m_value > 0);
--m_value;
return *this;
}
Quality
Quality::operator++ (int)
{
Quality prev (*this);
--*this;
return prev;
}
Quality&
Quality::operator--()
{
assert (m_value < std::numeric_limits<value_type>::max());
++m_value;
return *this;
}
Quality
Quality::operator-- (int)
{
Quality prev (*this);
++*this;
return prev;
}
Amounts
Quality::ceil_in (Amounts const& amount, Amount const& limit) const
{
if (amount.in > limit)
{
Amounts result (limit, Amount::divRound (
limit, rate(), amount.out, true));
// Clamp out
if (result.out > amount.out)
result.out = amount.out;
return result;
}
return amount;
}
Amounts
Quality::ceil_out (Amounts const& amount, Amount const& limit) const
{
if (amount.out > limit)
{
Amounts result (Amount::mulRound (
limit, rate(), amount.in, true), limit);
// Clamp in
if (result.in > amount.in)
result.in = amount.in;
return result;
}
return amount;
}
Quality
composed_quality (Quality const& lhs, Quality const& rhs)
{
Amount const lhs_rate (lhs.rate ());
assert (lhs_rate != zero);
Amount const rhs_rate (rhs.rate ());
assert (rhs_rate != zero);
Amount const rate (Amount::mulRound (lhs_rate, rhs_rate, true));
std::uint64_t const stored_exponent (rate.getExponent () + 100);
std::uint64_t const stored_mantissa (rate.getMantissa ());
assert ((stored_exponent >= 0) && (stored_exponent <= 255));
return Quality ((stored_exponent << (64 - 8)) | stored_mantissa);
}
}
}

View File

@@ -0,0 +1,281 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/module/app/book/Taker.h>
//#include <utility>
namespace ripple {
namespace core {
Taker::Taker (LedgerView& view, Account const& account,
Amounts const& amount, Options const& options)
: m_view (view)
, m_account (account)
, m_options (options)
, m_quality (amount)
, m_threshold (m_quality)
, m_amount (amount)
, m_remain (amount)
{
// If this is a passive order (tfPassive), this prevents
// offers at the same quality level from being consumed.
if (m_options.passive)
++m_threshold;
}
Amounts
Taker::remaining_offer () const
{
// If the taker is done, then there's no offer to place.
if (done ())
{
return Amounts (
Amount (m_amount.in.getCurrency (), m_amount.in.getIssuer ()),
Amount (m_amount.out.getCurrency (), m_amount.out.getIssuer ()));
}
// Avoid math altogether if we didn't cross.
if (m_amount == m_remain)
return m_amount;
if (m_options.sell)
{
assert (m_remain.in > zero);
// We scale the output based on the remaining input:
return Amounts (m_remain.in, Amount::divRound (
m_remain.in, m_quality.rate (), m_remain.out, true));
}
assert (m_remain.out > zero);
// We scale the input based on the remaining output:
return Amounts (Amount::mulRound (
m_remain.out, m_quality.rate (), m_remain.in, true), m_remain.out);
}
// Calculate the amount particular user could get through an offer.
// @param amount the maximum flow that is available to the taker.
// @param offer the offer to flow through.
// @param taker the person taking the offer.
// @return the maximum amount that can flow through this offer.
Amounts
Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
{
// Limit taker's input by available funds less fees
Amount const taker_funds (view ().accountFunds (taker, amount.in));
// Get fee rate paid by taker
std::uint32_t const taker_charge_rate (view ().rippleTransferRate (
taker, offer.account (), amount.in.getIssuer()));
// Skip some math when there's no fee
if (taker_charge_rate == QUALITY_ONE)
{
amount = offer.quality ().ceil_in (amount, taker_funds);
}
else
{
Amount const taker_charge (Amount::saFromRate (taker_charge_rate));
amount = offer.quality ().ceil_in (amount,
Amount::divide (taker_funds, taker_charge));
}
// Best flow the owner can get.
// Start out assuming entire offer will flow.
Amounts owner_amount (amount);
// Limit owner's output by available funds less fees
Amount const owner_funds (view ().accountFunds (
offer.account (), owner_amount.out));
// Get fee rate paid by owner
std::uint32_t const owner_charge_rate (view ().rippleTransferRate (
offer.account (), taker, amount.out.getIssuer()));
if (owner_charge_rate == QUALITY_ONE)
{
// Skip some math when there's no fee
owner_amount = offer.quality ().ceil_out (owner_amount, owner_funds);
}
else
{
Amount const owner_charge (Amount::saFromRate (owner_charge_rate));
owner_amount = offer.quality ().ceil_out (owner_amount,
Amount::divide (owner_funds, owner_charge));
}
// Calculate the amount that will flow through the offer
// This does not include the fees.
return (owner_amount.in < amount.in)
? owner_amount
: amount;
}
// Fill a direct offer.
// @param offer the offer we are going to use.
// @param amount the amount to flow through the offer.
// @returns: tesSUCCESS if successful, or an error code otherwise.
TER
Taker::fill (Offer const& offer, Amounts const& amount)
{
TER result (tesSUCCESS);
Amounts const remain (
offer.entry ()->getFieldAmount (sfTakerPays) - amount.in,
offer.entry ()->getFieldAmount (sfTakerGets) - amount.out);
offer.entry ()->setFieldAmount (sfTakerPays, remain.in);
offer.entry ()->setFieldAmount (sfTakerGets, remain.out);
view ().entryModify (offer.entry());
// Pay the taker, then the owner
result = view ().accountSend (offer.account(), account(), amount.out);
if (result == tesSUCCESS)
result = view ().accountSend (account(), offer.account(), amount.in);
return result;
}
// Fill a bridged offer.
// @param leg1 the first leg we are going to use.
// @param amount1 the amount to flow through the first leg of the offer.
// @param leg2 the second leg we are going to use.
// @param amount2 the amount to flow through the second leg of the offer.
// @return tesSUCCESS if successful, or an error code otherwise.
TER
Taker::fill (
Offer const& leg1, Amounts const& amount1,
Offer const& leg2, Amounts const& amount2)
{
assert (amount1.out == amount2.in);
TER result (tesSUCCESS);
Amounts const remain1 (
leg1.entry ()->getFieldAmount (sfTakerPays) - amount1.in,
leg1.entry ()->getFieldAmount (sfTakerGets) - amount1.out);
leg1.entry ()->setFieldAmount (sfTakerPays, remain1.in);
leg1.entry ()->setFieldAmount (sfTakerGets, remain1.out);
view ().entryModify (leg1.entry());
Amounts const remain2 (
leg2.entry ()->getFieldAmount (sfTakerPays) - amount2.in,
leg2.entry ()->getFieldAmount (sfTakerGets) - amount2.out);
view ().entryModify (leg2.entry ());
// Execute the payments in order:
// Taker pays Leg1 (amount1.in - A currency)
// Leg1 pays Leg2 (amount1.out == amount2.in, XRP)
// Leg2 pays Taker (amount2.out - B currency)
result = view ().accountSend (m_account, leg1.account (), amount1.in);
if (result == tesSUCCESS)
result = view ().accountSend (leg1.account (), leg2.account (), amount1.out);
if (result == tesSUCCESS)
result = view ().accountSend (leg2.account (), m_account, amount2.out);
return result;
}
bool
Taker::done () const
{
if (m_options.sell)
{
// With the sell option, we are finished when
// we have consumed all the input currency.
if (m_remain.in <= zero)
return true;
}
else if (m_remain.out <= zero)
{
// With the buy option (!sell) we are finished when we
// have received the desired amount of output currency.
return true;
}
// We are finished if the taker is out of funds
return view().accountFunds (account(), m_remain.in) <= zero;
}
TER
Taker::cross (Offer const& offer)
{
assert (!done ());
Amounts limit (offer.amount());
if (m_options.sell)
limit = offer.quality().ceil_in (limit, m_remain.in);
else
limit = offer.quality ().ceil_out (limit, m_remain.out);
assert (limit.out <= offer.amount().out);
assert (limit.in <= offer.amount().in);
Amounts const amount (flow (limit, offer, account ()));
m_remain.out -= amount.out;
m_remain.in -= amount.in;
assert (m_remain.in >= zero);
return fill (offer, amount);
}
TER
Taker::cross (Offer const& leg1, Offer const& leg2)
{
assert (!done ());
assert (leg1.amount ().out.isNative ());
assert (leg2.amount ().in.isNative ());
Amounts amount1 (leg1.amount());
Amounts amount2 (leg2.amount());
if (m_options.sell)
amount1 = leg1.quality().ceil_in (amount1, m_remain.in);
else
amount2 = leg2.quality().ceil_out (amount2, m_remain.out);
if (amount1.out <= amount2.in)
amount2 = leg2.quality().ceil_in (amount2, amount1.out);
else
amount1 = leg1.quality().ceil_out (amount1, amount2.in);
assert (amount1.out == amount2.in);
// As written, flow can't handle a 3-party transfer, but this works for
// us because the output of leg1 and the input leg2 are XRP.
Amounts flow1 (flow (amount1, leg1, m_account));
amount2 = leg2.quality().ceil_in (amount2, flow1.out);
Amounts flow2 (flow (amount2, leg2, m_account));
m_remain.out -= amount2.out;
m_remain.in -= amount1.in;
return fill (leg1, flow1, leg2, flow2);
}
}
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
/*
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/module/app/book/OfferStream.h>
#include <beast/unit_test/suite.h>
namespace ripple {
namespace core {
class OfferStream_test : public beast::unit_test::suite
{
public:
void
test()
{
pass();
}
void
run()
{
test();
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(OfferStream,core,ripple);
}
}

View File

@@ -0,0 +1,249 @@
//------------------------------------------------------------------------------
/*
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/module/app/book/Quality.h>
#include <beast/unit_test/suite.h>
#include <beast/cxx14/type_traits.h>
namespace ripple {
namespace core {
class Quality_test : public beast::unit_test::suite
{
public:
// Create a raw, non-integral amount from mantissa and exponent
Amount
static raw (std::uint64_t mantissa, int exponent)
{
return Amount (uint160(3), uint160(3), mantissa, exponent);
}
template <class Integer>
static
Amount
amount (Integer integer,
std::enable_if_t <std::is_signed <Integer>::value>* = 0)
{
static_assert (std::is_integral <Integer>::value, "");
return Amount (integer, false);
}
template <class Integer>
static
Amount
amount (Integer integer,
std::enable_if_t <! std::is_signed <Integer>::value>* = 0)
{
static_assert (std::is_integral <Integer>::value, "");
if (integer < 0)
return Amount (-integer, true);
return Amount (integer, false);
}
template <class In, class Out>
static
Amounts
amounts (In in, Out out)
{
return Amounts (amount(in), amount(out));
}
template <class In1, class Out1, class Int, class In2, class Out2>
void
ceil_in (Quality const& q,
In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected)
{
auto expect_result (amounts (in_expected, out_expected));
auto actual_result (q.ceil_in (amounts(in, out), amount(limit)));
expect (actual_result == expect_result);
}
template <class In1, class Out1, class Int, class In2, class Out2>
void
ceil_out (Quality const& q,
In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected)
{
auto const expect_result (amounts (in_expected, out_expected));
auto const actual_result (q.ceil_out (amounts(in, out), amount(limit)));
expect (actual_result == expect_result);
}
void
test_ceil_in ()
{
testcase ("ceil_in");
{
// 1 in, 1 out:
Quality q (Amounts (amount(1), amount(1)));
ceil_in (q,
1, 1, // 1 in, 1 out
1, // limit: 1
1, 1); // 1 in, 1 out
ceil_in (q,
10, 10, // 10 in, 10 out
5, // limit: 5
5, 5); // 5 in, 5 out
ceil_in (q,
5, 5, // 5 in, 5 out
10, // limit: 10
5, 5); // 5 in, 5 out
}
{
// 1 in, 2 out:
Quality q (Amounts (amount(1), amount(2)));
ceil_in (q,
40, 80, // 40 in, 80 out
40, // limit: 40
40, 80); // 40 in, 20 out
ceil_in (q,
40, 80, // 40 in, 80 out
20, // limit: 20
20, 40); // 20 in, 40 out
ceil_in (q,
40, 80, // 40 in, 80 out
60, // limit: 60
40, 80); // 40 in, 80 out
}
{
// 2 in, 1 out:
Quality q (Amounts (amount(2), amount(1)));
ceil_in (q,
40, 20, // 40 in, 20 out
20, // limit: 20
20, 10); // 20 in, 10 out
ceil_in (q,
40, 20, // 40 in, 20 out
40, // limit: 40
40, 20); // 40 in, 20 out
ceil_in (q,
40, 20, // 40 in, 20 out
50, // limit: 40
40, 20); // 40 in, 20 out
}
}
void
test_ceil_out ()
{
testcase ("ceil_out");
{
// 1 in, 1 out:
Quality q (Amounts (amount(1),amount(1)));
ceil_out (q,
1, 1, // 1 in, 1 out
1, // limit 1
1, 1); // 1 in, 1 out
ceil_out (q,
10, 10, // 10 in, 10 out
5, // limit 5
5, 5); // 5 in, 5 out
ceil_out (q,
10, 10, // 10 in, 10 out
20, // limit 20
10, 10); // 10 in, 10 out
}
{
// 1 in, 2 out:
Quality q (Amounts (amount(1),amount(2)));
ceil_out (q,
40, 80, // 40 in, 80 out
40, // limit 40
20, 40); // 20 in, 40 out
ceil_out (q,
40, 80, // 40 in, 80 out
80, // limit 80
40, 80); // 40 in, 80 out
ceil_out (q,
40, 80, // 40 in, 80 out
100, // limit 100
40, 80); // 40 in, 80 out
}
{
// 2 in, 1 out:
Quality q (Amounts (amount(2),amount(1)));
ceil_out (q,
40, 20, // 40 in, 20 out
20, // limit 20
40, 20); // 40 in, 20 out
ceil_out (q,
40, 20, // 40 in, 20 out
40, // limit 40
40, 20); // 40 in, 20 out
ceil_out (q,
40, 20, // 40 in, 20 out
10, // limit 10
20, 10); // 20 in, 10 out
}
}
void
test_raw()
{
{
Quality q (0x5d048191fb9130daull); // 126836389.7680090
Amounts const value (
amount(349469768), // 349.469768 XRP
raw (2755280000000000ull, -15)); // 2.75528
Amount const limit (
raw (4131113916555555, -16)); // .4131113916555555
Amounts const result (q.ceil_out (value, limit));
expect (result.in != zero);
}
}
void
run()
{
test_ceil_in ();
test_ceil_out ();
test_raw();
}
};
BEAST_DEFINE_TESTSUITE(Quality,core,ripple);
}
}

View File

@@ -0,0 +1,153 @@
//------------------------------------------------------------------------------
/*
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 {
// #define TRUST_NETWORK
// Track a peer's yes/no vote on a particular disputed transaction
void DisputedTx::setVote (const uint160& peer, bool votesYes)
{
// VFALCO TODO Simplify this declaration. It doesn't exactly roll off the tongue!
std::pair <ripple::unordered_map <uint160, bool>::iterator, bool> res =
mVotes.insert (std::make_pair (peer, votesYes));
// new vote
if (res.second)
{
if (votesYes)
{
WriteLog (lsDEBUG, LedgerConsensus) << "Peer " << peer << " votes YES on " << mTransactionID;
++mYays;
}
else
{
WriteLog (lsDEBUG, LedgerConsensus) << "Peer " << peer << " votes NO on " << mTransactionID;
++mNays;
}
}
// changes vote to yes
else if (votesYes && !res.first->second)
{
WriteLog (lsDEBUG, LedgerConsensus) << "Peer " << peer << " now votes YES on " << mTransactionID;
--mNays;
++mYays;
res.first->second = true;
}
// changes vote to no
else if (!votesYes && res.first->second)
{
WriteLog (lsDEBUG, LedgerConsensus) << "Peer " << peer << " now votes NO on " << mTransactionID;
++mNays;
--mYays;
res.first->second = false;
}
}
// Remove a peer's vote on this disputed transasction
void DisputedTx::unVote (const uint160& peer)
{
ripple::unordered_map<uint160, bool>::iterator it = mVotes.find (peer);
if (it != mVotes.end ())
{
if (it->second)
--mYays;
else
--mNays;
mVotes.erase (it);
}
}
bool DisputedTx::updateVote (int percentTime, bool proposing)
{
// VFALCO TODO Give the return value a descriptive local variable name
// and don't return from the middle.
if (mOurVote && (mNays == 0))
return false;
if (!mOurVote && (mYays == 0))
return false;
bool newPosition;
int weight;
if (proposing) // give ourselves full weight
{
// This is basically the percentage of nodes voting 'yes' (including us)
weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1);
// VFALCO TODO Rename these macros and turn them into language constructs.
// consolidate them into a class that collects all these related values.
//
// To prevent avalanche stalls, we increase the needed weight slightly over time
if (percentTime < AV_MID_CONSENSUS_TIME)
newPosition = weight > AV_INIT_CONSENSUS_PCT;
else if (percentTime < AV_LATE_CONSENSUS_TIME)
newPosition = weight > AV_MID_CONSENSUS_PCT;
else if (percentTime < AV_STUCK_CONSENSUS_TIME)
newPosition = weight > AV_LATE_CONSENSUS_PCT;
else
newPosition = weight > AV_STUCK_CONSENSUS_PCT;
}
else // don't let us outweigh a proposing node, just recognize consensus
{
weight = -1;
newPosition = mYays > mNays;
}
if (newPosition == mOurVote)
{
WriteLog (lsINFO, LedgerConsensus) <<
"No change (" << (mOurVote ? "YES" : "NO") << ") : weight " << weight << ", percent " << percentTime;
WriteLog (lsDEBUG, LedgerConsensus) << getJson ();
return false;
}
mOurVote = newPosition;
WriteLog (lsDEBUG, LedgerConsensus) << "We now vote " << (mOurVote ? "YES" : "NO") << " on " << mTransactionID;
WriteLog (lsDEBUG, LedgerConsensus) << getJson ();
return true;
}
Json::Value DisputedTx::getJson ()
{
Json::Value ret (Json::objectValue);
ret["yays"] = mYays;
ret["nays"] = mNays;
ret["our_vote"] = mOurVote;
if (!mVotes.empty ())
{
Json::Value votesj (Json::objectValue);
for (auto& vote : mVotes)
{
votesj[to_string (vote.first)] = vote.second;
}
ret["votes"] = votesj;
}
return ret;
}
} // ripple

View File

@@ -0,0 +1,92 @@
//------------------------------------------------------------------------------
/*
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_DISPUTEDTX_H
#define RIPPLE_DISPUTEDTX_H
namespace ripple {
/** A transaction discovered to be in dispute during conensus.
During consensus, a @ref DisputedTx is created when a transaction
is discovered to be disputed. The object persists only as long as
the dispute.
Undisputed transactions have no corresponding @ref DisputedTx object.
*/
class DisputedTx
{
public:
typedef boost::shared_ptr <DisputedTx> pointer;
DisputedTx (uint256 const& txID,
Blob const& tx,
bool ourVote) :
mTransactionID (txID), mYays (0), mNays (0), mOurVote (ourVote), transaction (tx)
{
;
}
uint256 const& getTransactionID () const
{
return mTransactionID;
}
bool getOurVote () const
{
return mOurVote;
}
// VFALCO TODO make this const
Serializer& peekTransaction ()
{
return transaction;
}
void setOurVote (bool o)
{
mOurVote = o;
}
// VFALCO NOTE its not really a peer, its the 160 bit hash of the validator's public key
//
void setVote (uint160 const& peer, bool votesYes);
void unVote (uint160 const& peer);
bool updateVote (int percentTime, bool proposing);
Json::Value getJson ();
private:
uint256 mTransactionID;
int mYays;
int mNays;
bool mOurVote;
Serializer transaction;
ripple::unordered_map <uint160, bool> mVotes;
};
// VFALCO TODO Rename and put these in a tidy place
typedef std::map<uint256, DisputedTx::pointer>::value_type u256_lct_pair;
typedef std::map<uint160, LedgerProposal::pointer>::value_type u160_prop_pair;
#define LEDGER_TOTAL_PASSES 8
#define LEDGER_RETRY_PASSES 5
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
//------------------------------------------------------------------------------
/*
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_LEDGERCONSENSUS_H
#define RIPPLE_LEDGERCONSENSUS_H
namespace ripple {
/** Manager for achieving consensus on the next ledger.
This object is created when the consensus process starts, and
is destroyed when the process is complete.
*/
class LedgerConsensus
{
public:
typedef beast::abstract_clock <std::chrono::seconds> clock_type;
virtual ~LedgerConsensus() = 0;
virtual int startup () = 0;
virtual Json::Value getJson (bool full) = 0;
virtual Ledger::ref peekPreviousLedger () = 0;
virtual uint256 getLCL () = 0;
virtual SHAMap::pointer getTransactionTree (uint256 const & hash,
bool doAcquire) = 0;
virtual void mapComplete (uint256 const & hash, SHAMap::ref map,
bool acquired) = 0;
virtual bool stillNeedTXSet (uint256 const & hash) = 0;
virtual void checkLCL () = 0;
virtual void handleLCL (uint256 const & lclHash) = 0;
virtual void timerEntry () = 0;
// state handlers
virtual void statePreClose () = 0;
virtual void stateEstablish () = 0;
virtual void stateFinished () = 0;
virtual void stateAccepted () = 0;
virtual bool haveConsensus (bool forReal) = 0;
virtual bool peerPosition (LedgerProposal::ref) = 0;
virtual bool peerHasSet (Peer::ptr const& peer, uint256 const & set,
protocol::TxSetStatus status) = 0;
virtual SHAMapAddNode peerGaveNodes (Peer::ptr const& peer,
uint256 const & setHash,
const std::list<SHAMapNode>& nodeIDs,
const std::list< Blob >& nodeData) = 0;
virtual bool isOurPubKey (const RippleAddress & k) = 0;
// test/debug
virtual void simulate () = 0;
};
boost::shared_ptr <LedgerConsensus>
make_LedgerConsensus (LedgerConsensus::clock_type& clock, LocalTxs& localtx,
LedgerHash const & prevLCLHash, Ledger::ref previousLedger,
std::uint32_t closeTime, FeeVote& feeVote);
} // ripple
#endif

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
/*
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 {
Contract::Contract ()
{
}
void Contract::executeCreate ()
{
}
void Contract::executeRemove ()
{
}
void Contract::executeFund ()
{
}
void Contract::executeAccept ()
{
//std::vector<char> code;
//Interpreter interpreter;
//interpreter.interpret(this,code);
}
} // ripple

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
/*
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 CONTRACT_H
#define CONTRACT_H
namespace ripple {
class Contract
{
public:
Contract ();
uint160& getIssuer ();
uint160& getOwner ();
STAmount& getRippleEscrow ();
std::uint32_t getEscrow ();
std::uint32_t getBond ();
Script::Data getData (int index);
void executeCreate ();
void executeRemove ();
void executeFund ();
void executeAccept ();
};
} // ripple
#endif

View File

@@ -0,0 +1,228 @@
//------------------------------------------------------------------------------
/*
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 {
namespace Script
{
Interpreter::Interpreter ()
{
mContract = nullptr;
mCode = nullptr;
mInstructionPointer = 0;
mTotalFee = 0;
mInBlock = false;
mBlockSuccess = true;
mBlockJump = 0;
mFunctionTable.resize (NUM_OF_OPS);
mFunctionTable[INT_OP] = new IntOp ();
mFunctionTable[FLOAT_OP] = new FloatOp ();
mFunctionTable[UINT160_OP] = new Uint160Op ();
mFunctionTable[BOOL_OP] = new Uint160Op ();
mFunctionTable[PATH_OP] = new Uint160Op ();
mFunctionTable[ADD_OP] = new AddOp ();
mFunctionTable[SUB_OP] = new SubOp ();
mFunctionTable[MUL_OP] = new MulOp ();
mFunctionTable[DIV_OP] = new DivOp ();
mFunctionTable[MOD_OP] = new ModOp ();
mFunctionTable[GTR_OP] = new GtrOp ();
mFunctionTable[LESS_OP] = new LessOp ();
mFunctionTable[EQUAL_OP] = new SubOp ();
mFunctionTable[NOT_EQUAL_OP] = new SubOp ();
mFunctionTable[AND_OP] = new SubOp ();
mFunctionTable[OR_OP] = new SubOp ();
mFunctionTable[NOT_OP] = new SubOp ();
mFunctionTable[JUMP_OP] = new SubOp ();
mFunctionTable[JUMPIF_OP] = new SubOp ();
mFunctionTable[STOP_OP] = new SubOp ();
mFunctionTable[CANCEL_OP] = new SubOp ();
mFunctionTable[BLOCK_OP] = new SubOp ();
mFunctionTable[BLOCK_END_OP] = new SubOp ();
mFunctionTable[SEND_XRP_OP] = new SendXRPOp ();
/*
mFunctionTable[SEND_OP]=new SendOp();
mFunctionTable[REMOVE_CONTRACT_OP]=new SubOp();
mFunctionTable[FEE_OP]=new SubOp();
mFunctionTable[CHANGE_CONTRACT_OWNER_OP]=new SubOp();
mFunctionTable[STOP_REMOVE_OP]=new SubOp();
mFunctionTable[SET_DATA_OP]=new SubOp();
mFunctionTable[GET_DATA_OP]=new SubOp();
mFunctionTable[GET_NUM_DATA_OP]=new SubOp();
mFunctionTable[SET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_ISSUER_ID_OP]=new SubOp();
mFunctionTable[GET_OWNER_ID_OP]=new SubOp();
mFunctionTable[GET_LEDGER_TIME_OP]=new SubOp();
mFunctionTable[GET_LEDGER_NUM_OP]=new SubOp();
mFunctionTable[GET_RAND_FLOAT_OP]=new SubOp();
mFunctionTable[GET_XRP_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_CURRENCY_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_ISSUER]=new GetRippleEscrowedIssuerOp();
mFunctionTable[GET_ACCEPT_DATA_OP]=new AcceptDataOp();
mFunctionTable[GET_ACCEPTOR_ID_OP]=new GetAcceptorIDOp();
mFunctionTable[GET_CONTRACT_ID_OP]=new GetContractIDOp();
*/
}
Data::pointer Interpreter::popStack ()
{
if (mStack.size ())
{
Data::pointer item = mStack[mStack.size () - 1];
mStack.pop_back ();
return (item);
}
else
{
return (Data::pointer (new ErrorData ()));
}
}
void Interpreter::pushStack (Data::pointer data)
{
mStack.push_back (data);
}
// offset is where to jump to if the block fails
bool Interpreter::startBlock (int offset)
{
if (mInBlock) return (false); // can't nest blocks
mBlockSuccess = true;
mInBlock = true;
mBlockJump = offset + mInstructionPointer;
return (true);
}
bool Interpreter::endBlock ()
{
if (!mInBlock) return (false);
mInBlock = false;
mBlockJump = 0;
pushStack (Data::pointer (new BoolData (mBlockSuccess)));
return (true);
}
TER Interpreter::interpret (Contract* contract, const SerializedTransaction& txn, Blob& code)
{
mContract = contract;
mCode = &code;
mTotalFee = 0;
mInstructionPointer = 0;
while (mInstructionPointer < code.size ())
{
unsigned int fun = (*mCode)[mInstructionPointer];
mInstructionPointer++;
if (fun >= mFunctionTable.size ())
{
// TODO: log
return (temMALFORMED); // TODO: is this actually what we want to do?
}
mTotalFee += mFunctionTable[ fun ]->getFee (); // FIXME: You can't use fees this way, there's no consensus
if (mTotalFee > txn.getTransactionFee ().getNValue ())
{
// TODO: log
return (telINSUF_FEE_P);
}
else
{
if (!mFunctionTable[ fun ]->work (this))
{
// TODO: log
return (temMALFORMED); // TODO: is this actually what we want to do?
}
}
}
return (tesSUCCESS);
}
Data::pointer Interpreter::getIntData ()
{
int value = 0; // TODO
mInstructionPointer += 4;
return (Data::pointer (new IntData (value)));
}
Data::pointer Interpreter::getFloatData ()
{
float value = 0; // TODO
mInstructionPointer += 4;
return (Data::pointer (new FloatData (value)));
}
Data::pointer Interpreter::getUint160Data ()
{
uint160 value; // TODO
mInstructionPointer += 20;
return (Data::pointer (new Uint160Data (value)));
}
bool Interpreter::jumpTo (int offset)
{
if (offset < 0)
{
if (-offset > mInstructionPointer)
return false;
}
else
{
if (offset > mCode->size () ||
mInstructionPointer > mCode->size () - offset)
return false;
}
mInstructionPointer += offset;
return (true);
}
void Interpreter::stop ()
{
mInstructionPointer = mCode->size ();
}
Data::pointer Interpreter::getContractData (int index)
{
return (Data::pointer (new ErrorData ()));
}
bool Interpreter::canSign (const uint160& signer)
{
return (true);
}
}
} // ripple

View File

@@ -0,0 +1,102 @@
//------------------------------------------------------------------------------
/*
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 INTERPRETER_H
#define INTERPRETER_H
namespace ripple {
namespace Script {
class Operation;
// Contracts are non typed have variable data types
class Interpreter
{
std::vector<Operation*> mFunctionTable;
std::vector<Data::pointer> mStack;
Contract* mContract;
Blob* mCode;
unsigned int mInstructionPointer;
int mTotalFee;
bool mInBlock;
int mBlockJump;
bool mBlockSuccess;
public:
enum { INT_OP = 1, FLOAT_OP, UINT160_OP, BOOL_OP, PATH_OP,
ADD_OP, SUB_OP, MUL_OP, DIV_OP, MOD_OP,
GTR_OP, LESS_OP, EQUAL_OP, NOT_EQUAL_OP,
AND_OP, OR_OP, NOT_OP,
JUMP_OP, JUMPIF_OP,
STOP_OP, CANCEL_OP,
BLOCK_OP, BLOCK_END_OP,
SEND_XRP_OP, SEND_OP, REMOVE_CONTRACT_OP, FEE_OP, CHANGE_CONTRACT_OWNER_OP,
STOP_REMOVE_OP,
SET_DATA_OP, GET_DATA_OP, GET_NUM_DATA_OP,
SET_REGISTER_OP, GET_REGISTER_OP,
GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP,
GET_XRP_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER,
GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP,
NUM_OF_OPS
};
Interpreter ();
// returns a TransactionEngineResult
TER interpret (Contract* contract, const SerializedTransaction& txn, Blob& code);
void stop ();
bool canSign (const uint160& signer);
int getInstructionPointer ()
{
return (mInstructionPointer);
}
void setInstructionPointer (int n)
{
mInstructionPointer = n;
}
Data::pointer popStack ();
void pushStack (Data::pointer data);
bool jumpTo (int offset);
bool startBlock (int offset);
bool endBlock ();
Data::pointer getIntData ();
Data::pointer getFloatData ();
Data::pointer getUint160Data ();
Data::pointer getAcceptData (int index);
Data::pointer getContractData (int index);
};
} // end namespace
} // ripple
#endif

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
/*
We also need to charge for each op
*/
namespace ripple {
namespace Script
{
int Operation::getFee ()
{
return (getConfig ().FEE_CONTRACT_OPERATION);
}
}
} // ripple

View File

@@ -0,0 +1,380 @@
//------------------------------------------------------------------------------
/*
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 OPERATION_H
#define OPERATION_H
namespace ripple {
namespace Script {
// Contracts are non typed have variable data types
class Operation
{
public:
// returns false if there was an error
virtual bool work (Interpreter* interpreter) = 0;
virtual int getFee ();
virtual ~Operation ()
{
;
}
};
// this is just an Int in the code
class IntOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getIntData ();
if (data->isInt32 ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class FloatOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getFloatData ();
if (data->isFloat ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class Uint160Op : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getUint160Data ();
if (data->isUint160 ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class AddOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () + data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () + data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class SubOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () - data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () - data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class MulOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat ()*data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt ()*data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class DivOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () / data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () / data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class GtrOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
interpreter->pushStack (Data::pointer (new BoolData (data1->getFloat () > data2->getFloat ())));
return (true);
}
else
{
return (false);
}
}
};
class LessOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () < data2->getFloat ())));
return (true);
}
else
{
return (false);
}
}
};
class ModOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( data1->isInt32 () && data2->isInt32 () )
{
interpreter->pushStack (Data::pointer (new IntData (data1->getInt () % data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class StartBlockOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
return (interpreter->startBlock (offset->getInt ()));
}
};
class EndBlockOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
return (interpreter->endBlock ());
}
};
class StopOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
interpreter->stop ();
return (true);
}
};
class AcceptDataOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->popStack ();
if (data->isInt32 ())
{
interpreter->pushStack ( interpreter->getAcceptData (data->getInt ()) );
return (true);
}
return (false);
}
};
class JumpIfOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
Data::pointer cond = interpreter->popStack ();
if (cond->isBool () && offset->isInt32 ())
{
if (cond->isTrue ())
{
return (interpreter->jumpTo (offset->getInt ()));
}
return (true);
}
return (false);
}
};
class JumpOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
if (offset->isInt32 ())
{
return (interpreter->jumpTo (offset->getInt ()));
}
return (false);
}
};
class SendXRPOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer sourceID = interpreter->popStack ();
Data::pointer destID = interpreter->popStack ();
Data::pointer amount = interpreter->popStack ();
if (sourceID->isUint160 () && destID->isUint160 () && amount->isInt32 () && interpreter->canSign (sourceID->getUint160 ()))
{
// make sure:
// source is either, this contract, issuer, or acceptor
// TODO do the send
//interpreter->pushStack( send result);
return (true);
}
return (false);
}
};
class GetDataOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer index = interpreter->popStack ();
if (index->isInt32 ())
{
interpreter->pushStack ( interpreter->getContractData (index->getInt ()));
return (true);
}
return (false);
}
};
}
} // ripple
#endif

View File

@@ -0,0 +1,22 @@
//------------------------------------------------------------------------------
/*
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 {
} // ripple

View File

@@ -0,0 +1,186 @@
//------------------------------------------------------------------------------
/*
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 SCRIPT_DATA_H
#define SCRIPT_DATA_H
namespace ripple {
namespace Script
{
class Data
{
public:
typedef boost::shared_ptr<Data> pointer;
virtual ~Data ()
{
;
}
virtual bool isInt32 ()
{
return (false);
}
virtual bool isFloat ()
{
return (false);
}
virtual bool isUint160 ()
{
return (false);
}
virtual bool isError ()
{
return (false);
}
virtual bool isTrue ()
{
return (false);
}
virtual bool isBool ()
{
return (false);
}
//virtual bool isBlockEnd(){ return(false); }
virtual int getInt ()
{
return (0);
}
virtual float getFloat ()
{
return (0);
}
virtual uint160 getUint160 ()
{
return uint160(0);
}
//virtual bool isCurrency(){ return(false); }
};
class IntData : public Data
{
int mValue;
public:
IntData (int value)
{
mValue = value;
}
bool isInt32 ()
{
return (true);
}
int getInt ()
{
return (mValue);
}
float getFloat ()
{
return ((float)mValue);
}
bool isTrue ()
{
return (mValue != 0);
}
};
class FloatData : public Data
{
float mValue;
public:
FloatData (float value)
{
mValue = value;
}
bool isFloat ()
{
return (true);
}
float getFloat ()
{
return (mValue);
}
bool isTrue ()
{
return (mValue != 0);
}
};
class Uint160Data : public Data
{
uint160 mValue;
public:
Uint160Data (uint160 value) : mValue (value)
{
;
}
bool isUint160 ()
{
return (true);
}
uint160 getUint160 ()
{
return (mValue);
}
};
class BoolData : public Data
{
bool mValue;
public:
BoolData (bool value)
{
mValue = value;
}
bool isBool ()
{
return (true);
}
bool isTrue ()
{
return (mValue);
}
};
class ErrorData : public Data
{
public:
bool isError ()
{
return (true);
}
};
class BlockEndData : public Data
{
public:
bool isBlockEnd ()
{
return (true);
}
};
}
} // ripple
#endif

View File

@@ -0,0 +1,337 @@
//------------------------------------------------------------------------------
/*
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 {
// Transaction database holds transactions and public keys
const char* TxnDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
"PRAGMA mmap_size=17179869184;",
#endif
"BEGIN TRANSACTION;",
"CREATE TABLE Transactions ( \
TransID CHARACTER(64) PRIMARY KEY, \
TransType CHARACTER(24), \
FromAcct CHARACTER(35), \
FromSeq BIGINT UNSIGNED, \
LedgerSeq BIGINT UNSIGNED, \
Status CHARACTER(1), \
RawTxn BLOB, \
TxnMeta BLOB \
);",
"CREATE INDEX TxLgrIndex ON \
Transactions(LedgerSeq);",
"CREATE TABLE AccountTransactions ( \
TransID CHARACTER(64), \
Account CHARACTER(64), \
LedgerSeq BIGINT UNSIGNED, \
TxnSeq INTEGER \
);",
"CREATE INDEX AcctTxIDIndex ON \
AccountTransactions(TransID);",
"CREATE INDEX AcctTxIndex ON \
AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);",
"CREATE INDEX AcctLgrIndex ON \
AccountTransactions(LedgerSeq, Account, TransID);",
"END TRANSACTION;"
};
int TxnDBCount = std::extent<decltype(TxnDBInit)>::value;
// Ledger database holds ledgers and ledger confirmations
const char* LedgerDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
"BEGIN TRANSACTION;",
"CREATE TABLE Ledgers ( \
LedgerHash CHARACTER(64) PRIMARY KEY, \
LedgerSeq BIGINT UNSIGNED, \
PrevHash CHARACTER(64), \
TotalCoins BIGINT UNSIGNED, \
ClosingTime BIGINT UNSIGNED, \
PrevClosingTime BIGINT UNSIGNED, \
CloseTimeRes BIGINT UNSIGNED, \
CloseFlags BIGINT UNSIGNED, \
AccountSetHash CHARACTER(64), \
TransSetHash CHARACTER(64) \
);",
"CREATE INDEX SeqLedger ON Ledgers(LedgerSeq);",
"CREATE TABLE Validations ( \
LedgerHash CHARACTER(64), \
NodePubKey CHARACTER(56), \
SignTime BIGINT UNSIGNED, \
RawData BLOB \
);",
"CREATE INDEX ValidationsByHash ON \
Validations(LedgerHash);",
"CREATE INDEX ValidationsByTime ON \
Validations(SignTime);",
"END TRANSACTION;"
};
int LedgerDBCount = std::extent<decltype(LedgerDBInit)>::value;
// RPC database holds persistent data for RPC clients.
const char* RpcDBInit[] =
{
// Local persistence of the RPC client
"CREATE TABLE RPCData ( \
Key TEXT PRIMARY Key, \
Value TEXT \
);",
};
int RpcDBCount = std::extent<decltype(RpcDBInit)>::value;
// NodeIdentity database holds local accounts and trusted nodes
// VFALCO NOTE but its a table not a database, so...?
//
const char* WalletDBInit[] =
{
// Node identity must be persisted for CAS routing and responsibilities.
"BEGIN TRANSACTION;",
"CREATE TABLE NodeIdentity ( \
PublicKey CHARACTER(53), \
PrivateKey CHARACTER(52), \
Dh512 TEXT, \
Dh1024 TEXT \
);",
// Miscellaneous persistent information
// Integer: 1 : Used to simplify SQL.
// ScoreUpdated: when scores was last updated.
// FetchUpdated: when last fetch succeeded.
"CREATE TABLE Misc ( \
Magic INTEGER UNIQUE NOT NULL, \
ScoreUpdated DATETIME, \
FetchUpdated DATETIME \
);",
// Scoring and other information for domains.
//
// Domain:
// Domain source for https.
// PublicKey:
// Set if ever succeeded.
// XXX Use NULL in place of ""
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
// Table of Domains user has asked to trust.
"CREATE TABLE SeedDomains ( \
Domain TEXT PRIMARY KEY NOT NULL, \
PublicKey CHARACTER(53), \
Source CHARACTER(1) NOT NULL, \
Next DATETIME, \
Scan DATETIME, \
Fetch DATETIME, \
Sha256 CHARACTER[64], \
Comment TEXT \
);",
// Allow us to easily find the next SeedDomain to fetch.
"CREATE INDEX SeedDomainNext ON SeedDomains (Next);",
// Table of PublicKeys user has asked to trust.
// Fetches are made to the CAS. This gets the ripple.txt so even validators
// without a web server can publish a ripple.txt.
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
"CREATE TABLE SeedNodes ( \
PublicKey CHARACTER(53) PRIMARY KEY NOT NULL, \
Source CHARACTER(1) NOT NULL, \
Next DATETIME, \
Scan DATETIME, \
Fetch DATETIME, \
Sha256 CHARACTER[64], \
Comment TEXT \
);",
// Allow us to easily find the next SeedNode to fetch.
"CREATE INDEX SeedNodeNext ON SeedNodes (Next);",
// Nodes we trust to not grossly collude against us. Derived from
// SeedDomains, SeedNodes, and ValidatorReferrals.
//
// Score:
// Computed trust score. Higher is better.
// Seen:
// Last validation received.
"CREATE TABLE TrustedNodes ( \
PublicKey CHARACTER(53) PRIMARY KEY NOT NULL, \
Score INTEGER DEFAULT 0 NOT NULL, \
Seen DATETIME, \
Comment TEXT \
);",
// List of referrals.
// - There may be multiple sources for a Validator. The last source is used.
// Validator:
// Public key of referrer.
// Entry:
// Entry index in [validators] table.
// Referral:
// This is the form provided by the ripple.txt:
// - Public key for CAS based referral.
// - Domain for domain based referral.
// XXX Do garbage collection when validators have no references.
"CREATE TABLE ValidatorReferrals ( \
Validator CHARACTER(53) NOT NULL, \
Entry INTEGER NOT NULL, \
Referral TEXT NOT NULL, \
PRIMARY KEY (Validator,Entry) \
);",
// List of referrals from ripple.txt files.
// Validator:
// Public key of referree.
// Entry:
// Entry index in [validators] table.
// IP:
// IP of referred.
// Port:
// -1 = Default
// XXX Do garbage collection when ips have no references.
"CREATE TABLE IpReferrals ( \
Validator CHARACTER(53) NOT NULL, \
Entry INTEGER NOT NULL, \
IP TEXT NOT NULL, \
Port INTEGER NOT NULL DEFAULT -1, \
PRIMARY KEY (Validator,Entry) \
);",
"CREATE TABLE Features ( \
Hash CHARACTER(64) PRIMARY KEY, \
FirstMajority BIGINT UNSIGNED, \
LastMajority BIGINT UNSIGNED \
);",
// This removes an old table and its index which are now redundant. This
// code will eventually go away. It's only here to clean up the wallet.db
"DROP TABLE IF EXISTS PeerIps;",
"DROP INDEX IF EXISTS;",
"END TRANSACTION;"
};
int WalletDBCount = std::extent<decltype(WalletDBInit)>::value;
// Hash node database holds nodes indexed by hash
// VFALCO TODO Remove this since it looks unused
/*
int HashNodeDBCount = std::extent<decltype(HashNodeDBInit)>::value;
*/
// Net node database holds nodes seen on the network
// XXX Not really used needs replacement.
/*
const char* NetNodeDBInit[] =
{
"CREATE TABLE KnownNodes ( \
Hanko CHARACTER(35) PRIMARY KEY, \
LastSeen TEXT, \
HaveContactInfo CHARACTER(1), \
ContactObject BLOB \
);"
};
int NetNodeDBCount = std::extent<decltype(NetNodeDBInit)>::value;
*/
// This appears to be unused
/*
const char* PathFindDBInit[] =
{
"PRAGMA synchronous = OFF; ",
"DROP TABLE TrustLines; ",
"CREATE TABLE TrustLines { "
"To CHARACTER(40), " // Hex of account trusted
"By CHARACTER(40), " // Hex of account trusting
"Currency CHARACTER(80), " // Hex currency, hex issuer
"Use INTEGER, " // Use count
"Seq BIGINT UNSIGNED " // Sequence when use count was updated
"}; ",
"CREATE INDEX TLBy ON TrustLines(By, Currency, Use);",
"CREATE INDEX TLTo ON TrustLines(To, Currency, Use);",
"DROP TABLE Exchanges;",
"CREATE TABLE Exchanges { "
"From CHARACTER(80), "
"To CHARACTER(80), "
"Currency CHARACTER(80), "
"Use INTEGER, "
"Seq BIGINT UNSIGNED "
"}; ",
"CREATE INDEX ExBy ON Exchanges(By, Currency, Use);",
"CREATE INDEX ExTo ON Exchanges(To, Currency, Use);",
};
int PathFindDBCount = std::extent<decltype(PathFindDBInit)>::value;
*/
} // ripple

View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
/*
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_DBINIT_H_INCLUDED
#define RIPPLE_DBINIT_H_INCLUDED
namespace ripple {
// VFALCO TODO Tidy these up into a class with functions and return types.
extern const char* RpcDBInit[];
extern const char* TxnDBInit[];
extern const char* LedgerDBInit[];
extern const char* WalletDBInit[];
// VFALCO TODO Figure out what these counts are for
extern int RpcDBCount;
extern int TxnDBCount;
extern int LedgerDBCount;
extern int WalletDBCount;
} // ripple
#endif

View File

@@ -0,0 +1,208 @@
//------------------------------------------------------------------------------
/*
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 {
Database::Database (const char* host)
: mNumCol (0)
{
mHost = host;
}
Database::~Database ()
{
}
bool Database::getNull (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getNull (index);
}
return true;
}
char* Database::getStr (const char* colName, std::string& retStr)
{
int index;
if (getColNumber (colName, &index))
{
return getStr (index, retStr);
}
return nullptr;
}
std::int32_t Database::getInt (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getInt (index);
}
return 0;
}
float Database::getFloat (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getFloat (index);
}
return 0;
}
bool Database::getBool (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getBool (index);
}
return 0;
}
int Database::getBinary (const char* colName, unsigned char* buf, int maxSize)
{
int index;
if (getColNumber (colName, &index))
{
return (getBinary (index, buf, maxSize));
}
return (0);
}
Blob Database::getBinary (const std::string& strColName)
{
int index;
if (getColNumber (strColName.c_str (), &index))
{
return getBinary (index);
}
return Blob ();
}
std::string Database::getStrBinary (const std::string& strColName)
{
// YYY Could eliminate a copy if getStrBinary was a template.
return strCopy (getBinary (strColName.c_str ()));
}
std::uint64_t Database::getBigInt (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getBigInt (index);
}
return 0;
}
// returns false if can't find col
bool Database::getColNumber (const char* colName, int* retIndex)
{
for (unsigned int n = 0; n < mColNameTable.size (); n++)
{
if (strcmp (colName, mColNameTable[n].c_str ()) == 0)
{
*retIndex = n;
return (true);
}
}
return false;
}
#if 0
int Database::getSingleDBValueInt (const char* sql)
{
int ret;
if ( executeSQL (sql) && startIterRows ()
{
ret = getInt (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
float Database::getSingleDBValueFloat (const char* sql)
{
float ret;
if (executeSQL (sql) && startIterRows () && getNextRow ())
{
ret = getFloat (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
char* Database::getSingleDBValueStr (const char* sql, std::string& retStr)
{
char* ret;
if (executeSQL (sql) && startIterRows ())
{
ret = getStr (0, retStr);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
} // ripple

View File

@@ -0,0 +1,123 @@
//------------------------------------------------------------------------------
/*
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_DATABASE_H_INCLUDED
#define RIPPLE_DATABASE_H_INCLUDED
namespace ripple {
// VFALCO Get rid of these macros
//
#define SQL_FOREACH(_db, _strQuery) \
if ((_db)->executeSQL(_strQuery)) \
for (bool _bMore = (_db)->startIterRows(); _bMore; _bMore = (_db)->getNextRow())
#define SQL_EXISTS(_db, _strQuery) \
((_db)->executeSQL(_strQuery) && (_db)->startIterRows())
/*
this maintains the connection to the database
*/
class SqliteDatabase;
class JobQueue;
class Database
{
public:
explicit Database (const char* host);
virtual ~Database ();
virtual void connect () = 0;
virtual void disconnect () = 0;
// returns true if the query went ok
virtual bool executeSQL (const char* sql, bool fail_okay = false) = 0;
bool executeSQL (std::string strSql, bool fail_okay = false)
{
return executeSQL (strSql.c_str (), fail_okay);
}
// returns false if there are no results
virtual bool startIterRows (bool finalize = true) = 0;
virtual void endIterRows () = 0;
// call this after you executeSQL
// will return false if there are no more rows
virtual bool getNextRow (bool finalize = true) = 0;
// get Data from the current row
bool getNull (const char* colName);
char* getStr (const char* colName, std::string& retStr);
std::string getStrBinary (const std::string& strColName);
std::int32_t getInt (const char* colName);
float getFloat (const char* colName);
bool getBool (const char* colName);
// returns amount stored in buf
int getBinary (const char* colName, unsigned char* buf, int maxSize);
Blob getBinary (const std::string& strColName);
std::uint64_t getBigInt (const char* colName);
virtual bool getNull (int colIndex) = 0;
virtual char* getStr (int colIndex, std::string& retStr) = 0;
virtual std::int32_t getInt (int colIndex) = 0;
virtual float getFloat (int colIndex) = 0;
virtual bool getBool (int colIndex) = 0;
virtual int getBinary (int colIndex, unsigned char* buf, int maxSize) = 0;
virtual std::uint64_t getBigInt (int colIndex) = 0;
virtual Blob getBinary (int colIndex) = 0;
// int getSingleDBValueInt(const char* sql);
// float getSingleDBValueFloat(const char* sql);
// char* getSingleDBValueStr(const char* sql, std::string& retStr);
// VFALCO TODO Make this parameter a reference instead of a pointer.
virtual bool setupCheckpointing (JobQueue*)
{
return false;
}
virtual SqliteDatabase* getSqliteDB ()
{
return nullptr;
}
virtual int getKBUsedAll ()
{
return -1;
}
virtual int getKBUsedDB ()
{
return -1;
}
protected:
bool getColNumber (const char* colName, int* retIndex);
int mNumCol;
std::string mHost;
std::vector <std::string> mColNameTable;
};
} // ripple
#endif

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
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 {
DatabaseCon::DatabaseCon (const std::string& strName, const char* initStrings[], int initCount)
{
// VFALCO TODO remove this dependency on the config by making it the caller's
// responsibility to pass in the path. Add a member function to Application
// or Config to compute this path.
//
auto const startUp = getConfig ().START_UP;
auto const useTempFiles // Use temporary files or regular DB files?
= getConfig ().RUN_STANDALONE &&
startUp != Config::LOAD &&
startUp != Config::LOAD_FILE &&
startUp != Config::REPLAY;
boost::filesystem::path pPath = useTempFiles
? "" : (getConfig ().DATA_DIR / strName);
mDatabase = new SqliteDatabase (pPath.string ().c_str ());
mDatabase->connect ();
for (int i = 0; i < initCount; ++i)
mDatabase->executeSQL (initStrings[i], true);
}
DatabaseCon::~DatabaseCon ()
{
mDatabase->disconnect ();
delete mDatabase;
}
} // ripple

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
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_DATABASECON_H
#define RIPPLE_DATABASECON_H
namespace ripple {
// VFALCO NOTE This looks like a pointless class. Figure out
// what purpose it is really trying to serve and do it better.
class DatabaseCon : beast::LeakChecked <DatabaseCon>
{
public:
DatabaseCon (const std::string& name, const char* initString[], int countInit);
~DatabaseCon ();
Database* getDB ()
{
return mDatabase;
}
DeprecatedRecursiveMutex& getDBLock ()
{
return mLock;
}
// VFALCO TODO change "protected" to "private" throughout the code
private:
Database* mDatabase;
DeprecatedRecursiveMutex mLock;
};
} // ripple
#endif

View File

@@ -0,0 +1,487 @@
//------------------------------------------------------------------------------
/*
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 {
SETUP_LOG (SqliteDatabase)
SqliteStatement::SqliteStatement (SqliteDatabase* db, const char* sql, bool aux)
{
assert (db);
sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection ();
int j = sqlite3_prepare_v2 (conn, sql, strlen (sql) + 1, &statement, nullptr);
if (j != SQLITE_OK)
throw j;
}
SqliteStatement::SqliteStatement (SqliteDatabase* db, const std::string& sql, bool aux)
{
assert (db);
sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection ();
int j = sqlite3_prepare_v2 (conn, sql.c_str (), sql.size () + 1, &statement, nullptr);
if (j != SQLITE_OK)
throw j;
}
SqliteStatement::~SqliteStatement ()
{
sqlite3_finalize (statement);
}
//------------------------------------------------------------------------------
SqliteDatabase::SqliteDatabase (const char* host)
: Database (host)
, Thread ("sqlitedb")
, mWalQ (nullptr)
, walRunning (false)
{
startThread ();
mConnection = nullptr;
mAuxConnection = nullptr;
mCurrentStmt = nullptr;
}
SqliteDatabase::~SqliteDatabase ()
{
// Blocks until the thread exits in an orderly fashion
stopThread ();
}
void SqliteDatabase::connect ()
{
int rc = sqlite3_open_v2 (mHost.c_str (), &mConnection,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't open " << mHost << " " << rc;
sqlite3_close (mConnection);
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
}
}
sqlite3* SqliteDatabase::getAuxConnection ()
{
ScopedLockType sl (m_walMutex);
if (mAuxConnection == nullptr)
{
int rc = sqlite3_open_v2 (mHost.c_str (), &mAuxConnection,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't aux open " << mHost << " " << rc;
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
if (mAuxConnection != nullptr)
{
sqlite3_close (mConnection);
mAuxConnection = nullptr;
}
}
}
return mAuxConnection;
}
void SqliteDatabase::disconnect ()
{
sqlite3_finalize (mCurrentStmt);
sqlite3_close (mConnection);
if (mAuxConnection != nullptr)
sqlite3_close (mAuxConnection);
}
// returns true if the query went ok
bool SqliteDatabase::executeSQL (const char* sql, bool fail_ok)
{
#ifdef DEBUG_HANGING_LOCKS
assert (fail_ok || (mCurrentStmt == nullptr));
#endif
sqlite3_finalize (mCurrentStmt);
int rc = sqlite3_prepare_v2 (mConnection, sql, -1, &mCurrentStmt, nullptr);
if (SQLITE_OK != rc)
{
if (!fail_ok)
{
#ifdef BEAST_DEBUG
WriteLog (lsWARNING, SqliteDatabase) << "Perror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg (mConnection);
#endif
}
endIterRows ();
return false;
}
rc = sqlite3_step (mCurrentStmt);
if (rc == SQLITE_ROW)
{
mMoreRows = true;
}
else if (rc == SQLITE_DONE)
{
endIterRows ();
mMoreRows = false;
}
else
{
if ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED))
{
WriteLog (lsFATAL, SqliteDatabase) << mHost << " returns error " << rc << ": " << sqlite3_errmsg (mConnection);
assert (false);
}
mMoreRows = false;
if (!fail_ok)
{
#ifdef BEAST_DEBUG
WriteLog (lsWARNING, SqliteDatabase) << "SQL Serror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg (mConnection);
#endif
}
endIterRows ();
return false;
}
return true;
}
// returns false if there are no results
bool SqliteDatabase::startIterRows (bool finalize)
{
mColNameTable.clear ();
mColNameTable.resize (sqlite3_column_count (mCurrentStmt));
for (unsigned n = 0; n < mColNameTable.size (); n++)
{
mColNameTable[n] = sqlite3_column_name (mCurrentStmt, n);
}
if (!mMoreRows && finalize)
endIterRows ();
return (mMoreRows);
}
void SqliteDatabase::endIterRows ()
{
sqlite3_finalize (mCurrentStmt);
mCurrentStmt = nullptr;
}
// call this after you executeSQL
// will return false if there are no more rows
bool SqliteDatabase::getNextRow (bool finalize)
{
if (mMoreRows)
{
int rc = sqlite3_step (mCurrentStmt);
if (rc == SQLITE_ROW)
return (true);
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
CondLog ((rc != SQLITE_DONE), lsWARNING, SqliteDatabase) << "Rerror: " << mHost << ": " << rc;
}
if (finalize)
endIterRows ();
return false;
}
bool SqliteDatabase::getNull (int colIndex)
{
return (SQLITE_NULL == sqlite3_column_type (mCurrentStmt, colIndex));
}
char* SqliteDatabase::getStr (int colIndex, std::string& retStr)
{
const char* text = reinterpret_cast<const char*> (sqlite3_column_text (mCurrentStmt, colIndex));
retStr = (text == nullptr) ? "" : text;
return const_cast<char*> (retStr.c_str ());
}
std::int32_t SqliteDatabase::getInt (int colIndex)
{
return (sqlite3_column_int (mCurrentStmt, colIndex));
}
float SqliteDatabase::getFloat (int colIndex)
{
return (static_cast <float> (sqlite3_column_double (mCurrentStmt, colIndex)));
}
bool SqliteDatabase::getBool (int colIndex)
{
return (sqlite3_column_int (mCurrentStmt, colIndex) ? true : false);
}
int SqliteDatabase::getBinary (int colIndex, unsigned char* buf, int maxSize)
{
const void* blob = sqlite3_column_blob (mCurrentStmt, colIndex);
int size = sqlite3_column_bytes (mCurrentStmt, colIndex);
if (size < maxSize) maxSize = size;
memcpy (buf, blob, maxSize);
return (size);
}
Blob SqliteDatabase::getBinary (int colIndex)
{
const unsigned char* blob = reinterpret_cast<const unsigned char*> (sqlite3_column_blob (mCurrentStmt, colIndex));
size_t iSize = sqlite3_column_bytes (mCurrentStmt, colIndex);
Blob vucResult;
vucResult.resize (iSize);
std::copy (blob, blob + iSize, vucResult.begin ());
return vucResult;
}
std::uint64_t SqliteDatabase::getBigInt (int colIndex)
{
return (sqlite3_column_int64 (mCurrentStmt, colIndex));
}
int SqliteDatabase::getKBUsedAll ()
{
return static_cast<int> (sqlite3_memory_used () / 1024);
}
int SqliteDatabase::getKBUsedDB ()
{
int cur = 0, hiw = 0;
sqlite3_db_status (mConnection, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0);
return cur / 1024;
}
static int SqliteWALHook (void* s, sqlite3* dbCon, const char* dbName, int walSize)
{
(reinterpret_cast<SqliteDatabase*> (s))->doHook (dbName, walSize);
return SQLITE_OK;
}
bool SqliteDatabase::setupCheckpointing (JobQueue* q)
{
mWalQ = q;
sqlite3_wal_hook (mConnection, SqliteWALHook, this);
return true;
}
void SqliteDatabase::doHook (const char* db, int pages)
{
if (pages < 1000)
return;
{
ScopedLockType sl (m_walMutex);
if (walRunning)
return;
walRunning = true;
}
if (mWalQ)
{
mWalQ->addJob (jtWAL, std::string ("WAL:") + mHost, std::bind (&SqliteDatabase::runWal, this));
}
else
{
notify();
}
}
void SqliteDatabase::run ()
{
// Simple thread loop runs Wal every time it wakes up via
// the call to Thread::notify, unless Thread::threadShouldExit returns
// true in which case we simply break.
//
for (;;)
{
wait ();
if (threadShouldExit())
break;
runWal();
}
}
void SqliteDatabase::runWal ()
{
int log = 0, ckpt = 0;
int ret = sqlite3_wal_checkpoint_v2 (mConnection, nullptr, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt);
if (ret != SQLITE_OK)
{
WriteLog ((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING, SqliteDatabase) << "WAL("
<< sqlite3_db_filename (mConnection, "main") << "): error " << ret;
}
else
WriteLog (lsTRACE, SqliteDatabase) << "WAL(" << sqlite3_db_filename (mConnection, "main") <<
"): frames=" << log << ", written=" << ckpt;
{
ScopedLockType sl (m_walMutex);
walRunning = false;
}
}
sqlite3_stmt* SqliteStatement::peekStatement ()
{
return statement;
}
int SqliteStatement::bind (int position, const void* data, int length)
{
return sqlite3_bind_blob (statement, position, data, length, SQLITE_TRANSIENT);
}
int SqliteStatement::bindStatic (int position, const void* data, int length)
{
return sqlite3_bind_blob (statement, position, data, length, SQLITE_STATIC);
}
int SqliteStatement::bindStatic (int position, Blob const& value)
{
return sqlite3_bind_blob (statement, position, &value.front (), value.size (), SQLITE_STATIC);
}
int SqliteStatement::bind (int position, std::uint32_t value)
{
return sqlite3_bind_int64 (statement, position, static_cast<sqlite3_int64> (value));
}
int SqliteStatement::bind (int position, const std::string& value)
{
return sqlite3_bind_text (statement, position, value.data (), value.size (), SQLITE_TRANSIENT);
}
int SqliteStatement::bindStatic (int position, const std::string& value)
{
return sqlite3_bind_text (statement, position, value.data (), value.size (), SQLITE_STATIC);
}
int SqliteStatement::bind (int position)
{
return sqlite3_bind_null (statement, position);
}
int SqliteStatement::size (int column)
{
return sqlite3_column_bytes (statement, column);
}
const void* SqliteStatement::peekBlob (int column)
{
return sqlite3_column_blob (statement, column);
}
Blob SqliteStatement::getBlob (int column)
{
int size = sqlite3_column_bytes (statement, column);
Blob ret (size);
memcpy (& (ret.front ()), sqlite3_column_blob (statement, column), size);
return ret;
}
std::string SqliteStatement::getString (int column)
{
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
const char* SqliteStatement::peekString (int column)
{
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
std::uint32_t SqliteStatement::getUInt32 (int column)
{
return static_cast<std::uint32_t> (sqlite3_column_int64 (statement, column));
}
std::int64_t SqliteStatement::getInt64 (int column)
{
return sqlite3_column_int64 (statement, column);
}
int SqliteStatement::step ()
{
return sqlite3_step (statement);
}
int SqliteStatement::reset ()
{
return sqlite3_reset (statement);
}
bool SqliteStatement::isOk (int j)
{
return j == SQLITE_OK;
}
bool SqliteStatement::isDone (int j)
{
return j == SQLITE_DONE;
}
bool SqliteStatement::isRow (int j)
{
return j == SQLITE_ROW;
}
bool SqliteStatement::isError (int j)
{
switch (j)
{
case SQLITE_OK:
case SQLITE_ROW:
case SQLITE_DONE:
return false;
default:
return true;
}
}
std::string SqliteStatement::getError (int j)
{
return sqlite3_errstr (j);
}
} // ripple

View File

@@ -0,0 +1,153 @@
//------------------------------------------------------------------------------
/*
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_SQLITEDATABASE_H_INCLUDED
#define RIPPLE_SQLITEDATABASE_H_INCLUDED
#include <beast/threads/Thread.h>
namespace ripple {
class SqliteDatabase
: public Database
, private beast::Thread
, private beast::LeakChecked <SqliteDatabase>
{
public:
explicit SqliteDatabase (char const* host);
~SqliteDatabase ();
void connect ();
void disconnect ();
// returns true if the query went ok
bool executeSQL (const char* sql, bool fail_okay);
// tells you how many rows were changed by an update or insert
int getNumRowsAffected ();
// returns false if there are no results
bool startIterRows (bool finalize);
void endIterRows ();
// call this after you executeSQL
// will return false if there are no more rows
bool getNextRow (bool finalize);
bool getNull (int colIndex);
char* getStr (int colIndex, std::string& retStr);
std::int32_t getInt (int colIndex);
float getFloat (int colIndex);
bool getBool (int colIndex);
// returns amount stored in buf
int getBinary (int colIndex, unsigned char* buf, int maxSize);
Blob getBinary (int colIndex);
std::uint64_t getBigInt (int colIndex);
sqlite3* peekConnection ()
{
return mConnection;
}
sqlite3* getAuxConnection ();
virtual bool setupCheckpointing (JobQueue*);
virtual SqliteDatabase* getSqliteDB ()
{
return this;
}
void doHook (const char* db, int walSize);
int getKBUsedDB ();
int getKBUsedAll ();
private:
void run ();
void runWal ();
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType m_walMutex;
sqlite3* mConnection;
// VFALCO TODO Why do we need an "aux" connection? Should just use a second SqliteDatabase object.
sqlite3* mAuxConnection;
sqlite3_stmt* mCurrentStmt;
bool mMoreRows;
JobQueue* mWalQ;
bool walRunning;
};
//------------------------------------------------------------------------------
class SqliteStatement
{
private:
SqliteStatement (const SqliteStatement&); // no implementation
SqliteStatement& operator= (const SqliteStatement&); // no implementation
protected:
sqlite3_stmt* statement;
public:
// VFALCO TODO This is quite a convoluted interface. A mysterious "aux" connection?
// Why not just have two SqliteDatabase objects?
//
SqliteStatement (SqliteDatabase* db, const char* statement, bool aux = false);
SqliteStatement (SqliteDatabase* db, const std::string& statement, bool aux = false);
~SqliteStatement ();
sqlite3_stmt* peekStatement ();
// positions start at 1
int bind (int position, const void* data, int length);
int bindStatic (int position, const void* data, int length);
int bindStatic (int position, Blob const& value);
int bind (int position, const std::string& value);
int bindStatic (int position, const std::string& value);
int bind (int position, std::uint32_t value);
int bind (int position);
// columns start at 0
int size (int column);
const void* peekBlob (int column);
Blob getBlob (int column);
std::string getString (int column);
const char* peekString (int column);
std::uint32_t getUInt32 (int column);
std::int64_t getInt64 (int column);
int step ();
int reset ();
// translate return values of step and reset
bool isOk (int);
bool isDone (int);
bool isRow (int);
bool isError (int);
std::string getError (int);
};
} // ripple
#endif

View File

@@ -0,0 +1,68 @@
//------------------------------------------------------------------------------
/*
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 {
// VFALCO TODO Remove this global and make it a member of the App
// Use a dependency injection to give AcceptedLedger access.
//
TaggedCache <uint256, AcceptedLedger> AcceptedLedger::s_cache (
"AcceptedLedger", 4, 60, get_seconds_clock (),
LogPartition::getJournal <TaggedCacheLog> ());
AcceptedLedger::AcceptedLedger (Ledger::ref ledger) : mLedger (ledger)
{
SHAMap& txSet = *ledger->peekTransactionMap ();
for (SHAMapItem::pointer item = txSet.peekFirstItem (); !!item; item = txSet.peekNextItem (item->getTag ()))
{
SerializerIterator sit (item->peekSerializer ());
insert (boost::make_shared<AcceptedLedgerTx> (ledger->getLedgerSeq (), boost::ref (sit)));
}
}
AcceptedLedger::pointer AcceptedLedger::makeAcceptedLedger (Ledger::ref ledger)
{
AcceptedLedger::pointer ret = s_cache.fetch (ledger->getHash ());
if (ret)
return ret;
ret = AcceptedLedger::pointer (new AcceptedLedger (ledger));
s_cache.canonicalize (ledger->getHash (), ret);
return ret;
}
void AcceptedLedger::insert (AcceptedLedgerTx::ref at)
{
assert (mMap.find (at->getIndex ()) == mMap.end ());
mMap.insert (std::make_pair (at->getIndex (), at));
}
AcceptedLedgerTx::pointer AcceptedLedger::getTxn (int i) const
{
map_t::const_iterator it = mMap.find (i);
if (it == mMap.end ())
return AcceptedLedgerTx::pointer ();
return it->second;
}
} // ripple

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
/*
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_ACCEPTEDLEDGER_H
#define RIPPLE_ACCEPTEDLEDGER_H
namespace ripple {
/** A ledger that has become irrevocable.
An accepted ledger is a ledger that has a sufficient number of
validations to convince the local server that it is irrevocable.
The existence of an accepted ledger implies all preceding ledgers
are accepted.
*/
/* VFALCO TODO digest this terminology clarification:
Closed and accepted refer to ledgers that have not passed the
validation threshold yet. Once they pass the threshold, they are
"Validated". Closed just means its close time has passed and no
new transactions can get in. "Accepted" means we believe it to be
the result of the a consensus process (though haven't validated
it yet).
*/
class AcceptedLedger
{
public:
typedef boost::shared_ptr<AcceptedLedger> pointer;
typedef const pointer& ret;
typedef std::map<int, AcceptedLedgerTx::pointer> map_t; // Must be an ordered map!
typedef map_t::value_type value_type;
typedef map_t::const_iterator const_iterator;
public:
static pointer makeAcceptedLedger (Ledger::ref ledger);
static void sweep ()
{
s_cache.sweep ();
}
Ledger::ref getLedger () const
{
return mLedger;
}
const map_t& getMap () const
{
return mMap;
}
int getLedgerSeq () const
{
return mLedger->getLedgerSeq ();
}
int getTxnCount () const
{
return mMap.size ();
}
static float getCacheHitRate ()
{
return s_cache.getHitRate ();
}
AcceptedLedgerTx::pointer getTxn (int) const;
private:
explicit AcceptedLedger (Ledger::ref ledger);
void insert (AcceptedLedgerTx::ref);
private:
static TaggedCache <uint256, AcceptedLedger> s_cache;
Ledger::pointer mLedger;
map_t mMap;
};
} // ripple
#endif

View File

@@ -0,0 +1,77 @@
//------------------------------------------------------------------------------
/*
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 {
AcceptedLedgerTx::AcceptedLedgerTx (std::uint32_t seq, SerializerIterator& sit)
{
Serializer txnSer (sit.getVL ());
SerializerIterator txnIt (txnSer);
mTxn = boost::make_shared<SerializedTransaction> (boost::ref (txnIt));
mRawMeta = sit.getVL ();
mMeta = boost::make_shared<TransactionMetaSet> (mTxn->getTransactionID (), seq, mRawMeta);
mAffected = mMeta->getAffectedAccounts ();
mResult = mMeta->getResultTER ();
buildJson ();
}
AcceptedLedgerTx::AcceptedLedgerTx (SerializedTransaction::ref txn, TransactionMetaSet::ref met) :
mTxn (txn), mMeta (met), mAffected (met->getAffectedAccounts ())
{
mResult = mMeta->getResultTER ();
buildJson ();
}
AcceptedLedgerTx::AcceptedLedgerTx (SerializedTransaction::ref txn, TER result) :
mTxn (txn), mResult (result), mAffected (txn->getMentionedAccounts ())
{
buildJson ();
}
std::string AcceptedLedgerTx::getEscMeta () const
{
assert (!mRawMeta.empty ());
return sqlEscape (mRawMeta);
}
void AcceptedLedgerTx::buildJson ()
{
mJson = Json::objectValue;
mJson[jss::transaction] = mTxn->getJson (0);
if (mMeta)
{
mJson[jss::meta] = mMeta->getJson (0);
mJson[jss::raw_meta] = strHex (mRawMeta);
}
mJson[jss::result] = transHuman (mResult);
if (!mAffected.empty ())
{
Json::Value& affected = (mJson[jss::affected] = Json::arrayValue);
BOOST_FOREACH (const RippleAddress & ra, mAffected)
{
affected.append (ra.humanAccountID ());
}
}
}
} // ripple

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.
*/
//==============================================================================
#ifndef RIPPLE_ACCEPTEDLEDGERTX_H
#define RIPPLE_ACCEPTEDLEDGERTX_H
namespace ripple {
/**
A transaction that is in a closed ledger.
Description
An accepted ledger transaction contains additional information that the
server needs to tell clients about the transaction. For example,
- The transaction in JSON form
- Which accounts are affected
* This is used by InfoSub to report to clients
- Cached stuff
@code
@endcode
@see {uri}
@ingroup ripple_ledger
*/
class AcceptedLedgerTx
{
public:
typedef boost::shared_ptr <AcceptedLedgerTx> pointer;
typedef const pointer& ref;
public:
AcceptedLedgerTx (LedgerIndex ledgerSeq, SerializerIterator& sit);
AcceptedLedgerTx (SerializedTransaction::ref, TransactionMetaSet::ref);
AcceptedLedgerTx (SerializedTransaction::ref, TER result);
SerializedTransaction::ref getTxn () const
{
return mTxn;
}
TransactionMetaSet::ref getMeta () const
{
return mMeta;
}
std::vector <RippleAddress> const& getAffected () const
{
return mAffected;
}
TxID getTransactionID () const
{
return mTxn->getTransactionID ();
}
TxType getTxnType () const
{
return mTxn->getTxnType ();
}
TER getResult () const
{
return mResult;
}
std::uint32_t getTxnSeq () const
{
return mMeta->getIndex ();
}
bool isApplied () const
{
return !!mMeta;
}
int getIndex () const
{
return mMeta ? mMeta->getIndex () : 0;
}
std::string getEscMeta () const;
Json::Value getJson () const
{
return mJson;
}
private:
SerializedTransaction::pointer mTxn;
TransactionMetaSet::pointer mMeta;
TER mResult;
std::vector <RippleAddress> mAffected;
Blob mRawMeta;
Json::Value mJson;
void buildJson ();
};
} // ripple
#endif

View File

@@ -0,0 +1,116 @@
//------------------------------------------------------------------------------
/*
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 {
/** Get the current ledger entry */
SLE::pointer DirectoryEntryIterator::getEntry (LedgerEntrySet& les, LedgerEntryType type)
{
return les.entryCache (type, mEntryIndex);
}
/** Position the iterator at the first entry
*/
bool DirectoryEntryIterator::firstEntry (LedgerEntrySet& les)
{
WriteLog (lsTRACE, Ledger) << "DirectoryEntryIterator::firstEntry(" <<
to_string (mRootIndex) << ")";
mEntry = 0;
mDirNode.reset ();
return nextEntry (les);
}
/** Advance the iterator to the next entry
*/
bool DirectoryEntryIterator::nextEntry (LedgerEntrySet& les)
{
if (!mDirNode)
{
WriteLog (lsTRACE, Ledger) << "DirectoryEntryIterator::nextEntry(" <<
to_string (mRootIndex) << ") need dir node";
// Are we already at the end
if (mDirIndex.isZero())
{
WriteLog (lsTRACE, Ledger) << "DirectoryEntryIterator::nextEntry(" <<
to_string (mRootIndex) << ") at end";
return false;
}
// Fetch the current directory
mDirNode = les.entryCache (ltDIR_NODE, mRootIndex);
if (!mDirNode)
{
WriteLog (lsTRACE, Ledger) << "DirectoryEntryIterator::nextEntry("
<< to_string (mRootIndex) << ") no dir node";
mEntryIndex.zero();
return false;
}
}
if (!les.dirNext (mRootIndex, mDirNode, mEntry, mEntryIndex))
{
mDirIndex.zero();
mDirNode.reset();
WriteLog (lsTRACE, Ledger) << "DirectoryEntryIterator::nextEntry(" <<
to_string (mRootIndex) << ") now at end";
return false;
}
WriteLog (lsTRACE, Ledger) << "DirectoryEntryIterator::nextEntry(" <<
to_string (mRootIndex) << ") now at " << mEntry;
return true;
}
bool DirectoryEntryIterator::addJson (Json::Value& j) const
{
if (mDirNode && (mEntry != 0))
{
j["dir_root"] = to_string (mRootIndex);
j["dir_entry"] = static_cast<Json::UInt> (mEntry);
if (mDirNode)
j["dir_index"] = to_string (mDirIndex);
return true;
}
return false;
}
bool DirectoryEntryIterator::setJson (Json::Value const& j, LedgerEntrySet& les)
{
if (!j.isMember("dir_root") || !j.isMember("dir_index") || !j.isMember("dir_entry"))
return false;
#if 0 // WRITEME
Json::Value const& dirRoot = j["dir_root"];
Json::Value const& dirIndex = j["dir_index"];
Json::Value const& dirEntry = j["dir_entry"];
assert(false); // CAUTION: This function is incomplete
mEntry = j["dir_entry"].asUInt ();
if (!mDirIndex.SetHex(j["dir_index"].asString()))
return false;
#endif
return true;
}
} // ripple

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
/*
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_DIRECTORYENTRYITERATOR_H_INCLUDED
#define RIPPLE_DIRECTORYENTRYITERATOR_H_INCLUDED
namespace ripple {
/** An iterator that walks the ledger entries in a single directory */
class DirectoryEntryIterator
{
public:
DirectoryEntryIterator ()
: mEntry(0)
{
}
DirectoryEntryIterator (uint256 const& index)
: mRootIndex(index), mEntry(0)
{
}
/** Construct from a reference to the root directory
*/
DirectoryEntryIterator (SLE::ref directory) : mEntry (0), mDirNode (directory)
{
if (mDirNode)
mRootIndex = mDirNode->getIndex();
}
/** Get the SLE this iterator currently references */
SLE::pointer getEntry (LedgerEntrySet& les, LedgerEntryType type);
/** Make this iterator point to the first offer */
bool firstEntry (LedgerEntrySet&);
/** Make this iterator point to the next offer */
bool nextEntry (LedgerEntrySet&);
/** Add this iterator's position to a JSON object */
bool addJson (Json::Value&) const;
/** Set this iterator's position from a JSON object */
bool setJson (Json::Value const&, LedgerEntrySet& les);
uint256 const& getEntryLedgerIndex () const
{
return mEntryIndex;
}
uint256 getDirectory () const
{
return mDirNode ? mDirNode->getIndex () : uint256();
}
bool
operator== (DirectoryEntryIterator const& other) const
{
return mEntry == other.mEntry && mDirIndex == other.mDirIndex;
}
bool
operator!= (DirectoryEntryIterator const& other) const
{
return ! (*this == other);
}
private:
uint256 mRootIndex; // ledger index of the root directory
uint256 mDirIndex; // ledger index of the current directory
unsigned int mEntry; // entry index we are on (0 means first is next)
uint256 mEntryIndex; // ledger index of the current entry
SLE::pointer mDirNode; // SLE for the entry we are on
};
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
//------------------------------------------------------------------------------
/*
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_INBOUNDLEDGER_H
#define RIPPLE_INBOUNDLEDGER_H
namespace ripple {
// VFALCO TODO Rename to InboundLedger
// A ledger we are trying to acquire
class InboundLedger
: public PeerSet
, public boost::enable_shared_from_this <InboundLedger>
, public CountedObject <InboundLedger>
{
public:
static char const* getCountedObjectName () { return "InboundLedger"; }
typedef boost::shared_ptr <InboundLedger> pointer;
typedef std::pair < boost::weak_ptr<Peer>, boost::shared_ptr<protocol::TMLedgerData> > PeerDataPairType;
// These are the reasons we might acquire a ledger
enum fcReason
{
fcHISTORY, // Acquiring past ledger
fcGENERIC, // Generic other reasons
fcVALIDATION, // Validations suggest this ledger is important
fcCURRENT, // This might be the current ledger
fcCONSENSUS, // We believe the consensus round requires this ledger
};
public:
InboundLedger (uint256 const& hash, std::uint32_t seq, fcReason reason, clock_type& clock);
~InboundLedger ();
bool isBase () const
{
return mHaveBase;
}
bool isAcctStComplete () const
{
return mHaveState;
}
bool isTransComplete () const
{
return mHaveTransactions;
}
bool isDone () const
{
return mAborted || isComplete () || isFailed ();
}
Ledger::ref getLedger ()
{
return mLedger;
}
void abort ()
{
mAborted = true;
}
std::uint32_t getSeq ()
{
return mSeq;
}
// VFALCO TODO Make this the Listener / Observer pattern
bool addOnComplete (std::function<void (InboundLedger::pointer)>);
void trigger (Peer::ptr const&);
bool tryLocal ();
void addPeers ();
bool checkLocal ();
void init (ScopedLockType& collectionLock);
bool gotData (boost::weak_ptr<Peer>, boost::shared_ptr<protocol::TMLedgerData>);
typedef std::pair <protocol::TMGetObjectByHash::ObjectType, uint256> neededHash_t;
std::vector<neededHash_t> getNeededHashes ();
// VFALCO TODO Replace uint256 with something semanticallyh meaningful
void filterNodes (std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& nodeHashes,
std::set<SHAMapNode>& recentNodes, int max, bool aggressive);
Json::Value getJson (int);
void runData ();
private:
void done ();
void onTimer (bool progress, ScopedLockType& peerSetLock);
void newPeer (Peer::ptr const& peer)
{
trigger (peer);
}
boost::weak_ptr <PeerSet> pmDowncast ();
int processData (boost::shared_ptr<Peer> peer, protocol::TMLedgerData& data);
bool takeBase (const std::string& data);
bool takeTxNode (const std::list<SHAMapNode>& IDs, const std::list<Blob >& data,
SHAMapAddNode&);
bool takeTxRootNode (Blob const& data, SHAMapAddNode&);
// VFALCO TODO Rename to receiveAccountStateNode
// Don't use acronyms, but if we are going to use them at least
// capitalize them correctly.
//
bool takeAsNode (const std::list<SHAMapNode>& IDs, const std::list<Blob >& data,
SHAMapAddNode&);
bool takeAsRootNode (Blob const& data, SHAMapAddNode&);
private:
Ledger::pointer mLedger;
bool mHaveBase;
bool mHaveState;
bool mHaveTransactions;
bool mAborted;
bool mSignaled;
bool mByHash;
std::uint32_t mSeq;
fcReason mReason;
std::set <SHAMapNode> mRecentTXNodes;
std::set <SHAMapNode> mRecentASNodes;
// Data we have received from peers
PeerSet::LockType mReceivedDataLock;
std::vector <PeerDataPairType> mReceivedData;
bool mReceiveDispatched;
std::vector <std::function <void (InboundLedger::pointer)> > mOnComplete;
};
} // ripple
#endif

View File

@@ -0,0 +1,405 @@
//------------------------------------------------------------------------------
/*
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 {
class InboundLedgersImp
: public InboundLedgers
, public beast::Stoppable
, public beast::LeakChecked <InboundLedgers>
{
public:
typedef std::pair<uint256, InboundLedger::pointer> u256_acq_pair;
// How long before we try again to acquire the same ledger
static const int kReacquireIntervalSeconds = 300;
InboundLedgersImp (clock_type& clock, Stoppable& parent,
beast::insight::Collector::ptr const& collector)
: Stoppable ("InboundLedgers", parent)
, m_clock (clock)
, mRecentFailures ("LedgerAcquireRecentFailures",
clock, 0, kReacquireIntervalSeconds)
, mCounter(collector->make_counter("ledger_fetches"))
{
}
// VFALCO TODO Should this be called findOrAdd ?
//
InboundLedger::pointer findCreate (uint256 const& hash, std::uint32_t seq, InboundLedger::fcReason reason)
{
assert (hash.isNonZero ());
InboundLedger::pointer ret;
// Ensure that any previous IL is destroyed outside the lock
InboundLedger::pointer oldLedger;
{
ScopedLockType sl (mLock);
if (! isStopping ())
{
if (reason == InboundLedger::fcCONSENSUS)
{
if (mConsensusLedger.isNonZero() && (mValidationLedger != mConsensusLedger) && (hash != mConsensusLedger))
{
ripple::unordered_map<uint256, InboundLedger::pointer>::iterator it = mLedgers.find (mConsensusLedger);
if (it != mLedgers.end ())
{
oldLedger = it->second;
mLedgers.erase (it);
}
}
mConsensusLedger = hash;
}
else if (reason == InboundLedger::fcVALIDATION)
{
if (mValidationLedger.isNonZero() && (mValidationLedger != mConsensusLedger) && (hash != mValidationLedger))
{
ripple::unordered_map<uint256, InboundLedger::pointer>::iterator it = mLedgers.find (mValidationLedger);
if (it != mLedgers.end ())
{
oldLedger = it->second;
mLedgers.erase (it);
}
}
mValidationLedger = hash;
}
ripple::unordered_map<uint256, InboundLedger::pointer>::iterator it = mLedgers.find (hash);
if (it != mLedgers.end ())
{
ret = it->second;
// FIXME: Should set the sequence if it's not set
}
else
{
ret = boost::make_shared <InboundLedger> (hash, seq, reason, std::ref (m_clock));
assert (ret);
mLedgers.insert (std::make_pair (hash, ret));
ret->init (sl);
++mCounter;
}
}
}
return ret;
}
InboundLedger::pointer find (uint256 const& hash)
{
assert (hash.isNonZero ());
InboundLedger::pointer ret;
{
ScopedLockType sl (mLock);
ripple::unordered_map<uint256, InboundLedger::pointer>::iterator it = mLedgers.find (hash);
if (it != mLedgers.end ())
{
ret = it->second;
}
}
return ret;
}
bool hasLedger (LedgerHash const& hash)
{
assert (hash.isNonZero ());
ScopedLockType sl (mLock);
return mLedgers.find (hash) != mLedgers.end ();
}
void dropLedger (LedgerHash const& hash)
{
assert (hash.isNonZero ());
ScopedLockType sl (mLock);
mLedgers.erase (hash);
}
/*
This gets called when
"We got some data from an inbound ledger"
inboundLedgerTrigger:
"What do we do with this partial data?"
Figures out what to do with the responses to our requests for information.
*/
// means "We got some data from an inbound ledger"
// VFALCO TODO Why is hash passed by value?
// VFALCO TODO Remove the dependency on the Peer object.
/** We received a TMLedgerData from a peer.
*/
bool gotLedgerData (LedgerHash const& hash,
boost::shared_ptr<Peer> peer,
boost::shared_ptr<protocol::TMLedgerData> packet_ptr)
{
protocol::TMLedgerData& packet = *packet_ptr;
WriteLog (lsTRACE, InboundLedger) << "Got data (" << packet.nodes ().size () << ") for acquiring ledger: " << hash;
InboundLedger::pointer ledger = find (hash);
if (!ledger)
{
WriteLog (lsTRACE, InboundLedger) << "Got data for ledger we're no longer acquiring";
// If it's state node data, stash it because it still might be useful
if (packet.type () == protocol::liAS_NODE)
{
getApp().getJobQueue().addJob(jtLEDGER_DATA, "gotStaleData",
std::bind(&InboundLedgers::gotStaleData, this, packet_ptr));
}
return false;
}
// Stash the data for later processing and see if we need to dispatch
if (ledger->gotData(boost::weak_ptr<Peer>(peer), packet_ptr))
getApp().getJobQueue().addJob (jtLEDGER_DATA, "processLedgerData",
std::bind (&InboundLedgers::doLedgerData, this,
std::placeholders::_1, hash));
return true;
}
int getFetchCount (int& timeoutCount)
{
timeoutCount = 0;
int ret = 0;
std::vector<u256_acq_pair> inboundLedgers;
{
ScopedLockType sl (mLock);
inboundLedgers.reserve(mLedgers.size());
for (auto const& it : mLedgers)
{
inboundLedgers.push_back(it);
}
}
for (auto const& it : inboundLedgers)
{
if (it.second->isActive ())
{
++ret;
timeoutCount += it.second->getTimeouts ();
}
}
return ret;
}
void logFailure (uint256 const& h)
{
mRecentFailures.insert (h);
}
bool isFailure (uint256 const& h)
{
return mRecentFailures.exists (h);
}
void doLedgerData (Job&, LedgerHash hash)
{
InboundLedger::pointer ledger = find (hash);
if (ledger)
ledger->runData ();
}
/** We got some data for a ledger we are no longer acquiring
Since we paid the price to receive it, we might as well stash it in case we need it.
Nodes are received in wire format and must be stashed/hashed in prefix format
*/
void gotStaleData (boost::shared_ptr<protocol::TMLedgerData> packet_ptr)
{
const uint256 uZero;
try
{
for (int i = 0; i < packet_ptr->nodes ().size (); ++i)
{
const protocol::TMLedgerNode& node = packet_ptr->nodes (i);
if (!node.has_nodeid () || !node.has_nodedata ())
return;
Serializer s;
SHAMapTreeNode newNode(
SHAMapNode (node.nodeid().data(), node.nodeid().size()),
Blob (node.nodedata().begin(), node.nodedata().end()),
0, snfWIRE, uZero, false);
newNode.addRaw(s, snfPREFIX);
boost::shared_ptr<Blob> blob = boost::make_shared<Blob> (s.begin(), s.end());
getApp().getOPs().addFetchPack (newNode.getNodeHash(), blob);
}
}
catch (...)
{
}
}
void clearFailures ()
{
ScopedLockType sl (mLock);
mRecentFailures.clear();
mLedgers.clear();
}
Json::Value getInfo()
{
Json::Value ret(Json::objectValue);
std::vector<u256_acq_pair> acquires;
{
ScopedLockType sl (mLock);
acquires.reserve (mLedgers.size ());
for (auto const& it : mLedgers)
{
assert (it.second);
acquires.push_back (it);
}
}
for (auto const& it : acquires)
{
std::uint32_t seq = it.second->getSeq();
if (seq > 1)
ret[beast::lexicalCastThrow <std::string>(seq)] = it.second->getJson(0);
else
ret[to_string (it.first)] = it.second->getJson(0);
}
return ret;
}
void gotFetchPack (Job&)
{
std::vector<InboundLedger::pointer> acquires;
{
ScopedLockType sl (mLock);
acquires.reserve (mLedgers.size ());
for (auto const& it : mLedgers)
{
assert (it.second);
acquires.push_back (it.second);
}
}
for (auto const& acquire : acquires)
{
acquire->checkLocal ();
}
}
void sweep ()
{
mRecentFailures.sweep ();
clock_type::time_point const now (m_clock.now());
// Make a list of things to sweep, while holding the lock
std::vector <MapType::mapped_type> stuffToSweep;
std::size_t total;
{
ScopedLockType sl (mLock);
MapType::iterator it (mLedgers.begin ());
total = mLedgers.size ();
stuffToSweep.reserve (total);
while (it != mLedgers.end ())
{
if (it->second->getLastAction () > now)
{
it->second->touch ();
++it;
}
else if ((it->second->getLastAction () + std::chrono::minutes (1)) < now)
{
stuffToSweep.push_back (it->second);
// shouldn't cause the actual final delete
// since we are holding a reference in the vector.
it = mLedgers.erase (it);
}
else
{
++it;
}
}
}
WriteLog (lsDEBUG, InboundLedger) <<
"Sweeped " << stuffToSweep.size () <<
" out of " << total << " inbound ledgers.";
}
void onStop ()
{
ScopedLockType lock (mLock);
mLedgers.clear();
mRecentFailures.clear();
stopped();
}
private:
clock_type& m_clock;
typedef ripple::unordered_map <uint256, InboundLedger::pointer> MapType;
typedef RippleRecursiveMutex LockType;
typedef std::unique_lock <LockType> ScopedLockType;
LockType mLock;
MapType mLedgers;
KeyCache <uint256> mRecentFailures;
uint256 mConsensusLedger;
uint256 mValidationLedger;
beast::insight::Counter mCounter;
};
//------------------------------------------------------------------------------
InboundLedgers::~InboundLedgers()
{
}
InboundLedgers* InboundLedgers::New (clock_type& clock, beast::Stoppable& parent,
beast::insight::Collector::ptr const& collector)
{
return new InboundLedgersImp (clock, parent, collector);
}
} // 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_INBOUNDLEDGERS_H
#define RIPPLE_INBOUNDLEDGERS_H
namespace ripple {
/** Manages the lifetime of inbound ledgers.
@see InboundLedger
*/
class InboundLedgers
{
public:
typedef beast::abstract_clock <std::chrono::seconds> clock_type;
virtual ~InboundLedgers() = 0;
// VFALCO TODO Make this a free function outside the class:
// std::unique_ptr <InboundLedger> make_InboundLedgers (...)
//
static InboundLedgers* New (clock_type& clock, beast::Stoppable& parent,
beast::insight::Collector::ptr const& collector);
// VFALCO TODO Should this be called findOrAdd ?
//
virtual InboundLedger::pointer findCreate (uint256 const& hash,
std::uint32_t seq, InboundLedger::fcReason) = 0;
virtual InboundLedger::pointer find (LedgerHash const& hash) = 0;
virtual bool hasLedger (LedgerHash const& ledgerHash) = 0;
virtual void dropLedger (LedgerHash const& ledgerHash) = 0;
// VFALCO TODO Why is hash passed by value?
// VFALCO TODO Remove the dependency on the Peer object.
//
virtual bool gotLedgerData (LedgerHash const& ledgerHash,
boost::shared_ptr<Peer>,
boost::shared_ptr <protocol::TMLedgerData>) = 0;
virtual void doLedgerData (Job&, LedgerHash hash) = 0;
virtual void gotStaleData (
boost::shared_ptr <protocol::TMLedgerData> packet) = 0;
virtual int getFetchCount (int& timeoutCount) = 0;
virtual void logFailure (uint256 const& h) = 0;
virtual bool isFailure (uint256 const& h) = 0;
virtual void clearFailures() = 0;
virtual Json::Value getInfo() = 0;
virtual void gotFetchPack (Job&) = 0;
virtual void sweep () = 0;
virtual void onStop() = 0;
};
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,540 @@
//------------------------------------------------------------------------------
/*
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_LEDGER_H
#define RIPPLE_LEDGER_H
namespace ripple {
class Job;
enum LedgerStateParms
{
lepNONE = 0, // no special flags
// input flags
lepCREATE = 1, // Create if not present
// output flags
lepOKAY = 2, // success
lepMISSING = 4, // No node in that slot
lepWRONGTYPE = 8, // Node of different type there
lepCREATED = 16, // Node was created
lepERROR = 32, // error
};
#define LEDGER_JSON_DUMP_TXRP 0x10000000
#define LEDGER_JSON_DUMP_STATE 0x20000000
#define LEDGER_JSON_EXPAND 0x40000000
#define LEDGER_JSON_FULL 0x80000000
class SqliteStatement;
class LedgerBase
{
protected:
LedgerBase ();
// VFALCO TODO eliminate the need for friends
friend class TransactionEngine;
friend class Transactor;
typedef RippleRecursiveMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
};
// VFALCO TODO figure out exactly how this thing works.
// It seems like some ledger database is stored as a global, static in the
// class. But then what is the meaning of a Ledger object? Is this
// really two classes in one? StoreOfAllLedgers + SingleLedgerObject?
//
/** Holds some or all of a ledger.
This can hold just the header, a partial set of data, or the entire set
of data. It all depends on what is in the corresponding SHAMap entry.
Various functions are provided to populate or depopulate the caches that
the object holds references to.
*/
class Ledger
: public boost::enable_shared_from_this <Ledger>
, public LedgerBase
, public CountedObject <Ledger>
, public beast::Uncopyable
{
public:
static char const* getCountedObjectName () { return "Ledger"; }
typedef boost::shared_ptr<Ledger> pointer;
typedef const boost::shared_ptr<Ledger>& ref;
enum TransResult
{
TR_ERROR = -1,
TR_SUCCESS = 0,
TR_NOTFOUND = 1,
TR_ALREADY = 2,
TR_BADTRANS = 3, // the transaction itself is corrupt
TR_BADACCT = 4, // one of the accounts is invalid
TR_INSUFF = 5, // the sending(apply)/receiving(remove) account is broke
TR_PASTASEQ = 6, // account is past this transaction
TR_PREASEQ = 7, // account is missing transactions before this
TR_BADLSEQ = 8, // ledger too early
TR_TOOSMALL = 9, // amount is less than Tx fee
};
// ledger close flags
static const std::uint32_t sLCF_NoConsensusTime = 1;
public:
Ledger (const RippleAddress & masterID, std::uint64_t startAmount); // used for the starting bootstrap ledger
Ledger (uint256 const & parentHash, uint256 const & transHash, uint256 const & accountHash,
std::uint64_t totCoins, std::uint32_t closeTime, std::uint32_t parentCloseTime,
int closeFlags, int closeResolution,
std::uint32_t ledgerSeq, bool & loaded); // used for database ledgers
Ledger (std::uint32_t ledgerSeq, std::uint32_t closeTime);
Ledger (Blob const & rawLedger, bool hasPrefix);
Ledger (const std::string & rawLedger, bool hasPrefix);
Ledger (bool dummy, Ledger & previous); // ledger after this one
Ledger (Ledger & target, bool isMutable); // snapshot
~Ledger ();
static Ledger::pointer getSQL (const std::string & sqlStatement);
static Ledger::pointer getSQL1 (SqliteStatement*);
static void getSQL2 (Ledger::ref);
static Ledger::pointer getLastFullLedger ();
static std::uint32_t roundCloseTime (std::uint32_t closeTime, std::uint32_t closeResolution);
void updateHash ();
void setClosed ()
{
mClosed = true;
}
void setValidated()
{
mValidated = true;
}
void setAccepted (std::uint32_t closeTime, int closeResolution, bool correctCloseTime);
void setAccepted ();
void setImmutable ();
bool isClosed ()
{
return mClosed;
}
bool isAccepted ()
{
return mAccepted;
}
bool isValidated ()
{
return mValidated;
}
bool isImmutable ()
{
return mImmutable;
}
bool isFixed ()
{
return mClosed || mImmutable;
}
void setFull ()
{
mTransactionMap->setLedgerSeq (mLedgerSeq);
mAccountStateMap->setLedgerSeq (mLedgerSeq);
}
// ledger signature operations
void addRaw (Serializer & s) const;
void setRaw (Serializer & s, bool hasPrefix);
uint256 getHash ();
uint256 const& getParentHash () const
{
return mParentHash;
}
uint256 const& getTransHash () const
{
return mTransHash;
}
uint256 const& getAccountHash () const
{
return mAccountHash;
}
std::uint64_t getTotalCoins () const
{
return mTotCoins;
}
void destroyCoins (std::uint64_t fee)
{
mTotCoins -= fee;
}
void setTotalCoins (std::uint64_t totCoins)
{
mTotCoins = totCoins;
}
std::uint32_t getCloseTimeNC () const
{
return mCloseTime;
}
std::uint32_t getParentCloseTimeNC () const
{
return mParentCloseTime;
}
std::uint32_t getLedgerSeq () const
{
return mLedgerSeq;
}
int getCloseResolution () const
{
return mCloseResolution;
}
bool getCloseAgree () const
{
return (mCloseFlags & sLCF_NoConsensusTime) == 0;
}
// close time functions
void setCloseTime (std::uint32_t ct)
{
assert (!mImmutable);
mCloseTime = ct;
}
void setCloseTime (boost::posix_time::ptime);
boost::posix_time::ptime getCloseTime () const;
// low level functions
SHAMap::ref peekTransactionMap ()
{
return mTransactionMap;
}
SHAMap::ref peekAccountStateMap ()
{
return mAccountStateMap;
}
void dropCache ()
{
assert (isImmutable ());
if (mTransactionMap)
mTransactionMap->dropCache ();
if (mAccountStateMap)
mAccountStateMap->dropCache ();
}
// returns false on error
bool addSLE (SLE const& sle);
// ledger sync functions
void setAcquiring (void);
bool isAcquiring (void);
bool isAcquiringTx (void);
bool isAcquiringAS (void);
// Transaction Functions
bool addTransaction (uint256 const & id, const Serializer & txn);
bool addTransaction (uint256 const & id, const Serializer & txn, const Serializer & metaData);
bool hasTransaction (uint256 const & TransID) const
{
return mTransactionMap->hasItem (TransID);
}
Transaction::pointer getTransaction (uint256 const & transID) const;
bool getTransaction (uint256 const & transID, Transaction::pointer & txn, TransactionMetaSet::pointer & txMeta);
bool getTransactionMeta (uint256 const & transID, TransactionMetaSet::pointer & txMeta);
bool getMetaHex (uint256 const & transID, std::string & hex);
static SerializedTransaction::pointer getSTransaction (SHAMapItem::ref, SHAMapTreeNode::TNType);
SerializedTransaction::pointer getSMTransaction (SHAMapItem::ref, SHAMapTreeNode::TNType,
TransactionMetaSet::pointer & txMeta);
// high-level functions
bool hasAccount (const RippleAddress & acctID);
AccountState::pointer getAccountState (const RippleAddress & acctID);
LedgerStateParms writeBack (LedgerStateParms parms, SLE::ref);
SLE::pointer getAccountRoot (const uint160 & accountID);
SLE::pointer getAccountRoot (const RippleAddress & naAccountID);
void updateSkipList ();
void visitAccountItems (const uint160 & acctID, std::function<void (SLE::ref)>);
void visitStateItems (std::function<void (SLE::ref)>);
// database functions (low-level)
static Ledger::pointer loadByIndex (std::uint32_t ledgerIndex);
static Ledger::pointer loadByHash (uint256 const & ledgerHash);
static uint256 getHashByIndex (std::uint32_t index);
static bool getHashesByIndex (std::uint32_t index, uint256 & ledgerHash, uint256 & parentHash);
static std::map< std::uint32_t, std::pair<uint256, uint256> >
getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq);
bool pendSaveValidated (bool isSynchronous, bool isCurrent);
// next/prev function
SLE::pointer getSLE (uint256 const & uHash); // SLE is mutable
SLE::pointer getSLEi (uint256 const & uHash); // SLE is immutable
// VFALCO NOTE These seem to let you walk the list of ledgers
//
uint256 getFirstLedgerIndex ();
uint256 getLastLedgerIndex ();
uint256 getNextLedgerIndex (uint256 const & uHash); // first node >hash
uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd); // first node >hash, <end
uint256 getPrevLedgerIndex (uint256 const & uHash); // last node <hash
uint256 getPrevLedgerIndex (uint256 const & uHash, uint256 const & uBegin); // last node <hash, >begin
// Ledger hash table function
static uint256 getLedgerHashIndex ();
static uint256 getLedgerHashIndex (std::uint32_t desiredLedgerIndex);
static int getLedgerHashOffset (std::uint32_t desiredLedgerIndex);
static int getLedgerHashOffset (std::uint32_t desiredLedgerIndex, std::uint32_t currentLedgerIndex);
uint256 getLedgerHash (std::uint32_t ledgerIndex);
std::vector< std::pair<std::uint32_t, uint256> > getLedgerHashes ();
static uint256 getLedgerAmendmentIndex ();
static uint256 getLedgerFeeIndex ();
std::vector<uint256> getLedgerAmendments ();
std::vector<uint256> getNeededTransactionHashes (int max, SHAMapSyncFilter * filter);
std::vector<uint256> getNeededAccountStateHashes (int max, SHAMapSyncFilter * filter);
// index calculation functions
static uint256 getAccountRootIndex (const uint160 & uAccountID);
static uint256 getAccountRootIndex (const RippleAddress & account)
{
return getAccountRootIndex (account.getAccountID ());
}
//
// Generator Map functions
//
SLE::pointer getGenerator (const uint160 & uGeneratorID);
static uint256 getGeneratorIndex (const uint160 & uGeneratorID);
//
// Nickname functions
//
static uint256 getNicknameHash (const std::string & strNickname)
{
Serializer s (strNickname);
return s.getSHA256 ();
}
NicknameState::pointer getNicknameState (uint256 const & uNickname);
NicknameState::pointer getNicknameState (const std::string & strNickname)
{
return getNicknameState (getNicknameHash (strNickname));
}
SLE::pointer getNickname (uint256 const & uNickname);
SLE::pointer getNickname (const std::string & strNickname)
{
return getNickname (getNicknameHash (strNickname));
}
static uint256 getNicknameIndex (uint256 const & uNickname);
//
// Order book functions
//
// Order book dirs have a base so we can use next to step through them in quality order.
static bool isValidBook (const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuerID,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuerID);
static uint256 getBookBase (const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuerID,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuerID);
//
// Offer functions
//
SLE::pointer getOffer (uint256 const & uIndex);
SLE::pointer getOffer (const uint160 & uAccountID, std::uint32_t uSequence)
{
return getOffer (getOfferIndex (uAccountID, uSequence));
}
// The index of an offer.
static uint256 getOfferIndex (const uint160 & uAccountID, std::uint32_t uSequence);
//
// Owner functions
//
// VFALCO NOTE This is a simple math operation that converts the account ID
// into a 256 bit object (I think....need to research this)
//
// All items controlled by an account are here: offers
static uint256 getOwnerDirIndex (const uint160 & uAccountID);
//
// Directory functions
// Directories are doubly linked lists of nodes.
// Given a directory root and and index compute the index of a node.
static uint256 getDirNodeIndex (uint256 const & uDirRoot, const std::uint64_t uNodeIndex = 0);
static void ownerDirDescriber (SLE::ref, bool, const uint160 & owner);
// Return a node: root or normal
SLE::pointer getDirNode (uint256 const & uNodeIndex);
//
// Quality
//
static uint256 getQualityIndex (uint256 const & uBase, const std::uint64_t uNodeDir = 0);
static uint256 getQualityNext (uint256 const & uBase);
static std::uint64_t getQuality (uint256 const & uBase);
static void qualityDirDescriber (SLE::ref, bool,
const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuer,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuer,
const std::uint64_t & uRate);
//
// Ripple functions : credit lines
//
// Index of node which is the ripple state between two accounts for a currency.
// VFALCO NOTE Rename these to make it clear they are simple functions that
// don't access global variables. e.g. "calculateKeyFromRippleStateAndAddress"
//
static uint256 getRippleStateIndex (const RippleAddress & naA, const RippleAddress & naB, const uint160 & uCurrency);
static uint256 getRippleStateIndex (const uint160 & uiA, const uint160 & uiB, const uint160 & uCurrency)
{
return getRippleStateIndex (RippleAddress::createAccountID (uiA), RippleAddress::createAccountID (uiB), uCurrency);
}
SLE::pointer getRippleState (uint256 const & uNode);
SLE::pointer getRippleState (const RippleAddress & naA, const RippleAddress & naB, const uint160 & uCurrency)
{
return getRippleState (getRippleStateIndex (naA, naB, uCurrency));
}
SLE::pointer getRippleState (const uint160 & uiA, const uint160 & uiB, const uint160 & uCurrency)
{
return getRippleState (getRippleStateIndex (RippleAddress::createAccountID (uiA), RippleAddress::createAccountID (uiB), uCurrency));
}
std::uint32_t getReferenceFeeUnits ()
{
if (!mBaseFee) updateFees ();
return mReferenceFeeUnits;
}
std::uint64_t getBaseFee ()
{
if (!mBaseFee) updateFees ();
return mBaseFee;
}
std::uint64_t getReserve (int increments)
{
if (!mBaseFee) updateFees ();
return scaleFeeBase (static_cast<std::uint64_t> (increments) * mReserveIncrement + mReserveBase);
}
std::uint64_t getReserveInc ()
{
if (!mBaseFee) updateFees ();
return mReserveIncrement;
}
std::uint64_t scaleFeeBase (std::uint64_t fee);
std::uint64_t scaleFeeLoad (std::uint64_t fee, bool bAdmin);
static std::set<std::uint32_t> getPendingSaves();
Json::Value getJson (int options);
void addJson (Json::Value&, int options);
bool walkLedger ();
bool assertSane ();
protected:
SLE::pointer getASNode (LedgerStateParms & parms, uint256 const & nodeID, LedgerEntryType let);
// returned SLE is immutable
SLE::pointer getASNodeI (uint256 const & nodeID, LedgerEntryType let);
void saveValidatedLedgerAsync(Job&, bool current)
{
saveValidatedLedger(current);
}
bool saveValidatedLedger (bool current);
void updateFees ();
private:
void initializeFees ();
private:
// The basic Ledger structure, can be opened, closed, or synching
uint256 mHash;
uint256 mParentHash;
uint256 mTransHash;
uint256 mAccountHash;
std::uint64_t mTotCoins;
std::uint32_t mLedgerSeq;
std::uint32_t mCloseTime; // when this ledger closed
std::uint32_t mParentCloseTime; // when the previous ledger closed
int mCloseResolution; // the resolution for this ledger close time (2-120 seconds)
std::uint32_t mCloseFlags; // flags indicating how this ledger close took place
bool mClosed, mValidated, mValidHash, mAccepted, mImmutable;
std::uint32_t mReferenceFeeUnits; // Fee units for the reference transaction
std::uint32_t mReserveBase, mReserveIncrement; // Reserve basse and increment in fee units
std::uint64_t mBaseFee; // Ripple cost of the reference transaction
SHAMap::pointer mTransactionMap;
SHAMap::pointer mAccountStateMap;
typedef RippleMutex StaticLockType;
typedef std::lock_guard <StaticLockType> StaticScopedLockType;
// ledgers not fully saved, validated ledger present but DB may not be correct yet
static StaticLockType sPendingSaveLock;
static std::set<std::uint32_t> sPendingSaves;
};
inline LedgerStateParms operator| (const LedgerStateParms& l1, const LedgerStateParms& l2)
{
return static_cast<LedgerStateParms> (static_cast<int> (l1) | static_cast<int> (l2));
}
inline LedgerStateParms operator& (const LedgerStateParms& l1, const LedgerStateParms& l2)
{
return static_cast<LedgerStateParms> (static_cast<int> (l1) & static_cast<int> (l2));
}
} // ripple
#endif

View File

@@ -0,0 +1,450 @@
//------------------------------------------------------------------------------
/*
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 {
/*
LedgerCleaner
Cleans up the ledger. Specifically, resolves these issues:
1. Older versions could leave the SQLite account and transaction databases in
an inconsistent state. The cleaner identifies these inconsistencies and
resolves them.
2. Upon request, checks for missing nodes in a ledger and triggers a fetch.
*/
class LedgerCleanerImp
: public LedgerCleaner
, public beast::Thread
, public beast::LeakChecked <LedgerCleanerImp>
{
public:
struct State
{
State()
: minRange (0)
, maxRange (0)
, checkNodes (false)
, fixTxns (false)
, failures (0)
{
}
LedgerIndex minRange; // The lowest ledger in the range we're checking
LedgerIndex maxRange; // The highest ledger in the range we're checking
bool checkNodes; // Check all state/transaction nodes
bool fixTxns; // Rewrite SQL databases
int failures; // Number of errors encountered since last success
};
typedef beast::SharedData <State> SharedState;
SharedState m_state;
beast::Journal m_journal;
//--------------------------------------------------------------------------
LedgerCleanerImp (
Stoppable& stoppable,
beast::Journal journal)
: LedgerCleaner (stoppable)
, Thread ("LedgerCleaner")
, m_journal (journal)
{
}
~LedgerCleanerImp ()
{
stopThread ();
}
//--------------------------------------------------------------------------
//
// Stoppable
//
//--------------------------------------------------------------------------
void onPrepare ()
{
}
void onStart ()
{
startThread();
}
void onStop ()
{
m_journal.info << "Stopping";
signalThreadShouldExit();
notify();
}
//--------------------------------------------------------------------------
//
// PropertyStream
//
//--------------------------------------------------------------------------
void onWrite (beast::PropertyStream::Map& map)
{
SharedState::Access state (m_state);
if (state->maxRange == 0)
map["status"] = "idle";
else
{
map["status"] = "running";
map["ledger_min"] = state->minRange;
map["ledger_max"] = state->maxRange;
map["check_nodes"] = state->checkNodes ? "true" : "false";
map["fix_txns"] = state->fixTxns ? "true" : "false";
if (state->failures > 0)
map["fail_counts"] = state->failures;
}
}
//--------------------------------------------------------------------------
//
// LedgerCleaner
//
//--------------------------------------------------------------------------
void doClean (Json::Value const& params)
{
LedgerIndex minRange;
LedgerIndex maxRange;
getApp().getLedgerMaster().getFullValidatedRange (minRange, maxRange);
{
SharedState::Access state (m_state);
state->maxRange = maxRange;
state->minRange = minRange;
state->checkNodes = false;
state->fixTxns = false;
state->failures = 0;
/*
JSON Parameters:
All parameters are optional. By default the cleaner cleans
things it thinks are necessary. This behavior can be modified
using the following options supplied via JSON RPC:
"ledger"
A single unsigned integer representing an individual
ledger to clean.
"min_ledger", "max_ledger"
Unsigned integers representing the starting and ending
ledger numbers to clean. If unspecified, clean all ledgers.
"full"
A boolean. When set to true, means clean everything possible.
"fix_txns"
A boolean value indicating whether or not to fix the
transactions in the database as well.
"check_nodes"
A boolean, when set to true means check the nodes.
"stop"
A boolean, when set to true informs the cleaner to gracefully
stop its current activities if any cleaning is taking place.
*/
// Quick way to fix a single ledger
if (params.isMember("ledger"))
{
state->maxRange = params["ledger"].asUInt();
state->minRange = params["ledger"].asUInt();
state->fixTxns = true;
state->checkNodes = true;
}
if (params.isMember("max_ledger"))
state->maxRange = params["max_ledger"].asUInt();
if (params.isMember("min_ledger"))
state->minRange = params["min_ledger"].asUInt();
if (params.isMember("full"))
state->fixTxns = state->checkNodes = params["full"].asBool();
if (params.isMember("fix_txns"))
state->fixTxns = params["fix_txns"].asBool();
if (params.isMember("check_nodes"))
state->checkNodes = params["check_nodes"].asBool();
if (params.isMember("stop") && params["stop"].asBool())
state->minRange = state->maxRange = 0;
}
notify();
}
//--------------------------------------------------------------------------
//
// LedgerCleanerImp
//
//--------------------------------------------------------------------------
void init ()
{
m_journal.debug << "Initializing";
}
void run ()
{
m_journal.debug << "Started";
init ();
while (! this->threadShouldExit())
{
this->wait ();
if (! this->threadShouldExit())
{
doLedgerCleaner();
}
}
stopped();
}
LedgerHash getLedgerHash(Ledger::pointer ledger, LedgerIndex index)
{
LedgerHash hash;
try
{
hash = ledger->getLedgerHash(index);
}
catch (SHAMapMissingNode &)
{
m_journal.warning <<
"Node missing from ledger " << ledger->getLedgerSeq();
getApp().getInboundLedgers().findCreate (
ledger->getHash(), ledger->getLedgerSeq(), InboundLedger::fcGENERIC);
}
return hash;
}
/** Process a single ledger
@param ledgerIndex The index of the ledger to process.
@param ledgerHash The known correct hash of the ledger.
@param doNodes Ensure all ledger nodes are in the node db.
@param doTxns Reprocess (account) transactions to SQL databases.
@return `true` if the ledger was cleaned.
*/
bool doLedger(
LedgerIndex const& ledgerIndex,
LedgerHash const& ledgerHash,
bool doNodes,
bool doTxns)
{
Ledger::pointer nodeLedger = getApp().getLedgerMaster().findAcquireLedger(ledgerIndex, ledgerHash);
if (!nodeLedger)
{
m_journal.debug << "Ledger " << ledgerIndex << " not available";
return false;
}
Ledger::pointer dbLedger = Ledger::loadByIndex(ledgerIndex);
if (! dbLedger ||
(dbLedger->getHash() != ledgerHash) ||
(dbLedger->getParentHash() != nodeLedger->getParentHash()))
{
// Ideally we'd also check for more than one ledger with that index
m_journal.debug <<
"Ledger " << ledgerIndex << " mismatches SQL DB";
doTxns = true;
}
if(! getApp().getLedgerMaster().fixIndex(ledgerIndex, ledgerHash))
{
m_journal.debug << "ledger " << ledgerIndex << " had wrong entry in history";
doTxns = true;
}
if (doNodes && !nodeLedger->walkLedger())
{
m_journal.debug << "Ledger " << ledgerIndex << " is missing nodes";
getApp().getInboundLedgers().findCreate(ledgerHash, ledgerIndex, InboundLedger::fcGENERIC);
return false;
}
if (doTxns && !nodeLedger->pendSaveValidated(true, false))
{
m_journal.debug << "Failed to save ledger " << ledgerIndex;
return false;
}
nodeLedger->dropCache();
return true;
}
/** Returns the hash of the specified ledger.
@param ledgerIndex The index of the desired ledger.
@param referenceLedger [out] An optional known good subsequent ledger.
@return The hash of the ledger. This will be all-bits-zero if not found.
*/
LedgerHash getHash(
LedgerIndex const& ledgerIndex,
Ledger::pointer& referenceLedger)
{
LedgerHash ledgerHash;
if (!referenceLedger || (referenceLedger->getLedgerSeq() < ledgerIndex))
{
referenceLedger = getApp().getLedgerMaster().getValidatedLedger();
if (!referenceLedger)
{
m_journal.warning << "No validated ledger";
return ledgerHash; // Nothing we can do. No validated ledger.
}
}
if (referenceLedger->getLedgerSeq() >= ledgerIndex)
{
// See if the hash for the ledger we need is in the reference ledger
ledgerHash = getLedgerHash(referenceLedger, ledgerIndex);
if (ledgerHash.isZero())
{
// No, Try to get another ledger that might have the hash we need
// Compute the index and hash of a ledger that will have the hash we need
LedgerIndex refIndex = (ledgerIndex + 255) & (~255);
LedgerHash refHash = getLedgerHash (referenceLedger, refIndex);
bool const nonzero (refHash.isNonZero ());
assert (nonzero);
if (nonzero)
{
// We found the hash and sequence of a better reference ledger
referenceLedger = getApp().getLedgerMaster().findAcquireLedger (refIndex, refHash);
if (referenceLedger)
ledgerHash = getLedgerHash(referenceLedger, ledgerIndex);
}
}
}
else
m_journal.warning << "Validated ledger is prior to target ledger";
return ledgerHash;
}
/** Run the ledger cleaner. */
void doLedgerCleaner()
{
Ledger::pointer goodLedger;
while (! this->threadShouldExit())
{
LedgerIndex ledgerIndex;
LedgerHash ledgerHash;
bool doNodes;
bool doTxns;
while (getApp().getFeeTrack().isLoadedLocal())
{
m_journal.debug << "Waiting for load to subside";
sleep(5000);
if (this->threadShouldExit ())
return;
}
{
SharedState::Access state (m_state);
if ((state->minRange > state->maxRange) ||
(state->maxRange == 0) || (state->minRange == 0))
{
state->minRange = state->maxRange = 0;
return;
}
ledgerIndex = state->maxRange;
doNodes = state->checkNodes;
doTxns = state->fixTxns;
}
ledgerHash = getHash(ledgerIndex, goodLedger);
bool fail = false;
if (ledgerHash.isZero())
{
m_journal.info << "Unable to get hash for ledger " << ledgerIndex;
fail = true;
}
else if (!doLedger(ledgerIndex, ledgerHash, doNodes, doTxns))
{
m_journal.info << "Failed to process ledger " << ledgerIndex;
fail = true;
}
if (fail)
{
{
SharedState::Access state (m_state);
++state->failures;
}
sleep(2000); // Wait for acquiring to catch up to us
}
else
{
{
SharedState::Access state (m_state);
if (ledgerIndex == state->minRange)
++state->minRange;
if (ledgerIndex == state->maxRange)
--state->maxRange;
state->failures = 0;
}
sleep(100); // Reduce I/O pressure a bit
}
}
}
};
//------------------------------------------------------------------------------
LedgerCleaner::LedgerCleaner (Stoppable& parent)
: Stoppable ("LedgerCleaner", parent)
, beast::PropertyStream::Source ("ledgercleaner")
{
}
LedgerCleaner::~LedgerCleaner ()
{
}
LedgerCleaner* LedgerCleaner::New (
Stoppable& parent,
beast::Journal journal)
{
return new LedgerCleanerImp (parent, journal);
}
} // ripple

View File

@@ -0,0 +1,59 @@
//------------------------------------------------------------------------------
/*
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_LEDGERCLEANER_H_INCLUDED
#define RIPPLE_LEDGERCLEANER_H_INCLUDED
namespace ripple {
/** Check the ledger/transaction databases to make sure they have continuity */
class LedgerCleaner
: public beast::Stoppable
, public beast::PropertyStream::Source
{
protected:
explicit LedgerCleaner (Stoppable& parent);
public:
/** Create a new object.
The caller receives ownership and must delete the object when done.
*/
static LedgerCleaner* New (
Stoppable& parent,
beast::Journal journal);
/** Destroy the object. */
virtual ~LedgerCleaner () = 0;
/** Start a long running task to clean the ledger.
The ledger is cleaned asynchronously, on an implementation defined
thread. This function call does not block. The long running task
will be stopped if the Stoppable stops.
Thread safety:
Safe to call from any thread at any time.
@param parameters A Json object with configurable parameters.
*/
virtual void doClean (Json::Value const& parameters) = 0;
};
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,294 @@
//------------------------------------------------------------------------------
/*
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_LEDGERENTRYSET_H
#define RIPPLE_LEDGERENTRYSET_H
namespace ripple {
enum TransactionEngineParams
{
tapNONE = 0x00,
tapNO_CHECK_SIGN = 0x01, // Signature already checked
tapOPEN_LEDGER = 0x10, // Transaction is running against an open ledger
// true = failures are not forwarded, check transaction fee
// false = debit ledger for consumed funds
tapRETRY = 0x20, // This is not the transaction's last pass
// Transaction can be retried, soft failures allowed
tapADMIN = 0x400, // Transaction came from a privileged source
};
enum LedgerEntryAction
{
taaNONE,
taaCACHED, // Unmodified.
taaMODIFY, // Modifed, must have previously been taaCACHED.
taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY.
taaCREATE, // Newly created.
};
class LedgerEntrySetEntry
: public CountedObject <LedgerEntrySetEntry>
{
public:
static char const* getCountedObjectName () { return "LedgerEntrySetEntry"; }
SLE::pointer mEntry;
LedgerEntryAction mAction;
int mSeq;
LedgerEntrySetEntry (SLE::ref e, LedgerEntryAction a, int s)
: mEntry (e)
, mAction (a)
, mSeq (s)
{
}
};
/** An LES is a LedgerEntrySet.
It's a view into a ledger used while a transaction is processing.
The transaction manipulates the LES rather than the ledger
(because it's cheaper, can be checkpointed, and so on). When the
transaction finishes, the LES is committed into the ledger to make
the modifications. The transaction metadata is built from the LES too.
*/
class LedgerEntrySet
: public CountedObject <LedgerEntrySet>
{
public:
static char const* getCountedObjectName () { return "LedgerEntrySet"; }
LedgerEntrySet (Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false) :
mLedger (ledger), mParams (tep), mSeq (0), mImmutable (immutable)
{
}
LedgerEntrySet () : mParams (tapNONE), mSeq (0), mImmutable (false)
{
}
// set functions
void setImmutable ()
{
mImmutable = true;
}
bool isImmutable () const
{
return mImmutable;
}
LedgerEntrySet duplicate () const; // Make a duplicate of this set
void setTo (const LedgerEntrySet&); // Set this set to have the same contents as another
void swapWith (LedgerEntrySet&); // Swap the contents of two sets
void invalidate ()
{
mLedger.reset ();
}
bool isValid () const
{
return mLedger != nullptr;
}
int getSeq () const
{
return mSeq;
}
TransactionEngineParams getParams () const
{
return mParams;
}
void bumpSeq ()
{
++mSeq;
}
void init (Ledger::ref ledger, uint256 const & transactionID,
std::uint32_t ledgerID, TransactionEngineParams params);
void clear ();
Ledger::pointer& getLedger ()
{
return mLedger;
}
Ledger::ref getLedgerRef () const
{
return mLedger;
}
// basic entry functions
SLE::pointer getEntry (uint256 const & index, LedgerEntryAction&);
LedgerEntryAction hasEntry (uint256 const & index) const;
void entryCache (SLE::ref); // Add this entry to the cache
void entryCreate (SLE::ref); // This entry will be created
void entryDelete (SLE::ref); // This entry will be deleted
void entryModify (SLE::ref); // This entry will be modified
bool hasChanges (); // True if LES has any changes
// higher-level ledger functions
SLE::pointer entryCreate (LedgerEntryType letType, uint256 const & uIndex);
SLE::pointer entryCache (LedgerEntryType letType, uint256 const & uIndex);
// Directory functions.
TER dirAdd (
std::uint64_t & uNodeDir, // Node of entry.
uint256 const & uRootIndex,
uint256 const & uLedgerIndex,
std::function<void (SLE::ref, bool)> fDescriber);
TER dirDelete (
const bool bKeepRoot,
const std::uint64_t & uNodeDir, // Node item is mentioned in.
uint256 const & uRootIndex,
uint256 const & uLedgerIndex, // Item being deleted
const bool bStable,
const bool bSoft);
bool dirFirst (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirNext (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirIsEmpty (uint256 const & uDirIndex);
TER dirCount (uint256 const & uDirIndex, std::uint32_t & uCount);
uint256 getNextLedgerIndex (uint256 const & uHash);
uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd);
void ownerCountAdjust (const uint160 & uOwnerID, int iAmount, SLE::ref sleAccountRoot = SLE::pointer ());
// Offer functions.
TER offerDelete (uint256 const & uOfferIndex);
TER offerDelete (SLE::pointer sleOffer);
// Balance functions.
std::uint32_t rippleTransferRate (const uint160 & uIssuerID);
std::uint32_t rippleTransferRate (const uint160 & uSenderID, const uint160 & uReceiverID, const uint160 & uIssuerID);
STAmount rippleOwed (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID);
STAmount rippleLimit (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID);
std::uint32_t rippleQualityIn (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID,
SField::ref sfLow = sfLowQualityIn, SField::ref sfHigh = sfHighQualityIn);
std::uint32_t rippleQualityOut (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID)
{
return rippleQualityIn (uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut);
}
STAmount rippleHolds (const uint160 & uAccountID, const uint160 & uCurrencyID, const uint160 & uIssuerID);
STAmount rippleTransferFee (const uint160 & uSenderID, const uint160 & uReceiverID, const uint160 & uIssuerID, const STAmount & saAmount);
TER rippleCredit (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount, bool bCheckIssuer = true);
TER rippleSend (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount, STAmount & saActual);
STAmount accountHolds (const uint160 & uAccountID, const uint160 & uCurrencyID, const uint160 & uIssuerID);
STAmount accountFunds (const uint160 & uAccountID, const STAmount & saDefault);
TER accountSend (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount);
TER trustCreate (
const bool bSrcHigh,
const uint160 & uSrcAccountID,
const uint160 & uDstAccountID,
uint256 const & uIndex,
SLE::ref sleAccount,
const bool bAuth,
const bool bNoRipple,
const STAmount & saSrcBalance,
const STAmount & saSrcLimit,
const std::uint32_t uSrcQualityIn = 0,
const std::uint32_t uSrcQualityOut = 0);
TER trustDelete (SLE::ref sleRippleState, const uint160 & uLowAccountID, const uint160 & uHighAccountID);
Json::Value getJson (int) const;
void calcRawMeta (Serializer&, TER result, std::uint32_t index);
// iterator functions
typedef std::map<uint256, LedgerEntrySetEntry>::iterator iterator;
typedef std::map<uint256, LedgerEntrySetEntry>::const_iterator const_iterator;
bool isEmpty () const
{
return mEntries.empty ();
}
std::map<uint256, LedgerEntrySetEntry>::const_iterator begin () const
{
return mEntries.begin ();
}
std::map<uint256, LedgerEntrySetEntry>::const_iterator end () const
{
return mEntries.end ();
}
std::map<uint256, LedgerEntrySetEntry>::iterator begin ()
{
return mEntries.begin ();
}
std::map<uint256, LedgerEntrySetEntry>::iterator end ()
{
return mEntries.end ();
}
void setDeliveredAmount (STAmount const& amt)
{
mSet.setDeliveredAmount (amt);
}
private:
Ledger::pointer mLedger;
std::map<uint256, LedgerEntrySetEntry> mEntries; // cannot be unordered!
TransactionMetaSet mSet;
TransactionEngineParams mParams;
int mSeq;
bool mImmutable;
LedgerEntrySet (Ledger::ref ledger, const std::map<uint256, LedgerEntrySetEntry>& e,
const TransactionMetaSet & s, int m) :
mLedger (ledger), mEntries (e), mSet (s), mParams (tapNONE), mSeq (m), mImmutable (false)
{
;
}
SLE::pointer getForMod (uint256 const & node, Ledger::ref ledger,
ripple::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx (const RippleAddress & threadTo, Ledger::ref ledger,
ripple::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx (SLE::ref threadTo, Ledger::ref ledger, ripple::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners (SLE::ref node, Ledger::ref ledger, ripple::unordered_map<uint256, SLE::pointer>& newMods);
};
inline LedgerEntrySet::iterator range_begin (LedgerEntrySet& x)
{
return x.begin ();
}
inline LedgerEntrySet::iterator range_end (LedgerEntrySet& x)
{
return x.end ();
}
} // ripple
#endif

View File

@@ -0,0 +1,194 @@
//------------------------------------------------------------------------------
/*
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 {
// VFALCO TODO replace macros
#ifndef CACHED_LEDGER_NUM
#define CACHED_LEDGER_NUM 96
#endif
#ifndef CACHED_LEDGER_AGE
#define CACHED_LEDGER_AGE 120
#endif
// FIXME: Need to clean up ledgers by index at some point
LedgerHistory::LedgerHistory ()
: m_ledgers_by_hash ("LedgerCache", CACHED_LEDGER_NUM, CACHED_LEDGER_AGE,
get_seconds_clock (), LogPartition::getJournal <TaggedCacheLog> ())
, m_consensus_validated ("ConsensusValidated", 64, 300,
get_seconds_clock (), LogPartition::getJournal <TaggedCacheLog> ())
{
}
bool LedgerHistory::addLedger (Ledger::pointer ledger, bool validated)
{
assert (ledger && ledger->isImmutable ());
assert (ledger->peekAccountStateMap ()->getHash ().isNonZero ());
LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());
const bool alreadyHad = m_ledgers_by_hash.canonicalize (ledger->getHash(), ledger, true);
if (validated)
mLedgersByIndex[ledger->getLedgerSeq()] = ledger->getHash();
return alreadyHad;
}
uint256 LedgerHistory::getLedgerHash (std::uint32_t index)
{
LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());
std::map<std::uint32_t, uint256>::iterator it (mLedgersByIndex.find (index));
if (it != mLedgersByIndex.end ())
return it->second;
return uint256 ();
}
Ledger::pointer LedgerHistory::getLedgerBySeq (std::uint32_t index)
{
{
LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());
std::map <std::uint32_t, uint256>::iterator it (mLedgersByIndex.find (index));
if (it != mLedgersByIndex.end ())
{
uint256 hash = it->second;
sl.unlock ();
return getLedgerByHash (hash);
}
}
Ledger::pointer ret (Ledger::loadByIndex (index));
if (!ret)
return ret;
assert (ret->getLedgerSeq () == index);
{
// Add this ledger to the local tracking by index
LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());
assert (ret->isImmutable ());
m_ledgers_by_hash.canonicalize (ret->getHash (), ret);
mLedgersByIndex[ret->getLedgerSeq ()] = ret->getHash ();
return (ret->getLedgerSeq () == index) ? ret : Ledger::pointer ();
}
}
Ledger::pointer LedgerHistory::getLedgerByHash (uint256 const& hash)
{
Ledger::pointer ret = m_ledgers_by_hash.fetch (hash);
if (ret)
{
assert (ret->isImmutable ());
assert (ret->getHash () == hash);
return ret;
}
ret = Ledger::loadByHash (hash);
if (!ret)
return ret;
assert (ret->isImmutable ());
assert (ret->getHash () == hash);
m_ledgers_by_hash.canonicalize (ret->getHash (), ret);
assert (ret->getHash () == hash);
return ret;
}
void LedgerHistory::builtLedger (Ledger::ref ledger)
{
LedgerIndex index = ledger->getLedgerSeq();
LedgerHash hash = ledger->getHash();
assert (!hash.isZero());
ConsensusValidated::ScopedLockType sl (
m_consensus_validated.peekMutex());
auto entry = boost::make_shared<std::pair< LedgerHash, LedgerHash >>();
m_consensus_validated.canonicalize(index, entry, false);
if (entry->first != hash)
{
if (entry->first.isNonZero() && (entry->first != hash))
{
WriteLog (lsERROR, LedgerMaster) << "MISMATCH: seq=" << index << " built:" << entry->first << " then:" << hash;
}
if (entry->second.isNonZero() && (entry->second != hash))
{
WriteLog (lsERROR, LedgerMaster) << "MISMATCH: seq=" << index << " validated:" << entry->second << " accepted:" << hash;
}
entry->first = hash;
}
}
void LedgerHistory::validatedLedger (Ledger::ref ledger)
{
LedgerIndex index = ledger->getLedgerSeq();
LedgerHash hash = ledger->getHash();
assert (!hash.isZero());
ConsensusValidated::ScopedLockType sl (
m_consensus_validated.peekMutex());
boost::shared_ptr< std::pair< LedgerHash, LedgerHash > > entry = boost::make_shared<std::pair< LedgerHash, LedgerHash >>();
m_consensus_validated.canonicalize(index, entry, false);
if (entry->second != hash)
{
if (entry->second.isNonZero() && (entry->second != hash))
{
WriteLog (lsERROR, LedgerMaster) << "MISMATCH: seq=" << index << " validated:" << entry->second << " then:" << hash;
}
if (entry->first.isNonZero() && (entry->first != hash))
{
WriteLog (lsERROR, LedgerMaster) << "MISMATCH: seq=" << index << " built:" << entry->first << " validated:" << hash;
}
entry->second = hash;
}
}
/** Ensure m_ledgers_by_hash doesn't have the wrong hash for a particular index
*/
bool LedgerHistory::fixIndex (LedgerIndex ledgerIndex, LedgerHash const& ledgerHash)
{
LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());
std::map<std::uint32_t, uint256>::iterator it (mLedgersByIndex.find (ledgerIndex));
if ((it != mLedgersByIndex.end ()) && (it->second != ledgerHash) )
{
it->second = ledgerHash;
return false;
}
return true;
}
void LedgerHistory::tune (int size, int age)
{
m_ledgers_by_hash.setTargetSize (size);
m_ledgers_by_hash.setTargetAge (age);
}
} // ripple

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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGERHISTORY_H
#define RIPPLE_LEDGERHISTORY_H
namespace ripple {
// VFALCO TODO Rename to OldLedgers ?
/** Retains historical ledgers. */
class LedgerHistory : beast::LeakChecked <LedgerHistory>
{
public:
LedgerHistory ();
/** Track a ledger
@return `true` if the ledger was already tracked
*/
bool addLedger (Ledger::pointer ledger, bool validated);
/** Get the ledgers_by_hash cache hit rate
@return the hit rate
*/
float getCacheHitRate ()
{
return m_ledgers_by_hash.getHitRate ();
}
/** Get a ledger given its squence number
@param ledgerIndex The sequence number of the desired ledger
*/
Ledger::pointer getLedgerBySeq (LedgerIndex ledgerIndex);
/** Get a ledger's hash given its sequence number
@param ledgerIndex The sequence number of the desired ledger
@return The hash of the specified ledger
*/
LedgerHash getLedgerHash (LedgerIndex ledgerIndex);
/** Retrieve a ledger given its hash
@param ledgerHash The hash of the requested ledger
@return The ledger requested
*/
Ledger::pointer getLedgerByHash (LedgerHash const& ledgerHash);
/** Set the history cache's paramters
@param size The target size of the cache
@param age The target age of the cache, in seconds
*/
void tune (int size, int age);
/** Remove stale cache entries
*/
void sweep ()
{
m_ledgers_by_hash.sweep ();
m_consensus_validated.sweep ();
}
/** Report that we have locally built a particular ledger
*/
void builtLedger (Ledger::ref);
/** Report that we have validated a particular ledger
*/
void validatedLedger (Ledger::ref);
/** Repair a hash to index mapping
@param ledgerIndex The index whose mapping is to be repaired
@param ledgerHash The hash it is to be mapped to
@return `true` if the mapping was repaired
*/
bool fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash);
private:
typedef TaggedCache <LedgerHash, Ledger> LedgersByHash;
LedgersByHash m_ledgers_by_hash;
// Maps ledger indexes to the corresponding hashes
// For debug and logging purposes
// 1) The hash of a ledger with that index we build
// 2) The hash of a ledger with that index we validated
typedef TaggedCache <LedgerIndex,
std::pair< LedgerHash, LedgerHash >> ConsensusValidated;
ConsensusValidated m_consensus_validated;
// Maps ledger indexes to the corresponding hash.
std::map <LedgerIndex, LedgerHash> mLedgersByIndex; // validated ledgers
};
} // ripple
#endif

View File

@@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
/*
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_LEDGERHOLDER_H
#define RIPPLE_LEDGERHOLDER_H
namespace ripple {
// Can std::atomic<std::shared_ptr>> make this lock free?
/** Hold a ledger in a thread-safe way.
*/
class LedgerHolder
{
public:
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
// Update the held ledger
void set (Ledger::pointer ledger)
{
// The held ledger must always be immutable
if (ledger && !ledger->isImmutable ())
ledger = boost::make_shared <Ledger> (*ledger, false);
{
ScopedLockType sl (m_lock);
m_heldLedger = ledger;
}
}
// Return the (immutable) held ledger
Ledger::pointer get ()
{
ScopedLockType sl (m_lock);
return m_heldLedger;
}
// Return a mutable snapshot of the held ledger
Ledger::pointer getMutable ()
{
Ledger::pointer ret = get ();
return ret ? boost::make_shared <Ledger> (*ret, true) : ret;
}
bool empty ()
{
ScopedLockType sl (m_lock);
return m_heldLedger == nullptr;
}
private:
LockType m_lock;
Ledger::pointer m_heldLedger;
};
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
//------------------------------------------------------------------------------
/*
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_LEDGERMASTER_H_INCLUDED
#define RIPPLE_LEDGERMASTER_H_INCLUDED
namespace ripple {
// Tracks the current ledger and any ledgers in the process of closing
// Tracks ledger history
// Tracks held transactions
// VFALCO TODO Rename to Ledgers
// It sounds like this holds all the ledgers...
//
class LedgerMaster
: public beast::Stoppable
{
protected:
explicit LedgerMaster (Stoppable& parent);
public:
typedef std::function <void (Ledger::ref)> callback;
public:
typedef RippleRecursiveMutex LockType;
typedef std::unique_lock <LockType> ScopedLockType;
typedef beast::GenericScopedUnlock <LockType> ScopedUnlockType;
static LedgerMaster* New (Stoppable& parent, beast::Journal journal);
virtual ~LedgerMaster () = 0;
virtual LedgerIndex getCurrentLedgerIndex () = 0;
virtual LedgerIndex getValidLedgerIndex () = 0;
virtual LockType& peekMutex () = 0;
// The current ledger is the ledger we believe new transactions should go in
virtual Ledger::pointer getCurrentLedger () = 0;
// The finalized ledger is the last closed/accepted ledger
virtual Ledger::pointer getClosedLedger () = 0;
// The validated ledger is the last fully validated ledger
virtual Ledger::pointer getValidatedLedger () = 0;
// This is the last ledger we published to clients and can lag the validated ledger
virtual Ledger::ref getPublishedLedger () = 0;
virtual int getPublishedLedgerAge () = 0;
virtual int getValidatedLedgerAge () = 0;
virtual bool isCaughtUp(std::string& reason) = 0;
virtual TER doTransaction (
SerializedTransaction::ref txn,
TransactionEngineParams params, bool& didApply) = 0;
virtual int getMinValidations () = 0;
virtual void setMinValidations (int v) = 0;
virtual std::uint32_t getEarliestFetch () = 0;
virtual void pushLedger (Ledger::pointer newLedger) = 0;
virtual void pushLedger (Ledger::pointer newLCL, Ledger::pointer newOL) = 0;
virtual bool storeLedger (Ledger::pointer) = 0;
virtual void forceValid (Ledger::pointer) = 0;
virtual void setFullLedger (Ledger::pointer ledger, bool isSynchronous, bool isCurrent) = 0;
virtual void switchLedgers (Ledger::pointer lastClosed, Ledger::pointer newCurrent) = 0;
virtual void failedSave(std::uint32_t seq, uint256 const& hash) = 0;
virtual std::string getCompleteLedgers () = 0;
virtual void applyHeldTransactions () = 0;
/** Get a ledger's hash by sequence number using the cache
*/
virtual uint256 getHashBySeq (std::uint32_t index) = 0;
/** Walk to a ledger's hash using the skip list
*/
virtual uint256 walkHashBySeq (std::uint32_t index) = 0;
virtual uint256 walkHashBySeq (std::uint32_t index, Ledger::ref referenceLedger) = 0;
virtual Ledger::pointer findAcquireLedger (std::uint32_t index, uint256 const& hash) = 0;
virtual Ledger::pointer getLedgerBySeq (std::uint32_t index) = 0;
virtual Ledger::pointer getLedgerByHash (uint256 const& hash) = 0;
virtual void setLedgerRangePresent (std::uint32_t minV, std::uint32_t maxV) = 0;
virtual uint256 getLedgerHash(std::uint32_t desiredSeq, Ledger::ref knownGoodLedger) = 0;
virtual void addHeldTransaction (Transaction::ref trans) = 0;
virtual void fixMismatch (Ledger::ref ledger) = 0;
virtual bool haveLedgerRange (std::uint32_t from, std::uint32_t to) = 0;
virtual bool haveLedger (std::uint32_t seq) = 0;
virtual void clearLedger (std::uint32_t seq) = 0;
virtual bool getValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVal) = 0;
virtual bool getFullValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVal) = 0;
virtual void tune (int size, int age) = 0;
virtual void sweep () = 0;
virtual float getCacheHitRate () = 0;
virtual void addValidateCallback (callback& c) = 0;
virtual void checkAccept (Ledger::ref ledger) = 0;
virtual void checkAccept (uint256 const& hash, std::uint32_t seq) = 0;
virtual void consensusBuilt (Ledger::ref ledger) = 0;
virtual LedgerIndex getBuildingLedger () = 0;
virtual void setBuildingLedger (LedgerIndex index) = 0;
virtual void tryAdvance () = 0;
virtual void newPathRequest () = 0;
virtual bool isNewPathRequest () = 0;
virtual void newOrderBookDB () = 0;
virtual bool fixIndex (LedgerIndex ledgerIndex, LedgerHash const& ledgerHash) = 0;
virtual void doLedgerCleaner(const Json::Value& parameters) = 0;
virtual beast::PropertyStream::Source& getPropertySource () = 0;
static bool shouldAcquire (std::uint32_t currentLedgerID,
std::uint32_t ledgerHistory, std::uint32_t targetLedger);
};
} // ripple
#endif

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.
*/
//==============================================================================
namespace ripple {
LedgerProposal::LedgerProposal (uint256 const& pLgr, std::uint32_t seq,
uint256 const& tx, std::uint32_t closeTime,
const RippleAddress& naPeerPublic, uint256 const& suppression) :
mPreviousLedger (pLgr), mCurrentHash (tx), mSuppression (suppression), mCloseTime (closeTime),
mProposeSeq (seq), mPublicKey (naPeerPublic)
{
// XXX Validate key.
// if (!mKey->SetPubKey(pubKey))
// throw std::runtime_error("Invalid public key in proposal");
mPeerID = mPublicKey.getNodeID ();
mTime = boost::posix_time::second_clock::universal_time ();
}
LedgerProposal::LedgerProposal (const RippleAddress& naPub, const RippleAddress& naPriv,
uint256 const& prevLgr, uint256 const& position,
std::uint32_t closeTime) :
mPreviousLedger (prevLgr), mCurrentHash (position), mCloseTime (closeTime), mProposeSeq (0),
mPublicKey (naPub), mPrivateKey (naPriv)
{
mPeerID = mPublicKey.getNodeID ();
mTime = boost::posix_time::second_clock::universal_time ();
}
LedgerProposal::LedgerProposal (uint256 const& prevLgr, uint256 const& position,
std::uint32_t closeTime) :
mPreviousLedger (prevLgr), mCurrentHash (position), mCloseTime (closeTime), mProposeSeq (0)
{
mTime = boost::posix_time::second_clock::universal_time ();
}
uint256 LedgerProposal::getSigningHash () const
{
Serializer s ((32 + 32 + 32 + 256 + 256) / 8);
s.add32 (getConfig ().SIGN_PROPOSAL);
s.add32 (mProposeSeq);
s.add32 (mCloseTime);
s.add256 (mPreviousLedger);
s.add256 (mCurrentHash);
return s.getSHA512Half ();
}
// Compute a unique identifier for this signed proposal
uint256 LedgerProposal::computeSuppressionID (
uint256 const& proposeHash,
uint256 const& previousLedger,
std::uint32_t proposeSeq,
std::uint32_t closeTime,
Blob const& pubKey,
Blob const& signature)
{
Serializer s (512);
s.add256 (proposeHash);
s.add256 (previousLedger);
s.add32 (proposeSeq);
s.add32 (closeTime);
s.addVL (pubKey);
s.addVL (signature);
return s.getSHA512Half ();
}
bool LedgerProposal::checkSign (const std::string& signature, uint256 const& signingHash)
{
return mPublicKey.verifyNodePublic (signingHash, signature, ECDSA::not_strict);
}
bool LedgerProposal::changePosition (uint256 const& newPosition, std::uint32_t closeTime)
{
if (mProposeSeq == seqLeave)
return false;
mCurrentHash = newPosition;
mCloseTime = closeTime;
mTime = boost::posix_time::second_clock::universal_time ();
++mProposeSeq;
return true;
}
void LedgerProposal::bowOut ()
{
mTime = boost::posix_time::second_clock::universal_time ();
mProposeSeq = seqLeave;
}
Blob LedgerProposal::sign (void)
{
Blob ret;
mPrivateKey.signNodePrivate (getSigningHash (), ret);
// XXX If this can fail, find out sooner.
// if (!mPrivateKey.signNodePrivate(getSigningHash(), ret))
// throw std::runtime_error("unable to sign proposal");
mSuppression = computeSuppressionID (mCurrentHash, mPreviousLedger, mProposeSeq,
mCloseTime, mPublicKey.getNodePublic (), ret);
return ret;
}
Json::Value LedgerProposal::getJson () const
{
Json::Value ret = Json::objectValue;
ret["previous_ledger"] = to_string (mPreviousLedger);
if (mProposeSeq != seqLeave)
{
ret["transaction_hash"] = to_string (mCurrentHash);
ret["propose_seq"] = mProposeSeq;
}
ret["close_time"] = mCloseTime;
if (mPublicKey.isValid ())
ret["peer_id"] = mPublicKey.humanNodePublic ();
return ret;
}
} // ripple

View File

@@ -0,0 +1,148 @@
//------------------------------------------------------------------------------
/*
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 __PROPOSELEDGER__
#define __PROPOSELEDGER__
namespace ripple {
class LedgerProposal
: public CountedObject <LedgerProposal>
{
public:
static char const* getCountedObjectName () { return "LedgerProposal"; }
static const std::uint32_t seqLeave = 0xffffffff; // leaving the consensus process
typedef boost::shared_ptr<LedgerProposal> pointer;
typedef const pointer& ref;
// proposal from peer
LedgerProposal (uint256 const & prevLgr, std::uint32_t proposeSeq, uint256 const & propose,
std::uint32_t closeTime, const RippleAddress & naPeerPublic, uint256 const & suppress);
// our first proposal
LedgerProposal (const RippleAddress & pubKey, const RippleAddress & privKey,
uint256 const & prevLedger, uint256 const & position, std::uint32_t closeTime);
// an unsigned "dummy" proposal for nodes not validating
LedgerProposal (uint256 const & prevLedger, uint256 const & position, std::uint32_t closeTime);
uint256 getSigningHash () const;
bool checkSign (const std::string & signature, uint256 const & signingHash);
bool checkSign (const std::string & signature)
{
return checkSign (signature, getSigningHash ());
}
bool checkSign ()
{
return checkSign (mSignature, getSigningHash ());
}
const uint160& getPeerID () const
{
return mPeerID;
}
uint256 const& getCurrentHash () const
{
return mCurrentHash;
}
uint256 const& getPrevLedger () const
{
return mPreviousLedger;
}
uint256 const& getSuppressionID () const
{
return mSuppression;
}
std::uint32_t getProposeSeq () const
{
return mProposeSeq;
}
std::uint32_t getCloseTime () const
{
return mCloseTime;
}
const RippleAddress& peekPublic () const
{
return mPublicKey;
}
Blob getPubKey () const
{
return mPublicKey.getNodePublic ();
}
Blob sign ();
void setPrevLedger (uint256 const & prevLedger)
{
mPreviousLedger = prevLedger;
}
void setSignature (const std::string & signature)
{
mSignature = signature;
}
bool hasSignature ()
{
return !mSignature.empty ();
}
bool isPrevLedger (uint256 const & pl)
{
return mPreviousLedger == pl;
}
bool isBowOut ()
{
return mProposeSeq == seqLeave;
}
const boost::posix_time::ptime getCreateTime ()
{
return mTime;
}
bool isStale (boost::posix_time::ptime cutoff)
{
return mTime <= cutoff;
}
bool changePosition (uint256 const & newPosition, std::uint32_t newCloseTime);
void bowOut ();
Json::Value getJson () const;
static uint256 computeSuppressionID (
uint256 const& proposeHash,
uint256 const& previousLedger,
std::uint32_t proposeSeq,
std::uint32_t closeTime,
Blob const& pubKey,
Blob const& signature);
private:
uint256 mPreviousLedger, mCurrentHash, mSuppression;
std::uint32_t mCloseTime, mProposeSeq;
uint160 mPeerID;
RippleAddress mPublicKey;
RippleAddress mPrivateKey; // If ours
std::string mSignature; // set only if needed
boost::posix_time::ptime mTime;
};
} // 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.
*/
//==============================================================================
namespace ripple {
// VFALCO Should rename ContinuousLedgerTiming to LedgerTiming
struct LedgerTiming; // for Log
SETUP_LOG (LedgerTiming)
// NOTE: First and last times must be repeated
int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 120, 120 };
// Called when a ledger is open and no close is in progress -- when a transaction is received and no close
// is in process, or when a close completes. Returns the number of seconds the ledger should be be open.
bool ContinuousLedgerTiming::shouldClose (
bool anyTransactions,
int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed this ledgers
int proposersValidated, // proposers who have validated the last closed ledger
int previousMSeconds, // milliseconds the previous ledger took to reach consensus
int currentMSeconds, // milliseconds since the previous ledger closed
int openMSeconds, // milliseconds since the previous LCL was computed
int idleInterval) // network's desired idle interval
{
if ((previousMSeconds < -1000) || (previousMSeconds > 600000) ||
(currentMSeconds < -1000) || (currentMSeconds > 600000))
{
WriteLog (lsWARNING, LedgerTiming) <<
"CLC::shouldClose range Trans=" << (anyTransactions ? "yes" : "no") <<
" Prop: " << previousProposers << "/" << proposersClosed <<
" Secs: " << currentMSeconds << " (last: " << previousMSeconds << ")";
return true;
}
if (!anyTransactions)
{
// no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
{
WriteLog (lsTRACE, LedgerTiming) <<
"no transactions, many proposers: now (" << proposersClosed <<
" closed, " << previousProposers << " before)";
return true;
}
#if 0 // This false triggers on the genesis ledger
if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close
{
WriteLog (lsTRACE, LedgerTiming) << "was slow to converge (p=" << (previousMSeconds) << ")";
if (previousMSeconds < 2000)
return previousMSeconds;
return previousMSeconds - 1000;
}
#endif
return currentMSeconds >= (idleInterval * 1000); // normal idle
}
if ((openMSeconds < LEDGER_MIN_CLOSE) && ((proposersClosed + proposersValidated) < (previousProposers / 2 )))
{
WriteLog (lsDEBUG, LedgerTiming) <<
"Must wait minimum time before closing";
return false;
}
if ((currentMSeconds < previousMSeconds) && ((proposersClosed + proposersValidated) < previousProposers))
{
WriteLog (lsDEBUG, LedgerTiming) <<
"We are waiting for more closes/validations";
return false;
}
return true; // this ledger should close now
}
// Returns whether we have a consensus or not. If so, we expect all honest nodes
// to already have everything they need to accept a consensus. Our vote is 'locked in'.
bool ContinuousLedgerTiming::haveConsensus (
int previousProposers, // proposers in the last closing (not including us)
int currentProposers, // proposers in this closing so far (not including us)
int currentAgree, // proposers who agree with us
int currentFinished, // proposers who have validated a ledger after this one
int previousAgreeTime, // how long it took to agree on the last ledger
int currentAgreeTime, // how long we've been trying to agree
bool forReal, // deciding whether to stop consensus process
bool& failed) // we can't reach a consensus
{
WriteLog (lsTRACE, LedgerTiming) <<
"CLC::haveConsensus: prop=" << currentProposers <<
"/" << previousProposers <<
" agree=" << currentAgree << " validated=" << currentFinished <<
" time=" << currentAgreeTime << "/" << previousAgreeTime <<
(forReal ? "" : "X");
if (currentAgreeTime <= LEDGER_MIN_CONSENSUS)
return false;
if (currentProposers < (previousProposers * 3 / 4))
{
// Less than 3/4 of the last ledger's proposers are present, we may need more time
if (currentAgreeTime < (previousAgreeTime + LEDGER_MIN_CONSENSUS))
{
CondLog (forReal, lsTRACE, LedgerTiming) <<
"too fast, not enough proposers";
return false;
}
}
// If 80% of current proposers (plus us) agree on a set, we have consensus
if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsINFO, LedgerTiming) << "normal consensus";
failed = false;
return true;
}
// If 80% of the nodes on your UNL have moved on, you should declare consensus
if (((currentFinished * 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsWARNING, LedgerTiming) <<
"We see no consensus, but 80% of nodes have moved on";
failed = true;
return true;
}
// no consensus yet
CondLog (forReal, lsTRACE, LedgerTiming) << "no consensus";
return false;
}
int ContinuousLedgerTiming::getNextLedgerTimeResolution (int previousResolution, bool previousAgree, int ledgerSeq)
{
assert (ledgerSeq);
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
{
// reduce resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i + 1];
}
if ((previousAgree) && ((ledgerSeq % LEDGER_RES_INCREASE) == 0))
{
// increase resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i - 1];
}
return previousResolution;
}
} // ripple

View File

@@ -0,0 +1,111 @@
//------------------------------------------------------------------------------
/*
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 __LEDGERTIMING__
#define __LEDGERTIMING__
namespace ripple {
// The number of seconds a ledger may remain idle before closing
const int LEDGER_IDLE_INTERVAL = 15;
// The number of seconds a validation remains current after its ledger's close time
// This is a safety to protect against very old validations and the time it takes to adjust
// the close time accuracy window
const int LEDGER_VAL_INTERVAL = 300;
// The number of seconds before a close time that we consider a validation acceptable
// This protects against extreme clock errors
const int LEDGER_EARLY_INTERVAL = 180;
// The number of milliseconds we wait minimum to ensure participation
const int LEDGER_MIN_CONSENSUS = 2000;
// The number of milliseconds we wait minimum to ensure others have computed the LCL
const int LEDGER_MIN_CLOSE = 2000;
// Initial resolution of ledger close time
const int LEDGER_TIME_ACCURACY = 30;
// How often to increase resolution
const int LEDGER_RES_INCREASE = 8;
// How often to decrease resolution
const int LEDGER_RES_DECREASE = 1;
// How often we check state or change positions (in milliseconds)
const int LEDGER_GRANULARITY = 1000;
// The percentage of active trusted validators that must be able to
// keep up with the network or we consider the network overloaded
const int LEDGER_NET_RATIO = 70;
// How long we consider a proposal fresh
const int PROPOSE_FRESHNESS = 20;
// How often we force generating a new proposal to keep ours fresh
const int PROPOSE_INTERVAL = 12;
// Avalanche tuning
// percentage of nodes on our UNL that must vote yes
const int AV_INIT_CONSENSUS_PCT = 50;
// percentage of previous close time before we advance
const int AV_MID_CONSENSUS_TIME = 50;
// percentage of nodes that most vote yes after advancing
const int AV_MID_CONSENSUS_PCT = 65;
// percentage of previous close time before we advance
const int AV_LATE_CONSENSUS_TIME = 85;
// percentage of nodes that most vote yes after advancing
const int AV_LATE_CONSENSUS_PCT = 70;
const int AV_STUCK_CONSENSUS_TIME = 200;
const int AV_STUCK_CONSENSUS_PCT = 95;
const int AV_CT_CONSENSUS_PCT = 75;
class ContinuousLedgerTiming
{
public:
static int LedgerTimeResolution[];
// Returns the number of seconds the ledger was or should be open
// Call when a consensus is reached and when any transaction is relayed to be added
static bool shouldClose (
bool anyTransactions,
int previousProposers, int proposersClosed, int proposerersValidated,
int previousMSeconds, int currentMSeconds, int openMSeconds,
int idleInterval);
static bool haveConsensus (
int previousProposers, int currentProposers,
int currentAgree, int currentClosed,
int previousAgreeTime, int currentAgreeTime,
bool forReal, bool& failed);
static int getNextLedgerTimeResolution (int previousResolution, bool previousAgree, int ledgerSeq);
};
} // ripple
#endif

View File

@@ -0,0 +1,339 @@
//------------------------------------------------------------------------------
/*
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 {
SETUP_LOG (OrderBookDB)
OrderBookDB::OrderBookDB (Stoppable& parent)
: Stoppable ("OrderBookDB", parent)
, mSeq (0)
{
}
void OrderBookDB::invalidate ()
{
ScopedLockType sl (mLock);
mSeq = 0;
}
void OrderBookDB::setup (Ledger::ref ledger)
{
{
ScopedLockType sl (mLock);
// Do a full update every 256 ledgers
if (mSeq != 0)
{
if (ledger->getLedgerSeq () == mSeq)
return;
if ((ledger->getLedgerSeq () > mSeq) && ((ledger->getLedgerSeq () - mSeq) < 256))
return;
if ((ledger->getLedgerSeq () < mSeq) && ((mSeq - ledger->getLedgerSeq ()) < 16))
return;
}
WriteLog (lsDEBUG, OrderBookDB) << "Advancing from " << mSeq << " to " << ledger->getLedgerSeq();
mSeq = ledger->getLedgerSeq ();
}
if (getConfig().RUN_STANDALONE)
update(ledger);
else
getApp().getJobQueue().addJob(jtUPDATE_PF, "OrderBookDB::update",
std::bind(&OrderBookDB::update, this, ledger));
}
static void updateHelper (SLE::ref entry,
boost::unordered_set< uint256 >& seen,
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> >& destMap,
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> >& sourceMap,
boost::unordered_set< RippleAsset >& XRPBooks,
int& books)
{
if ((entry->getType () == ltDIR_NODE) && (entry->isFieldPresent (sfExchangeRate)) &&
(entry->getFieldH256 (sfRootIndex) == entry->getIndex()))
{
const uint160& ci = entry->getFieldH160 (sfTakerPaysCurrency);
const uint160& co = entry->getFieldH160 (sfTakerGetsCurrency);
const uint160& ii = entry->getFieldH160 (sfTakerPaysIssuer);
const uint160& io = entry->getFieldH160 (sfTakerGetsIssuer);
uint256 index = Ledger::getBookBase (ci, ii, co, io);
if (seen.insert (index).second)
{
// VFALCO TODO Reduce the clunkiness of these parameter wrappers
OrderBook::pointer book = boost::make_shared<OrderBook> (boost::cref (index),
boost::cref (ci), boost::cref (co), boost::cref (ii), boost::cref (io));
sourceMap[RippleAssetRef (ci, ii)].push_back (book);
destMap[RippleAssetRef (co, io)].push_back (book);
if (co.isZero())
XRPBooks.insert(RippleAssetRef (ci, ii));
++books;
}
}
}
void OrderBookDB::update (Ledger::pointer ledger)
{
boost::unordered_set< uint256 > seen;
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> > destMap;
ripple::unordered_map< RippleAsset, std::vector<OrderBook::pointer> > sourceMap;
boost::unordered_set< RippleAsset > XRPBooks;
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB::update>";
// walk through the entire ledger looking for orderbook entries
int books = 0;
try
{
ledger->visitStateItems(std::bind(&updateHelper, std::placeholders::_1,
boost::ref(seen), boost::ref(destMap),
boost::ref(sourceMap), boost::ref(XRPBooks), boost::ref(books)));
}
catch (const SHAMapMissingNode&)
{
WriteLog (lsINFO, OrderBookDB) << "OrderBookDB::update encountered a missing node";
ScopedLockType sl (mLock);
mSeq = 0;
return;
}
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB::update< " << books << " books found";
{
ScopedLockType sl (mLock);
mXRPBooks.swap(XRPBooks);
mSourceMap.swap(sourceMap);
mDestMap.swap(destMap);
}
getApp().getLedgerMaster().newOrderBookDB();
}
void OrderBookDB::addOrderBook(const uint160& ci, const uint160& co,
const uint160& ii, const uint160& io)
{
bool toXRP = co.isZero();
ScopedLockType sl (mLock);
if (toXRP)
{ // We don't want to search through all the to-XRP or from-XRP order books!
for (auto ob : mSourceMap[RippleAssetRef(ci, ii)])
{
if (ob->getCurrencyOut().isZero ()) // also to XRP
return;
}
}
else
{
for (auto ob : mDestMap[RippleAssetRef(co, io)])
{
if ((ob->getCurrencyIn() == ci) && (ob->getIssuerIn() == ii))
return;
}
}
uint256 index = Ledger::getBookBase(ci, ii, co, io);
OrderBook::pointer book = boost::make_shared<OrderBook> (boost::cref (index),
boost::cref (ci), boost::cref (co), boost::cref (ii), boost::cref (io));
mSourceMap[RippleAssetRef (ci, ii)].push_back (book);
mDestMap[RippleAssetRef (co, io)].push_back (book);
if (toXRP)
mXRPBooks.insert(RippleAssetRef (ci, ii));
}
// return list of all orderbooks that want this issuerID and currencyID
void OrderBookDB::getBooksByTakerPays (RippleIssuer const& issuerID, RippleCurrency const& currencyID,
std::vector<OrderBook::pointer>& bookRet)
{
ScopedLockType sl (mLock);
auto it = mSourceMap.find (RippleAssetRef (currencyID, issuerID));
if (it != mSourceMap.end ())
bookRet = it->second;
else
bookRet.clear ();
}
bool OrderBookDB::isBookToXRP(RippleIssuer const& issuerID, RippleCurrency const& currencyID)
{
ScopedLockType sl (mLock);
return mXRPBooks.count(RippleAssetRef(currencyID, issuerID)) > 0;
}
// return list of all orderbooks that give this issuerID and currencyID
void OrderBookDB::getBooksByTakerGets (RippleIssuer const& issuerID, RippleCurrency const& currencyID,
std::vector<OrderBook::pointer>& bookRet)
{
ScopedLockType sl (mLock);
auto it = mDestMap.find (RippleAssetRef (currencyID, issuerID));
if (it != mDestMap.end ())
bookRet = it->second;
else
bookRet.clear ();
}
BookListeners::pointer OrderBookDB::makeBookListeners (RippleCurrency const& currencyPays, RippleCurrency const& currencyGets,
RippleIssuer const& issuerPays, RippleIssuer const& issuerGets)
{
ScopedLockType sl (mLock);
BookListeners::pointer ret = getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
if (!ret)
{
ret = boost::make_shared<BookListeners> ();
mListeners [RippleBookRef (
RippleAssetRef (currencyPays, issuerPays),
RippleAssetRef (currencyGets, issuerGets))] = ret;
assert (getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets) == ret);
}
return ret;
}
BookListeners::pointer OrderBookDB::getBookListeners (RippleCurrency const& currencyPays, RippleCurrency const& currencyGets,
RippleIssuer const& issuerPays, RippleIssuer const& issuerGets)
{
BookListeners::pointer ret;
ScopedLockType sl (mLock);
MapType::iterator it0 (mListeners.find (RippleBookRef (
RippleAssetRef (currencyPays, issuerPays),
RippleAssetRef (currencyGets, issuerGets))));
if (it0 != mListeners.end ())
ret = it0->second;
return ret;
}
// Based on the meta, send the meta to the streams that are listening
// We need to determine which streams a given meta effects
void OrderBookDB::processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value const& jvObj)
{
ScopedLockType sl (mLock);
if (alTx.getResult () == tesSUCCESS)
{
// check if this is an offer or an offer cancel or a payment that consumes an offer
//check to see what the meta looks like
for (auto& node : alTx.getMeta ()->getNodes ())
{
try
{
if (node.getFieldU16 (sfLedgerEntryType) == ltOFFER)
{
SField* field = nullptr;
// We need a field that contains the TakerGets and TakerPays parameters
if (node.getFName () == sfModifiedNode)
{
field = &sfPreviousFields;
}
else if (node.getFName () == sfCreatedNode)
{
field = &sfNewFields;
}
else if (node.getFName () == sfDeletedNode)
{
field = &sfFinalFields;
}
if (field)
{
const STObject* data = dynamic_cast<const STObject*> (node.peekAtPField (*field));
if (data)
{
const STAmount& takerGets = data->getFieldAmount (sfTakerGets);
RippleCurrency const& currencyGets = takerGets.getCurrency ();
RippleIssuer const& issuerGets = takerGets.getIssuer ();
const STAmount& takerPays = data->getFieldAmount (sfTakerPays);
RippleCurrency const& currencyPays = takerPays.getCurrency ();
RippleIssuer const& issuerPays = takerPays.getIssuer ();
// determine the OrderBook
BookListeners::pointer book =
getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
if (book)
book->publish (jvObj);
}
}
}
}
catch (...)
{
WriteLog (lsINFO, OrderBookDB) << "Fields not found in OrderBookDB::processTxn";
}
}
}
}
//------------------------------------------------------------------------------
BookListeners::BookListeners ()
{
}
void BookListeners::addSubscriber (InfoSub::ref sub)
{
ScopedLockType sl (mLock);
mListeners[sub->getSeq ()] = sub;
}
void BookListeners::removeSubscriber (std::uint64_t seq)
{
ScopedLockType sl (mLock);
mListeners.erase (seq);
}
void BookListeners::publish (Json::Value const& jvObj)
{
Json::FastWriter jfwWriter;
std::string sObj = jfwWriter.write (jvObj);
ScopedLockType sl (mLock);
NetworkOPs::SubMapType::const_iterator it = mListeners.begin ();
while (it != mListeners.end ())
{
InfoSub::pointer p = it->second.lock ();
if (p)
{
p->send (jvObj, sObj, true);
++it;
}
else
it = mListeners.erase (it);
}
}
} // ripple

View File

@@ -0,0 +1,106 @@
//------------------------------------------------------------------------------
/*
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_ORDERBOOKDB_H_INCLUDED
#define RIPPLE_ORDERBOOKDB_H_INCLUDED
namespace ripple {
// VFALCO TODO Add Javadoc comment explaining what this class does
class BookListeners
{
public:
typedef boost::shared_ptr<BookListeners> pointer;
BookListeners ();
void addSubscriber (InfoSub::ref sub);
void removeSubscriber (std::uint64_t sub);
void publish (Json::Value const& jvObj);
private:
typedef RippleRecursiveMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
// VFALCO TODO Use a typedef for the uint64
// Use a typedef for the container
ripple::unordered_map<std::uint64_t, InfoSub::wptr> mListeners;
};
//------------------------------------------------------------------------------
// VFALCO TODO Add Javadoc comment explaining what this class does
class OrderBookDB
: public beast::Stoppable
, public beast::LeakChecked <OrderBookDB>
{
public:
explicit OrderBookDB (Stoppable& parent);
void setup (Ledger::ref ledger);
void update (Ledger::pointer ledger);
void invalidate ();
void addOrderBook(const uint160& takerPaysCurrency, const uint160& takerGetsCurrency,
const uint160& takerPaysIssuer, const uint160& takerGetsIssuer);
// return list of all orderbooks that want this issuerID and currencyID
void getBooksByTakerPays (RippleIssuer const& issuerID, RippleCurrency const& currencyID,
std::vector<OrderBook::pointer>& bookRet);
void getBooksByTakerGets (RippleIssuer const& issuerID, RippleCurrency const& currencyID,
std::vector<OrderBook::pointer>& bookRet);
bool isBookToXRP (RippleIssuer const& issuerID, RippleCurrency const& currencyID);
BookListeners::pointer getBookListeners (RippleCurrency const& currencyPays, RippleCurrency const& currencyGets,
RippleIssuer const& issuerPays, RippleIssuer const& issuerGets);
BookListeners::pointer makeBookListeners (RippleCurrency const& currencyPays, RippleCurrency const& currencyGets,
RippleIssuer const& issuerPays, RippleIssuer const& issuerGets);
// see if this txn effects any orderbook
void processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value const& jvObj);
private:
// by ci/ii
ripple::unordered_map <RippleAsset,
std::vector <OrderBook::pointer>> mSourceMap;
// by co/io
ripple::unordered_map <RippleAsset,
std::vector<OrderBook::pointer>> mDestMap;
// does an order book to XRP exist
boost::unordered_set <RippleAsset> mXRPBooks;
typedef RippleRecursiveMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
typedef ripple::unordered_map <RippleBook, BookListeners::pointer> MapType;
MapType mListeners;
std::uint32_t mSeq;
};
} // ripple
#endif

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.
*/
//==============================================================================
namespace ripple {
/** Iterate through the directories in an order book */
BookDirIterator::BookDirIterator(uint160 const& uInCurrency, uint160 const& uInIssuer,
uint160 const& uOutCurrency, uint160 const& uOutIssuer)
{
mBase = Ledger::getBookBase(uInCurrency, uInIssuer, uOutCurrency, uOutIssuer);
mEnd = Ledger::getQualityNext(mBase);
mIndex = mBase;
}
bool BookDirIterator::nextDirectory (LedgerEntrySet& les)
{
WriteLog (lsTRACE, Ledger) << "BookDirectoryIterator:: nextDirectory";
// Are we already at the end?
if (mIndex.isZero ())
return false;
// Get the ledger index of the next directory
mIndex = les.getNextLedgerIndex (mIndex, mEnd);
if (mIndex.isZero ())
{
// We ran off the end of the book
WriteLog (lsTRACE, Ledger) <<
"BookDirectoryIterator:: no next ledger index";
return false;
}
assert (mIndex < mEnd);
WriteLog (lsTRACE, Ledger) <<
"BookDirectoryIterator:: index " << to_string (mIndex);
// Retrieve the SLE from the LES
mOfferDir = les.entryCache (ltDIR_NODE, mIndex);
assert (mOfferDir);
return !!mOfferDir;
}
bool BookDirIterator::firstDirectory (LedgerEntrySet& les)
{
WriteLog (lsTRACE, Ledger) <<
"BookDirIterator(" << to_string (mBase) << ") firstDirectory";
/** Jump to the beginning
*/
mIndex = mBase;
return nextDirectory (les);
}
/** The LES may have changed. Repoint to the current directory if it still exists,
Otherwise, go to the next one.
*/
bool BookDirIterator::resync (LedgerEntrySet& les)
{
if (mIndex.isZero ())
mIndex = mBase;
else if (mIndex != mBase)
--mIndex;
return nextDirectory (les);
}
DirectoryEntryIterator BookDirIterator::getOfferIterator () const
{
WriteLog (lsTRACE, Ledger) << "BookDirIterator(" <<
to_string (mBase) << ") get offer iterator";
return DirectoryEntryIterator (mOfferDir);
}
std::uint64_t BookDirIterator::getRate () const
{
return Ledger::getQuality(mIndex);
}
bool BookDirIterator::addJson (Json::Value& jv) const
{
if (! (*this))
return false;
jv["book_index"] = to_string (mIndex);
return true;
}
bool BookDirIterator::setJson(Json::Value const& jv)
{
if (!jv.isMember("book_index"))
return false;
const Json::Value& bi = jv["book_index"];
if (!bi.isString ())
return false;
mIndex.SetHexExact(bi.asString());
return true;
}
bool OrderBookIterator::addJson (Json::Value& jv) const
{
return mOfferIterator.addJson(jv) && mDirectoryIterator.addJson(jv);
}
bool OrderBookIterator::setJson (Json::Value const& jv)
{
return mDirectoryIterator.setJson (jv) && mOfferIterator.setJson (jv, mEntrySet);
}
STAmount OrderBookIterator::getCurrentRate () const
{
return mDirectoryIterator.getCurrentRate();
}
std::uint64_t OrderBookIterator::getCurrentQuality () const
{
return mDirectoryIterator.getCurrentQuality();
}
uint256 OrderBookIterator::getCurrentDirectory () const
{
return mOfferIterator.getDirectory ();
}
uint256 OrderBookIterator::getCurrentIndex () const
{
return mOfferIterator.getEntryLedgerIndex();
}
/** Retrieve the offer the iterator points to
*/
SLE::pointer OrderBookIterator::getCurrentOffer ()
{
return mOfferIterator.getEntry (mEntrySet, ltOFFER);
}
/** Go to the first offer in the first directory
*/
bool OrderBookIterator::firstOffer ()
{
WriteLog (lsTRACE, Ledger) << "OrderBookIterator: first offer";
// Go to first directory in order book
if (!mDirectoryIterator.firstDirectory (mEntrySet))
{
WriteLog (lsTRACE, Ledger) << "OrderBookIterator: no first directory";
return false;
}
mOfferIterator = mDirectoryIterator.getOfferIterator ();
// Take the next offer
return nextOffer();
}
/** Go to the next offer, possibly changing directories
*/
bool OrderBookIterator::nextOffer ()
{
WriteLog (lsTRACE, Ledger) << "OrderBookIterator: next offer";
do
{
// Is there a next offer in the current directory
if (mOfferIterator.nextEntry (mEntrySet))
{
WriteLog (lsTRACE, Ledger) << "OrderBookIterator: there is a next offer in this directory";
return true;
}
// Is there a next directory
if (!mDirectoryIterator.nextDirectory (mEntrySet))
{
WriteLog (lsTRACE, Ledger) << "OrderBookIterator: there is no next directory";
return false;
}
WriteLog (lsTRACE, Ledger) << "OrderBookIterator: going to next directory";
// Set to before its first offer
mOfferIterator = mDirectoryIterator.getOfferIterator ();
}
while (1);
}
/** Rewind to the beginning of this directory, then take the next offer
*/
bool OrderBookIterator::rewind ()
{
if (!mDirectoryIterator.resync (mEntrySet))
return false;
mOfferIterator = mDirectoryIterator.getOfferIterator ();
return nextOffer ();
}
/** Go to before the first offer in the next directory
*/
bool OrderBookIterator::nextDir ()
{
if (!mDirectoryIterator.nextDirectory (mEntrySet))
return false;
mOfferIterator = mDirectoryIterator.getOfferIterator ();
return true;
}
/** Advance to the next offer in this directory
*/
bool OrderBookIterator::nextOfferInDir ()
{
return mOfferIterator.nextEntry (mEntrySet);
}
} // ripple

View File

@@ -0,0 +1,238 @@
//------------------------------------------------------------------------------
/*
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_ORDERBOOKITERATOR_H_INCLUDED
#define RIPPLE_ORDERBOOKITERATOR_H_INCLUDED
namespace ripple {
/** An iterator that walks the directories in a book */
class BookDirIterator
{
public:
BookDirIterator ()
{
}
BookDirIterator (
uint160 const& uInCurrency, uint160 const& uInIssuer,
uint160 const& uOutCurrency, uint160 const& uOutIssuer);
uint256 const& getBookBase () const
{
return mBase;
}
uint256 const& getBookEnd () const
{
return mEnd;
}
uint256 const& getCurrentIndex() const
{
return mIndex;
}
void setCurrentIndex(uint256 const& index)
{
mIndex = index;
}
/** Get the current exchange rate
*/
STAmount getCurrentRate () const
{
return STAmount::setRate (getCurrentQuality());
}
/** Get the current quality
*/
std::uint64_t getCurrentQuality () const
{
return Ledger::getQuality(mIndex);
}
/** Make this iterator refer to the next book
*/
bool nextDirectory (LedgerEntrySet&);
/** Make this iterator refer to the first book
*/
bool firstDirectory (LedgerEntrySet&);
/** The LES may have changed
Resync the iterator
*/
bool resync (LedgerEntrySet&);
/** Get an iterator to the offers in this directory
*/
DirectoryEntryIterator getOfferIterator () const;
std::uint64_t getRate () const;
bool addJson (Json::Value&) const;
bool setJson (Json::Value const&);
// Does this iterator currently point to a valid directory
explicit
operator bool () const
{
return mOfferDir && (mOfferDir->getIndex() == mIndex);
}
bool
operator== (BookDirIterator const& other) const
{
assert (! mIndex.isZero() && ! other.mIndex.isZero());
return mIndex == other.mIndex;
}
bool
operator!= (BookDirIterator const& other) const
{
return ! (*this == other);
}
private:
uint256 mBase; // The first index a directory in the book can have
uint256 mEnd; // The first index a directory in the book cannot have
uint256 mIndex; // The index we are currently on
SLE::pointer mOfferDir; // The directory page we are currently on
};
//------------------------------------------------------------------------------
/** An iterator that walks the offers in a book
CAUTION: The LedgerEntrySet must remain valid for the life of the iterator
*/
class OrderBookIterator
{
public:
OrderBookIterator (
LedgerEntrySet& set,
uint160 const& uInCurrency,
uint160 const& uInIssuer,
uint160 const& uOutCurrency,
uint160 const& uOutIssuer) :
mEntrySet (set),
mDirectoryIterator (uInCurrency, uInIssuer, uOutCurrency, uOutIssuer)
{
}
OrderBookIterator&
operator= (OrderBookIterator const&) = default;
bool addJson (Json::Value&) const;
bool setJson (Json::Value const&);
STAmount getCurrentRate () const;
std::uint64_t getCurrentQuality () const;
uint256 getCurrentIndex () const;
uint256 getCurrentDirectory () const;
SLE::pointer getCurrentOffer ();
/** Position the iterator at the first offer in the first directory.
Returns whether there is an offer to point to.
*/
bool firstOffer ();
/** Position the iterator at the next offer, going to the next directory if needed
Returns whether there is a next offer.
*/
bool nextOffer ();
/** Position the iterator at the first offer in the next directory.
Returns whether there is a next directory to point to.
*/
bool nextDir ();
/** Position the iterator at the first offer in the current directory.
Returns whether there is an offer in the directory.
*/
bool firstOfferInDir ();
/** Position the iterator at the next offer in the current directory.
Returns whether there is a next offer in the directory.
*/
bool nextOfferInDir ();
/** Position the iterator at the first offer at the current quality.
If none, position the iterator at the first offer at the next quality.
This rather odd semantic is required by the payment engine.
*/
bool rewind ();
LedgerEntrySet& peekEntrySet ()
{
return mEntrySet;
}
BookDirIterator const& peekDirIterator () const
{
return mDirectoryIterator;
}
DirectoryEntryIterator const& peekDirectoryEntryIterator () const
{
return mOfferIterator;
}
BookDirIterator& peekDirIterator ()
{
return mDirectoryIterator;
}
DirectoryEntryIterator& peekDirectoryEntryIterator ()
{
return mOfferIterator;
}
bool
operator== (OrderBookIterator const& other) const
{
return
std::addressof(mEntrySet) == std::addressof(other.mEntrySet) &&
mDirectoryIterator == other.mDirectoryIterator &&
mOfferIterator == mOfferIterator;
}
bool
operator!= (OrderBookIterator const& other) const
{
return ! (*this == other);
}
private:
std::reference_wrapper <LedgerEntrySet> mEntrySet;
BookDirIterator mDirectoryIterator;
DirectoryEntryIterator mOfferIterator;
};
} // ripple
#endif

View File

@@ -0,0 +1,164 @@
//------------------------------------------------------------------------------
/*
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 {
SerializedValidation::SerializedValidation (SerializerIterator& sit, bool checkSignature)
: STObject (getFormat (), sit, sfValidation)
, mTrusted (false)
{
mNodeID = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey)).getNodeID ();
assert (mNodeID.isNonZero ());
if (checkSignature && !isValid ())
{
Log (lsTRACE) << "Invalid validation " << getJson (0);
throw std::runtime_error ("Invalid validation");
}
}
SerializedValidation::SerializedValidation (
uint256 const& ledgerHash, std::uint32_t signTime,
const RippleAddress& raPub, bool isFull)
: STObject (getFormat (), sfValidation)
, mTrusted (false)
{
// Does not sign
setFieldH256 (sfLedgerHash, ledgerHash);
setFieldU32 (sfSigningTime, signTime);
setFieldVL (sfSigningPubKey, raPub.getNodePublic ());
mNodeID = raPub.getNodeID ();
assert (mNodeID.isNonZero ());
if (!isFull)
setFlag (kFullFlag);
}
void SerializedValidation::sign (const RippleAddress& raPriv)
{
uint256 signingHash;
sign (signingHash, raPriv);
}
void SerializedValidation::sign (uint256& signingHash, const RippleAddress& raPriv)
{
setFlag (vfFullyCanonicalSig);
signingHash = getSigningHash ();
Blob signature;
raPriv.signNodePrivate (signingHash, signature);
setFieldVL (sfSignature, signature);
}
uint256 SerializedValidation::getSigningHash () const
{
return STObject::getSigningHash (getConfig ().SIGN_VALIDATION);
}
uint256 SerializedValidation::getLedgerHash () const
{
return getFieldH256 (sfLedgerHash);
}
std::uint32_t SerializedValidation::getSignTime () const
{
return getFieldU32 (sfSigningTime);
}
std::uint32_t SerializedValidation::getFlags () const
{
return getFieldU32 (sfFlags);
}
bool SerializedValidation::isValid () const
{
return isValid (getSigningHash ());
}
bool SerializedValidation::isValid (uint256 const& signingHash) const
{
try
{
const ECDSA fullyCanonical = getFlags () & vfFullyCanonicalSig ?
ECDSA::strict : ECDSA::not_strict;
RippleAddress raPublicKey = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey));
return raPublicKey.isValid () &&
raPublicKey.verifyNodePublic (signingHash, getFieldVL (sfSignature), fullyCanonical);
}
catch (...)
{
Log (lsINFO) << "exception validating validation";
return false;
}
}
RippleAddress SerializedValidation::getSignerPublic () const
{
RippleAddress a;
a.setNodePublic (getFieldVL (sfSigningPubKey));
return a;
}
bool SerializedValidation::isFull () const
{
return (getFlags () & kFullFlag) != 0;
}
Blob SerializedValidation::getSignature () const
{
return getFieldVL (sfSignature);
}
Blob SerializedValidation::getSigned () const
{
Serializer s;
add (s);
return s.peekData ();
}
SOTemplate const& SerializedValidation::getFormat ()
{
struct FormatHolder
{
SOTemplate format;
FormatHolder ()
{
format.push_back (SOElement (sfFlags, SOE_REQUIRED));
format.push_back (SOElement (sfLedgerHash, SOE_REQUIRED));
format.push_back (SOElement (sfLedgerSequence, SOE_OPTIONAL));
format.push_back (SOElement (sfCloseTime, SOE_OPTIONAL));
format.push_back (SOElement (sfLoadFee, SOE_OPTIONAL));
format.push_back (SOElement (sfAmendments, SOE_OPTIONAL));
format.push_back (SOElement (sfBaseFee, SOE_OPTIONAL));
format.push_back (SOElement (sfReserveBase, SOE_OPTIONAL));
format.push_back (SOElement (sfReserveIncrement, SOE_OPTIONAL));
format.push_back (SOElement (sfSigningTime, SOE_REQUIRED));
format.push_back (SOElement (sfSigningPubKey, SOE_REQUIRED));
format.push_back (SOElement (sfSignature, SOE_OPTIONAL));
}
};
static FormatHolder holder;
return holder.format;
}
} // ripple

View File

@@ -0,0 +1,102 @@
//------------------------------------------------------------------------------
/*
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_SERIALIZEDVALIDATION_H
#define RIPPLE_SERIALIZEDVALIDATION_H
namespace ripple {
// Validation flags
const std::uint32_t vfFullyCanonicalSig = 0x80000000; // signature is fully canonical
class SerializedValidation
: public STObject
, public CountedObject <SerializedValidation>
{
public:
static char const* getCountedObjectName () { return "SerializedValidation"; }
typedef boost::shared_ptr<SerializedValidation> pointer;
typedef const boost::shared_ptr<SerializedValidation>& ref;
enum
{
kFullFlag = 0x1
};
// These throw if the object is not valid
SerializedValidation (SerializerIterator & sit, bool checkSignature = true);
// Does not sign the validation
SerializedValidation (uint256 const & ledgerHash, std::uint32_t signTime,
const RippleAddress & raPub, bool isFull);
uint256 getLedgerHash () const;
std::uint32_t getSignTime () const;
std::uint32_t getFlags () const;
RippleAddress getSignerPublic () const;
uint160 getNodeID () const
{
return mNodeID;
}
bool isValid () const;
bool isFull () const;
bool isTrusted () const
{
return mTrusted;
}
uint256 getSigningHash () const;
bool isValid (uint256 const& ) const;
void setTrusted ()
{
mTrusted = true;
}
Blob getSigned () const;
Blob getSignature () const;
void sign (uint256 & signingHash, const RippleAddress & raPrivate);
void sign (const RippleAddress & raPrivate);
// The validation this replaced
uint256 const& getPreviousHash ()
{
return mPreviousHash;
}
bool isPreviousHash (uint256 const & h) const
{
return mPreviousHash == h;
}
void setPreviousHash (uint256 const & h)
{
mPreviousHash = h;
}
private:
static SOTemplate const& getFormat ();
void setNode ();
uint256 mPreviousHash;
uint160 mNodeID;
bool mTrusted;
};
} // ripple
#endif

View File

@@ -0,0 +1,18 @@
# ripple_app
## Ledger.cpp
- Move all inlines into the .cpp, make the interface abstract
- Move static database functions into a real class, perhaps LedgerMaster
## LedgerMaster.cpp
- Change getLedgerByHash() to not use "all bits zero" to mean
"return the current ledger"
- replace uint32 with LedgerIndex and choose appropriate names
## Beast
- Change Stoppable to not require a constructor with parameters

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,157 @@
//------------------------------------------------------------------------------
/*
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_APP_APPLICATION_H_INCLUDED
#define RIPPLE_APP_APPLICATION_H_INCLUDED
#include <ripple/module/app/main/FullBelowCache.h>
namespace ripple {
namespace SiteFiles { class Manager; }
namespace Validators { class Manager; }
namespace Resource { class Manager; }
namespace NodeStore { class Database; }
namespace RPC { class Manager; }
// VFALCO TODO Fix forward declares required for header dependency loops
class CollectorManager;
class AmendmentTable;
class IHashRouter;
class LoadFeeTrack;
class Overlay;
class UniqueNodeList;
class JobQueue;
class InboundLedgers;
class LedgerMaster;
class LoadManager;
class NetworkOPs;
class OrderBookDB;
class ProofOfWorkFactory;
class SerializedLedgerEntry;
class TransactionMaster;
class TxQueue;
class LocalCredentials;
class PathRequests;
class DatabaseCon;
typedef TaggedCache <uint256, Blob> NodeCache;
typedef TaggedCache <uint256, SerializedLedgerEntry> SLECache;
class Application : public beast::PropertyStream::Source
{
public:
/* VFALCO NOTE
The master lock protects:
- The open ledger
- Server global state
* What the last closed ledger is
* State of the consensus engine
other things
*/
typedef RippleRecursiveMutex LockType;
typedef std::unique_lock <LockType> ScopedLockType;
virtual LockType& getMasterLock () = 0;
public:
Application ();
virtual ~Application () { }
virtual boost::asio::io_service& getIOService () = 0;
virtual CollectorManager& getCollectorManager () = 0;
virtual FullBelowCache& getFullBelowCache () = 0;
virtual JobQueue& getJobQueue () = 0;
virtual RPC::Manager& getRPCManager () = 0;
virtual SiteFiles::Manager& getSiteFiles () = 0;
virtual NodeCache& getTempNodeCache () = 0;
virtual SLECache& getSLECache () = 0;
virtual Validators::Manager& getValidators () = 0;
virtual AmendmentTable& getAmendmentTable() = 0;
virtual IHashRouter& getHashRouter () = 0;
virtual LoadFeeTrack& getFeeTrack () = 0;
virtual LoadManager& getLoadManager () = 0;
virtual Overlay& overlay () = 0;
virtual ProofOfWorkFactory& getProofOfWorkFactory () = 0;
virtual UniqueNodeList& getUNL () = 0;
virtual Validations& getValidations () = 0;
virtual NodeStore::Database& getNodeStore () = 0;
virtual InboundLedgers& getInboundLedgers () = 0;
virtual LedgerMaster& getLedgerMaster () = 0;
virtual NetworkOPs& getOPs () = 0;
virtual OrderBookDB& getOrderBookDB () = 0;
virtual TransactionMaster& getMasterTransaction () = 0;
virtual TxQueue& getTxQueue () = 0;
virtual LocalCredentials& getLocalCredentials () = 0;
virtual Resource::Manager& getResourceManager () = 0;
virtual PathRequests& getPathRequests () = 0;
virtual DatabaseCon* getRpcDB () = 0;
virtual DatabaseCon* getTxnDB () = 0;
virtual DatabaseCon* getLedgerDB () = 0;
virtual std::chrono::milliseconds getIOLatency () = 0;
/** Retrieve the "wallet database"
It looks like this is used to store the unique node list.
*/
// VFALCO TODO Rename, document this
// NOTE This will be replaced by class Validators
//
virtual DatabaseCon* getWalletDB () = 0;
virtual bool getSystemTimeOffset (int& offset) = 0;
virtual bool isShutdown () = 0;
virtual bool running () = 0;
virtual void setup () = 0;
virtual void run () = 0;
virtual void signalStop () = 0;
};
/** Create an instance of the Application object.
As long as there are legacy calls to getApp it is not safe
to create more than one Application object at a time.
*/
std::unique_ptr <Application> make_Application();
// VFALCO DEPRECATED
//
// Please do not write new code that calls getApp(). Instead,
// Use dependency injection to construct your class with a
// reference to the desired interface (Application in this case).
// Or better yet, instead of relying on the entire Application
// object, construct with just the interfaces that you need.
//
// When working in existing code, try to clean it up by rewriting
// calls to getApp to use a data member instead, and inject the
// needed interfaces in the constructor.
//
// http://en.wikipedia.org/wiki/Dependency_injection
//
extern Application& getApp ();
}
#endif

View File

@@ -0,0 +1,79 @@
//------------------------------------------------------------------------------
/*
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 {
class CollectorManagerImp
: public CollectorManager
{
public:
beast::Journal m_journal;
beast::insight::Collector::ptr m_collector;
std::unique_ptr <beast::insight::Groups> m_groups;
CollectorManagerImp (beast::StringPairArray const& params,
beast::Journal journal)
: m_journal (journal)
{
std::string const& server (params ["server"].toStdString());
if (server == "statsd")
{
beast::IP::Endpoint const address (beast::IP::Endpoint::from_string (
params ["address"].toStdString ()));
std::string const& prefix (params ["prefix"].toStdString ());
m_collector = beast::insight::StatsDCollector::New (address, prefix, journal);
}
else
{
m_collector = beast::insight::NullCollector::New ();
}
m_groups = beast::insight::make_Groups (m_collector);
}
~CollectorManagerImp ()
{
}
beast::insight::Collector::ptr const& collector ()
{
return m_collector;
}
beast::insight::Group::ptr const& group (std::string const& name)
{
return m_groups->get (name);
}
};
//------------------------------------------------------------------------------
CollectorManager::~CollectorManager ()
{
}
CollectorManager* CollectorManager::New (beast::StringPairArray const& params,
beast::Journal journal)
{
return new CollectorManagerImp (params, journal);
}
}

View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------------------------
/*
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_RIPPLECOLLECTOR_H_INCLUDED
#define RIPPLE_RIPPLECOLLECTOR_H_INCLUDED
#include <beast/Insight.h>
namespace ripple {
/** Provides the beast::insight::Collector service. */
class CollectorManager
{
public:
static CollectorManager* New (beast::StringPairArray const& params,
beast::Journal journal);
virtual ~CollectorManager () = 0;
virtual beast::insight::Collector::ptr const& collector () = 0;
virtual beast::insight::Group::ptr const& group (std::string const& name) = 0;
};
}
#endif

View File

@@ -0,0 +1,57 @@
//------------------------------------------------------------------------------
/*
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>
namespace ripple {
FatalErrorReporter::FatalErrorReporter ()
{
m_savedReporter = beast::FatalError::setReporter (this);
}
FatalErrorReporter::~FatalErrorReporter ()
{
beast::FatalError::setReporter (m_savedReporter);
}
void FatalErrorReporter::reportMessage (beast::String& formattedMessage)
{
Log::out() << formattedMessage.toRawUTF8 ();
}
//------------------------------------------------------------------------------
class FatalErrorReporter_test : public beast::unit_test::suite
{
public:
void run ()
{
FatalErrorReporter reporter;
// We don't really expect the program to run after this
// but the unit test is here so you can manually test it.
beast::FatalError ("The unit test intentionally failed", __FILE__, __LINE__);
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(FatalErrorReporter,ripple_app,ripple);
} // ripple

View File

@@ -0,0 +1,52 @@
//------------------------------------------------------------------------------
/*
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_FATALERRORREPORTER_H_INCLUDED
#define RIPPLE_FATALERRORREPORTER_H_INCLUDED
#include <beast/module/core/diagnostic/FatalError.h>
namespace ripple {
/** FatalError reporter.
This writes the details to standard error and the log. The reporter is
installed for the lifetime of the object so typically you would put this
at the top of main().
An alternative is to make it a global variable but for this to cover all
possible cases, there can be no other global variables with non trivial
constructors that can report a fatal error. Also, the Log would need
to be guaranteed to be set up for this handler to work.
*/
class FatalErrorReporter : public beast::FatalError::Reporter
{
public:
FatalErrorReporter ();
~FatalErrorReporter ();
void reportMessage (beast::String& formattedMessage);
private:
beast::FatalError::Reporter* m_savedReporter;
};
} // ripple
#endif

View File

@@ -0,0 +1,32 @@
//------------------------------------------------------------------------------
/*
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_FULLBELOWCACHE_H_INCLUDED
#define RIPPLE_FULLBELOWCACHE_H_INCLUDED
#include <ripple/types/api/base_uint.h>
#include <ripple/radmap/api/BasicFullBelowCache.h>
namespace ripple {
typedef RadMap::BasicFullBelowCache <uint256> FullBelowCache;
}
#endif

View File

@@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
/*
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/cxx14/memory.h> // <memory>
namespace ripple {
class IoServicePool::ServiceThread : private beast::Thread
{
public:
explicit ServiceThread (
beast::String const& name,
IoServicePool& owner,
boost::asio::io_service& service)
: Thread (name)
, m_owner (owner)
, m_service (service)
{
startThread ();
}
~ServiceThread ()
{
// block until thread exits
stopThread ();
}
void start ()
{
startThread ();
}
void run ()
{
m_service.run ();
m_owner.onThreadExit();
}
private:
IoServicePool& m_owner;
boost::asio::io_service& m_service;
};
//------------------------------------------------------------------------------
IoServicePool::IoServicePool (Stoppable& parent, beast::String const& name,
int numberOfThreads)
: Stoppable (name.toStdString().c_str(), parent)
, m_name (name)
, m_service (numberOfThreads)
, m_work (boost::ref (m_service))
, m_threadsDesired (numberOfThreads)
{
bassert (m_threadsDesired > 0);
}
IoServicePool::~IoServicePool ()
{
// the dtor of m_threads will block until each thread exits.
}
boost::asio::io_service& IoServicePool::getService ()
{
return m_service;
}
IoServicePool::operator boost::asio::io_service& ()
{
return m_service;
}
void IoServicePool::onStart ()
{
m_threads.reserve (m_threadsDesired);
for (int i = 0; i < m_threadsDesired; ++i)
{
m_threads.emplace_back (std::move (std::make_unique <
ServiceThread> (m_name, *this, m_service)));
++m_threadsRunning;
m_threads[i]->start ();
}
}
void IoServicePool::onStop ()
{
// VFALCO NOTE This is how it SHOULD work
//
//m_work = boost::none;
}
void IoServicePool::onChildrenStopped ()
{
// VFALCO NOTE This is a hack! We should gracefully
// cancel all pending I/O, and delete the work
// object using boost::optional, and let run()
// just return naturally.
//
m_service.stop ();
}
// Called every time io_service::run() returns and a thread will exit.
//
void IoServicePool::onThreadExit()
{
// service must be stopping for threads to exit.
bassert (isStopping());
// must have at least count 1
bassert (m_threadsRunning.get() > 0);
if (--m_threadsRunning == 0)
{
// last thread just exited
stopped ();
}
}
} // ripple

View File

@@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
/*
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_APP_IOSERVICEPOOL_H_INCLUDED
#define RIPPLE_APP_IOSERVICEPOOL_H_INCLUDED
namespace ripple {
/** An io_service with an associated group of threads. */
class IoServicePool : public beast::Stoppable
{
public:
IoServicePool (Stoppable& parent, beast::String const& name, int numberOfThreads);
~IoServicePool ();
boost::asio::io_service& getService ();
operator boost::asio::io_service& ();
void onStart ();
void onStop ();
void onChildrenStopped ();
private:
class ServiceThread;
void onThreadExit();
beast::String m_name;
boost::asio::io_service m_service;
boost::optional <boost::asio::io_service::work> m_work;
std::vector <std::unique_ptr <ServiceThread>> m_threads;
int m_threadsDesired;
beast::Atomic <int> m_threadsRunning;
};
} // ripple
#endif

View File

@@ -0,0 +1,264 @@
//------------------------------------------------------------------------------
/*
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 {
class LoadManagerImp
: public LoadManager
, public beast::Thread
{
public:
/* Entry mapping utilization to cost.
The cost is expressed as a unitless relative quantity. These
mappings are statically loaded at startup with heuristic values.
*/
class Cost
{
public:
// VFALCO TODO Eliminate this default ctor somehow
Cost ()
: m_loadType ()
, m_cost (0)
, m_resourceFlags (0)
{
}
Cost (LoadType loadType, int cost, int resourceFlags)
: m_loadType (loadType)
, m_cost (cost)
, m_resourceFlags (resourceFlags)
{
}
LoadType getLoadType () const
{
return m_loadType;
}
int getCost () const
{
return m_cost;
}
int getResourceFlags () const
{
return m_resourceFlags;
}
public:
// VFALCO TODO Make these private and const
LoadType m_loadType;
int m_cost;
int m_resourceFlags;
};
//--------------------------------------------------------------------------
beast::Journal m_journal;
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
bool mArmed;
int mDeadLock; // Detect server deadlocks
std::vector <Cost> mCosts;
//--------------------------------------------------------------------------
LoadManagerImp (Stoppable& parent, beast::Journal journal)
: LoadManager (parent)
, Thread ("loadmgr")
, m_journal (journal)
, mArmed (false)
, mDeadLock (0)
, mCosts (LT_MAX)
{
UptimeTimer::getInstance ().beginManualUpdates ();
}
~LoadManagerImp ()
{
UptimeTimer::getInstance ().endManualUpdates ();
stopThread ();
}
//--------------------------------------------------------------------------
//
// Stoppable
//
//--------------------------------------------------------------------------
void onPrepare ()
{
}
void onStart ()
{
m_journal.debug << "Starting";
startThread ();
}
void onStop ()
{
if (isThreadRunning ())
{
m_journal.debug << "Stopping";
stopThreadAsync ();
}
else
{
stopped ();
}
}
//--------------------------------------------------------------------------
void resetDeadlockDetector ()
{
ScopedLockType sl (mLock);
mDeadLock = UptimeTimer::getInstance ().getElapsedSeconds ();
}
void activateDeadlockDetector ()
{
mArmed = true;
}
void logDeadlock (int dlTime)
{
m_journal.warning << "Server stalled for " << dlTime << " seconds.";
#if RIPPLE_TRACK_MUTEXES
StringArray report;
TrackedMutex::generateGlobalBlockedReport (report);
if (report.size () > 0)
{
report.insert (0, String::empty);
report.insert (-1, String::empty);
Log::print (report);
}
#endif
}
// VFALCO NOTE Where's the thread object? It's not a data member...
//
void run ()
{
// VFALCO TODO replace this with a beast Time object?
//
// Initialize the clock to the current time.
boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time ();
while (! threadShouldExit ())
{
{
// VFALCO NOTE What is this lock protecting?
ScopedLockType sl (mLock);
// VFALCO NOTE I think this is to reduce calls to the operating system
// for retrieving the current time.
//
// TODO Instead of incrementing can't we just retrieve the current
// time again?
//
// Manually update the timer.
UptimeTimer::getInstance ().incrementElapsedTime ();
// Measure the amount of time we have been deadlocked, in seconds.
//
// VFALCO NOTE mDeadLock is a canary for detecting the condition.
int const timeSpentDeadlocked = UptimeTimer::getInstance ().getElapsedSeconds () - mDeadLock;
// VFALCO NOTE I think that "armed" refers to the deadlock detector
//
int const reportingIntervalSeconds = 10;
if (mArmed && (timeSpentDeadlocked >= reportingIntervalSeconds))
{
// Report the deadlocked condition every 10 seconds
if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0)
{
logDeadlock (timeSpentDeadlocked);
}
// If we go over 500 seconds spent deadlocked, it means that the
// deadlock resolution code has failed, which qualifies as undefined
// behavior.
//
assert (timeSpentDeadlocked < 500);
}
}
bool change;
// VFALCO TODO Eliminate the dependence on the Application object.
// Choices include constructing with the job queue / feetracker.
// Another option is using an observer pattern to invert the dependency.
if (getApp().getJobQueue ().isOverloaded ())
{
m_journal.info << getApp().getJobQueue ().getJson (0);
change = getApp().getFeeTrack ().raiseLocalFee ();
}
else
{
change = getApp().getFeeTrack ().lowerLocalFee ();
}
if (change)
{
// VFALCO TODO replace this with a Listener / observer and subscribe in NetworkOPs or Application
getApp().getOPs ().reportFeeChange ();
}
t += boost::posix_time::seconds (1);
boost::posix_time::time_duration when = t - boost::posix_time::microsec_clock::universal_time ();
if ((when.is_negative ()) || (when.total_seconds () > 1))
{
m_journal.warning << "time jump";
t = boost::posix_time::microsec_clock::universal_time ();
}
else
{
boost::this_thread::sleep (when);
}
}
stopped ();
}
};
//------------------------------------------------------------------------------
LoadManager::LoadManager (Stoppable& parent)
: Stoppable ("LoadManager", parent)
{
}
//------------------------------------------------------------------------------
LoadManager* LoadManager::New (Stoppable& parent, beast::Journal journal)
{
return new LoadManagerImp (parent, journal);
}
} // ripple

View File

@@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
/*
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_LOADMANAGER_H_INCLUDED
#define RIPPLE_LOADMANAGER_H_INCLUDED
namespace ripple {
/** Manages load sources.
This object creates an associated thread to maintain a clock.
When the server is overloaded by a particular peer it issues a warning
first. This allows friendly peers to reduce their consumption of resources,
or disconnect from the server.
The warning system is used instead of merely dropping, because hostile
peers can just reconnect anyway.
@see LoadSource, LoadType
*/
class LoadManager : public beast::Stoppable
{
protected:
explicit LoadManager (Stoppable& parent);
public:
/** Create a new manager.
@note The thresholds for warnings and punishments are in
the ctor-initializer
*/
static LoadManager* New (Stoppable& parent, beast::Journal journal);
/** Destroy the manager.
The destructor returns only after the thread has stopped.
*/
virtual ~LoadManager () { }
/** Turn on deadlock detection.
The deadlock detector begins in a disabled state. After this function
is called, it will report deadlocks using a separate thread whenever
the reset function is not called at least once per 10 seconds.
@see resetDeadlockDetector
*/
// VFALCO NOTE it seems that the deadlock detector has an "armed" state to prevent it
// from going off during program startup if there's a lengthy initialization
// operation taking place?
//
virtual void activateDeadlockDetector () = 0;
/** Reset the deadlock detection timer.
A dedicated thread monitors the deadlock timer, and if too much
time passes it will produce log warnings.
*/
virtual void resetDeadlockDetector () = 0;
};
} // ripple
#endif

View File

@@ -0,0 +1,171 @@
//------------------------------------------------------------------------------
/*
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 {
LocalCredentials::LocalCredentials ()
: mLedger (0)
{
}
void LocalCredentials::start ()
{
// We need our node identity before we begin networking.
// - Allows others to identify if they have connected multiple times.
// - Determines our CAS routing and responsibilities.
// - This is not our validation identity.
if (!nodeIdentityLoad ())
{
nodeIdentityCreate ();
if (!nodeIdentityLoad ())
throw std::runtime_error ("unable to retrieve new node identity.");
}
if (!getConfig ().QUIET)
Log::out() << "NodeIdentity: " << mNodePublicKey.humanNodePublic ();
getApp().getUNL ().start ();
}
// Retrieve network identity.
bool LocalCredentials::nodeIdentityLoad ()
{
Database* db = getApp().getWalletDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
bool bSuccess = false;
if (db->executeSQL ("SELECT * FROM NodeIdentity;") && db->startIterRows ())
{
std::string strPublicKey, strPrivateKey;
db->getStr ("PublicKey", strPublicKey);
db->getStr ("PrivateKey", strPrivateKey);
mNodePublicKey.setNodePublic (strPublicKey);
mNodePrivateKey.setNodePrivate (strPrivateKey);
db->endIterRows ();
bSuccess = true;
}
if (getConfig ().NODE_PUB.isValid () && getConfig ().NODE_PRIV.isValid ())
{
mNodePublicKey = getConfig ().NODE_PUB;
mNodePrivateKey = getConfig ().NODE_PRIV;
}
return bSuccess;
}
// Create and store a network identity.
bool LocalCredentials::nodeIdentityCreate ()
{
if (!getConfig ().QUIET)
Log::out() << "NodeIdentity: Creating.";
//
// Generate the public and private key
//
RippleAddress naSeed = RippleAddress::createSeedRandom ();
RippleAddress naNodePublic = RippleAddress::createNodePublic (naSeed);
RippleAddress naNodePrivate = RippleAddress::createNodePrivate (naSeed);
// Make new key.
#ifdef CREATE_NEW_DH_PARAMS
std::string strDh512 = DH_der_gen (512);
#else
std::string strDh512 (RippleSSLContext::getRawDHParams (512));
#endif
#if 1
std::string strDh1024 = strDh512; // For testing and most cases 512 is fine.
#else
std::string strDh1024 = DH_der_gen (1024);
#endif
//
// Store the node information
//
Database* db = getApp().getWalletDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
db->executeSQL (str (boost::format ("INSERT INTO NodeIdentity (PublicKey,PrivateKey,Dh512,Dh1024) VALUES ('%s','%s',%s,%s);")
% naNodePublic.humanNodePublic ()
% naNodePrivate.humanNodePrivate ()
% sqlEscape (strDh512)
% sqlEscape (strDh1024)));
// XXX Check error result.
if (!getConfig ().QUIET)
Log::out() << "NodeIdentity: Created.";
return true;
}
bool LocalCredentials::dataDelete (const std::string& strKey)
{
Database* db = getApp().getRpcDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getRpcDB ()->getDBLock ());
return db->executeSQL (str (boost::format ("DELETE FROM RPCData WHERE Key=%s;")
% sqlEscape (strKey)));
}
bool LocalCredentials::dataFetch (const std::string& strKey, std::string& strValue)
{
Database* db = getApp().getRpcDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getRpcDB ()->getDBLock ());
bool bSuccess = false;
if (db->executeSQL (str (boost::format ("SELECT Value FROM RPCData WHERE Key=%s;")
% sqlEscape (strKey))) && db->startIterRows ())
{
Blob vucData = db->getBinary ("Value");
strValue.assign (vucData.begin (), vucData.end ());
db->endIterRows ();
bSuccess = true;
}
return bSuccess;
}
bool LocalCredentials::dataStore (const std::string& strKey, const std::string& strValue)
{
Database* db = getApp().getRpcDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getRpcDB ()->getDBLock ());
bool bSuccess = false;
return (db->executeSQL (str (boost::format ("REPLACE INTO RPCData (Key, Value) VALUES (%s,%s);")
% sqlEscape (strKey)
% sqlEscape (strValue)
)));
return bSuccess;
}
} // ripple

View File

@@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
/*
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_LOCALCREDENTIALS_H
#define RIPPLE_LOCALCREDENTIALS_H
namespace ripple {
/** Holds the cryptographic credentials identifying this instance of the server. */
class LocalCredentials : public beast::Uncopyable
{
public:
LocalCredentials ();
// Begin processing.
// - Maintain peer connectivity through validation and peer management.
void start ();
RippleAddress const& getNodePublic () const
{
return mNodePublicKey;
}
RippleAddress const& getNodePrivate () const
{
return mNodePrivateKey;
}
// Local persistence of RPC clients
bool dataDelete (std::string const& strKey);
// VFALCO NOTE why is strValue non-const?
bool dataFetch (std::string const& strKey, std::string& strValue);
bool dataStore (std::string const& strKey, std::string const& strValue);
private:
LocalCredentials (LocalCredentials const&); // disallowed
LocalCredentials& operator= (const LocalCredentials&); // disallowed
bool nodeIdentityLoad ();
bool nodeIdentityCreate ();
private:
boost::recursive_mutex mLock;
RippleAddress mNodePublicKey;
RippleAddress mNodePrivateKey;
LedgerIndex mLedger; // ledger we last synched to
};
} // ripple
#endif

View File

@@ -0,0 +1,396 @@
//------------------------------------------------------------------------------
/*
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.h>
#include <beast/streams/debug_ostream.h>
#include <ripple/module/basics/system/CheckLibraryVersions.h>
namespace po = boost::program_options;
namespace ripple {
void setupServer ()
{
#ifdef RLIMIT_NOFILE
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
{
if (rl.rlim_cur != rl.rlim_max)
{
rl.rlim_cur = rl.rlim_max;
setrlimit(RLIMIT_NOFILE, &rl);
}
}
#endif
getApp().setup ();
}
void startServer ()
{
//
// Execute start up rpc commands.
//
if (getConfig ().RPC_STARTUP.isArray ())
{
for (int i = 0; i != getConfig ().RPC_STARTUP.size (); ++i)
{
const Json::Value& jvCommand = getConfig ().RPC_STARTUP[i];
if (!getConfig ().QUIET)
Log::out() << "Startup RPC: " << jvCommand;
RPCHandler rhHandler (&getApp().getOPs ());
Resource::Charge loadType = Resource::feeReferenceRPC;
Json::Value jvResult = rhHandler.doCommand (jvCommand, Config::ADMIN, loadType);
if (!getConfig ().QUIET)
Log::out() << "Result: " << jvResult;
}
}
getApp().run (); // Blocks till we get a stop RPC.
}
void printHelp (const po::options_description& desc)
{
using namespace std;
cerr << SYSTEM_NAME "d [options] <command> <params>" << endl;
cerr << desc << endl;
cerr << "Commands: " << endl;
cerr << " account_info <account>|<nickname>|<seed>|<pass_phrase>|<key> [<ledger>] [strict]" << endl;
cerr << " account_lines <account> <account>|\"\" [<ledger>]" << endl;
cerr << " account_offers <account>|<nickname>|<account_public_key> [<ledger>]" << endl;
cerr << " account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]" << endl;
cerr << " book_offers <taker_pays> <taker_gets> [<taker [<ledger> [<limit> [<proof> [<marker>]]]]]" << endl;
cerr << " connect <ip> [<port>]" << endl;
cerr << " consensus_info" << endl;
cerr << " get_counts" << endl;
cerr << " json <method> <json>" << endl;
cerr << " ledger [<id>|current|closed|validated] [full]" << endl;
cerr << " ledger_accept" << endl;
cerr << " ledger_closed" << endl;
cerr << " ledger_current" << endl;
cerr << " ledger_header <ledger>" << endl;
cerr << " logrotate " << endl;
cerr << " peers" << endl;
cerr << " proof_create [<difficulty>] [<secret>]" << endl;
cerr << " proof_solve <token>" << endl;
cerr << " proof_verify <token> <solution> [<difficulty>] [<secret>]" << endl;
cerr << " random" << endl;
cerr << " ripple ..." << endl;
cerr << " ripple_path_find <json> [<ledger>]" << endl;
// cerr << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
cerr << " stop" << endl;
cerr << " tx <id>" << endl;
cerr << " unl_add <domain>|<public> [<comment>]" << endl;
cerr << " unl_delete <domain>|<public_key>" << endl;
cerr << " unl_list" << endl;
cerr << " unl_load" << endl;
cerr << " unl_network" << endl;
cerr << " unl_reset" << endl;
cerr << " validation_create [<seed>|<pass_phrase>|<key>]" << endl;
cerr << " validation_seed [<seed>|<pass_phrase>|<key>]" << endl;
cerr << " wallet_add <regular_seed> <paying_account> <master_seed> [<initial_funds>] [<account_annotation>]" << endl;
cerr << " wallet_accounts <seed>" << endl;
cerr << " wallet_claim <master_seed> <regular_seed> [<source_tag>] [<account_annotation>]" << endl;
cerr << " wallet_seed [<seed>|<passphrase>|<passkey>]" << endl;
cerr << " wallet_propose [<passphrase>]" << endl;
// Transaction helpers (that were removed):
// cerr << " account_domain_set <seed> <paying_account> [<domain>]" << endl;
// cerr << " account_email_set <seed> <paying_account> [<email_address>]" << endl;
// cerr << " account_rate_set <seed> <paying_account> <rate>" << endl;
// cerr << " account_wallet_set <seed> <paying_account> [<wallet_hash>]" << endl;
// cerr << " nickname_info <nickname>" << endl;
// cerr << " nickname_set <seed> <paying_account> <nickname> [<offer_minimum>] [<authorization>]" << endl;
// cerr << " offer_create <seed> <paying_account> <taker_pays_amount> <taker_pays_currency> <taker_pays_issuer> <takers_gets_amount> <takers_gets_currency> <takers_gets_issuer> <expires> [passive]" << endl;
// cerr << " offer_cancel <seed> <paying_account> <sequence>" << endl;
// cerr << " password_fund <seed> <paying_account> [<account>]" << endl;
// cerr << " password_set <master_seed> <regular_seed> [<account>]" << endl;
// cerr << " trust_set <seed> <paying_account> <destination_account> <limit_amount> <currency> [<quality_in>] [<quality_out>]" << endl;
}
//------------------------------------------------------------------------------
static
void
setupConfigForUnitTests (Config* config)
{
config->nodeDatabase = parseDelimitedKeyValueString ("type=memory");
config->ephemeralNodeDatabase = beast::StringPairArray ();
config->importNodeDatabase = beast::StringPairArray ();
}
static
int
runUnitTests (std::string pattern, std::string format)
{
// Config needs to be set up before creating Application
setupConfigForUnitTests (&getConfig ());
// VFALCO TODO Remove dependence on constructing Application object
auto app (make_Application());
using namespace beast::unit_test;
beast::debug_ostream stream;
reporter r (stream);
bool const failed (r.run_each_if (
global_suites(), match_auto (pattern)));
if (failed)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
//------------------------------------------------------------------------------
int run (int argc, char** argv)
{
// Make sure that we have the right OpenSSL and Boost libraries.
version::checkLibraryVersions();
FatalErrorReporter reporter;
using namespace std;
setCallingThreadName ("main");
int iResult = 0;
po::variables_map vm;
beast::String importDescription;
{
importDescription <<
"Import an existing node database (specified in the " <<
"[" << ConfigSection::importNodeDatabase () << "] configuration file section) "
"into the current node database (specified in the " <<
"[" << ConfigSection::nodeDatabase () << "] configuration file section). ";
}
// VFALCO TODO Replace boost program options with something from Beast.
//
// Set up option parsing.
//
po::options_description desc ("General Options");
desc.add_options ()
("help,h", "Display this message.")
("conf", po::value<std::string> (), "Specify the configuration file.")
("rpc", "Perform rpc command (default).")
("rpc_ip", po::value <std::string> (), "Specify the IP address for RPC command. Format: <ip-address>[':'<port-number>]")
("rpc_port", po::value <int> (), "Specify the port number for RPC command.")
("standalone,a", "Run with no peers.")
("unittest,u", po::value <std::string> ()->implicit_value (""), "Perform unit tests.")
("unittest-format", po::value <std::string> ()->implicit_value ("text"), "Format unit test output. Choices are 'text', 'junit'")
("parameters", po::value< vector<string> > (), "Specify comma separated parameters.")
("quiet,q", "Reduce diagnotics.")
("verbose,v", "Verbose logging.")
("load", "Load the current ledger from the local DB.")
("replay","Replay a ledger close.")
("ledger", po::value<std::string> (), "Load the specified ledger and start from .")
("ledgerfile", po::value<std::string> (), "Load the specified ledger file.")
("start", "Start from a fresh Ledger.")
("net", "Get the initial ledger from the network.")
("fg", "Run in the foreground.")
("import", importDescription.toStdString ().c_str ())
("version", "Display the build version.")
;
// Interpret positional arguments as --parameters.
po::positional_options_description p;
p.add ("parameters", -1);
if (! RandomNumbers::getInstance ().initialize ())
{
Log::out() << "Unable to add system entropy";
iResult = 2;
}
if (iResult)
{
nothing ();
}
else
{
// Parse options, if no error.
try
{
po::store (po::command_line_parser (argc, argv)
.options (desc) // Parse options.
.positional (p) // Remainder as --parameters.
.run (),
vm);
po::notify (vm); // Invoke option notify functions.
}
catch (...)
{
iResult = 1;
}
}
if (iResult)
{
nothing ();
}
else if (vm.count ("help"))
{
iResult = 1;
}
if (vm.count ("version"))
{
beast::String const& s (BuildInfo::getVersionString ());
std::cout << "rippled version " << s.toStdString() << std::endl;
return 0;
}
// Use a watchdog process unless we're invoking a stand alone type of mode
//
if (HaveSustain ()
&& !iResult
&& !vm.count ("parameters")
&& !vm.count ("fg")
&& !vm.count ("standalone")
&& !vm.count ("unittest"))
{
std::string logMe = DoSustain (getConfig ().DEBUG_LOGFILE.string());
if (!logMe.empty ())
Log (lsWARNING) << logMe;
}
if (vm.count ("quiet"))
{
LogSink::get()->setMinSeverity (lsFATAL, true);
}
else if (vm.count ("verbose"))
{
LogSink::get()->setMinSeverity (lsTRACE, true);
}
else
{
LogSink::get()->setMinSeverity (lsINFO, true);
}
// Run the unit tests if requested.
// The unit tests will exit the application with an appropriate return code.
//
if (vm.count ("unittest"))
{
std::string format;
if (vm.count ("unittest-format"))
format = vm ["unittest-format"].as <std::string> ();
return runUnitTests (vm ["unittest"].as <std::string> (), format);
}
if (!iResult)
{
getConfig ().setup (
vm.count ("conf") ? vm["conf"].as<std::string> () : "", // Config file.
!!vm.count ("quiet")); // Quiet flag.
if (vm.count ("standalone"))
{
getConfig ().RUN_STANDALONE = true;
getConfig ().LEDGER_HISTORY = 0;
}
}
if (vm.count ("start")) getConfig ().START_UP = Config::FRESH;
// Handle a one-time import option
//
if (vm.count ("import"))
{
getConfig ().doImport = true;
}
if (vm.count ("ledger"))
{
getConfig ().START_LEDGER = vm["ledger"].as<std::string> ();
if (vm.count("replay"))
getConfig ().START_UP = Config::REPLAY;
else
getConfig ().START_UP = Config::LOAD;
}
else if (vm.count ("ledgerfile"))
{
getConfig ().START_LEDGER = vm["ledgerfile"].as<std::string> ();
getConfig ().START_UP = Config::LOAD_FILE;
}
else if (vm.count ("load"))
{
getConfig ().START_UP = Config::LOAD;
}
else if (vm.count ("net"))
{
getConfig ().START_UP = Config::NETWORK;
if (getConfig ().VALIDATION_QUORUM < 2)
getConfig ().VALIDATION_QUORUM = 2;
}
if (iResult == 0)
{
// These overrides must happen after the config file is loaded.
// Override the RPC destination IP address
//
if (vm.count ("rpc_ip"))
{
getConfig ().setRpcIpAndOptionalPort (vm ["rpc_ip"].as <std::string> ());
}
// Override the RPC destination port number
//
if (vm.count ("rpc_port"))
{
// VFALCO TODO This should be a short.
getConfig ().setRpcPort (vm ["rpc_port"].as <int> ());
}
}
if (iResult == 0)
{
if (!vm.count ("parameters"))
{
// No arguments. Run server.
std::unique_ptr <Application> app (make_Application ());
setupServer ();
startServer ();
}
else
{
// Have a RPC command.
setCallingThreadName ("rpc");
std::vector<std::string> vCmd = vm["parameters"].as<std::vector<std::string> > ();
iResult = RPCCall::fromCommandLine (vCmd);
}
}
if (1 == iResult && !vm.count ("quiet"))
printHelp (desc);
return iResult;
}
}

View File

@@ -0,0 +1,75 @@
//------------------------------------------------------------------------------
/*
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 {
NodeStoreScheduler::NodeStoreScheduler (Stoppable& parent)
: Stoppable ("NodeStoreScheduler", parent)
, m_jobQueue (nullptr)
, m_taskCount (0)
{
}
void NodeStoreScheduler::setJobQueue (JobQueue& jobQueue)
{
m_jobQueue = &jobQueue;
}
void NodeStoreScheduler::onStop ()
{
}
void NodeStoreScheduler::onChildrenStopped ()
{
bassert (m_taskCount == 0);
stopped ();
}
void NodeStoreScheduler::scheduleTask (NodeStore::Task& task)
{
++m_taskCount;
m_jobQueue->addJob (
jtWRITE,
"NodeObject::store",
std::bind (&NodeStoreScheduler::doTask,
this, boost::ref(task), std::placeholders::_1));
}
void NodeStoreScheduler::doTask (NodeStore::Task& task, Job&)
{
task.performScheduledTask ();
if ((--m_taskCount == 0) && isStopping())
stopped();
}
void NodeStoreScheduler::onFetch (NodeStore::FetchReport const& report)
{
if (report.wentToDisk)
m_jobQueue->addLoadEvents (
report.isAsync ? jtNS_ASYNC_READ : jtNS_SYNC_READ,
1, report.elapsed);
}
void NodeStoreScheduler::onBatchWrite (NodeStore::BatchWriteReport const& report)
{
m_jobQueue->addLoadEvents (jtNS_WRITE,
report.writeCount, report.elapsed);
}
} // ripple

View File

@@ -0,0 +1,53 @@
//------------------------------------------------------------------------------
/*
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_APP_NODESTORESCHEDULER_H_INCLUDED
#define RIPPLE_APP_NODESTORESCHEDULER_H_INCLUDED
namespace ripple {
/** A NodeStore::Scheduler which uses the JobQueue and implements the Stoppable API. */
class NodeStoreScheduler
: public NodeStore::Scheduler
, public beast::Stoppable
{
public:
NodeStoreScheduler (Stoppable& parent);
// VFALCO NOTE This is a temporary hack to solve the problem
// of circular dependency.
//
void setJobQueue (JobQueue& jobQueue);
void onStop ();
void onChildrenStopped ();
void scheduleTask (NodeStore::Task& task);
void onFetch (NodeStore::FetchReport const& report) override;
void onBatchWrite (NodeStore::BatchWriteReport const& report) override;
private:
void doTask (NodeStore::Task& task, Job&);
JobQueue* m_jobQueue;
std::atomic <int> m_taskCount;
};
} // ripple
#endif

View File

@@ -0,0 +1,197 @@
//------------------------------------------------------------------------------
/*
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/common/jsonrpc_fields.h>
namespace ripple {
bool ParameterNode::setValue (const std::string& name, const Json::Value& value, Json::Value& error)
{
if (name.empty ()) // this node
return setValue (value, error);
size_t dot = name.find ('.');
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name);
if (it == mChildren.end ())
{
error = Json::objectValue;
error[jss::error] = "Name not found";
error[jss::name] = name;
return false;
}
return it->second->setValue (value, error);
}
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name.substr (0, dot));
if (it == mChildren.end ())
{
error = Json::objectValue;
error[jss::error] = "Name not found";
error[jss::name] = name;
return false;
}
ParameterNode* n = dynamic_cast<ParameterNode*> (it->second.get ());
if (!n)
{
error = Json::objectValue;
error[jss::error] = "Node has no children";
error[jss::name] = it->second->getName ();
return false;
}
return n->setValue (name.substr (dot + 1), value, error);
}
bool ParameterNode::addNode (const std::string& name, Parameter::ref node)
{
if (name.empty ()) // this node
return false;
size_t dot = name.find ('.');
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name);
if (it != mChildren.end ())
return false;
mChildren[name] = node;
return true;
}
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name.substr (0, dot));
ParameterNode* n;
if (it == mChildren.end ())
{
// create a new inner node
ParameterNode::pointer node = boost::make_shared<ParameterNode> (getShared (), name.substr (0, dot));
n = dynamic_cast<ParameterNode*> (node.get ());
assert (n);
mChildren[name] = node;
}
else
{
// existing node passed through must be inner
n = dynamic_cast<ParameterNode*> (it->second.get ());
if (!n)
return false;
}
return n->addNode (name.substr (dot + 1), node);
}
Json::Value ParameterNode::getValue (int i) const
{
Json::Value v (Json::objectValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH (const string_ref_pair & it, mChildren)
{
v[it.first] = it.second->getValue (i);
}
return v;
}
bool ParameterNode::setValue (const Json::Value& value, Json::Value& error)
{
error = Json::objectValue;
error[jss::error] = "Cannot end on an inner node";
Json::Value nodes (Json::arrayValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH (const string_ref_pair & it, mChildren)
{
nodes.append (it.first);
}
error["legal_nodes"] = nodes;
return false;
}
ParameterString::ParameterString (Parameter::ref parent, const std::string& name, const std::string& value)
: Parameter (parent, name), mValue (value)
{
;
}
Json::Value ParameterString::getValue (int) const
{
return Json::Value (mValue);
}
bool ParameterString::setValue (const Json::Value& value, Json::Value& error)
{
if (!value.isConvertibleTo (Json::stringValue))
{
error = Json::objectValue;
error[jss::error] = "Cannot convert to string";
error[jss::value] = value;
return false;
}
mValue = value.asString ();
return true;
}
ParameterInt::ParameterInt (Parameter::ref parent, const std::string& name, int value)
: Parameter (parent, name), mValue (value)
{
;
}
Json::Value ParameterInt::getValue (int) const
{
return Json::Value (mValue);
}
bool ParameterInt::setValue (const Json::Value& value, Json::Value& error)
{
if (value.isConvertibleTo (Json::intValue))
{
mValue = value.asInt ();
return true;
}
if (value.isConvertibleTo (Json::stringValue))
{
try
{
mValue = beast::lexicalCastThrow <int> (value.asString ());
}
catch (...)
{
}
}
error = Json::objectValue;
error[jss::error] = "Cannot convert to integer";
error[jss::value] = value;
return false;
}
} // ripple

View File

@@ -0,0 +1,103 @@
//------------------------------------------------------------------------------
/*
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_PARAMETERTABLE_H
#define RIPPLE_PARAMETERTABLE_H
namespace ripple {
class Parameter : public boost::enable_shared_from_this<Parameter>
{
// abstract base class parameters are derived from
public:
typedef boost::shared_ptr<Parameter> pointer;
typedef const boost::shared_ptr<Parameter>& ref;
public:
Parameter (Parameter::ref parent, const std::string& name) : mParent (parent), mName (name)
{
;
}
virtual ~Parameter ()
{
;
}
const std::string& getName () const
{
return mName;
}
virtual Json::Value getValue (int) const = 0;
virtual bool setValue (const Json::Value& value, Json::Value& error) = 0;
Parameter::pointer getShared ()
{
return shared_from_this ();
}
private:
pointer mParent;
std::string mName;
};
class ParameterNode : public Parameter
{
public:
ParameterNode (Parameter::ref parent, const std::string& name) : Parameter (parent, name)
{
;
}
bool addChildNode (Parameter::ref node);
bool setValue (const std::string& name, const Json::Value& value, Json::Value& error);
bool addNode (const std::string& name, Parameter::ref node);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
std::map<std::string, Parameter::pointer> mChildren;
};
class ParameterString : public Parameter
{
public:
ParameterString (Parameter::ref parent, const std::string& name, const std::string& value);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
std::string mValue;
};
class ParameterInt : public Parameter
{
public:
ParameterInt (Parameter::ref parent, const std::string& name, int value);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
int mValue;
};
} // ripple
#endif

View File

@@ -0,0 +1,294 @@
//------------------------------------------------------------------------------
/*
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/common/RippleSSLContext.h>
namespace ripple {
class RPCHTTPServerImp
: public RPCHTTPServer
, public beast::LeakChecked <RPCHTTPServerImp>
, public HTTP::Handler
{
public:
Resource::Manager& m_resourceManager;
beast::Journal m_journal;
JobQueue& m_jobQueue;
NetworkOPs& m_networkOPs;
RPCServerHandler m_deprecatedHandler;
HTTP::Server m_server;
std::unique_ptr <RippleSSLContext> m_context;
RPCHTTPServerImp (Stoppable& parent,
beast::Journal journal,
JobQueue& jobQueue,
NetworkOPs& networkOPs,
Resource::Manager& resourceManager)
: RPCHTTPServer (parent)
, m_resourceManager (resourceManager)
, m_journal (journal)
, m_jobQueue (jobQueue)
, m_networkOPs (networkOPs)
, m_deprecatedHandler (networkOPs, resourceManager)
, m_server (*this, journal)
{
if (getConfig ().RPC_SECURE == 0)
{
m_context.reset (RippleSSLContext::createBare ());
}
else
{
m_context.reset (RippleSSLContext::createAuthenticated (
getConfig ().RPC_SSL_KEY,
getConfig ().RPC_SSL_CERT,
getConfig ().RPC_SSL_CHAIN));
}
}
~RPCHTTPServerImp ()
{
m_server.stop();
}
void setup (beast::Journal journal)
{
if (! getConfig ().getRpcIP().empty () &&
getConfig ().getRpcPort() != 0)
{
beast::IP::Endpoint ep (beast::IP::Endpoint::from_string (getConfig().getRpcIP()));
if (! is_unspecified (ep))
{
HTTP::Port port;
port.addr = ep.at_port(0);
if (getConfig ().getRpcPort() != 0)
port.port = getConfig ().getRpcPort();
else
port.port = ep.port();
port.context = m_context.get ();
HTTP::Ports ports;
ports.push_back (port);
m_server.setPorts (ports);
}
}
else
{
journal.info << "RPC interface: disabled";
}
}
//--------------------------------------------------------------------------
//
// Stoppable
//
void onStop ()
{
m_server.stopAsync();
}
void onChildrenStopped ()
{
}
//--------------------------------------------------------------------------
//
// HTTP::Handler
//
void onAccept (HTTP::Session& session)
{
// Reject non-loopback connections if RPC_ALLOW_REMOTE is not set
if (! getConfig().RPC_ALLOW_REMOTE &&
! beast::IP::is_loopback (session.remoteAddress()))
{
session.close();
}
}
void onHeaders (HTTP::Session& session)
{
}
void onRequest (HTTP::Session& session)
{
#if 0
Job job;
processSession (job, session);
#else
session.detach();
// The "boost::"'s are a workaround for broken versions of tr1::functional that
// require the reference wrapper to be callable. HTTP::Session has abstract functions
// and so references to it are not callable.
m_jobQueue.addJob (jtRPC, "RPC", boost::bind (
&RPCHTTPServerImp::processSession, this, boost::_1,
boost::ref (session)));
#endif
}
void onClose (HTTP::Session& session, int errorCode)
{
}
void onStopped (HTTP::Server&)
{
stopped();
}
//--------------------------------------------------------------------------
void processSession (Job& job, HTTP::Session& session)
{
session.write (m_deprecatedHandler.processRequest (
session.content(), session.remoteAddress().at_port(0)));
session.close();
}
std::string createResponse (
int statusCode,
std::string const& description)
{
return HTTPReply (statusCode, description);
}
bool isAuthorized (
std::map <std::string, std::string> const& headers)
{
return HTTPAuthorized (headers);
}
// Stolen directly from RPCServerHandler
std::string processRequest (std::string const& request, beast::IP::Endpoint const& remoteIPAddress)
{
Json::Value jvRequest;
{
Json::Reader reader;
if ((request.size () > 1000000) ||
! reader.parse (request, jvRequest) ||
jvRequest.isNull () ||
! jvRequest.isObject ())
{
return createResponse (400, "Unable to parse request");
}
}
Config::Role const role (getConfig ().getAdminRole (jvRequest, remoteIPAddress));
Resource::Consumer usage;
if (role == Config::ADMIN)
usage = m_resourceManager.newAdminEndpoint (remoteIPAddress.to_string());
else
usage = m_resourceManager.newInboundEndpoint(remoteIPAddress);
if (usage.disconnect ())
return createResponse (503, "Server is overloaded");
// Parse id now so errors from here on will have the id
//
// VFALCO NOTE Except that "id" isn't included in the following errors...
//
Json::Value const id = jvRequest ["id"];
Json::Value const method = jvRequest ["method"];
if (method.isNull ())
{
return createResponse (400, "Null method");
}
else if (! method.isString ())
{
return createResponse (400, "method is not string");
}
std::string strMethod = method.asString ();
// Parse params
Json::Value params = jvRequest ["params"];
if (params.isNull ())
{
params = Json::Value (Json::arrayValue);
}
else if (!params.isArray ())
{
return HTTPReply (400, "params unparseable");
}
// VFALCO TODO Shouldn't we handle this earlier?
//
if (role == Config::FORBID)
{
// VFALCO TODO Needs implementing
// FIXME Needs implementing
// XXX This needs rate limiting to prevent brute forcing password.
return HTTPReply (403, "Forbidden");
}
// This code does all the work on the io_service thread and
// has no rate-limiting based on source IP or anything.
// This is a temporary safety
if ((role != Config::ADMIN) && (getApp().getFeeTrack().isLoadedLocal()))
{
return HTTPReply (503, "Unable to service at this time");
}
std::string response;
m_journal.debug << "Query: " << strMethod << params;
RPCHandler rpcHandler (&m_networkOPs);
Resource::Charge loadType = Resource::feeReferenceRPC;
Json::Value const result (rpcHandler.doRpcCommand (
strMethod, params, role, loadType));
usage.charge (loadType);
m_journal.debug << "Reply: " << result;
response = JSONRPCReply (result, Json::Value (), id);
return createResponse (200, response);
}
};
//------------------------------------------------------------------------------
RPCHTTPServer::RPCHTTPServer (Stoppable& parent)
: Stoppable ("RPCHTTPServer", parent)
{
}
//------------------------------------------------------------------------------
RPCHTTPServer* RPCHTTPServer::New (Stoppable& parent,
beast::Journal journal,
JobQueue& jobQueue,
NetworkOPs& networkOPs,
Resource::Manager& resourceManager)
{
return new RPCHTTPServerImp (parent, journal, jobQueue, networkOPs, resourceManager);
}
}

View File

@@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
/*
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_APP_RPCHTTPSERVER_H_INCLUDED
#define RIPPLE_APP_RPCHTTPSERVER_H_INCLUDED
namespace ripple {
class RPCHTTPServer : public beast::Stoppable
{
protected:
RPCHTTPServer (Stoppable& parent);
public:
static RPCHTTPServer* New (Stoppable& parent,
beast::Journal journal, JobQueue& jobQueue, NetworkOPs& networkOPs,
Resource::Manager& resourceManager);
virtual ~RPCHTTPServer () { }
/** Opens listening ports based on the Config settings. */
virtual void setup (beast::Journal journal) = 0;
};
}
#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.
*/
//==============================================================================
#ifndef RIPPLE_APPLICATION_TUNING_H_INCLUDED
#define RIPPLE_APPLICATION_TUNING_H_INCLUDED
namespace ripple {
enum
{
fullBelowTargetSize = 524288
,fullBelowExpirationSeconds = 600
};
}
#endif

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
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 {
AccountItem::AccountItem (SerializedLedgerEntry::ref ledger)
: mLedgerEntry (ledger)
{
}
} // 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_ACCOUNTITEM_H
#define RIPPLE_ACCOUNTITEM_H
namespace ripple {
//
// Fetch ledger entries from an account's owner dir.
//
/** Base class representing account items.
Account items include:
- Offers
- Trust Lines
NOTE these are deprecated and will go away, to be replaced with
simple visitor patterns.
*/
class AccountItem
{
public:
typedef boost::shared_ptr <AccountItem> pointer;
typedef const pointer& ref;
public:
AccountItem ()
{ }
/** Construct from a flat ledger entry.
*/
explicit AccountItem (SerializedLedgerEntry::ref ledger);
virtual ~AccountItem ()
{
;
}
virtual AccountItem::pointer makeItem (const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry) = 0;
// VFALCO TODO Make this const and change derived classes
virtual LedgerEntryType getType () = 0;
// VFALCO TODO Document the int parameter
virtual Json::Value getJson (int) = 0;
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
const SerializedLedgerEntry& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Blob getRaw () const;
// VFALCO TODO Make this private and use the existing accessors
//
protected:
// VFALCO TODO Research making the object pointed to const
SerializedLedgerEntry::pointer mLedgerEntry;
};
} // 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.
*/
//==============================================================================
namespace ripple {
AccountItems::AccountItems (uint160 const& accountID,
Ledger::ref ledger,
AccountItem::pointer ofType)
{
mOfType = ofType;
fillItems (accountID, ledger);
}
void AccountItems::fillItems (const uint160& accountID, Ledger::ref ledger)
{
uint256 const rootIndex = Ledger::getOwnerDirIndex (accountID);
uint256 currentIndex = rootIndex;
// VFALCO TODO Rewrite all infinite loops to have clear terminating
// conditions defined in one location.
//
while (1)
{
SLE::pointer ownerDir = ledger->getDirNode (currentIndex);
// VFALCO TODO Rewrite to not return from the middle of the function
if (!ownerDir)
return;
BOOST_FOREACH (uint256 const & uNode, ownerDir->getFieldV256 (sfIndexes).peekValue ())
{
// VFALCO TODO rename getSLEi() to something legible.
SLE::pointer sleCur = ledger->getSLEi (uNode);
if (!sleCur)
{
// item in directory not in ledger
}
else
{
AccountItem::pointer item = mOfType->makeItem (accountID, sleCur);
// VFALCO NOTE Under what conditions would makeItem() return nullptr?
// DJS NOTE If the item wasn't one this particular AccountItems was interested in
// (For example, if the owner is only interested in ripple lines and this is an offer)
if (item)
{
mItems.push_back (item);
}
}
}
std::uint64_t uNodeNext = ownerDir->getFieldU64 (sfIndexNext);
// VFALCO TODO Rewrite to not return from the middle of the function
if (!uNodeNext)
return;
currentIndex = Ledger::getDirNodeIndex (rootIndex, uNodeNext);
}
}
Json::Value AccountItems::getJson (int v)
{
Json::Value ret (Json::arrayValue);
BOOST_FOREACH (AccountItem::ref ai, mItems)
{
ret.append (ai->getJson (v));
}
return ret;
}
} // ripple

Some files were not shown because too many files have changed in this diff Show More