mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
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:
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <modules/beast_asio/beast_asio.h>
|
||||
#include <beast/module/asio/asio.h>
|
||||
#include <beast/asio/IPAddressConversion.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <modules/beast_core/text/LexicalCast.h>
|
||||
#include <beast/module/core/text/LexicalCast.h>
|
||||
|
||||
namespace Json {
|
||||
|
||||
|
||||
29
src/ripple/module/app/TODO.md
Normal file
29
src/ripple/module/app/TODO.md
Normal 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
|
||||
213
src/ripple/module/app/book/Amount.h
Normal file
213
src/ripple/module/app/book/Amount.h
Normal 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
|
||||
68
src/ripple/module/app/book/Amounts.h
Normal file
68
src/ripple/module/app/book/Amounts.h
Normal 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
|
||||
93
src/ripple/module/app/book/BookTip.h
Normal file
93
src/ripple/module/app/book/BookTip.h
Normal 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
|
||||
117
src/ripple/module/app/book/Offer.h
Normal file
117
src/ripple/module/app/book/Offer.h
Normal 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
|
||||
124
src/ripple/module/app/book/OfferStream.h
Normal file
124
src/ripple/module/app/book/OfferStream.h
Normal 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
|
||||
|
||||
141
src/ripple/module/app/book/Quality.h
Normal file
141
src/ripple/module/app/book/Quality.h
Normal 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
|
||||
147
src/ripple/module/app/book/Taker.h
Normal file
147
src/ripple/module/app/book/Taker.h
Normal 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
|
||||
63
src/ripple/module/app/book/Types.h
Normal file
63
src/ripple/module/app/book/Types.h
Normal 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
|
||||
81
src/ripple/module/app/book/impl/BookTip.cpp
Normal file
81
src/ripple/module/app/book/impl/BookTip.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
170
src/ripple/module/app/book/impl/OfferStream.cpp
Normal file
170
src/ripple/module/app/book/impl/OfferStream.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
120
src/ripple/module/app/book/impl/Quality.cpp
Normal file
120
src/ripple/module/app/book/impl/Quality.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
281
src/ripple/module/app/book/impl/Taker.cpp
Normal file
281
src/ripple/module/app/book/impl/Taker.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
46
src/ripple/module/app/book/tests/OfferStream.test.cpp
Normal file
46
src/ripple/module/app/book/tests/OfferStream.test.cpp
Normal 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);
|
||||
|
||||
}
|
||||
}
|
||||
249
src/ripple/module/app/book/tests/Quality.test.cpp
Normal file
249
src/ripple/module/app/book/tests/Quality.test.cpp
Normal 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);
|
||||
|
||||
}
|
||||
}
|
||||
153
src/ripple/module/app/consensus/DisputedTx.cpp
Normal file
153
src/ripple/module/app/consensus/DisputedTx.cpp
Normal 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
|
||||
|
||||
92
src/ripple/module/app/consensus/DisputedTx.h
Normal file
92
src/ripple/module/app/consensus/DisputedTx.h
Normal 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
|
||||
1930
src/ripple/module/app/consensus/LedgerConsensus.cpp
Normal file
1930
src/ripple/module/app/consensus/LedgerConsensus.cpp
Normal file
File diff suppressed because it is too large
Load Diff
90
src/ripple/module/app/consensus/LedgerConsensus.h
Normal file
90
src/ripple/module/app/consensus/LedgerConsensus.h
Normal 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
|
||||
48
src/ripple/module/app/contracts/Contract.cpp
Normal file
48
src/ripple/module/app/contracts/Contract.cpp
Normal 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
|
||||
46
src/ripple/module/app/contracts/Contract.h
Normal file
46
src/ripple/module/app/contracts/Contract.h
Normal 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
|
||||
228
src/ripple/module/app/contracts/Interpreter.cpp
Normal file
228
src/ripple/module/app/contracts/Interpreter.cpp
Normal 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
|
||||
102
src/ripple/module/app/contracts/Interpreter.h
Normal file
102
src/ripple/module/app/contracts/Interpreter.h
Normal 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
|
||||
38
src/ripple/module/app/contracts/Operation.cpp
Normal file
38
src/ripple/module/app/contracts/Operation.cpp
Normal 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
|
||||
380
src/ripple/module/app/contracts/Operation.h
Normal file
380
src/ripple/module/app/contracts/Operation.h
Normal 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
|
||||
22
src/ripple/module/app/contracts/ScriptData.cpp
Normal file
22
src/ripple/module/app/contracts/ScriptData.cpp
Normal 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
|
||||
186
src/ripple/module/app/contracts/ScriptData.h
Normal file
186
src/ripple/module/app/contracts/ScriptData.h
Normal 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
|
||||
337
src/ripple/module/app/data/DBInit.cpp
Normal file
337
src/ripple/module/app/data/DBInit.cpp
Normal 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
|
||||
39
src/ripple/module/app/data/DBInit.h
Normal file
39
src/ripple/module/app/data/DBInit.h
Normal 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
|
||||
208
src/ripple/module/app/data/Database.cpp
Normal file
208
src/ripple/module/app/data/Database.cpp
Normal 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
|
||||
123
src/ripple/module/app/data/Database.h
Normal file
123
src/ripple/module/app/data/Database.h
Normal 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
|
||||
50
src/ripple/module/app/data/DatabaseCon.cpp
Normal file
50
src/ripple/module/app/data/DatabaseCon.cpp
Normal 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
|
||||
50
src/ripple/module/app/data/DatabaseCon.h
Normal file
50
src/ripple/module/app/data/DatabaseCon.h
Normal 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
|
||||
|
||||
487
src/ripple/module/app/data/SqliteDatabase.cpp
Normal file
487
src/ripple/module/app/data/SqliteDatabase.cpp
Normal 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
|
||||
153
src/ripple/module/app/data/SqliteDatabase.h
Normal file
153
src/ripple/module/app/data/SqliteDatabase.h
Normal 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
|
||||
68
src/ripple/module/app/ledger/AcceptedLedger.cpp
Normal file
68
src/ripple/module/app/ledger/AcceptedLedger.cpp
Normal 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
|
||||
96
src/ripple/module/app/ledger/AcceptedLedger.h
Normal file
96
src/ripple/module/app/ledger/AcceptedLedger.h
Normal 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
|
||||
77
src/ripple/module/app/ledger/AcceptedLedgerTx.cpp
Normal file
77
src/ripple/module/app/ledger/AcceptedLedgerTx.cpp
Normal 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
|
||||
112
src/ripple/module/app/ledger/AcceptedLedgerTx.h
Normal file
112
src/ripple/module/app/ledger/AcceptedLedgerTx.h
Normal 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
|
||||
116
src/ripple/module/app/ledger/DirectoryEntryIterator.cpp
Normal file
116
src/ripple/module/app/ledger/DirectoryEntryIterator.cpp
Normal 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
|
||||
95
src/ripple/module/app/ledger/DirectoryEntryIterator.h
Normal file
95
src/ripple/module/app/ledger/DirectoryEntryIterator.h
Normal 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
|
||||
1283
src/ripple/module/app/ledger/InboundLedger.cpp
Normal file
1283
src/ripple/module/app/ledger/InboundLedger.cpp
Normal file
File diff suppressed because it is too large
Load Diff
156
src/ripple/module/app/ledger/InboundLedger.h
Normal file
156
src/ripple/module/app/ledger/InboundLedger.h
Normal 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
|
||||
405
src/ripple/module/app/ledger/InboundLedgers.cpp
Normal file
405
src/ripple/module/app/ledger/InboundLedgers.cpp
Normal 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
|
||||
84
src/ripple/module/app/ledger/InboundLedgers.h
Normal file
84
src/ripple/module/app/ledger/InboundLedgers.h
Normal 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
|
||||
2117
src/ripple/module/app/ledger/Ledger.cpp
Normal file
2117
src/ripple/module/app/ledger/Ledger.cpp
Normal file
File diff suppressed because it is too large
Load Diff
540
src/ripple/module/app/ledger/Ledger.h
Normal file
540
src/ripple/module/app/ledger/Ledger.h
Normal 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
|
||||
450
src/ripple/module/app/ledger/LedgerCleaner.cpp
Normal file
450
src/ripple/module/app/ledger/LedgerCleaner.cpp
Normal 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
|
||||
59
src/ripple/module/app/ledger/LedgerCleaner.h
Normal file
59
src/ripple/module/app/ledger/LedgerCleaner.h
Normal 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
|
||||
1721
src/ripple/module/app/ledger/LedgerEntrySet.cpp
Normal file
1721
src/ripple/module/app/ledger/LedgerEntrySet.cpp
Normal file
File diff suppressed because it is too large
Load Diff
294
src/ripple/module/app/ledger/LedgerEntrySet.h
Normal file
294
src/ripple/module/app/ledger/LedgerEntrySet.h
Normal 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
|
||||
194
src/ripple/module/app/ledger/LedgerHistory.cpp
Normal file
194
src/ripple/module/app/ledger/LedgerHistory.cpp
Normal 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
|
||||
112
src/ripple/module/app/ledger/LedgerHistory.h
Normal file
112
src/ripple/module/app/ledger/LedgerHistory.h
Normal 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
|
||||
81
src/ripple/module/app/ledger/LedgerHolder.h
Normal file
81
src/ripple/module/app/ledger/LedgerHolder.h
Normal 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
|
||||
1486
src/ripple/module/app/ledger/LedgerMaster.cpp
Normal file
1486
src/ripple/module/app/ledger/LedgerMaster.cpp
Normal file
File diff suppressed because it is too large
Load Diff
152
src/ripple/module/app/ledger/LedgerMaster.h
Normal file
152
src/ripple/module/app/ledger/LedgerMaster.h
Normal 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
|
||||
145
src/ripple/module/app/ledger/LedgerProposal.cpp
Normal file
145
src/ripple/module/app/ledger/LedgerProposal.cpp
Normal 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
|
||||
148
src/ripple/module/app/ledger/LedgerProposal.h
Normal file
148
src/ripple/module/app/ledger/LedgerProposal.h
Normal 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
|
||||
181
src/ripple/module/app/ledger/LedgerTiming.cpp
Normal file
181
src/ripple/module/app/ledger/LedgerTiming.cpp
Normal 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
|
||||
111
src/ripple/module/app/ledger/LedgerTiming.h
Normal file
111
src/ripple/module/app/ledger/LedgerTiming.h
Normal 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
|
||||
339
src/ripple/module/app/ledger/OrderBookDB.cpp
Normal file
339
src/ripple/module/app/ledger/OrderBookDB.cpp
Normal 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
|
||||
106
src/ripple/module/app/ledger/OrderBookDB.h
Normal file
106
src/ripple/module/app/ledger/OrderBookDB.h
Normal 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
|
||||
231
src/ripple/module/app/ledger/OrderBookIterator.cpp
Normal file
231
src/ripple/module/app/ledger/OrderBookIterator.cpp
Normal 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
|
||||
238
src/ripple/module/app/ledger/OrderBookIterator.h
Normal file
238
src/ripple/module/app/ledger/OrderBookIterator.h
Normal 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
|
||||
164
src/ripple/module/app/ledger/SerializedValidation.cpp
Normal file
164
src/ripple/module/app/ledger/SerializedValidation.cpp
Normal 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
|
||||
102
src/ripple/module/app/ledger/SerializedValidation.h
Normal file
102
src/ripple/module/app/ledger/SerializedValidation.h
Normal 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
|
||||
18
src/ripple/module/app/ledger/TODO.md
Normal file
18
src/ripple/module/app/ledger/TODO.md
Normal 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
|
||||
1543
src/ripple/module/app/main/Application.cpp
Normal file
1543
src/ripple/module/app/main/Application.cpp
Normal file
File diff suppressed because it is too large
Load Diff
157
src/ripple/module/app/main/Application.h
Normal file
157
src/ripple/module/app/main/Application.h
Normal 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
|
||||
79
src/ripple/module/app/main/CollectorManager.cpp
Normal file
79
src/ripple/module/app/main/CollectorManager.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
40
src/ripple/module/app/main/CollectorManager.h
Normal file
40
src/ripple/module/app/main/CollectorManager.h
Normal 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
|
||||
57
src/ripple/module/app/main/FatalErrorReporter.cpp
Normal file
57
src/ripple/module/app/main/FatalErrorReporter.cpp
Normal 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
|
||||
52
src/ripple/module/app/main/FatalErrorReporter.h
Normal file
52
src/ripple/module/app/main/FatalErrorReporter.h
Normal 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
|
||||
32
src/ripple/module/app/main/FullBelowCache.h
Normal file
32
src/ripple/module/app/main/FullBelowCache.h
Normal 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
|
||||
135
src/ripple/module/app/main/IoServicePool.cpp
Normal file
135
src/ripple/module/app/main/IoServicePool.cpp
Normal 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
|
||||
54
src/ripple/module/app/main/IoServicePool.h
Normal file
54
src/ripple/module/app/main/IoServicePool.h
Normal 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
|
||||
264
src/ripple/module/app/main/LoadManager.cpp
Normal file
264
src/ripple/module/app/main/LoadManager.cpp
Normal 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
|
||||
81
src/ripple/module/app/main/LoadManager.h
Normal file
81
src/ripple/module/app/main/LoadManager.h
Normal 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
|
||||
171
src/ripple/module/app/main/LocalCredentials.cpp
Normal file
171
src/ripple/module/app/main/LocalCredentials.cpp
Normal 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
|
||||
70
src/ripple/module/app/main/LocalCredentials.h
Normal file
70
src/ripple/module/app/main/LocalCredentials.h
Normal 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
|
||||
396
src/ripple/module/app/main/Main.cpp
Normal file
396
src/ripple/module/app/main/Main.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
75
src/ripple/module/app/main/NodeStoreScheduler.cpp
Normal file
75
src/ripple/module/app/main/NodeStoreScheduler.cpp
Normal 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
|
||||
53
src/ripple/module/app/main/NodeStoreScheduler.h
Normal file
53
src/ripple/module/app/main/NodeStoreScheduler.h
Normal 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
|
||||
197
src/ripple/module/app/main/ParameterTable.cpp
Normal file
197
src/ripple/module/app/main/ParameterTable.cpp
Normal 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
|
||||
103
src/ripple/module/app/main/ParameterTable.h
Normal file
103
src/ripple/module/app/main/ParameterTable.h
Normal 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
|
||||
294
src/ripple/module/app/main/RPCHTTPServer.cpp
Normal file
294
src/ripple/module/app/main/RPCHTTPServer.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
43
src/ripple/module/app/main/RPCHTTPServer.h
Normal file
43
src/ripple/module/app/main/RPCHTTPServer.h
Normal 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
|
||||
34
src/ripple/module/app/main/Tuning.h
Normal file
34
src/ripple/module/app/main/Tuning.h
Normal 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
|
||||
28
src/ripple/module/app/misc/AccountItem.cpp
Normal file
28
src/ripple/module/app/misc/AccountItem.cpp
Normal 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
|
||||
91
src/ripple/module/app/misc/AccountItem.h
Normal file
91
src/ripple/module/app/misc/AccountItem.h
Normal 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
|
||||
93
src/ripple/module/app/misc/AccountItems.cpp
Normal file
93
src/ripple/module/app/misc/AccountItems.cpp
Normal 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
Reference in New Issue
Block a user