mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 00:36:48 +00:00
Format first-party source according to .clang-format
This commit is contained in:
committed by
manojsdoshi
parent
65dfc5d19e
commit
50760c6935
@@ -37,25 +37,28 @@ public:
|
||||
TxID txid;
|
||||
Sequence seq;
|
||||
|
||||
TxIDSeq (TxID const& txid_, Sequence const& seq_)
|
||||
: txid (txid_)
|
||||
, seq (seq_)
|
||||
{ }
|
||||
TxIDSeq(TxID const& txid_, Sequence const& seq_)
|
||||
: txid(txid_), seq(seq_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
friend bool operator< (TxIDSeq const& lhs, TxIDSeq const& rhs)
|
||||
friend bool
|
||||
operator<(TxIDSeq const& lhs, TxIDSeq const& rhs)
|
||||
{
|
||||
if (lhs.txid != rhs.txid)
|
||||
return lhs.txid < rhs.txid;
|
||||
return lhs.seq < rhs.seq;
|
||||
}
|
||||
|
||||
friend bool operator< (TxIDSeq const& lhs, TxID const& rhs)
|
||||
friend bool
|
||||
operator<(TxIDSeq const& lhs, TxID const& rhs)
|
||||
{
|
||||
return lhs.txid < rhs;
|
||||
}
|
||||
|
||||
friend bool operator< (TxID const& lhs, TxIDSeq const& rhs)
|
||||
friend bool
|
||||
operator<(TxID const& lhs, TxIDSeq const& rhs)
|
||||
{
|
||||
return lhs < rhs.txid;
|
||||
}
|
||||
@@ -73,17 +76,21 @@ public:
|
||||
@param proposed The set of transactions that we are initially proposing
|
||||
for this round.
|
||||
*/
|
||||
void propose(TxIDSeqVec proposed)
|
||||
void
|
||||
propose(TxIDSeqVec proposed)
|
||||
{
|
||||
// We want to remove any entries that we proposed in a previous round
|
||||
// that did not make it in yet if we are no longer proposing them.
|
||||
// And we also want to preserve the Sequence of entries that we proposed
|
||||
// in the last round and want to propose again.
|
||||
std::sort(proposed.begin(), proposed.end());
|
||||
generalized_set_intersection(proposed.begin(), proposed.end(),
|
||||
tracker_.cbegin(), tracker_.cend(),
|
||||
[](auto& x, auto const& y) {x.seq = y.seq;},
|
||||
[](auto const& x, auto const& y) {return x.txid < y.txid;});
|
||||
generalized_set_intersection(
|
||||
proposed.begin(),
|
||||
proposed.end(),
|
||||
tracker_.cbegin(),
|
||||
tracker_.cend(),
|
||||
[](auto& x, auto const& y) { x.seq = y.seq; },
|
||||
[](auto const& x, auto const& y) { return x.txid < y.txid; });
|
||||
tracker_ = std::move(proposed);
|
||||
}
|
||||
|
||||
@@ -101,9 +108,8 @@ public:
|
||||
It must return true for entries that should be removed.
|
||||
*/
|
||||
template <class Predicate>
|
||||
void check(
|
||||
std::vector<TxID> accepted,
|
||||
Predicate&& pred)
|
||||
void
|
||||
check(std::vector<TxID> accepted, Predicate&& pred)
|
||||
{
|
||||
auto acceptTxid = accepted.begin();
|
||||
auto const ae = accepted.end();
|
||||
@@ -112,10 +118,13 @@ public:
|
||||
// We want to remove all tracking entries for transactions that were
|
||||
// accepted as well as those which match the predicate.
|
||||
|
||||
auto i = remove_if_intersect_or_match(tracker_.begin(), tracker_.end(),
|
||||
accepted.begin(), accepted.end(),
|
||||
[&pred](auto const& x) {return pred(x.txid, x.seq);},
|
||||
std::less<void>{});
|
||||
auto i = remove_if_intersect_or_match(
|
||||
tracker_.begin(),
|
||||
tracker_.end(),
|
||||
accepted.begin(),
|
||||
accepted.end(),
|
||||
[&pred](auto const& x) { return pred(x.txid, x.seq); },
|
||||
std::less<void>{});
|
||||
tracker_.erase(i, tracker_.end());
|
||||
}
|
||||
|
||||
@@ -124,12 +133,13 @@ public:
|
||||
Typically, this function might be called after we reconnect to the
|
||||
network following an outage, or after we start tracking the network.
|
||||
*/
|
||||
void reset()
|
||||
void
|
||||
reset()
|
||||
{
|
||||
tracker_.clear();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -77,14 +77,14 @@ RCLConsensus::Adaptor::Adaptor(
|
||||
ValidatorKeys const& validatorKeys,
|
||||
beast::Journal journal)
|
||||
: app_(app)
|
||||
, feeVote_(std::move(feeVote))
|
||||
, ledgerMaster_(ledgerMaster)
|
||||
, localTxs_(localTxs)
|
||||
, inboundTransactions_{inboundTransactions}
|
||||
, j_(journal)
|
||||
, nodeID_{validatorKeys.nodeID}
|
||||
, valPublic_{validatorKeys.publicKey}
|
||||
, valSecret_{validatorKeys.secretKey}
|
||||
, feeVote_(std::move(feeVote))
|
||||
, ledgerMaster_(ledgerMaster)
|
||||
, localTxs_(localTxs)
|
||||
, inboundTransactions_{inboundTransactions}
|
||||
, j_(journal)
|
||||
, nodeID_{validatorKeys.nodeID}
|
||||
, valPublic_{validatorKeys.publicKey}
|
||||
, valSecret_{validatorKeys.secretKey}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -103,11 +103,12 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash)
|
||||
// Tell the ledger acquire system that we need the consensus ledger
|
||||
acquiringLedger_ = hash;
|
||||
|
||||
app_.getJobQueue().addJob(jtADVANCE, "getConsensusLedger",
|
||||
[id = hash, &app = app_](Job&)
|
||||
{
|
||||
app.getInboundLedgers().acquire(id, 0,
|
||||
InboundLedger::Reason::CONSENSUS);
|
||||
app_.getJobQueue().addJob(
|
||||
jtADVANCE,
|
||||
"getConsensusLedger",
|
||||
[id = hash, &app = app_](Job&) {
|
||||
app.getInboundLedgers().acquire(
|
||||
id, 0, InboundLedger::Reason::CONSENSUS);
|
||||
});
|
||||
}
|
||||
return boost::none;
|
||||
@@ -205,7 +206,7 @@ RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal)
|
||||
valPublic_,
|
||||
sig);
|
||||
|
||||
app_.getHashRouter ().addSuppression (suppression);
|
||||
app_.getHashRouter().addSuppression(suppression);
|
||||
|
||||
app_.overlay().send(prop);
|
||||
}
|
||||
@@ -264,7 +265,7 @@ RCLConsensus::Adaptor::getPrevLedger(
|
||||
if (mode != ConsensusMode::wrongLedger)
|
||||
app_.getOPs().consensusViewChange();
|
||||
|
||||
JLOG(j_.debug())<< Json::Compact(app_.getValidations().getJsonTrie());
|
||||
JLOG(j_.debug()) << Json::Compact(app_.getValidations().getJsonTrie());
|
||||
}
|
||||
|
||||
return netLgr;
|
||||
@@ -289,15 +290,15 @@ RCLConsensus::Adaptor::onClose(
|
||||
|
||||
auto initialLedger = app_.openLedger().current();
|
||||
|
||||
auto initialSet = std::make_shared<SHAMap>(
|
||||
SHAMapType::TRANSACTION, app_.family());
|
||||
auto initialSet =
|
||||
std::make_shared<SHAMap>(SHAMapType::TRANSACTION, app_.family());
|
||||
initialSet->setUnbacked();
|
||||
|
||||
// Build SHAMap containing all transactions in our open ledger
|
||||
for (auto const& tx : initialLedger->txs)
|
||||
{
|
||||
JLOG(j_.trace()) << "Adding open ledger TX " <<
|
||||
tx.first->getTransactionID();
|
||||
JLOG(j_.trace()) << "Adding open ledger TX "
|
||||
<< tx.first->getTransactionID();
|
||||
Serializer s(2048);
|
||||
tx.first->add(s);
|
||||
initialSet->addItem(
|
||||
@@ -311,11 +312,10 @@ RCLConsensus::Adaptor::onClose(
|
||||
((prevLedger->info().seq % 256) == 0))
|
||||
{
|
||||
// previous ledger was flag ledger, add pseudo-transactions
|
||||
auto const validations =
|
||||
app_.getValidations().getTrustedForLedger (
|
||||
prevLedger->info().parentHash);
|
||||
auto const validations = app_.getValidations().getTrustedForLedger(
|
||||
prevLedger->info().parentHash);
|
||||
|
||||
if (validations.size() >= app_.validators ().quorum ())
|
||||
if (validations.size() >= app_.validators().quorum())
|
||||
{
|
||||
feeVote_->doVoting(prevLedger, validations, initialSet);
|
||||
app_.getAmendmentTable().doVoting(
|
||||
@@ -332,8 +332,7 @@ RCLConsensus::Adaptor::onClose(
|
||||
RCLCensorshipDetector<TxID, LedgerIndex>::TxIDSeqVec proposed;
|
||||
|
||||
initialSet->visitLeaves(
|
||||
[&proposed, seq](std::shared_ptr<SHAMapItem const> const& item)
|
||||
{
|
||||
[&proposed, seq](std::shared_ptr<SHAMapItem const> const& item) {
|
||||
proposed.emplace_back(item->key(), seq);
|
||||
});
|
||||
|
||||
@@ -361,7 +360,7 @@ RCLConsensus::Adaptor::onForceAccept(
|
||||
NetClock::duration const& closeResolution,
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
Json::Value&& consensusJson)
|
||||
{
|
||||
doAccept(
|
||||
result,
|
||||
@@ -379,12 +378,12 @@ RCLConsensus::Adaptor::onAccept(
|
||||
NetClock::duration const& closeResolution,
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
Json::Value&& consensusJson)
|
||||
{
|
||||
app_.getJobQueue().addJob(
|
||||
jtACCEPT,
|
||||
"acceptLedger",
|
||||
[=, cj = std::move(consensusJson) ](auto&) mutable {
|
||||
[=, cj = std::move(consensusJson)](auto&) mutable {
|
||||
// Note that no lock is held or acquired during this job.
|
||||
// This is because generic Consensus guarantees that once a ledger
|
||||
// is accepted, the consensus results and capture by reference state
|
||||
@@ -408,7 +407,7 @@ RCLConsensus::Adaptor::doAccept(
|
||||
NetClock::duration closeResolution,
|
||||
ConsensusCloseTimes const& rawCloseTimes,
|
||||
ConsensusMode const& mode,
|
||||
Json::Value && consensusJson)
|
||||
Json::Value&& consensusJson)
|
||||
{
|
||||
prevProposers_ = result.proposers;
|
||||
prevRoundTime_ = result.roundTime.read();
|
||||
@@ -450,7 +449,7 @@ RCLConsensus::Adaptor::doAccept(
|
||||
// we use the hash of the set.
|
||||
//
|
||||
// FIXME: Use a std::vector and a custom sorter instead of CanonicalTXSet?
|
||||
CanonicalTXSet retriableTxs{ result.txns.map_->getHash().as_uint256() };
|
||||
CanonicalTXSet retriableTxs{result.txns.map_->getHash().as_uint256()};
|
||||
|
||||
JLOG(j_.debug()) << "Building canonical tx set: " << retriableTxs.key();
|
||||
|
||||
@@ -458,7 +457,8 @@ RCLConsensus::Adaptor::doAccept(
|
||||
{
|
||||
try
|
||||
{
|
||||
retriableTxs.insert(std::make_shared<STTx const>(SerialIter{item.slice()}));
|
||||
retriableTxs.insert(
|
||||
std::make_shared<STTx const>(SerialIter{item.slice()}));
|
||||
JLOG(j_.debug()) << " Tx: " << item.key();
|
||||
}
|
||||
catch (std::exception const&)
|
||||
@@ -468,8 +468,14 @@ RCLConsensus::Adaptor::doAccept(
|
||||
}
|
||||
}
|
||||
|
||||
auto built = buildLCL(prevLedger, retriableTxs, consensusCloseTime,
|
||||
closeTimeCorrect, closeResolution, result.roundTime.read(), failed);
|
||||
auto built = buildLCL(
|
||||
prevLedger,
|
||||
retriableTxs,
|
||||
consensusCloseTime,
|
||||
closeTimeCorrect,
|
||||
closeResolution,
|
||||
result.roundTime.read(),
|
||||
failed);
|
||||
|
||||
auto const newLCLHash = built.id();
|
||||
JLOG(j_.debug()) << "Built ledger #" << built.seq() << ": " << newLCLHash;
|
||||
@@ -484,20 +490,20 @@ RCLConsensus::Adaptor::doAccept(
|
||||
{
|
||||
std::vector<TxID> accepted;
|
||||
|
||||
result.txns.map_->visitLeaves (
|
||||
[&accepted](std::shared_ptr<SHAMapItem const> const& item)
|
||||
{
|
||||
result.txns.map_->visitLeaves(
|
||||
[&accepted](std::shared_ptr<SHAMapItem const> const& item) {
|
||||
accepted.push_back(item->key());
|
||||
});
|
||||
|
||||
// Track all the transactions which failed or were marked as retriable
|
||||
for (auto const& r : retriableTxs)
|
||||
failed.insert (r.first.getTXID());
|
||||
failed.insert(r.first.getTXID());
|
||||
|
||||
censorshipDetector_.check(std::move(accepted),
|
||||
[curr = built.seq(), j = app_.journal("CensorshipDetector"), &failed]
|
||||
(uint256 const& id, LedgerIndex seq)
|
||||
{
|
||||
censorshipDetector_.check(
|
||||
std::move(accepted),
|
||||
[curr = built.seq(),
|
||||
j = app_.journal("CensorshipDetector"),
|
||||
&failed](uint256 const& id, LedgerIndex seq) {
|
||||
if (failed.count(id))
|
||||
return true;
|
||||
|
||||
@@ -508,8 +514,7 @@ RCLConsensus::Adaptor::doAccept(
|
||||
std::ostringstream ss;
|
||||
ss << "Potential Censorship: Eligible tx " << id
|
||||
<< ", which we are tracking since ledger " << seq
|
||||
<< " has not been included as of ledger " << curr
|
||||
<< ".";
|
||||
<< " has not been included as of ledger " << curr << ".";
|
||||
|
||||
JLOG(j.warn()) << ss.str();
|
||||
}
|
||||
@@ -617,15 +622,16 @@ RCLConsensus::Adaptor::doAccept(
|
||||
|
||||
// Do these need to exist?
|
||||
assert(ledgerMaster_.getClosedLedger()->info().hash == built.id());
|
||||
assert(
|
||||
app_.openLedger().current()->info().parentHash == built.id());
|
||||
assert(app_.openLedger().current()->info().parentHash == built.id());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// we entered the round with the network,
|
||||
// see how close our close time is to other node's
|
||||
// close time reports, and update our clock.
|
||||
if ((mode == ConsensusMode::proposing || mode == ConsensusMode::observing) && !consensusFail)
|
||||
if ((mode == ConsensusMode::proposing ||
|
||||
mode == ConsensusMode::observing) &&
|
||||
!consensusFail)
|
||||
{
|
||||
auto closeTime = rawCloseTimes.self;
|
||||
|
||||
@@ -638,9 +644,8 @@ RCLConsensus::Adaptor::doAccept(
|
||||
|
||||
for (auto const& [t, v] : rawCloseTimes.peers)
|
||||
{
|
||||
JLOG(j_.info())
|
||||
<< std::to_string(v) << " time votes for "
|
||||
<< std::to_string(t.time_since_epoch().count());
|
||||
JLOG(j_.info()) << std::to_string(v) << " time votes for "
|
||||
<< std::to_string(t.time_since_epoch().count());
|
||||
closeCount += v;
|
||||
closeTotal +=
|
||||
std::chrono::duration_cast<usec64_t>(t.time_since_epoch()) * v;
|
||||
@@ -695,10 +700,9 @@ RCLConsensus::Adaptor::notify(
|
||||
}
|
||||
s.set_firstseq(uMin);
|
||||
s.set_lastseq(uMax);
|
||||
app_.overlay ().foreach (send_always (
|
||||
std::make_shared <Message> (
|
||||
s, protocol::mtSTATUS_CHANGE)));
|
||||
JLOG (j_.trace()) << "send status change to peer";
|
||||
app_.overlay().foreach (
|
||||
send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
|
||||
JLOG(j_.trace()) << "send status change to peer";
|
||||
}
|
||||
|
||||
RCLCxLedger
|
||||
@@ -711,15 +715,21 @@ RCLConsensus::Adaptor::buildLCL(
|
||||
std::chrono::milliseconds roundTime,
|
||||
std::set<TxID>& failedTxs)
|
||||
{
|
||||
std::shared_ptr<Ledger> built = [&]()
|
||||
{
|
||||
std::shared_ptr<Ledger> built = [&]() {
|
||||
if (auto const replayData = ledgerMaster_.releaseReplay())
|
||||
{
|
||||
assert(replayData->parent()->info().hash == previousLedger.id());
|
||||
return buildLedger(*replayData, tapNONE, app_, j_);
|
||||
}
|
||||
return buildLedger(previousLedger.ledger_, closeTime, closeTimeCorrect,
|
||||
closeResolution, app_, retriableTxs, failedTxs, j_);
|
||||
return buildLedger(
|
||||
previousLedger.ledger_,
|
||||
closeTime,
|
||||
closeTimeCorrect,
|
||||
closeResolution,
|
||||
app_,
|
||||
retriableTxs,
|
||||
failedTxs,
|
||||
j_);
|
||||
}();
|
||||
|
||||
// Update fee computations based on accepted txs
|
||||
@@ -737,7 +747,8 @@ RCLConsensus::Adaptor::buildLCL(
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger,
|
||||
RCLConsensus::Adaptor::validate(
|
||||
RCLCxLedger const& ledger,
|
||||
RCLTxSet const& txns,
|
||||
bool proposing)
|
||||
{
|
||||
@@ -762,7 +773,8 @@ RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger,
|
||||
{
|
||||
// Suggest fee changes and new features
|
||||
feeVote_->doValidation(ledger.ledger_, fees);
|
||||
amendments = app_.getAmendmentTable().doValidation (getEnabledAmendments(*ledger.ledger_));
|
||||
amendments = app_.getAmendmentTable().doValidation(
|
||||
getEnabledAmendments(*ledger.ledger_));
|
||||
}
|
||||
|
||||
auto v = std::make_shared<STValidation>(
|
||||
@@ -789,16 +801,16 @@ RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger,
|
||||
}
|
||||
|
||||
void
|
||||
RCLConsensus::Adaptor::onModeChange(
|
||||
ConsensusMode before,
|
||||
ConsensusMode after)
|
||||
RCLConsensus::Adaptor::onModeChange(ConsensusMode before, ConsensusMode after)
|
||||
{
|
||||
JLOG(j_.info()) << "Consensus mode change before=" << to_string(before)
|
||||
<< ", after=" << to_string(after);
|
||||
|
||||
// If we were proposing but aren't any longer, we need to reset the
|
||||
// censorship tracking to avoid bogus warnings.
|
||||
if ((before == ConsensusMode::proposing || before == ConsensusMode::observing) && before != after)
|
||||
if ((before == ConsensusMode::proposing ||
|
||||
before == ConsensusMode::observing) &&
|
||||
before != after)
|
||||
censorshipDetector_.reset();
|
||||
|
||||
mode_ = after;
|
||||
@@ -809,8 +821,8 @@ RCLConsensus::getJson(bool full) const
|
||||
{
|
||||
Json::Value ret;
|
||||
{
|
||||
std::lock_guard _{mutex_};
|
||||
ret = consensus_.getJson(full);
|
||||
std::lock_guard _{mutex_};
|
||||
ret = consensus_.getJson(full);
|
||||
}
|
||||
ret["validating"] = adaptor_.validating();
|
||||
return ret;
|
||||
@@ -848,7 +860,6 @@ RCLConsensus::gotTxSet(NetClock::time_point const& now, RCLTxSet const& txSet)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! @see Consensus::simulate
|
||||
|
||||
void
|
||||
@@ -870,13 +881,13 @@ RCLConsensus::peerProposal(
|
||||
}
|
||||
|
||||
bool
|
||||
RCLConsensus::Adaptor::preStartRound(RCLCxLedger const & prevLgr)
|
||||
RCLConsensus::Adaptor::preStartRound(RCLCxLedger const& prevLgr)
|
||||
{
|
||||
// We have a key, we do not want out of sync validations after a restart
|
||||
// and are not amendment blocked.
|
||||
validating_ = valPublic_.size() != 0 &&
|
||||
prevLgr.seq() >= app_.getMaxDisallowedLedger() &&
|
||||
!app_.getOPs().isAmendmentBlocked();
|
||||
prevLgr.seq() >= app_.getMaxDisallowedLedger() &&
|
||||
!app_.getOPs().isAmendmentBlocked();
|
||||
|
||||
// If we are not running in standalone mode and there's a configured UNL,
|
||||
// check to make sure that it's not expired.
|
||||
@@ -892,8 +903,7 @@ RCLConsensus::Adaptor::preStartRound(RCLCxLedger const & prevLgr)
|
||||
}
|
||||
}
|
||||
|
||||
const bool synced = app_.getOPs().getOperatingMode() ==
|
||||
OperatingMode::FULL;
|
||||
const bool synced = app_.getOPs().getOperatingMode() == OperatingMode::FULL;
|
||||
|
||||
if (validating_)
|
||||
{
|
||||
@@ -933,7 +943,8 @@ RCLConsensus::Adaptor::getQuorumKeys() const
|
||||
}
|
||||
|
||||
std::size_t
|
||||
RCLConsensus::Adaptor::laggards(Ledger_t::Seq const seq,
|
||||
RCLConsensus::Adaptor::laggards(
|
||||
Ledger_t::Seq const seq,
|
||||
hash_set<RCLConsensus::Adaptor::NodeKey_t>& trustedKeys) const
|
||||
{
|
||||
return app_.getValidations().laggards(seq, trustedKeys);
|
||||
@@ -948,7 +959,7 @@ RCLConsensus::Adaptor::validator() const
|
||||
void
|
||||
RCLConsensus::Adaptor::updateOperatingMode(std::size_t const positions) const
|
||||
{
|
||||
if (! positions && app_.getOPs().isFull())
|
||||
if (!positions && app_.getOPs().isFull())
|
||||
app_.getOPs().setMode(OperatingMode::CONNECTED);
|
||||
}
|
||||
|
||||
@@ -963,4 +974,4 @@ RCLConsensus::startRound(
|
||||
consensus_.startRound(
|
||||
now, prevLgrId, prevLgr, nowUntrusted, adaptor_.preStartRound(prevLgr));
|
||||
}
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#ifndef RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED
|
||||
#define RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED
|
||||
|
||||
#include <ripple/app/consensus/RCLCensorshipDetector.h>
|
||||
#include <ripple/app/consensus/RCLCxLedger.h>
|
||||
#include <ripple/app/consensus/RCLCxPeerPos.h>
|
||||
#include <ripple/app/consensus/RCLCxTx.h>
|
||||
#include <ripple/app/consensus/RCLCensorshipDetector.h>
|
||||
#include <ripple/app/misc/FeeVote.h>
|
||||
#include <ripple/basics/CountedObject.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
@@ -45,10 +45,11 @@ class LedgerMaster;
|
||||
class ValidatorKeys;
|
||||
|
||||
/** Manages the generic consensus algorithm for use by the RCL.
|
||||
*/
|
||||
*/
|
||||
class RCLConsensus
|
||||
{
|
||||
/** Warn for transactions that haven't been included every so many ledgers. */
|
||||
/** Warn for transactions that haven't been included every so many ledgers.
|
||||
*/
|
||||
constexpr static unsigned int censorshipWarnInternal = 15;
|
||||
|
||||
// Implements the Adaptor template interface required by Consensus.
|
||||
@@ -97,7 +98,7 @@ class RCLConsensus
|
||||
LedgerMaster& ledgerMaster,
|
||||
LocalTxs& localTxs,
|
||||
InboundTransactions& inboundTransactions,
|
||||
ValidatorKeys const & validatorKeys,
|
||||
ValidatorKeys const& validatorKeys,
|
||||
beast::Journal journal);
|
||||
|
||||
bool
|
||||
@@ -130,7 +131,7 @@ class RCLConsensus
|
||||
@return Whether we enter the round proposing
|
||||
*/
|
||||
bool
|
||||
preStartRound(RCLCxLedger const & prevLedger);
|
||||
preStartRound(RCLCxLedger const& prevLedger);
|
||||
|
||||
bool
|
||||
haveValidated() const;
|
||||
@@ -142,8 +143,8 @@ class RCLConsensus
|
||||
getQuorumKeys() const;
|
||||
|
||||
std::size_t
|
||||
laggards(Ledger_t::Seq const seq,
|
||||
hash_set<NodeKey_t >& trustedKeys) const;
|
||||
laggards(Ledger_t::Seq const seq, hash_set<NodeKey_t>& trustedKeys)
|
||||
const;
|
||||
|
||||
/** Whether I am a validator.
|
||||
*
|
||||
@@ -159,7 +160,8 @@ class RCLConsensus
|
||||
*
|
||||
* @param positions Number of current peer positions.
|
||||
*/
|
||||
void updateOperatingMode(std::size_t const positions) const;
|
||||
void
|
||||
updateOperatingMode(std::size_t const positions) const;
|
||||
|
||||
/** Consensus simulation parameters
|
||||
*/
|
||||
@@ -173,9 +175,9 @@ class RCLConsensus
|
||||
//---------------------------------------------------------------------
|
||||
// The following members implement the generic Consensus requirements
|
||||
// and are marked private to indicate ONLY Consensus<Adaptor> will call
|
||||
// them (via friendship). Since they are called only from Consensus<Adaptor>
|
||||
// methods and since RCLConsensus::consensus_ should only be accessed
|
||||
// under lock, these will only be called under lock.
|
||||
// them (via friendship). Since they are called only from
|
||||
// Consensus<Adaptor> methods and since RCLConsensus::consensus_ should
|
||||
// only be accessed under lock, these will only be called under lock.
|
||||
//
|
||||
// In general, the idea is that there is only ONE thread that is running
|
||||
// consensus code at anytime. The only special case is the dispatched
|
||||
@@ -242,7 +244,7 @@ class RCLConsensus
|
||||
descended from the preferred working ledger.
|
||||
*/
|
||||
std::size_t
|
||||
proposersFinished(RCLCxLedger const & ledger, LedgerHash const& h) const;
|
||||
proposersFinished(RCLCxLedger const& ledger, LedgerHash const& h) const;
|
||||
|
||||
/** Propose the given position to my peers.
|
||||
|
||||
@@ -281,9 +283,7 @@ class RCLConsensus
|
||||
@param after The new consensus mode
|
||||
*/
|
||||
void
|
||||
onModeChange(
|
||||
ConsensusMode before,
|
||||
ConsensusMode after);
|
||||
onModeChange(ConsensusMode before, ConsensusMode after);
|
||||
|
||||
/** Close the open ledger and return initial consensus position.
|
||||
|
||||
@@ -400,7 +400,10 @@ class RCLConsensus
|
||||
but are still around and trying to catch up.
|
||||
*/
|
||||
void
|
||||
validate(RCLCxLedger const& ledger, RCLTxSet const& txns, bool proposing);
|
||||
validate(
|
||||
RCLCxLedger const& ledger,
|
||||
RCLTxSet const& txns,
|
||||
bool proposing);
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -412,7 +415,7 @@ public:
|
||||
LocalTxs& localTxs,
|
||||
InboundTransactions& inboundTransactions,
|
||||
Consensus<Adaptor>::clock_type const& clock,
|
||||
ValidatorKeys const & validatorKeys,
|
||||
ValidatorKeys const& validatorKeys,
|
||||
beast::Journal journal);
|
||||
|
||||
RCLConsensus(RCLConsensus const&) = delete;
|
||||
@@ -501,7 +504,7 @@ public:
|
||||
NetClock::time_point const& now,
|
||||
RCLCxPeerPos const& newProposal);
|
||||
|
||||
ConsensusParms const &
|
||||
ConsensusParms const&
|
||||
parms() const
|
||||
{
|
||||
return adaptor_.parms();
|
||||
@@ -517,6 +520,6 @@ private:
|
||||
Consensus<Adaptor> consensus_;
|
||||
beast::Journal const j_;
|
||||
};
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -119,5 +119,5 @@ public:
|
||||
*/
|
||||
std::shared_ptr<Ledger const> ledger_;
|
||||
};
|
||||
}
|
||||
} // namespace ripple
|
||||
#endif
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
#include <ripple/app/consensus/RCLCxPeerPos.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/HashPrefix.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -54,11 +54,9 @@ RCLCxPeerPos::signingHash() const
|
||||
bool
|
||||
RCLCxPeerPos::checkSign() const
|
||||
{
|
||||
return verifyDigest(
|
||||
publicKey(), signingHash(), signature(), false);
|
||||
return verifyDigest(publicKey(), signingHash(), signature(), false);
|
||||
}
|
||||
|
||||
|
||||
Json::Value
|
||||
RCLCxPeerPos::getJson() const
|
||||
{
|
||||
@@ -102,4 +100,4 @@ RCLCxPeerPos::Data::Data(
|
||||
{
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
return data_->suppression_;
|
||||
}
|
||||
|
||||
Proposal const &
|
||||
Proposal const&
|
||||
proposal() const
|
||||
{
|
||||
return data_->proposal_;
|
||||
@@ -101,7 +101,6 @@ public:
|
||||
getJson() const;
|
||||
|
||||
private:
|
||||
|
||||
struct Data : public CountedObject<Data>
|
||||
{
|
||||
PublicKey publicKey_;
|
||||
@@ -135,7 +134,6 @@ private:
|
||||
hash_append(h, proposal().prevLedger());
|
||||
hash_append(h, proposal().position());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Calculate a unique identifier for a signed proposal.
|
||||
@@ -163,6 +161,6 @@ proposalUniqueId(
|
||||
Slice const& publicKey,
|
||||
Slice const& signature);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -178,9 +178,7 @@ public:
|
||||
std::map<uint256, bool> ret;
|
||||
for (auto const& [k, v] : delta)
|
||||
{
|
||||
assert(
|
||||
(v.first && !v.second) ||
|
||||
(v.second && !v.first));
|
||||
assert((v.first && !v.second) || (v.second && !v.first));
|
||||
|
||||
ret[k] = static_cast<bool>(v.first);
|
||||
}
|
||||
@@ -190,5 +188,5 @@ public:
|
||||
//! The SHAMap representing the transactions.
|
||||
std::shared_ptr<SHAMap> map_;
|
||||
};
|
||||
}
|
||||
} // namespace ripple
|
||||
#endif
|
||||
|
||||
@@ -75,7 +75,8 @@ RCLValidatedLedger::id() const -> ID
|
||||
return ledgerID_;
|
||||
}
|
||||
|
||||
auto RCLValidatedLedger::operator[](Seq const& s) const -> ID
|
||||
auto
|
||||
RCLValidatedLedger::operator[](Seq const& s) const -> ID
|
||||
{
|
||||
if (s >= minSeq() && s <= seq())
|
||||
{
|
||||
@@ -112,7 +113,7 @@ mismatch(RCLValidatedLedger const& a, RCLValidatedLedger const& b)
|
||||
}
|
||||
|
||||
RCLValidationsAdaptor::RCLValidationsAdaptor(Application& app, beast::Journal j)
|
||||
: app_(app), j_(j)
|
||||
: app_(app), j_(j)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ RCLValidationsAdaptor::now() const
|
||||
}
|
||||
|
||||
boost::optional<RCLValidatedLedger>
|
||||
RCLValidationsAdaptor::acquire(LedgerHash const & hash)
|
||||
RCLValidationsAdaptor::acquire(LedgerHash const& hash)
|
||||
{
|
||||
auto ledger = app_.getLedgerMaster().getLedgerByHash(hash);
|
||||
if (!ledger)
|
||||
@@ -131,11 +132,11 @@ RCLValidationsAdaptor::acquire(LedgerHash const & hash)
|
||||
JLOG(j_.debug())
|
||||
<< "Need validated ledger for preferred ledger analysis " << hash;
|
||||
|
||||
Application * pApp = &app_;
|
||||
Application* pApp = &app_;
|
||||
|
||||
app_.getJobQueue().addJob(
|
||||
jtADVANCE, "getConsensusLedger", [pApp, hash](Job&) {
|
||||
pApp ->getInboundLedgers().acquire(
|
||||
pApp->getInboundLedgers().acquire(
|
||||
hash, 0, InboundLedger::Reason::CONSENSUS);
|
||||
});
|
||||
return boost::none;
|
||||
@@ -148,7 +149,8 @@ RCLValidationsAdaptor::acquire(LedgerHash const & hash)
|
||||
}
|
||||
|
||||
bool
|
||||
handleNewValidation(Application& app,
|
||||
handleNewValidation(
|
||||
Application& app,
|
||||
STValidation::ref val,
|
||||
std::string const& source)
|
||||
{
|
||||
@@ -175,14 +177,13 @@ handleNewValidation(Application& app,
|
||||
<< (val->isFull() ? "full" : "partial") << " from "
|
||||
<< (masterKey ? toBase58(TokenType::NodePublic, *masterKey)
|
||||
: "unknown")
|
||||
<< " signing key "
|
||||
<< toBase58(TokenType::NodePublic, signingKey) << " " << msg
|
||||
<< " src=" << source;
|
||||
<< " signing key " << toBase58(TokenType::NodePublic, signingKey)
|
||||
<< " " << msg << " src=" << source;
|
||||
};
|
||||
|
||||
if(!val->isFieldPresent(sfLedgerSequence))
|
||||
if (!val->isFieldPresent(sfLedgerSequence))
|
||||
{
|
||||
if(j.error())
|
||||
if (j.error())
|
||||
dmp(j.error(), "missing ledger sequence field");
|
||||
return false;
|
||||
}
|
||||
@@ -191,7 +192,7 @@ handleNewValidation(Application& app,
|
||||
if (masterKey)
|
||||
{
|
||||
ValStatus const outcome = validations.add(calcNodeID(*masterKey), val);
|
||||
if(j.debug())
|
||||
if (j.debug())
|
||||
dmp(j.debug(), to_string(outcome));
|
||||
|
||||
if (outcome == ValStatus::badSeq && j.warn())
|
||||
@@ -211,8 +212,8 @@ handleNewValidation(Application& app,
|
||||
else
|
||||
{
|
||||
JLOG(j.debug()) << "Val for " << hash << " from "
|
||||
<< toBase58(TokenType::NodePublic, signingKey)
|
||||
<< " not added UNlisted";
|
||||
<< toBase58(TokenType::NodePublic, signingKey)
|
||||
<< " not added UNlisted";
|
||||
}
|
||||
|
||||
// This currently never forwards untrusted validations, though we may
|
||||
@@ -226,5 +227,4 @@ handleNewValidation(Application& app,
|
||||
return shouldRelay;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -39,6 +39,7 @@ class Application;
|
||||
class RCLValidation
|
||||
{
|
||||
STValidation::pointer val_;
|
||||
|
||||
public:
|
||||
using NodeKey = ripple::PublicKey;
|
||||
using NodeID = ripple::NodeID;
|
||||
@@ -132,7 +133,6 @@ public:
|
||||
{
|
||||
return val_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Wraps a ledger instance for use in generic Validations LedgerTrie.
|
||||
@@ -174,7 +174,8 @@ public:
|
||||
@return The ID of this ledger's ancestor with that sequence number or
|
||||
ID{0} if one was not determined
|
||||
*/
|
||||
ID operator[](Seq const& s) const;
|
||||
ID
|
||||
operator[](Seq const& s) const;
|
||||
|
||||
/// Find the sequence number of the earliest mismatching ancestor
|
||||
friend Seq
|
||||
@@ -212,7 +213,7 @@ public:
|
||||
|
||||
/** Attempt to acquire the ledger with given id from the network */
|
||||
boost::optional<RCLValidatedLedger>
|
||||
acquire(LedgerHash const & id);
|
||||
acquire(LedgerHash const& id);
|
||||
|
||||
beast::Journal
|
||||
journal() const
|
||||
@@ -228,7 +229,6 @@ private:
|
||||
/// Alias for RCL-specific instantiation of generic Validations
|
||||
using RCLValidations = Validations<RCLValidationsAdaptor>;
|
||||
|
||||
|
||||
/** Handle a new validation
|
||||
|
||||
Also sets the trust status of a validation based on the validating node's
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_ABSTRACTFETCHPACKCONTAINER_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_ABSTRACTFETCHPACKCONTAINER_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/basics/Blob.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace ripple {
|
||||
@@ -40,9 +40,10 @@ public:
|
||||
@return `boost::none` if the hash isn't cached,
|
||||
otherwise, the hash associated data.
|
||||
*/
|
||||
virtual boost::optional<Blob> getFetchPack(uint256 const& nodeHash) = 0;
|
||||
virtual boost::optional<Blob>
|
||||
getFetchPack(uint256 const& nodeHash) = 0;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,32 +23,35 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
AcceptedLedger::AcceptedLedger (
|
||||
AcceptedLedger::AcceptedLedger(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
AccountIDCache const& accountCache, Logs& logs)
|
||||
: mLedger (ledger)
|
||||
AccountIDCache const& accountCache,
|
||||
Logs& logs)
|
||||
: mLedger(ledger)
|
||||
{
|
||||
for (auto const& item : ledger->txs)
|
||||
{
|
||||
insert (std::make_shared<AcceptedLedgerTx>(
|
||||
insert(std::make_shared<AcceptedLedgerTx>(
|
||||
ledger, item.first, item.second, accountCache, logs));
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptedLedger::insert (AcceptedLedgerTx::ref at)
|
||||
void
|
||||
AcceptedLedger::insert(AcceptedLedgerTx::ref at)
|
||||
{
|
||||
assert (mMap.find (at->getIndex ()) == mMap.end ());
|
||||
mMap.insert (std::make_pair (at->getIndex (), at));
|
||||
assert(mMap.find(at->getIndex()) == mMap.end());
|
||||
mMap.insert(std::make_pair(at->getIndex(), at));
|
||||
}
|
||||
|
||||
AcceptedLedgerTx::pointer AcceptedLedger::getTxn (int i) const
|
||||
AcceptedLedgerTx::pointer
|
||||
AcceptedLedger::getTxn(int i) const
|
||||
{
|
||||
map_t::const_iterator it = mMap.find (i);
|
||||
map_t::const_iterator it = mMap.find(i);
|
||||
|
||||
if (it == mMap.end ())
|
||||
return AcceptedLedgerTx::pointer ();
|
||||
if (it == mMap.end())
|
||||
return AcceptedLedgerTx::pointer();
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -44,41 +44,46 @@ namespace ripple {
|
||||
class AcceptedLedger
|
||||
{
|
||||
public:
|
||||
using pointer = std::shared_ptr<AcceptedLedger>;
|
||||
using ret = const pointer&;
|
||||
using map_t = std::map<int, AcceptedLedgerTx::pointer>;
|
||||
using pointer = std::shared_ptr<AcceptedLedger>;
|
||||
using ret = const pointer&;
|
||||
using map_t = std::map<int, AcceptedLedgerTx::pointer>;
|
||||
// mapt_t must be an ordered map!
|
||||
using value_type = map_t::value_type;
|
||||
using value_type = map_t::value_type;
|
||||
using const_iterator = map_t::const_iterator;
|
||||
|
||||
public:
|
||||
std::shared_ptr<ReadView const> const& getLedger () const
|
||||
std::shared_ptr<ReadView const> const&
|
||||
getLedger() const
|
||||
{
|
||||
return mLedger;
|
||||
}
|
||||
const map_t& getMap () const
|
||||
const map_t&
|
||||
getMap() const
|
||||
{
|
||||
return mMap;
|
||||
}
|
||||
|
||||
int getTxnCount () const
|
||||
int
|
||||
getTxnCount() const
|
||||
{
|
||||
return mMap.size ();
|
||||
return mMap.size();
|
||||
}
|
||||
|
||||
AcceptedLedgerTx::pointer getTxn (int) const;
|
||||
AcceptedLedgerTx::pointer
|
||||
getTxn(int) const;
|
||||
|
||||
AcceptedLedger (
|
||||
AcceptedLedger(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
AccountIDCache const& accountCache, Logs& logs);
|
||||
AccountIDCache const& accountCache,
|
||||
Logs& logs);
|
||||
|
||||
private:
|
||||
void insert (AcceptedLedgerTx::ref);
|
||||
void insert(AcceptedLedgerTx::ref);
|
||||
|
||||
std::shared_ptr<ReadView const> mLedger;
|
||||
map_t mMap;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,96 +17,104 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/ledger/AcceptedLedgerTx.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
AcceptedLedgerTx::AcceptedLedgerTx (
|
||||
AcceptedLedgerTx::AcceptedLedgerTx(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
std::shared_ptr<STTx const> const& txn,
|
||||
std::shared_ptr<STObject const> const& met,
|
||||
AccountIDCache const& accountCache,
|
||||
Logs& logs)
|
||||
: mLedger (ledger)
|
||||
, mTxn (txn)
|
||||
, mMeta (std::make_shared<TxMeta> (
|
||||
txn->getTransactionID(), ledger->seq(), *met))
|
||||
, mAffected (mMeta->getAffectedAccounts (logs.journal("View")))
|
||||
, accountCache_ (accountCache)
|
||||
, logs_ (logs)
|
||||
: mLedger(ledger)
|
||||
, mTxn(txn)
|
||||
, mMeta(std::make_shared<TxMeta>(
|
||||
txn->getTransactionID(),
|
||||
ledger->seq(),
|
||||
*met))
|
||||
, mAffected(mMeta->getAffectedAccounts(logs.journal("View")))
|
||||
, accountCache_(accountCache)
|
||||
, logs_(logs)
|
||||
{
|
||||
assert (! ledger->open());
|
||||
assert(!ledger->open());
|
||||
|
||||
mResult = mMeta->getResultTER ();
|
||||
mResult = mMeta->getResultTER();
|
||||
|
||||
Serializer s;
|
||||
met->add(s);
|
||||
mRawMeta = std::move (s.modData());
|
||||
mRawMeta = std::move(s.modData());
|
||||
|
||||
buildJson ();
|
||||
buildJson();
|
||||
}
|
||||
|
||||
AcceptedLedgerTx::AcceptedLedgerTx (
|
||||
AcceptedLedgerTx::AcceptedLedgerTx(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
std::shared_ptr<STTx const> const& txn,
|
||||
TER result,
|
||||
AccountIDCache const& accountCache,
|
||||
Logs& logs)
|
||||
: mLedger (ledger)
|
||||
, mTxn (txn)
|
||||
, mResult (result)
|
||||
, mAffected (txn->getMentionedAccounts ())
|
||||
, accountCache_ (accountCache)
|
||||
, logs_ (logs)
|
||||
: mLedger(ledger)
|
||||
, mTxn(txn)
|
||||
, mResult(result)
|
||||
, mAffected(txn->getMentionedAccounts())
|
||||
, accountCache_(accountCache)
|
||||
, logs_(logs)
|
||||
{
|
||||
assert (ledger->open());
|
||||
buildJson ();
|
||||
assert(ledger->open());
|
||||
buildJson();
|
||||
}
|
||||
|
||||
std::string AcceptedLedgerTx::getEscMeta () const
|
||||
std::string
|
||||
AcceptedLedgerTx::getEscMeta() const
|
||||
{
|
||||
assert (!mRawMeta.empty ());
|
||||
return sqlEscape (mRawMeta);
|
||||
assert(!mRawMeta.empty());
|
||||
return sqlEscape(mRawMeta);
|
||||
}
|
||||
|
||||
void AcceptedLedgerTx::buildJson ()
|
||||
void
|
||||
AcceptedLedgerTx::buildJson()
|
||||
{
|
||||
mJson = Json::objectValue;
|
||||
mJson[jss::transaction] = mTxn->getJson (JsonOptions::none);
|
||||
mJson[jss::transaction] = mTxn->getJson(JsonOptions::none);
|
||||
|
||||
if (mMeta)
|
||||
{
|
||||
mJson[jss::meta] = mMeta->getJson (JsonOptions::none);
|
||||
mJson[jss::raw_meta] = strHex (mRawMeta);
|
||||
mJson[jss::meta] = mMeta->getJson(JsonOptions::none);
|
||||
mJson[jss::raw_meta] = strHex(mRawMeta);
|
||||
}
|
||||
|
||||
mJson[jss::result] = transHuman (mResult);
|
||||
mJson[jss::result] = transHuman(mResult);
|
||||
|
||||
if (! mAffected.empty ())
|
||||
if (!mAffected.empty())
|
||||
{
|
||||
Json::Value& affected = (mJson[jss::affected] = Json::arrayValue);
|
||||
for (auto const& account: mAffected)
|
||||
affected.append (accountCache_.toBase58(account));
|
||||
for (auto const& account : mAffected)
|
||||
affected.append(accountCache_.toBase58(account));
|
||||
}
|
||||
|
||||
if (mTxn->getTxnType () == ttOFFER_CREATE)
|
||||
if (mTxn->getTxnType() == ttOFFER_CREATE)
|
||||
{
|
||||
auto const& account = mTxn->getAccountID(sfAccount);
|
||||
auto const amount = mTxn->getFieldAmount (sfTakerGets);
|
||||
auto const amount = mTxn->getFieldAmount(sfTakerGets);
|
||||
|
||||
// If the offer create is not self funded then add the owner balance
|
||||
if (account != amount.issue ().account)
|
||||
if (account != amount.issue().account)
|
||||
{
|
||||
auto const ownerFunds = accountFunds(*mLedger,
|
||||
account, amount, fhIGNORE_FREEZE, logs_.journal ("View"));
|
||||
mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText ();
|
||||
auto const ownerFunds = accountFunds(
|
||||
*mLedger,
|
||||
account,
|
||||
amount,
|
||||
fhIGNORE_FREEZE,
|
||||
logs_.journal("View"));
|
||||
mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -50,28 +50,30 @@ class Logs;
|
||||
class AcceptedLedgerTx
|
||||
{
|
||||
public:
|
||||
using pointer = std::shared_ptr <AcceptedLedgerTx>;
|
||||
using pointer = std::shared_ptr<AcceptedLedgerTx>;
|
||||
using ref = const pointer&;
|
||||
|
||||
public:
|
||||
AcceptedLedgerTx (
|
||||
AcceptedLedgerTx(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
std::shared_ptr<STTx const> const&,
|
||||
std::shared_ptr<STObject const> const&,
|
||||
AccountIDCache const&,
|
||||
Logs&);
|
||||
AcceptedLedgerTx (
|
||||
AcceptedLedgerTx(
|
||||
std::shared_ptr<ReadView const> const&,
|
||||
std::shared_ptr<STTx const> const&,
|
||||
TER,
|
||||
AccountIDCache const&,
|
||||
Logs&);
|
||||
|
||||
std::shared_ptr <STTx const> const& getTxn () const
|
||||
std::shared_ptr<STTx const> const&
|
||||
getTxn() const
|
||||
{
|
||||
return mTxn;
|
||||
}
|
||||
std::shared_ptr <TxMeta> const& getMeta () const
|
||||
std::shared_ptr<TxMeta> const&
|
||||
getMeta() const
|
||||
{
|
||||
return mMeta;
|
||||
}
|
||||
@@ -82,33 +84,41 @@ public:
|
||||
return mAffected;
|
||||
}
|
||||
|
||||
TxID getTransactionID () const
|
||||
TxID
|
||||
getTransactionID() const
|
||||
{
|
||||
return mTxn->getTransactionID ();
|
||||
return mTxn->getTransactionID();
|
||||
}
|
||||
TxType getTxnType () const
|
||||
TxType
|
||||
getTxnType() const
|
||||
{
|
||||
return mTxn->getTxnType ();
|
||||
return mTxn->getTxnType();
|
||||
}
|
||||
TER getResult () const
|
||||
TER
|
||||
getResult() const
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
std::uint32_t getTxnSeq () const
|
||||
std::uint32_t
|
||||
getTxnSeq() const
|
||||
{
|
||||
return mMeta->getIndex ();
|
||||
return mMeta->getIndex();
|
||||
}
|
||||
|
||||
bool isApplied () const
|
||||
bool
|
||||
isApplied() const
|
||||
{
|
||||
return bool(mMeta);
|
||||
}
|
||||
int getIndex () const
|
||||
int
|
||||
getIndex() const
|
||||
{
|
||||
return mMeta ? mMeta->getIndex () : 0;
|
||||
return mMeta ? mMeta->getIndex() : 0;
|
||||
}
|
||||
std::string getEscMeta () const;
|
||||
Json::Value getJson () const
|
||||
std::string
|
||||
getEscMeta() const;
|
||||
Json::Value
|
||||
getJson() const
|
||||
{
|
||||
return mJson;
|
||||
}
|
||||
@@ -117,16 +127,17 @@ private:
|
||||
std::shared_ptr<ReadView const> mLedger;
|
||||
std::shared_ptr<STTx const> mTxn;
|
||||
std::shared_ptr<TxMeta> mMeta;
|
||||
TER mResult;
|
||||
TER mResult;
|
||||
boost::container::flat_set<AccountID> mAffected;
|
||||
Blob mRawMeta;
|
||||
Json::Value mJson;
|
||||
Blob mRawMeta;
|
||||
Json::Value mJson;
|
||||
AccountIDCache const& accountCache_;
|
||||
Logs& logs_;
|
||||
|
||||
void buildJson ();
|
||||
void
|
||||
buildJson();
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,12 +22,15 @@
|
||||
namespace ripple {
|
||||
|
||||
void
|
||||
AccountStateSF::gotNode(bool, SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq, Blob&& nodeData,
|
||||
AccountStateSF::gotNode(
|
||||
bool,
|
||||
SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq,
|
||||
Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType) const
|
||||
{
|
||||
db_.store(hotACCOUNT_NODE, std::move(nodeData),
|
||||
nodeHash.as_uint256(), ledgerSeq);
|
||||
db_.store(
|
||||
hotACCOUNT_NODE, std::move(nodeData), nodeHash.as_uint256(), ledgerSeq);
|
||||
}
|
||||
|
||||
boost::optional<Blob>
|
||||
@@ -36,4 +39,4 @@ AccountStateSF::getNode(SHAMapHash const& nodeHash) const
|
||||
return fp_.getFetchPack(nodeHash.as_uint256());
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -32,14 +32,17 @@ class AccountStateSF : public SHAMapSyncFilter
|
||||
{
|
||||
public:
|
||||
AccountStateSF(NodeStore::Database& db, AbstractFetchPackContainer& fp)
|
||||
: db_(db)
|
||||
, fp_(fp)
|
||||
{}
|
||||
: db_(db), fp_(fp)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
gotNode(bool fromFilter, SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq, Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const override;
|
||||
gotNode(
|
||||
bool fromFilter,
|
||||
SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq,
|
||||
Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const override;
|
||||
|
||||
boost::optional<Blob>
|
||||
getNode(SHAMapHash const& nodeHash) const override;
|
||||
@@ -49,6 +52,6 @@ private:
|
||||
AbstractFetchPackContainer& fp_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,7 @@ BookListeners::publish(
|
||||
if (p)
|
||||
{
|
||||
// Only publish jvObj if this is the first occurence
|
||||
if(havePublished.emplace(p->getSeq()).second)
|
||||
if (havePublished.emplace(p->getSeq()).second)
|
||||
{
|
||||
p->send(jvObj, true);
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ public:
|
||||
}
|
||||
|
||||
/** Add a new subscription for this book
|
||||
*/
|
||||
*/
|
||||
void
|
||||
addSubscriber(InfoSub::ref sub);
|
||||
|
||||
/** Stop publishing to a subscriber
|
||||
*/
|
||||
*/
|
||||
void
|
||||
removeSubscriber(std::uint64_t sub);
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED
|
||||
|
||||
#include <ripple/ledger/ApplyView.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/ledger/ApplyView.h>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
@@ -34,7 +34,6 @@ class Ledger;
|
||||
class LedgerReplay;
|
||||
class SHAMap;
|
||||
|
||||
|
||||
/** Build a new ledger by applying consensus transactions
|
||||
|
||||
Build a new ledger by applying a set of transactions accepted as part of
|
||||
|
||||
@@ -23,80 +23,80 @@
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/core/JobQueue.h>
|
||||
#include <ripple/nodestore/Database.h>
|
||||
#include <ripple/protocol/HashPrefix.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
ConsensusTransSetSF::ConsensusTransSetSF (Application& app, NodeCache& nodeCache)
|
||||
: app_ (app)
|
||||
, m_nodeCache (nodeCache)
|
||||
, j_ (app.journal ("TransactionAcquire"))
|
||||
ConsensusTransSetSF::ConsensusTransSetSF(Application& app, NodeCache& nodeCache)
|
||||
: app_(app), m_nodeCache(nodeCache), j_(app.journal("TransactionAcquire"))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ConsensusTransSetSF::gotNode(bool fromFilter, SHAMapHash const& nodeHash,
|
||||
std::uint32_t, Blob&& nodeData, SHAMapTreeNode::TNType type) const
|
||||
ConsensusTransSetSF::gotNode(
|
||||
bool fromFilter,
|
||||
SHAMapHash const& nodeHash,
|
||||
std::uint32_t,
|
||||
Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const
|
||||
{
|
||||
if (fromFilter)
|
||||
return;
|
||||
|
||||
m_nodeCache.insert (nodeHash, nodeData);
|
||||
m_nodeCache.insert(nodeHash, nodeData);
|
||||
|
||||
if ((type == SHAMapTreeNode::tnTRANSACTION_NM) && (nodeData.size () > 16))
|
||||
if ((type == SHAMapTreeNode::tnTRANSACTION_NM) && (nodeData.size() > 16))
|
||||
{
|
||||
// this is a transaction, and we didn't have it
|
||||
JLOG (j_.debug())
|
||||
<< "Node on our acquiring TX set is TXN we may not have";
|
||||
JLOG(j_.debug())
|
||||
<< "Node on our acquiring TX set is TXN we may not have";
|
||||
|
||||
try
|
||||
{
|
||||
// skip prefix
|
||||
Serializer s (nodeData.data() + 4, nodeData.size() - 4);
|
||||
SerialIter sit (s.slice());
|
||||
auto stx = std::make_shared<STTx const> (std::ref (sit));
|
||||
assert (stx->getTransactionID () == nodeHash.as_uint256());
|
||||
Serializer s(nodeData.data() + 4, nodeData.size() - 4);
|
||||
SerialIter sit(s.slice());
|
||||
auto stx = std::make_shared<STTx const>(std::ref(sit));
|
||||
assert(stx->getTransactionID() == nodeHash.as_uint256());
|
||||
auto const pap = &app_;
|
||||
app_.getJobQueue ().addJob (
|
||||
jtTRANSACTION, "TXS->TXN",
|
||||
[pap, stx] (Job&) {
|
||||
app_.getJobQueue().addJob(
|
||||
jtTRANSACTION, "TXS->TXN", [pap, stx](Job&) {
|
||||
pap->getOPs().submitTransaction(stx);
|
||||
});
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
JLOG (j_.warn())
|
||||
<< "Fetched invalid transaction in proposed set";
|
||||
JLOG(j_.warn()) << "Fetched invalid transaction in proposed set";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<Blob>
|
||||
ConsensusTransSetSF::getNode (SHAMapHash const& nodeHash) const
|
||||
ConsensusTransSetSF::getNode(SHAMapHash const& nodeHash) const
|
||||
{
|
||||
Blob nodeData;
|
||||
if (m_nodeCache.retrieve (nodeHash, nodeData))
|
||||
if (m_nodeCache.retrieve(nodeHash, nodeData))
|
||||
return nodeData;
|
||||
|
||||
auto txn = app_.getMasterTransaction().fetch_from_cache (nodeHash.as_uint256());
|
||||
auto txn =
|
||||
app_.getMasterTransaction().fetch_from_cache(nodeHash.as_uint256());
|
||||
|
||||
if (txn)
|
||||
{
|
||||
// this is a transaction, and we have it
|
||||
JLOG (j_.trace())
|
||||
<< "Node in our acquiring TX set is TXN we have";
|
||||
JLOG(j_.trace()) << "Node in our acquiring TX set is TXN we have";
|
||||
Serializer s;
|
||||
s.add32 (HashPrefix::transactionID);
|
||||
txn->getSTransaction ()->add (s);
|
||||
s.add32(HashPrefix::transactionID);
|
||||
txn->getSTransaction()->add(s);
|
||||
assert(sha512Half(s.slice()) == nodeHash.as_uint256());
|
||||
nodeData = s.peekData ();
|
||||
nodeData = s.peekData();
|
||||
return nodeData;
|
||||
}
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#define RIPPLE_APP_LEDGER_CONSENSUSTRANSSETSF_H_INCLUDED
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/shamap/SHAMapSyncFilter.h>
|
||||
#include <ripple/basics/TaggedCache.h>
|
||||
#include <ripple/shamap/SHAMapSyncFilter.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -34,18 +34,21 @@ namespace ripple {
|
||||
class ConsensusTransSetSF : public SHAMapSyncFilter
|
||||
{
|
||||
public:
|
||||
using NodeCache = TaggedCache <SHAMapHash, Blob>;
|
||||
using NodeCache = TaggedCache<SHAMapHash, Blob>;
|
||||
|
||||
ConsensusTransSetSF (Application& app, NodeCache& nodeCache);
|
||||
ConsensusTransSetSF(Application& app, NodeCache& nodeCache);
|
||||
|
||||
// Note that the nodeData is overwritten by this call
|
||||
void
|
||||
gotNode(bool fromFilter, SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq, Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const override;
|
||||
gotNode(
|
||||
bool fromFilter,
|
||||
SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq,
|
||||
Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const override;
|
||||
|
||||
boost::optional<Blob>
|
||||
getNode (SHAMapHash const& nodeHash) const override;
|
||||
getNode(SHAMapHash const& nodeHash) const override;
|
||||
|
||||
private:
|
||||
Application& app_;
|
||||
@@ -53,6 +56,6 @@ private:
|
||||
beast::Journal const j_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_INBOUNDLEDGER_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_INBOUNDLEDGER_H_INCLUDED
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/overlay/PeerSet.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/basics/CountedObject.h>
|
||||
#include <ripple/overlay/PeerSet.h>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
@@ -31,37 +31,44 @@
|
||||
namespace ripple {
|
||||
|
||||
// A ledger we are trying to acquire
|
||||
class InboundLedger
|
||||
: public PeerSet
|
||||
, public std::enable_shared_from_this <InboundLedger>
|
||||
, public CountedObject <InboundLedger>
|
||||
class InboundLedger : public PeerSet,
|
||||
public std::enable_shared_from_this<InboundLedger>,
|
||||
public CountedObject<InboundLedger>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "InboundLedger"; }
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "InboundLedger";
|
||||
}
|
||||
|
||||
using PeerDataPairType = std::pair<
|
||||
std::weak_ptr<Peer>,
|
||||
std::shared_ptr<protocol::TMLedgerData>>;
|
||||
using PeerDataPairType =
|
||||
std::pair<std::weak_ptr<Peer>, std::shared_ptr<protocol::TMLedgerData>>;
|
||||
|
||||
// These are the reasons we might acquire a ledger
|
||||
enum class Reason
|
||||
{
|
||||
HISTORY, // Acquiring past ledger
|
||||
SHARD, // Acquiring for shard
|
||||
GENERIC, // Generic other reasons
|
||||
CONSENSUS // We believe the consensus round requires this ledger
|
||||
enum class Reason {
|
||||
HISTORY, // Acquiring past ledger
|
||||
SHARD, // Acquiring for shard
|
||||
GENERIC, // Generic other reasons
|
||||
CONSENSUS // We believe the consensus round requires this ledger
|
||||
};
|
||||
|
||||
InboundLedger(Application& app, uint256 const& hash,
|
||||
std::uint32_t seq, Reason reason, clock_type&);
|
||||
InboundLedger(
|
||||
Application& app,
|
||||
uint256 const& hash,
|
||||
std::uint32_t seq,
|
||||
Reason reason,
|
||||
clock_type&);
|
||||
|
||||
~InboundLedger ();
|
||||
~InboundLedger();
|
||||
|
||||
// Called when the PeerSet timer expires
|
||||
void execute () override;
|
||||
void
|
||||
execute() override;
|
||||
|
||||
// Called when another attempt is made to fetch this same ledger
|
||||
void update (std::uint32_t seq);
|
||||
void
|
||||
update(std::uint32_t seq);
|
||||
|
||||
std::shared_ptr<Ledger const>
|
||||
getLedger() const
|
||||
@@ -69,7 +76,8 @@ public:
|
||||
return mLedger;
|
||||
}
|
||||
|
||||
std::uint32_t getSeq () const
|
||||
std::uint32_t
|
||||
getSeq() const
|
||||
{
|
||||
return mSeq;
|
||||
}
|
||||
@@ -80,82 +88,96 @@ public:
|
||||
return mReason;
|
||||
}
|
||||
|
||||
bool checkLocal ();
|
||||
void init (ScopedLockType& collectionLock);
|
||||
bool
|
||||
checkLocal();
|
||||
void
|
||||
init(ScopedLockType& collectionLock);
|
||||
|
||||
bool
|
||||
gotData(std::weak_ptr<Peer>,
|
||||
gotData(
|
||||
std::weak_ptr<Peer>,
|
||||
std::shared_ptr<protocol::TMLedgerData> const&);
|
||||
|
||||
using neededHash_t =
|
||||
std::pair <protocol::TMGetObjectByHash::ObjectType, uint256>;
|
||||
std::pair<protocol::TMGetObjectByHash::ObjectType, uint256>;
|
||||
|
||||
/** Return a Json::objectValue. */
|
||||
Json::Value getJson (int);
|
||||
Json::Value
|
||||
getJson(int);
|
||||
|
||||
void runData ();
|
||||
void
|
||||
runData();
|
||||
|
||||
static
|
||||
LedgerInfo
|
||||
static LedgerInfo
|
||||
deserializeHeader(Slice data, bool hasPrefix);
|
||||
|
||||
private:
|
||||
enum class TriggerReason
|
||||
{
|
||||
added,
|
||||
reply,
|
||||
timeout
|
||||
};
|
||||
enum class TriggerReason { added, reply, timeout };
|
||||
|
||||
void filterNodes (
|
||||
void
|
||||
filterNodes(
|
||||
std::vector<std::pair<SHAMapNodeID, uint256>>& nodes,
|
||||
TriggerReason reason);
|
||||
|
||||
void trigger (std::shared_ptr<Peer> const&, TriggerReason);
|
||||
void
|
||||
trigger(std::shared_ptr<Peer> const&, TriggerReason);
|
||||
|
||||
std::vector<neededHash_t> getNeededHashes ();
|
||||
std::vector<neededHash_t>
|
||||
getNeededHashes();
|
||||
|
||||
void addPeers ();
|
||||
void tryDB (Family& f);
|
||||
void
|
||||
addPeers();
|
||||
void
|
||||
tryDB(Family& f);
|
||||
|
||||
void done ();
|
||||
void
|
||||
done();
|
||||
|
||||
void onTimer (bool progress, ScopedLockType& peerSetLock) override;
|
||||
void
|
||||
onTimer(bool progress, ScopedLockType& peerSetLock) override;
|
||||
|
||||
void newPeer (std::shared_ptr<Peer> const& peer) override
|
||||
void
|
||||
newPeer(std::shared_ptr<Peer> const& peer) override
|
||||
{
|
||||
// For historical nodes, do not trigger too soon
|
||||
// since a fetch pack is probably coming
|
||||
if (mReason != Reason::HISTORY)
|
||||
trigger (peer, TriggerReason::added);
|
||||
trigger(peer, TriggerReason::added);
|
||||
}
|
||||
|
||||
std::weak_ptr <PeerSet> pmDowncast () override;
|
||||
std::weak_ptr<PeerSet>
|
||||
pmDowncast() override;
|
||||
|
||||
int processData (std::shared_ptr<Peer> peer, protocol::TMLedgerData& data);
|
||||
int
|
||||
processData(std::shared_ptr<Peer> peer, protocol::TMLedgerData& data);
|
||||
|
||||
bool takeHeader (std::string const& data);
|
||||
bool takeTxNode (const std::vector<SHAMapNodeID>& IDs,
|
||||
const std::vector<Blob>& data,
|
||||
SHAMapAddNode&);
|
||||
bool takeTxRootNode (Slice const& data, SHAMapAddNode&);
|
||||
bool
|
||||
takeHeader(std::string const& data);
|
||||
bool
|
||||
takeTxNode(
|
||||
const std::vector<SHAMapNodeID>& IDs,
|
||||
const std::vector<Blob>& data,
|
||||
SHAMapAddNode&);
|
||||
bool
|
||||
takeTxRootNode(Slice 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::vector<SHAMapNodeID>& IDs,
|
||||
const std::vector<Blob>& data,
|
||||
SHAMapAddNode&);
|
||||
bool takeAsRootNode (Slice const& data, SHAMapAddNode&);
|
||||
bool
|
||||
takeAsNode(
|
||||
const std::vector<SHAMapNodeID>& IDs,
|
||||
const std::vector<Blob>& data,
|
||||
SHAMapAddNode&);
|
||||
bool
|
||||
takeAsRootNode(Slice const& data, SHAMapAddNode&);
|
||||
|
||||
std::vector<uint256>
|
||||
neededTxHashes (
|
||||
int max, SHAMapSyncFilter* filter) const;
|
||||
neededTxHashes(int max, SHAMapSyncFilter* filter) const;
|
||||
|
||||
std::vector<uint256>
|
||||
neededStateHashes (
|
||||
int max, SHAMapSyncFilter* filter) const;
|
||||
neededStateHashes(int max, SHAMapSyncFilter* filter) const;
|
||||
|
||||
std::shared_ptr<Ledger> mLedger;
|
||||
bool mHaveHeader;
|
||||
@@ -166,16 +188,16 @@ private:
|
||||
std::uint32_t mSeq;
|
||||
Reason const mReason;
|
||||
|
||||
std::set <uint256> mRecentNodes;
|
||||
std::set<uint256> mRecentNodes;
|
||||
|
||||
SHAMapAddNode mStats;
|
||||
|
||||
// Data we have received from peers
|
||||
std::mutex mReceivedDataLock;
|
||||
std::vector <PeerDataPairType> mReceivedData;
|
||||
std::vector<PeerDataPairType> mReceivedData;
|
||||
bool mReceiveDispatched;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#define RIPPLE_APP_LEDGER_INBOUNDLEDGERS_H_INCLUDED
|
||||
|
||||
#include <ripple/app/ledger/InboundLedger.h>
|
||||
#include <ripple/protocol/RippleLedgerHash.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/protocol/RippleLedgerHash.h>
|
||||
#include <memory>
|
||||
|
||||
namespace ripple {
|
||||
@@ -34,58 +34,71 @@ namespace ripple {
|
||||
class InboundLedgers
|
||||
{
|
||||
public:
|
||||
using clock_type = beast::abstract_clock <std::chrono::steady_clock>;
|
||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
|
||||
virtual ~InboundLedgers() = 0;
|
||||
|
||||
// VFALCO TODO Should this be called findOrAdd ?
|
||||
//
|
||||
virtual
|
||||
std::shared_ptr<Ledger const>
|
||||
acquire (uint256 const& hash,
|
||||
std::uint32_t seq, InboundLedger::Reason) = 0;
|
||||
virtual std::shared_ptr<Ledger const>
|
||||
acquire(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason) = 0;
|
||||
|
||||
virtual std::shared_ptr<InboundLedger> find (LedgerHash const& hash) = 0;
|
||||
virtual std::shared_ptr<InboundLedger>
|
||||
find(LedgerHash const& hash) = 0;
|
||||
|
||||
// VFALCO TODO Remove the dependency on the Peer object.
|
||||
//
|
||||
virtual bool gotLedgerData (LedgerHash const& ledgerHash,
|
||||
virtual bool
|
||||
gotLedgerData(
|
||||
LedgerHash const& ledgerHash,
|
||||
std::shared_ptr<Peer>,
|
||||
std::shared_ptr <protocol::TMLedgerData>) = 0;
|
||||
std::shared_ptr<protocol::TMLedgerData>) = 0;
|
||||
|
||||
virtual void doLedgerData (LedgerHash hash) = 0;
|
||||
virtual void
|
||||
doLedgerData(LedgerHash hash) = 0;
|
||||
|
||||
virtual void gotStaleData (
|
||||
std::shared_ptr <protocol::TMLedgerData> packet) = 0;
|
||||
virtual void
|
||||
gotStaleData(std::shared_ptr<protocol::TMLedgerData> packet) = 0;
|
||||
|
||||
virtual int getFetchCount (int& timeoutCount) = 0;
|
||||
virtual int
|
||||
getFetchCount(int& timeoutCount) = 0;
|
||||
|
||||
virtual void logFailure (uint256 const& h, std::uint32_t seq) = 0;
|
||||
virtual void
|
||||
logFailure(uint256 const& h, std::uint32_t seq) = 0;
|
||||
|
||||
virtual bool isFailure (uint256 const& h) = 0;
|
||||
virtual bool
|
||||
isFailure(uint256 const& h) = 0;
|
||||
|
||||
virtual void clearFailures() = 0;
|
||||
virtual void
|
||||
clearFailures() = 0;
|
||||
|
||||
virtual Json::Value getInfo() = 0;
|
||||
virtual Json::Value
|
||||
getInfo() = 0;
|
||||
|
||||
/** Returns the rate of historical ledger fetches per minute. */
|
||||
virtual std::size_t fetchRate() = 0;
|
||||
virtual std::size_t
|
||||
fetchRate() = 0;
|
||||
|
||||
/** Called when a complete ledger is obtained. */
|
||||
virtual void onLedgerFetched() = 0;
|
||||
virtual void
|
||||
onLedgerFetched() = 0;
|
||||
|
||||
virtual void gotFetchPack () = 0;
|
||||
virtual void sweep () = 0;
|
||||
virtual void
|
||||
gotFetchPack() = 0;
|
||||
virtual void
|
||||
sweep() = 0;
|
||||
|
||||
virtual void onStop() = 0;
|
||||
virtual void
|
||||
onStop() = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<InboundLedgers>
|
||||
make_InboundLedgers (Application& app,
|
||||
InboundLedgers::clock_type& clock, Stoppable& parent,
|
||||
make_InboundLedgers(
|
||||
Application& app,
|
||||
InboundLedgers::clock_type& clock,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector);
|
||||
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_INBOUNDTRANSACTIONS_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_INBOUNDTRANSACTIONS_H_INCLUDED
|
||||
|
||||
#include <ripple/overlay/Peer.h>
|
||||
#include <ripple/shamap/SHAMap.h>
|
||||
#include <ripple/beast/clock/abstract_clock.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/overlay/Peer.h>
|
||||
#include <ripple/shamap/SHAMap.h>
|
||||
#include <memory>
|
||||
|
||||
namespace ripple {
|
||||
@@ -31,57 +31,61 @@ namespace ripple {
|
||||
class Application;
|
||||
|
||||
/** Manages the acquisition and lifetime of transaction sets.
|
||||
*/
|
||||
*/
|
||||
|
||||
class InboundTransactions
|
||||
{
|
||||
public:
|
||||
using clock_type = beast::abstract_clock <std::chrono::steady_clock>;
|
||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
|
||||
InboundTransactions() = default;
|
||||
InboundTransactions(InboundTransactions const&) = delete;
|
||||
InboundTransactions& operator=(InboundTransactions const&) = delete;
|
||||
InboundTransactions&
|
||||
operator=(InboundTransactions const&) = delete;
|
||||
|
||||
virtual ~InboundTransactions() = 0;
|
||||
|
||||
/** Retrieves a transaction set by hash
|
||||
*/
|
||||
virtual std::shared_ptr <SHAMap> getSet (
|
||||
uint256 const& setHash,
|
||||
bool acquire) = 0;
|
||||
*/
|
||||
virtual std::shared_ptr<SHAMap>
|
||||
getSet(uint256 const& setHash, bool acquire) = 0;
|
||||
|
||||
/** Gives data to an inbound transaction set
|
||||
*/
|
||||
virtual void gotData (uint256 const& setHash,
|
||||
std::shared_ptr <Peer>,
|
||||
std::shared_ptr <protocol::TMLedgerData>) = 0;
|
||||
*/
|
||||
virtual void
|
||||
gotData(
|
||||
uint256 const& setHash,
|
||||
std::shared_ptr<Peer>,
|
||||
std::shared_ptr<protocol::TMLedgerData>) = 0;
|
||||
|
||||
/** Gives set to the container
|
||||
*/
|
||||
virtual void giveSet (uint256 const& setHash,
|
||||
std::shared_ptr <SHAMap> const& set,
|
||||
*/
|
||||
virtual void
|
||||
giveSet(
|
||||
uint256 const& setHash,
|
||||
std::shared_ptr<SHAMap> const& set,
|
||||
bool acquired) = 0;
|
||||
|
||||
/** Informs the container if a new consensus round
|
||||
*/
|
||||
virtual void newRound (std::uint32_t seq) = 0;
|
||||
*/
|
||||
virtual void
|
||||
newRound(std::uint32_t seq) = 0;
|
||||
|
||||
virtual Json::Value getInfo() = 0;
|
||||
virtual Json::Value
|
||||
getInfo() = 0;
|
||||
|
||||
virtual void onStop() = 0;
|
||||
virtual void
|
||||
onStop() = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr <InboundTransactions>
|
||||
make_InboundTransactions (
|
||||
std::unique_ptr<InboundTransactions>
|
||||
make_InboundTransactions(
|
||||
Application& app,
|
||||
InboundTransactions::clock_type& clock,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
std::function
|
||||
<void (std::shared_ptr <SHAMap> const&,
|
||||
bool)> gotSet);
|
||||
std::function<void(std::shared_ptr<SHAMap> const&, bool)> gotSet);
|
||||
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,17 +20,17 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/CountedObject.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/core/TimeKeeper.h>
|
||||
#include <ripple/ledger/CachedView.h>
|
||||
#include <ripple/ledger/TxMeta.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/ledger/CachedView.h>
|
||||
#include <ripple/basics/CountedObject.h>
|
||||
#include <ripple/core/TimeKeeper.h>
|
||||
#include <ripple/protocol/Book.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/STLedgerEntry.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/Book.h>
|
||||
#include <ripple/shamap/SHAMap.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <mutex>
|
||||
|
||||
@@ -74,17 +74,21 @@ extern create_genesis_t const create_genesis;
|
||||
@note Presented to clients as ReadView
|
||||
@note Calls virtuals in the constructor, so marked as final
|
||||
*/
|
||||
class Ledger final
|
||||
: public std::enable_shared_from_this <Ledger>
|
||||
, public DigestAwareReadView
|
||||
, public TxsRawView
|
||||
, public CountedObject <Ledger>
|
||||
class Ledger final : public std::enable_shared_from_this<Ledger>,
|
||||
public DigestAwareReadView,
|
||||
public TxsRawView,
|
||||
public CountedObject<Ledger>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "Ledger"; }
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "Ledger";
|
||||
}
|
||||
|
||||
Ledger (Ledger const&) = delete;
|
||||
Ledger& operator= (Ledger const&) = delete;
|
||||
Ledger(Ledger const&) = delete;
|
||||
Ledger&
|
||||
operator=(Ledger const&) = delete;
|
||||
|
||||
/** Create the Genesis ledger.
|
||||
|
||||
@@ -100,22 +104,19 @@ public:
|
||||
|
||||
Amendments specified are enabled in the genesis ledger
|
||||
*/
|
||||
Ledger (
|
||||
Ledger(
|
||||
create_genesis_t,
|
||||
Config const& config,
|
||||
std::vector<uint256> const& amendments,
|
||||
Family& family);
|
||||
|
||||
Ledger (
|
||||
LedgerInfo const& info,
|
||||
Config const& config,
|
||||
Family& family);
|
||||
Ledger(LedgerInfo const& info, Config const& config, Family& family);
|
||||
|
||||
/** Used for ledgers loaded from JSON files
|
||||
|
||||
@param acquire If true, acquires the ledger if not found locally
|
||||
*/
|
||||
Ledger (
|
||||
Ledger(
|
||||
LedgerInfo const& info,
|
||||
bool& loaded,
|
||||
bool acquire,
|
||||
@@ -129,13 +130,14 @@ public:
|
||||
follows previous, and have
|
||||
parentCloseTime == previous.closeTime.
|
||||
*/
|
||||
Ledger (Ledger const& previous,
|
||||
NetClock::time_point closeTime);
|
||||
Ledger(Ledger const& previous, NetClock::time_point closeTime);
|
||||
|
||||
// used for database ledgers
|
||||
Ledger (std::uint32_t ledgerSeq,
|
||||
NetClock::time_point closeTime, Config const& config,
|
||||
Family& family);
|
||||
Ledger(
|
||||
std::uint32_t ledgerSeq,
|
||||
NetClock::time_point closeTime,
|
||||
Config const& config,
|
||||
Family& family);
|
||||
|
||||
~Ledger() = default;
|
||||
|
||||
@@ -168,14 +170,14 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
exists (Keylet const& k) const override;
|
||||
exists(Keylet const& k) const override;
|
||||
|
||||
boost::optional<uint256>
|
||||
succ (uint256 const& key, boost::optional<
|
||||
uint256> const& last = boost::none) const override;
|
||||
succ(uint256 const& key, boost::optional<uint256> const& last = boost::none)
|
||||
const override;
|
||||
|
||||
std::shared_ptr<SLE const>
|
||||
read (Keylet const& k) const override;
|
||||
read(Keylet const& k) const override;
|
||||
|
||||
std::unique_ptr<sles_type::iter_base>
|
||||
slesBegin() const override;
|
||||
@@ -193,36 +195,33 @@ public:
|
||||
txsEnd() const override;
|
||||
|
||||
bool
|
||||
txExists (uint256 const& key) const override;
|
||||
txExists(uint256 const& key) const override;
|
||||
|
||||
tx_type
|
||||
txRead (key_type const& key) const override;
|
||||
txRead(key_type const& key) const override;
|
||||
|
||||
//
|
||||
// DigestAwareReadView
|
||||
//
|
||||
|
||||
boost::optional<digest_type>
|
||||
digest (key_type const& key) const override;
|
||||
digest(key_type const& key) const override;
|
||||
|
||||
//
|
||||
// RawView
|
||||
//
|
||||
|
||||
void
|
||||
rawErase (std::shared_ptr<
|
||||
SLE> const& sle) override;
|
||||
rawErase(std::shared_ptr<SLE> const& sle) override;
|
||||
|
||||
void
|
||||
rawInsert (std::shared_ptr<
|
||||
SLE> const& sle) override;
|
||||
rawInsert(std::shared_ptr<SLE> const& sle) override;
|
||||
|
||||
void
|
||||
rawReplace (std::shared_ptr<
|
||||
SLE> const& sle) override;
|
||||
rawReplace(std::shared_ptr<SLE> const& sle) override;
|
||||
|
||||
void
|
||||
rawDestroyXRP (XRPAmount const& fee) override
|
||||
rawDestroyXRP(XRPAmount const& fee) override
|
||||
{
|
||||
info_.drops -= fee;
|
||||
}
|
||||
@@ -232,25 +231,31 @@ public:
|
||||
//
|
||||
|
||||
void
|
||||
rawTxInsert (uint256 const& key,
|
||||
std::shared_ptr<Serializer const
|
||||
> const& txn, std::shared_ptr<
|
||||
Serializer const> const& metaData) override;
|
||||
rawTxInsert(
|
||||
uint256 const& key,
|
||||
std::shared_ptr<Serializer const> const& txn,
|
||||
std::shared_ptr<Serializer const> const& metaData) override;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void setValidated() const
|
||||
void
|
||||
setValidated() const
|
||||
{
|
||||
info_.validated = true;
|
||||
}
|
||||
|
||||
void setAccepted (NetClock::time_point closeTime,
|
||||
NetClock::duration closeResolution, bool correctCloseTime,
|
||||
Config const& config);
|
||||
void
|
||||
setAccepted(
|
||||
NetClock::time_point closeTime,
|
||||
NetClock::duration closeResolution,
|
||||
bool correctCloseTime,
|
||||
Config const& config);
|
||||
|
||||
void setImmutable (Config const& config);
|
||||
void
|
||||
setImmutable(Config const& config);
|
||||
|
||||
bool isImmutable () const
|
||||
bool
|
||||
isImmutable() const
|
||||
{
|
||||
return mImmutable;
|
||||
}
|
||||
@@ -274,7 +279,8 @@ public:
|
||||
stateMap_->setLedgerSeq(info_.seq);
|
||||
}
|
||||
|
||||
void setTotalDrops (std::uint64_t totDrops)
|
||||
void
|
||||
setTotalDrops(std::uint64_t totDrops)
|
||||
{
|
||||
info_.drops = totDrops;
|
||||
}
|
||||
@@ -304,27 +310,34 @@ public:
|
||||
}
|
||||
|
||||
// returns false on error
|
||||
bool addSLE (SLE const& sle);
|
||||
bool
|
||||
addSLE(SLE const& sle);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void updateSkipList ();
|
||||
void
|
||||
updateSkipList();
|
||||
|
||||
bool walkLedger (beast::Journal j) const;
|
||||
bool
|
||||
walkLedger(beast::Journal j) const;
|
||||
|
||||
bool assertSane (beast::Journal ledgerJ) const;
|
||||
bool
|
||||
assertSane(beast::Journal ledgerJ) const;
|
||||
|
||||
void
|
||||
invariants() const;
|
||||
void
|
||||
unshare() const;
|
||||
|
||||
void invariants() const;
|
||||
void unshare() const;
|
||||
private:
|
||||
class sles_iter_impl;
|
||||
class txs_iter_impl;
|
||||
|
||||
bool
|
||||
setup (Config const& config);
|
||||
setup(Config const& config);
|
||||
|
||||
std::shared_ptr<SLE>
|
||||
peek (Keylet const& k) const;
|
||||
peek(Keylet const& k) const;
|
||||
|
||||
bool mImmutable;
|
||||
|
||||
@@ -348,44 +361,38 @@ using CachedLedger = CachedView<Ledger>;
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern
|
||||
bool
|
||||
extern bool
|
||||
pendSaveValidated(
|
||||
Application& app,
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
bool isSynchronous,
|
||||
bool isCurrent);
|
||||
|
||||
extern
|
||||
std::shared_ptr<Ledger>
|
||||
loadByIndex (std::uint32_t ledgerIndex,
|
||||
Application& app, bool acquire = true);
|
||||
extern std::shared_ptr<Ledger>
|
||||
loadByIndex(std::uint32_t ledgerIndex, Application& app, bool acquire = true);
|
||||
|
||||
extern
|
||||
std::tuple<std::shared_ptr<Ledger>, std::uint32_t, uint256>
|
||||
loadLedgerHelper(std::string const& sqlSuffix,
|
||||
Application& app, bool acquire = true);
|
||||
extern std::tuple<std::shared_ptr<Ledger>, std::uint32_t, uint256>
|
||||
loadLedgerHelper(
|
||||
std::string const& sqlSuffix,
|
||||
Application& app,
|
||||
bool acquire = true);
|
||||
|
||||
extern
|
||||
std::shared_ptr<Ledger>
|
||||
loadByHash (uint256 const& ledgerHash,
|
||||
Application& app, bool acquire = true);
|
||||
extern std::shared_ptr<Ledger>
|
||||
loadByHash(uint256 const& ledgerHash, Application& app, bool acquire = true);
|
||||
|
||||
extern
|
||||
uint256
|
||||
extern uint256
|
||||
getHashByIndex(std::uint32_t index, Application& app);
|
||||
|
||||
extern
|
||||
bool
|
||||
getHashesByIndex(std::uint32_t index,
|
||||
uint256 &ledgerHash, uint256& parentHash,
|
||||
Application& app);
|
||||
|
||||
extern
|
||||
std::map< std::uint32_t, std::pair<uint256, uint256>>
|
||||
getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq,
|
||||
extern bool
|
||||
getHashesByIndex(
|
||||
std::uint32_t index,
|
||||
uint256& ledgerHash,
|
||||
uint256& parentHash,
|
||||
Application& app);
|
||||
|
||||
extern std::map<std::uint32_t, std::pair<uint256, uint256>>
|
||||
getHashesByIndex(std::uint32_t minSeq, std::uint32_t maxSeq, Application& app);
|
||||
|
||||
/** Deserialize a SHAMapItem containing a single STTx
|
||||
|
||||
Throw:
|
||||
@@ -393,7 +400,7 @@ getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq,
|
||||
May throw on deserializaton error
|
||||
*/
|
||||
std::shared_ptr<STTx const>
|
||||
deserializeTx (SHAMapItem const& item);
|
||||
deserializeTx(SHAMapItem const& item);
|
||||
|
||||
/** Deserialize a SHAMapItem containing STTx + STObject metadata
|
||||
|
||||
@@ -404,11 +411,9 @@ deserializeTx (SHAMapItem const& item);
|
||||
|
||||
May throw on deserializaton error
|
||||
*/
|
||||
std::pair<std::shared_ptr<
|
||||
STTx const>, std::shared_ptr<
|
||||
STObject const>>
|
||||
deserializeTxPlusMeta (SHAMapItem const& item);
|
||||
std::pair<std::shared_ptr<STTx const>, std::shared_ptr<STObject const>>
|
||||
deserializeTxPlusMeta(SHAMapItem const& item);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,26 +21,24 @@
|
||||
#define RIPPLE_APP_LEDGER_LEDGERCLEANER_H_INCLUDED
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/beast/utility/PropertyStream.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/beast/utility/PropertyStream.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <memory>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
/** Check the ledger/transaction databases to make sure they have continuity */
|
||||
class LedgerCleaner
|
||||
: public Stoppable
|
||||
, public beast::PropertyStream::Source
|
||||
class LedgerCleaner : public Stoppable, public beast::PropertyStream::Source
|
||||
{
|
||||
protected:
|
||||
explicit LedgerCleaner (Stoppable& parent);
|
||||
explicit LedgerCleaner(Stoppable& parent);
|
||||
|
||||
public:
|
||||
/** Destroy the object. */
|
||||
virtual ~LedgerCleaner () = 0;
|
||||
virtual ~LedgerCleaner() = 0;
|
||||
|
||||
/** Start a long running task to clean the ledger.
|
||||
The ledger is cleaned asynchronously, on an implementation defined
|
||||
@@ -52,14 +50,14 @@ public:
|
||||
|
||||
@param parameters A Json object with configurable parameters.
|
||||
*/
|
||||
virtual void doClean (Json::Value const& parameters) = 0;
|
||||
virtual void
|
||||
doClean(Json::Value const& parameters) = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<LedgerCleaner>
|
||||
make_LedgerCleaner (Application& app,
|
||||
Stoppable& parent, beast::Journal journal);
|
||||
make_LedgerCleaner(Application& app, Stoppable& parent, beast::Journal journal);
|
||||
|
||||
} // detail
|
||||
} // ripple
|
||||
} // namespace detail
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,31 +36,37 @@ std::chrono::seconds constexpr CachedLedgerAge = std::chrono::minutes{2};
|
||||
|
||||
// FIXME: Need to clean up ledgers by index at some point
|
||||
|
||||
LedgerHistory::LedgerHistory (
|
||||
LedgerHistory::LedgerHistory(
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
Application& app)
|
||||
: app_ (app)
|
||||
, collector_ (collector)
|
||||
, mismatch_counter_ (collector->make_counter ("ledger.history", "mismatch"))
|
||||
, m_ledgers_by_hash ("LedgerCache", CACHED_LEDGER_NUM, CachedLedgerAge,
|
||||
stopwatch(), app_.journal("TaggedCache"))
|
||||
, m_consensus_validated ("ConsensusValidated", 64, std::chrono::minutes {5},
|
||||
stopwatch(), app_.journal("TaggedCache"))
|
||||
, j_ (app.journal ("LedgerHistory"))
|
||||
Application& app)
|
||||
: app_(app)
|
||||
, collector_(collector)
|
||||
, mismatch_counter_(collector->make_counter("ledger.history", "mismatch"))
|
||||
, m_ledgers_by_hash(
|
||||
"LedgerCache",
|
||||
CACHED_LEDGER_NUM,
|
||||
CachedLedgerAge,
|
||||
stopwatch(),
|
||||
app_.journal("TaggedCache"))
|
||||
, m_consensus_validated(
|
||||
"ConsensusValidated",
|
||||
64,
|
||||
std::chrono::minutes{5},
|
||||
stopwatch(),
|
||||
app_.journal("TaggedCache"))
|
||||
, j_(app.journal("LedgerHistory"))
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
LedgerHistory::insert(
|
||||
std::shared_ptr<Ledger const> ledger,
|
||||
bool validated)
|
||||
LedgerHistory::insert(std::shared_ptr<Ledger const> ledger, bool validated)
|
||||
{
|
||||
if(! ledger->isImmutable())
|
||||
if (!ledger->isImmutable())
|
||||
LogicError("mutable Ledger in insert");
|
||||
|
||||
assert (ledger->stateMap().getHash ().isNonZero ());
|
||||
assert(ledger->stateMap().getHash().isNonZero());
|
||||
|
||||
std::unique_lock sl (m_ledgers_by_hash.peekMutex ());
|
||||
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
|
||||
|
||||
const bool alreadyHad = m_ledgers_by_hash.canonicalize_replace_cache(
|
||||
ledger->info().hash, ledger);
|
||||
@@ -70,44 +76,45 @@ LedgerHistory::insert(
|
||||
return alreadyHad;
|
||||
}
|
||||
|
||||
LedgerHash LedgerHistory::getLedgerHash (LedgerIndex index)
|
||||
LedgerHash
|
||||
LedgerHistory::getLedgerHash(LedgerIndex index)
|
||||
{
|
||||
std::unique_lock sl (m_ledgers_by_hash.peekMutex ());
|
||||
auto it = mLedgersByIndex.find (index);
|
||||
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
|
||||
auto it = mLedgersByIndex.find(index);
|
||||
|
||||
if (it != mLedgersByIndex.end ())
|
||||
if (it != mLedgersByIndex.end())
|
||||
return it->second;
|
||||
|
||||
return uint256 ();
|
||||
return uint256();
|
||||
}
|
||||
|
||||
std::shared_ptr<Ledger const>
|
||||
LedgerHistory::getLedgerBySeq (LedgerIndex index)
|
||||
LedgerHistory::getLedgerBySeq(LedgerIndex index)
|
||||
{
|
||||
{
|
||||
std::unique_lock sl (m_ledgers_by_hash.peekMutex ());
|
||||
auto it = mLedgersByIndex.find (index);
|
||||
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
|
||||
auto it = mLedgersByIndex.find(index);
|
||||
|
||||
if (it != mLedgersByIndex.end ())
|
||||
if (it != mLedgersByIndex.end())
|
||||
{
|
||||
uint256 hash = it->second;
|
||||
sl.unlock ();
|
||||
return getLedgerByHash (hash);
|
||||
sl.unlock();
|
||||
return getLedgerByHash(hash);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Ledger const> ret = loadByIndex (index, app_);
|
||||
std::shared_ptr<Ledger const> ret = loadByIndex(index, app_);
|
||||
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
assert (ret->info().seq == index);
|
||||
assert(ret->info().seq == index);
|
||||
|
||||
{
|
||||
// Add this ledger to the local tracking by index
|
||||
std::unique_lock sl (m_ledgers_by_hash.peekMutex ());
|
||||
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
|
||||
|
||||
assert (ret->isImmutable ());
|
||||
assert(ret->isImmutable());
|
||||
m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret);
|
||||
mLedgersByIndex[ret->info().seq] = ret->info().hash;
|
||||
return (ret->info().seq == index) ? ret : nullptr;
|
||||
@@ -115,32 +122,31 @@ LedgerHistory::getLedgerBySeq (LedgerIndex index)
|
||||
}
|
||||
|
||||
std::shared_ptr<Ledger const>
|
||||
LedgerHistory::getLedgerByHash (LedgerHash const& hash)
|
||||
LedgerHistory::getLedgerByHash(LedgerHash const& hash)
|
||||
{
|
||||
auto ret = m_ledgers_by_hash.fetch (hash);
|
||||
auto ret = m_ledgers_by_hash.fetch(hash);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
assert (ret->isImmutable ());
|
||||
assert (ret->info().hash == hash);
|
||||
assert(ret->isImmutable());
|
||||
assert(ret->info().hash == hash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = loadByHash (hash, app_);
|
||||
ret = loadByHash(hash, app_);
|
||||
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
assert (ret->isImmutable ());
|
||||
assert (ret->info().hash == hash);
|
||||
assert(ret->isImmutable());
|
||||
assert(ret->info().hash == hash);
|
||||
m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret);
|
||||
assert (ret->info().hash == hash);
|
||||
assert(ret->info().hash == hash);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
static void
|
||||
log_one(
|
||||
ReadView const& ledger,
|
||||
uint256 const& tx,
|
||||
@@ -151,19 +157,18 @@ log_one(
|
||||
|
||||
if (metaData != nullptr)
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": " << msg << " is missing this transaction:\n" <<
|
||||
metaData->getJson (JsonOptions::none);
|
||||
JLOG(j.debug()) << "MISMATCH on TX " << tx << ": " << msg
|
||||
<< " is missing this transaction:\n"
|
||||
<< metaData->getJson(JsonOptions::none);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": " << msg << " is missing this transaction.";
|
||||
JLOG(j.debug()) << "MISMATCH on TX " << tx << ": " << msg
|
||||
<< " is missing this transaction.";
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
static void
|
||||
log_metadata_difference(
|
||||
ReadView const& builtLedger,
|
||||
ReadView const& validLedger,
|
||||
@@ -171,35 +176,34 @@ log_metadata_difference(
|
||||
beast::Journal j)
|
||||
{
|
||||
auto getMeta = [](ReadView const& ledger,
|
||||
uint256 const& txID) -> std::shared_ptr<TxMeta>
|
||||
{
|
||||
uint256 const& txID) -> std::shared_ptr<TxMeta> {
|
||||
auto meta = ledger.txRead(txID).second;
|
||||
if (!meta)
|
||||
return {};
|
||||
return std::make_shared<TxMeta> (txID, ledger.seq(), *meta);
|
||||
return std::make_shared<TxMeta>(txID, ledger.seq(), *meta);
|
||||
};
|
||||
|
||||
auto validMetaData = getMeta (validLedger, tx);
|
||||
auto builtMetaData = getMeta (builtLedger, tx);
|
||||
auto validMetaData = getMeta(validLedger, tx);
|
||||
auto builtMetaData = getMeta(builtLedger, tx);
|
||||
assert(validMetaData != nullptr || builtMetaData != nullptr);
|
||||
|
||||
if (validMetaData != nullptr && builtMetaData != nullptr)
|
||||
{
|
||||
auto const& validNodes = validMetaData->getNodes ();
|
||||
auto const& builtNodes = builtMetaData->getNodes ();
|
||||
auto const& validNodes = validMetaData->getNodes();
|
||||
auto const& builtNodes = builtMetaData->getNodes();
|
||||
|
||||
bool const result_diff =
|
||||
validMetaData->getResultTER () != builtMetaData->getResultTER ();
|
||||
validMetaData->getResultTER() != builtMetaData->getResultTER();
|
||||
|
||||
bool const index_diff =
|
||||
validMetaData->getIndex() != builtMetaData->getIndex ();
|
||||
validMetaData->getIndex() != builtMetaData->getIndex();
|
||||
|
||||
bool const nodes_diff = validNodes != builtNodes;
|
||||
|
||||
if (!result_diff && !index_diff && !nodes_diff)
|
||||
{
|
||||
JLOG (j.error()) << "MISMATCH on TX " << tx <<
|
||||
": No apparent mismatches detected!";
|
||||
JLOG(j.error()) << "MISMATCH on TX " << tx
|
||||
<< ": No apparent mismatches detected!";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,105 +211,111 @@ log_metadata_difference(
|
||||
{
|
||||
if (result_diff && index_diff)
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": Different result and index!";
|
||||
JLOG (j.debug()) << " Built:" <<
|
||||
" Result: " << builtMetaData->getResult () <<
|
||||
" Index: " << builtMetaData->getIndex ();
|
||||
JLOG (j.debug()) << " Valid:" <<
|
||||
" Result: " << validMetaData->getResult () <<
|
||||
" Index: " << validMetaData->getIndex ();
|
||||
JLOG(j.debug()) << "MISMATCH on TX " << tx
|
||||
<< ": Different result and index!";
|
||||
JLOG(j.debug()) << " Built:"
|
||||
<< " Result: " << builtMetaData->getResult()
|
||||
<< " Index: " << builtMetaData->getIndex();
|
||||
JLOG(j.debug()) << " Valid:"
|
||||
<< " Result: " << validMetaData->getResult()
|
||||
<< " Index: " << validMetaData->getIndex();
|
||||
}
|
||||
else if (result_diff)
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": Different result!";
|
||||
JLOG (j.debug()) << " Built:" <<
|
||||
" Result: " << builtMetaData->getResult ();
|
||||
JLOG (j.debug()) << " Valid:" <<
|
||||
" Result: " << validMetaData->getResult ();
|
||||
JLOG(j.debug())
|
||||
<< "MISMATCH on TX " << tx << ": Different result!";
|
||||
JLOG(j.debug()) << " Built:"
|
||||
<< " Result: " << builtMetaData->getResult();
|
||||
JLOG(j.debug()) << " Valid:"
|
||||
<< " Result: " << validMetaData->getResult();
|
||||
}
|
||||
else if (index_diff)
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": Different index!";
|
||||
JLOG (j.debug()) << " Built:" <<
|
||||
" Index: " << builtMetaData->getIndex ();
|
||||
JLOG (j.debug()) << " Valid:" <<
|
||||
" Index: " << validMetaData->getIndex ();
|
||||
JLOG(j.debug())
|
||||
<< "MISMATCH on TX " << tx << ": Different index!";
|
||||
JLOG(j.debug()) << " Built:"
|
||||
<< " Index: " << builtMetaData->getIndex();
|
||||
JLOG(j.debug()) << " Valid:"
|
||||
<< " Index: " << validMetaData->getIndex();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result_diff && index_diff)
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": Different result, index and nodes!";
|
||||
JLOG (j.debug()) << " Built:\n" <<
|
||||
builtMetaData->getJson (JsonOptions::none);
|
||||
JLOG (j.debug()) << " Valid:\n" <<
|
||||
validMetaData->getJson (JsonOptions::none);
|
||||
JLOG(j.debug()) << "MISMATCH on TX " << tx
|
||||
<< ": Different result, index and nodes!";
|
||||
JLOG(j.debug()) << " Built:\n"
|
||||
<< builtMetaData->getJson(JsonOptions::none);
|
||||
JLOG(j.debug()) << " Valid:\n"
|
||||
<< validMetaData->getJson(JsonOptions::none);
|
||||
}
|
||||
else if (result_diff)
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": Different result and nodes!";
|
||||
JLOG (j.debug()) << " Built:" <<
|
||||
" Result: " << builtMetaData->getResult () <<
|
||||
" Nodes:\n" << builtNodes.getJson (JsonOptions::none);
|
||||
JLOG (j.debug()) << " Valid:" <<
|
||||
" Result: " << validMetaData->getResult () <<
|
||||
" Nodes:\n" << validNodes.getJson (JsonOptions::none);
|
||||
JLOG(j.debug()) << "MISMATCH on TX " << tx
|
||||
<< ": Different result and nodes!";
|
||||
JLOG(j.debug())
|
||||
<< " Built:"
|
||||
<< " Result: " << builtMetaData->getResult() << " Nodes:\n"
|
||||
<< builtNodes.getJson(JsonOptions::none);
|
||||
JLOG(j.debug())
|
||||
<< " Valid:"
|
||||
<< " Result: " << validMetaData->getResult() << " Nodes:\n"
|
||||
<< validNodes.getJson(JsonOptions::none);
|
||||
}
|
||||
else if (index_diff)
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": Different index and nodes!";
|
||||
JLOG (j.debug()) << " Built:" <<
|
||||
" Index: " << builtMetaData->getIndex () <<
|
||||
" Nodes:\n" << builtNodes.getJson (JsonOptions::none);
|
||||
JLOG (j.debug()) << " Valid:" <<
|
||||
" Index: " << validMetaData->getIndex () <<
|
||||
" Nodes:\n" << validNodes.getJson (JsonOptions::none);
|
||||
JLOG(j.debug()) << "MISMATCH on TX " << tx
|
||||
<< ": Different index and nodes!";
|
||||
JLOG(j.debug())
|
||||
<< " Built:"
|
||||
<< " Index: " << builtMetaData->getIndex() << " Nodes:\n"
|
||||
<< builtNodes.getJson(JsonOptions::none);
|
||||
JLOG(j.debug())
|
||||
<< " Valid:"
|
||||
<< " Index: " << validMetaData->getIndex() << " Nodes:\n"
|
||||
<< validNodes.getJson(JsonOptions::none);
|
||||
}
|
||||
else // nodes_diff
|
||||
else // nodes_diff
|
||||
{
|
||||
JLOG (j.debug()) << "MISMATCH on TX " << tx <<
|
||||
": Different nodes!";
|
||||
JLOG (j.debug()) << " Built:" <<
|
||||
" Nodes:\n" << builtNodes.getJson (JsonOptions::none);
|
||||
JLOG (j.debug()) << " Valid:" <<
|
||||
" Nodes:\n" << validNodes.getJson (JsonOptions::none);
|
||||
JLOG(j.debug())
|
||||
<< "MISMATCH on TX " << tx << ": Different nodes!";
|
||||
JLOG(j.debug()) << " Built:"
|
||||
<< " Nodes:\n"
|
||||
<< builtNodes.getJson(JsonOptions::none);
|
||||
JLOG(j.debug()) << " Valid:"
|
||||
<< " Nodes:\n"
|
||||
<< validNodes.getJson(JsonOptions::none);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (validMetaData != nullptr)
|
||||
{
|
||||
JLOG (j.error()) << "MISMATCH on TX " << tx <<
|
||||
": Metadata Difference (built has none)\n" <<
|
||||
validMetaData->getJson (JsonOptions::none);
|
||||
JLOG(j.error()) << "MISMATCH on TX " << tx
|
||||
<< ": Metadata Difference (built has none)\n"
|
||||
<< validMetaData->getJson(JsonOptions::none);
|
||||
}
|
||||
else // builtMetaData != nullptr
|
||||
else // builtMetaData != nullptr
|
||||
{
|
||||
JLOG (j.error()) << "MISMATCH on TX " << tx <<
|
||||
": Metadata Difference (valid has none)\n" <<
|
||||
builtMetaData->getJson (JsonOptions::none);
|
||||
JLOG(j.error()) << "MISMATCH on TX " << tx
|
||||
<< ": Metadata Difference (valid has none)\n"
|
||||
<< builtMetaData->getJson(JsonOptions::none);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Return list of leaves sorted by key
|
||||
static
|
||||
std::vector<SHAMapItem const*>
|
||||
leaves (SHAMap const& sm)
|
||||
static std::vector<SHAMapItem const*>
|
||||
leaves(SHAMap const& sm)
|
||||
{
|
||||
std::vector<SHAMapItem const*> v;
|
||||
for (auto const& item : sm)
|
||||
v.push_back(&item);
|
||||
std::sort(v.begin(), v.end(),
|
||||
[](SHAMapItem const* lhs, SHAMapItem const* rhs)
|
||||
{ return lhs->key() < rhs->key(); });
|
||||
std::sort(
|
||||
v.begin(), v.end(), [](SHAMapItem const* lhs, SHAMapItem const* rhs) {
|
||||
return lhs->key() < rhs->key();
|
||||
});
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -317,26 +327,27 @@ LedgerHistory::handleMismatch(
|
||||
boost::optional<uint256> const& validatedConsensusHash,
|
||||
Json::Value const& consensus)
|
||||
{
|
||||
assert (built != valid);
|
||||
assert(built != valid);
|
||||
++mismatch_counter_;
|
||||
|
||||
auto builtLedger = getLedgerByHash (built);
|
||||
auto validLedger = getLedgerByHash (valid);
|
||||
auto builtLedger = getLedgerByHash(built);
|
||||
auto validLedger = getLedgerByHash(valid);
|
||||
|
||||
if (!builtLedger || !validLedger)
|
||||
{
|
||||
JLOG (j_.error()) << "MISMATCH cannot be analyzed:" <<
|
||||
" builtLedger: " << to_string (built) << " -> " << builtLedger <<
|
||||
" validLedger: " << to_string (valid) << " -> " << validLedger;
|
||||
JLOG(j_.error()) << "MISMATCH cannot be analyzed:"
|
||||
<< " builtLedger: " << to_string(built) << " -> "
|
||||
<< builtLedger << " validLedger: " << to_string(valid)
|
||||
<< " -> " << validLedger;
|
||||
return;
|
||||
}
|
||||
|
||||
assert (builtLedger->info().seq == validLedger->info().seq);
|
||||
assert(builtLedger->info().seq == validLedger->info().seq);
|
||||
|
||||
if (auto stream = j_.debug())
|
||||
{
|
||||
stream << "Built: " << getJson (*builtLedger);
|
||||
stream << "Valid: " << getJson (*validLedger);
|
||||
stream << "Built: " << getJson(*builtLedger);
|
||||
stream << "Valid: " << getJson(*validLedger);
|
||||
stream << "Consensus: " << consensus;
|
||||
}
|
||||
|
||||
@@ -346,14 +357,14 @@ LedgerHistory::handleMismatch(
|
||||
// Disagreement over prior ledger indicates sync issue
|
||||
if (builtLedger->info().parentHash != validLedger->info().parentHash)
|
||||
{
|
||||
JLOG (j_.error()) << "MISMATCH on prior ledger";
|
||||
JLOG(j_.error()) << "MISMATCH on prior ledger";
|
||||
return;
|
||||
}
|
||||
|
||||
// Disagreement over close time indicates Byzantine failure
|
||||
if (builtLedger->info().closeTime != validLedger->info().closeTime)
|
||||
{
|
||||
JLOG (j_.error()) << "MISMATCH on close time";
|
||||
JLOG(j_.error()) << "MISMATCH on close time";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -374,25 +385,23 @@ LedgerHistory::handleMismatch(
|
||||
auto const validTx = leaves(validLedger->txMap());
|
||||
|
||||
if (builtTx == validTx)
|
||||
JLOG (j_.error()) <<
|
||||
"MISMATCH with same " << builtTx.size() <<
|
||||
" transactions";
|
||||
JLOG(j_.error()) << "MISMATCH with same " << builtTx.size()
|
||||
<< " transactions";
|
||||
else
|
||||
JLOG (j_.error()) << "MISMATCH with " <<
|
||||
builtTx.size() << " built and " <<
|
||||
validTx.size() << " valid transactions.";
|
||||
JLOG(j_.error()) << "MISMATCH with " << builtTx.size() << " built and "
|
||||
<< validTx.size() << " valid transactions.";
|
||||
|
||||
JLOG (j_.error()) << "built\n" << getJson(*builtLedger);
|
||||
JLOG (j_.error()) << "valid\n" << getJson(*validLedger);
|
||||
JLOG(j_.error()) << "built\n" << getJson(*builtLedger);
|
||||
JLOG(j_.error()) << "valid\n" << getJson(*validLedger);
|
||||
|
||||
// Log all differences between built and valid ledgers
|
||||
auto b = builtTx.begin();
|
||||
auto v = validTx.begin();
|
||||
while(b != builtTx.end() && v != validTx.end())
|
||||
while (b != builtTx.end() && v != validTx.end())
|
||||
{
|
||||
if ((*b)->key() < (*v)->key())
|
||||
{
|
||||
log_one (*builtLedger, (*b)->key(), "valid", j_);
|
||||
log_one(*builtLedger, (*b)->key(), "valid", j_);
|
||||
++b;
|
||||
}
|
||||
else if ((*b)->key() > (*v)->key())
|
||||
@@ -406,41 +415,40 @@ LedgerHistory::handleMismatch(
|
||||
{
|
||||
// Same transaction with different metadata
|
||||
log_metadata_difference(
|
||||
*builtLedger,
|
||||
*validLedger, (*b)->key(), j_);
|
||||
*builtLedger, *validLedger, (*b)->key(), j_);
|
||||
}
|
||||
++b;
|
||||
++v;
|
||||
}
|
||||
}
|
||||
for (; b != builtTx.end(); ++b)
|
||||
log_one (*builtLedger, (*b)->key(), "valid", j_);
|
||||
log_one(*builtLedger, (*b)->key(), "valid", j_);
|
||||
for (; v != validTx.end(); ++v)
|
||||
log_one (*validLedger, (*v)->key(), "built", j_);
|
||||
log_one(*validLedger, (*v)->key(), "built", j_);
|
||||
}
|
||||
|
||||
void LedgerHistory::builtLedger (
|
||||
void
|
||||
LedgerHistory::builtLedger(
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
uint256 const& consensusHash,
|
||||
Json::Value consensus)
|
||||
{
|
||||
LedgerIndex index = ledger->info().seq;
|
||||
LedgerHash hash = ledger->info().hash;
|
||||
assert (!hash.isZero());
|
||||
assert(!hash.isZero());
|
||||
|
||||
std::unique_lock sl (
|
||||
m_consensus_validated.peekMutex());
|
||||
std::unique_lock sl(m_consensus_validated.peekMutex());
|
||||
|
||||
auto entry = std::make_shared<cv_entry>();
|
||||
m_consensus_validated.canonicalize_replace_client(index, entry);
|
||||
|
||||
if (entry->validated && ! entry->built)
|
||||
if (entry->validated && !entry->built)
|
||||
{
|
||||
if (entry->validated.get() != hash)
|
||||
{
|
||||
JLOG (j_.error()) << "MISMATCH: seq=" << index
|
||||
<< " validated:" << entry->validated.get()
|
||||
<< " then:" << hash;
|
||||
JLOG(j_.error())
|
||||
<< "MISMATCH: seq=" << index
|
||||
<< " validated:" << entry->validated.get() << " then:" << hash;
|
||||
handleMismatch(
|
||||
hash,
|
||||
entry->validated.get(),
|
||||
@@ -451,35 +459,35 @@ void LedgerHistory::builtLedger (
|
||||
else
|
||||
{
|
||||
// We validated a ledger and then built it locally
|
||||
JLOG (j_.debug()) << "MATCH: seq=" << index << " late";
|
||||
JLOG(j_.debug()) << "MATCH: seq=" << index << " late";
|
||||
}
|
||||
}
|
||||
|
||||
entry->built.emplace (hash);
|
||||
entry->built.emplace(hash);
|
||||
entry->builtConsensusHash.emplace(consensusHash);
|
||||
entry->consensus.emplace (std::move (consensus));
|
||||
entry->consensus.emplace(std::move(consensus));
|
||||
}
|
||||
|
||||
void LedgerHistory::validatedLedger (
|
||||
void
|
||||
LedgerHistory::validatedLedger(
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
boost::optional<uint256> const& consensusHash)
|
||||
{
|
||||
LedgerIndex index = ledger->info().seq;
|
||||
LedgerHash hash = ledger->info().hash;
|
||||
assert (!hash.isZero());
|
||||
assert(!hash.isZero());
|
||||
|
||||
std::unique_lock sl (
|
||||
m_consensus_validated.peekMutex());
|
||||
std::unique_lock sl(m_consensus_validated.peekMutex());
|
||||
|
||||
auto entry = std::make_shared<cv_entry>();
|
||||
m_consensus_validated.canonicalize_replace_client(index, entry);
|
||||
|
||||
if (entry->built && ! entry->validated)
|
||||
if (entry->built && !entry->validated)
|
||||
{
|
||||
if (entry->built.get() != hash)
|
||||
{
|
||||
JLOG (j_.error()) << "MISMATCH: seq=" << index
|
||||
<< " built:" << entry->built.get()
|
||||
JLOG(j_.error())
|
||||
<< "MISMATCH: seq=" << index << " built:" << entry->built.get()
|
||||
<< " then:" << hash;
|
||||
handleMismatch(
|
||||
entry->built.get(),
|
||||
@@ -491,23 +499,23 @@ void LedgerHistory::validatedLedger (
|
||||
else
|
||||
{
|
||||
// We built a ledger locally and then validated it
|
||||
JLOG (j_.debug()) << "MATCH: seq=" << index;
|
||||
JLOG(j_.debug()) << "MATCH: seq=" << index;
|
||||
}
|
||||
}
|
||||
|
||||
entry->validated.emplace (hash);
|
||||
entry->validated.emplace(hash);
|
||||
entry->validatedConsensusHash = consensusHash;
|
||||
}
|
||||
|
||||
/** Ensure m_ledgers_by_hash doesn't have the wrong hash for a particular index
|
||||
*/
|
||||
bool LedgerHistory::fixIndex (
|
||||
LedgerIndex ledgerIndex, LedgerHash const& ledgerHash)
|
||||
*/
|
||||
bool
|
||||
LedgerHistory::fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash)
|
||||
{
|
||||
std::unique_lock sl (m_ledgers_by_hash.peekMutex ());
|
||||
auto it = mLedgersByIndex.find (ledgerIndex);
|
||||
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
|
||||
auto it = mLedgersByIndex.find(ledgerIndex);
|
||||
|
||||
if ((it != mLedgersByIndex.end ()) && (it->second != ledgerHash) )
|
||||
if ((it != mLedgersByIndex.end()) && (it->second != ledgerHash))
|
||||
{
|
||||
it->second = ledgerHash;
|
||||
return false;
|
||||
@@ -515,20 +523,22 @@ bool LedgerHistory::fixIndex (
|
||||
return true;
|
||||
}
|
||||
|
||||
void LedgerHistory::tune (int size, std::chrono::seconds age)
|
||||
void
|
||||
LedgerHistory::tune(int size, std::chrono::seconds age)
|
||||
{
|
||||
m_ledgers_by_hash.setTargetSize (size);
|
||||
m_ledgers_by_hash.setTargetAge (age);
|
||||
m_ledgers_by_hash.setTargetSize(size);
|
||||
m_ledgers_by_hash.setTargetAge(age);
|
||||
}
|
||||
|
||||
void LedgerHistory::clearLedgerCachePrior (LedgerIndex seq)
|
||||
void
|
||||
LedgerHistory::clearLedgerCachePrior(LedgerIndex seq)
|
||||
{
|
||||
for (LedgerHash it: m_ledgers_by_hash.getKeys())
|
||||
for (LedgerHash it : m_ledgers_by_hash.getKeys())
|
||||
{
|
||||
auto const ledger = getLedgerByHash (it);
|
||||
auto const ledger = getLedgerByHash(it);
|
||||
if (!ledger || ledger->info().seq < seq)
|
||||
m_ledgers_by_hash.del (it, false);
|
||||
m_ledgers_by_hash.del(it, false);
|
||||
}
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/protocol/RippleLedgerHash.h>
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
#include <ripple/beast/insight/Event.h>
|
||||
#include <ripple/protocol/RippleLedgerHash.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -34,59 +34,66 @@ namespace ripple {
|
||||
class LedgerHistory
|
||||
{
|
||||
public:
|
||||
LedgerHistory (beast::insight::Collector::ptr const& collector,
|
||||
LedgerHistory(
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
Application& app);
|
||||
|
||||
/** Track a ledger
|
||||
@return `true` if the ledger was already tracked
|
||||
*/
|
||||
bool insert (std::shared_ptr<Ledger const> ledger,
|
||||
bool validated);
|
||||
bool
|
||||
insert(std::shared_ptr<Ledger const> ledger, bool validated);
|
||||
|
||||
/** Get the ledgers_by_hash cache hit rate
|
||||
@return the hit rate
|
||||
*/
|
||||
float getCacheHitRate ()
|
||||
float
|
||||
getCacheHitRate()
|
||||
{
|
||||
return m_ledgers_by_hash.getHitRate ();
|
||||
return m_ledgers_by_hash.getHitRate();
|
||||
}
|
||||
|
||||
/** Get a ledger given its sequence number */
|
||||
std::shared_ptr<Ledger const>
|
||||
getLedgerBySeq (LedgerIndex ledgerIndex);
|
||||
getLedgerBySeq(LedgerIndex ledgerIndex);
|
||||
|
||||
/** Retrieve a ledger given its hash */
|
||||
std::shared_ptr<Ledger const>
|
||||
getLedgerByHash (LedgerHash const& ledgerHash);
|
||||
getLedgerByHash(LedgerHash const& ledgerHash);
|
||||
|
||||
/** 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);
|
||||
LedgerHash
|
||||
getLedgerHash(LedgerIndex ledgerIndex);
|
||||
|
||||
/** Set the history cache's parameters
|
||||
@param size The target size of the cache
|
||||
@param age The target age of the cache, in seconds
|
||||
*/
|
||||
void tune (int size, std::chrono::seconds age);
|
||||
void
|
||||
tune(int size, std::chrono::seconds age);
|
||||
|
||||
/** Remove stale cache entries
|
||||
*/
|
||||
void sweep ()
|
||||
*/
|
||||
void
|
||||
sweep()
|
||||
{
|
||||
m_ledgers_by_hash.sweep ();
|
||||
m_consensus_validated.sweep ();
|
||||
m_ledgers_by_hash.sweep();
|
||||
m_consensus_validated.sweep();
|
||||
}
|
||||
|
||||
/** Report that we have locally built a particular ledger */
|
||||
void builtLedger (
|
||||
void
|
||||
builtLedger(
|
||||
std::shared_ptr<Ledger const> const&,
|
||||
uint256 const& consensusHash,
|
||||
Json::Value);
|
||||
|
||||
/** Report that we have validated a particular ledger */
|
||||
void validatedLedger (
|
||||
void
|
||||
validatedLedger(
|
||||
std::shared_ptr<Ledger const> const&,
|
||||
boost::optional<uint256> const& consensusHash);
|
||||
|
||||
@@ -95,12 +102,13 @@ public:
|
||||
@param ledgerHash The hash it is to be mapped to
|
||||
@return `true` if the mapping was repaired
|
||||
*/
|
||||
bool fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash);
|
||||
bool
|
||||
fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash);
|
||||
|
||||
void clearLedgerCachePrior (LedgerIndex seq);
|
||||
void
|
||||
clearLedgerCachePrior(LedgerIndex seq);
|
||||
|
||||
private:
|
||||
|
||||
/** Log details in the case where we build one ledger but
|
||||
validate a different one.
|
||||
@param built The hash of the ledger we built
|
||||
@@ -123,7 +131,7 @@ private:
|
||||
beast::insight::Collector::ptr collector_;
|
||||
beast::insight::Counter mismatch_counter_;
|
||||
|
||||
using LedgersByHash = TaggedCache <LedgerHash, Ledger const>;
|
||||
using LedgersByHash = TaggedCache<LedgerHash, Ledger const>;
|
||||
|
||||
LedgersByHash m_ledgers_by_hash;
|
||||
|
||||
@@ -142,16 +150,15 @@ private:
|
||||
// Consensus metadata of built ledger
|
||||
boost::optional<Json::Value> consensus;
|
||||
};
|
||||
using ConsensusValidated = TaggedCache <LedgerIndex, cv_entry>;
|
||||
using ConsensusValidated = TaggedCache<LedgerIndex, cv_entry>;
|
||||
ConsensusValidated m_consensus_validated;
|
||||
|
||||
|
||||
// Maps ledger indexes to the corresponding hash.
|
||||
std::map <LedgerIndex, LedgerHash> mLedgersByIndex; // validated ledgers
|
||||
std::map<LedgerIndex, LedgerHash> mLedgersByIndex; // validated ledgers
|
||||
|
||||
beast::Journal j_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,26 +39,29 @@ class LedgerHolder
|
||||
{
|
||||
public:
|
||||
// Update the held ledger
|
||||
void set (std::shared_ptr<Ledger const> ledger)
|
||||
void
|
||||
set(std::shared_ptr<Ledger const> ledger)
|
||||
{
|
||||
if(! ledger)
|
||||
if (!ledger)
|
||||
LogicError("LedgerHolder::set with nullptr");
|
||||
if(! ledger->isImmutable())
|
||||
if (!ledger->isImmutable())
|
||||
LogicError("LedgerHolder::set with mutable Ledger");
|
||||
std::lock_guard sl (m_lock);
|
||||
std::lock_guard sl(m_lock);
|
||||
m_heldLedger = std::move(ledger);
|
||||
}
|
||||
|
||||
// Return the (immutable) held ledger
|
||||
std::shared_ptr<Ledger const> get ()
|
||||
std::shared_ptr<Ledger const>
|
||||
get()
|
||||
{
|
||||
std::lock_guard sl (m_lock);
|
||||
std::lock_guard sl(m_lock);
|
||||
return m_heldLedger;
|
||||
}
|
||||
|
||||
bool empty ()
|
||||
bool
|
||||
empty()
|
||||
{
|
||||
std::lock_guard sl (m_lock);
|
||||
std::lock_guard sl(m_lock);
|
||||
return m_heldLedger == nullptr;
|
||||
}
|
||||
|
||||
@@ -67,6 +70,6 @@ private:
|
||||
std::shared_ptr<Ledger const> m_heldLedger;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_LEDGERMASTER_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_LEDGERMASTER_H_INCLUDED
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/ledger/AbstractFetchPackContainer.h>
|
||||
#include <ripple/app/ledger/InboundLedgers.h>
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
@@ -28,17 +27,18 @@
|
||||
#include <ripple/app/ledger/LedgerHistory.h>
|
||||
#include <ripple/app/ledger/LedgerHolder.h>
|
||||
#include <ripple/app/ledger/LedgerReplay.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/CanonicalTXSet.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/basics/RangeSet.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
#include <ripple/beast/utility/PropertyStream.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/protocol/messages.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/RippleLedgerHash.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/protocol/messages.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <mutex>
|
||||
@@ -48,8 +48,6 @@ namespace ripple {
|
||||
class Peer;
|
||||
class Transaction;
|
||||
|
||||
|
||||
|
||||
// Tracks the current ledger and any ledgers in the process of closing
|
||||
// Tracks ledger history
|
||||
// Tracks held transactions
|
||||
@@ -57,28 +55,28 @@ class Transaction;
|
||||
// VFALCO TODO Rename to Ledgers
|
||||
// It sounds like this holds all the ledgers...
|
||||
//
|
||||
class LedgerMaster
|
||||
: public Stoppable
|
||||
, public AbstractFetchPackContainer
|
||||
class LedgerMaster : public Stoppable, public AbstractFetchPackContainer
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
LedgerMaster(Application& app, Stopwatch& stopwatch,
|
||||
explicit LedgerMaster(
|
||||
Application& app,
|
||||
Stopwatch& stopwatch,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
beast::Journal journal);
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
beast::Journal journal);
|
||||
|
||||
virtual ~LedgerMaster () = default;
|
||||
virtual ~LedgerMaster() = default;
|
||||
|
||||
LedgerIndex getCurrentLedgerIndex ();
|
||||
LedgerIndex getValidLedgerIndex ();
|
||||
LedgerIndex
|
||||
getCurrentLedgerIndex();
|
||||
LedgerIndex
|
||||
getValidLedgerIndex();
|
||||
|
||||
bool isCompatible (
|
||||
ReadView const&,
|
||||
beast::Journal::Stream,
|
||||
char const* reason);
|
||||
bool
|
||||
isCompatible(ReadView const&, beast::Journal::Stream, char const* reason);
|
||||
|
||||
std::recursive_mutex& peekMutex ();
|
||||
std::recursive_mutex&
|
||||
peekMutex();
|
||||
|
||||
// The current ledger is the ledger we believe new transactions should go in
|
||||
std::shared_ptr<ReadView const>
|
||||
@@ -93,49 +91,62 @@ public:
|
||||
|
||||
// The validated ledger is the last fully validated ledger
|
||||
std::shared_ptr<Ledger const>
|
||||
getValidatedLedger ()
|
||||
getValidatedLedger()
|
||||
{
|
||||
return mValidLedger.get();
|
||||
}
|
||||
|
||||
// The Rules are in the last fully validated ledger if there is one.
|
||||
Rules getValidatedRules();
|
||||
Rules
|
||||
getValidatedRules();
|
||||
|
||||
// This is the last ledger we published to clients and can lag the validated
|
||||
// ledger
|
||||
std::shared_ptr<ReadView const>
|
||||
getPublishedLedger();
|
||||
|
||||
std::chrono::seconds getPublishedLedgerAge ();
|
||||
std::chrono::seconds getValidatedLedgerAge ();
|
||||
bool isCaughtUp(std::string& reason);
|
||||
std::chrono::seconds
|
||||
getPublishedLedgerAge();
|
||||
std::chrono::seconds
|
||||
getValidatedLedgerAge();
|
||||
bool
|
||||
isCaughtUp(std::string& reason);
|
||||
|
||||
std::uint32_t getEarliestFetch ();
|
||||
std::uint32_t
|
||||
getEarliestFetch();
|
||||
|
||||
bool storeLedger (std::shared_ptr<Ledger const> ledger);
|
||||
bool
|
||||
storeLedger(std::shared_ptr<Ledger const> ledger);
|
||||
|
||||
void setFullLedger (
|
||||
void
|
||||
setFullLedger(
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
bool isSynchronous, bool isCurrent);
|
||||
bool isSynchronous,
|
||||
bool isCurrent);
|
||||
|
||||
/** Check the sequence number and parent close time of a
|
||||
ledger against our clock and last validated ledger to
|
||||
see if it can be the network's current ledger
|
||||
*/
|
||||
bool canBeCurrent (std::shared_ptr<Ledger const> const& ledger);
|
||||
bool
|
||||
canBeCurrent(std::shared_ptr<Ledger const> const& ledger);
|
||||
|
||||
void switchLCL (std::shared_ptr<Ledger const> const& lastClosed);
|
||||
void
|
||||
switchLCL(std::shared_ptr<Ledger const> const& lastClosed);
|
||||
|
||||
void failedSave(std::uint32_t seq, uint256 const& hash);
|
||||
void
|
||||
failedSave(std::uint32_t seq, uint256 const& hash);
|
||||
|
||||
std::string getCompleteLedgers ();
|
||||
std::string
|
||||
getCompleteLedgers();
|
||||
|
||||
/** Apply held transactions to the open ledger
|
||||
This is normally called as we close the ledger.
|
||||
The open ledger remains open to handle new transactions
|
||||
until a new open ledger is built.
|
||||
*/
|
||||
void applyHeldTransactions ();
|
||||
void
|
||||
applyHeldTransactions();
|
||||
|
||||
/** Get all the transactions held for a particular account.
|
||||
This is normally called when a transaction for that
|
||||
@@ -144,15 +155,16 @@ public:
|
||||
waiting for ledger close.
|
||||
*/
|
||||
std::vector<std::shared_ptr<STTx const>>
|
||||
pruneHeldTransactions(AccountID const& account,
|
||||
std::uint32_t const seq);
|
||||
pruneHeldTransactions(AccountID const& account, std::uint32_t const seq);
|
||||
|
||||
/** Get a ledger's hash by sequence number using the cache
|
||||
*/
|
||||
uint256 getHashBySeq (std::uint32_t index);
|
||||
*/
|
||||
uint256
|
||||
getHashBySeq(std::uint32_t index);
|
||||
|
||||
/** Walk to a ledger's hash using the skip list */
|
||||
boost::optional<LedgerHash> walkHashBySeq (std::uint32_t index);
|
||||
boost::optional<LedgerHash>
|
||||
walkHashBySeq(std::uint32_t index);
|
||||
|
||||
/** Walk the chain of ledger hashes to determine the hash of the
|
||||
ledger with the specified index. The referenceLedger is used as
|
||||
@@ -161,92 +173,115 @@ public:
|
||||
from the reference ledger or any prior ledger are not present
|
||||
in the node store.
|
||||
*/
|
||||
boost::optional<LedgerHash> walkHashBySeq (
|
||||
boost::optional<LedgerHash>
|
||||
walkHashBySeq(
|
||||
std::uint32_t index,
|
||||
std::shared_ptr<ReadView const> const& referenceLedger);
|
||||
|
||||
std::shared_ptr<Ledger const>
|
||||
getLedgerBySeq (std::uint32_t index);
|
||||
getLedgerBySeq(std::uint32_t index);
|
||||
|
||||
std::shared_ptr<Ledger const>
|
||||
getLedgerByHash (uint256 const& hash);
|
||||
getLedgerByHash(uint256 const& hash);
|
||||
|
||||
void setLedgerRangePresent (
|
||||
std::uint32_t minV, std::uint32_t maxV);
|
||||
void
|
||||
setLedgerRangePresent(std::uint32_t minV, std::uint32_t maxV);
|
||||
|
||||
boost::optional<LedgerHash> getLedgerHash(
|
||||
boost::optional<LedgerHash>
|
||||
getLedgerHash(
|
||||
std::uint32_t desiredSeq,
|
||||
std::shared_ptr<ReadView const> const& knownGoodLedger);
|
||||
|
||||
boost::optional <NetClock::time_point> getCloseTimeBySeq (
|
||||
LedgerIndex ledgerIndex);
|
||||
boost::optional<NetClock::time_point>
|
||||
getCloseTimeBySeq(LedgerIndex ledgerIndex);
|
||||
|
||||
boost::optional <NetClock::time_point> getCloseTimeByHash (
|
||||
LedgerHash const& ledgerHash, LedgerIndex ledgerIndex);
|
||||
boost::optional<NetClock::time_point>
|
||||
getCloseTimeByHash(LedgerHash const& ledgerHash, LedgerIndex ledgerIndex);
|
||||
|
||||
void addHeldTransaction (std::shared_ptr<Transaction> const& trans);
|
||||
void fixMismatch (ReadView const& ledger);
|
||||
void
|
||||
addHeldTransaction(std::shared_ptr<Transaction> const& trans);
|
||||
void
|
||||
fixMismatch(ReadView const& ledger);
|
||||
|
||||
bool haveLedger (std::uint32_t seq);
|
||||
void clearLedger (std::uint32_t seq);
|
||||
bool getValidatedRange (
|
||||
std::uint32_t& minVal, std::uint32_t& maxVal);
|
||||
bool getFullValidatedRange (
|
||||
std::uint32_t& minVal, std::uint32_t& maxVal);
|
||||
bool
|
||||
haveLedger(std::uint32_t seq);
|
||||
void
|
||||
clearLedger(std::uint32_t seq);
|
||||
bool
|
||||
getValidatedRange(std::uint32_t& minVal, std::uint32_t& maxVal);
|
||||
bool
|
||||
getFullValidatedRange(std::uint32_t& minVal, std::uint32_t& maxVal);
|
||||
|
||||
void tune (int size, std::chrono::seconds age);
|
||||
void sweep ();
|
||||
float getCacheHitRate ();
|
||||
void
|
||||
tune(int size, std::chrono::seconds age);
|
||||
void
|
||||
sweep();
|
||||
float
|
||||
getCacheHitRate();
|
||||
|
||||
void checkAccept (std::shared_ptr<Ledger const> const& ledger);
|
||||
void checkAccept (uint256 const& hash, std::uint32_t seq);
|
||||
void
|
||||
checkAccept(std::shared_ptr<Ledger const> const& ledger);
|
||||
void
|
||||
checkAccept(uint256 const& hash, std::uint32_t seq);
|
||||
void
|
||||
consensusBuilt(
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
uint256 const& consensusHash,
|
||||
Json::Value consensus);
|
||||
|
||||
LedgerIndex getBuildingLedger ();
|
||||
void setBuildingLedger (LedgerIndex index);
|
||||
LedgerIndex
|
||||
getBuildingLedger();
|
||||
void
|
||||
setBuildingLedger(LedgerIndex index);
|
||||
|
||||
void tryAdvance ();
|
||||
bool newPathRequest (); // Returns true if path request successfully placed.
|
||||
bool isNewPathRequest ();
|
||||
bool newOrderBookDB (); // Returns true if able to fulfill request.
|
||||
void
|
||||
tryAdvance();
|
||||
bool
|
||||
newPathRequest(); // Returns true if path request successfully placed.
|
||||
bool
|
||||
isNewPathRequest();
|
||||
bool
|
||||
newOrderBookDB(); // Returns true if able to fulfill request.
|
||||
|
||||
bool fixIndex (
|
||||
LedgerIndex ledgerIndex, LedgerHash const& ledgerHash);
|
||||
void doLedgerCleaner(Json::Value const& parameters);
|
||||
bool
|
||||
fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash);
|
||||
void
|
||||
doLedgerCleaner(Json::Value const& parameters);
|
||||
|
||||
beast::PropertyStream::Source& getPropertySource ();
|
||||
beast::PropertyStream::Source&
|
||||
getPropertySource();
|
||||
|
||||
void clearPriorLedgers (LedgerIndex seq);
|
||||
void
|
||||
clearPriorLedgers(LedgerIndex seq);
|
||||
|
||||
void clearLedgerCachePrior (LedgerIndex seq);
|
||||
void
|
||||
clearLedgerCachePrior(LedgerIndex seq);
|
||||
|
||||
// ledger replay
|
||||
void takeReplay (std::unique_ptr<LedgerReplay> replay);
|
||||
std::unique_ptr<LedgerReplay> releaseReplay ();
|
||||
void
|
||||
takeReplay(std::unique_ptr<LedgerReplay> replay);
|
||||
std::unique_ptr<LedgerReplay>
|
||||
releaseReplay();
|
||||
|
||||
// Fetch Packs
|
||||
void gotFetchPack (
|
||||
bool progress,
|
||||
std::uint32_t seq);
|
||||
void
|
||||
gotFetchPack(bool progress, std::uint32_t seq);
|
||||
|
||||
void addFetchPack (
|
||||
uint256 const& hash,
|
||||
std::shared_ptr<Blob>& data);
|
||||
void
|
||||
addFetchPack(uint256 const& hash, std::shared_ptr<Blob>& data);
|
||||
|
||||
boost::optional<Blob>
|
||||
getFetchPack (uint256 const& hash) override;
|
||||
getFetchPack(uint256 const& hash) override;
|
||||
|
||||
void makeFetchPack (
|
||||
void
|
||||
makeFetchPack(
|
||||
std::weak_ptr<Peer> const& wPeer,
|
||||
std::shared_ptr<protocol::TMGetObjectByHash> const& request,
|
||||
uint256 haveLedgerHash,
|
||||
UptimeClock::time_point uptime);
|
||||
|
||||
std::size_t getFetchPackCacheSize () const;
|
||||
std::size_t
|
||||
getFetchPackCacheSize() const;
|
||||
|
||||
//! Whether we have ever fully validated a ledger.
|
||||
bool
|
||||
@@ -256,40 +291,45 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void setValidLedger(
|
||||
std::shared_ptr<Ledger const> const& l);
|
||||
void setPubLedger(
|
||||
std::shared_ptr<Ledger const> const& l);
|
||||
void
|
||||
setValidLedger(std::shared_ptr<Ledger const> const& l);
|
||||
void
|
||||
setPubLedger(std::shared_ptr<Ledger const> const& l);
|
||||
|
||||
void tryFill(
|
||||
Job& job,
|
||||
std::shared_ptr<Ledger const> ledger);
|
||||
void
|
||||
tryFill(Job& job, std::shared_ptr<Ledger const> ledger);
|
||||
|
||||
void getFetchPack(
|
||||
LedgerIndex missing, InboundLedger::Reason reason);
|
||||
void
|
||||
getFetchPack(LedgerIndex missing, InboundLedger::Reason reason);
|
||||
|
||||
boost::optional<LedgerHash> getLedgerHashForHistory(
|
||||
LedgerIndex index, InboundLedger::Reason reason);
|
||||
boost::optional<LedgerHash>
|
||||
getLedgerHashForHistory(LedgerIndex index, InboundLedger::Reason reason);
|
||||
|
||||
std::size_t getNeededValidations();
|
||||
void advanceThread();
|
||||
void fetchForHistory(
|
||||
std::size_t
|
||||
getNeededValidations();
|
||||
void
|
||||
advanceThread();
|
||||
void
|
||||
fetchForHistory(
|
||||
std::uint32_t missing,
|
||||
bool& progress,
|
||||
InboundLedger::Reason reason,
|
||||
std::unique_lock<std::recursive_mutex>&);
|
||||
// Try to publish ledgers, acquire missing ledgers. Always called with
|
||||
// m_mutex locked. The passed lock is a reminder to callers.
|
||||
void doAdvance(std::unique_lock<std::recursive_mutex>&);
|
||||
void
|
||||
doAdvance(std::unique_lock<std::recursive_mutex>&);
|
||||
|
||||
std::vector<std::shared_ptr<Ledger const>>
|
||||
findNewLedgersToPublish(std::unique_lock<std::recursive_mutex>&);
|
||||
|
||||
void updatePaths(Job& job);
|
||||
void
|
||||
updatePaths(Job& job);
|
||||
|
||||
// Returns true if work started. Always called with m_mutex locked.
|
||||
// The passed lock is a reminder to callers.
|
||||
bool newPFWork(const char *name, std::unique_lock<std::recursive_mutex>&);
|
||||
bool
|
||||
newPFWork(const char* name, std::unique_lock<std::recursive_mutex>&);
|
||||
|
||||
Application& app_;
|
||||
beast::Journal m_journal;
|
||||
@@ -315,11 +355,11 @@ private:
|
||||
std::shared_ptr<Ledger const> mShardLedger;
|
||||
|
||||
// Fully validated ledger, whether or not we have the ledger resident.
|
||||
std::pair <uint256, LedgerIndex> mLastValidLedger {uint256(), 0};
|
||||
std::pair<uint256, LedgerIndex> mLastValidLedger{uint256(), 0};
|
||||
|
||||
LedgerHistory mLedgerHistory;
|
||||
|
||||
CanonicalTXSet mHeldTransactions {uint256()};
|
||||
CanonicalTXSet mHeldTransactions{uint256()};
|
||||
|
||||
// A set of transactions to replay during the next close
|
||||
std::unique_ptr<LedgerReplay> replayData;
|
||||
@@ -327,25 +367,26 @@ private:
|
||||
std::recursive_mutex mCompleteLock;
|
||||
RangeSet<std::uint32_t> mCompleteLedgers;
|
||||
|
||||
std::unique_ptr <detail::LedgerCleaner> mLedgerCleaner;
|
||||
std::unique_ptr<detail::LedgerCleaner> mLedgerCleaner;
|
||||
|
||||
// Publish thread is running.
|
||||
bool mAdvanceThread {false};
|
||||
bool mAdvanceThread{false};
|
||||
|
||||
// Publish thread has work to do.
|
||||
bool mAdvanceWork {false};
|
||||
int mFillInProgress {0};
|
||||
bool mAdvanceWork{false};
|
||||
int mFillInProgress{0};
|
||||
|
||||
int mPathFindThread {0}; // Pathfinder jobs dispatched
|
||||
bool mPathFindNewRequest {false};
|
||||
int mPathFindThread{0}; // Pathfinder jobs dispatched
|
||||
bool mPathFindNewRequest{false};
|
||||
|
||||
std::atomic_flag mGotFetchPackThread = ATOMIC_FLAG_INIT; // GotFetchPack jobs dispatched
|
||||
std::atomic_flag mGotFetchPackThread =
|
||||
ATOMIC_FLAG_INIT; // GotFetchPack jobs dispatched
|
||||
|
||||
std::atomic <std::uint32_t> mPubLedgerClose {0};
|
||||
std::atomic <LedgerIndex> mPubLedgerSeq {0};
|
||||
std::atomic <std::uint32_t> mValidLedgerSign {0};
|
||||
std::atomic <LedgerIndex> mValidLedgerSeq {0};
|
||||
std::atomic <LedgerIndex> mBuildingLedgerSeq {0};
|
||||
std::atomic<std::uint32_t> mPubLedgerClose{0};
|
||||
std::atomic<LedgerIndex> mPubLedgerSeq{0};
|
||||
std::atomic<std::uint32_t> mValidLedgerSign{0};
|
||||
std::atomic<LedgerIndex> mValidLedgerSeq{0};
|
||||
std::atomic<LedgerIndex> mBuildingLedgerSeq{0};
|
||||
|
||||
// The server is in standalone mode
|
||||
bool const standalone_;
|
||||
@@ -360,21 +401,26 @@ private:
|
||||
|
||||
TaggedCache<uint256, Blob> fetch_packs_;
|
||||
|
||||
std::uint32_t fetch_seq_ {0};
|
||||
std::uint32_t fetch_seq_{0};
|
||||
|
||||
// Try to keep a validator from switching from test to live network
|
||||
// without first wiping the database.
|
||||
LedgerIndex const max_ledger_difference_ {1000000};
|
||||
LedgerIndex const max_ledger_difference_{1000000};
|
||||
|
||||
private:
|
||||
struct Stats
|
||||
{
|
||||
template <class Handler>
|
||||
Stats (Handler const& handler, beast::insight::Collector::ptr const& collector)
|
||||
: hook (collector->make_hook (handler))
|
||||
, validatedLedgerAge (collector->make_gauge ("LedgerMaster", "Validated_Ledger_Age"))
|
||||
, publishedLedgerAge (collector->make_gauge ("LedgerMaster", "Published_Ledger_Age"))
|
||||
{ }
|
||||
Stats(
|
||||
Handler const& handler,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: hook(collector->make_hook(handler))
|
||||
, validatedLedgerAge(
|
||||
collector->make_gauge("LedgerMaster", "Validated_Ledger_Age"))
|
||||
, publishedLedgerAge(
|
||||
collector->make_gauge("LedgerMaster", "Published_Ledger_Age"))
|
||||
{
|
||||
}
|
||||
|
||||
beast::insight::Hook hook;
|
||||
beast::insight::Gauge validatedLedgerAge;
|
||||
@@ -384,19 +430,15 @@ private:
|
||||
Stats m_stats;
|
||||
|
||||
private:
|
||||
void collect_metrics()
|
||||
void
|
||||
collect_metrics()
|
||||
{
|
||||
std::lock_guard lock (m_mutex);
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_stats.validatedLedgerAge.set(getValidatedLedgerAge().count());
|
||||
m_stats.publishedLedgerAge.set(getPublishedLedgerAge().count());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
std::shared_ptr<Ledger const> replay);
|
||||
|
||||
/** @return The parent of the ledger to replay
|
||||
*/
|
||||
*/
|
||||
std::shared_ptr<Ledger const> const&
|
||||
parent() const
|
||||
{
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
}
|
||||
|
||||
/** @return The ledger to replay
|
||||
*/
|
||||
*/
|
||||
std::shared_ptr<Ledger const> const&
|
||||
replay() const
|
||||
{
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
}
|
||||
|
||||
/** @return Transactions in the order they should be replayed
|
||||
*/
|
||||
*/
|
||||
std::map<std::uint32_t, std::shared_ptr<STTx const>> const&
|
||||
orderedTxns() const
|
||||
{
|
||||
|
||||
@@ -23,20 +23,20 @@
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/json/Object.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
struct LedgerFill
|
||||
{
|
||||
LedgerFill (ReadView const& l, int o = 0, std::vector<TxQ::TxDetails> q = {},
|
||||
LedgerEntryType t = ltINVALID)
|
||||
: ledger (l)
|
||||
, options (o)
|
||||
, txQueue(std::move(q))
|
||||
, type (t)
|
||||
LedgerFill(
|
||||
ReadView const& l,
|
||||
int o = 0,
|
||||
std::vector<TxQ::TxDetails> q = {},
|
||||
LedgerEntryType t = ltINVALID)
|
||||
: ledger(l), options(o), txQueue(std::move(q)), type(t)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,14 +60,17 @@ struct LedgerFill
|
||||
description of the ledger.
|
||||
*/
|
||||
|
||||
void addJson(Json::Value&, LedgerFill const&);
|
||||
void
|
||||
addJson(Json::Value&, LedgerFill const&);
|
||||
|
||||
/** Return a new Json::Value representing the ledger with given options.*/
|
||||
Json::Value getJson (LedgerFill const&);
|
||||
Json::Value
|
||||
getJson(LedgerFill const&);
|
||||
|
||||
/** Serialize an object to a blob. */
|
||||
template <class Object>
|
||||
Blob serializeBlob(Object const& o)
|
||||
Blob
|
||||
serializeBlob(Object const& o)
|
||||
{
|
||||
Serializer s;
|
||||
o.add(s);
|
||||
@@ -75,11 +78,11 @@ Blob serializeBlob(Object const& o)
|
||||
}
|
||||
|
||||
/** Serialize an object to a hex string. */
|
||||
inline
|
||||
std::string serializeHex(STObject const& o)
|
||||
inline std::string
|
||||
serializeHex(STObject const& o)
|
||||
{
|
||||
return strHex(serializeBlob(o));
|
||||
}
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,23 +33,27 @@ namespace ripple {
|
||||
class LocalTxs
|
||||
{
|
||||
public:
|
||||
virtual ~LocalTxs () = default;
|
||||
virtual ~LocalTxs() = default;
|
||||
|
||||
// Add a new local transaction
|
||||
virtual void push_back (LedgerIndex index, std::shared_ptr<STTx const> const& txn) = 0;
|
||||
virtual void
|
||||
push_back(LedgerIndex index, std::shared_ptr<STTx const> const& txn) = 0;
|
||||
|
||||
// Return the set of local transactions to a new open ledger
|
||||
virtual CanonicalTXSet getTxSet () = 0;
|
||||
virtual CanonicalTXSet
|
||||
getTxSet() = 0;
|
||||
|
||||
// Remove obsolete transactions based on a new fully-valid ledger
|
||||
virtual void sweep (ReadView const& view) = 0;
|
||||
virtual void
|
||||
sweep(ReadView const& view) = 0;
|
||||
|
||||
virtual std::size_t size () = 0;
|
||||
virtual std::size_t
|
||||
size() = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<LocalTxs>
|
||||
make_LocalTxs ();
|
||||
make_LocalTxs();
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
#define RIPPLE_APP_LEDGER_OPENLEDGER_H_INCLUDED
|
||||
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/ledger/CachedSLEs.h>
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <ripple/app/misc/CanonicalTXSet.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/ledger/CachedSLEs.h>
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
|
||||
@@ -67,22 +67,21 @@ public:
|
||||
`true` won't cause harm, but it may be
|
||||
sub-optimal.
|
||||
*/
|
||||
using modify_type = std::function<
|
||||
bool(OpenView&, beast::Journal)>;
|
||||
using modify_type = std::function<bool(OpenView&, beast::Journal)>;
|
||||
|
||||
OpenLedger() = delete;
|
||||
OpenLedger (OpenLedger const&) = delete;
|
||||
OpenLedger& operator= (OpenLedger const&) = delete;
|
||||
OpenLedger(OpenLedger const&) = delete;
|
||||
OpenLedger&
|
||||
operator=(OpenLedger const&) = delete;
|
||||
|
||||
/** Create a new open ledger object.
|
||||
|
||||
@param ledger A closed ledger
|
||||
*/
|
||||
explicit
|
||||
OpenLedger(std::shared_ptr<
|
||||
Ledger const> const& ledger,
|
||||
CachedSLEs& cache,
|
||||
beast::Journal journal);
|
||||
explicit OpenLedger(
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
CachedSLEs& cache,
|
||||
beast::Journal journal);
|
||||
|
||||
/** Returns `true` if there are no transactions.
|
||||
|
||||
@@ -124,7 +123,7 @@ public:
|
||||
@return `true` if the open view was changed
|
||||
*/
|
||||
bool
|
||||
modify (modify_type const& f);
|
||||
modify(modify_type const& f);
|
||||
|
||||
/** Accept a new ledger.
|
||||
|
||||
@@ -160,12 +159,16 @@ public:
|
||||
@param ledger A new closed ledger
|
||||
*/
|
||||
void
|
||||
accept (Application& app, Rules const& rules,
|
||||
accept(
|
||||
Application& app,
|
||||
Rules const& rules,
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
OrderedTxs const& locals, bool retriesFirst,
|
||||
OrderedTxs& retries, ApplyFlags flags,
|
||||
std::string const& suffix = "",
|
||||
modify_type const& f = {});
|
||||
OrderedTxs const& locals,
|
||||
bool retriesFirst,
|
||||
OrderedTxs& retries,
|
||||
ApplyFlags flags,
|
||||
std::string const& suffix = "",
|
||||
modify_type const& f = {});
|
||||
|
||||
private:
|
||||
/** Algorithm for applying transactions.
|
||||
@@ -174,45 +177,48 @@ private:
|
||||
used for consensus and building the open ledger.
|
||||
*/
|
||||
template <class FwdRange>
|
||||
static
|
||||
void
|
||||
apply (Application& app, OpenView& view,
|
||||
ReadView const& check, FwdRange const& txs,
|
||||
OrderedTxs& retries, ApplyFlags flags,
|
||||
std::map<uint256, bool>& shouldRecover,
|
||||
beast::Journal j);
|
||||
static void
|
||||
apply(
|
||||
Application& app,
|
||||
OpenView& view,
|
||||
ReadView const& check,
|
||||
FwdRange const& txs,
|
||||
OrderedTxs& retries,
|
||||
ApplyFlags flags,
|
||||
std::map<uint256, bool>& shouldRecover,
|
||||
beast::Journal j);
|
||||
|
||||
enum Result
|
||||
{
|
||||
success,
|
||||
failure,
|
||||
retry
|
||||
};
|
||||
enum Result { success, failure, retry };
|
||||
|
||||
std::shared_ptr<OpenView>
|
||||
create (Rules const& rules,
|
||||
std::shared_ptr<Ledger const> const& ledger);
|
||||
create(Rules const& rules, std::shared_ptr<Ledger const> const& ledger);
|
||||
|
||||
static
|
||||
Result
|
||||
apply_one (Application& app, OpenView& view,
|
||||
std::shared_ptr< STTx const> const& tx,
|
||||
bool retry, ApplyFlags flags,
|
||||
bool shouldRecover, beast::Journal j);
|
||||
static Result
|
||||
apply_one(
|
||||
Application& app,
|
||||
OpenView& view,
|
||||
std::shared_ptr<STTx const> const& tx,
|
||||
bool retry,
|
||||
ApplyFlags flags,
|
||||
bool shouldRecover,
|
||||
beast::Journal j);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class FwdRange>
|
||||
void
|
||||
OpenLedger::apply (Application& app, OpenView& view,
|
||||
ReadView const& check, FwdRange const& txs,
|
||||
OrderedTxs& retries, ApplyFlags flags,
|
||||
std::map<uint256, bool>& shouldRecover,
|
||||
beast::Journal j)
|
||||
OpenLedger::apply(
|
||||
Application& app,
|
||||
OpenView& view,
|
||||
ReadView const& check,
|
||||
FwdRange const& txs,
|
||||
OrderedTxs& retries,
|
||||
ApplyFlags flags,
|
||||
std::map<uint256, bool>& shouldRecover,
|
||||
beast::Journal j)
|
||||
{
|
||||
for (auto iter = txs.begin();
|
||||
iter != txs.end(); ++iter)
|
||||
for (auto iter = txs.begin(); iter != txs.end(); ++iter)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -222,51 +228,53 @@ OpenLedger::apply (Application& app, OpenView& view,
|
||||
auto const txId = tx->getTransactionID();
|
||||
if (check.txExists(txId))
|
||||
continue;
|
||||
auto const result = apply_one(app, view,
|
||||
tx, true, flags, shouldRecover[txId], j);
|
||||
auto const result =
|
||||
apply_one(app, view, tx, true, flags, shouldRecover[txId], j);
|
||||
if (result == Result::retry)
|
||||
retries.insert(tx);
|
||||
}
|
||||
catch(std::exception const&)
|
||||
catch (std::exception const&)
|
||||
{
|
||||
JLOG(j.error()) <<
|
||||
"Caught exception";
|
||||
JLOG(j.error()) << "Caught exception";
|
||||
}
|
||||
}
|
||||
bool retry = true;
|
||||
for (int pass = 0;
|
||||
pass < LEDGER_TOTAL_PASSES;
|
||||
++pass)
|
||||
for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
|
||||
{
|
||||
int changes = 0;
|
||||
auto iter = retries.begin();
|
||||
while (iter != retries.end())
|
||||
{
|
||||
switch (apply_one(app, view,
|
||||
iter->second, retry, flags,
|
||||
shouldRecover[iter->second->getTransactionID()], j))
|
||||
switch (apply_one(
|
||||
app,
|
||||
view,
|
||||
iter->second,
|
||||
retry,
|
||||
flags,
|
||||
shouldRecover[iter->second->getTransactionID()],
|
||||
j))
|
||||
{
|
||||
case Result::success:
|
||||
++changes;
|
||||
[[fallthrough]];
|
||||
case Result::failure:
|
||||
iter = retries.erase (iter);
|
||||
break;
|
||||
case Result::retry:
|
||||
++iter;
|
||||
case Result::success:
|
||||
++changes;
|
||||
[[fallthrough]];
|
||||
case Result::failure:
|
||||
iter = retries.erase(iter);
|
||||
break;
|
||||
case Result::retry:
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
// A non-retry pass made no changes
|
||||
if (! changes && ! retry)
|
||||
if (!changes && !retry)
|
||||
return;
|
||||
// Stop retriable passes
|
||||
if (! changes || (pass >= LEDGER_RETRY_PASSES))
|
||||
if (!changes || (pass >= LEDGER_RETRY_PASSES))
|
||||
retry = false;
|
||||
}
|
||||
|
||||
// If there are any transactions left, we must have
|
||||
// tried them in at least one final pass
|
||||
assert (retries.empty() || ! retry);
|
||||
assert(retries.empty() || !retry);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -274,17 +282,17 @@ OpenLedger::apply (Application& app, OpenView& view,
|
||||
// For debug logging
|
||||
|
||||
std::string
|
||||
debugTxstr (std::shared_ptr<STTx const> const& tx);
|
||||
debugTxstr(std::shared_ptr<STTx const> const& tx);
|
||||
|
||||
std::string
|
||||
debugTostr (OrderedTxs const& set);
|
||||
debugTostr(OrderedTxs const& set);
|
||||
|
||||
std::string
|
||||
debugTostr (SHAMap const& set);
|
||||
debugTostr(SHAMap const& set);
|
||||
|
||||
std::string
|
||||
debugTostr (std::shared_ptr<ReadView const> const& view);
|
||||
debugTostr(std::shared_ptr<ReadView const> const& view);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/OrderBookDB.h>
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/ledger/OrderBookDB.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
@@ -27,25 +27,26 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
OrderBookDB::OrderBookDB (Application& app, Stoppable& parent)
|
||||
: Stoppable ("OrderBookDB", parent)
|
||||
, app_ (app)
|
||||
, mSeq (0)
|
||||
, j_ (app.journal ("OrderBookDB"))
|
||||
OrderBookDB::OrderBookDB(Application& app, Stoppable& parent)
|
||||
: Stoppable("OrderBookDB", parent)
|
||||
, app_(app)
|
||||
, mSeq(0)
|
||||
, j_(app.journal("OrderBookDB"))
|
||||
{
|
||||
}
|
||||
|
||||
void OrderBookDB::invalidate ()
|
||||
void
|
||||
OrderBookDB::invalidate()
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
mSeq = 0;
|
||||
}
|
||||
|
||||
void OrderBookDB::setup(
|
||||
std::shared_ptr<ReadView const> const& ledger)
|
||||
void
|
||||
OrderBookDB::setup(std::shared_ptr<ReadView const> const& ledger)
|
||||
{
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
auto seq = ledger->info().seq;
|
||||
|
||||
// Do a full update every 256 ledgers
|
||||
@@ -59,8 +60,7 @@ void OrderBookDB::setup(
|
||||
return;
|
||||
}
|
||||
|
||||
JLOG (j_.debug())
|
||||
<< "Advancing from " << mSeq << " to " << seq;
|
||||
JLOG(j_.debug()) << "Advancing from " << mSeq << " to " << seq;
|
||||
|
||||
mSeq = seq;
|
||||
}
|
||||
@@ -73,19 +73,20 @@ void OrderBookDB::setup(
|
||||
update(ledger);
|
||||
else
|
||||
app_.getJobQueue().addJob(
|
||||
jtUPDATE_PF, "OrderBookDB::update",
|
||||
[this, ledger] (Job&) { update(ledger); });
|
||||
jtUPDATE_PF, "OrderBookDB::update", [this, ledger](Job&) {
|
||||
update(ledger);
|
||||
});
|
||||
}
|
||||
|
||||
void OrderBookDB::update(
|
||||
std::shared_ptr<ReadView const> const& ledger)
|
||||
void
|
||||
OrderBookDB::update(std::shared_ptr<ReadView const> const& ledger)
|
||||
{
|
||||
hash_set< uint256 > seen;
|
||||
hash_set<uint256> seen;
|
||||
OrderBookDB::IssueToOrderBook destMap;
|
||||
OrderBookDB::IssueToOrderBook sourceMap;
|
||||
hash_set< Issue > XRPBooks;
|
||||
hash_set<Issue> XRPBooks;
|
||||
|
||||
JLOG (j_.debug()) << "OrderBookDB::update>";
|
||||
JLOG(j_.debug()) << "OrderBookDB::update>";
|
||||
|
||||
if (app_.config().PATH_SEARCH_MAX == 0)
|
||||
{
|
||||
@@ -98,20 +99,20 @@ void OrderBookDB::update(
|
||||
|
||||
try
|
||||
{
|
||||
for(auto& sle : ledger->sles)
|
||||
for (auto& sle : ledger->sles)
|
||||
{
|
||||
if (isStopping())
|
||||
{
|
||||
JLOG (j_.info())
|
||||
JLOG(j_.info())
|
||||
<< "OrderBookDB::update exiting due to isStopping";
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
mSeq = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sle->getType () == ltDIR_NODE &&
|
||||
sle->isFieldPresent (sfExchangeRate) &&
|
||||
sle->getFieldH256 (sfRootIndex) == sle->key())
|
||||
if (sle->getType() == ltDIR_NODE &&
|
||||
sle->isFieldPresent(sfExchangeRate) &&
|
||||
sle->getFieldH256(sfRootIndex) == sle->key())
|
||||
{
|
||||
Book book;
|
||||
book.in.currency = sle->getFieldH160(sfTakerPaysCurrency);
|
||||
@@ -119,12 +120,12 @@ void OrderBookDB::update(
|
||||
book.out.account = sle->getFieldH160(sfTakerGetsIssuer);
|
||||
book.out.currency = sle->getFieldH160(sfTakerGetsCurrency);
|
||||
|
||||
uint256 index = getBookBase (book);
|
||||
if (seen.insert (index).second)
|
||||
uint256 index = getBookBase(book);
|
||||
if (seen.insert(index).second)
|
||||
{
|
||||
auto orderBook = std::make_shared<OrderBook> (index, book);
|
||||
sourceMap[book.in].push_back (orderBook);
|
||||
destMap[book.out].push_back (orderBook);
|
||||
auto orderBook = std::make_shared<OrderBook>(index, book);
|
||||
sourceMap[book.in].push_back(orderBook);
|
||||
destMap[book.out].push_back(orderBook);
|
||||
if (isXRP(book.out))
|
||||
XRPBooks.insert(book.in);
|
||||
++books;
|
||||
@@ -134,17 +135,15 @@ void OrderBookDB::update(
|
||||
}
|
||||
catch (SHAMapMissingNode const& mn)
|
||||
{
|
||||
JLOG (j_.info())
|
||||
<< "OrderBookDB::update: " << mn.what();
|
||||
std::lock_guard sl (mLock);
|
||||
JLOG(j_.info()) << "OrderBookDB::update: " << mn.what();
|
||||
std::lock_guard sl(mLock);
|
||||
mSeq = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
JLOG (j_.debug())
|
||||
<< "OrderBookDB::update< " << books << " books found";
|
||||
JLOG(j_.debug()) << "OrderBookDB::update< " << books << " books found";
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
mXRPBooks.swap(XRPBooks);
|
||||
mSourceMap.swap(sourceMap);
|
||||
@@ -153,24 +152,25 @@ void OrderBookDB::update(
|
||||
app_.getLedgerMaster().newOrderBookDB();
|
||||
}
|
||||
|
||||
void OrderBookDB::addOrderBook(Book const& book)
|
||||
void
|
||||
OrderBookDB::addOrderBook(Book const& book)
|
||||
{
|
||||
bool toXRP = isXRP (book.out);
|
||||
std::lock_guard sl (mLock);
|
||||
bool toXRP = isXRP(book.out);
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
if (toXRP)
|
||||
{
|
||||
// We don't want to search through all the to-XRP or from-XRP order
|
||||
// books!
|
||||
for (auto ob: mSourceMap[book.in])
|
||||
for (auto ob : mSourceMap[book.in])
|
||||
{
|
||||
if (isXRP (ob->getCurrencyOut ())) // also to XRP
|
||||
if (isXRP(ob->getCurrencyOut())) // also to XRP
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto ob: mDestMap[book.out])
|
||||
for (auto ob : mDestMap[book.out])
|
||||
{
|
||||
if (ob->getCurrencyIn() == book.in.currency &&
|
||||
ob->getIssuerIn() == book.in.account)
|
||||
@@ -180,57 +180,63 @@ void OrderBookDB::addOrderBook(Book const& book)
|
||||
}
|
||||
}
|
||||
uint256 index = getBookBase(book);
|
||||
auto orderBook = std::make_shared<OrderBook> (index, book);
|
||||
auto orderBook = std::make_shared<OrderBook>(index, book);
|
||||
|
||||
mSourceMap[book.in].push_back (orderBook);
|
||||
mDestMap[book.out].push_back (orderBook);
|
||||
mSourceMap[book.in].push_back(orderBook);
|
||||
mDestMap[book.out].push_back(orderBook);
|
||||
if (toXRP)
|
||||
mXRPBooks.insert(book.in);
|
||||
}
|
||||
|
||||
// return list of all orderbooks that want this issuerID and currencyID
|
||||
OrderBook::List OrderBookDB::getBooksByTakerPays (Issue const& issue)
|
||||
OrderBook::List
|
||||
OrderBookDB::getBooksByTakerPays(Issue const& issue)
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
auto it = mSourceMap.find (issue);
|
||||
return it == mSourceMap.end () ? OrderBook::List() : it->second;
|
||||
std::lock_guard sl(mLock);
|
||||
auto it = mSourceMap.find(issue);
|
||||
return it == mSourceMap.end() ? OrderBook::List() : it->second;
|
||||
}
|
||||
|
||||
int OrderBookDB::getBookSize(Issue const& issue) {
|
||||
std::lock_guard sl (mLock);
|
||||
auto it = mSourceMap.find (issue);
|
||||
return it == mSourceMap.end () ? 0 : it->second.size();
|
||||
int
|
||||
OrderBookDB::getBookSize(Issue const& issue)
|
||||
{
|
||||
std::lock_guard sl(mLock);
|
||||
auto it = mSourceMap.find(issue);
|
||||
return it == mSourceMap.end() ? 0 : it->second.size();
|
||||
}
|
||||
|
||||
bool OrderBookDB::isBookToXRP(Issue const& issue)
|
||||
bool
|
||||
OrderBookDB::isBookToXRP(Issue const& issue)
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
return mXRPBooks.count(issue) > 0;
|
||||
}
|
||||
|
||||
BookListeners::pointer OrderBookDB::makeBookListeners (Book const& book)
|
||||
BookListeners::pointer
|
||||
OrderBookDB::makeBookListeners(Book const& book)
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
auto ret = getBookListeners (book);
|
||||
std::lock_guard sl(mLock);
|
||||
auto ret = getBookListeners(book);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
ret = std::make_shared<BookListeners> ();
|
||||
ret = std::make_shared<BookListeners>();
|
||||
|
||||
mListeners [book] = ret;
|
||||
assert (getBookListeners (book) == ret);
|
||||
mListeners[book] = ret;
|
||||
assert(getBookListeners(book) == ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BookListeners::pointer OrderBookDB::getBookListeners (Book const& book)
|
||||
BookListeners::pointer
|
||||
OrderBookDB::getBookListeners(Book const& book)
|
||||
{
|
||||
BookListeners::pointer ret;
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
auto it0 = mListeners.find (book);
|
||||
if (it0 != mListeners.end ())
|
||||
auto it0 = mListeners.find(book);
|
||||
if (it0 != mListeners.end())
|
||||
ret = it0->second;
|
||||
|
||||
return ret;
|
||||
@@ -238,12 +244,14 @@ BookListeners::pointer OrderBookDB::getBookListeners (Book const& book)
|
||||
|
||||
// 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 (
|
||||
void
|
||||
OrderBookDB::processTxn(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
const AcceptedLedgerTx& alTx, Json::Value const& jvObj)
|
||||
const AcceptedLedgerTx& alTx,
|
||||
Json::Value const& jvObj)
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
if (alTx.getResult () == tesSUCCESS)
|
||||
std::lock_guard sl(mLock);
|
||||
if (alTx.getResult() == tesSUCCESS)
|
||||
{
|
||||
// For this particular transaction, maintain the set of unique
|
||||
// subscriptions that have already published it. This prevents sending
|
||||
@@ -255,34 +263,34 @@ void OrderBookDB::processTxn (
|
||||
// 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 ())
|
||||
for (auto& node : alTx.getMeta()->getNodes())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (node.getFieldU16 (sfLedgerEntryType) == ltOFFER)
|
||||
if (node.getFieldU16(sfLedgerEntryType) == ltOFFER)
|
||||
{
|
||||
SField const* field = nullptr;
|
||||
|
||||
// We need a field that contains the TakerGets and TakerPays
|
||||
// parameters.
|
||||
if (node.getFName () == sfModifiedNode)
|
||||
if (node.getFName() == sfModifiedNode)
|
||||
field = &sfPreviousFields;
|
||||
else if (node.getFName () == sfCreatedNode)
|
||||
else if (node.getFName() == sfCreatedNode)
|
||||
field = &sfNewFields;
|
||||
else if (node.getFName () == sfDeletedNode)
|
||||
else if (node.getFName() == sfDeletedNode)
|
||||
field = &sfFinalFields;
|
||||
|
||||
if (field)
|
||||
{
|
||||
auto data = dynamic_cast<const STObject*> (
|
||||
node.peekAtPField (*field));
|
||||
auto data = dynamic_cast<const STObject*>(
|
||||
node.peekAtPField(*field));
|
||||
|
||||
if (data &&
|
||||
data->isFieldPresent (sfTakerPays) &&
|
||||
data->isFieldPresent (sfTakerGets))
|
||||
if (data && data->isFieldPresent(sfTakerPays) &&
|
||||
data->isFieldPresent(sfTakerGets))
|
||||
{
|
||||
// determine the OrderBook
|
||||
Book b{data->getFieldAmount(sfTakerGets).issue(),
|
||||
Book b{
|
||||
data->getFieldAmount(sfTakerGets).issue(),
|
||||
data->getFieldAmount(sfTakerPays).issue()};
|
||||
|
||||
auto listeners = getBookListeners(b);
|
||||
@@ -296,11 +304,11 @@ void OrderBookDB::processTxn (
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
JLOG (j_.info())
|
||||
JLOG(j_.info())
|
||||
<< "Fields not found in OrderBookDB::processTxn";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -28,40 +28,51 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class OrderBookDB
|
||||
: public Stoppable
|
||||
class OrderBookDB : public Stoppable
|
||||
{
|
||||
public:
|
||||
OrderBookDB (Application& app, Stoppable& parent);
|
||||
OrderBookDB(Application& app, Stoppable& parent);
|
||||
|
||||
void setup (std::shared_ptr<ReadView const> const& ledger);
|
||||
void update (std::shared_ptr<ReadView const> const& ledger);
|
||||
void invalidate ();
|
||||
void
|
||||
setup(std::shared_ptr<ReadView const> const& ledger);
|
||||
void
|
||||
update(std::shared_ptr<ReadView const> const& ledger);
|
||||
void
|
||||
invalidate();
|
||||
|
||||
void addOrderBook(Book const&);
|
||||
void
|
||||
addOrderBook(Book const&);
|
||||
|
||||
/** @return a list of all orderbooks that want this issuerID and currencyID.
|
||||
*/
|
||||
OrderBook::List getBooksByTakerPays (Issue const&);
|
||||
OrderBook::List
|
||||
getBooksByTakerPays(Issue const&);
|
||||
|
||||
/** @return a count of all orderbooks that want this issuerID and
|
||||
currencyID. */
|
||||
int getBookSize(Issue const&);
|
||||
int
|
||||
getBookSize(Issue const&);
|
||||
|
||||
bool isBookToXRP (Issue const&);
|
||||
bool
|
||||
isBookToXRP(Issue const&);
|
||||
|
||||
BookListeners::pointer getBookListeners (Book const&);
|
||||
BookListeners::pointer makeBookListeners (Book const&);
|
||||
BookListeners::pointer
|
||||
getBookListeners(Book const&);
|
||||
BookListeners::pointer
|
||||
makeBookListeners(Book const&);
|
||||
|
||||
// see if this txn effects any orderbook
|
||||
void processTxn (
|
||||
void
|
||||
processTxn(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
const AcceptedLedgerTx& alTx, Json::Value const& jvObj);
|
||||
const AcceptedLedgerTx& alTx,
|
||||
Json::Value const& jvObj);
|
||||
|
||||
using IssueToOrderBook = hash_map <Issue, OrderBook::List>;
|
||||
using IssueToOrderBook = hash_map<Issue, OrderBook::List>;
|
||||
|
||||
private:
|
||||
void rawAddBook(Book const&);
|
||||
void
|
||||
rawAddBook(Book const&);
|
||||
|
||||
Application& app_;
|
||||
|
||||
@@ -72,11 +83,11 @@ private:
|
||||
IssueToOrderBook mDestMap;
|
||||
|
||||
// does an order book to XRP exist
|
||||
hash_set <Issue> mXRPBooks;
|
||||
hash_set<Issue> mXRPBooks;
|
||||
|
||||
std::recursive_mutex mLock;
|
||||
|
||||
using BookToListenersMap = hash_map <Book, BookListeners::pointer>;
|
||||
using BookToListenersMap = hash_map<Book, BookListeners::pointer>;
|
||||
|
||||
BookToListenersMap mListeners;
|
||||
|
||||
@@ -85,6 +96,6 @@ private:
|
||||
beast::Journal const j_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#define RIPPLE_APP_PENDINGSAVES_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <condition_variable>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -37,11 +37,10 @@ class PendingSaves
|
||||
{
|
||||
private:
|
||||
std::mutex mutable mutex_;
|
||||
std::map <LedgerIndex, bool> map_;
|
||||
std::map<LedgerIndex, bool> map_;
|
||||
std::condition_variable await_;
|
||||
|
||||
public:
|
||||
|
||||
/** Start working on a ledger
|
||||
|
||||
This is called prior to updating the SQLite indexes.
|
||||
@@ -49,11 +48,11 @@ public:
|
||||
@return 'true' if work should be done
|
||||
*/
|
||||
bool
|
||||
startWork (LedgerIndex seq)
|
||||
startWork(LedgerIndex seq)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
auto it = map_.find (seq);
|
||||
auto it = map_.find(seq);
|
||||
|
||||
if ((it == map_.end()) || it->second)
|
||||
{
|
||||
@@ -72,17 +71,17 @@ public:
|
||||
threads awaiting completion are notified.
|
||||
*/
|
||||
void
|
||||
finishWork (LedgerIndex seq)
|
||||
finishWork(LedgerIndex seq)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
map_.erase (seq);
|
||||
map_.erase(seq);
|
||||
await_.notify_all();
|
||||
}
|
||||
|
||||
/** Return `true` if a ledger is in the progress of being saved. */
|
||||
bool
|
||||
pending (LedgerIndex seq)
|
||||
pending(LedgerIndex seq)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return map_.find(seq) != map_.end();
|
||||
@@ -97,12 +96,12 @@ public:
|
||||
@return 'true' if work should be done or dispatched
|
||||
*/
|
||||
bool
|
||||
shouldWork (LedgerIndex seq, bool isSynchronous)
|
||||
shouldWork(LedgerIndex seq, bool isSynchronous)
|
||||
{
|
||||
std::unique_lock <std::mutex> lock(mutex_);
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
do
|
||||
{
|
||||
auto it = map_.find (seq);
|
||||
auto it = map_.find(seq);
|
||||
|
||||
if (it == map_.end())
|
||||
{
|
||||
@@ -110,20 +109,20 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! isSynchronous)
|
||||
if (!isSynchronous)
|
||||
{
|
||||
// Already dispatched
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! it->second)
|
||||
if (!it->second)
|
||||
{
|
||||
// Scheduled, but not dispatched
|
||||
return true;
|
||||
}
|
||||
|
||||
// Already in progress, just need to wait
|
||||
await_.wait (lock);
|
||||
await_.wait(lock);
|
||||
|
||||
} while (true);
|
||||
}
|
||||
@@ -134,16 +133,15 @@ public:
|
||||
that is in progress or dispatched. The boolean indicates
|
||||
whether work is currently in progress.
|
||||
*/
|
||||
std::map <LedgerIndex, bool>
|
||||
getSnapshot () const
|
||||
std::map<LedgerIndex, bool>
|
||||
getSnapshot() const
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
return map_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_TRANSACTIONMASTER_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_TRANSACTIONMASTER_H_INCLUDED
|
||||
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/basics/RangeSet.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/shamap/SHAMapItem.h>
|
||||
#include <ripple/shamap/SHAMapTreeNode.h>
|
||||
#include <ripple/basics/RangeSet.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -36,15 +36,16 @@ class STTx;
|
||||
class TransactionMaster
|
||||
{
|
||||
public:
|
||||
TransactionMaster (Application& app);
|
||||
TransactionMaster (TransactionMaster const&) = delete;
|
||||
TransactionMaster& operator= (TransactionMaster const&) = delete;
|
||||
TransactionMaster(Application& app);
|
||||
TransactionMaster(TransactionMaster const&) = delete;
|
||||
TransactionMaster&
|
||||
operator=(TransactionMaster const&) = delete;
|
||||
|
||||
std::shared_ptr<Transaction>
|
||||
fetch_from_cache (uint256 const&);
|
||||
fetch_from_cache(uint256 const&);
|
||||
|
||||
std::shared_ptr<Transaction>
|
||||
fetch (uint256 const& , error_code_i& ec);
|
||||
fetch(uint256 const&, error_code_i& ec);
|
||||
|
||||
/**
|
||||
* Fetch transaction from the cache or database.
|
||||
@@ -56,27 +57,35 @@ public:
|
||||
* while the search was conducted.
|
||||
*/
|
||||
boost::variant<Transaction::pointer, bool>
|
||||
fetch (uint256 const& , ClosedInterval<uint32_t> const& range, error_code_i& ec);
|
||||
fetch(
|
||||
uint256 const&,
|
||||
ClosedInterval<uint32_t> const& range,
|
||||
error_code_i& ec);
|
||||
|
||||
std::shared_ptr<STTx const>
|
||||
fetch (std::shared_ptr<SHAMapItem> const& item,
|
||||
SHAMapTreeNode::TNType type, std::uint32_t uCommitLedger);
|
||||
fetch(
|
||||
std::shared_ptr<SHAMapItem> const& item,
|
||||
SHAMapTreeNode::TNType type,
|
||||
std::uint32_t uCommitLedger);
|
||||
|
||||
// return value: true = we had the transaction already
|
||||
bool inLedger (uint256 const& hash, std::uint32_t ledger);
|
||||
bool
|
||||
inLedger(uint256 const& hash, std::uint32_t ledger);
|
||||
|
||||
void canonicalize (std::shared_ptr<Transaction>* pTransaction);
|
||||
void
|
||||
canonicalize(std::shared_ptr<Transaction>* pTransaction);
|
||||
|
||||
void sweep (void);
|
||||
void
|
||||
sweep(void);
|
||||
|
||||
TaggedCache <uint256, Transaction>&
|
||||
TaggedCache<uint256, Transaction>&
|
||||
getCache();
|
||||
|
||||
private:
|
||||
Application& mApp;
|
||||
TaggedCache <uint256, Transaction> mCache;
|
||||
TaggedCache<uint256, Transaction> mCache;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,13 +22,20 @@
|
||||
namespace ripple {
|
||||
|
||||
void
|
||||
TransactionStateSF::gotNode(bool, SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq, Blob&& nodeData, SHAMapTreeNode::TNType type) const
|
||||
TransactionStateSF::gotNode(
|
||||
bool,
|
||||
SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq,
|
||||
Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const
|
||||
|
||||
{
|
||||
assert(type != SHAMapTreeNode::tnTRANSACTION_NM);
|
||||
db_.store(hotTRANSACTION_NODE, std::move(nodeData),
|
||||
nodeHash.as_uint256(), ledgerSeq);
|
||||
db_.store(
|
||||
hotTRANSACTION_NODE,
|
||||
std::move(nodeData),
|
||||
nodeHash.as_uint256(),
|
||||
ledgerSeq);
|
||||
}
|
||||
|
||||
boost::optional<Blob>
|
||||
@@ -37,4 +44,4 @@ TransactionStateSF::getNode(SHAMapHash const& nodeHash) const
|
||||
return fp_.getFetchPack(nodeHash.as_uint256());
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -32,14 +32,17 @@ class TransactionStateSF : public SHAMapSyncFilter
|
||||
{
|
||||
public:
|
||||
TransactionStateSF(NodeStore::Database& db, AbstractFetchPackContainer& fp)
|
||||
: db_(db)
|
||||
, fp_(fp)
|
||||
{}
|
||||
: db_(db), fp_(fp)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
gotNode(bool fromFilter, SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq, Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const override;
|
||||
gotNode(
|
||||
bool fromFilter,
|
||||
SHAMapHash const& nodeHash,
|
||||
std::uint32_t ledgerSeq,
|
||||
Blob&& nodeData,
|
||||
SHAMapTreeNode::TNType type) const override;
|
||||
|
||||
boost::optional<Blob>
|
||||
getNode(SHAMapHash const& nodeHash) const override;
|
||||
@@ -49,6 +52,6 @@ private:
|
||||
AbstractFetchPackContainer& fp_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -62,10 +62,10 @@ buildLedgerImpl(
|
||||
// Write the final version of all modified SHAMap
|
||||
// nodes to the node store to preserve the new LCL
|
||||
|
||||
int const asf = built->stateMap().flushDirty(
|
||||
hotACCOUNT_NODE, built->info().seq);
|
||||
int const tmf = built->txMap().flushDirty(
|
||||
hotTRANSACTION_NODE, built->info().seq);
|
||||
int const asf =
|
||||
built->stateMap().flushDirty(hotACCOUNT_NODE, built->info().seq);
|
||||
int const tmf =
|
||||
built->txMap().flushDirty(hotTRANSACTION_NODE, built->info().seq);
|
||||
JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf
|
||||
<< " transaction nodes";
|
||||
}
|
||||
@@ -103,9 +103,8 @@ applyTransactions(
|
||||
// Attempt to apply all of the retriable transactions
|
||||
for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
|
||||
{
|
||||
JLOG(j.debug())
|
||||
<< (certainRetry ? "Pass: " : "Final pass: ") << pass
|
||||
<< " begins (" << txns.size() << " transactions)";
|
||||
JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
|
||||
<< " begins (" << txns.size() << " transactions)";
|
||||
int changes = 0;
|
||||
|
||||
auto it = txns.begin();
|
||||
@@ -147,9 +146,8 @@ applyTransactions(
|
||||
}
|
||||
}
|
||||
|
||||
JLOG(j.debug())
|
||||
<< (certainRetry ? "Pass: " : "Final pass: ") << pass
|
||||
<< " completed (" << changes << " changes)";
|
||||
JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
|
||||
<< " completed (" << changes << " changes)";
|
||||
|
||||
// Accumulate changes.
|
||||
count += changes;
|
||||
@@ -181,30 +179,30 @@ buildLedger(
|
||||
std::set<TxID>& failedTxns,
|
||||
beast::Journal j)
|
||||
{
|
||||
JLOG(j.debug()) << "Report: Transaction Set = " << txns.key()
|
||||
<< ", close " << closeTime.time_since_epoch().count()
|
||||
JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close "
|
||||
<< closeTime.time_since_epoch().count()
|
||||
<< (closeTimeCorrect ? "" : " (incorrect)");
|
||||
|
||||
return buildLedgerImpl(parent, closeTime, closeTimeCorrect,
|
||||
closeResolution, app, j,
|
||||
[&](OpenView& accum, std::shared_ptr<Ledger> const& built)
|
||||
{
|
||||
return buildLedgerImpl(
|
||||
parent,
|
||||
closeTime,
|
||||
closeTimeCorrect,
|
||||
closeResolution,
|
||||
app,
|
||||
j,
|
||||
[&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
|
||||
JLOG(j.debug())
|
||||
<< "Attempting to apply " << txns.size()
|
||||
<< " transactions";
|
||||
<< "Attempting to apply " << txns.size() << " transactions";
|
||||
|
||||
auto const applied = applyTransactions(app, built, txns,
|
||||
failedTxns, accum, j);
|
||||
auto const applied =
|
||||
applyTransactions(app, built, txns, failedTxns, accum, j);
|
||||
|
||||
if (!txns.empty() || !failedTxns.empty())
|
||||
JLOG(j.debug())
|
||||
<< "Applied " << applied << " transactions; "
|
||||
<< failedTxns.size() << " failed and "
|
||||
<< txns.size() << " will be retried.";
|
||||
JLOG(j.debug()) << "Applied " << applied << " transactions; "
|
||||
<< failedTxns.size() << " failed and "
|
||||
<< txns.size() << " will be retried.";
|
||||
else
|
||||
JLOG(j.debug())
|
||||
<< "Applied " << applied
|
||||
<< " transactions.";
|
||||
JLOG(j.debug()) << "Applied " << applied << " transactions.";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -227,8 +225,7 @@ buildLedger(
|
||||
replayLedger->info().closeTimeResolution,
|
||||
app,
|
||||
j,
|
||||
[&](OpenView& accum, std::shared_ptr<Ledger> const& built)
|
||||
{
|
||||
[&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
|
||||
for (auto& tx : replayData.orderedTxns())
|
||||
applyTransaction(app, accum, *tx.second, false, applyFlags, j);
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,19 +23,17 @@
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/basics/DecayingSample.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/beast/container/aged_map.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
#include <ripple/core/JobQueue.h>
|
||||
#include <ripple/nodestore/DatabaseShard.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
#include <ripple/beast/container/aged_map.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class InboundLedgersImp
|
||||
: public InboundLedgers
|
||||
, public Stoppable
|
||||
class InboundLedgersImp : public InboundLedgers, public Stoppable
|
||||
{
|
||||
private:
|
||||
Application& app_;
|
||||
@@ -45,32 +43,36 @@ private:
|
||||
beast::Journal const j_;
|
||||
|
||||
public:
|
||||
using u256_acq_pair = std::pair<
|
||||
uint256,
|
||||
std::shared_ptr <InboundLedger>>;
|
||||
using u256_acq_pair = std::pair<uint256, std::shared_ptr<InboundLedger>>;
|
||||
|
||||
// How long before we try again to acquire the same ledger
|
||||
static const std::chrono::minutes kReacquireInterval;
|
||||
|
||||
InboundLedgersImp (Application& app, clock_type& clock, Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: Stoppable ("InboundLedgers", parent)
|
||||
, app_ (app)
|
||||
InboundLedgersImp(
|
||||
Application& app,
|
||||
clock_type& clock,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: Stoppable("InboundLedgers", parent)
|
||||
, app_(app)
|
||||
, fetchRate_(clock.now())
|
||||
, j_ (app.journal ("InboundLedger"))
|
||||
, m_clock (clock)
|
||||
, mRecentFailures (clock)
|
||||
, j_(app.journal("InboundLedger"))
|
||||
, m_clock(clock)
|
||||
, mRecentFailures(clock)
|
||||
, mCounter(collector->make_counter("ledger_fetches"))
|
||||
{
|
||||
}
|
||||
|
||||
/** @callgraph */
|
||||
std::shared_ptr<Ledger const>
|
||||
acquire(uint256 const& hash, std::uint32_t seq,
|
||||
acquire(
|
||||
uint256 const& hash,
|
||||
std::uint32_t seq,
|
||||
InboundLedger::Reason reason) override
|
||||
{
|
||||
assert(hash.isNonZero());
|
||||
assert(reason != InboundLedger::Reason::SHARD ||
|
||||
assert(
|
||||
reason != InboundLedger::Reason::SHARD ||
|
||||
(seq != 0 && app_.getShardStore()));
|
||||
if (isStopping())
|
||||
return {};
|
||||
@@ -87,7 +89,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
inbound = std::make_shared <InboundLedger>(
|
||||
inbound = std::make_shared<InboundLedger>(
|
||||
app_, hash, seq, reason, std::ref(m_clock));
|
||||
mLedgers.emplace(hash, inbound);
|
||||
inbound->init(sl);
|
||||
@@ -98,10 +100,10 @@ public:
|
||||
if (inbound->isFailed())
|
||||
return {};
|
||||
|
||||
if (! isNew)
|
||||
if (!isNew)
|
||||
inbound->update(seq);
|
||||
|
||||
if (! inbound->isComplete())
|
||||
if (!inbound->isComplete())
|
||||
return {};
|
||||
|
||||
if (reason == InboundLedger::Reason::HISTORY)
|
||||
@@ -114,8 +116,8 @@ public:
|
||||
auto shardStore = app_.getShardStore();
|
||||
if (!shardStore)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"Acquiring shard with no shard store available";
|
||||
JLOG(j_.error())
|
||||
<< "Acquiring shard with no shard store available";
|
||||
return {};
|
||||
}
|
||||
if (inbound->getLedger()->stateMap().family().isShardBacked())
|
||||
@@ -126,17 +128,18 @@ public:
|
||||
return inbound->getLedger();
|
||||
}
|
||||
|
||||
std::shared_ptr<InboundLedger> find (uint256 const& hash) override
|
||||
std::shared_ptr<InboundLedger>
|
||||
find(uint256 const& hash) override
|
||||
{
|
||||
assert (hash.isNonZero ());
|
||||
assert(hash.isNonZero());
|
||||
|
||||
std::shared_ptr<InboundLedger> ret;
|
||||
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
auto it = mLedgers.find (hash);
|
||||
if (it != mLedgers.end ())
|
||||
auto it = mLedgers.find(hash);
|
||||
if (it != mLedgers.end())
|
||||
{
|
||||
ret = it->second;
|
||||
}
|
||||
@@ -158,31 +161,32 @@ public:
|
||||
|
||||
// VFALCO TODO Remove the dependency on the Peer object.
|
||||
/** We received a TMLedgerData from a peer.
|
||||
*/
|
||||
bool gotLedgerData (LedgerHash const& hash,
|
||||
std::shared_ptr<Peer> peer,
|
||||
std::shared_ptr<protocol::TMLedgerData> packet_ptr) override
|
||||
*/
|
||||
bool
|
||||
gotLedgerData(
|
||||
LedgerHash const& hash,
|
||||
std::shared_ptr<Peer> peer,
|
||||
std::shared_ptr<protocol::TMLedgerData> packet_ptr) override
|
||||
{
|
||||
protocol::TMLedgerData& packet = *packet_ptr;
|
||||
|
||||
JLOG (j_.trace())
|
||||
<< "Got data (" << packet.nodes ().size ()
|
||||
<< ") for acquiring ledger: " << hash;
|
||||
JLOG(j_.trace()) << "Got data (" << packet.nodes().size()
|
||||
<< ") for acquiring ledger: " << hash;
|
||||
|
||||
auto ledger = find (hash);
|
||||
auto ledger = find(hash);
|
||||
|
||||
if (!ledger)
|
||||
{
|
||||
JLOG (j_.trace())
|
||||
<< "Got data for ledger we're no longer acquiring";
|
||||
JLOG(j_.trace()) << "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)
|
||||
if (packet.type() == protocol::liAS_NODE)
|
||||
{
|
||||
app_.getJobQueue().addJob(
|
||||
jtLEDGER_DATA, "gotStaleData",
|
||||
[this, packet_ptr] (Job&) { gotStaleData(packet_ptr); });
|
||||
jtLEDGER_DATA, "gotStaleData", [this, packet_ptr](Job&) {
|
||||
gotStaleData(packet_ptr);
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -190,14 +194,16 @@ public:
|
||||
|
||||
// Stash the data for later processing and see if we need to dispatch
|
||||
if (ledger->gotData(std::weak_ptr<Peer>(peer), packet_ptr))
|
||||
app_.getJobQueue().addJob (
|
||||
jtLEDGER_DATA, "processLedgerData",
|
||||
[this, hash] (Job&) { doLedgerData(hash); });
|
||||
app_.getJobQueue().addJob(
|
||||
jtLEDGER_DATA, "processLedgerData", [this, hash](Job&) {
|
||||
doLedgerData(hash);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int getFetchCount (int& timeoutCount) override
|
||||
int
|
||||
getFetchCount(int& timeoutCount) override
|
||||
{
|
||||
timeoutCount = 0;
|
||||
int ret = 0;
|
||||
@@ -205,7 +211,7 @@ public:
|
||||
std::vector<u256_acq_pair> inboundLedgers;
|
||||
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
inboundLedgers.reserve(mLedgers.size());
|
||||
for (auto const& it : mLedgers)
|
||||
@@ -216,34 +222,37 @@ public:
|
||||
|
||||
for (auto const& it : inboundLedgers)
|
||||
{
|
||||
if (it.second->isActive ())
|
||||
if (it.second->isActive())
|
||||
{
|
||||
++ret;
|
||||
timeoutCount += it.second->getTimeouts ();
|
||||
timeoutCount += it.second->getTimeouts();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void logFailure (uint256 const& h, std::uint32_t seq) override
|
||||
void
|
||||
logFailure(uint256 const& h, std::uint32_t seq) override
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
mRecentFailures.emplace(h, seq);
|
||||
}
|
||||
|
||||
bool isFailure (uint256 const& h) override
|
||||
bool
|
||||
isFailure(uint256 const& h) override
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
beast::expire (mRecentFailures, kReacquireInterval);
|
||||
return mRecentFailures.find (h) != mRecentFailures.end();
|
||||
beast::expire(mRecentFailures, kReacquireInterval);
|
||||
return mRecentFailures.find(h) != mRecentFailures.end();
|
||||
}
|
||||
|
||||
void doLedgerData (LedgerHash hash) override
|
||||
void
|
||||
doLedgerData(LedgerHash hash) override
|
||||
{
|
||||
if (auto ledger = find (hash))
|
||||
ledger->runData ();
|
||||
if (auto ledger = find(hash))
|
||||
ledger->runData();
|
||||
}
|
||||
|
||||
/** We got some data for a ledger we are no longer acquiring Since we paid
|
||||
@@ -252,23 +261,28 @@ public:
|
||||
Nodes are received in wire format and must be stashed/hashed in prefix
|
||||
format
|
||||
*/
|
||||
void gotStaleData (std::shared_ptr<protocol::TMLedgerData> packet_ptr) override
|
||||
void
|
||||
gotStaleData(std::shared_ptr<protocol::TMLedgerData> packet_ptr) override
|
||||
{
|
||||
const uint256 uZero;
|
||||
Serializer s;
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < packet_ptr->nodes ().size (); ++i)
|
||||
for (int i = 0; i < packet_ptr->nodes().size(); ++i)
|
||||
{
|
||||
auto const& node = packet_ptr->nodes (i);
|
||||
auto const& node = packet_ptr->nodes(i);
|
||||
|
||||
if (!node.has_nodeid () || !node.has_nodedata ())
|
||||
if (!node.has_nodeid() || !node.has_nodedata())
|
||||
return;
|
||||
|
||||
auto id_string = node.nodeid();
|
||||
auto newNode = SHAMapAbstractNode::make(
|
||||
makeSlice(node.nodedata()),
|
||||
0, snfWIRE, SHAMapHash{uZero}, false, app_.journal ("SHAMapNodeID"),
|
||||
0,
|
||||
snfWIRE,
|
||||
SHAMapHash{uZero},
|
||||
false,
|
||||
app_.journal("SHAMapNodeID"),
|
||||
SHAMapNodeID(id_string.data(), id_string.size()));
|
||||
|
||||
if (!newNode)
|
||||
@@ -277,7 +291,7 @@ public:
|
||||
s.erase();
|
||||
newNode->addRaw(s, snfPREFIX);
|
||||
|
||||
auto blob = std::make_shared<Blob> (s.begin(), s.end());
|
||||
auto blob = std::make_shared<Blob>(s.begin(), s.end());
|
||||
|
||||
app_.getLedgerMaster().addFetchPack(
|
||||
newNode->getNodeHash().as_uint256(), blob);
|
||||
@@ -288,50 +302,53 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void clearFailures () override
|
||||
void
|
||||
clearFailures() override
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
mRecentFailures.clear();
|
||||
mLedgers.clear();
|
||||
}
|
||||
|
||||
std::size_t fetchRate() override
|
||||
std::size_t
|
||||
fetchRate() override
|
||||
{
|
||||
std::lock_guard lock(fetchRateMutex_);
|
||||
return 60 * fetchRate_.value(
|
||||
m_clock.now());
|
||||
return 60 * fetchRate_.value(m_clock.now());
|
||||
}
|
||||
|
||||
// Should only be called with an inboundledger that has
|
||||
// a reason of history or shard
|
||||
void onLedgerFetched() override
|
||||
void
|
||||
onLedgerFetched() override
|
||||
{
|
||||
std::lock_guard lock(fetchRateMutex_);
|
||||
fetchRate_.add(1, m_clock.now());
|
||||
}
|
||||
|
||||
Json::Value getInfo() override
|
||||
Json::Value
|
||||
getInfo() override
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
std::vector<u256_acq_pair> acquires;
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
acquires.reserve (mLedgers.size ());
|
||||
acquires.reserve(mLedgers.size());
|
||||
for (auto const& it : mLedgers)
|
||||
{
|
||||
assert (it.second);
|
||||
acquires.push_back (it);
|
||||
assert(it.second);
|
||||
acquires.push_back(it);
|
||||
}
|
||||
for (auto const& it : mRecentFailures)
|
||||
{
|
||||
if (it.second > 1)
|
||||
ret[beast::lexicalCastThrow <std::string>(
|
||||
it.second)][jss::failed] = true;
|
||||
ret[beast::lexicalCastThrow<std::string>(it.second)]
|
||||
[jss::failed] = true;
|
||||
else
|
||||
ret[to_string (it.first)][jss::failed] = true;
|
||||
ret[to_string(it.first)][jss::failed] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,59 +359,62 @@ public:
|
||||
if (seq > 1)
|
||||
ret[std::to_string(seq)] = it.second->getJson(0);
|
||||
else
|
||||
ret[to_string (it.first)] = it.second->getJson(0);
|
||||
ret[to_string(it.first)] = it.second->getJson(0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gotFetchPack () override
|
||||
void
|
||||
gotFetchPack() override
|
||||
{
|
||||
std::vector<std::shared_ptr<InboundLedger>> acquires;
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
acquires.reserve (mLedgers.size ());
|
||||
acquires.reserve(mLedgers.size());
|
||||
for (auto const& it : mLedgers)
|
||||
{
|
||||
assert (it.second);
|
||||
acquires.push_back (it.second);
|
||||
assert(it.second);
|
||||
acquires.push_back(it.second);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& acquire : acquires)
|
||||
{
|
||||
acquire->checkLocal ();
|
||||
acquire->checkLocal();
|
||||
}
|
||||
}
|
||||
|
||||
void sweep () override
|
||||
void
|
||||
sweep() override
|
||||
{
|
||||
clock_type::time_point const now (m_clock.now());
|
||||
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::vector<MapType::mapped_type> stuffToSweep;
|
||||
std::size_t total;
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
MapType::iterator it (mLedgers.begin ());
|
||||
total = mLedgers.size ();
|
||||
stuffToSweep.reserve (total);
|
||||
ScopedLockType sl(mLock);
|
||||
MapType::iterator it(mLedgers.begin());
|
||||
total = mLedgers.size();
|
||||
stuffToSweep.reserve(total);
|
||||
|
||||
while (it != mLedgers.end ())
|
||||
while (it != mLedgers.end())
|
||||
{
|
||||
if (it->second->getLastAction () > now)
|
||||
if (it->second->getLastAction() > now)
|
||||
{
|
||||
it->second->touch ();
|
||||
it->second->touch();
|
||||
++it;
|
||||
}
|
||||
else if ((it->second->getLastAction () +
|
||||
std::chrono::minutes (1)) < now)
|
||||
else if (
|
||||
(it->second->getLastAction() + std::chrono::minutes(1)) <
|
||||
now)
|
||||
{
|
||||
stuffToSweep.push_back (it->second);
|
||||
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);
|
||||
it = mLedgers.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -402,18 +422,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
beast::expire (mRecentFailures, kReacquireInterval);
|
||||
|
||||
beast::expire(mRecentFailures, kReacquireInterval);
|
||||
}
|
||||
|
||||
JLOG (j_.debug()) <<
|
||||
"Swept " << stuffToSweep.size () <<
|
||||
" out of " << total << " inbound ledgers.";
|
||||
JLOG(j_.debug()) << "Swept " << stuffToSweep.size() << " out of "
|
||||
<< total << " inbound ledgers.";
|
||||
}
|
||||
|
||||
void onStop () override
|
||||
void
|
||||
onStop() override
|
||||
{
|
||||
ScopedLockType lock (mLock);
|
||||
ScopedLockType lock(mLock);
|
||||
|
||||
mLedgers.clear();
|
||||
mRecentFailures.clear();
|
||||
@@ -424,13 +443,13 @@ public:
|
||||
private:
|
||||
clock_type& m_clock;
|
||||
|
||||
using ScopedLockType = std::unique_lock <std::recursive_mutex>;
|
||||
using ScopedLockType = std::unique_lock<std::recursive_mutex>;
|
||||
std::recursive_mutex mLock;
|
||||
|
||||
using MapType = hash_map <uint256, std::shared_ptr<InboundLedger>>;
|
||||
using MapType = hash_map<uint256, std::shared_ptr<InboundLedger>>;
|
||||
MapType mLedgers;
|
||||
|
||||
beast::aged_map <uint256, std::uint32_t> mRecentFailures;
|
||||
beast::aged_map<uint256, std::uint32_t> mRecentFailures;
|
||||
|
||||
beast::insight::Counter mCounter;
|
||||
};
|
||||
@@ -438,16 +457,18 @@ private:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
decltype(InboundLedgersImp::kReacquireInterval)
|
||||
InboundLedgersImp::kReacquireInterval{5};
|
||||
InboundLedgersImp::kReacquireInterval{5};
|
||||
|
||||
InboundLedgers::~InboundLedgers() = default;
|
||||
|
||||
std::unique_ptr<InboundLedgers>
|
||||
make_InboundLedgers (Application& app,
|
||||
InboundLedgers::clock_type& clock, Stoppable& parent,
|
||||
make_InboundLedgers(
|
||||
Application& app,
|
||||
InboundLedgers::clock_type& clock,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
{
|
||||
return std::make_unique<InboundLedgersImp> (app, clock, parent, collector);
|
||||
return std::make_unique<InboundLedgersImp>(app, clock, parent, collector);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/InboundTransactions.h>
|
||||
#include <ripple/app/ledger/InboundLedgers.h>
|
||||
#include <ripple/app/ledger/InboundTransactions.h>
|
||||
#include <ripple/app/ledger/impl/TransactionAcquire.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
@@ -31,8 +31,7 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
// Ideal number of peers to start with
|
||||
startPeers = 2,
|
||||
|
||||
@@ -42,152 +41,155 @@ enum
|
||||
|
||||
class InboundTransactionSet
|
||||
{
|
||||
// A transaction set we generated, acquired, or are acquiring
|
||||
// A transaction set we generated, acquired, or are acquiring
|
||||
public:
|
||||
std::uint32_t mSeq;
|
||||
std::uint32_t mSeq;
|
||||
TransactionAcquire::pointer mAcquire;
|
||||
std::shared_ptr <SHAMap> mSet;
|
||||
std::shared_ptr<SHAMap> mSet;
|
||||
|
||||
InboundTransactionSet (
|
||||
std::uint32_t seq,
|
||||
std::shared_ptr <SHAMap> const& set) :
|
||||
mSeq (seq), mSet (set)
|
||||
{ ; }
|
||||
InboundTransactionSet () : mSeq (0)
|
||||
{ ; }
|
||||
InboundTransactionSet(std::uint32_t seq, std::shared_ptr<SHAMap> const& set)
|
||||
: mSeq(seq), mSet(set)
|
||||
{
|
||||
;
|
||||
}
|
||||
InboundTransactionSet() : mSeq(0)
|
||||
{
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
class InboundTransactionsImp
|
||||
: public InboundTransactions
|
||||
, public Stoppable
|
||||
class InboundTransactionsImp : public InboundTransactions, public Stoppable
|
||||
{
|
||||
public:
|
||||
Application& app_;
|
||||
|
||||
InboundTransactionsImp (
|
||||
Application& app,
|
||||
clock_type& clock,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
std::function <void (std::shared_ptr <SHAMap> const&,
|
||||
bool)> gotSet)
|
||||
: Stoppable ("InboundTransactions", parent)
|
||||
, app_ (app)
|
||||
, m_clock (clock)
|
||||
, m_seq (0)
|
||||
, m_zeroSet (m_map[uint256()])
|
||||
, m_gotSet (std::move (gotSet))
|
||||
InboundTransactionsImp(
|
||||
Application& app,
|
||||
clock_type& clock,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
std::function<void(std::shared_ptr<SHAMap> const&, bool)> gotSet)
|
||||
: Stoppable("InboundTransactions", parent)
|
||||
, app_(app)
|
||||
, m_clock(clock)
|
||||
, m_seq(0)
|
||||
, m_zeroSet(m_map[uint256()])
|
||||
, m_gotSet(std::move(gotSet))
|
||||
{
|
||||
m_zeroSet.mSet = std::make_shared<SHAMap> (
|
||||
SHAMapType::TRANSACTION, uint256(),
|
||||
app_.family());
|
||||
m_zeroSet.mSet = std::make_shared<SHAMap>(
|
||||
SHAMapType::TRANSACTION, uint256(), app_.family());
|
||||
m_zeroSet.mSet->setUnbacked();
|
||||
}
|
||||
|
||||
TransactionAcquire::pointer getAcquire (uint256 const& hash)
|
||||
TransactionAcquire::pointer
|
||||
getAcquire(uint256 const& hash)
|
||||
{
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
auto it = m_map.find (hash);
|
||||
auto it = m_map.find(hash);
|
||||
|
||||
if (it != m_map.end ())
|
||||
if (it != m_map.end())
|
||||
return it->second.mAcquire;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_ptr <SHAMap> getSet (
|
||||
uint256 const& hash,
|
||||
bool acquire) override
|
||||
std::shared_ptr<SHAMap>
|
||||
getSet(uint256 const& hash, bool acquire) override
|
||||
{
|
||||
TransactionAcquire::pointer ta;
|
||||
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
auto it = m_map.find (hash);
|
||||
auto it = m_map.find(hash);
|
||||
|
||||
if (it != m_map.end ())
|
||||
if (it != m_map.end())
|
||||
{
|
||||
if (acquire)
|
||||
{
|
||||
it->second.mSeq = m_seq;
|
||||
if (it->second.mAcquire)
|
||||
{
|
||||
it->second.mAcquire->stillNeed ();
|
||||
it->second.mAcquire->stillNeed();
|
||||
}
|
||||
}
|
||||
return it->second.mSet;
|
||||
}
|
||||
|
||||
if (!acquire || isStopping ())
|
||||
return std::shared_ptr <SHAMap> ();
|
||||
if (!acquire || isStopping())
|
||||
return std::shared_ptr<SHAMap>();
|
||||
|
||||
ta = std::make_shared <TransactionAcquire> (app_, hash, m_clock);
|
||||
ta = std::make_shared<TransactionAcquire>(app_, hash, m_clock);
|
||||
|
||||
auto &obj = m_map[hash];
|
||||
auto& obj = m_map[hash];
|
||||
obj.mAcquire = ta;
|
||||
obj.mSeq = m_seq;
|
||||
}
|
||||
|
||||
|
||||
ta->init (startPeers);
|
||||
ta->init(startPeers);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/** We received a TMLedgerData from a peer.
|
||||
*/
|
||||
void gotData (LedgerHash const& hash,
|
||||
std::shared_ptr<Peer> peer,
|
||||
std::shared_ptr<protocol::TMLedgerData> packet_ptr) override
|
||||
*/
|
||||
void
|
||||
gotData(
|
||||
LedgerHash const& hash,
|
||||
std::shared_ptr<Peer> peer,
|
||||
std::shared_ptr<protocol::TMLedgerData> packet_ptr) override
|
||||
{
|
||||
protocol::TMLedgerData& packet = *packet_ptr;
|
||||
|
||||
JLOG (app_.journal("InboundLedger").trace()) <<
|
||||
"Got data (" << packet.nodes ().size () << ") "
|
||||
"for acquiring ledger: " << hash;
|
||||
JLOG(app_.journal("InboundLedger").trace())
|
||||
<< "Got data (" << packet.nodes().size()
|
||||
<< ") "
|
||||
"for acquiring ledger: "
|
||||
<< hash;
|
||||
|
||||
TransactionAcquire::pointer ta = getAcquire (hash);
|
||||
TransactionAcquire::pointer ta = getAcquire(hash);
|
||||
|
||||
if (ta == nullptr)
|
||||
{
|
||||
peer->charge (Resource::feeUnwantedData);
|
||||
peer->charge(Resource::feeUnwantedData);
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<SHAMapNodeID> nodeIDs;
|
||||
std::list< Blob > nodeData;
|
||||
for (auto const &node : packet.nodes())
|
||||
std::list<Blob> nodeData;
|
||||
for (auto const& node : packet.nodes())
|
||||
{
|
||||
if (!node.has_nodeid () || !node.has_nodedata () || (
|
||||
node.nodeid ().size () != 33))
|
||||
if (!node.has_nodeid() || !node.has_nodedata() ||
|
||||
(node.nodeid().size() != 33))
|
||||
{
|
||||
peer->charge (Resource::feeInvalidRequest);
|
||||
peer->charge(Resource::feeInvalidRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
nodeIDs.emplace_back (node.nodeid ().data (),
|
||||
static_cast<int>(node.nodeid ().size ()));
|
||||
nodeData.emplace_back (node.nodedata ().begin (),
|
||||
node.nodedata ().end ());
|
||||
nodeIDs.emplace_back(
|
||||
node.nodeid().data(), static_cast<int>(node.nodeid().size()));
|
||||
nodeData.emplace_back(
|
||||
node.nodedata().begin(), node.nodedata().end());
|
||||
}
|
||||
|
||||
if (! ta->takeNodes (nodeIDs, nodeData, peer).isUseful ())
|
||||
peer->charge (Resource::feeUnwantedData);
|
||||
if (!ta->takeNodes(nodeIDs, nodeData, peer).isUseful())
|
||||
peer->charge(Resource::feeUnwantedData);
|
||||
}
|
||||
|
||||
void giveSet (uint256 const& hash,
|
||||
std::shared_ptr <SHAMap> const& set,
|
||||
void
|
||||
giveSet(
|
||||
uint256 const& hash,
|
||||
std::shared_ptr<SHAMap> const& set,
|
||||
bool fromAcquire) override
|
||||
{
|
||||
bool isNew = true;
|
||||
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
auto& inboundSet = m_map [hash];
|
||||
auto& inboundSet = m_map[hash];
|
||||
|
||||
if (inboundSet.mSeq < m_seq)
|
||||
inboundSet.mSeq = m_seq;
|
||||
@@ -197,28 +199,28 @@ public:
|
||||
else
|
||||
inboundSet.mSet = set;
|
||||
|
||||
inboundSet.mAcquire.reset ();
|
||||
|
||||
inboundSet.mAcquire.reset();
|
||||
}
|
||||
|
||||
if (isNew)
|
||||
m_gotSet (set, fromAcquire);
|
||||
m_gotSet(set, fromAcquire);
|
||||
}
|
||||
|
||||
Json::Value getInfo() override
|
||||
Json::Value
|
||||
getInfo() override
|
||||
{
|
||||
Json::Value ret (Json::objectValue);
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
Json::Value& sets = (ret["sets"] = Json::arrayValue);
|
||||
|
||||
{
|
||||
std::lock_guard sl (mLock);
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
ret["seq"] = m_seq;
|
||||
|
||||
for (auto const& it : m_map)
|
||||
{
|
||||
Json::Value& set = sets [to_string (it.first)];
|
||||
Json::Value& set = sets[to_string(it.first)];
|
||||
set["seq"] = it.second.mSeq;
|
||||
if (it.second.mSet)
|
||||
set["state"] = "complete";
|
||||
@@ -227,45 +229,45 @@ public:
|
||||
else
|
||||
set["state"] = "dead";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void newRound (std::uint32_t seq) override
|
||||
void
|
||||
newRound(std::uint32_t seq) override
|
||||
{
|
||||
std::lock_guard lock (mLock);
|
||||
std::lock_guard lock(mLock);
|
||||
|
||||
// Protect zero set from expiration
|
||||
m_zeroSet.mSeq = seq;
|
||||
|
||||
if (m_seq != seq)
|
||||
{
|
||||
|
||||
m_seq = seq;
|
||||
|
||||
auto it = m_map.begin ();
|
||||
auto it = m_map.begin();
|
||||
|
||||
std::uint32_t const minSeq =
|
||||
(seq < setKeepRounds) ? 0 : (seq - setKeepRounds);
|
||||
std::uint32_t maxSeq = seq + setKeepRounds;
|
||||
|
||||
while (it != m_map.end ())
|
||||
while (it != m_map.end())
|
||||
{
|
||||
if (it->second.mSeq < minSeq || it->second.mSeq > maxSeq)
|
||||
it = m_map.erase (it);
|
||||
it = m_map.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onStop () override
|
||||
void
|
||||
onStop() override
|
||||
{
|
||||
std::lock_guard lock (mLock);
|
||||
std::lock_guard lock(mLock);
|
||||
|
||||
m_map.clear ();
|
||||
m_map.clear();
|
||||
|
||||
stopped();
|
||||
}
|
||||
@@ -273,7 +275,7 @@ public:
|
||||
private:
|
||||
clock_type& m_clock;
|
||||
|
||||
using MapType = hash_map <uint256, InboundTransactionSet>;
|
||||
using MapType = hash_map<uint256, InboundTransactionSet>;
|
||||
|
||||
std::recursive_mutex mLock;
|
||||
|
||||
@@ -283,24 +285,23 @@ private:
|
||||
// The empty transaction set whose hash is zero
|
||||
InboundTransactionSet& m_zeroSet;
|
||||
|
||||
std::function <void (std::shared_ptr <SHAMap> const&, bool)> m_gotSet;
|
||||
std::function<void(std::shared_ptr<SHAMap> const&, bool)> m_gotSet;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
InboundTransactions::~InboundTransactions() = default;
|
||||
|
||||
std::unique_ptr <InboundTransactions>
|
||||
make_InboundTransactions (
|
||||
std::unique_ptr<InboundTransactions>
|
||||
make_InboundTransactions(
|
||||
Application& app,
|
||||
InboundLedgers::clock_type& clock,
|
||||
Stoppable& parent,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
std::function <void (std::shared_ptr <SHAMap> const&,
|
||||
bool)> gotSet)
|
||||
std::function<void(std::shared_ptr<SHAMap> const&, bool)> gotSet)
|
||||
{
|
||||
return std::make_unique <InboundTransactionsImp>
|
||||
(app, clock, parent, collector, std::move (gotSet));
|
||||
return std::make_unique<InboundTransactionsImp>(
|
||||
app, clock, parent, collector, std::move(gotSet));
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/LedgerCleaner.h>
|
||||
#include <ripple/app/ledger/InboundLedgers.h>
|
||||
#include <ripple/app/ledger/LedgerCleaner.h>
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/beast/core/CurrentThreadName.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
@@ -51,19 +51,15 @@ class LedgerCleanerImp : public LedgerCleaner
|
||||
|
||||
std::thread thread_;
|
||||
|
||||
enum class State : char {
|
||||
readyToClean = 0,
|
||||
startCleaning,
|
||||
cleaning
|
||||
};
|
||||
enum class State : char { readyToClean = 0, startCleaning, cleaning };
|
||||
State state_ = State::readyToClean;
|
||||
bool shouldExit_ = false;
|
||||
|
||||
// The lowest ledger in the range we're checking.
|
||||
LedgerIndex minRange_ = 0;
|
||||
LedgerIndex minRange_ = 0;
|
||||
|
||||
// The highest ledger in the range we're checking
|
||||
LedgerIndex maxRange_ = 0;
|
||||
LedgerIndex maxRange_ = 0;
|
||||
|
||||
// Check all state/transaction nodes
|
||||
bool checkNodes_ = false;
|
||||
@@ -76,20 +72,18 @@ class LedgerCleanerImp : public LedgerCleaner
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
public:
|
||||
LedgerCleanerImp (
|
||||
LedgerCleanerImp(
|
||||
Application& app,
|
||||
Stoppable& stoppable,
|
||||
beast::Journal journal)
|
||||
: LedgerCleaner (stoppable)
|
||||
, app_ (app)
|
||||
, j_ (journal)
|
||||
: LedgerCleaner(stoppable), app_(app), j_(journal)
|
||||
{
|
||||
}
|
||||
|
||||
~LedgerCleanerImp () override
|
||||
~LedgerCleanerImp() override
|
||||
{
|
||||
if (thread_.joinable())
|
||||
LogicError ("LedgerCleanerImp::onStop not called.");
|
||||
LogicError("LedgerCleanerImp::onStop not called.");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -98,20 +92,23 @@ public:
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void onPrepare () override
|
||||
void
|
||||
onPrepare() override
|
||||
{
|
||||
}
|
||||
|
||||
void onStart () override
|
||||
void
|
||||
onStart() override
|
||||
{
|
||||
thread_ = std::thread {&LedgerCleanerImp::run, this};
|
||||
thread_ = std::thread{&LedgerCleanerImp::run, this};
|
||||
}
|
||||
|
||||
void onStop () override
|
||||
void
|
||||
onStop() override
|
||||
{
|
||||
JLOG (j_.info()) << "Stopping";
|
||||
JLOG(j_.info()) << "Stopping";
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
shouldExit_ = true;
|
||||
wakeup_.notify_one();
|
||||
}
|
||||
@@ -124,9 +121,10 @@ public:
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void onWrite (beast::PropertyStream::Map& map) override
|
||||
void
|
||||
onWrite(beast::PropertyStream::Map& map) override
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
if (maxRange_ == 0)
|
||||
map["status"] = "idle";
|
||||
@@ -148,14 +146,15 @@ public:
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void doClean (Json::Value const& params) override
|
||||
void
|
||||
doClean(Json::Value const& params) override
|
||||
{
|
||||
LedgerIndex minRange = 0;
|
||||
LedgerIndex maxRange = 0;
|
||||
app_.getLedgerMaster().getFullValidatedRange (minRange, maxRange);
|
||||
app_.getLedgerMaster().getFullValidatedRange(minRange, maxRange);
|
||||
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
maxRange_ = maxRange;
|
||||
minRange_ = minRange;
|
||||
@@ -203,7 +202,7 @@ public:
|
||||
}
|
||||
|
||||
if (params.isMember(jss::max_ledger))
|
||||
maxRange_ = params[jss::max_ledger].asUInt();
|
||||
maxRange_ = params[jss::max_ledger].asUInt();
|
||||
|
||||
if (params.isMember(jss::min_ledger))
|
||||
minRange_ = params[jss::min_ledger].asUInt();
|
||||
@@ -234,28 +233,27 @@ public:
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
private:
|
||||
void init ()
|
||||
void
|
||||
init()
|
||||
{
|
||||
JLOG (j_.debug()) << "Initializing";
|
||||
JLOG(j_.debug()) << "Initializing";
|
||||
}
|
||||
|
||||
void run ()
|
||||
void
|
||||
run()
|
||||
{
|
||||
beast::setCurrentThreadName ("LedgerCleaner");
|
||||
JLOG (j_.debug()) << "Started";
|
||||
beast::setCurrentThreadName("LedgerCleaner");
|
||||
JLOG(j_.debug()) << "Started";
|
||||
|
||||
init();
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (mutex_);
|
||||
wakeup_.wait(lock, [this]()
|
||||
{
|
||||
return (
|
||||
shouldExit_ ||
|
||||
state_ == State::startCleaning);
|
||||
});
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
wakeup_.wait(lock, [this]() {
|
||||
return (shouldExit_ || state_ == State::startCleaning);
|
||||
});
|
||||
if (shouldExit_)
|
||||
break;
|
||||
|
||||
@@ -268,9 +266,8 @@ private:
|
||||
}
|
||||
|
||||
// VFALCO TODO This should return boost::optional<uint256>
|
||||
LedgerHash getLedgerHash(
|
||||
std::shared_ptr<ReadView const>& ledger,
|
||||
LedgerIndex index)
|
||||
LedgerHash
|
||||
getLedgerHash(std::shared_ptr<ReadView const>& ledger, LedgerIndex index)
|
||||
{
|
||||
boost::optional<LedgerHash> hash;
|
||||
try
|
||||
@@ -279,13 +276,14 @@ private:
|
||||
}
|
||||
catch (SHAMapMissingNode const& mn)
|
||||
{
|
||||
JLOG (j_.warn()) <<
|
||||
"Ledger #" << ledger->info().seq << ": " << mn.what();
|
||||
app_.getInboundLedgers().acquire (
|
||||
ledger->info().hash, ledger->info().seq,
|
||||
JLOG(j_.warn())
|
||||
<< "Ledger #" << ledger->info().seq << ": " << mn.what();
|
||||
app_.getInboundLedgers().acquire(
|
||||
ledger->info().hash,
|
||||
ledger->info().seq,
|
||||
InboundLedger::Reason::GENERIC);
|
||||
}
|
||||
return hash ? *hash : beast::zero; // kludge
|
||||
return hash ? *hash : beast::zero; // kludge
|
||||
}
|
||||
|
||||
/** Process a single ledger
|
||||
@@ -295,45 +293,45 @@ private:
|
||||
@param doTxns Reprocess (account) transactions to SQL databases.
|
||||
@return `true` if the ledger was cleaned.
|
||||
*/
|
||||
bool doLedger(
|
||||
bool
|
||||
doLedger(
|
||||
LedgerIndex const& ledgerIndex,
|
||||
LedgerHash const& ledgerHash,
|
||||
bool doNodes,
|
||||
bool doTxns)
|
||||
{
|
||||
auto nodeLedger = app_.getInboundLedgers().acquire (
|
||||
auto nodeLedger = app_.getInboundLedgers().acquire(
|
||||
ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
|
||||
if (!nodeLedger)
|
||||
{
|
||||
JLOG (j_.debug()) << "Ledger " << ledgerIndex << " not available";
|
||||
app_.getLedgerMaster().clearLedger (ledgerIndex);
|
||||
JLOG(j_.debug()) << "Ledger " << ledgerIndex << " not available";
|
||||
app_.getLedgerMaster().clearLedger(ledgerIndex);
|
||||
app_.getInboundLedgers().acquire(
|
||||
ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto dbLedger = loadByIndex(ledgerIndex, app_);
|
||||
if (! dbLedger ||
|
||||
(dbLedger->info().hash != ledgerHash) ||
|
||||
if (!dbLedger || (dbLedger->info().hash != ledgerHash) ||
|
||||
(dbLedger->info().parentHash != nodeLedger->info().parentHash))
|
||||
{
|
||||
// Ideally we'd also check for more than one ledger with that index
|
||||
JLOG (j_.debug()) <<
|
||||
"Ledger " << ledgerIndex << " mismatches SQL DB";
|
||||
JLOG(j_.debug())
|
||||
<< "Ledger " << ledgerIndex << " mismatches SQL DB";
|
||||
doTxns = true;
|
||||
}
|
||||
|
||||
if(! app_.getLedgerMaster().fixIndex(ledgerIndex, ledgerHash))
|
||||
if (!app_.getLedgerMaster().fixIndex(ledgerIndex, ledgerHash))
|
||||
{
|
||||
JLOG (j_.debug()) << "ledger " << ledgerIndex
|
||||
<< " had wrong entry in history";
|
||||
JLOG(j_.debug())
|
||||
<< "ledger " << ledgerIndex << " had wrong entry in history";
|
||||
doTxns = true;
|
||||
}
|
||||
|
||||
if (doNodes && !nodeLedger->walkLedger(app_.journal ("Ledger")))
|
||||
if (doNodes && !nodeLedger->walkLedger(app_.journal("Ledger")))
|
||||
{
|
||||
JLOG (j_.debug()) << "Ledger " << ledgerIndex << " is missing nodes";
|
||||
app_.getLedgerMaster().clearLedger (ledgerIndex);
|
||||
JLOG(j_.debug()) << "Ledger " << ledgerIndex << " is missing nodes";
|
||||
app_.getLedgerMaster().clearLedger(ledgerIndex);
|
||||
app_.getInboundLedgers().acquire(
|
||||
ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
|
||||
return false;
|
||||
@@ -341,7 +339,7 @@ private:
|
||||
|
||||
if (doTxns && !pendSaveValidated(app_, nodeLedger, true, false))
|
||||
{
|
||||
JLOG (j_.debug()) << "Failed to save ledger " << ledgerIndex;
|
||||
JLOG(j_.debug()) << "Failed to save ledger " << ledgerIndex;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -353,7 +351,8 @@ private:
|
||||
@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(
|
||||
LedgerHash
|
||||
getHash(
|
||||
LedgerIndex const& ledgerIndex,
|
||||
std::shared_ptr<ReadView const>& referenceLedger)
|
||||
{
|
||||
@@ -364,8 +363,8 @@ private:
|
||||
referenceLedger = app_.getLedgerMaster().getValidatedLedger();
|
||||
if (!referenceLedger)
|
||||
{
|
||||
JLOG (j_.warn()) << "No validated ledger";
|
||||
return ledgerHash; // Nothing we can do. No validated ledger.
|
||||
JLOG(j_.warn()) << "No validated ledger";
|
||||
return ledgerHash; // Nothing we can do. No validated ledger.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,42 +377,41 @@ private:
|
||||
// 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 = getCandidateLedger (ledgerIndex);
|
||||
LedgerHash refHash = getLedgerHash (referenceLedger, refIndex);
|
||||
LedgerIndex refIndex = getCandidateLedger(ledgerIndex);
|
||||
LedgerHash refHash = getLedgerHash(referenceLedger, refIndex);
|
||||
|
||||
bool const nonzero (refHash.isNonZero ());
|
||||
assert (nonzero);
|
||||
bool const nonzero(refHash.isNonZero());
|
||||
assert(nonzero);
|
||||
if (nonzero)
|
||||
{
|
||||
// We found the hash and sequence of a better reference
|
||||
// ledger.
|
||||
referenceLedger =
|
||||
app_.getInboundLedgers().acquire(
|
||||
refHash, refIndex, InboundLedger::Reason::GENERIC);
|
||||
referenceLedger = app_.getInboundLedgers().acquire(
|
||||
refHash, refIndex, InboundLedger::Reason::GENERIC);
|
||||
if (referenceLedger)
|
||||
ledgerHash = getLedgerHash(
|
||||
referenceLedger, ledgerIndex);
|
||||
ledgerHash =
|
||||
getLedgerHash(referenceLedger, ledgerIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
JLOG (j_.warn()) << "Validated ledger is prior to target ledger";
|
||||
JLOG(j_.warn()) << "Validated ledger is prior to target ledger";
|
||||
|
||||
return ledgerHash;
|
||||
}
|
||||
|
||||
/** Run the ledger cleaner. */
|
||||
void doLedgerCleaner()
|
||||
void
|
||||
doLedgerCleaner()
|
||||
{
|
||||
auto shouldExit = [this]()
|
||||
{
|
||||
auto shouldExit = [this]() {
|
||||
std::lock_guard lock(mutex_);
|
||||
return shouldExit_;
|
||||
};
|
||||
|
||||
std::shared_ptr<ReadView const> goodLedger;
|
||||
|
||||
while (! shouldExit())
|
||||
while (!shouldExit())
|
||||
{
|
||||
LedgerIndex ledgerIndex;
|
||||
LedgerHash ledgerHash;
|
||||
@@ -422,16 +420,16 @@ private:
|
||||
|
||||
while (app_.getFeeTrack().isLoadedLocal())
|
||||
{
|
||||
JLOG (j_.debug()) << "Waiting for load to subside";
|
||||
JLOG(j_.debug()) << "Waiting for load to subside";
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
if (shouldExit())
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
if ((minRange_ > maxRange_) ||
|
||||
(maxRange_ == 0) || (minRange_ == 0))
|
||||
std::lock_guard lock(mutex_);
|
||||
if ((minRange_ > maxRange_) || (maxRange_ == 0) ||
|
||||
(minRange_ == 0))
|
||||
{
|
||||
minRange_ = maxRange_ = 0;
|
||||
state_ = State::readyToClean;
|
||||
@@ -447,20 +445,20 @@ private:
|
||||
bool fail = false;
|
||||
if (ledgerHash.isZero())
|
||||
{
|
||||
JLOG (j_.info()) << "Unable to get hash for ledger "
|
||||
<< ledgerIndex;
|
||||
JLOG(j_.info())
|
||||
<< "Unable to get hash for ledger " << ledgerIndex;
|
||||
fail = true;
|
||||
}
|
||||
else if (!doLedger(ledgerIndex, ledgerHash, doNodes, doTxns))
|
||||
{
|
||||
JLOG (j_.info()) << "Failed to process ledger " << ledgerIndex;
|
||||
JLOG(j_.info()) << "Failed to process ledger " << ledgerIndex;
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (fail)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
++failures_;
|
||||
}
|
||||
// Wait for acquiring to catch up to us
|
||||
@@ -469,7 +467,7 @@ private:
|
||||
else
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
if (ledgerIndex == minRange_)
|
||||
++minRange_;
|
||||
if (ledgerIndex == maxRange_)
|
||||
@@ -479,27 +477,25 @@ private:
|
||||
// Reduce I/O pressure and wait for acquiring to catch up to us
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
LedgerCleaner::LedgerCleaner (Stoppable& parent)
|
||||
: Stoppable ("LedgerCleaner", parent)
|
||||
, beast::PropertyStream::Source ("ledgercleaner")
|
||||
LedgerCleaner::LedgerCleaner(Stoppable& parent)
|
||||
: Stoppable("LedgerCleaner", parent)
|
||||
, beast::PropertyStream::Source("ledgercleaner")
|
||||
{
|
||||
}
|
||||
|
||||
LedgerCleaner::~LedgerCleaner() = default;
|
||||
|
||||
std::unique_ptr<LedgerCleaner>
|
||||
make_LedgerCleaner (Application& app,
|
||||
Stoppable& parent, beast::Journal journal)
|
||||
make_LedgerCleaner(Application& app, Stoppable& parent, beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<LedgerCleanerImp>(app, parent, journal);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ripple
|
||||
} // namespace detail
|
||||
} // namespace ripple
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,74 +29,80 @@ namespace ripple {
|
||||
|
||||
namespace {
|
||||
|
||||
bool isFull(LedgerFill const& fill)
|
||||
bool
|
||||
isFull(LedgerFill const& fill)
|
||||
{
|
||||
return fill.options & LedgerFill::full;
|
||||
}
|
||||
|
||||
bool isExpanded(LedgerFill const& fill)
|
||||
bool
|
||||
isExpanded(LedgerFill const& fill)
|
||||
{
|
||||
return isFull(fill) || (fill.options & LedgerFill::expand);
|
||||
}
|
||||
|
||||
bool isBinary(LedgerFill const& fill)
|
||||
bool
|
||||
isBinary(LedgerFill const& fill)
|
||||
{
|
||||
return fill.options & LedgerFill::binary;
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
void fillJson(Object& json, bool closed, LedgerInfo const& info, bool bFull)
|
||||
void
|
||||
fillJson(Object& json, bool closed, LedgerInfo const& info, bool bFull)
|
||||
{
|
||||
json[jss::parent_hash] = to_string (info.parentHash);
|
||||
json[jss::ledger_index] = to_string (info.seq);
|
||||
json[jss::seqNum] = to_string (info.seq); // DEPRECATED
|
||||
json[jss::parent_hash] = to_string(info.parentHash);
|
||||
json[jss::ledger_index] = to_string(info.seq);
|
||||
json[jss::seqNum] = to_string(info.seq); // DEPRECATED
|
||||
|
||||
if (closed)
|
||||
{
|
||||
json[jss::closed] = true;
|
||||
}
|
||||
else if (! bFull)
|
||||
else if (!bFull)
|
||||
{
|
||||
json[jss::closed] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
json[jss::ledger_hash] = to_string (info.hash);
|
||||
json[jss::transaction_hash] = to_string (info.txHash);
|
||||
json[jss::account_hash] = to_string (info.accountHash);
|
||||
json[jss::total_coins] = to_string (info.drops);
|
||||
json[jss::ledger_hash] = to_string(info.hash);
|
||||
json[jss::transaction_hash] = to_string(info.txHash);
|
||||
json[jss::account_hash] = to_string(info.accountHash);
|
||||
json[jss::total_coins] = to_string(info.drops);
|
||||
|
||||
// These next three are DEPRECATED.
|
||||
json[jss::hash] = to_string (info.hash);
|
||||
json[jss::totalCoins] = to_string (info.drops);
|
||||
json[jss::hash] = to_string(info.hash);
|
||||
json[jss::totalCoins] = to_string(info.drops);
|
||||
json[jss::accepted] = closed;
|
||||
json[jss::close_flags] = info.closeFlags;
|
||||
|
||||
// Always show fields that contribute to the ledger hash
|
||||
json[jss::parent_close_time] = info.parentCloseTime.time_since_epoch().count();
|
||||
json[jss::parent_close_time] =
|
||||
info.parentCloseTime.time_since_epoch().count();
|
||||
json[jss::close_time] = info.closeTime.time_since_epoch().count();
|
||||
json[jss::close_time_resolution] = info.closeTimeResolution.count();
|
||||
|
||||
if (info.closeTime != NetClock::time_point{})
|
||||
{
|
||||
json[jss::close_time_human] = to_string(info.closeTime);
|
||||
if (! getCloseAgree(info))
|
||||
if (!getCloseAgree(info))
|
||||
json[jss::close_time_estimated] = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
void fillJsonBinary(Object& json, bool closed, LedgerInfo const& info)
|
||||
void
|
||||
fillJsonBinary(Object& json, bool closed, LedgerInfo const& info)
|
||||
{
|
||||
if (! closed)
|
||||
if (!closed)
|
||||
json[jss::closed] = false;
|
||||
else
|
||||
{
|
||||
json[jss::closed] = true;
|
||||
|
||||
Serializer s;
|
||||
addRaw (info, s);
|
||||
json[jss::ledger_data] = strHex (s.peekData ());
|
||||
addRaw(info, s);
|
||||
json[jss::ledger_data] = strHex(s.peekData());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,17 +166,19 @@ fillJsonTx(
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
void fillJsonTx (Object& json, LedgerFill const& fill)
|
||||
void
|
||||
fillJsonTx(Object& json, LedgerFill const& fill)
|
||||
{
|
||||
auto&& txns = setArray (json, jss::transactions);
|
||||
auto&& txns = setArray(json, jss::transactions);
|
||||
auto bBinary = isBinary(fill);
|
||||
auto bExpanded = isExpanded(fill);
|
||||
|
||||
try
|
||||
{
|
||||
for (auto& i: fill.ledger.txs)
|
||||
for (auto& i : fill.ledger.txs)
|
||||
{
|
||||
txns.append(fillJsonTx(fill, bBinary, bExpanded, i.first, i.second));
|
||||
txns.append(
|
||||
fillJsonTx(fill, bBinary, bExpanded, i.first, i.second));
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
@@ -180,16 +188,17 @@ void fillJsonTx (Object& json, LedgerFill const& fill)
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
void fillJsonState(Object& json, LedgerFill const& fill)
|
||||
void
|
||||
fillJsonState(Object& json, LedgerFill const& fill)
|
||||
{
|
||||
auto& ledger = fill.ledger;
|
||||
auto&& array = Json::setArray (json, jss::accountState);
|
||||
auto&& array = Json::setArray(json, jss::accountState);
|
||||
auto expanded = isExpanded(fill);
|
||||
auto binary = isBinary(fill);
|
||||
|
||||
for(auto const& sle : ledger.sles)
|
||||
for (auto const& sle : ledger.sles)
|
||||
{
|
||||
if (fill.type == ltINVALID || sle->getType () == fill.type)
|
||||
if (fill.type == ltINVALID || sle->getType() == fill.type)
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
@@ -206,7 +215,8 @@ void fillJsonState(Object& json, LedgerFill const& fill)
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
void fillJsonQueue(Object& json, LedgerFill const& fill)
|
||||
void
|
||||
fillJsonQueue(Object& json, LedgerFill const& fill)
|
||||
{
|
||||
auto&& queueData = Json::setArray(json, jss::queue_data);
|
||||
auto bBinary = isBinary(fill);
|
||||
@@ -220,13 +230,11 @@ void fillJsonQueue(Object& json, LedgerFill const& fill)
|
||||
txJson[jss::LastLedgerSequence] = *tx.lastValid;
|
||||
if (tx.consequences)
|
||||
{
|
||||
txJson[jss::fee] = to_string(
|
||||
tx.consequences->fee);
|
||||
auto spend = tx.consequences->potentialSpend +
|
||||
tx.consequences->fee;
|
||||
txJson[jss::fee] = to_string(tx.consequences->fee);
|
||||
auto spend = tx.consequences->potentialSpend + tx.consequences->fee;
|
||||
txJson[jss::max_spend_drops] = to_string(spend);
|
||||
auto authChanged = tx.consequences->category ==
|
||||
TxConsequences::blocker;
|
||||
auto authChanged =
|
||||
tx.consequences->category == TxConsequences::blocker;
|
||||
txJson[jss::auth_change] = authChanged;
|
||||
}
|
||||
|
||||
@@ -241,15 +249,16 @@ void fillJsonQueue(Object& json, LedgerFill const& fill)
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
void fillJson (Object& json, LedgerFill const& fill)
|
||||
void
|
||||
fillJson(Object& json, LedgerFill const& fill)
|
||||
{
|
||||
// TODO: what happens if bBinary and bExtracted are both set?
|
||||
// Is there a way to report this back?
|
||||
auto bFull = isFull(fill);
|
||||
if (isBinary(fill))
|
||||
fillJsonBinary(json, ! fill.ledger.open(), fill.ledger.info());
|
||||
fillJsonBinary(json, !fill.ledger.open(), fill.ledger.info());
|
||||
else
|
||||
fillJson(json, ! fill.ledger.open(), fill.ledger.info(), bFull);
|
||||
fillJson(json, !fill.ledger.open(), fill.ledger.info(), bFull);
|
||||
|
||||
if (bFull || fill.options & LedgerFill::dumpTxrp)
|
||||
fillJsonTx(json, fill);
|
||||
@@ -258,22 +267,24 @@ void fillJson (Object& json, LedgerFill const& fill)
|
||||
fillJsonState(json, fill);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
void addJson (Json::Value& json, LedgerFill const& fill)
|
||||
void
|
||||
addJson(Json::Value& json, LedgerFill const& fill)
|
||||
{
|
||||
auto&& object = Json::addObject (json, jss::ledger);
|
||||
fillJson (object, fill);
|
||||
auto&& object = Json::addObject(json, jss::ledger);
|
||||
fillJson(object, fill);
|
||||
|
||||
if ((fill.options & LedgerFill::dumpQueue) && !fill.txQueue.empty())
|
||||
fillJsonQueue(json, fill);
|
||||
}
|
||||
|
||||
Json::Value getJson (LedgerFill const& fill)
|
||||
Json::Value
|
||||
getJson(LedgerFill const& fill)
|
||||
{
|
||||
Json::Value json;
|
||||
fillJson (json, fill);
|
||||
fillJson(json, fill);
|
||||
return json;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -53,85 +53,90 @@ namespace ripple {
|
||||
class LocalTx
|
||||
{
|
||||
public:
|
||||
|
||||
// The number of ledgers to hold a transaction is essentially
|
||||
// arbitrary. It should be sufficient to allow the transaction to
|
||||
// get into a fully-validated ledger.
|
||||
static int const holdLedgers = 5;
|
||||
|
||||
LocalTx (LedgerIndex index, std::shared_ptr<STTx const> const& txn)
|
||||
: m_txn (txn)
|
||||
, m_expire (index + holdLedgers)
|
||||
, m_id (txn->getTransactionID ())
|
||||
, m_account (txn->getAccountID(sfAccount))
|
||||
, m_seq (txn->getSequence())
|
||||
LocalTx(LedgerIndex index, std::shared_ptr<STTx const> const& txn)
|
||||
: m_txn(txn)
|
||||
, m_expire(index + holdLedgers)
|
||||
, m_id(txn->getTransactionID())
|
||||
, m_account(txn->getAccountID(sfAccount))
|
||||
, m_seq(txn->getSequence())
|
||||
{
|
||||
if (txn->isFieldPresent (sfLastLedgerSequence))
|
||||
m_expire = std::min (m_expire, txn->getFieldU32 (sfLastLedgerSequence) + 1);
|
||||
if (txn->isFieldPresent(sfLastLedgerSequence))
|
||||
m_expire =
|
||||
std::min(m_expire, txn->getFieldU32(sfLastLedgerSequence) + 1);
|
||||
}
|
||||
|
||||
uint256 const& getID () const
|
||||
uint256 const&
|
||||
getID() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
std::uint32_t getSeq () const
|
||||
std::uint32_t
|
||||
getSeq() const
|
||||
{
|
||||
return m_seq;
|
||||
}
|
||||
|
||||
bool isExpired (LedgerIndex i) const
|
||||
bool
|
||||
isExpired(LedgerIndex i) const
|
||||
{
|
||||
return i > m_expire;
|
||||
}
|
||||
|
||||
std::shared_ptr<STTx const> const& getTX () const
|
||||
std::shared_ptr<STTx const> const&
|
||||
getTX() const
|
||||
{
|
||||
return m_txn;
|
||||
}
|
||||
|
||||
AccountID const& getAccount () const
|
||||
AccountID const&
|
||||
getAccount() const
|
||||
{
|
||||
return m_account;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<STTx const> m_txn;
|
||||
LedgerIndex m_expire;
|
||||
uint256 m_id;
|
||||
AccountID m_account;
|
||||
std::uint32_t m_seq;
|
||||
LedgerIndex m_expire;
|
||||
uint256 m_id;
|
||||
AccountID m_account;
|
||||
std::uint32_t m_seq;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class LocalTxsImp
|
||||
: public LocalTxs
|
||||
class LocalTxsImp : public LocalTxs
|
||||
{
|
||||
public:
|
||||
LocalTxsImp() = default;
|
||||
|
||||
// Add a new transaction to the set of local transactions
|
||||
void push_back (LedgerIndex index, std::shared_ptr<STTx const> const& txn) override
|
||||
void
|
||||
push_back(LedgerIndex index, std::shared_ptr<STTx const> const& txn)
|
||||
override
|
||||
{
|
||||
std::lock_guard lock (m_lock);
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
m_txns.emplace_back (index, txn);
|
||||
m_txns.emplace_back(index, txn);
|
||||
}
|
||||
|
||||
CanonicalTXSet
|
||||
getTxSet () override
|
||||
getTxSet() override
|
||||
{
|
||||
CanonicalTXSet tset (uint256 {});
|
||||
CanonicalTXSet tset(uint256{});
|
||||
|
||||
// Get the set of local transactions as a canonical
|
||||
// set (so they apply in a valid order)
|
||||
{
|
||||
std::lock_guard lock (m_lock);
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
for (auto const& it : m_txns)
|
||||
tset.insert (it.getTX());
|
||||
tset.insert(it.getTX());
|
||||
}
|
||||
|
||||
return tset;
|
||||
@@ -140,41 +145,42 @@ public:
|
||||
// Remove transactions that have either been accepted
|
||||
// into a fully-validated ledger, are (now) impossible,
|
||||
// or have expired
|
||||
void sweep (ReadView const& view) override
|
||||
void
|
||||
sweep(ReadView const& view) override
|
||||
{
|
||||
std::lock_guard lock (m_lock);
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
m_txns.remove_if ([&view](auto const& txn)
|
||||
{
|
||||
if (txn.isExpired (view.info().seq))
|
||||
m_txns.remove_if([&view](auto const& txn) {
|
||||
if (txn.isExpired(view.info().seq))
|
||||
return true;
|
||||
if (view.txExists(txn.getID()))
|
||||
return true;
|
||||
|
||||
std::shared_ptr<SLE const> sle = view.read(
|
||||
keylet::account(txn.getAccount()));
|
||||
if (! sle)
|
||||
std::shared_ptr<SLE const> sle =
|
||||
view.read(keylet::account(txn.getAccount()));
|
||||
if (!sle)
|
||||
return false;
|
||||
return sle->getFieldU32 (sfSequence) > txn.getSeq ();
|
||||
return sle->getFieldU32(sfSequence) > txn.getSeq();
|
||||
});
|
||||
}
|
||||
|
||||
std::size_t size () override
|
||||
std::size_t
|
||||
size() override
|
||||
{
|
||||
std::lock_guard lock (m_lock);
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
return m_txns.size ();
|
||||
return m_txns.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex m_lock;
|
||||
std::list <LocalTx> m_txns;
|
||||
std::list<LocalTx> m_txns;
|
||||
};
|
||||
|
||||
std::unique_ptr<LocalTxs>
|
||||
make_LocalTxs ()
|
||||
make_LocalTxs()
|
||||
{
|
||||
return std::make_unique<LocalTxsImp> ();
|
||||
return std::make_unique<LocalTxsImp>();
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -31,13 +31,11 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
OpenLedger::OpenLedger(std::shared_ptr<
|
||||
Ledger const> const& ledger,
|
||||
CachedSLEs& cache,
|
||||
beast::Journal journal)
|
||||
: j_ (journal)
|
||||
, cache_ (cache)
|
||||
, current_ (create(ledger->rules(), ledger))
|
||||
OpenLedger::OpenLedger(
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
CachedSLEs& cache,
|
||||
beast::Journal journal)
|
||||
: j_(journal), cache_(cache), current_(create(ledger->rules(), ledger))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,11 +54,10 @@ OpenLedger::current() const
|
||||
}
|
||||
|
||||
bool
|
||||
OpenLedger::modify (modify_type const& f)
|
||||
OpenLedger::modify(modify_type const& f)
|
||||
{
|
||||
std::lock_guard lock1(modify_mutex_);
|
||||
auto next = std::make_shared<
|
||||
OpenView>(*current_);
|
||||
auto next = std::make_shared<OpenView>(*current_);
|
||||
auto const changed = f(*next, j_);
|
||||
if (changed)
|
||||
{
|
||||
@@ -71,15 +68,18 @@ OpenLedger::modify (modify_type const& f)
|
||||
}
|
||||
|
||||
void
|
||||
OpenLedger::accept(Application& app, Rules const& rules,
|
||||
OpenLedger::accept(
|
||||
Application& app,
|
||||
Rules const& rules,
|
||||
std::shared_ptr<Ledger const> const& ledger,
|
||||
OrderedTxs const& locals, bool retriesFirst,
|
||||
OrderedTxs& retries, ApplyFlags flags,
|
||||
std::string const& suffix,
|
||||
modify_type const& f)
|
||||
OrderedTxs const& locals,
|
||||
bool retriesFirst,
|
||||
OrderedTxs& retries,
|
||||
ApplyFlags flags,
|
||||
std::string const& suffix,
|
||||
modify_type const& f)
|
||||
{
|
||||
JLOG(j_.trace()) <<
|
||||
"accept ledger " << ledger->seq() << " " << suffix;
|
||||
JLOG(j_.trace()) << "accept ledger " << ledger->seq() << " " << suffix;
|
||||
auto next = create(rules, ledger);
|
||||
std::map<uint256, bool> shouldRecover;
|
||||
if (retriesFirst)
|
||||
@@ -90,49 +90,49 @@ OpenLedger::accept(Application& app, Rules const& rules,
|
||||
shouldRecover[txID] = app.getHashRouter().shouldRecover(txID);
|
||||
}
|
||||
// Handle disputed tx, outside lock
|
||||
using empty =
|
||||
std::vector<std::shared_ptr<
|
||||
STTx const>>;
|
||||
apply (app, *next, *ledger, empty{},
|
||||
retries, flags, shouldRecover, j_);
|
||||
using empty = std::vector<std::shared_ptr<STTx const>>;
|
||||
apply(app, *next, *ledger, empty{}, retries, flags, shouldRecover, j_);
|
||||
}
|
||||
// Block calls to modify, otherwise
|
||||
// new tx going into the open ledger
|
||||
// would get lost.
|
||||
std::lock_guard lock1(modify_mutex_);
|
||||
// Apply tx from the current open view
|
||||
if (! current_->txs.empty())
|
||||
if (!current_->txs.empty())
|
||||
{
|
||||
for (auto const& tx : current_->txs)
|
||||
{
|
||||
auto const txID = tx.first->getTransactionID();
|
||||
auto iter = shouldRecover.lower_bound(txID);
|
||||
if (iter != shouldRecover.end()
|
||||
&& iter->first == txID)
|
||||
if (iter != shouldRecover.end() && iter->first == txID)
|
||||
// already had a chance via disputes
|
||||
iter->second = false;
|
||||
else
|
||||
shouldRecover.emplace_hint(iter, txID,
|
||||
app.getHashRouter().shouldRecover(txID));
|
||||
shouldRecover.emplace_hint(
|
||||
iter, txID, app.getHashRouter().shouldRecover(txID));
|
||||
}
|
||||
apply (app, *next, *ledger,
|
||||
apply(
|
||||
app,
|
||||
*next,
|
||||
*ledger,
|
||||
boost::adaptors::transform(
|
||||
current_->txs,
|
||||
[](std::pair<std::shared_ptr<
|
||||
STTx const>, std::shared_ptr<
|
||||
STObject const>> const& p)
|
||||
{
|
||||
return p.first;
|
||||
}),
|
||||
retries, flags, shouldRecover, j_);
|
||||
[](std::pair<
|
||||
std::shared_ptr<STTx const>,
|
||||
std::shared_ptr<STObject const>> const& p) {
|
||||
return p.first;
|
||||
}),
|
||||
retries,
|
||||
flags,
|
||||
shouldRecover,
|
||||
j_);
|
||||
}
|
||||
// Call the modifier
|
||||
if (f)
|
||||
f(*next, j_);
|
||||
// Apply local tx
|
||||
for (auto const& item : locals)
|
||||
app.getTxQ().apply(app, *next,
|
||||
item.second, flags, j_);
|
||||
app.getTxQ().apply(app, *next, item.second, flags, j_);
|
||||
|
||||
// If we didn't relay this transaction recently, relay it to all peers
|
||||
for (auto const& txpair : next->txs)
|
||||
@@ -150,7 +150,7 @@ OpenLedger::accept(Application& app, Rules const& rules,
|
||||
msg.set_status(protocol::tsNEW);
|
||||
msg.set_receivetimestamp(
|
||||
app.timeKeeper().now().time_since_epoch().count());
|
||||
app.overlay().foreach(send_if_not(
|
||||
app.overlay().foreach (send_if_not(
|
||||
std::make_shared<Message>(msg, protocol::mtTRANSACTION),
|
||||
peer_in_set(*toSkip)));
|
||||
}
|
||||
@@ -164,27 +164,31 @@ OpenLedger::accept(Application& app, Rules const& rules,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::shared_ptr<OpenView>
|
||||
OpenLedger::create (Rules const& rules,
|
||||
OpenLedger::create(
|
||||
Rules const& rules,
|
||||
std::shared_ptr<Ledger const> const& ledger)
|
||||
{
|
||||
return std::make_shared<OpenView>(
|
||||
open_ledger, rules, std::make_shared<
|
||||
CachedLedger const>(ledger,
|
||||
cache_));
|
||||
open_ledger,
|
||||
rules,
|
||||
std::make_shared<CachedLedger const>(ledger, cache_));
|
||||
}
|
||||
|
||||
auto
|
||||
OpenLedger::apply_one (Application& app, OpenView& view,
|
||||
OpenLedger::apply_one(
|
||||
Application& app,
|
||||
OpenView& view,
|
||||
std::shared_ptr<STTx const> const& tx,
|
||||
bool retry, ApplyFlags flags, bool shouldRecover,
|
||||
beast::Journal j) -> Result
|
||||
bool retry,
|
||||
ApplyFlags flags,
|
||||
bool shouldRecover,
|
||||
beast::Journal j) -> Result
|
||||
{
|
||||
if (retry)
|
||||
flags = flags | tapRETRY;
|
||||
auto const result = [&]
|
||||
{
|
||||
auto const queueResult = app.getTxQ().apply(
|
||||
app, view, tx, flags | tapPREFER_QUEUE, j);
|
||||
auto const result = [&] {
|
||||
auto const queueResult =
|
||||
app.getTxQ().apply(app, view, tx, flags | tapPREFER_QUEUE, j);
|
||||
// If the transaction can't get into the queue for intrinsic
|
||||
// reasons, and it can still be recovered, try to put it
|
||||
// directly into the open ledger, else drop it.
|
||||
@@ -192,12 +196,10 @@ OpenLedger::apply_one (Application& app, OpenView& view,
|
||||
return ripple::apply(app, view, *tx, flags, j);
|
||||
return queueResult;
|
||||
}();
|
||||
if (result.second ||
|
||||
result.first == terQUEUED)
|
||||
if (result.second || result.first == terQUEUED)
|
||||
return Result::success;
|
||||
if (isTefFailure (result.first) ||
|
||||
isTemMalformed (result.first) ||
|
||||
isTelLocal (result.first))
|
||||
if (isTefFailure(result.first) || isTemMalformed(result.first) ||
|
||||
isTelLocal(result.first))
|
||||
return Result::failure;
|
||||
return Result::retry;
|
||||
}
|
||||
@@ -205,7 +207,7 @@ OpenLedger::apply_one (Application& app, OpenView& view,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::string
|
||||
debugTxstr (std::shared_ptr<STTx const> const& tx)
|
||||
debugTxstr(std::shared_ptr<STTx const> const& tx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx->getTransactionID();
|
||||
@@ -213,16 +215,16 @@ debugTxstr (std::shared_ptr<STTx const> const& tx)
|
||||
}
|
||||
|
||||
std::string
|
||||
debugTostr (OrderedTxs const& set)
|
||||
debugTostr(OrderedTxs const& set)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for(auto const& item : set)
|
||||
for (auto const& item : set)
|
||||
ss << debugTxstr(item.second) << ", ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
debugTostr (SHAMap const& set)
|
||||
debugTostr(SHAMap const& set)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for (auto const& item : set)
|
||||
@@ -230,11 +232,10 @@ debugTostr (SHAMap const& set)
|
||||
try
|
||||
{
|
||||
SerialIter sit(item.slice());
|
||||
auto const tx = std::make_shared<
|
||||
STTx const>(sit);
|
||||
auto const tx = std::make_shared<STTx const>(sit);
|
||||
ss << debugTxstr(tx) << ", ";
|
||||
}
|
||||
catch(std::exception const&)
|
||||
catch (std::exception const&)
|
||||
{
|
||||
ss << "THRO, ";
|
||||
}
|
||||
@@ -243,12 +244,12 @@ debugTostr (SHAMap const& set)
|
||||
}
|
||||
|
||||
std::string
|
||||
debugTostr (std::shared_ptr<ReadView const> const& view)
|
||||
debugTostr(std::shared_ptr<ReadView const> const& view)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for(auto const& item : view->txs)
|
||||
for (auto const& item : view->txs)
|
||||
ss << debugTxstr(item.first) << ", ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/impl/TransactionAcquire.h>
|
||||
#include <ripple/app/ledger/ConsensusTransSetSF.h>
|
||||
#include <ripple/app/ledger/InboundLedgers.h>
|
||||
#include <ripple/app/ledger/InboundTransactions.h>
|
||||
#include <ripple/app/ledger/impl/TransactionAcquire.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/overlay/Overlay.h>
|
||||
@@ -34,235 +34,253 @@ using namespace std::chrono_literals;
|
||||
// Timeout interval in milliseconds
|
||||
auto constexpr TX_ACQUIRE_TIMEOUT = 250ms;
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
NORM_TIMEOUTS = 4,
|
||||
MAX_TIMEOUTS = 20,
|
||||
};
|
||||
|
||||
TransactionAcquire::TransactionAcquire (Application& app, uint256 const& hash, clock_type& clock)
|
||||
: PeerSet (app, hash, TX_ACQUIRE_TIMEOUT, clock,
|
||||
app.journal("TransactionAcquire"))
|
||||
, mHaveRoot (false)
|
||||
TransactionAcquire::TransactionAcquire(
|
||||
Application& app,
|
||||
uint256 const& hash,
|
||||
clock_type& clock)
|
||||
: PeerSet(
|
||||
app,
|
||||
hash,
|
||||
TX_ACQUIRE_TIMEOUT,
|
||||
clock,
|
||||
app.journal("TransactionAcquire"))
|
||||
, mHaveRoot(false)
|
||||
, j_(app.journal("TransactionAcquire"))
|
||||
{
|
||||
mMap = std::make_shared<SHAMap> (SHAMapType::TRANSACTION, hash,
|
||||
app_.family());
|
||||
mMap->setUnbacked ();
|
||||
mMap =
|
||||
std::make_shared<SHAMap>(SHAMapType::TRANSACTION, hash, app_.family());
|
||||
mMap->setUnbacked();
|
||||
}
|
||||
|
||||
void TransactionAcquire::execute ()
|
||||
void
|
||||
TransactionAcquire::execute()
|
||||
{
|
||||
app_.getJobQueue ().addJob (
|
||||
jtTXN_DATA, "TransactionAcquire",
|
||||
[ptr = shared_from_this()](Job&)
|
||||
{
|
||||
ptr->invokeOnTimer ();
|
||||
app_.getJobQueue().addJob(
|
||||
jtTXN_DATA, "TransactionAcquire", [ptr = shared_from_this()](Job&) {
|
||||
ptr->invokeOnTimer();
|
||||
});
|
||||
}
|
||||
|
||||
void TransactionAcquire::done ()
|
||||
void
|
||||
TransactionAcquire::done()
|
||||
{
|
||||
// We hold a PeerSet lock and so cannot do real work here
|
||||
|
||||
if (mFailed)
|
||||
{
|
||||
JLOG (j_.warn()) << "Failed to acquire TX set " << mHash;
|
||||
JLOG(j_.warn()) << "Failed to acquire TX set " << mHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG (j_.debug()) << "Acquired TX set " << mHash;
|
||||
mMap->setImmutable ();
|
||||
JLOG(j_.debug()) << "Acquired TX set " << mHash;
|
||||
mMap->setImmutable();
|
||||
|
||||
uint256 const& hash (mHash);
|
||||
std::shared_ptr <SHAMap> const& map (mMap);
|
||||
uint256 const& hash(mHash);
|
||||
std::shared_ptr<SHAMap> const& map(mMap);
|
||||
auto const pap = &app_;
|
||||
// Note that, when we're in the process of shutting down, addJob()
|
||||
// may reject the request. If that happens then giveSet() will
|
||||
// not be called. That's fine. According to David the giveSet() call
|
||||
// just updates the consensus and related structures when we acquire
|
||||
// a transaction set. No need to update them if we're shutting down.
|
||||
app_.getJobQueue().addJob (jtTXN_DATA, "completeAcquire",
|
||||
[pap, hash, map](Job&)
|
||||
{
|
||||
pap->getInboundTransactions().giveSet (
|
||||
hash, map, true);
|
||||
app_.getJobQueue().addJob(
|
||||
jtTXN_DATA, "completeAcquire", [pap, hash, map](Job&) {
|
||||
pap->getInboundTransactions().giveSet(hash, map, true);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TransactionAcquire::onTimer (bool progress, ScopedLockType& psl)
|
||||
void
|
||||
TransactionAcquire::onTimer(bool progress, ScopedLockType& psl)
|
||||
{
|
||||
bool aggressive = false;
|
||||
|
||||
if (getTimeouts () >= NORM_TIMEOUTS)
|
||||
if (getTimeouts() >= NORM_TIMEOUTS)
|
||||
{
|
||||
aggressive = true;
|
||||
|
||||
if (getTimeouts () > MAX_TIMEOUTS)
|
||||
if (getTimeouts() > MAX_TIMEOUTS)
|
||||
{
|
||||
mFailed = true;
|
||||
done ();
|
||||
done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (aggressive)
|
||||
trigger (nullptr);
|
||||
trigger(nullptr);
|
||||
|
||||
addPeers (1);
|
||||
addPeers(1);
|
||||
}
|
||||
|
||||
std::weak_ptr<PeerSet> TransactionAcquire::pmDowncast ()
|
||||
std::weak_ptr<PeerSet>
|
||||
TransactionAcquire::pmDowncast()
|
||||
{
|
||||
return std::dynamic_pointer_cast<PeerSet> (shared_from_this ());
|
||||
return std::dynamic_pointer_cast<PeerSet>(shared_from_this());
|
||||
}
|
||||
|
||||
void TransactionAcquire::trigger (std::shared_ptr<Peer> const& peer)
|
||||
void
|
||||
TransactionAcquire::trigger(std::shared_ptr<Peer> const& peer)
|
||||
{
|
||||
if (mComplete)
|
||||
{
|
||||
JLOG (j_.info()) << "trigger after complete";
|
||||
JLOG(j_.info()) << "trigger after complete";
|
||||
return;
|
||||
}
|
||||
if (mFailed)
|
||||
{
|
||||
JLOG (j_.info()) << "trigger after fail";
|
||||
JLOG(j_.info()) << "trigger after fail";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mHaveRoot)
|
||||
{
|
||||
JLOG (j_.trace()) << "TransactionAcquire::trigger " << (peer ? "havePeer" : "noPeer") << " no root";
|
||||
JLOG(j_.trace()) << "TransactionAcquire::trigger "
|
||||
<< (peer ? "havePeer" : "noPeer") << " no root";
|
||||
protocol::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash (mHash.begin (), mHash.size ());
|
||||
tmGL.set_itype (protocol::liTS_CANDIDATE);
|
||||
tmGL.set_querydepth (3); // We probably need the whole thing
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(protocol::liTS_CANDIDATE);
|
||||
tmGL.set_querydepth(3); // We probably need the whole thing
|
||||
|
||||
if (getTimeouts () != 0)
|
||||
tmGL.set_querytype (protocol::qtINDIRECT);
|
||||
if (getTimeouts() != 0)
|
||||
tmGL.set_querytype(protocol::qtINDIRECT);
|
||||
|
||||
* (tmGL.add_nodeids ()) = SHAMapNodeID ().getRawString ();
|
||||
sendRequest (tmGL, peer);
|
||||
*(tmGL.add_nodeids()) = SHAMapNodeID().getRawString();
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
else if (!mMap->isValid ())
|
||||
else if (!mMap->isValid())
|
||||
{
|
||||
mFailed = true;
|
||||
done ();
|
||||
done();
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsensusTransSetSF sf (app_, app_.getTempNodeCache ());
|
||||
auto nodes = mMap->getMissingNodes (256, &sf);
|
||||
ConsensusTransSetSF sf(app_, app_.getTempNodeCache());
|
||||
auto nodes = mMap->getMissingNodes(256, &sf);
|
||||
|
||||
if (nodes.empty ())
|
||||
if (nodes.empty())
|
||||
{
|
||||
if (mMap->isValid ())
|
||||
if (mMap->isValid())
|
||||
mComplete = true;
|
||||
else
|
||||
mFailed = true;
|
||||
|
||||
done ();
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
protocol::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash (mHash.begin (), mHash.size ());
|
||||
tmGL.set_itype (protocol::liTS_CANDIDATE);
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(protocol::liTS_CANDIDATE);
|
||||
|
||||
if (getTimeouts () != 0)
|
||||
tmGL.set_querytype (protocol::qtINDIRECT);
|
||||
if (getTimeouts() != 0)
|
||||
tmGL.set_querytype(protocol::qtINDIRECT);
|
||||
|
||||
for (auto const& node : nodes)
|
||||
{
|
||||
*tmGL.add_nodeids () = node.first.getRawString ();
|
||||
*tmGL.add_nodeids() = node.first.getRawString();
|
||||
}
|
||||
sendRequest (tmGL, peer);
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
|
||||
SHAMapAddNode TransactionAcquire::takeNodes (const std::list<SHAMapNodeID>& nodeIDs,
|
||||
const std::list< Blob >& data, std::shared_ptr<Peer> const& peer)
|
||||
SHAMapAddNode
|
||||
TransactionAcquire::takeNodes(
|
||||
const std::list<SHAMapNodeID>& nodeIDs,
|
||||
const std::list<Blob>& data,
|
||||
std::shared_ptr<Peer> const& peer)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
if (mComplete)
|
||||
{
|
||||
JLOG (j_.trace()) << "TX set complete";
|
||||
return SHAMapAddNode ();
|
||||
JLOG(j_.trace()) << "TX set complete";
|
||||
return SHAMapAddNode();
|
||||
}
|
||||
|
||||
if (mFailed)
|
||||
{
|
||||
JLOG (j_.trace()) << "TX set failed";
|
||||
return SHAMapAddNode ();
|
||||
JLOG(j_.trace()) << "TX set failed";
|
||||
return SHAMapAddNode();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (nodeIDs.empty ())
|
||||
return SHAMapAddNode::invalid ();
|
||||
if (nodeIDs.empty())
|
||||
return SHAMapAddNode::invalid();
|
||||
|
||||
std::list<SHAMapNodeID>::const_iterator nodeIDit = nodeIDs.begin ();
|
||||
std::list< Blob >::const_iterator nodeDatait = data.begin ();
|
||||
ConsensusTransSetSF sf (app_, app_.getTempNodeCache ());
|
||||
std::list<SHAMapNodeID>::const_iterator nodeIDit = nodeIDs.begin();
|
||||
std::list<Blob>::const_iterator nodeDatait = data.begin();
|
||||
ConsensusTransSetSF sf(app_, app_.getTempNodeCache());
|
||||
|
||||
while (nodeIDit != nodeIDs.end ())
|
||||
while (nodeIDit != nodeIDs.end())
|
||||
{
|
||||
if (nodeIDit->isRoot ())
|
||||
if (nodeIDit->isRoot())
|
||||
{
|
||||
if (mHaveRoot)
|
||||
JLOG (j_.debug()) << "Got root TXS node, already have it";
|
||||
else if (!mMap->addRootNode (SHAMapHash{getHash ()},
|
||||
makeSlice(*nodeDatait), snfWIRE, nullptr).isGood())
|
||||
JLOG(j_.debug()) << "Got root TXS node, already have it";
|
||||
else if (!mMap->addRootNode(
|
||||
SHAMapHash{getHash()},
|
||||
makeSlice(*nodeDatait),
|
||||
snfWIRE,
|
||||
nullptr)
|
||||
.isGood())
|
||||
{
|
||||
JLOG (j_.warn()) << "TX acquire got bad root node";
|
||||
JLOG(j_.warn()) << "TX acquire got bad root node";
|
||||
}
|
||||
else
|
||||
mHaveRoot = true;
|
||||
}
|
||||
else if (!mMap->addKnownNode (*nodeIDit, makeSlice(*nodeDatait), &sf).isGood())
|
||||
else if (!mMap->addKnownNode(*nodeIDit, makeSlice(*nodeDatait), &sf)
|
||||
.isGood())
|
||||
{
|
||||
JLOG (j_.warn()) << "TX acquire got bad non-root node";
|
||||
return SHAMapAddNode::invalid ();
|
||||
JLOG(j_.warn()) << "TX acquire got bad non-root node";
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
|
||||
++nodeIDit;
|
||||
++nodeDatait;
|
||||
}
|
||||
|
||||
trigger (peer);
|
||||
progress ();
|
||||
return SHAMapAddNode::useful ();
|
||||
trigger(peer);
|
||||
progress();
|
||||
return SHAMapAddNode::useful();
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
JLOG (j_.error()) << "Peer sends us junky transaction node data";
|
||||
return SHAMapAddNode::invalid ();
|
||||
JLOG(j_.error()) << "Peer sends us junky transaction node data";
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
void TransactionAcquire::addPeers (int numPeers)
|
||||
void
|
||||
TransactionAcquire::addPeers(int numPeers)
|
||||
{
|
||||
app_.overlay().selectPeers (*this, numPeers, ScoreHasTxSet (getHash()));
|
||||
app_.overlay().selectPeers(*this, numPeers, ScoreHasTxSet(getHash()));
|
||||
}
|
||||
|
||||
void TransactionAcquire::init (int numPeers)
|
||||
void
|
||||
TransactionAcquire::init(int numPeers)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
addPeers (numPeers);
|
||||
addPeers(numPeers);
|
||||
|
||||
setTimer ();
|
||||
setTimer();
|
||||
}
|
||||
|
||||
void TransactionAcquire::stillNeed ()
|
||||
void
|
||||
TransactionAcquire::stillNeed()
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
if (mTimeouts > NORM_TIMEOUTS)
|
||||
mTimeouts = NORM_TIMEOUTS;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -29,56 +29,74 @@ namespace ripple {
|
||||
// VFALCO TODO rename to PeerTxRequest
|
||||
// A transaction set we are trying to acquire
|
||||
class TransactionAcquire
|
||||
: public PeerSet
|
||||
, public std::enable_shared_from_this <TransactionAcquire>
|
||||
, public CountedObject <TransactionAcquire>
|
||||
: public PeerSet,
|
||||
public std::enable_shared_from_this<TransactionAcquire>,
|
||||
public CountedObject<TransactionAcquire>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "TransactionAcquire"; }
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "TransactionAcquire";
|
||||
}
|
||||
|
||||
using pointer = std::shared_ptr<TransactionAcquire>;
|
||||
|
||||
public:
|
||||
TransactionAcquire (Application& app, uint256 const& hash, clock_type& clock);
|
||||
~TransactionAcquire () = default;
|
||||
TransactionAcquire(
|
||||
Application& app,
|
||||
uint256 const& hash,
|
||||
clock_type& clock);
|
||||
~TransactionAcquire() = default;
|
||||
|
||||
std::shared_ptr<SHAMap> const& getMap ()
|
||||
std::shared_ptr<SHAMap> const&
|
||||
getMap()
|
||||
{
|
||||
return mMap;
|
||||
}
|
||||
|
||||
SHAMapAddNode takeNodes (const std::list<SHAMapNodeID>& IDs,
|
||||
const std::list< Blob >& data, std::shared_ptr<Peer> const&);
|
||||
SHAMapAddNode
|
||||
takeNodes(
|
||||
const std::list<SHAMapNodeID>& IDs,
|
||||
const std::list<Blob>& data,
|
||||
std::shared_ptr<Peer> const&);
|
||||
|
||||
void init (int startPeers);
|
||||
void
|
||||
init(int startPeers);
|
||||
|
||||
void stillNeed ();
|
||||
void
|
||||
stillNeed();
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<SHAMap> mMap;
|
||||
bool mHaveRoot;
|
||||
beast::Journal j_;
|
||||
bool mHaveRoot;
|
||||
beast::Journal j_;
|
||||
|
||||
void execute () override;
|
||||
void
|
||||
execute() override;
|
||||
|
||||
void onTimer (bool progress, ScopedLockType& peerSetLock) override;
|
||||
void
|
||||
onTimer(bool progress, ScopedLockType& peerSetLock) override;
|
||||
|
||||
|
||||
void newPeer (std::shared_ptr<Peer> const& peer) override
|
||||
void
|
||||
newPeer(std::shared_ptr<Peer> const& peer) override
|
||||
{
|
||||
trigger (peer);
|
||||
trigger(peer);
|
||||
}
|
||||
|
||||
void done ();
|
||||
void
|
||||
done();
|
||||
|
||||
// Tries to add the specified number of peers
|
||||
void addPeers (int num);
|
||||
void
|
||||
addPeers(int num);
|
||||
|
||||
void trigger (std::shared_ptr<Peer> const&);
|
||||
std::weak_ptr<PeerSet> pmDowncast () override;
|
||||
void
|
||||
trigger(std::shared_ptr<Peer> const&);
|
||||
std::weak_ptr<PeerSet>
|
||||
pmDowncast() override;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,46 +18,51 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/TransactionMaster.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TransactionMaster::TransactionMaster (Application& app)
|
||||
: mApp (app)
|
||||
, mCache ("TransactionCache", 65536, std::chrono::minutes {30}, stopwatch(),
|
||||
mApp.journal("TaggedCache"))
|
||||
TransactionMaster::TransactionMaster(Application& app)
|
||||
: mApp(app)
|
||||
, mCache(
|
||||
"TransactionCache",
|
||||
65536,
|
||||
std::chrono::minutes{30},
|
||||
stopwatch(),
|
||||
mApp.journal("TaggedCache"))
|
||||
{
|
||||
}
|
||||
|
||||
bool TransactionMaster::inLedger (uint256 const& hash, std::uint32_t ledger)
|
||||
bool
|
||||
TransactionMaster::inLedger(uint256 const& hash, std::uint32_t ledger)
|
||||
{
|
||||
auto txn = mCache.fetch (hash);
|
||||
auto txn = mCache.fetch(hash);
|
||||
|
||||
if (!txn)
|
||||
return false;
|
||||
|
||||
txn->setStatus (COMMITTED, ledger);
|
||||
txn->setStatus(COMMITTED, ledger);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<Transaction>
|
||||
TransactionMaster::fetch_from_cache (uint256 const& txnID)
|
||||
TransactionMaster::fetch_from_cache(uint256 const& txnID)
|
||||
{
|
||||
return mCache.fetch (txnID);
|
||||
return mCache.fetch(txnID);
|
||||
}
|
||||
|
||||
std::shared_ptr<Transaction>
|
||||
TransactionMaster::fetch (uint256 const& txnID, error_code_i& ec)
|
||||
TransactionMaster::fetch(uint256 const& txnID, error_code_i& ec)
|
||||
{
|
||||
auto txn = fetch_from_cache (txnID);
|
||||
auto txn = fetch_from_cache(txnID);
|
||||
|
||||
if (txn)
|
||||
return txn;
|
||||
|
||||
txn = Transaction::load (txnID, mApp, ec);
|
||||
txn = Transaction::load(txnID, mApp, ec);
|
||||
|
||||
if (!txn)
|
||||
return txn;
|
||||
@@ -68,52 +73,56 @@ TransactionMaster::fetch (uint256 const& txnID, error_code_i& ec)
|
||||
}
|
||||
|
||||
boost::variant<Transaction::pointer, bool>
|
||||
TransactionMaster::fetch (uint256 const& txnID, ClosedInterval<uint32_t> const& range,
|
||||
TransactionMaster::fetch(
|
||||
uint256 const& txnID,
|
||||
ClosedInterval<uint32_t> const& range,
|
||||
error_code_i& ec)
|
||||
{
|
||||
using pointer = Transaction::pointer;
|
||||
|
||||
auto txn = mCache.fetch (txnID);
|
||||
auto txn = mCache.fetch(txnID);
|
||||
|
||||
if (txn)
|
||||
return txn;
|
||||
|
||||
boost::variant<Transaction::pointer, bool> v = Transaction::load (
|
||||
txnID, mApp, range, ec);
|
||||
boost::variant<Transaction::pointer, bool> v =
|
||||
Transaction::load(txnID, mApp, range, ec);
|
||||
|
||||
if (v.which () == 0 && boost::get<pointer> (v))
|
||||
mCache.canonicalize_replace_client(txnID, boost::get<pointer> (v));
|
||||
if (v.which() == 0 && boost::get<pointer>(v))
|
||||
mCache.canonicalize_replace_client(txnID, boost::get<pointer>(v));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::shared_ptr<STTx const>
|
||||
TransactionMaster::fetch (std::shared_ptr<SHAMapItem> const& item,
|
||||
SHAMapTreeNode::TNType type, std::uint32_t uCommitLedger)
|
||||
TransactionMaster::fetch(
|
||||
std::shared_ptr<SHAMapItem> const& item,
|
||||
SHAMapTreeNode::TNType type,
|
||||
std::uint32_t uCommitLedger)
|
||||
{
|
||||
std::shared_ptr<STTx const> txn;
|
||||
auto iTx = fetch_from_cache (item->key());
|
||||
std::shared_ptr<STTx const> txn;
|
||||
auto iTx = fetch_from_cache(item->key());
|
||||
|
||||
if (!iTx)
|
||||
{
|
||||
|
||||
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
|
||||
{
|
||||
SerialIter sit (item->slice());
|
||||
txn = std::make_shared<STTx const> (std::ref (sit));
|
||||
SerialIter sit(item->slice());
|
||||
txn = std::make_shared<STTx const>(std::ref(sit));
|
||||
}
|
||||
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
|
||||
{
|
||||
auto blob = SerialIter{item->data(), item->size()}.getVL();
|
||||
txn = std::make_shared<STTx const>(SerialIter{blob.data(), blob.size()});
|
||||
txn = std::make_shared<STTx const>(
|
||||
SerialIter{blob.data(), blob.size()});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uCommitLedger)
|
||||
iTx->setStatus (COMMITTED, uCommitLedger);
|
||||
iTx->setStatus(COMMITTED, uCommitLedger);
|
||||
|
||||
txn = iTx->getSTransaction ();
|
||||
txn = iTx->getSTransaction();
|
||||
}
|
||||
|
||||
return txn;
|
||||
@@ -132,14 +141,16 @@ TransactionMaster::canonicalize(std::shared_ptr<Transaction>* pTransaction)
|
||||
}
|
||||
}
|
||||
|
||||
void TransactionMaster::sweep (void)
|
||||
void
|
||||
TransactionMaster::sweep(void)
|
||||
{
|
||||
mCache.sweep ();
|
||||
mCache.sweep();
|
||||
}
|
||||
|
||||
TaggedCache <uint256, Transaction>& TransactionMaster::getCache()
|
||||
TaggedCache<uint256, Transaction>&
|
||||
TransactionMaster::getCache()
|
||||
{
|
||||
return mCache;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,23 +20,32 @@
|
||||
#ifndef RIPPLE_APP_MAIN_APPLICATION_H_INCLUDED
|
||||
#define RIPPLE_APP_MAIN_APPLICATION_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/TaggedCache.h>
|
||||
#include <ripple/beast/utility/PropertyStream.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/overlay/PeerReservationTable.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/shamap/FullBelowCache.h>
|
||||
#include <ripple/shamap/TreeNodeCache.h>
|
||||
#include <ripple/basics/TaggedCache.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/beast/utility/PropertyStream.h>
|
||||
#include <ripple/overlay/PeerReservationTable.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace unl { class Manager; }
|
||||
namespace Resource { class Manager; }
|
||||
namespace NodeStore { class Database; class DatabaseShard; }
|
||||
namespace perf { class PerfLog; }
|
||||
namespace unl {
|
||||
class Manager;
|
||||
}
|
||||
namespace Resource {
|
||||
class Manager;
|
||||
}
|
||||
namespace NodeStore {
|
||||
class Database;
|
||||
class DatabaseShard;
|
||||
} // namespace NodeStore
|
||||
namespace perf {
|
||||
class PerfLog;
|
||||
}
|
||||
|
||||
// VFALCO TODO Fix forward declares required for header dependency loops
|
||||
class AmendmentTable;
|
||||
@@ -75,7 +84,7 @@ class Cluster;
|
||||
class DatabaseCon;
|
||||
class SHAMapStore;
|
||||
|
||||
using NodeCache = TaggedCache <SHAMapHash, Blob>;
|
||||
using NodeCache = TaggedCache<SHAMapHash, Blob>;
|
||||
|
||||
template <class Adaptor>
|
||||
class Validations;
|
||||
@@ -97,110 +106,158 @@ public:
|
||||
other things
|
||||
*/
|
||||
using MutexType = std::recursive_mutex;
|
||||
virtual MutexType& getMasterMutex () = 0;
|
||||
virtual MutexType&
|
||||
getMasterMutex() = 0;
|
||||
|
||||
public:
|
||||
Application ();
|
||||
Application();
|
||||
|
||||
virtual ~Application () = default;
|
||||
virtual ~Application() = default;
|
||||
|
||||
virtual bool setup() = 0;
|
||||
virtual void doStart(bool withTimers) = 0;
|
||||
virtual void run() = 0;
|
||||
virtual bool isShutdown () = 0;
|
||||
virtual void signalStop () = 0;
|
||||
virtual bool checkSigs() const = 0;
|
||||
virtual void checkSigs(bool) = 0;
|
||||
virtual bool
|
||||
setup() = 0;
|
||||
virtual void
|
||||
doStart(bool withTimers) = 0;
|
||||
virtual void
|
||||
run() = 0;
|
||||
virtual bool
|
||||
isShutdown() = 0;
|
||||
virtual void
|
||||
signalStop() = 0;
|
||||
virtual bool
|
||||
checkSigs() const = 0;
|
||||
virtual void
|
||||
checkSigs(bool) = 0;
|
||||
|
||||
//
|
||||
// ---
|
||||
//
|
||||
|
||||
virtual Logs& logs() = 0;
|
||||
virtual Config& config() = 0;
|
||||
virtual Logs&
|
||||
logs() = 0;
|
||||
virtual Config&
|
||||
config() = 0;
|
||||
|
||||
virtual
|
||||
boost::asio::io_service&
|
||||
getIOService () = 0;
|
||||
virtual boost::asio::io_service&
|
||||
getIOService() = 0;
|
||||
|
||||
virtual CollectorManager& getCollectorManager () = 0;
|
||||
virtual Family& family() = 0;
|
||||
virtual Family* shardFamily() = 0;
|
||||
virtual TimeKeeper& timeKeeper() = 0;
|
||||
virtual JobQueue& getJobQueue () = 0;
|
||||
virtual NodeCache& getTempNodeCache () = 0;
|
||||
virtual CachedSLEs& cachedSLEs() = 0;
|
||||
virtual AmendmentTable& getAmendmentTable() = 0;
|
||||
virtual HashRouter& getHashRouter () = 0;
|
||||
virtual LoadFeeTrack& getFeeTrack () = 0;
|
||||
virtual LoadManager& getLoadManager () = 0;
|
||||
virtual Overlay& overlay () = 0;
|
||||
virtual TxQ& getTxQ() = 0;
|
||||
virtual ValidatorList& validators () = 0;
|
||||
virtual ValidatorSite& validatorSites () = 0;
|
||||
virtual ManifestCache& validatorManifests () = 0;
|
||||
virtual ManifestCache& publisherManifests () = 0;
|
||||
virtual Cluster& cluster () = 0;
|
||||
virtual PeerReservationTable& peerReservations () = 0;
|
||||
virtual RCLValidations& getValidations () = 0;
|
||||
virtual NodeStore::Database& getNodeStore () = 0;
|
||||
virtual NodeStore::DatabaseShard* getShardStore() = 0;
|
||||
virtual InboundLedgers& getInboundLedgers () = 0;
|
||||
virtual InboundTransactions& getInboundTransactions () = 0;
|
||||
virtual CollectorManager&
|
||||
getCollectorManager() = 0;
|
||||
virtual Family&
|
||||
family() = 0;
|
||||
virtual Family*
|
||||
shardFamily() = 0;
|
||||
virtual TimeKeeper&
|
||||
timeKeeper() = 0;
|
||||
virtual JobQueue&
|
||||
getJobQueue() = 0;
|
||||
virtual NodeCache&
|
||||
getTempNodeCache() = 0;
|
||||
virtual CachedSLEs&
|
||||
cachedSLEs() = 0;
|
||||
virtual AmendmentTable&
|
||||
getAmendmentTable() = 0;
|
||||
virtual HashRouter&
|
||||
getHashRouter() = 0;
|
||||
virtual LoadFeeTrack&
|
||||
getFeeTrack() = 0;
|
||||
virtual LoadManager&
|
||||
getLoadManager() = 0;
|
||||
virtual Overlay&
|
||||
overlay() = 0;
|
||||
virtual TxQ&
|
||||
getTxQ() = 0;
|
||||
virtual ValidatorList&
|
||||
validators() = 0;
|
||||
virtual ValidatorSite&
|
||||
validatorSites() = 0;
|
||||
virtual ManifestCache&
|
||||
validatorManifests() = 0;
|
||||
virtual ManifestCache&
|
||||
publisherManifests() = 0;
|
||||
virtual Cluster&
|
||||
cluster() = 0;
|
||||
virtual PeerReservationTable&
|
||||
peerReservations() = 0;
|
||||
virtual RCLValidations&
|
||||
getValidations() = 0;
|
||||
virtual NodeStore::Database&
|
||||
getNodeStore() = 0;
|
||||
virtual NodeStore::DatabaseShard*
|
||||
getShardStore() = 0;
|
||||
virtual InboundLedgers&
|
||||
getInboundLedgers() = 0;
|
||||
virtual InboundTransactions&
|
||||
getInboundTransactions() = 0;
|
||||
|
||||
virtual
|
||||
TaggedCache <uint256, AcceptedLedger>&
|
||||
getAcceptedLedgerCache () = 0;
|
||||
virtual TaggedCache<uint256, AcceptedLedger>&
|
||||
getAcceptedLedgerCache() = 0;
|
||||
|
||||
virtual LedgerMaster& getLedgerMaster () = 0;
|
||||
virtual NetworkOPs& getOPs () = 0;
|
||||
virtual OrderBookDB& getOrderBookDB () = 0;
|
||||
virtual TransactionMaster& getMasterTransaction () = 0;
|
||||
virtual perf::PerfLog& getPerfLog () = 0;
|
||||
virtual LedgerMaster&
|
||||
getLedgerMaster() = 0;
|
||||
virtual NetworkOPs&
|
||||
getOPs() = 0;
|
||||
virtual OrderBookDB&
|
||||
getOrderBookDB() = 0;
|
||||
virtual TransactionMaster&
|
||||
getMasterTransaction() = 0;
|
||||
virtual perf::PerfLog&
|
||||
getPerfLog() = 0;
|
||||
|
||||
virtual
|
||||
std::pair<PublicKey, SecretKey> const&
|
||||
nodeIdentity () = 0;
|
||||
virtual std::pair<PublicKey, SecretKey> const&
|
||||
nodeIdentity() = 0;
|
||||
|
||||
virtual
|
||||
PublicKey const &
|
||||
getValidationPublicKey() const = 0;
|
||||
virtual PublicKey const&
|
||||
getValidationPublicKey() const = 0;
|
||||
|
||||
virtual Resource::Manager& getResourceManager () = 0;
|
||||
virtual PathRequests& getPathRequests () = 0;
|
||||
virtual SHAMapStore& getSHAMapStore () = 0;
|
||||
virtual PendingSaves& pendingSaves() = 0;
|
||||
virtual AccountIDCache const& accountIDCache() const = 0;
|
||||
virtual OpenLedger& openLedger() = 0;
|
||||
virtual OpenLedger const& openLedger() const = 0;
|
||||
virtual DatabaseCon& getTxnDB () = 0;
|
||||
virtual DatabaseCon& getLedgerDB () = 0;
|
||||
virtual Resource::Manager&
|
||||
getResourceManager() = 0;
|
||||
virtual PathRequests&
|
||||
getPathRequests() = 0;
|
||||
virtual SHAMapStore&
|
||||
getSHAMapStore() = 0;
|
||||
virtual PendingSaves&
|
||||
pendingSaves() = 0;
|
||||
virtual AccountIDCache const&
|
||||
accountIDCache() const = 0;
|
||||
virtual OpenLedger&
|
||||
openLedger() = 0;
|
||||
virtual OpenLedger const&
|
||||
openLedger() const = 0;
|
||||
virtual DatabaseCon&
|
||||
getTxnDB() = 0;
|
||||
virtual DatabaseCon&
|
||||
getLedgerDB() = 0;
|
||||
|
||||
virtual
|
||||
std::chrono::milliseconds
|
||||
getIOLatency () = 0;
|
||||
virtual std::chrono::milliseconds
|
||||
getIOLatency() = 0;
|
||||
|
||||
virtual bool serverOkay (std::string& reason) = 0;
|
||||
virtual bool
|
||||
serverOkay(std::string& reason) = 0;
|
||||
|
||||
virtual beast::Journal journal (std::string const& name) = 0;
|
||||
virtual beast::Journal
|
||||
journal(std::string const& name) = 0;
|
||||
|
||||
/* Returns the number of file descriptors the application needs */
|
||||
virtual int fdRequired() const = 0;
|
||||
virtual int
|
||||
fdRequired() const = 0;
|
||||
|
||||
/** Retrieve the "wallet database" */
|
||||
virtual DatabaseCon& getWalletDB () = 0;
|
||||
virtual DatabaseCon&
|
||||
getWalletDB() = 0;
|
||||
|
||||
/** Ensure that a newly-started validator does not sign proposals older
|
||||
* than the last ledger it persisted. */
|
||||
virtual LedgerIndex getMaxDisallowedLedger() = 0;
|
||||
virtual LedgerIndex
|
||||
getMaxDisallowedLedger() = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr <Application>
|
||||
std::unique_ptr<Application>
|
||||
make_Application(
|
||||
std::unique_ptr<Config> config,
|
||||
std::unique_ptr<Logs> logs,
|
||||
std::unique_ptr<TimeKeeper> timeKeeper);
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,17 +22,16 @@
|
||||
|
||||
BasicApp::BasicApp(std::size_t numberOfThreads)
|
||||
{
|
||||
work_.emplace (io_service_);
|
||||
work_.emplace(io_service_);
|
||||
threads_.reserve(numberOfThreads);
|
||||
|
||||
while(numberOfThreads--)
|
||||
while (numberOfThreads--)
|
||||
{
|
||||
threads_.emplace_back([this, numberOfThreads]()
|
||||
{
|
||||
beast::setCurrentThreadName("io svc #" +
|
||||
std::to_string(numberOfThreads));
|
||||
this->io_service_.run();
|
||||
});
|
||||
threads_.emplace_back([this, numberOfThreads]() {
|
||||
beast::setCurrentThreadName(
|
||||
"io svc #" + std::to_string(numberOfThreads));
|
||||
this->io_service_.run();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,46 +22,47 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class CollectorManagerImp
|
||||
: public CollectorManager
|
||||
class CollectorManagerImp : public CollectorManager
|
||||
{
|
||||
public:
|
||||
beast::Journal m_journal;
|
||||
beast::insight::Collector::ptr m_collector;
|
||||
std::unique_ptr <beast::insight::Groups> m_groups;
|
||||
std::unique_ptr<beast::insight::Groups> m_groups;
|
||||
|
||||
CollectorManagerImp (Section const& params,
|
||||
beast::Journal journal)
|
||||
: m_journal (journal)
|
||||
CollectorManagerImp(Section const& params, beast::Journal journal)
|
||||
: m_journal(journal)
|
||||
{
|
||||
std::string const& server = get<std::string> (params, "server");
|
||||
std::string const& server = get<std::string>(params, "server");
|
||||
|
||||
if (server == "statsd")
|
||||
{
|
||||
beast::IP::Endpoint const address (beast::IP::Endpoint::from_string (
|
||||
get<std::string> (params, "address")));
|
||||
std::string const& prefix (get<std::string> (params, "prefix"));
|
||||
beast::IP::Endpoint const address(beast::IP::Endpoint::from_string(
|
||||
get<std::string>(params, "address")));
|
||||
std::string const& prefix(get<std::string>(params, "prefix"));
|
||||
|
||||
m_collector = beast::insight::StatsDCollector::New (address, prefix, journal);
|
||||
m_collector =
|
||||
beast::insight::StatsDCollector::New(address, prefix, journal);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_collector = beast::insight::NullCollector::New ();
|
||||
m_collector = beast::insight::NullCollector::New();
|
||||
}
|
||||
|
||||
m_groups = beast::insight::make_Groups (m_collector);
|
||||
m_groups = beast::insight::make_Groups(m_collector);
|
||||
}
|
||||
|
||||
~CollectorManagerImp() = default;
|
||||
|
||||
beast::insight::Collector::ptr const& collector () override
|
||||
beast::insight::Collector::ptr const&
|
||||
collector() override
|
||||
{
|
||||
return m_collector;
|
||||
}
|
||||
|
||||
beast::insight::Group::ptr const& group (std::string const& name) override
|
||||
beast::insight::Group::ptr const&
|
||||
group(std::string const& name) override
|
||||
{
|
||||
return m_groups->get (name);
|
||||
return m_groups->get(name);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -69,10 +70,10 @@ public:
|
||||
|
||||
CollectorManager::~CollectorManager() = default;
|
||||
|
||||
std::unique_ptr<CollectorManager> CollectorManager::New(Section const& params,
|
||||
beast::Journal journal)
|
||||
std::unique_ptr<CollectorManager>
|
||||
CollectorManager::New(Section const& params, beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<CollectorManagerImp>(params, journal);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
@@ -29,15 +29,16 @@ namespace ripple {
|
||||
class CollectorManager
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<CollectorManager> New (
|
||||
Section const& params, beast::Journal journal);
|
||||
static std::unique_ptr<CollectorManager>
|
||||
New(Section 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;
|
||||
virtual ~CollectorManager() = 0;
|
||||
virtual beast::insight::Collector::ptr const&
|
||||
collector() = 0;
|
||||
virtual beast::insight::Group::ptr const&
|
||||
group(std::string const& name) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,20 +27,17 @@ namespace ripple {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Ledger database holds ledgers and ledger confirmations
|
||||
inline constexpr auto LgrDBName {"ledger.db"};
|
||||
inline constexpr auto LgrDBName{"ledger.db"};
|
||||
|
||||
inline constexpr
|
||||
std::array<char const*, 3> LgrDBPragma {{
|
||||
"PRAGMA synchronous=NORMAL;",
|
||||
"PRAGMA journal_mode=WAL;",
|
||||
"PRAGMA journal_size_limit=1582080;"
|
||||
}};
|
||||
inline constexpr std::array<char const*, 3> LgrDBPragma{
|
||||
{"PRAGMA synchronous=NORMAL;",
|
||||
"PRAGMA journal_mode=WAL;",
|
||||
"PRAGMA journal_size_limit=1582080;"}};
|
||||
|
||||
inline constexpr
|
||||
std::array<char const*, 5> LgrDBInit {{
|
||||
"BEGIN TRANSACTION;",
|
||||
inline constexpr std::array<char const*, 5> LgrDBInit{
|
||||
{"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS Ledgers ( \
|
||||
"CREATE TABLE IF NOT EXISTS Ledgers ( \
|
||||
LedgerHash CHARACTER(64) PRIMARY KEY, \
|
||||
LedgerSeq BIGINT UNSIGNED, \
|
||||
PrevHash CHARACTER(64), \
|
||||
@@ -52,40 +49,40 @@ std::array<char const*, 5> LgrDBInit {{
|
||||
AccountSetHash CHARACTER(64), \
|
||||
TransSetHash CHARACTER(64) \
|
||||
);",
|
||||
"CREATE INDEX IF NOT EXISTS SeqLedger ON Ledgers(LedgerSeq);",
|
||||
"CREATE INDEX IF NOT EXISTS SeqLedger ON Ledgers(LedgerSeq);",
|
||||
|
||||
// Old table and indexes no longer needed
|
||||
"DROP TABLE IF EXISTS Validations;",
|
||||
// Old table and indexes no longer needed
|
||||
"DROP TABLE IF EXISTS Validations;",
|
||||
|
||||
"END TRANSACTION;"
|
||||
}};
|
||||
"END TRANSACTION;"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Transaction database holds transactions and public keys
|
||||
inline constexpr auto TxDBName {"transaction.db"};
|
||||
inline constexpr auto TxDBName{"transaction.db"};
|
||||
|
||||
inline constexpr
|
||||
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
|
||||
std::array<char const*, 6> TxDBPragma {{
|
||||
#if (ULONG_MAX > UINT_MAX) && !defined(NO_SQLITE_MMAP)
|
||||
std::array<char const*, 6>
|
||||
TxDBPragma
|
||||
{
|
||||
{
|
||||
#else
|
||||
std::array<char const*, 5> TxDBPragma {{
|
||||
#endif
|
||||
"PRAGMA page_size=4096;",
|
||||
"PRAGMA synchronous=NORMAL;",
|
||||
"PRAGMA journal_mode=WAL;",
|
||||
"PRAGMA journal_size_limit=1582080;",
|
||||
"PRAGMA max_page_count=2147483646;",
|
||||
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
|
||||
"PRAGMA mmap_size=17179869184;"
|
||||
"PRAGMA page_size=4096;", "PRAGMA synchronous=NORMAL;",
|
||||
"PRAGMA journal_mode=WAL;", "PRAGMA journal_size_limit=1582080;",
|
||||
"PRAGMA max_page_count=2147483646;",
|
||||
#if (ULONG_MAX > UINT_MAX) && !defined(NO_SQLITE_MMAP)
|
||||
"PRAGMA mmap_size=17179869184;"
|
||||
#endif
|
||||
}};
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr
|
||||
std::array<char const*, 8> TxDBInit {{
|
||||
"BEGIN TRANSACTION;",
|
||||
inline constexpr std::array<char const*, 8> TxDBInit{
|
||||
{"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS Transactions ( \
|
||||
"CREATE TABLE IF NOT EXISTS Transactions ( \
|
||||
TransID CHARACTER(64) PRIMARY KEY, \
|
||||
TransType CHARACTER(24), \
|
||||
FromAcct CHARACTER(35), \
|
||||
@@ -95,131 +92,111 @@ std::array<char const*, 8> TxDBInit {{
|
||||
RawTxn BLOB, \
|
||||
TxnMeta BLOB \
|
||||
);",
|
||||
"CREATE INDEX IF NOT EXISTS TxLgrIndex ON \
|
||||
"CREATE INDEX IF NOT EXISTS TxLgrIndex ON \
|
||||
Transactions(LedgerSeq);",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS AccountTransactions ( \
|
||||
"CREATE TABLE IF NOT EXISTS AccountTransactions ( \
|
||||
TransID CHARACTER(64), \
|
||||
Account CHARACTER(64), \
|
||||
LedgerSeq BIGINT UNSIGNED, \
|
||||
TxnSeq INTEGER \
|
||||
);",
|
||||
"CREATE INDEX IF NOT EXISTS AcctTxIDIndex ON \
|
||||
"CREATE INDEX IF NOT EXISTS AcctTxIDIndex ON \
|
||||
AccountTransactions(TransID);",
|
||||
"CREATE INDEX IF NOT EXISTS AcctTxIndex ON \
|
||||
"CREATE INDEX IF NOT EXISTS AcctTxIndex ON \
|
||||
AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);",
|
||||
"CREATE INDEX IF NOT EXISTS AcctLgrIndex ON \
|
||||
"CREATE INDEX IF NOT EXISTS AcctLgrIndex ON \
|
||||
AccountTransactions(LedgerSeq, Account, TransID);",
|
||||
|
||||
"END TRANSACTION;"
|
||||
}};
|
||||
"END TRANSACTION;"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Temporary database used with an incomplete shard that is being acquired
|
||||
inline constexpr auto AcquireShardDBName {"acquire.db"};
|
||||
inline constexpr auto AcquireShardDBName{"acquire.db"};
|
||||
|
||||
inline constexpr
|
||||
std::array<char const*, 3> AcquireShardDBPragma {{
|
||||
"PRAGMA synchronous=NORMAL;",
|
||||
"PRAGMA journal_mode=WAL;",
|
||||
"PRAGMA journal_size_limit=1582080;"
|
||||
}};
|
||||
inline constexpr std::array<char const*, 3> AcquireShardDBPragma{
|
||||
{"PRAGMA synchronous=NORMAL;",
|
||||
"PRAGMA journal_mode=WAL;",
|
||||
"PRAGMA journal_size_limit=1582080;"}};
|
||||
|
||||
inline constexpr
|
||||
std::array<char const*, 1> AcquireShardDBInit {{
|
||||
"CREATE TABLE IF NOT EXISTS Shard ( \
|
||||
inline constexpr std::array<char const*, 1> AcquireShardDBInit{
|
||||
{"CREATE TABLE IF NOT EXISTS Shard ( \
|
||||
ShardIndex INTEGER PRIMARY KEY, \
|
||||
LastLedgerHash CHARACTER(64), \
|
||||
StoredLedgerSeqs BLOB \
|
||||
);"
|
||||
}};
|
||||
);"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Pragma for Ledger and Transaction databases with complete shards
|
||||
inline constexpr
|
||||
std::array<char const*, 2> CompleteShardDBPragma{{
|
||||
"PRAGMA synchronous=OFF;",
|
||||
"PRAGMA journal_mode=OFF;"
|
||||
}};
|
||||
inline constexpr std::array<char const*, 2> CompleteShardDBPragma{
|
||||
{"PRAGMA synchronous=OFF;", "PRAGMA journal_mode=OFF;"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline constexpr auto WalletDBName {"wallet.db"};
|
||||
inline constexpr auto WalletDBName{"wallet.db"};
|
||||
|
||||
inline constexpr
|
||||
std::array<char const*, 6> WalletDBInit {{
|
||||
"BEGIN TRANSACTION;",
|
||||
inline constexpr std::array<char const*, 6> WalletDBInit{
|
||||
{"BEGIN TRANSACTION;",
|
||||
|
||||
// A node's identity must be persisted, including
|
||||
// for clustering purposes. This table holds one
|
||||
// entry: the server's unique identity, but the
|
||||
// value can be overriden by specifying a node
|
||||
// identity in the config file using a [node_seed]
|
||||
// entry.
|
||||
"CREATE TABLE IF NOT EXISTS NodeIdentity ( \
|
||||
// A node's identity must be persisted, including
|
||||
// for clustering purposes. This table holds one
|
||||
// entry: the server's unique identity, but the
|
||||
// value can be overriden by specifying a node
|
||||
// identity in the config file using a [node_seed]
|
||||
// entry.
|
||||
"CREATE TABLE IF NOT EXISTS NodeIdentity ( \
|
||||
PublicKey CHARACTER(53), \
|
||||
PrivateKey CHARACTER(52) \
|
||||
);",
|
||||
|
||||
// Peer reservations
|
||||
"CREATE TABLE IF NOT EXISTS PeerReservations ( \
|
||||
// Peer reservations
|
||||
"CREATE TABLE IF NOT EXISTS PeerReservations ( \
|
||||
PublicKey CHARACTER(53) UNIQUE NOT NULL, \
|
||||
Description CHARACTER(64) NOT NULL \
|
||||
);",
|
||||
|
||||
// Validator Manifests
|
||||
"CREATE TABLE IF NOT EXISTS ValidatorManifests ( \
|
||||
// Validator Manifests
|
||||
"CREATE TABLE IF NOT EXISTS ValidatorManifests ( \
|
||||
RawData BLOB NOT NULL \
|
||||
);",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS PublisherManifests ( \
|
||||
"CREATE TABLE IF NOT EXISTS PublisherManifests ( \
|
||||
RawData BLOB NOT NULL \
|
||||
);",
|
||||
|
||||
"END TRANSACTION;"
|
||||
}};
|
||||
"END TRANSACTION;"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static constexpr auto stateDBName {"state.db"};
|
||||
static constexpr auto stateDBName{"state.db"};
|
||||
|
||||
static constexpr
|
||||
std::array<char const*, 2> DownloaderDBPragma
|
||||
{{
|
||||
"PRAGMA synchronous=FULL;",
|
||||
"PRAGMA journal_mode=DELETE;"
|
||||
}};
|
||||
static constexpr std::array<char const*, 2> DownloaderDBPragma{
|
||||
{"PRAGMA synchronous=FULL;", "PRAGMA journal_mode=DELETE;"}};
|
||||
|
||||
static constexpr
|
||||
std::array<char const*, 3> ShardArchiveHandlerDBInit
|
||||
{{
|
||||
"BEGIN TRANSACTION;",
|
||||
static constexpr std::array<char const*, 3> ShardArchiveHandlerDBInit{
|
||||
{"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS State ( \
|
||||
"CREATE TABLE IF NOT EXISTS State ( \
|
||||
ShardIndex INTEGER PRIMARY KEY, \
|
||||
URL TEXT \
|
||||
);",
|
||||
|
||||
"END TRANSACTION;"
|
||||
}};
|
||||
"END TRANSACTION;"}};
|
||||
|
||||
static constexpr
|
||||
std::array<char const*, 3> DatabaseBodyDBInit
|
||||
{{
|
||||
"BEGIN TRANSACTION;",
|
||||
static constexpr std::array<char const*, 3> DatabaseBodyDBInit{
|
||||
{"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS download ( \
|
||||
"CREATE TABLE IF NOT EXISTS download ( \
|
||||
Path TEXT, \
|
||||
Data BLOB, \
|
||||
Size BIGINT UNSIGNED, \
|
||||
Part BIGINT UNSIGNED PRIMARY KEY \
|
||||
);",
|
||||
|
||||
"END TRANSACTION;"
|
||||
}};
|
||||
"END TRANSACTION;"}};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -100,15 +100,14 @@ GRPCServerImpl::CallData<Request, Response>::process()
|
||||
JobType::jtRPC,
|
||||
"gRPC-Client",
|
||||
[thisShared](std::shared_ptr<JobQueue::Coro> coro) {
|
||||
|
||||
thisShared->process(coro);
|
||||
});
|
||||
|
||||
// If coro is null, then the JobQueue has already been shutdown
|
||||
if (!coro)
|
||||
{
|
||||
grpc::Status status{grpc::StatusCode::INTERNAL,
|
||||
"Job Queue is already stopped"};
|
||||
grpc::Status status{
|
||||
grpc::StatusCode::INTERNAL, "Job Queue is already stopped"};
|
||||
responder_.FinishWithError(status, this);
|
||||
}
|
||||
}
|
||||
@@ -123,8 +122,9 @@ GRPCServerImpl::CallData<Request, Response>::process(
|
||||
auto usage = getUsage();
|
||||
if (usage.disconnect())
|
||||
{
|
||||
grpc::Status status{grpc::StatusCode::RESOURCE_EXHAUSTED,
|
||||
"usage balance exceeds threshhold"};
|
||||
grpc::Status status{
|
||||
grpc::StatusCode::RESOURCE_EXHAUSTED,
|
||||
"usage balance exceeds threshhold"};
|
||||
responder_.FinishWithError(status, this);
|
||||
}
|
||||
else
|
||||
@@ -133,16 +133,17 @@ GRPCServerImpl::CallData<Request, Response>::process(
|
||||
usage.charge(loadType);
|
||||
auto role = getRole();
|
||||
|
||||
RPC::GRPCContext<Request> context{{app_.journal("gRPCServer"),
|
||||
app_,
|
||||
loadType,
|
||||
app_.getOPs(),
|
||||
app_.getLedgerMaster(),
|
||||
usage,
|
||||
role,
|
||||
coro,
|
||||
InfoSub::pointer()},
|
||||
request_};
|
||||
RPC::GRPCContext<Request> context{
|
||||
{app_.journal("gRPCServer"),
|
||||
app_,
|
||||
loadType,
|
||||
app_.getOPs(),
|
||||
app_.getLedgerMaster(),
|
||||
usage,
|
||||
role,
|
||||
coro,
|
||||
InfoSub::pointer()},
|
||||
request_};
|
||||
|
||||
// Make sure we can currently handle the rpc
|
||||
error_code_i conditionMetRes =
|
||||
@@ -151,8 +152,9 @@ GRPCServerImpl::CallData<Request, Response>::process(
|
||||
if (conditionMetRes != rpcSUCCESS)
|
||||
{
|
||||
RPC::ErrorInfo errorInfo = RPC::get_error_info(conditionMetRes);
|
||||
grpc::Status status{grpc::StatusCode::FAILED_PRECONDITION,
|
||||
errorInfo.message.c_str()};
|
||||
grpc::Status status{
|
||||
grpc::StatusCode::FAILED_PRECONDITION,
|
||||
errorInfo.message.c_str()};
|
||||
responder_.FinishWithError(status, this);
|
||||
}
|
||||
else
|
||||
@@ -234,13 +236,13 @@ GRPCServerImpl::shutdown()
|
||||
{
|
||||
JLOG(journal_.debug()) << "Shutting down";
|
||||
|
||||
//The below call cancels all "listeners" (CallData objects that are waiting
|
||||
//for a request, as opposed to processing a request), and blocks until all
|
||||
//requests being processed are completed. CallData objects in the midst of
|
||||
//processing requests need to actually send data back to the client, via
|
||||
//responder_.Finish(...) or responder_.FinishWithError(...), for this call
|
||||
//to unblock. Each cancelled listener is returned via cq_.Next(...) with ok
|
||||
//set to false
|
||||
// The below call cancels all "listeners" (CallData objects that are waiting
|
||||
// for a request, as opposed to processing a request), and blocks until all
|
||||
// requests being processed are completed. CallData objects in the midst of
|
||||
// processing requests need to actually send data back to the client, via
|
||||
// responder_.Finish(...) or responder_.FinishWithError(...), for this call
|
||||
// to unblock. Each cancelled listener is returned via cq_.Next(...) with ok
|
||||
// set to false
|
||||
server_->Shutdown();
|
||||
JLOG(journal_.debug()) << "Server has been shutdown";
|
||||
|
||||
@@ -249,7 +251,6 @@ GRPCServerImpl::shutdown()
|
||||
// queue have been processed. See handleRpcs() for more details.
|
||||
cq_->Shutdown();
|
||||
JLOG(journal_.debug()) << "Completion Queue has been shutdown";
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -292,13 +293,12 @@ GRPCServerImpl::handleRpcs()
|
||||
{
|
||||
auto ptr = static_cast<Processor*>(tag);
|
||||
JLOG(journal_.trace()) << "Processing CallData object."
|
||||
<< " ptr = " << ptr
|
||||
<< " ok = " << ok;
|
||||
<< " ptr = " << ptr << " ok = " << ok;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Request listener cancelled. "
|
||||
<< "Destroying object";
|
||||
<< "Destroying object";
|
||||
erase(ptr);
|
||||
}
|
||||
else
|
||||
@@ -315,7 +315,6 @@ GRPCServerImpl::handleRpcs()
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
JLOG(journal_.debug()) << "Sent response. Destroying object";
|
||||
erase(ptr);
|
||||
}
|
||||
@@ -335,13 +334,16 @@ GRPCServerImpl::setupListeners()
|
||||
};
|
||||
|
||||
{
|
||||
using cd = CallData<org::xrpl::rpc::v1::GetFeeRequest, org::xrpl::rpc::v1::GetFeeResponse>;
|
||||
using cd = CallData<
|
||||
org::xrpl::rpc::v1::GetFeeRequest,
|
||||
org::xrpl::rpc::v1::GetFeeResponse>;
|
||||
|
||||
addToRequests(std::make_shared<cd>(
|
||||
service_,
|
||||
*cq_,
|
||||
app_,
|
||||
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetFee,
|
||||
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::
|
||||
RequestGetFee,
|
||||
doFeeGrpc,
|
||||
RPC::NEEDS_CURRENT_LEDGER,
|
||||
Resource::feeReferenceRPC));
|
||||
@@ -355,7 +357,8 @@ GRPCServerImpl::setupListeners()
|
||||
service_,
|
||||
*cq_,
|
||||
app_,
|
||||
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetAccountInfo,
|
||||
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::
|
||||
RequestGetAccountInfo,
|
||||
doAccountInfoGrpc,
|
||||
RPC::NO_CONDITION,
|
||||
Resource::feeReferenceRPC));
|
||||
@@ -369,7 +372,8 @@ GRPCServerImpl::setupListeners()
|
||||
service_,
|
||||
*cq_,
|
||||
app_,
|
||||
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetTransaction,
|
||||
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::
|
||||
RequestGetTransaction,
|
||||
doTxGrpc,
|
||||
RPC::NEEDS_CURRENT_LEDGER,
|
||||
Resource::feeReferenceRPC));
|
||||
|
||||
@@ -17,93 +17,101 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/main/LoadManager.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/main/LoadManager.h>
|
||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/basics/UptimeClock.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/beast/core/CurrentThreadName.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
LoadManager::LoadManager (
|
||||
Application& app, Stoppable& parent, beast::Journal journal)
|
||||
: Stoppable ("LoadManager", parent)
|
||||
, app_ (app)
|
||||
, journal_ (journal)
|
||||
, deadLock_ ()
|
||||
, armed_ (false)
|
||||
, stop_ (false)
|
||||
LoadManager::LoadManager(
|
||||
Application& app,
|
||||
Stoppable& parent,
|
||||
beast::Journal journal)
|
||||
: Stoppable("LoadManager", parent)
|
||||
, app_(app)
|
||||
, journal_(journal)
|
||||
, deadLock_()
|
||||
, armed_(false)
|
||||
, stop_(false)
|
||||
{
|
||||
}
|
||||
|
||||
LoadManager::~LoadManager ()
|
||||
LoadManager::~LoadManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
onStop ();
|
||||
onStop();
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
// Swallow the exception in a destructor.
|
||||
JLOG(journal_.warn()) << "std::exception in ~LoadManager. "
|
||||
<< ex.what();
|
||||
JLOG(journal_.warn())
|
||||
<< "std::exception in ~LoadManager. " << ex.what();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void LoadManager::activateDeadlockDetector ()
|
||||
void
|
||||
LoadManager::activateDeadlockDetector()
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
armed_ = true;
|
||||
deadLock_ = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void LoadManager::resetDeadlockDetector ()
|
||||
void
|
||||
LoadManager::resetDeadlockDetector()
|
||||
{
|
||||
auto const detector_start = std::chrono::steady_clock::now();
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
deadLock_ = detector_start;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void LoadManager::onPrepare ()
|
||||
void
|
||||
LoadManager::onPrepare()
|
||||
{
|
||||
}
|
||||
|
||||
void LoadManager::onStart ()
|
||||
void
|
||||
LoadManager::onStart()
|
||||
{
|
||||
JLOG(journal_.debug()) << "Starting";
|
||||
assert (! thread_.joinable());
|
||||
assert(!thread_.joinable());
|
||||
|
||||
thread_ = std::thread {&LoadManager::run, this};
|
||||
thread_ = std::thread{&LoadManager::run, this};
|
||||
}
|
||||
|
||||
void LoadManager::onStop ()
|
||||
void
|
||||
LoadManager::onStop()
|
||||
{
|
||||
if (thread_.joinable())
|
||||
{
|
||||
JLOG(journal_.debug()) << "Stopping";
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
stop_ = true;
|
||||
}
|
||||
thread_.join();
|
||||
}
|
||||
stopped ();
|
||||
stopped();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void LoadManager::run ()
|
||||
void
|
||||
LoadManager::run()
|
||||
{
|
||||
beast::setCurrentThreadName ("LoadManager");
|
||||
beast::setCurrentThreadName("LoadManager");
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using clock_type = std::chrono::system_clock;
|
||||
@@ -111,11 +119,11 @@ void LoadManager::run ()
|
||||
auto t = clock_type::now();
|
||||
bool stop = false;
|
||||
|
||||
while (! (stop || isStopping ()))
|
||||
while (!(stop || isStopping()))
|
||||
{
|
||||
{
|
||||
// Copy out shared data under a lock. Use copies outside lock.
|
||||
std::unique_lock<std::mutex> sl (mutex_);
|
||||
std::unique_lock<std::mutex> sl(mutex_);
|
||||
auto const deadLock = deadLock_;
|
||||
auto const armed = armed_;
|
||||
stop = stop_;
|
||||
@@ -131,8 +139,8 @@ void LoadManager::run ()
|
||||
constexpr auto deadlockLogicErrorTimeLimit = 600s;
|
||||
if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
|
||||
{
|
||||
|
||||
// Report the deadlocked condition every reportingIntervalSeconds
|
||||
// Report the deadlocked condition every
|
||||
// reportingIntervalSeconds
|
||||
if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
|
||||
{
|
||||
if (timeSpentDeadlocked < deadlockFatalLogMessageTimeLimit)
|
||||
@@ -154,9 +162,9 @@ void LoadManager::run ()
|
||||
}
|
||||
}
|
||||
|
||||
// If we go over the deadlockTimeLimit spent deadlocked, it means that
|
||||
// the deadlock resolution code has failed, which qualifies
|
||||
// as undefined behavior.
|
||||
// If we go over the deadlockTimeLimit spent deadlocked, it
|
||||
// means that the deadlock resolution code has failed, which
|
||||
// qualifies as undefined behavior.
|
||||
//
|
||||
if (timeSpentDeadlocked >= deadlockLogicErrorTimeLimit)
|
||||
{
|
||||
@@ -173,21 +181,21 @@ void LoadManager::run ()
|
||||
}
|
||||
|
||||
bool change = false;
|
||||
if (app_.getJobQueue ().isOverloaded ())
|
||||
if (app_.getJobQueue().isOverloaded())
|
||||
{
|
||||
JLOG(journal_.info()) << app_.getJobQueue ().getJson (0);
|
||||
change = app_.getFeeTrack ().raiseLocalFee ();
|
||||
JLOG(journal_.info()) << app_.getJobQueue().getJson(0);
|
||||
change = app_.getFeeTrack().raiseLocalFee();
|
||||
}
|
||||
else
|
||||
{
|
||||
change = app_.getFeeTrack ().lowerLocalFee ();
|
||||
change = app_.getFeeTrack().lowerLocalFee();
|
||||
}
|
||||
|
||||
if (change)
|
||||
{
|
||||
// VFALCO TODO replace this with a Listener / observer and
|
||||
// subscribe in NetworkOPs or Application.
|
||||
app_.getOPs ().reportFeeChange ();
|
||||
app_.getOPs().reportFeeChange();
|
||||
}
|
||||
|
||||
t += 1s;
|
||||
@@ -204,16 +212,15 @@ void LoadManager::run ()
|
||||
}
|
||||
}
|
||||
|
||||
stopped ();
|
||||
stopped();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::unique_ptr<LoadManager>
|
||||
make_LoadManager (Application& app,
|
||||
Stoppable& parent, beast::Journal journal)
|
||||
make_LoadManager(Application& app, Stoppable& parent, beast::Journal journal)
|
||||
{
|
||||
return std::unique_ptr<LoadManager>{new LoadManager{app, parent, journal}};
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -42,18 +42,19 @@ class Application;
|
||||
*/
|
||||
class LoadManager : public Stoppable
|
||||
{
|
||||
LoadManager (Application& app, Stoppable& parent, beast::Journal journal);
|
||||
LoadManager(Application& app, Stoppable& parent, beast::Journal journal);
|
||||
|
||||
public:
|
||||
LoadManager () = delete;
|
||||
LoadManager (LoadManager const&) = delete;
|
||||
LoadManager& operator=(LoadManager const&) = delete;
|
||||
LoadManager() = delete;
|
||||
LoadManager(LoadManager const&) = delete;
|
||||
LoadManager&
|
||||
operator=(LoadManager const&) = delete;
|
||||
|
||||
/** Destroy the manager.
|
||||
|
||||
The destructor returns only after the thread has stopped.
|
||||
*/
|
||||
~LoadManager ();
|
||||
~LoadManager();
|
||||
|
||||
/** Turn on deadlock detection.
|
||||
|
||||
@@ -67,47 +68,55 @@ public:
|
||||
// to prevent it from going off during program startup if
|
||||
// there's a lengthy initialization operation taking place?
|
||||
//
|
||||
void activateDeadlockDetector ();
|
||||
void
|
||||
activateDeadlockDetector();
|
||||
|
||||
/** Reset the deadlock detection timer.
|
||||
|
||||
A dedicated thread monitors the deadlock timer, and if too much
|
||||
time passes it will produce log warnings.
|
||||
*/
|
||||
void resetDeadlockDetector ();
|
||||
void
|
||||
resetDeadlockDetector();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Stoppable members
|
||||
void onPrepare () override;
|
||||
void
|
||||
onPrepare() override;
|
||||
|
||||
void onStart () override;
|
||||
void
|
||||
onStart() override;
|
||||
|
||||
void onStop () override;
|
||||
void
|
||||
onStop() override;
|
||||
|
||||
private:
|
||||
void run ();
|
||||
void
|
||||
run();
|
||||
|
||||
private:
|
||||
Application& app_;
|
||||
beast::Journal const journal_;
|
||||
|
||||
std::thread thread_;
|
||||
std::mutex mutex_; // Guards deadLock_, armed_, and stop_.
|
||||
std::mutex mutex_; // Guards deadLock_, armed_, and stop_.
|
||||
|
||||
std::chrono::steady_clock::time_point deadLock_; // Detect server deadlocks.
|
||||
std::chrono::steady_clock::time_point
|
||||
deadLock_; // Detect server deadlocks.
|
||||
bool armed_;
|
||||
bool stop_;
|
||||
|
||||
friend
|
||||
std::unique_ptr<LoadManager>
|
||||
make_LoadManager(Application& app, Stoppable& parent, beast::Journal journal);
|
||||
friend std::unique_ptr<LoadManager>
|
||||
make_LoadManager(
|
||||
Application& app,
|
||||
Stoppable& parent,
|
||||
beast::Journal journal);
|
||||
};
|
||||
|
||||
std::unique_ptr<LoadManager>
|
||||
make_LoadManager (
|
||||
Application& app, Stoppable& parent, beast::Journal journal);
|
||||
make_LoadManager(Application& app, Stoppable& parent, beast::Journal journal);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,25 +17,24 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/main/DBInit.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/basics/Sustain.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/beast/clock/basic_seconds_clock.h>
|
||||
#include <ripple/beast/core/CurrentThreadName.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/core/TimeKeeper.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/net/RPCCall.h>
|
||||
#include <ripple/protocol/BuildInfo.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <ripple/protocol/BuildInfo.h>
|
||||
#include <ripple/beast/clock/basic_seconds_clock.h>
|
||||
#include <ripple/beast/core/CurrentThreadName.h>
|
||||
|
||||
#include <beast/unit_test/match.hpp>
|
||||
#include <test/unit_test/multi_runner.h>
|
||||
@@ -43,18 +42,18 @@
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/predef.h>
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <sys/types.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
// Do we know the plaform we're compiling on? If you're adding new platforms
|
||||
@@ -64,9 +63,9 @@
|
||||
#endif
|
||||
|
||||
// Ensure that precisely one platform is detected.
|
||||
#if (BOOST_OS_LINUX && (BOOST_OS_WINDOWS || BOOST_OS_MACOS)) || \
|
||||
(BOOST_OS_MACOS && (BOOST_OS_WINDOWS || BOOST_OS_LINUX)) || \
|
||||
(BOOST_OS_WINDOWS && (BOOST_OS_LINUX || BOOST_OS_MACOS))
|
||||
#if (BOOST_OS_LINUX && (BOOST_OS_WINDOWS || BOOST_OS_MACOS)) || \
|
||||
(BOOST_OS_MACOS && (BOOST_OS_WINDOWS || BOOST_OS_LINUX)) || \
|
||||
(BOOST_OS_WINDOWS && (BOOST_OS_LINUX || BOOST_OS_MACOS))
|
||||
#error Multiple supported platforms appear active at once
|
||||
#endif
|
||||
|
||||
@@ -105,15 +104,12 @@ adjustDescriptorLimit(int needed, beast::Journal j)
|
||||
|
||||
if (needed > available)
|
||||
{
|
||||
j.fatal() <<
|
||||
"Insufficient number of file descriptors: " <<
|
||||
needed << " are needed, but only " <<
|
||||
available << " are available.";
|
||||
j.fatal() << "Insufficient number of file descriptors: " << needed
|
||||
<< " are needed, but only " << available << " are available.";
|
||||
|
||||
std::cerr <<
|
||||
"Insufficient number of file descriptors: " <<
|
||||
needed << " are needed, but only " <<
|
||||
available << " are available.\n";
|
||||
std::cerr << "Insufficient number of file descriptors: " << needed
|
||||
<< " are needed, but only " << available
|
||||
<< " are available.\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -122,30 +118,37 @@ adjustDescriptorLimit(int needed, beast::Journal j)
|
||||
return true;
|
||||
}
|
||||
|
||||
void printHelp (const po::options_description& desc)
|
||||
void
|
||||
printHelp(const po::options_description& desc)
|
||||
{
|
||||
std::cerr
|
||||
<< systemName () << "d [options] <command> <params>\n"
|
||||
<< systemName() << "d [options] <command> <params>\n"
|
||||
<< desc << std::endl
|
||||
<< "Commands: \n"
|
||||
" account_currencies <account> [<ledger>] [strict]\n"
|
||||
" account_info <account>|<seed>|<pass_phrase>|<key> [<ledger>] [strict]\n"
|
||||
" account_info <account>|<seed>|<pass_phrase>|<key> [<ledger>] "
|
||||
"[strict]\n"
|
||||
" account_lines <account> <account>|\"\" [<ledger>]\n"
|
||||
" account_channels <account> <account>|\"\" [<ledger>]\n"
|
||||
" account_objects <account> [<ledger>] [strict]\n"
|
||||
" account_offers <account>|<account_public_key> [<ledger>] [strict]\n"
|
||||
" account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]\n"
|
||||
" book_offers <taker_pays> <taker_gets> [<taker [<ledger> [<limit> [<proof> [<marker>]]]]]\n"
|
||||
" account_offers <account>|<account_public_key> [<ledger>] "
|
||||
"[strict]\n"
|
||||
" account_tx accountID [ledger_min [ledger_max [limit "
|
||||
"[offset]]]] [binary] [count] [descending]\n"
|
||||
" book_offers <taker_pays> <taker_gets> [<taker [<ledger> "
|
||||
"[<limit> [<proof> [<marker>]]]]]\n"
|
||||
" can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n"
|
||||
" channel_authorize <private_key> <channel_id> <drops>\n"
|
||||
" channel_verify <public_key> <channel_id> <drops> <signature>\n"
|
||||
" connect <ip> [<port>]\n"
|
||||
" consensus_info\n"
|
||||
" deposit_authorized <source_account> <destination_account> [<ledger>]\n"
|
||||
" deposit_authorized <source_account> <destination_account> "
|
||||
"[<ledger>]\n"
|
||||
" download_shard [[<index> <url>]]\n"
|
||||
" feature [<feature> [accept|reject]]\n"
|
||||
" fetch_info [clear]\n"
|
||||
" gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ <hotwallet> ]]\n"
|
||||
" gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ "
|
||||
"<hotwallet> ]]\n"
|
||||
" get_counts\n"
|
||||
" json <method> <json>\n"
|
||||
" ledger [<id>|current|closed|validated] [full]\n"
|
||||
@@ -167,7 +170,8 @@ void printHelp (const po::options_description& desc)
|
||||
" server_info [counters]\n"
|
||||
" server_state [counters]\n"
|
||||
" sign <private_key> <tx_json> [offline]\n"
|
||||
" sign_for <signer_address> <signer_private_key> <tx_json> [offline]\n"
|
||||
" sign_for <signer_address> <signer_private_key> <tx_json> "
|
||||
"[offline]\n"
|
||||
" stop\n"
|
||||
" submit <tx_blob>|[<private_key> <tx_json>]\n"
|
||||
" submit_multisigned <tx_json>\n"
|
||||
@@ -188,21 +192,19 @@ class multi_selector
|
||||
{
|
||||
private:
|
||||
std::vector<beast::unit_test::selector> selectors_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
multi_selector(std::string const& patterns = "")
|
||||
explicit multi_selector(std::string const& patterns = "")
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
boost::split (v, patterns, boost::algorithm::is_any_of (","));
|
||||
boost::split(v, patterns, boost::algorithm::is_any_of(","));
|
||||
selectors_.reserve(v.size());
|
||||
std::for_each(v.begin(), v.end(),
|
||||
[this](std::string s)
|
||||
{
|
||||
boost::trim (s);
|
||||
if (selectors_.empty() || !s.empty())
|
||||
selectors_.emplace_back(
|
||||
beast::unit_test::selector::automatch, s);
|
||||
});
|
||||
std::for_each(v.begin(), v.end(), [this](std::string s) {
|
||||
boost::trim(s);
|
||||
if (selectors_.empty() || !s.empty())
|
||||
selectors_.emplace_back(
|
||||
beast::unit_test::selector::automatch, s);
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -215,9 +217,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace test{ extern std::atomic<bool> envUseIPv4; }
|
||||
namespace test {
|
||||
extern std::atomic<bool> envUseIPv4;
|
||||
}
|
||||
|
||||
static int runUnitTests(
|
||||
static int
|
||||
runUnitTests(
|
||||
std::string const& pattern,
|
||||
std::string const& argument,
|
||||
bool quiet,
|
||||
@@ -231,7 +236,7 @@ static int runUnitTests(
|
||||
using namespace beast::unit_test;
|
||||
using namespace ripple::test;
|
||||
|
||||
ripple::test::envUseIPv4 = (! ipv6);
|
||||
ripple::test::envUseIPv4 = (!ipv6);
|
||||
|
||||
if (!child && num_jobs == 1)
|
||||
{
|
||||
@@ -264,7 +269,7 @@ static int runUnitTests(
|
||||
boost::process::exe = exe_name, boost::process::args = args);
|
||||
|
||||
int bad_child_exits = 0;
|
||||
for(auto& c : children)
|
||||
for (auto& c : children)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -298,21 +303,22 @@ static int runUnitTests(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int run (int argc, char** argv)
|
||||
int
|
||||
run(int argc, char** argv)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
beast::setCurrentThreadName ("rippled: main");
|
||||
beast::setCurrentThreadName("rippled: main");
|
||||
|
||||
po::variables_map vm;
|
||||
|
||||
std::string importText;
|
||||
{
|
||||
importText += "Import an existing node database (specified in the [";
|
||||
importText += ConfigSection::importNodeDatabase ();
|
||||
importText += ConfigSection::importNodeDatabase();
|
||||
importText += "] configuration file section) into the current ";
|
||||
importText += "node database (specified in the [";
|
||||
importText += ConfigSection::nodeDatabase ();
|
||||
importText += ConfigSection::nodeDatabase();
|
||||
importText += "] configuration file section).";
|
||||
}
|
||||
std::string shardsText;
|
||||
@@ -324,90 +330,97 @@ int run (int argc, char** argv)
|
||||
|
||||
// Set up option parsing.
|
||||
//
|
||||
po::options_description gen ("General Options");
|
||||
gen.add_options ()
|
||||
("conf", po::value<std::string> (), "Specify the configuration file.")
|
||||
("debug", "Enable normally suppressed debug logging")
|
||||
("fg", "Run in the foreground.")
|
||||
("help,h", "Display this message.")
|
||||
("quorum", po::value <std::size_t> (),
|
||||
"Override the minimum validation quorum.")
|
||||
("silent", "No output to the console after startup.")
|
||||
("standalone,a", "Run with no peers.")
|
||||
("verbose,v", "Verbose logging.")
|
||||
("version", "Display the build version.")
|
||||
;
|
||||
po::options_description gen("General Options");
|
||||
gen.add_options()(
|
||||
"conf", po::value<std::string>(), "Specify the configuration file.")(
|
||||
"debug", "Enable normally suppressed debug logging")(
|
||||
"fg", "Run in the foreground.")("help,h", "Display this message.")(
|
||||
"quorum",
|
||||
po::value<std::size_t>(),
|
||||
"Override the minimum validation quorum.")(
|
||||
"silent", "No output to the console after startup.")(
|
||||
"standalone,a", "Run with no peers.")("verbose,v", "Verbose logging.")(
|
||||
"version", "Display the build version.");
|
||||
|
||||
po::options_description data ("Ledger/Data Options");
|
||||
data.add_options ()
|
||||
("import", importText.c_str ())
|
||||
("ledger", po::value<std::string> (),
|
||||
"Load the specified ledger and start from the value given.")
|
||||
("ledgerfile", po::value<std::string> (), "Load the specified ledger file.")
|
||||
("load", "Load the current ledger from the local DB.")
|
||||
("net", "Get the initial ledger from the network.")
|
||||
("nodetoshard", "Import node store into shards")
|
||||
("replay","Replay a ledger close.")
|
||||
("start", "Start from a fresh Ledger.")
|
||||
("vacuum", po::value<std::string>(),
|
||||
po::options_description data("Ledger/Data Options");
|
||||
data.add_options()("import", importText.c_str())(
|
||||
"ledger",
|
||||
po::value<std::string>(),
|
||||
"Load the specified ledger and start from the value given.")(
|
||||
"ledgerfile",
|
||||
po::value<std::string>(),
|
||||
"Load the specified ledger file.")(
|
||||
"load", "Load the current ledger from the local DB.")(
|
||||
"net", "Get the initial ledger from the network.")(
|
||||
"nodetoshard", "Import node store into shards")(
|
||||
"replay", "Replay a ledger close.")(
|
||||
"start", "Start from a fresh Ledger.")(
|
||||
"vacuum",
|
||||
po::value<std::string>(),
|
||||
"VACUUM the transaction db. Mandatory string argument specifies "
|
||||
"temporary directory path.")
|
||||
("valid", "Consider the initial ledger a valid network ledger.")
|
||||
("validateShards", shardsText.c_str ())
|
||||
;
|
||||
"temporary directory path.")(
|
||||
"valid", "Consider the initial ledger a valid network ledger.")(
|
||||
"validateShards", shardsText.c_str());
|
||||
|
||||
po::options_description rpc ("RPC Client Options");
|
||||
rpc.add_options()
|
||||
("rpc",
|
||||
po::options_description rpc("RPC Client Options");
|
||||
rpc.add_options()(
|
||||
"rpc",
|
||||
"Perform rpc command - see below for available commands. "
|
||||
"This is assumed if any positional parameters are provided.")
|
||||
("rpc_ip", po::value <std::string> (),
|
||||
"This is assumed if any positional parameters are provided.")(
|
||||
"rpc_ip",
|
||||
po::value<std::string>(),
|
||||
"Specify the IP address for RPC command. "
|
||||
"Format: <ip-address>[':'<port-number>]")
|
||||
("rpc_port", po::value <std::uint16_t> (),
|
||||
"Format: <ip-address>[':'<port-number>]")(
|
||||
"rpc_port",
|
||||
po::value<std::uint16_t>(),
|
||||
"DEPRECATED: include with rpc_ip instead. "
|
||||
"Specify the port number for RPC command.")
|
||||
;
|
||||
"Specify the port number for RPC command.");
|
||||
|
||||
po::options_description test ("Unit Test Options");
|
||||
test.add_options()
|
||||
("quiet,q",
|
||||
po::options_description test("Unit Test Options");
|
||||
test.add_options()(
|
||||
"quiet,q",
|
||||
"Suppress test suite messages, "
|
||||
"including suite/case name (at start) and test log messages.")
|
||||
("unittest,u", po::value <std::string> ()->implicit_value (""),
|
||||
"including suite/case name (at start) and test log messages.")(
|
||||
"unittest,u",
|
||||
po::value<std::string>()->implicit_value(""),
|
||||
"Perform unit tests. The optional argument specifies one or "
|
||||
"more comma-separated selectors. Each selector specifies a suite name, "
|
||||
"full-name (lib.module.suite), module, or library "
|
||||
"(checked in that ""order).")
|
||||
("unittest-arg", po::value <std::string> ()->implicit_value (""),
|
||||
"(checked in that "
|
||||
"order).")(
|
||||
"unittest-arg",
|
||||
po::value<std::string>()->implicit_value(""),
|
||||
"Supplies an argument string to unit tests. If provided, this argument "
|
||||
"is made available to each suite that runs. Interpretation of the "
|
||||
"argument is handled individually by any suite that accesses it -- "
|
||||
"as such, it typically only make sense to provide this when running "
|
||||
"a single suite.")
|
||||
("unittest-ipv6", "Use IPv6 localhost when running unittests (default is IPv4).")
|
||||
("unittest-log",
|
||||
"a single suite.")(
|
||||
"unittest-ipv6",
|
||||
"Use IPv6 localhost when running unittests (default is IPv4).")(
|
||||
"unittest-log",
|
||||
"Force unit test log message output. Only useful in combination with "
|
||||
"--quiet, in which case log messages will print but suite/case names "
|
||||
"will not.")
|
||||
("unittest-jobs", po::value <std::size_t> (),
|
||||
"Number of unittest jobs to run in parallel (child processes).")
|
||||
;
|
||||
"will not.")(
|
||||
"unittest-jobs",
|
||||
po::value<std::size_t>(),
|
||||
"Number of unittest jobs to run in parallel (child processes).");
|
||||
|
||||
// These are hidden options, not intended to be shown in the usage/help message
|
||||
po::options_description hidden ("Hidden Options");
|
||||
hidden.add_options()
|
||||
("parameters", po::value< vector<string> > (),
|
||||
// These are hidden options, not intended to be shown in the usage/help
|
||||
// message
|
||||
po::options_description hidden("Hidden Options");
|
||||
hidden.add_options()(
|
||||
"parameters",
|
||||
po::value<vector<string>>(),
|
||||
"Specify rpc command and parameters. This option must be repeated "
|
||||
"for each command/param. Positional parameters also serve this purpose, "
|
||||
"so this option is not needed for users")
|
||||
("unittest-child",
|
||||
"For internal use only when spawning child unit test processes.")
|
||||
;
|
||||
"for each command/param. Positional parameters also serve this "
|
||||
"purpose, "
|
||||
"so this option is not needed for users")(
|
||||
"unittest-child",
|
||||
"For internal use only when spawning child unit test processes.");
|
||||
|
||||
// Interpret positional arguments as --parameters.
|
||||
po::positional_options_description p;
|
||||
p.add ("parameters", -1);
|
||||
p.add("parameters", -1);
|
||||
|
||||
po::options_description all;
|
||||
all.add(gen).add(rpc).add(data).add(test).add(hidden);
|
||||
@@ -418,12 +431,13 @@ int run (int argc, char** argv)
|
||||
// Parse options, if no error.
|
||||
try
|
||||
{
|
||||
po::store (po::command_line_parser (argc, argv)
|
||||
.options (all) // Parse options.
|
||||
.positional (p) // Remainder as --parameters.
|
||||
.run (),
|
||||
po::store(
|
||||
po::command_line_parser(argc, argv)
|
||||
.options(all) // Parse options.
|
||||
.positional(p) // Remainder as --parameters.
|
||||
.run(),
|
||||
vm);
|
||||
po::notify (vm); // Invoke option notify functions.
|
||||
po::notify(vm); // Invoke option notify functions.
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
@@ -432,23 +446,23 @@ int run (int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vm.count ("help"))
|
||||
if (vm.count("help"))
|
||||
{
|
||||
printHelp (desc);
|
||||
printHelp(desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm.count ("version"))
|
||||
if (vm.count("version"))
|
||||
{
|
||||
std::cout << "rippled version " <<
|
||||
BuildInfo::getVersionString () << std::endl;
|
||||
std::cout << "rippled version " << BuildInfo::getVersionString()
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Run the unit tests if requested.
|
||||
// The unit tests will exit the application with an appropriate return code.
|
||||
//
|
||||
if (vm.count ("unittest"))
|
||||
if (vm.count("unittest"))
|
||||
{
|
||||
std::string argument;
|
||||
|
||||
@@ -459,14 +473,15 @@ int run (int argc, char** argv)
|
||||
bool unittestChild = false;
|
||||
if (vm.count("unittest-jobs"))
|
||||
numJobs = std::max(numJobs, vm["unittest-jobs"].as<std::size_t>());
|
||||
unittestChild = bool (vm.count("unittest-child"));
|
||||
unittestChild = bool(vm.count("unittest-child"));
|
||||
|
||||
return runUnitTests(
|
||||
vm["unittest"].as<std::string>(), argument,
|
||||
bool (vm.count ("quiet")),
|
||||
bool (vm.count ("unittest-log")),
|
||||
vm["unittest"].as<std::string>(),
|
||||
argument,
|
||||
bool(vm.count("quiet")),
|
||||
bool(vm.count("unittest-log")),
|
||||
unittestChild,
|
||||
bool (vm.count ("unittest-ipv6")),
|
||||
bool(vm.count("unittest-ipv6")),
|
||||
numJobs,
|
||||
argc,
|
||||
argv);
|
||||
@@ -476,20 +491,25 @@ int run (int argc, char** argv)
|
||||
if (vm.count("unittest-jobs"))
|
||||
{
|
||||
// unittest jobs only makes sense with `unittest`
|
||||
std::cerr << "rippled: '--unittest-jobs' specified without '--unittest'.\n";
|
||||
std::cerr << "To run the unit tests the '--unittest' option must be present.\n";
|
||||
std::cerr << "rippled: '--unittest-jobs' specified without "
|
||||
"'--unittest'.\n";
|
||||
std::cerr << "To run the unit tests the '--unittest' option must "
|
||||
"be present.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto config = std::make_unique<Config>();
|
||||
|
||||
auto configFile = vm.count ("conf") ?
|
||||
vm["conf"].as<std::string> () : std::string();
|
||||
auto configFile =
|
||||
vm.count("conf") ? vm["conf"].as<std::string>() : std::string();
|
||||
|
||||
// config file, quiet flag.
|
||||
config->setup (configFile, bool (vm.count ("quiet")),
|
||||
bool(vm.count("silent")), bool(vm.count("standalone")));
|
||||
config->setup(
|
||||
configFile,
|
||||
bool(vm.count("quiet")),
|
||||
bool(vm.count("silent")),
|
||||
bool(vm.count("standalone")));
|
||||
|
||||
if (vm.count("vacuum"))
|
||||
{
|
||||
@@ -516,8 +536,7 @@ int run (int argc, char** argv)
|
||||
"as much free space as the size of "
|
||||
<< dbPath.string() << ", which is " << dbSize
|
||||
<< " bytes. The filesystem for " << tmpPath.string()
|
||||
<< " only has "
|
||||
<< space(tmpPath).available
|
||||
<< " only has " << space(tmpPath).available
|
||||
<< " bytes.\n";
|
||||
return -1;
|
||||
}
|
||||
@@ -529,71 +548,71 @@ int run (int argc, char** argv)
|
||||
|
||||
session << "PRAGMA page_size;", soci::into(pageSize);
|
||||
|
||||
std::cout << "VACUUM beginning. page_size: " <<
|
||||
pageSize << std::endl;
|
||||
std::cout << "VACUUM beginning. page_size: " << pageSize
|
||||
<< std::endl;
|
||||
|
||||
session << "PRAGMA journal_mode=OFF;";
|
||||
session << "PRAGMA temp_store_directory=\"" <<
|
||||
tmpPath.string() << "\";";
|
||||
session << "PRAGMA temp_store_directory=\"" << tmpPath.string()
|
||||
<< "\";";
|
||||
session << "VACUUM;";
|
||||
session << "PRAGMA journal_mode=WAL;";
|
||||
session << "PRAGMA page_size;", soci::into(pageSize);
|
||||
|
||||
std::cout << "VACUUM finished. page_size: " <<
|
||||
pageSize << std::endl;
|
||||
std::cout << "VACUUM finished. page_size: " << pageSize
|
||||
<< std::endl;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
std::cerr << "exception " << e.what() <<
|
||||
" in function " << __func__ << std::endl;
|
||||
std::cerr << "exception " << e.what() << " in function " << __func__
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm.count ("start"))
|
||||
if (vm.count("start"))
|
||||
config->START_UP = Config::FRESH;
|
||||
|
||||
if (vm.count ("import"))
|
||||
if (vm.count("import"))
|
||||
config->doImport = true;
|
||||
|
||||
if (vm.count("nodetoshard"))
|
||||
config->nodeToShard = true;
|
||||
|
||||
if (vm.count ("validateShards"))
|
||||
if (vm.count("validateShards"))
|
||||
config->validateShards = true;
|
||||
|
||||
if (vm.count ("ledger"))
|
||||
if (vm.count("ledger"))
|
||||
{
|
||||
config->START_LEDGER = vm["ledger"].as<std::string> ();
|
||||
config->START_LEDGER = vm["ledger"].as<std::string>();
|
||||
if (vm.count("replay"))
|
||||
config->START_UP = Config::REPLAY;
|
||||
else
|
||||
config->START_UP = Config::LOAD;
|
||||
}
|
||||
else if (vm.count ("ledgerfile"))
|
||||
else if (vm.count("ledgerfile"))
|
||||
{
|
||||
config->START_LEDGER = vm["ledgerfile"].as<std::string> ();
|
||||
config->START_LEDGER = vm["ledgerfile"].as<std::string>();
|
||||
config->START_UP = Config::LOAD_FILE;
|
||||
}
|
||||
else if (vm.count ("load"))
|
||||
else if (vm.count("load"))
|
||||
{
|
||||
config->START_UP = Config::LOAD;
|
||||
}
|
||||
|
||||
if (vm.count ("valid"))
|
||||
if (vm.count("valid"))
|
||||
{
|
||||
config->START_VALID = true;
|
||||
}
|
||||
|
||||
if (vm.count ("net"))
|
||||
if (vm.count("net"))
|
||||
{
|
||||
if ((config->START_UP == Config::LOAD) ||
|
||||
(config->START_UP == Config::REPLAY))
|
||||
{
|
||||
std::cerr <<
|
||||
"Net and load/reply options are incompatible" << std::endl;
|
||||
std::cerr << "Net and load/reply options are incompatible"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -602,31 +621,31 @@ int run (int argc, char** argv)
|
||||
|
||||
// Override the RPC destination IP address. This must
|
||||
// happen after the config file is loaded.
|
||||
if (vm.count ("rpc_ip"))
|
||||
if (vm.count("rpc_ip"))
|
||||
{
|
||||
auto endpoint = beast::IP::Endpoint::from_string_checked(
|
||||
vm["rpc_ip"].as<std::string>());
|
||||
if (! endpoint)
|
||||
if (!endpoint)
|
||||
{
|
||||
std::cerr << "Invalid rpc_ip = " <<
|
||||
vm["rpc_ip"].as<std::string>() << "\n";
|
||||
std::cerr << "Invalid rpc_ip = " << vm["rpc_ip"].as<std::string>()
|
||||
<< "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (endpoint->port() == 0)
|
||||
{
|
||||
std::cerr << "No port specified in rpc_ip.\n";
|
||||
if (vm.count ("rpc_port"))
|
||||
if (vm.count("rpc_port"))
|
||||
{
|
||||
std::cerr << "WARNING: using deprecated rpc_port param.\n";
|
||||
try
|
||||
{
|
||||
endpoint = endpoint->at_port(
|
||||
vm["rpc_port"].as<std::uint16_t>());
|
||||
endpoint =
|
||||
endpoint->at_port(vm["rpc_port"].as<std::uint16_t>());
|
||||
if (endpoint->port() == 0)
|
||||
throw std::domain_error("0");
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
std::cerr << "Invalid rpc_port = " << e.what() << "\n";
|
||||
return -1;
|
||||
@@ -639,20 +658,20 @@ int run (int argc, char** argv)
|
||||
config->rpc_ip = std::move(*endpoint);
|
||||
}
|
||||
|
||||
if (vm.count ("quorum"))
|
||||
if (vm.count("quorum"))
|
||||
{
|
||||
try
|
||||
{
|
||||
config->VALIDATION_QUORUM = vm["quorum"].as <std::size_t> ();
|
||||
config->VALIDATION_QUORUM = vm["quorum"].as<std::size_t>();
|
||||
if (config->VALIDATION_QUORUM == std::size_t{})
|
||||
{
|
||||
throw std::domain_error("0");
|
||||
}
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
std::cerr << "Invalid value specified for --quorum ("
|
||||
<< e.what() << ")\n";
|
||||
std::cerr << "Invalid value specified for --quorum (" << e.what()
|
||||
<< ")\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -661,25 +680,27 @@ int run (int argc, char** argv)
|
||||
using namespace beast::severities;
|
||||
Severity thresh = kInfo;
|
||||
|
||||
if (vm.count ("quiet"))
|
||||
if (vm.count("quiet"))
|
||||
thresh = kFatal;
|
||||
else if (vm.count ("verbose"))
|
||||
else if (vm.count("verbose"))
|
||||
thresh = kTrace;
|
||||
|
||||
auto logs = std::make_unique<Logs>(thresh);
|
||||
|
||||
// No arguments. Run server.
|
||||
if (!vm.count ("parameters"))
|
||||
if (!vm.count("parameters"))
|
||||
{
|
||||
// TODO: this comment can be removed in a future release -
|
||||
// say 1.7 or higher
|
||||
if (config->had_trailing_comments())
|
||||
{
|
||||
JLOG(logs->journal("Application").warn()) <<
|
||||
"Trailing comments were seen in your config file. " <<
|
||||
"The treatment of inline/trailing comments has changed recently. " <<
|
||||
"Any `#` characters NOT intended to delimit comments should be " <<
|
||||
"preceded by a \\";
|
||||
JLOG(logs->journal("Application").warn())
|
||||
<< "Trailing comments were seen in your config file. "
|
||||
<< "The treatment of inline/trailing comments has changed "
|
||||
"recently. "
|
||||
<< "Any `#` characters NOT intended to delimit comments should "
|
||||
"be "
|
||||
<< "preceded by a \\";
|
||||
}
|
||||
|
||||
// We want at least 1024 file descriptors. We'll
|
||||
@@ -687,29 +708,25 @@ int run (int argc, char** argv)
|
||||
if (!adjustDescriptorLimit(1024, logs->journal("Application")))
|
||||
return -1;
|
||||
|
||||
if (HaveSustain() && !vm.count ("fg") && !config->standalone())
|
||||
if (HaveSustain() && !vm.count("fg") && !config->standalone())
|
||||
{
|
||||
auto const ret = DoSustain ();
|
||||
auto const ret = DoSustain();
|
||||
|
||||
if (!ret.empty ())
|
||||
if (!ret.empty())
|
||||
std::cerr << "Watchdog: " << ret << std::endl;
|
||||
}
|
||||
|
||||
if (vm.count ("debug"))
|
||||
if (vm.count("debug"))
|
||||
{
|
||||
setDebugLogSink (logs->makeSink (
|
||||
"Debug", beast::severities::kTrace));
|
||||
setDebugLogSink(logs->makeSink("Debug", beast::severities::kTrace));
|
||||
}
|
||||
|
||||
auto timeKeeper = make_TimeKeeper(
|
||||
logs->journal("TimeKeeper"));
|
||||
auto timeKeeper = make_TimeKeeper(logs->journal("TimeKeeper"));
|
||||
|
||||
auto app = make_Application(
|
||||
std::move(config),
|
||||
std::move(logs),
|
||||
std::move(timeKeeper));
|
||||
std::move(config), std::move(logs), std::move(timeKeeper));
|
||||
|
||||
if (!app->setup ())
|
||||
if (!app->setup())
|
||||
{
|
||||
StopSustain();
|
||||
return -1;
|
||||
@@ -718,8 +735,7 @@ int run (int argc, char** argv)
|
||||
// With our configuration parsed, ensure we have
|
||||
// enough file descriptors available:
|
||||
if (!adjustDescriptorLimit(
|
||||
app->fdRequired(),
|
||||
app->logs().journal("Application")))
|
||||
app->fdRequired(), app->logs().journal("Application")))
|
||||
{
|
||||
StopSustain();
|
||||
return -1;
|
||||
@@ -735,18 +751,17 @@ int run (int argc, char** argv)
|
||||
}
|
||||
|
||||
// We have an RPC command to process:
|
||||
beast::setCurrentThreadName ("rippled: rpc");
|
||||
return RPCCall::fromCommandLine (
|
||||
*config,
|
||||
vm["parameters"].as<std::vector<std::string>>(),
|
||||
*logs);
|
||||
beast::setCurrentThreadName("rippled: rpc");
|
||||
return RPCCall::fromCommandLine(
|
||||
*config, vm["parameters"].as<std::vector<std::string>>(), *logs);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
// Must be outside the namespace for obvious reasons
|
||||
//
|
||||
int main (int argc, char** argv)
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
{
|
||||
@@ -758,18 +773,18 @@ int main (int argc, char** argv)
|
||||
// coroutines. At the time of this writing the _ftime call is
|
||||
// used to initialize the timezone information.
|
||||
struct _timeb t;
|
||||
#ifdef _INC_TIME_INL
|
||||
_ftime_s (&t);
|
||||
#else
|
||||
_ftime (&t);
|
||||
#endif
|
||||
#ifdef _INC_TIME_INL
|
||||
_ftime_s(&t);
|
||||
#else
|
||||
_ftime(&t);
|
||||
#endif
|
||||
}
|
||||
ripple::sha512_deprecatedMSVCWorkaround();
|
||||
#endif
|
||||
|
||||
atexit(&google::protobuf::ShutdownProtobufLibrary);
|
||||
|
||||
auto const result (ripple::run (argc, argv));
|
||||
auto const result(ripple::run(argc, argv));
|
||||
|
||||
beast::basic_seconds_clock_main_hook();
|
||||
|
||||
|
||||
@@ -17,19 +17,19 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/main/NodeIdentity.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::pair<PublicKey, SecretKey>
|
||||
loadNodeIdentity (Application& app)
|
||||
loadNodeIdentity(Application& app)
|
||||
{
|
||||
// If a seed is specified in the configuration file use that directly.
|
||||
if (app.config().exists(SECTION_NODE_SEED))
|
||||
@@ -38,31 +38,29 @@ loadNodeIdentity (Application& app)
|
||||
app.config().section(SECTION_NODE_SEED).lines().front());
|
||||
|
||||
if (!seed)
|
||||
Throw<std::runtime_error>(
|
||||
"NodeIdentity: Bad [" SECTION_NODE_SEED "] specified");
|
||||
Throw<std::runtime_error>("NodeIdentity: Bad [" SECTION_NODE_SEED
|
||||
"] specified");
|
||||
|
||||
auto secretKey =
|
||||
generateSecretKey (KeyType::secp256k1, *seed);
|
||||
auto publicKey =
|
||||
derivePublicKey (KeyType::secp256k1, secretKey);
|
||||
auto secretKey = generateSecretKey(KeyType::secp256k1, *seed);
|
||||
auto publicKey = derivePublicKey(KeyType::secp256k1, secretKey);
|
||||
|
||||
return { publicKey, secretKey };
|
||||
return {publicKey, secretKey};
|
||||
}
|
||||
|
||||
// Try to load a node identity from the database:
|
||||
boost::optional<PublicKey> publicKey;
|
||||
boost::optional<SecretKey> secretKey;
|
||||
|
||||
auto db = app.getWalletDB ().checkoutDb ();
|
||||
auto db = app.getWalletDB().checkoutDb();
|
||||
|
||||
{
|
||||
boost::optional<std::string> pubKO, priKO;
|
||||
soci::statement st = (db->prepare <<
|
||||
"SELECT PublicKey, PrivateKey FROM NodeIdentity;",
|
||||
soci::into(pubKO),
|
||||
soci::into(priKO));
|
||||
st.execute ();
|
||||
while (st.fetch ())
|
||||
soci::statement st =
|
||||
(db->prepare << "SELECT PublicKey, PrivateKey FROM NodeIdentity;",
|
||||
soci::into(pubKO),
|
||||
soci::into(priKO));
|
||||
st.execute();
|
||||
while (st.fetch())
|
||||
{
|
||||
auto const sk = parseBase58<SecretKey>(
|
||||
TokenType::NodePrivate, priKO.value_or(""));
|
||||
@@ -70,7 +68,7 @@ loadNodeIdentity (Application& app)
|
||||
TokenType::NodePublic, pubKO.value_or(""));
|
||||
|
||||
// Only use if the public and secret keys are a pair
|
||||
if (sk && pk && (*pk == derivePublicKey (KeyType::secp256k1, *sk)))
|
||||
if (sk && pk && (*pk == derivePublicKey(KeyType::secp256k1, *sk)))
|
||||
{
|
||||
secretKey = sk;
|
||||
publicKey = pk;
|
||||
@@ -83,13 +81,14 @@ loadNodeIdentity (Application& app)
|
||||
{
|
||||
std::tie(publicKey, secretKey) = randomKeyPair(KeyType::secp256k1);
|
||||
|
||||
*db << str (boost::format (
|
||||
"INSERT INTO NodeIdentity (PublicKey,PrivateKey) VALUES ('%s','%s');")
|
||||
% toBase58 (TokenType::NodePublic, *publicKey)
|
||||
% toBase58 (TokenType::NodePrivate, *secretKey));
|
||||
*db << str(
|
||||
boost::format("INSERT INTO NodeIdentity (PublicKey,PrivateKey) "
|
||||
"VALUES ('%s','%s');") %
|
||||
toBase58(TokenType::NodePublic, *publicKey) %
|
||||
toBase58(TokenType::NodePrivate, *secretKey));
|
||||
}
|
||||
|
||||
return { *publicKey, *secretKey };
|
||||
return {*publicKey, *secretKey};
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace ripple {
|
||||
|
||||
/** The cryptographic credentials identifying this server instance. */
|
||||
std::pair<PublicKey, SecretKey>
|
||||
loadNodeIdentity (Application& app);
|
||||
loadNodeIdentity(Application& app);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,43 +22,47 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
NodeStoreScheduler::NodeStoreScheduler (Stoppable& parent)
|
||||
: Stoppable ("NodeStoreScheduler", parent)
|
||||
NodeStoreScheduler::NodeStoreScheduler(Stoppable& parent)
|
||||
: Stoppable("NodeStoreScheduler", parent)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeStoreScheduler::setJobQueue (JobQueue& jobQueue)
|
||||
void
|
||||
NodeStoreScheduler::setJobQueue(JobQueue& jobQueue)
|
||||
{
|
||||
m_jobQueue = &jobQueue;
|
||||
}
|
||||
|
||||
void NodeStoreScheduler::onStop ()
|
||||
void
|
||||
NodeStoreScheduler::onStop()
|
||||
{
|
||||
}
|
||||
|
||||
void NodeStoreScheduler::onChildrenStopped ()
|
||||
void
|
||||
NodeStoreScheduler::onChildrenStopped()
|
||||
{
|
||||
assert (m_taskCount == 0);
|
||||
stopped ();
|
||||
assert(m_taskCount == 0);
|
||||
stopped();
|
||||
}
|
||||
|
||||
void NodeStoreScheduler::scheduleTask (NodeStore::Task& task)
|
||||
void
|
||||
NodeStoreScheduler::scheduleTask(NodeStore::Task& task)
|
||||
{
|
||||
++m_taskCount;
|
||||
if (!m_jobQueue->addJob (
|
||||
jtWRITE,
|
||||
"NodeObject::store",
|
||||
[this, &task] (Job&) { doTask(task); }))
|
||||
if (!m_jobQueue->addJob(jtWRITE, "NodeObject::store", [this, &task](Job&) {
|
||||
doTask(task);
|
||||
}))
|
||||
{
|
||||
// Job not added, presumably because we're shutting down.
|
||||
// Recover by executing the task synchronously.
|
||||
doTask (task);
|
||||
doTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeStoreScheduler::doTask (NodeStore::Task& task)
|
||||
void
|
||||
NodeStoreScheduler::doTask(NodeStore::Task& task)
|
||||
{
|
||||
task.performScheduledTask ();
|
||||
task.performScheduledTask();
|
||||
|
||||
// NOTE: It feels a bit off that there are two different methods that
|
||||
// call stopped(): onChildrenStopped() and doTask(). There's a
|
||||
@@ -71,18 +75,20 @@ void NodeStoreScheduler::doTask (NodeStore::Task& task)
|
||||
stopped();
|
||||
}
|
||||
|
||||
void NodeStoreScheduler::onFetch (NodeStore::FetchReport const& report)
|
||||
void
|
||||
NodeStoreScheduler::onFetch(NodeStore::FetchReport const& report)
|
||||
{
|
||||
if (report.wentToDisk)
|
||||
m_jobQueue->addLoadEvents (
|
||||
m_jobQueue->addLoadEvents(
|
||||
report.isAsync ? jtNS_ASYNC_READ : jtNS_SYNC_READ,
|
||||
1, report.elapsed);
|
||||
1,
|
||||
report.elapsed);
|
||||
}
|
||||
|
||||
void NodeStoreScheduler::onBatchWrite (NodeStore::BatchWriteReport const& report)
|
||||
void
|
||||
NodeStoreScheduler::onBatchWrite(NodeStore::BatchWriteReport const& report)
|
||||
{
|
||||
m_jobQueue->addLoadEvents (jtNS_WRITE,
|
||||
report.writeCount, report.elapsed);
|
||||
m_jobQueue->addLoadEvents(jtNS_WRITE, report.writeCount, report.elapsed);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -20,39 +20,45 @@
|
||||
#ifndef RIPPLE_APP_MAIN_NODESTORESCHEDULER_H_INCLUDED
|
||||
#define RIPPLE_APP_MAIN_NODESTORESCHEDULER_H_INCLUDED
|
||||
|
||||
#include <ripple/nodestore/Scheduler.h>
|
||||
#include <ripple/core/JobQueue.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/nodestore/Scheduler.h>
|
||||
#include <atomic>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** A NodeStore::Scheduler which uses the JobQueue and implements the Stoppable API. */
|
||||
class NodeStoreScheduler
|
||||
: public NodeStore::Scheduler
|
||||
, public Stoppable
|
||||
/** A NodeStore::Scheduler which uses the JobQueue and implements the Stoppable
|
||||
* API. */
|
||||
class NodeStoreScheduler : public NodeStore::Scheduler, public Stoppable
|
||||
{
|
||||
public:
|
||||
NodeStoreScheduler (Stoppable& parent);
|
||||
NodeStoreScheduler(Stoppable& parent);
|
||||
|
||||
// VFALCO NOTE This is a temporary hack to solve the problem
|
||||
// of circular dependency.
|
||||
//
|
||||
void setJobQueue (JobQueue& jobQueue);
|
||||
void
|
||||
setJobQueue(JobQueue& jobQueue);
|
||||
|
||||
void onStop () override;
|
||||
void onChildrenStopped () override;
|
||||
void scheduleTask (NodeStore::Task& task) override;
|
||||
void onFetch (NodeStore::FetchReport const& report) override;
|
||||
void onBatchWrite (NodeStore::BatchWriteReport const& report) override;
|
||||
void
|
||||
onStop() override;
|
||||
void
|
||||
onChildrenStopped() override;
|
||||
void
|
||||
scheduleTask(NodeStore::Task& task) override;
|
||||
void
|
||||
onFetch(NodeStore::FetchReport const& report) override;
|
||||
void
|
||||
onBatchWrite(NodeStore::BatchWriteReport const& report) override;
|
||||
|
||||
private:
|
||||
void doTask (NodeStore::Task& task);
|
||||
void
|
||||
doTask(NodeStore::Task& task);
|
||||
|
||||
JobQueue* m_jobQueue {nullptr};
|
||||
std::atomic <int> m_taskCount {0};
|
||||
JobQueue* m_jobQueue{nullptr};
|
||||
std::atomic<int> m_taskCount{0};
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,6 @@ namespace ripple {
|
||||
constexpr std::size_t fullBelowTargetSize = 524288;
|
||||
constexpr std::chrono::seconds fullBelowExpiration = std::chrono::minutes{10};
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#define RIPPLE_APP_MISC_AMENDMENTTABLE_H_INCLUDED
|
||||
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -36,16 +36,23 @@ class AmendmentTable
|
||||
public:
|
||||
virtual ~AmendmentTable() = default;
|
||||
|
||||
virtual uint256 find (std::string const& name) = 0;
|
||||
virtual uint256
|
||||
find(std::string const& name) = 0;
|
||||
|
||||
virtual bool veto (uint256 const& amendment) = 0;
|
||||
virtual bool unVeto (uint256 const& amendment) = 0;
|
||||
virtual bool
|
||||
veto(uint256 const& amendment) = 0;
|
||||
virtual bool
|
||||
unVeto(uint256 const& amendment) = 0;
|
||||
|
||||
virtual bool enable (uint256 const& amendment) = 0;
|
||||
virtual bool disable (uint256 const& amendment) = 0;
|
||||
virtual bool
|
||||
enable(uint256 const& amendment) = 0;
|
||||
virtual bool
|
||||
disable(uint256 const& amendment) = 0;
|
||||
|
||||
virtual bool isEnabled (uint256 const& amendment) = 0;
|
||||
virtual bool isSupported (uint256 const& amendment) = 0;
|
||||
virtual bool
|
||||
isEnabled(uint256 const& amendment) = 0;
|
||||
virtual bool
|
||||
isSupported(uint256 const& amendment) = 0;
|
||||
|
||||
/**
|
||||
* @brief returns true if one or more amendments on the network
|
||||
@@ -53,14 +60,17 @@ public:
|
||||
*
|
||||
* @return true if an unsupported feature is enabled on the network
|
||||
*/
|
||||
virtual bool hasUnsupportedEnabled () = 0;
|
||||
virtual bool
|
||||
hasUnsupportedEnabled() = 0;
|
||||
virtual boost::optional<NetClock::time_point>
|
||||
firstUnsupportedExpected() = 0;
|
||||
|
||||
virtual Json::Value getJson (int) = 0;
|
||||
virtual Json::Value
|
||||
getJson(int) = 0;
|
||||
|
||||
/** Returns a Json::objectValue. */
|
||||
virtual Json::Value getJson (uint256 const& ) = 0;
|
||||
virtual Json::Value
|
||||
getJson(uint256 const&) = 0;
|
||||
|
||||
/** Called when a new fully-validated ledger is accepted. */
|
||||
void
|
||||
@@ -78,34 +88,34 @@ public:
|
||||
a new validated ledger. (If it could have changed things.)
|
||||
*/
|
||||
virtual bool
|
||||
needValidatedLedger (LedgerIndex seq) = 0;
|
||||
needValidatedLedger(LedgerIndex seq) = 0;
|
||||
|
||||
virtual void
|
||||
doValidatedLedger (
|
||||
doValidatedLedger(
|
||||
LedgerIndex ledgerSeq,
|
||||
std::set <uint256> const& enabled,
|
||||
std::set<uint256> const& enabled,
|
||||
majorityAmendments_t const& majority) = 0;
|
||||
|
||||
// Called by the consensus code when we need to
|
||||
// inject pseudo-transactions
|
||||
virtual std::map <uint256, std::uint32_t>
|
||||
doVoting (
|
||||
virtual std::map<uint256, std::uint32_t>
|
||||
doVoting(
|
||||
NetClock::time_point closeTime,
|
||||
std::set <uint256> const& enabledAmendments,
|
||||
std::set<uint256> const& enabledAmendments,
|
||||
majorityAmendments_t const& majorityAmendments,
|
||||
std::vector<STValidation::pointer> const& valSet) = 0;
|
||||
|
||||
// Called by the consensus code when we need to
|
||||
// add feature entries to a validation
|
||||
virtual std::vector <uint256>
|
||||
doValidation (std::set <uint256> const& enabled) = 0;
|
||||
virtual std::vector<uint256>
|
||||
doValidation(std::set<uint256> const& enabled) = 0;
|
||||
|
||||
// The set of amendments to enable in the genesis ledger
|
||||
// This will return all known, non-vetoed amendments.
|
||||
// If we ever have two amendments that should not both be
|
||||
// enabled at the same time, we should ensure one is vetoed.
|
||||
virtual std::vector <uint256>
|
||||
getDesired () = 0;
|
||||
virtual std::vector<uint256>
|
||||
getDesired() = 0;
|
||||
|
||||
// The function below adapts the API callers expect to the
|
||||
// internal amendment table API. This allows the amendment
|
||||
@@ -114,13 +124,13 @@ public:
|
||||
// supports a full ledger API
|
||||
|
||||
void
|
||||
doVoting (
|
||||
std::shared_ptr <ReadView const> const& lastClosedLedger,
|
||||
doVoting(
|
||||
std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
std::vector<STValidation::pointer> const& parentValidations,
|
||||
std::shared_ptr<SHAMap> const& initialPosition)
|
||||
{
|
||||
// Ask implementation what to do
|
||||
auto actions = doVoting (
|
||||
auto actions = doVoting(
|
||||
lastClosedLedger->parentCloseTime(),
|
||||
getEnabledAmendments(*lastClosedLedger),
|
||||
getMajorityAmendments(*lastClosedLedger),
|
||||
@@ -129,32 +139,31 @@ public:
|
||||
// Inject appropriate pseudo-transactions
|
||||
for (auto const& it : actions)
|
||||
{
|
||||
STTx amendTx (ttAMENDMENT,
|
||||
[&it, seq = lastClosedLedger->seq() + 1](auto& obj)
|
||||
{
|
||||
obj.setAccountID (sfAccount, AccountID());
|
||||
obj.setFieldH256 (sfAmendment, it.first);
|
||||
obj.setFieldU32 (sfLedgerSequence, seq);
|
||||
STTx amendTx(
|
||||
ttAMENDMENT,
|
||||
[&it, seq = lastClosedLedger->seq() + 1](auto& obj) {
|
||||
obj.setAccountID(sfAccount, AccountID());
|
||||
obj.setFieldH256(sfAmendment, it.first);
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
|
||||
if (it.second != 0)
|
||||
obj.setFieldU32 (sfFlags, it.second);
|
||||
obj.setFieldU32(sfFlags, it.second);
|
||||
});
|
||||
|
||||
Serializer s;
|
||||
amendTx.add (s);
|
||||
amendTx.add(s);
|
||||
|
||||
initialPosition->addGiveItem (
|
||||
std::make_shared <SHAMapItem> (
|
||||
amendTx.getTransactionID(),
|
||||
s.peekData()),
|
||||
initialPosition->addGiveItem(
|
||||
std::make_shared<SHAMapItem>(
|
||||
amendTx.getTransactionID(), s.peekData()),
|
||||
true,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::unique_ptr<AmendmentTable> make_AmendmentTable (
|
||||
std::unique_ptr<AmendmentTable>
|
||||
make_AmendmentTable(
|
||||
std::chrono::seconds majorityTime,
|
||||
int majorityFraction,
|
||||
Section const& supported,
|
||||
@@ -162,6 +171,6 @@ std::unique_ptr<AmendmentTable> make_AmendmentTable (
|
||||
Section const& vetoed,
|
||||
beast::Journal journal);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,94 +22,109 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
bool CanonicalTXSet::Key::operator< (Key const& rhs) const
|
||||
bool
|
||||
CanonicalTXSet::Key::operator<(Key const& rhs) const
|
||||
{
|
||||
if (mAccount < rhs.mAccount) return true;
|
||||
if (mAccount < rhs.mAccount)
|
||||
return true;
|
||||
|
||||
if (mAccount > rhs.mAccount) return false;
|
||||
if (mAccount > rhs.mAccount)
|
||||
return false;
|
||||
|
||||
if (mSeq < rhs.mSeq) return true;
|
||||
if (mSeq < rhs.mSeq)
|
||||
return true;
|
||||
|
||||
if (mSeq > rhs.mSeq) return false;
|
||||
if (mSeq > rhs.mSeq)
|
||||
return false;
|
||||
|
||||
return mTXid < rhs.mTXid;
|
||||
}
|
||||
|
||||
bool CanonicalTXSet::Key::operator> (Key const& rhs) const
|
||||
bool
|
||||
CanonicalTXSet::Key::operator>(Key const& rhs) const
|
||||
{
|
||||
if (mAccount > rhs.mAccount) return true;
|
||||
if (mAccount > rhs.mAccount)
|
||||
return true;
|
||||
|
||||
if (mAccount < rhs.mAccount) return false;
|
||||
if (mAccount < rhs.mAccount)
|
||||
return false;
|
||||
|
||||
if (mSeq > rhs.mSeq) return true;
|
||||
if (mSeq > rhs.mSeq)
|
||||
return true;
|
||||
|
||||
if (mSeq < rhs.mSeq) return false;
|
||||
if (mSeq < rhs.mSeq)
|
||||
return false;
|
||||
|
||||
return mTXid > rhs.mTXid;
|
||||
}
|
||||
|
||||
bool CanonicalTXSet::Key::operator<= (Key const& rhs) const
|
||||
bool
|
||||
CanonicalTXSet::Key::operator<=(Key const& rhs) const
|
||||
{
|
||||
if (mAccount < rhs.mAccount) return true;
|
||||
if (mAccount < rhs.mAccount)
|
||||
return true;
|
||||
|
||||
if (mAccount > rhs.mAccount) return false;
|
||||
if (mAccount > rhs.mAccount)
|
||||
return false;
|
||||
|
||||
if (mSeq < rhs.mSeq) return true;
|
||||
if (mSeq < rhs.mSeq)
|
||||
return true;
|
||||
|
||||
if (mSeq > rhs.mSeq) return false;
|
||||
if (mSeq > rhs.mSeq)
|
||||
return false;
|
||||
|
||||
return mTXid <= rhs.mTXid;
|
||||
}
|
||||
|
||||
bool CanonicalTXSet::Key::operator>= (Key const& rhs)const
|
||||
bool
|
||||
CanonicalTXSet::Key::operator>=(Key const& rhs) const
|
||||
{
|
||||
if (mAccount > rhs.mAccount) return true;
|
||||
if (mAccount > rhs.mAccount)
|
||||
return true;
|
||||
|
||||
if (mAccount < rhs.mAccount) return false;
|
||||
if (mAccount < rhs.mAccount)
|
||||
return false;
|
||||
|
||||
if (mSeq > rhs.mSeq) return true;
|
||||
if (mSeq > rhs.mSeq)
|
||||
return true;
|
||||
|
||||
if (mSeq < rhs.mSeq) return false;
|
||||
if (mSeq < rhs.mSeq)
|
||||
return false;
|
||||
|
||||
return mTXid >= rhs.mTXid;
|
||||
}
|
||||
|
||||
uint256 CanonicalTXSet::accountKey (AccountID const& account)
|
||||
uint256
|
||||
CanonicalTXSet::accountKey(AccountID const& account)
|
||||
{
|
||||
uint256 ret = beast::zero;
|
||||
memcpy (
|
||||
ret.begin (),
|
||||
account.begin (),
|
||||
account.size ());
|
||||
memcpy(ret.begin(), account.begin(), account.size());
|
||||
ret ^= salt_;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CanonicalTXSet::insert (std::shared_ptr<STTx const> const& txn)
|
||||
void
|
||||
CanonicalTXSet::insert(std::shared_ptr<STTx const> const& txn)
|
||||
{
|
||||
map_.insert (
|
||||
std::make_pair (
|
||||
Key (
|
||||
accountKey (txn->getAccountID(sfAccount)),
|
||||
txn->getSequence (),
|
||||
txn->getTransactionID ()),
|
||||
txn));
|
||||
map_.insert(std::make_pair(
|
||||
Key(accountKey(txn->getAccountID(sfAccount)),
|
||||
txn->getSequence(),
|
||||
txn->getTransactionID()),
|
||||
txn));
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<STTx const>>
|
||||
CanonicalTXSet::prune(AccountID const& account,
|
||||
std::uint32_t const seq)
|
||||
CanonicalTXSet::prune(AccountID const& account, std::uint32_t const seq)
|
||||
{
|
||||
auto effectiveAccount = accountKey (account);
|
||||
auto effectiveAccount = accountKey(account);
|
||||
|
||||
Key keyLow(effectiveAccount, seq, beast::zero);
|
||||
Key keyHigh(effectiveAccount, seq+1, beast::zero);
|
||||
Key keyHigh(effectiveAccount, seq + 1, beast::zero);
|
||||
|
||||
auto range = boost::make_iterator_range(
|
||||
map_.lower_bound(keyLow),
|
||||
map_.lower_bound(keyHigh));
|
||||
auto txRange = boost::adaptors::transform(range,
|
||||
[](auto const& p) { return p.second; });
|
||||
map_.lower_bound(keyLow), map_.lower_bound(keyHigh));
|
||||
auto txRange = boost::adaptors::transform(
|
||||
range, [](auto const& p) { return p.second; });
|
||||
|
||||
std::vector<std::shared_ptr<STTx const>> result(
|
||||
txRange.begin(), txRange.end());
|
||||
@@ -118,4 +133,4 @@ CanonicalTXSet::prune(AccountID const& account,
|
||||
return result;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -39,28 +39,33 @@ private:
|
||||
class Key
|
||||
{
|
||||
public:
|
||||
Key (uint256 const& account, std::uint32_t seq, uint256 const& id)
|
||||
: mAccount (account)
|
||||
, mTXid (id)
|
||||
, mSeq (seq)
|
||||
Key(uint256 const& account, std::uint32_t seq, uint256 const& id)
|
||||
: mAccount(account), mTXid(id), mSeq(seq)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator< (Key const& rhs) const;
|
||||
bool operator> (Key const& rhs) const;
|
||||
bool operator<= (Key const& rhs) const;
|
||||
bool operator>= (Key const& rhs) const;
|
||||
bool
|
||||
operator<(Key const& rhs) const;
|
||||
bool
|
||||
operator>(Key const& rhs) const;
|
||||
bool
|
||||
operator<=(Key const& rhs) const;
|
||||
bool
|
||||
operator>=(Key const& rhs) const;
|
||||
|
||||
bool operator== (Key const& rhs) const
|
||||
bool
|
||||
operator==(Key const& rhs) const
|
||||
{
|
||||
return mTXid == rhs.mTXid;
|
||||
}
|
||||
bool operator!= (Key const& rhs) const
|
||||
bool
|
||||
operator!=(Key const& rhs) const
|
||||
{
|
||||
return mTXid != rhs.mTXid;
|
||||
}
|
||||
|
||||
uint256 const& getTXID () const
|
||||
uint256 const&
|
||||
getTXID() const
|
||||
{
|
||||
return mTXid;
|
||||
}
|
||||
@@ -72,65 +77,74 @@ private:
|
||||
};
|
||||
|
||||
// Calculate the salted key for the given account
|
||||
uint256 accountKey (AccountID const& account);
|
||||
uint256
|
||||
accountKey(AccountID const& account);
|
||||
|
||||
public:
|
||||
using const_iterator = std::map <Key, std::shared_ptr<STTx const>>::const_iterator;
|
||||
using const_iterator =
|
||||
std::map<Key, std::shared_ptr<STTx const>>::const_iterator;
|
||||
|
||||
public:
|
||||
explicit CanonicalTXSet (LedgerHash const& saltHash)
|
||||
: salt_ (saltHash)
|
||||
explicit CanonicalTXSet(LedgerHash const& saltHash) : salt_(saltHash)
|
||||
{
|
||||
}
|
||||
|
||||
void insert (std::shared_ptr<STTx const> const& txn);
|
||||
void
|
||||
insert(std::shared_ptr<STTx const> const& txn);
|
||||
|
||||
std::vector<std::shared_ptr<STTx const>>
|
||||
prune(AccountID const& account, std::uint32_t const seq);
|
||||
|
||||
// VFALCO TODO remove this function
|
||||
void reset (LedgerHash const& salt)
|
||||
void
|
||||
reset(LedgerHash const& salt)
|
||||
{
|
||||
salt_ = salt;
|
||||
map_.clear ();
|
||||
map_.clear();
|
||||
}
|
||||
|
||||
const_iterator erase (const_iterator const& it)
|
||||
const_iterator
|
||||
erase(const_iterator const& it)
|
||||
{
|
||||
return map_.erase(it);
|
||||
}
|
||||
|
||||
const_iterator begin () const
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return map_.begin();
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return map_.end();
|
||||
}
|
||||
|
||||
size_t size () const
|
||||
size_t
|
||||
size() const
|
||||
{
|
||||
return map_.size ();
|
||||
return map_.size();
|
||||
}
|
||||
bool empty () const
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return map_.empty ();
|
||||
return map_.empty();
|
||||
}
|
||||
|
||||
uint256 const& key() const
|
||||
uint256 const&
|
||||
key() const
|
||||
{
|
||||
return salt_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map <Key, std::shared_ptr<STTx const>> map_;
|
||||
std::map<Key, std::shared_ptr<STTx const>> map_;
|
||||
|
||||
// Used to salt the accounts so people can't mine for low account numbers
|
||||
uint256 salt_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#ifndef RIPPLE_APP_MISC_FEEVOTE_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_FEEVOTE_H_INCLUDED
|
||||
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/shamap/SHAMap.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/basics/BasicConfig.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <ripple/shamap/SHAMap.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -40,53 +40,53 @@ public:
|
||||
struct Setup
|
||||
{
|
||||
/** The cost of a reference transaction in drops. */
|
||||
XRPAmount reference_fee{ 10 };
|
||||
XRPAmount reference_fee{10};
|
||||
|
||||
/** The cost of a reference transaction in fee units. */
|
||||
static constexpr FeeUnit32 reference_fee_units{ 10 };
|
||||
static constexpr FeeUnit32 reference_fee_units{10};
|
||||
|
||||
/** The account reserve requirement in drops. */
|
||||
XRPAmount account_reserve{ 20 * DROPS_PER_XRP };
|
||||
XRPAmount account_reserve{20 * DROPS_PER_XRP};
|
||||
|
||||
/** The per-owned item reserve requirement in drops. */
|
||||
XRPAmount owner_reserve{ 5 * DROPS_PER_XRP };
|
||||
XRPAmount owner_reserve{5 * DROPS_PER_XRP};
|
||||
};
|
||||
|
||||
virtual ~FeeVote () = default;
|
||||
virtual ~FeeVote() = default;
|
||||
|
||||
/** Add local fee preference to validation.
|
||||
|
||||
@param lastClosedLedger
|
||||
@param baseValidation
|
||||
*/
|
||||
virtual
|
||||
void
|
||||
doValidation (std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
STValidation::FeeSettings & fees) = 0;
|
||||
virtual void
|
||||
doValidation(
|
||||
std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
STValidation::FeeSettings& fees) = 0;
|
||||
|
||||
/** Cast our local vote on the fee.
|
||||
|
||||
@param lastClosedLedger
|
||||
@param initialPosition
|
||||
*/
|
||||
virtual
|
||||
void
|
||||
doVoting (std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
virtual void
|
||||
doVoting(
|
||||
std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
std::vector<STValidation::pointer> const& parentValidations,
|
||||
std::shared_ptr<SHAMap> const& initialPosition) = 0;
|
||||
std::shared_ptr<SHAMap> const& initialPosition) = 0;
|
||||
};
|
||||
|
||||
/** Build FeeVote::Setup from a config section. */
|
||||
FeeVote::Setup
|
||||
setup_FeeVote (Section const& section);
|
||||
setup_FeeVote(Section const& section);
|
||||
|
||||
/** Create an instance of the FeeVote logic.
|
||||
@param setup The fee schedule to vote for.
|
||||
@param journal Where to log.
|
||||
*/
|
||||
std::unique_ptr <FeeVote>
|
||||
make_FeeVote (FeeVote::Setup const& setup, beast::Journal journal);
|
||||
std::unique_ptr<FeeVote>
|
||||
make_FeeVote(FeeVote::Setup const& setup, beast::Journal journal);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/st.h>
|
||||
#include <ripple/app/misc/FeeVote.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/app/misc/FeeVote.h>
|
||||
#include <ripple/basics/BasicConfig.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -32,14 +32,13 @@ class VotableValue
|
||||
{
|
||||
private:
|
||||
using value_type = XRPAmount;
|
||||
value_type const mCurrent; // The current setting
|
||||
value_type const mTarget; // The setting we want
|
||||
std::map <value_type, int> mVoteMap;
|
||||
value_type const mCurrent; // The current setting
|
||||
value_type const mTarget; // The setting we want
|
||||
std::map<value_type, int> mVoteMap;
|
||||
|
||||
public:
|
||||
VotableValue (value_type current, value_type target)
|
||||
: mCurrent (current)
|
||||
, mTarget (target)
|
||||
VotableValue(value_type current, value_type target)
|
||||
: mCurrent(current), mTarget(target)
|
||||
{
|
||||
// Add our vote
|
||||
++mVoteMap[mTarget];
|
||||
@@ -54,7 +53,7 @@ public:
|
||||
void
|
||||
noVote()
|
||||
{
|
||||
addVote (mCurrent);
|
||||
addVote(mCurrent);
|
||||
}
|
||||
|
||||
value_type
|
||||
@@ -62,17 +61,15 @@ public:
|
||||
};
|
||||
|
||||
auto
|
||||
VotableValue::getVotes() const
|
||||
-> value_type
|
||||
VotableValue::getVotes() const -> value_type
|
||||
{
|
||||
value_type ourVote = mCurrent;
|
||||
int weight = 0;
|
||||
for (auto const& [key, val] : mVoteMap)
|
||||
{
|
||||
// Take most voted value between current and target, inclusive
|
||||
if ((key <= std::max (mTarget, mCurrent)) &&
|
||||
(key >= std::min (mTarget, mCurrent)) &&
|
||||
(val > weight))
|
||||
if ((key <= std::max(mTarget, mCurrent)) &&
|
||||
(key >= std::min(mTarget, mCurrent)) && (val > weight))
|
||||
{
|
||||
ourVote = key;
|
||||
weight = val;
|
||||
@@ -82,7 +79,7 @@ VotableValue::getVotes() const
|
||||
return ourVote;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -93,51 +90,52 @@ private:
|
||||
beast::Journal const journal_;
|
||||
|
||||
public:
|
||||
FeeVoteImpl (Setup const& setup, beast::Journal journal);
|
||||
FeeVoteImpl(Setup const& setup, beast::Journal journal);
|
||||
|
||||
void
|
||||
doValidation (std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
doValidation(
|
||||
std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
STValidation::FeeSettings& fees) override;
|
||||
|
||||
void
|
||||
doVoting (std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
doVoting(
|
||||
std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
std::vector<STValidation::pointer> const& parentValidations,
|
||||
std::shared_ptr<SHAMap> const& initialPosition) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
FeeVoteImpl::FeeVoteImpl (Setup const& setup, beast::Journal journal)
|
||||
: target_ (setup)
|
||||
, journal_ (journal)
|
||||
FeeVoteImpl::FeeVoteImpl(Setup const& setup, beast::Journal journal)
|
||||
: target_(setup), journal_(journal)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FeeVoteImpl::doValidation(
|
||||
std::shared_ptr<ReadView const> const& lastClosedLedger,
|
||||
STValidation::FeeSettings& fees)
|
||||
STValidation::FeeSettings& fees)
|
||||
{
|
||||
if (lastClosedLedger->fees().base != target_.reference_fee)
|
||||
{
|
||||
JLOG(journal_.info()) <<
|
||||
"Voting for base fee of " << target_.reference_fee;
|
||||
JLOG(journal_.info())
|
||||
<< "Voting for base fee of " << target_.reference_fee;
|
||||
|
||||
fees.baseFee = target_.reference_fee;
|
||||
}
|
||||
|
||||
if (lastClosedLedger->fees().accountReserve(0) != target_.account_reserve)
|
||||
{
|
||||
JLOG(journal_.info()) <<
|
||||
"Voting for base reserve of " << target_.account_reserve;
|
||||
JLOG(journal_.info())
|
||||
<< "Voting for base reserve of " << target_.account_reserve;
|
||||
|
||||
fees.reserveBase = target_.account_reserve;
|
||||
}
|
||||
|
||||
if (lastClosedLedger->fees().increment != target_.owner_reserve)
|
||||
{
|
||||
JLOG(journal_.info()) <<
|
||||
"Voting for reserve increment of " << target_.owner_reserve;
|
||||
JLOG(journal_.info())
|
||||
<< "Voting for reserve increment of " << target_.owner_reserve;
|
||||
|
||||
fees.reserveIncrement = target_.owner_reserve;
|
||||
}
|
||||
@@ -150,32 +148,29 @@ FeeVoteImpl::doVoting(
|
||||
std::shared_ptr<SHAMap> const& initialPosition)
|
||||
{
|
||||
// LCL must be flag ledger
|
||||
assert ((lastClosedLedger->info().seq % 256) == 0);
|
||||
assert((lastClosedLedger->info().seq % 256) == 0);
|
||||
|
||||
detail::VotableValue baseFeeVote (
|
||||
lastClosedLedger->fees().base,
|
||||
target_.reference_fee);
|
||||
detail::VotableValue baseFeeVote(
|
||||
lastClosedLedger->fees().base, target_.reference_fee);
|
||||
|
||||
detail::VotableValue baseReserveVote(
|
||||
lastClosedLedger->fees().accountReserve(0),
|
||||
target_.account_reserve);
|
||||
lastClosedLedger->fees().accountReserve(0), target_.account_reserve);
|
||||
|
||||
detail::VotableValue incReserveVote (
|
||||
lastClosedLedger->fees().increment,
|
||||
target_.owner_reserve);
|
||||
detail::VotableValue incReserveVote(
|
||||
lastClosedLedger->fees().increment, target_.owner_reserve);
|
||||
|
||||
for (auto const& val : set)
|
||||
{
|
||||
if (val->isTrusted ())
|
||||
if (val->isTrusted())
|
||||
{
|
||||
if (val->isFieldPresent (sfBaseFee))
|
||||
if (val->isFieldPresent(sfBaseFee))
|
||||
{
|
||||
using xrptype = XRPAmount::value_type;
|
||||
auto const vote = val->getFieldU64 (sfBaseFee);
|
||||
auto const vote = val->getFieldU64(sfBaseFee);
|
||||
if (vote <= std::numeric_limits<xrptype>::max() &&
|
||||
isLegalAmount(XRPAmount{unsafe_cast<xrptype>(vote)}))
|
||||
baseFeeVote.addVote(XRPAmount{
|
||||
unsafe_cast<XRPAmount::value_type>(vote)});
|
||||
baseFeeVote.addVote(
|
||||
XRPAmount{unsafe_cast<XRPAmount::value_type>(vote)});
|
||||
else
|
||||
// Invalid amounts will be treated as if they're
|
||||
// not provided. Don't throw because this value is
|
||||
@@ -184,38 +179,38 @@ FeeVoteImpl::doVoting(
|
||||
}
|
||||
else
|
||||
{
|
||||
baseFeeVote.noVote ();
|
||||
baseFeeVote.noVote();
|
||||
}
|
||||
|
||||
if (val->isFieldPresent (sfReserveBase))
|
||||
if (val->isFieldPresent(sfReserveBase))
|
||||
{
|
||||
baseReserveVote.addVote(XRPAmount{
|
||||
val->getFieldU32(sfReserveBase)});
|
||||
baseReserveVote.addVote(
|
||||
XRPAmount{val->getFieldU32(sfReserveBase)});
|
||||
}
|
||||
else
|
||||
{
|
||||
baseReserveVote.noVote ();
|
||||
baseReserveVote.noVote();
|
||||
}
|
||||
|
||||
if (val->isFieldPresent (sfReserveIncrement))
|
||||
if (val->isFieldPresent(sfReserveIncrement))
|
||||
{
|
||||
incReserveVote.addVote (XRPAmount{
|
||||
val->getFieldU32 (sfReserveIncrement)});
|
||||
incReserveVote.addVote(
|
||||
XRPAmount{val->getFieldU32(sfReserveIncrement)});
|
||||
}
|
||||
else
|
||||
{
|
||||
incReserveVote.noVote ();
|
||||
incReserveVote.noVote();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// choose our positions
|
||||
// If any of the values are invalid, send the current values.
|
||||
auto const baseFee = baseFeeVote.getVotes ().dropsAs<std::uint64_t>(
|
||||
auto const baseFee = baseFeeVote.getVotes().dropsAs<std::uint64_t>(
|
||||
lastClosedLedger->fees().base);
|
||||
auto const baseReserve = baseReserveVote.getVotes ().dropsAs<std::uint32_t>(
|
||||
auto const baseReserve = baseReserveVote.getVotes().dropsAs<std::uint32_t>(
|
||||
lastClosedLedger->fees().accountReserve(0));
|
||||
auto const incReserve = incReserveVote.getVotes ().dropsAs<std::uint32_t>(
|
||||
auto const incReserve = incReserveVote.getVotes().dropsAs<std::uint32_t>(
|
||||
lastClosedLedger->fees().increment);
|
||||
constexpr FeeUnit32 feeUnits = Setup::reference_fee_units;
|
||||
auto const seq = lastClosedLedger->info().seq + 1;
|
||||
@@ -223,16 +218,14 @@ FeeVoteImpl::doVoting(
|
||||
// add transactions to our position
|
||||
if ((baseFee != lastClosedLedger->fees().base) ||
|
||||
(baseReserve != lastClosedLedger->fees().accountReserve(0)) ||
|
||||
(incReserve != lastClosedLedger->fees().increment))
|
||||
(incReserve != lastClosedLedger->fees().increment))
|
||||
{
|
||||
JLOG(journal_.warn()) <<
|
||||
"We are voting for a fee change: " << baseFee <<
|
||||
"/" << baseReserve <<
|
||||
"/" << incReserve;
|
||||
JLOG(journal_.warn()) << "We are voting for a fee change: " << baseFee
|
||||
<< "/" << baseReserve << "/" << incReserve;
|
||||
|
||||
STTx feeTx (ttFEE,
|
||||
[seq,baseFee,baseReserve,incReserve,feeUnits](auto& obj)
|
||||
{
|
||||
STTx feeTx(
|
||||
ttFEE,
|
||||
[seq, baseFee, baseReserve, incReserve, feeUnits](auto& obj) {
|
||||
obj[sfAccount] = AccountID();
|
||||
obj[sfLedgerSequence] = seq;
|
||||
obj[sfBaseFee] = baseFee;
|
||||
@@ -241,20 +234,18 @@ FeeVoteImpl::doVoting(
|
||||
obj[sfReferenceFeeUnits] = feeUnits.fee();
|
||||
});
|
||||
|
||||
uint256 txID = feeTx.getTransactionID ();
|
||||
uint256 txID = feeTx.getTransactionID();
|
||||
|
||||
JLOG(journal_.warn()) <<
|
||||
"Vote: " << txID;
|
||||
JLOG(journal_.warn()) << "Vote: " << txID;
|
||||
|
||||
Serializer s;
|
||||
feeTx.add (s);
|
||||
feeTx.add(s);
|
||||
|
||||
auto tItem = std::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
auto tItem = std::make_shared<SHAMapItem>(txID, s.peekData());
|
||||
|
||||
if (!initialPosition->addGiveItem (tItem, true, false))
|
||||
if (!initialPosition->addGiveItem(tItem, true, false))
|
||||
{
|
||||
JLOG(journal_.warn()) <<
|
||||
"Ledger already had fee change";
|
||||
JLOG(journal_.warn()) << "Ledger already had fee change";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,7 +253,7 @@ FeeVoteImpl::doVoting(
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
FeeVote::Setup
|
||||
setup_FeeVote (Section const& section)
|
||||
setup_FeeVote(Section const& section)
|
||||
{
|
||||
FeeVote::Setup setup;
|
||||
{
|
||||
@@ -282,9 +273,9 @@ setup_FeeVote (Section const& section)
|
||||
}
|
||||
|
||||
std::unique_ptr<FeeVote>
|
||||
make_FeeVote (FeeVote::Setup const& setup, beast::Journal journal)
|
||||
make_FeeVote(FeeVote::Setup const& setup, beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<FeeVoteImpl> (setup, journal);
|
||||
return std::make_unique<FeeVoteImpl>(setup, journal);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -22,92 +22,97 @@
|
||||
namespace ripple {
|
||||
|
||||
auto
|
||||
HashRouter::emplace (uint256 const& key)
|
||||
-> std::pair<Entry&, bool>
|
||||
HashRouter::emplace(uint256 const& key) -> std::pair<Entry&, bool>
|
||||
{
|
||||
auto iter = suppressionMap_.find (key);
|
||||
auto iter = suppressionMap_.find(key);
|
||||
|
||||
if (iter != suppressionMap_.end ())
|
||||
if (iter != suppressionMap_.end())
|
||||
{
|
||||
suppressionMap_.touch(iter);
|
||||
return std::make_pair(
|
||||
std::ref(iter->second), false);
|
||||
return std::make_pair(std::ref(iter->second), false);
|
||||
}
|
||||
|
||||
// See if any supressions need to be expired
|
||||
expire(suppressionMap_, holdTime_);
|
||||
|
||||
return std::make_pair(std::ref(
|
||||
suppressionMap_.emplace (
|
||||
key, Entry ()).first->second),
|
||||
true);
|
||||
return std::make_pair(
|
||||
std::ref(suppressionMap_.emplace(key, Entry()).first->second), true);
|
||||
}
|
||||
|
||||
void HashRouter::addSuppression (uint256 const& key)
|
||||
void
|
||||
HashRouter::addSuppression(uint256 const& key)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
emplace (key);
|
||||
emplace(key);
|
||||
}
|
||||
|
||||
bool HashRouter::addSuppressionPeer (uint256 const& key, PeerShortID peer)
|
||||
bool
|
||||
HashRouter::addSuppressionPeer(uint256 const& key, PeerShortID peer)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
auto result = emplace(key);
|
||||
result.first.addPeer(peer);
|
||||
return result.second;
|
||||
}
|
||||
|
||||
bool HashRouter::addSuppressionPeer (uint256 const& key, PeerShortID peer, int& flags)
|
||||
bool
|
||||
HashRouter::addSuppressionPeer(uint256 const& key, PeerShortID peer, int& flags)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
auto [s, created] = emplace(key);
|
||||
s.addPeer (peer);
|
||||
flags = s.getFlags ();
|
||||
s.addPeer(peer);
|
||||
flags = s.getFlags();
|
||||
return created;
|
||||
}
|
||||
|
||||
bool HashRouter::shouldProcess (uint256 const& key, PeerShortID peer,
|
||||
int& flags, std::chrono::seconds tx_interval)
|
||||
bool
|
||||
HashRouter::shouldProcess(
|
||||
uint256 const& key,
|
||||
PeerShortID peer,
|
||||
int& flags,
|
||||
std::chrono::seconds tx_interval)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
auto result = emplace(key);
|
||||
auto& s = result.first;
|
||||
s.addPeer (peer);
|
||||
flags = s.getFlags ();
|
||||
return s.shouldProcess (suppressionMap_.clock().now(), tx_interval);
|
||||
s.addPeer(peer);
|
||||
flags = s.getFlags();
|
||||
return s.shouldProcess(suppressionMap_.clock().now(), tx_interval);
|
||||
}
|
||||
|
||||
int HashRouter::getFlags (uint256 const& key)
|
||||
int
|
||||
HashRouter::getFlags(uint256 const& key)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
return emplace(key).first.getFlags ();
|
||||
return emplace(key).first.getFlags();
|
||||
}
|
||||
|
||||
bool HashRouter::setFlags (uint256 const& key, int flags)
|
||||
bool
|
||||
HashRouter::setFlags(uint256 const& key, int flags)
|
||||
{
|
||||
assert (flags != 0);
|
||||
assert(flags != 0);
|
||||
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
auto& s = emplace(key).first;
|
||||
|
||||
if ((s.getFlags () & flags) == flags)
|
||||
if ((s.getFlags() & flags) == flags)
|
||||
return false;
|
||||
|
||||
s.setFlags (flags);
|
||||
s.setFlags(flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto
|
||||
HashRouter::shouldRelay (uint256 const& key)
|
||||
HashRouter::shouldRelay(uint256 const& key)
|
||||
-> boost::optional<std::set<PeerShortID>>
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
auto& s = emplace(key).first;
|
||||
|
||||
@@ -127,4 +132,4 @@ HashRouter::shouldRecover(uint256 const& key)
|
||||
return s.shouldRecover(recoverLimit_);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#ifndef RIPPLE_APP_MISC_HASHROUTER_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_HASHROUTER_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/basics/CountedObject.h>
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/beast/container/aged_unordered_map.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
@@ -32,17 +32,17 @@ namespace ripple {
|
||||
// VFALCO NOTE Are these the flags?? Why aren't we using a packed struct?
|
||||
// VFALCO TODO convert these macros to int constants
|
||||
// VFALCO NOTE How can both bad and good be set on a hash?
|
||||
#define SF_BAD 0x02 // Temporarily bad
|
||||
#define SF_SAVED 0x04
|
||||
#define SF_TRUSTED 0x10 // comes from trusted source
|
||||
#define SF_BAD 0x02 // Temporarily bad
|
||||
#define SF_SAVED 0x04
|
||||
#define SF_TRUSTED 0x10 // comes from trusted source
|
||||
// Private flags, used internally in apply.cpp.
|
||||
// Do not attempt to read, set, or reuse.
|
||||
#define SF_PRIVATE1 0x0100
|
||||
#define SF_PRIVATE2 0x0200
|
||||
#define SF_PRIVATE3 0x0400
|
||||
#define SF_PRIVATE4 0x0800
|
||||
#define SF_PRIVATE5 0x1000
|
||||
#define SF_PRIVATE6 0x2000
|
||||
#define SF_PRIVATE1 0x0100
|
||||
#define SF_PRIVATE2 0x0200
|
||||
#define SF_PRIVATE3 0x0400
|
||||
#define SF_PRIVATE4 0x0800
|
||||
#define SF_PRIVATE5 0x1000
|
||||
#define SF_PRIVATE6 0x2000
|
||||
|
||||
/** Routing table for objects identified by hash.
|
||||
|
||||
@@ -58,34 +58,42 @@ public:
|
||||
|
||||
private:
|
||||
/** An entry in the routing table.
|
||||
*/
|
||||
class Entry : public CountedObject <Entry>
|
||||
*/
|
||||
class Entry : public CountedObject<Entry>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "HashRouterEntry"; }
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "HashRouterEntry";
|
||||
}
|
||||
|
||||
Entry ()
|
||||
Entry()
|
||||
{
|
||||
}
|
||||
|
||||
void addPeer (PeerShortID peer)
|
||||
void
|
||||
addPeer(PeerShortID peer)
|
||||
{
|
||||
if (peer != 0)
|
||||
peers_.insert (peer);
|
||||
peers_.insert(peer);
|
||||
}
|
||||
|
||||
int getFlags (void) const
|
||||
int
|
||||
getFlags(void) const
|
||||
{
|
||||
return flags_;
|
||||
}
|
||||
|
||||
void setFlags (int flagsToSet)
|
||||
void
|
||||
setFlags(int flagsToSet)
|
||||
{
|
||||
flags_ |= flagsToSet;
|
||||
}
|
||||
|
||||
/** Return set of peers we've relayed to and reset tracking */
|
||||
std::set<PeerShortID> releasePeerSet()
|
||||
std::set<PeerShortID>
|
||||
releasePeerSet()
|
||||
{
|
||||
return std::move(peers_);
|
||||
}
|
||||
@@ -96,7 +104,9 @@ private:
|
||||
If it has, return false. If it has not, update the
|
||||
last relay timestamp and return true.
|
||||
*/
|
||||
bool shouldRelay (Stopwatch::time_point const& now,
|
||||
bool
|
||||
shouldRelay(
|
||||
Stopwatch::time_point const& now,
|
||||
std::chrono::seconds holdTime)
|
||||
{
|
||||
if (relayed_ && *relayed_ + holdTime > now)
|
||||
@@ -113,22 +123,24 @@ private:
|
||||
|
||||
@note The limit must be > 0
|
||||
*/
|
||||
bool shouldRecover(std::uint32_t limit)
|
||||
bool
|
||||
shouldRecover(std::uint32_t limit)
|
||||
{
|
||||
return ++recoveries_ % limit != 0;
|
||||
}
|
||||
|
||||
bool shouldProcess(Stopwatch::time_point now, std::chrono::seconds interval)
|
||||
bool
|
||||
shouldProcess(Stopwatch::time_point now, std::chrono::seconds interval)
|
||||
{
|
||||
if (processed_ && ((*processed_ + interval) > now))
|
||||
return false;
|
||||
processed_.emplace (now);
|
||||
return true;
|
||||
if (processed_ && ((*processed_ + interval) > now))
|
||||
return false;
|
||||
processed_.emplace(now);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
int flags_ = 0;
|
||||
std::set <PeerShortID> peers_;
|
||||
std::set<PeerShortID> peers_;
|
||||
// This could be generalized to a map, if more
|
||||
// than one flag needs to expire independently.
|
||||
boost::optional<Stopwatch::time_point> relayed_;
|
||||
@@ -137,50 +149,63 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
static inline std::chrono::seconds getDefaultHoldTime ()
|
||||
static inline std::chrono::seconds
|
||||
getDefaultHoldTime()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
return 300s;
|
||||
}
|
||||
|
||||
static inline std::uint32_t getDefaultRecoverLimit()
|
||||
static inline std::uint32_t
|
||||
getDefaultRecoverLimit()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
HashRouter (Stopwatch& clock, std::chrono::seconds entryHoldTimeInSeconds,
|
||||
HashRouter(
|
||||
Stopwatch& clock,
|
||||
std::chrono::seconds entryHoldTimeInSeconds,
|
||||
std::uint32_t recoverLimit)
|
||||
: suppressionMap_(clock)
|
||||
, holdTime_ (entryHoldTimeInSeconds)
|
||||
, recoverLimit_ (recoverLimit + 1u)
|
||||
, holdTime_(entryHoldTimeInSeconds)
|
||||
, recoverLimit_(recoverLimit + 1u)
|
||||
{
|
||||
}
|
||||
|
||||
HashRouter& operator= (HashRouter const&) = delete;
|
||||
HashRouter&
|
||||
operator=(HashRouter const&) = delete;
|
||||
|
||||
virtual ~HashRouter() = default;
|
||||
|
||||
// VFALCO TODO Replace "Supression" terminology with something more
|
||||
// semantically meaningful.
|
||||
void addSuppression(uint256 const& key);
|
||||
void
|
||||
addSuppression(uint256 const& key);
|
||||
|
||||
bool addSuppressionPeer (uint256 const& key, PeerShortID peer);
|
||||
bool
|
||||
addSuppressionPeer(uint256 const& key, PeerShortID peer);
|
||||
|
||||
bool addSuppressionPeer (uint256 const& key, PeerShortID peer,
|
||||
int& flags);
|
||||
bool
|
||||
addSuppressionPeer(uint256 const& key, PeerShortID peer, int& flags);
|
||||
|
||||
// Add a peer suppression and return whether the entry should be processed
|
||||
bool shouldProcess (uint256 const& key, PeerShortID peer, int& flags,
|
||||
bool
|
||||
shouldProcess(
|
||||
uint256 const& key,
|
||||
PeerShortID peer,
|
||||
int& flags,
|
||||
std::chrono::seconds tx_interval);
|
||||
|
||||
/** Set the flags on a hash.
|
||||
|
||||
@return `true` if the flags were changed. `false` if unchanged.
|
||||
*/
|
||||
bool setFlags (uint256 const& key, int flags);
|
||||
bool
|
||||
setFlags(uint256 const& key, int flags);
|
||||
|
||||
int getFlags (uint256 const& key);
|
||||
int
|
||||
getFlags(uint256 const& key);
|
||||
|
||||
/** Determines whether the hashed item should be relayed.
|
||||
|
||||
@@ -194,7 +219,8 @@ public:
|
||||
relayed to. If the result is uninitialized, the item should
|
||||
_not_ be relayed.
|
||||
*/
|
||||
boost::optional<std::set<PeerShortID>> shouldRelay(uint256 const& key);
|
||||
boost::optional<std::set<PeerShortID>>
|
||||
shouldRelay(uint256 const& key);
|
||||
|
||||
/** Determines whether the hashed item should be recovered
|
||||
from the open ledger into the next open ledger or the transaction
|
||||
@@ -202,23 +228,29 @@ public:
|
||||
|
||||
@return `bool` indicates whether the item should be recovered
|
||||
*/
|
||||
bool shouldRecover(uint256 const& key);
|
||||
bool
|
||||
shouldRecover(uint256 const& key);
|
||||
|
||||
private:
|
||||
// pair.second indicates whether the entry was created
|
||||
std::pair<Entry&, bool> emplace (uint256 const&);
|
||||
std::pair<Entry&, bool>
|
||||
emplace(uint256 const&);
|
||||
|
||||
std::mutex mutable mutex_;
|
||||
|
||||
// Stores all suppressed hashes and their expiration time
|
||||
beast::aged_unordered_map<uint256, Entry, Stopwatch::clock_type,
|
||||
hardened_hash<strong_hash>> suppressionMap_;
|
||||
beast::aged_unordered_map<
|
||||
uint256,
|
||||
Entry,
|
||||
Stopwatch::clock_type,
|
||||
hardened_hash<strong_hash>>
|
||||
suppressionMap_;
|
||||
|
||||
std::chrono::seconds const holdTime_;
|
||||
|
||||
std::uint32_t const recoverLimit_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#define RIPPLE_CORE_LOADFEETRACK_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/FeeUnits.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
@@ -43,51 +43,58 @@ struct Fees;
|
||||
class LoadFeeTrack final
|
||||
{
|
||||
public:
|
||||
explicit LoadFeeTrack (beast::Journal journal =
|
||||
beast::Journal(beast::Journal::getNullSink()))
|
||||
: j_ (journal)
|
||||
, localTxnLoadFee_ (lftNormalFee)
|
||||
, remoteTxnLoadFee_ (lftNormalFee)
|
||||
, clusterTxnLoadFee_ (lftNormalFee)
|
||||
, raiseCount_ (0)
|
||||
explicit LoadFeeTrack(
|
||||
beast::Journal journal = beast::Journal(beast::Journal::getNullSink()))
|
||||
: j_(journal)
|
||||
, localTxnLoadFee_(lftNormalFee)
|
||||
, remoteTxnLoadFee_(lftNormalFee)
|
||||
, clusterTxnLoadFee_(lftNormalFee)
|
||||
, raiseCount_(0)
|
||||
{
|
||||
}
|
||||
|
||||
~LoadFeeTrack() = default;
|
||||
|
||||
void setRemoteFee (std::uint32_t f)
|
||||
void
|
||||
setRemoteFee(std::uint32_t f)
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
remoteTxnLoadFee_ = f;
|
||||
}
|
||||
|
||||
std::uint32_t getRemoteFee () const
|
||||
std::uint32_t
|
||||
getRemoteFee() const
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
return remoteTxnLoadFee_;
|
||||
}
|
||||
|
||||
std::uint32_t getLocalFee () const
|
||||
std::uint32_t
|
||||
getLocalFee() const
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
return localTxnLoadFee_;
|
||||
}
|
||||
|
||||
std::uint32_t getClusterFee () const
|
||||
std::uint32_t
|
||||
getClusterFee() const
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
return clusterTxnLoadFee_;
|
||||
}
|
||||
|
||||
std::uint32_t getLoadBase () const
|
||||
std::uint32_t
|
||||
getLoadBase() const
|
||||
{
|
||||
return lftNormalFee;
|
||||
}
|
||||
|
||||
std::uint32_t getLoadFactor () const
|
||||
std::uint32_t
|
||||
getLoadFactor() const
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
return std::max({ clusterTxnLoadFee_, localTxnLoadFee_, remoteTxnLoadFee_ });
|
||||
std::lock_guard sl(lock_);
|
||||
return std::max(
|
||||
{clusterTxnLoadFee_, localTxnLoadFee_, remoteTxnLoadFee_});
|
||||
}
|
||||
|
||||
std::pair<std::uint32_t, std::uint32_t>
|
||||
@@ -100,41 +107,49 @@ public:
|
||||
std::max(remoteTxnLoadFee_, clusterTxnLoadFee_));
|
||||
}
|
||||
|
||||
|
||||
void setClusterFee (std::uint32_t fee)
|
||||
void
|
||||
setClusterFee(std::uint32_t fee)
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
clusterTxnLoadFee_ = fee;
|
||||
}
|
||||
|
||||
bool raiseLocalFee ();
|
||||
bool lowerLocalFee ();
|
||||
bool
|
||||
raiseLocalFee();
|
||||
bool
|
||||
lowerLocalFee();
|
||||
|
||||
bool isLoadedLocal () const
|
||||
bool
|
||||
isLoadedLocal() const
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
return (raiseCount_ != 0) || (localTxnLoadFee_ != lftNormalFee);
|
||||
}
|
||||
|
||||
bool isLoadedCluster () const
|
||||
bool
|
||||
isLoadedCluster() const
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
return (raiseCount_ != 0) || (localTxnLoadFee_ != lftNormalFee) ||
|
||||
(clusterTxnLoadFee_ != lftNormalFee);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::uint32_t constexpr lftNormalFee = 256; // 256 is the minimum/normal load factor
|
||||
static std::uint32_t constexpr lftFeeIncFraction = 4; // increase fee by 1/4
|
||||
static std::uint32_t constexpr lftFeeDecFraction = 4; // decrease fee by 1/4
|
||||
static std::uint32_t constexpr lftNormalFee =
|
||||
256; // 256 is the minimum/normal load factor
|
||||
static std::uint32_t constexpr lftFeeIncFraction =
|
||||
4; // increase fee by 1/4
|
||||
static std::uint32_t constexpr lftFeeDecFraction =
|
||||
4; // decrease fee by 1/4
|
||||
static std::uint32_t constexpr lftFeeMax = lftNormalFee * 1000000;
|
||||
|
||||
beast::Journal const j_;
|
||||
std::mutex mutable lock_;
|
||||
|
||||
std::uint32_t localTxnLoadFee_; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t remoteTxnLoadFee_; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t clusterTxnLoadFee_; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t localTxnLoadFee_; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t remoteTxnLoadFee_; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t
|
||||
clusterTxnLoadFee_; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t raiseCount_;
|
||||
};
|
||||
|
||||
@@ -142,9 +157,12 @@ private:
|
||||
|
||||
// Scale using load as well as base rate
|
||||
XRPAmount
|
||||
scaleFeeLoad(FeeUnit64 fee, LoadFeeTrack const& feeTrack,
|
||||
Fees const& fees, bool bUnlimited);
|
||||
scaleFeeLoad(
|
||||
FeeUnit64 fee,
|
||||
LoadFeeTrack const& feeTrack,
|
||||
Fees const& fees,
|
||||
bool bUnlimited);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#define RIPPLE_APP_MISC_MANIFEST_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/SecretKey.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <string>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace ripple {
|
||||
Validator key manifests
|
||||
-----------------------
|
||||
|
||||
Suppose the secret keys installed on a Ripple validator are compromised. Not
|
||||
Suppose the secret keys installed on a Ripple validator are compromised. Not
|
||||
only do you have to generate and install new key pairs on each validator,
|
||||
EVERY rippled needs to have its config updated with the new public keys, and
|
||||
is vulnerable to forged validation signatures until this is done. The
|
||||
@@ -94,24 +94,31 @@ struct Manifest
|
||||
|
||||
Manifest() = default;
|
||||
Manifest(Manifest const& other) = delete;
|
||||
Manifest& operator=(Manifest const& other) = delete;
|
||||
Manifest&
|
||||
operator=(Manifest const& other) = delete;
|
||||
Manifest(Manifest&& other) = default;
|
||||
Manifest& operator=(Manifest&& other) = default;
|
||||
Manifest&
|
||||
operator=(Manifest&& other) = default;
|
||||
|
||||
/// Returns `true` if manifest signature is valid
|
||||
bool verify () const;
|
||||
bool
|
||||
verify() const;
|
||||
|
||||
/// Returns hash of serialized manifest data
|
||||
uint256 hash () const;
|
||||
uint256
|
||||
hash() const;
|
||||
|
||||
/// Returns `true` if manifest revokes master key
|
||||
bool revoked () const;
|
||||
bool
|
||||
revoked() const;
|
||||
|
||||
/// Returns manifest signature
|
||||
boost::optional<Blob> getSignature () const;
|
||||
boost::optional<Blob>
|
||||
getSignature() const;
|
||||
|
||||
/// Returns manifest master key signature
|
||||
Blob getMasterSignature () const;
|
||||
Blob
|
||||
getMasterSignature() const;
|
||||
};
|
||||
|
||||
/** Constructs Manifest from serialized string
|
||||
@@ -127,15 +134,16 @@ struct Manifest
|
||||
boost::optional<Manifest>
|
||||
deserializeManifest(Slice s);
|
||||
|
||||
inline
|
||||
boost::optional<Manifest>
|
||||
inline boost::optional<Manifest>
|
||||
deserializeManifest(std::string const& s)
|
||||
{
|
||||
return deserializeManifest(makeSlice(s));
|
||||
}
|
||||
|
||||
template <class T, class = std::enable_if_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, unsigned char>::value>>
|
||||
template <
|
||||
class T,
|
||||
class = std::enable_if_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, unsigned char>::value>>
|
||||
boost::optional<Manifest>
|
||||
deserializeManifest(std::vector<T> const& v)
|
||||
{
|
||||
@@ -143,21 +151,17 @@ deserializeManifest(std::vector<T> const& v)
|
||||
}
|
||||
/** @} */
|
||||
|
||||
inline
|
||||
bool
|
||||
inline bool
|
||||
operator==(Manifest const& lhs, Manifest const& rhs)
|
||||
{
|
||||
// In theory, comparing the two serialized strings should be
|
||||
// sufficient.
|
||||
return lhs.sequence == rhs.sequence &&
|
||||
lhs.masterKey == rhs.masterKey &&
|
||||
lhs.signingKey == rhs.signingKey &&
|
||||
lhs.domain == rhs.domain &&
|
||||
return lhs.sequence == rhs.sequence && lhs.masterKey == rhs.masterKey &&
|
||||
lhs.signingKey == rhs.signingKey && lhs.domain == rhs.domain &&
|
||||
lhs.serialized == rhs.serialized;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
inline bool
|
||||
operator!=(Manifest const& lhs, Manifest const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
@@ -179,8 +183,7 @@ public:
|
||||
make_ValidatorToken(std::vector<std::string> const& tokenBlob);
|
||||
};
|
||||
|
||||
enum class ManifestDisposition
|
||||
{
|
||||
enum class ManifestDisposition {
|
||||
/// Manifest is valid
|
||||
accepted = 0,
|
||||
|
||||
@@ -218,16 +221,15 @@ private:
|
||||
std::mutex mutable read_mutex_;
|
||||
|
||||
/** Active manifests stored by master public key. */
|
||||
hash_map <PublicKey, Manifest> map_;
|
||||
hash_map<PublicKey, Manifest> map_;
|
||||
|
||||
/** Master public keys stored by current ephemeral public key. */
|
||||
hash_map <PublicKey, PublicKey> signingToMasterKeys_;
|
||||
hash_map<PublicKey, PublicKey> signingToMasterKeys_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
ManifestCache (beast::Journal j =
|
||||
beast::Journal(beast::Journal::getNullSink()))
|
||||
: j_ (j)
|
||||
explicit ManifestCache(
|
||||
beast::Journal j = beast::Journal(beast::Journal::getNullSink()))
|
||||
: j_(j)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -242,7 +244,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
PublicKey
|
||||
getSigningKey (PublicKey const& pk) const;
|
||||
getSigningKey(PublicKey const& pk) const;
|
||||
|
||||
/** Returns ephemeral signing key's master public key.
|
||||
|
||||
@@ -255,7 +257,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
PublicKey
|
||||
getMasterKey (PublicKey const& pk) const;
|
||||
getMasterKey(PublicKey const& pk) const;
|
||||
|
||||
/** Returns master key's current manifest sequence.
|
||||
|
||||
@@ -263,7 +265,7 @@ public:
|
||||
if configured or boost::none otherwise
|
||||
*/
|
||||
boost::optional<std::uint32_t>
|
||||
getSequence (PublicKey const& pk) const;
|
||||
getSequence(PublicKey const& pk) const;
|
||||
|
||||
/** Returns domain claimed by a given public key
|
||||
|
||||
@@ -271,7 +273,7 @@ public:
|
||||
if present, otherwise boost::none
|
||||
*/
|
||||
boost::optional<std::string>
|
||||
getDomain (PublicKey const& pk) const;
|
||||
getDomain(PublicKey const& pk) const;
|
||||
|
||||
/** Returns mainfest corresponding to a given public key
|
||||
|
||||
@@ -279,7 +281,7 @@ public:
|
||||
if present, otherwise boost::none
|
||||
*/
|
||||
boost::optional<std::string>
|
||||
getManifest (PublicKey const& pk) const;
|
||||
getManifest(PublicKey const& pk) const;
|
||||
|
||||
/** Returns `true` if master key has been revoked in a manifest.
|
||||
|
||||
@@ -290,7 +292,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
bool
|
||||
revoked (PublicKey const& pk) const;
|
||||
revoked(PublicKey const& pk) const;
|
||||
|
||||
/** Add manifest to cache.
|
||||
|
||||
@@ -304,8 +306,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
ManifestDisposition
|
||||
applyManifest (
|
||||
Manifest m);
|
||||
applyManifest(Manifest m);
|
||||
|
||||
/** Populate manifest cache with manifests in database and config.
|
||||
|
||||
@@ -323,8 +324,10 @@ public:
|
||||
|
||||
May be called concurrently
|
||||
*/
|
||||
bool load (
|
||||
DatabaseCon& dbCon, std::string const& dbTable,
|
||||
bool
|
||||
load(
|
||||
DatabaseCon& dbCon,
|
||||
std::string const& dbTable,
|
||||
std::string const& configManifest,
|
||||
std::vector<std::string> const& configRevocation);
|
||||
|
||||
@@ -338,8 +341,8 @@ public:
|
||||
|
||||
May be called concurrently
|
||||
*/
|
||||
void load (
|
||||
DatabaseCon& dbCon, std::string const& dbTable);
|
||||
void
|
||||
load(DatabaseCon& dbCon, std::string const& dbTable);
|
||||
|
||||
/** Save cached manifests to database.
|
||||
|
||||
@@ -351,9 +354,11 @@ public:
|
||||
|
||||
May be called concurrently
|
||||
*/
|
||||
void save (
|
||||
DatabaseCon& dbCon, std::string const& dbTable,
|
||||
std::function <bool (PublicKey const&)> isTrusted);
|
||||
void
|
||||
save(
|
||||
DatabaseCon& dbCon,
|
||||
std::string const& dbTable,
|
||||
std::function<bool(PublicKey const&)> isTrusted);
|
||||
|
||||
/** Invokes the callback once for every populated manifest.
|
||||
|
||||
@@ -397,7 +402,7 @@ public:
|
||||
for_each_manifest(PreFun&& pf, EachFun&& f) const
|
||||
{
|
||||
std::lock_guard lock{read_mutex_};
|
||||
pf(map_.size ());
|
||||
pf(map_.size());
|
||||
for (auto const& [_, manifest] : map_)
|
||||
{
|
||||
(void)_;
|
||||
@@ -406,6 +411,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,16 +20,16 @@
|
||||
#ifndef RIPPLE_APP_MISC_NETWORKOPS_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_NETWORKOPS_H_INCLUDED
|
||||
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/app/consensus/RCLCxPeerPos.h>
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/core/JobQueue.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/net/InfoSub.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
#include <ripple/protocol/messages.h>
|
||||
@@ -65,13 +65,12 @@ class ValidatorKeys;
|
||||
not change them without verifying each use and ensuring that it is
|
||||
not a breaking change.
|
||||
*/
|
||||
enum class OperatingMode
|
||||
{
|
||||
DISCONNECTED = 0, //!< not ready to process requests
|
||||
CONNECTED = 1, //!< convinced we are talking to the network
|
||||
SYNCING = 2, //!< fallen slightly behind
|
||||
TRACKING = 3, //!< convinced we agree with the network
|
||||
FULL = 4 //!< we have the ledger and can even validate
|
||||
enum class OperatingMode {
|
||||
DISCONNECTED = 0, //!< not ready to process requests
|
||||
CONNECTED = 1, //!< convinced we are talking to the network
|
||||
SYNCING = 2, //!< fallen slightly behind
|
||||
TRACKING = 3, //!< convinced we agree with the network
|
||||
FULL = 4 //!< we have the ledger and can even validate
|
||||
};
|
||||
|
||||
/** Provides server functionality for clients.
|
||||
@@ -86,37 +85,36 @@ enum class OperatingMode
|
||||
instances of rippled will need to be hardened to protect against hostile
|
||||
or unreliable servers.
|
||||
*/
|
||||
class NetworkOPs
|
||||
: public InfoSub::Source
|
||||
class NetworkOPs : public InfoSub::Source
|
||||
{
|
||||
protected:
|
||||
explicit NetworkOPs (Stoppable& parent);
|
||||
explicit NetworkOPs(Stoppable& parent);
|
||||
|
||||
public:
|
||||
using clock_type = beast::abstract_clock <std::chrono::steady_clock>;
|
||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
|
||||
enum class FailHard : unsigned char
|
||||
{
|
||||
no,
|
||||
yes
|
||||
};
|
||||
static inline FailHard doFailHard (bool noMeansDont)
|
||||
enum class FailHard : unsigned char { no, yes };
|
||||
static inline FailHard
|
||||
doFailHard(bool noMeansDont)
|
||||
{
|
||||
return noMeansDont ? FailHard::yes : FailHard::no;
|
||||
}
|
||||
|
||||
public:
|
||||
~NetworkOPs () override = default;
|
||||
~NetworkOPs() override = default;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Network information
|
||||
//
|
||||
|
||||
virtual OperatingMode getOperatingMode () const = 0;
|
||||
virtual std::string strOperatingMode (
|
||||
OperatingMode const mode, bool const admin = false) const = 0;
|
||||
virtual std::string strOperatingMode (bool const admin = false) const = 0;
|
||||
virtual OperatingMode
|
||||
getOperatingMode() const = 0;
|
||||
virtual std::string
|
||||
strOperatingMode(OperatingMode const mode, bool const admin = false)
|
||||
const = 0;
|
||||
virtual std::string
|
||||
strOperatingMode(bool const admin = false) const = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
@@ -124,7 +122,8 @@ public:
|
||||
//
|
||||
|
||||
// must complete immediately
|
||||
virtual void submitTransaction (std::shared_ptr<STTx const> const&) = 0;
|
||||
virtual void
|
||||
submitTransaction(std::shared_ptr<STTx const> const&) = 0;
|
||||
|
||||
/**
|
||||
* Process transactions as they arrive from the network or which are
|
||||
@@ -135,15 +134,21 @@ public:
|
||||
* @param bLocal Client submission.
|
||||
* @param failType fail_hard setting from transaction submission.
|
||||
*/
|
||||
virtual void processTransaction (std::shared_ptr<Transaction>& transaction,
|
||||
bool bUnlimited, bool bLocal, FailHard failType) = 0;
|
||||
virtual void
|
||||
processTransaction(
|
||||
std::shared_ptr<Transaction>& transaction,
|
||||
bool bUnlimited,
|
||||
bool bLocal,
|
||||
FailHard failType) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Owner functions
|
||||
//
|
||||
|
||||
virtual Json::Value getOwnerInfo (std::shared_ptr<ReadView const> lpLedger,
|
||||
virtual Json::Value
|
||||
getOwnerInfo(
|
||||
std::shared_ptr<ReadView const> lpLedger,
|
||||
AccountID const& account) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -151,7 +156,8 @@ public:
|
||||
// Book functions
|
||||
//
|
||||
|
||||
virtual void getBookPage (
|
||||
virtual void
|
||||
getBookPage(
|
||||
std::shared_ptr<ReadView const>& lpLedger,
|
||||
Book const& book,
|
||||
AccountID const& uTakerID,
|
||||
@@ -163,38 +169,58 @@ public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// ledger proposal/close functions
|
||||
virtual void processTrustedProposal (RCLCxPeerPos peerPos,
|
||||
virtual void
|
||||
processTrustedProposal(
|
||||
RCLCxPeerPos peerPos,
|
||||
std::shared_ptr<protocol::TMProposeSet> set) = 0;
|
||||
|
||||
virtual bool recvValidation (STValidation::ref val,
|
||||
std::string const& source) = 0;
|
||||
virtual bool
|
||||
recvValidation(STValidation::ref val, std::string const& source) = 0;
|
||||
|
||||
virtual void mapComplete (std::shared_ptr<SHAMap> const& map,
|
||||
bool fromAcquire) = 0;
|
||||
virtual void
|
||||
mapComplete(std::shared_ptr<SHAMap> const& map, bool fromAcquire) = 0;
|
||||
|
||||
// network state machine
|
||||
virtual bool beginConsensus (uint256 const& netLCL) = 0;
|
||||
virtual void endConsensus () = 0;
|
||||
virtual void setStandAlone () = 0;
|
||||
virtual void setStateTimer () = 0;
|
||||
virtual bool
|
||||
beginConsensus(uint256 const& netLCL) = 0;
|
||||
virtual void
|
||||
endConsensus() = 0;
|
||||
virtual void
|
||||
setStandAlone() = 0;
|
||||
virtual void
|
||||
setStateTimer() = 0;
|
||||
|
||||
virtual void setNeedNetworkLedger () = 0;
|
||||
virtual void clearNeedNetworkLedger () = 0;
|
||||
virtual bool isNeedNetworkLedger () = 0;
|
||||
virtual bool isFull () = 0;
|
||||
virtual void setMode(OperatingMode om) = 0;
|
||||
virtual bool isAmendmentBlocked () = 0;
|
||||
virtual void setAmendmentBlocked () = 0;
|
||||
virtual bool isAmendmentWarned() = 0;
|
||||
virtual void setAmendmentWarned() = 0;
|
||||
virtual void clearAmendmentWarned() = 0;
|
||||
virtual void consensusViewChange () = 0;
|
||||
virtual void
|
||||
setNeedNetworkLedger() = 0;
|
||||
virtual void
|
||||
clearNeedNetworkLedger() = 0;
|
||||
virtual bool
|
||||
isNeedNetworkLedger() = 0;
|
||||
virtual bool
|
||||
isFull() = 0;
|
||||
virtual void
|
||||
setMode(OperatingMode om) = 0;
|
||||
virtual bool
|
||||
isAmendmentBlocked() = 0;
|
||||
virtual void
|
||||
setAmendmentBlocked() = 0;
|
||||
virtual bool
|
||||
isAmendmentWarned() = 0;
|
||||
virtual void
|
||||
setAmendmentWarned() = 0;
|
||||
virtual void
|
||||
clearAmendmentWarned() = 0;
|
||||
virtual void
|
||||
consensusViewChange() = 0;
|
||||
|
||||
virtual Json::Value getConsensusInfo () = 0;
|
||||
virtual Json::Value getServerInfo (
|
||||
bool human, bool admin, bool counters) = 0;
|
||||
virtual void clearLedgerFetch () = 0;
|
||||
virtual Json::Value getLedgerFetchInfo () = 0;
|
||||
virtual Json::Value
|
||||
getConsensusInfo() = 0;
|
||||
virtual Json::Value
|
||||
getServerInfo(bool human, bool admin, bool counters) = 0;
|
||||
virtual void
|
||||
clearLedgerFetch() = 0;
|
||||
virtual Json::Value
|
||||
getLedgerFetchInfo() = 0;
|
||||
|
||||
/** Accepts the current transaction tree, return the new ledger's sequence
|
||||
|
||||
@@ -202,15 +228,21 @@ public:
|
||||
performs a virtual consensus round, with all the transactions we are
|
||||
proposing being accepted.
|
||||
*/
|
||||
virtual std::uint32_t acceptLedger (
|
||||
boost::optional<std::chrono::milliseconds> consensusDelay = boost::none) = 0;
|
||||
virtual std::uint32_t
|
||||
acceptLedger(
|
||||
boost::optional<std::chrono::milliseconds> consensusDelay =
|
||||
boost::none) = 0;
|
||||
|
||||
virtual uint256 getConsensusLCL () = 0;
|
||||
virtual uint256
|
||||
getConsensusLCL() = 0;
|
||||
|
||||
virtual void reportFeeChange () = 0;
|
||||
virtual void
|
||||
reportFeeChange() = 0;
|
||||
|
||||
virtual void updateLocalTx (ReadView const& newValidLedger) = 0;
|
||||
virtual std::size_t getLocalTxCount () = 0;
|
||||
virtual void
|
||||
updateLocalTx(ReadView const& newValidLedger) = 0;
|
||||
virtual std::size_t
|
||||
getLocalTxCount() = 0;
|
||||
|
||||
struct AccountTxMarker
|
||||
{
|
||||
@@ -219,13 +251,18 @@ public:
|
||||
};
|
||||
|
||||
// client information retrieval functions
|
||||
using AccountTx = std::pair<std::shared_ptr<Transaction>, TxMeta::pointer>;
|
||||
using AccountTx = std::pair<std::shared_ptr<Transaction>, TxMeta::pointer>;
|
||||
using AccountTxs = std::vector<AccountTx>;
|
||||
|
||||
virtual AccountTxs getAccountTxs (
|
||||
virtual AccountTxs
|
||||
getAccountTxs(
|
||||
AccountID const& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||
std::uint32_t offset, int limit, bool bUnlimited) = 0;
|
||||
std::int32_t minLedger,
|
||||
std::int32_t maxLedger,
|
||||
bool descending,
|
||||
std::uint32_t offset,
|
||||
int limit,
|
||||
bool bUnlimited) = 0;
|
||||
|
||||
virtual AccountTxs
|
||||
getTxsAccount(
|
||||
@@ -238,11 +275,17 @@ public:
|
||||
bool bUnlimited) = 0;
|
||||
|
||||
using txnMetaLedgerType = std::tuple<Blob, Blob, std::uint32_t>;
|
||||
using MetaTxsList = std::vector<txnMetaLedgerType>;
|
||||
using MetaTxsList = std::vector<txnMetaLedgerType>;
|
||||
|
||||
virtual MetaTxsList getAccountTxsB (AccountID const& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||
std::uint32_t offset, int limit, bool bUnlimited) = 0;
|
||||
virtual MetaTxsList
|
||||
getAccountTxsB(
|
||||
AccountID const& account,
|
||||
std::int32_t minLedger,
|
||||
std::int32_t maxLedger,
|
||||
bool descending,
|
||||
std::uint32_t offset,
|
||||
int limit,
|
||||
bool bUnlimited) = 0;
|
||||
|
||||
virtual MetaTxsList
|
||||
getTxsAccountB(
|
||||
@@ -258,26 +301,34 @@ public:
|
||||
//
|
||||
// Monitoring: publisher side
|
||||
//
|
||||
virtual void pubLedger (
|
||||
std::shared_ptr<ReadView const> const& lpAccepted) = 0;
|
||||
virtual void pubProposedTransaction (
|
||||
virtual void
|
||||
pubLedger(std::shared_ptr<ReadView const> const& lpAccepted) = 0;
|
||||
virtual void
|
||||
pubProposedTransaction(
|
||||
std::shared_ptr<ReadView const> const& lpCurrent,
|
||||
std::shared_ptr<STTx const> const& stTxn, TER terResult) = 0;
|
||||
virtual void pubValidation (STValidation::ref val) = 0;
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<STTx const> const& stTxn,
|
||||
TER terResult) = 0;
|
||||
virtual void
|
||||
pubValidation(STValidation::ref val) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::unique_ptr<NetworkOPs>
|
||||
make_NetworkOPs (Application& app, NetworkOPs::clock_type& clock,
|
||||
bool standalone, std::size_t minPeerCount, bool start_valid,
|
||||
JobQueue& job_queue, LedgerMaster& ledgerMaster, Stoppable& parent,
|
||||
ValidatorKeys const & validatorKeys, boost::asio::io_service& io_svc,
|
||||
beast::Journal journal, beast::insight::Collector::ptr const& collector);
|
||||
make_NetworkOPs(
|
||||
Application& app,
|
||||
NetworkOPs::clock_type& clock,
|
||||
bool standalone,
|
||||
std::size_t minPeerCount,
|
||||
bool start_valid,
|
||||
JobQueue& job_queue,
|
||||
LedgerMaster& ledgerMaster,
|
||||
Stoppable& parent,
|
||||
ValidatorKeys const& validatorKeys,
|
||||
boost::asio::io_service& io_svc,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector);
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,8 +26,8 @@ namespace ripple {
|
||||
class OrderBook
|
||||
{
|
||||
public:
|
||||
using pointer = std::shared_ptr <OrderBook>;
|
||||
using ref = std::shared_ptr <OrderBook> const&;
|
||||
using pointer = std::shared_ptr<OrderBook>;
|
||||
using ref = std::shared_ptr<OrderBook> const&;
|
||||
using List = std::vector<pointer>;
|
||||
|
||||
/** Construct from a currency specification.
|
||||
@@ -36,37 +36,43 @@ public:
|
||||
@param book in and out currency/issuer pairs.
|
||||
*/
|
||||
// VFALCO NOTE what is the meaning of the index parameter?
|
||||
OrderBook (uint256 const& base, Book const& book)
|
||||
: mBookBase(base), mBook(book)
|
||||
OrderBook(uint256 const& base, Book const& book)
|
||||
: mBookBase(base), mBook(book)
|
||||
{
|
||||
}
|
||||
|
||||
uint256 const& getBookBase () const
|
||||
uint256 const&
|
||||
getBookBase() const
|
||||
{
|
||||
return mBookBase;
|
||||
}
|
||||
|
||||
Book const& book() const
|
||||
Book const&
|
||||
book() const
|
||||
{
|
||||
return mBook;
|
||||
}
|
||||
|
||||
Currency const& getCurrencyIn () const
|
||||
Currency const&
|
||||
getCurrencyIn() const
|
||||
{
|
||||
return mBook.in.currency;
|
||||
}
|
||||
|
||||
Currency const& getCurrencyOut () const
|
||||
Currency const&
|
||||
getCurrencyOut() const
|
||||
{
|
||||
return mBook.out.currency;
|
||||
}
|
||||
|
||||
AccountID const& getIssuerIn () const
|
||||
AccountID const&
|
||||
getIssuerIn() const
|
||||
{
|
||||
return mBook.in.account;
|
||||
}
|
||||
|
||||
AccountID const& getIssuerOut () const
|
||||
AccountID const&
|
||||
getIssuerOut() const
|
||||
{
|
||||
return mBook.out.account;
|
||||
}
|
||||
@@ -76,6 +82,6 @@ private:
|
||||
Book const mBook;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#define RIPPLE_APP_MISC_SHAMAPSTORE_H_INCLUDED
|
||||
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
#include <ripple/nodestore/Manager.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/core/Stoppable.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -33,39 +33,47 @@ class TransactionMaster;
|
||||
* class to create database, launch online delete thread, and
|
||||
* related SQLite database
|
||||
*/
|
||||
class SHAMapStore
|
||||
: public Stoppable
|
||||
class SHAMapStore : public Stoppable
|
||||
{
|
||||
public:
|
||||
SHAMapStore (Stoppable& parent) : Stoppable ("SHAMapStore", parent) {}
|
||||
SHAMapStore(Stoppable& parent) : Stoppable("SHAMapStore", parent)
|
||||
{
|
||||
}
|
||||
|
||||
/** Called by LedgerMaster every time a ledger validates. */
|
||||
virtual void onLedgerClosed(std::shared_ptr<Ledger const> const& ledger) = 0;
|
||||
virtual void
|
||||
onLedgerClosed(std::shared_ptr<Ledger const> const& ledger) = 0;
|
||||
|
||||
virtual void rendezvous() const = 0;
|
||||
virtual void
|
||||
rendezvous() const = 0;
|
||||
|
||||
virtual std::uint32_t clampFetchDepth (std::uint32_t fetch_depth) const = 0;
|
||||
virtual std::uint32_t
|
||||
clampFetchDepth(std::uint32_t fetch_depth) const = 0;
|
||||
|
||||
virtual
|
||||
std::unique_ptr <NodeStore::Database>
|
||||
virtual std::unique_ptr<NodeStore::Database>
|
||||
makeNodeStore(std::string const& name, std::int32_t readThreads) = 0;
|
||||
|
||||
/** Highest ledger that may be deleted. */
|
||||
virtual LedgerIndex setCanDelete (LedgerIndex canDelete) = 0;
|
||||
virtual LedgerIndex
|
||||
setCanDelete(LedgerIndex canDelete) = 0;
|
||||
|
||||
/** Whether advisory delete is enabled. */
|
||||
virtual bool advisoryDelete() const = 0;
|
||||
virtual bool
|
||||
advisoryDelete() const = 0;
|
||||
|
||||
/** Maximum ledger that has been deleted, or will be deleted if
|
||||
* currently in the act of online deletion.
|
||||
*/
|
||||
virtual LedgerIndex getLastRotated() = 0;
|
||||
virtual LedgerIndex
|
||||
getLastRotated() = 0;
|
||||
|
||||
/** Highest ledger that may be deleted. */
|
||||
virtual LedgerIndex getCanDelete() = 0;
|
||||
virtual LedgerIndex
|
||||
getCanDelete() = 0;
|
||||
|
||||
/** Returns the number of file descriptors that are needed. */
|
||||
virtual int fdRequired() const = 0;
|
||||
virtual int
|
||||
fdRequired() const = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -76,6 +84,6 @@ make_SHAMapStore(
|
||||
Stoppable& parent,
|
||||
NodeStore::Scheduler& scheduler,
|
||||
beast::Journal journal);
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
|
||||
#include <ripple/app/ledger/TransactionMaster.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/app/misc/SHAMapStoreImp.h>
|
||||
@@ -28,63 +27,58 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
namespace ripple {
|
||||
void SHAMapStoreImp::SavedStateDB::init (BasicConfig const& config,
|
||||
std::string const& dbName)
|
||||
void
|
||||
SHAMapStoreImp::SavedStateDB::init(
|
||||
BasicConfig const& config,
|
||||
std::string const& dbName)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
open(session_, config, dbName);
|
||||
|
||||
session_ << "PRAGMA synchronous=FULL;";
|
||||
|
||||
session_ <<
|
||||
"CREATE TABLE IF NOT EXISTS DbState ("
|
||||
" Key INTEGER PRIMARY KEY,"
|
||||
" WritableDb TEXT,"
|
||||
" ArchiveDb TEXT,"
|
||||
" LastRotatedLedger INTEGER"
|
||||
");"
|
||||
;
|
||||
session_ << "CREATE TABLE IF NOT EXISTS DbState ("
|
||||
" Key INTEGER PRIMARY KEY,"
|
||||
" WritableDb TEXT,"
|
||||
" ArchiveDb TEXT,"
|
||||
" LastRotatedLedger INTEGER"
|
||||
");";
|
||||
|
||||
session_ <<
|
||||
"CREATE TABLE IF NOT EXISTS CanDelete ("
|
||||
" Key INTEGER PRIMARY KEY,"
|
||||
" CanDeleteSeq INTEGER"
|
||||
");"
|
||||
;
|
||||
session_ << "CREATE TABLE IF NOT EXISTS CanDelete ("
|
||||
" Key INTEGER PRIMARY KEY,"
|
||||
" CanDeleteSeq INTEGER"
|
||||
");";
|
||||
|
||||
std::int64_t count = 0;
|
||||
{
|
||||
boost::optional<std::int64_t> countO;
|
||||
session_ <<
|
||||
"SELECT COUNT(Key) FROM DbState WHERE Key = 1;"
|
||||
, soci::into (countO);
|
||||
session_ << "SELECT COUNT(Key) FROM DbState WHERE Key = 1;",
|
||||
soci::into(countO);
|
||||
if (!countO)
|
||||
Throw<std::runtime_error> ("Failed to fetch Key Count from DbState.");
|
||||
Throw<std::runtime_error>(
|
||||
"Failed to fetch Key Count from DbState.");
|
||||
count = *countO;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
session_ <<
|
||||
"INSERT INTO DbState VALUES (1, '', '', 0);";
|
||||
session_ << "INSERT INTO DbState VALUES (1, '', '', 0);";
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
boost::optional<std::int64_t> countO;
|
||||
session_ <<
|
||||
"SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;"
|
||||
, soci::into (countO);
|
||||
session_ << "SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;",
|
||||
soci::into(countO);
|
||||
if (!countO)
|
||||
Throw<std::runtime_error> ("Failed to fetch Key Count from CanDelete.");
|
||||
Throw<std::runtime_error>(
|
||||
"Failed to fetch Key Count from CanDelete.");
|
||||
count = *countO;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
session_ <<
|
||||
"INSERT INTO CanDelete VALUES (1, 0);";
|
||||
session_ << "INSERT INTO CanDelete VALUES (1, 0);";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,25 +86,22 @@ LedgerIndex
|
||||
SHAMapStoreImp::SavedStateDB::getCanDelete()
|
||||
{
|
||||
LedgerIndex seq;
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
session_ <<
|
||||
"SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;"
|
||||
, soci::into (seq);
|
||||
session_ << "SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;",
|
||||
soci::into(seq);
|
||||
;
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
LedgerIndex
|
||||
SHAMapStoreImp::SavedStateDB::setCanDelete (LedgerIndex canDelete)
|
||||
SHAMapStoreImp::SavedStateDB::setCanDelete(LedgerIndex canDelete)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
session_ <<
|
||||
"UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;"
|
||||
, soci::use (canDelete)
|
||||
;
|
||||
session_ << "UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;",
|
||||
soci::use(canDelete);
|
||||
|
||||
return canDelete;
|
||||
}
|
||||
@@ -120,43 +111,36 @@ SHAMapStoreImp::SavedStateDB::getState()
|
||||
{
|
||||
SavedState state;
|
||||
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
session_ <<
|
||||
"SELECT WritableDb, ArchiveDb, LastRotatedLedger"
|
||||
" FROM DbState WHERE Key = 1;"
|
||||
, soci::into (state.writableDb), soci::into (state.archiveDb)
|
||||
, soci::into (state.lastRotated)
|
||||
;
|
||||
session_ << "SELECT WritableDb, ArchiveDb, LastRotatedLedger"
|
||||
" FROM DbState WHERE Key = 1;",
|
||||
soci::into(state.writableDb), soci::into(state.archiveDb),
|
||||
soci::into(state.lastRotated);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapStoreImp::SavedStateDB::setState (SavedState const& state)
|
||||
SHAMapStoreImp::SavedStateDB::setState(SavedState const& state)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
session_ <<
|
||||
"UPDATE DbState"
|
||||
" SET WritableDb = :writableDb,"
|
||||
" ArchiveDb = :archiveDb,"
|
||||
" LastRotatedLedger = :lastRotated"
|
||||
" WHERE Key = 1;"
|
||||
, soci::use (state.writableDb)
|
||||
, soci::use (state.archiveDb)
|
||||
, soci::use (state.lastRotated)
|
||||
;
|
||||
std::lock_guard lock(mutex_);
|
||||
session_ << "UPDATE DbState"
|
||||
" SET WritableDb = :writableDb,"
|
||||
" ArchiveDb = :archiveDb,"
|
||||
" LastRotatedLedger = :lastRotated"
|
||||
" WHERE Key = 1;",
|
||||
soci::use(state.writableDb), soci::use(state.archiveDb),
|
||||
soci::use(state.lastRotated);
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapStoreImp::SavedStateDB::setLastRotated (LedgerIndex seq)
|
||||
SHAMapStoreImp::SavedStateDB::setLastRotated(LedgerIndex seq)
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
session_ <<
|
||||
"UPDATE DbState SET LastRotatedLedger = :seq"
|
||||
" WHERE Key = 1;"
|
||||
, soci::use (seq)
|
||||
;
|
||||
std::lock_guard lock(mutex_);
|
||||
session_ << "UPDATE DbState SET LastRotatedLedger = :seq"
|
||||
" WHERE Key = 1;",
|
||||
soci::use(seq);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -166,31 +150,30 @@ SHAMapStoreImp::SHAMapStoreImp(
|
||||
Stoppable& parent,
|
||||
NodeStore::Scheduler& scheduler,
|
||||
beast::Journal journal)
|
||||
: SHAMapStore (parent)
|
||||
, app_ (app)
|
||||
, scheduler_ (scheduler)
|
||||
, journal_ (journal)
|
||||
: SHAMapStore(parent)
|
||||
, app_(app)
|
||||
, scheduler_(scheduler)
|
||||
, journal_(journal)
|
||||
, working_(true)
|
||||
, canDelete_ (std::numeric_limits <LedgerIndex>::max())
|
||||
, canDelete_(std::numeric_limits<LedgerIndex>::max())
|
||||
{
|
||||
Config& config {app.config()};
|
||||
Section& section {config.section(ConfigSection::nodeDatabase())};
|
||||
Config& config{app.config()};
|
||||
Section& section{config.section(ConfigSection::nodeDatabase())};
|
||||
if (section.empty())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"Missing [" + ConfigSection::nodeDatabase() +
|
||||
"] entry in configuration file");
|
||||
|
||||
}
|
||||
|
||||
// RocksDB only. Use sensible defaults if no values specified.
|
||||
if (boost::iequals(
|
||||
get<std::string>(section, "type"), "RocksDB"))
|
||||
if (boost::iequals(get<std::string>(section, "type"), "RocksDB"))
|
||||
{
|
||||
if (!section.exists("cache_mb"))
|
||||
{
|
||||
section.set("cache_mb", std::to_string(
|
||||
config.getValueFor(SizedItem::hashNodeDBCache)));
|
||||
section.set(
|
||||
"cache_mb",
|
||||
std::to_string(config.getValueFor(SizedItem::hashNodeDBCache)));
|
||||
}
|
||||
|
||||
if (!section.exists("filter_bits") && (config.NODE_SIZE >= 2))
|
||||
@@ -206,19 +189,22 @@ SHAMapStoreImp::SHAMapStoreImp(
|
||||
{
|
||||
get_if_exists(section, "advisory_delete", advisoryDelete_);
|
||||
|
||||
auto const minInterval = config.standalone() ?
|
||||
minimumDeletionIntervalSA_ : minimumDeletionInterval_;
|
||||
auto const minInterval = config.standalone()
|
||||
? minimumDeletionIntervalSA_
|
||||
: minimumDeletionInterval_;
|
||||
if (deleteInterval_ < minInterval)
|
||||
{
|
||||
Throw<std::runtime_error>("online_delete must be at least " +
|
||||
std::to_string (minInterval));
|
||||
Throw<std::runtime_error>(
|
||||
"online_delete must be at least " +
|
||||
std::to_string(minInterval));
|
||||
}
|
||||
|
||||
if (config.LEDGER_HISTORY > deleteInterval_)
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"online_delete must not be less than ledger_history (currently " +
|
||||
std::to_string (config.LEDGER_HISTORY) + ")");
|
||||
"online_delete must not be less than ledger_history "
|
||||
"(currently " +
|
||||
std::to_string(config.LEDGER_HISTORY) + ")");
|
||||
}
|
||||
|
||||
state_db_.init(config, dbName_);
|
||||
@@ -226,22 +212,22 @@ SHAMapStoreImp::SHAMapStoreImp(
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr <NodeStore::Database>
|
||||
std::unique_ptr<NodeStore::Database>
|
||||
SHAMapStoreImp::makeNodeStore(std::string const& name, std::int32_t readThreads)
|
||||
{
|
||||
// Anything which calls addJob must be a descendant of the JobQueue.
|
||||
// Therefore Database objects use the JobQueue as Stoppable parent.
|
||||
std::unique_ptr <NodeStore::Database> db;
|
||||
std::unique_ptr<NodeStore::Database> db;
|
||||
if (deleteInterval_)
|
||||
{
|
||||
SavedState state = state_db_.getState();
|
||||
auto writableBackend = makeBackendRotating(state.writableDb);
|
||||
auto archiveBackend = makeBackendRotating(state.archiveDb);
|
||||
if (! state.writableDb.size())
|
||||
if (!state.writableDb.size())
|
||||
{
|
||||
state.writableDb = writableBackend->getName();
|
||||
state.archiveDb = archiveBackend->getName();
|
||||
state_db_.setState (state);
|
||||
state_db_.setState(state);
|
||||
}
|
||||
|
||||
// Create NodeStore with two backends to allow online deletion of data
|
||||
@@ -273,11 +259,10 @@ SHAMapStoreImp::makeNodeStore(std::string const& name, std::int32_t readThreads)
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapStoreImp::onLedgerClosed(
|
||||
std::shared_ptr<Ledger const> const& ledger)
|
||||
SHAMapStoreImp::onLedgerClosed(std::shared_ptr<Ledger const> const& ledger)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
newLedger_ = ledger;
|
||||
working_ = true;
|
||||
}
|
||||
@@ -290,11 +275,8 @@ SHAMapStoreImp::rendezvous() const
|
||||
if (!working_)
|
||||
return;
|
||||
|
||||
std::unique_lock <std::mutex> lock(mutex_);
|
||||
rendezvous_.wait(lock, [&]
|
||||
{
|
||||
return !working_;
|
||||
});
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
rendezvous_.wait(lock, [&] { return !working_; });
|
||||
}
|
||||
|
||||
int
|
||||
@@ -304,12 +286,13 @@ SHAMapStoreImp::fdRequired() const
|
||||
}
|
||||
|
||||
bool
|
||||
SHAMapStoreImp::copyNode (std::uint64_t& nodeCount,
|
||||
SHAMapAbstractNode const& node)
|
||||
SHAMapStoreImp::copyNode(
|
||||
std::uint64_t& nodeCount,
|
||||
SHAMapAbstractNode const& node)
|
||||
{
|
||||
// Copy a single record from node to dbRotating_
|
||||
dbRotating_->fetch(node.getNodeHash().as_uint256(), node.getSeq());
|
||||
if (! (++nodeCount % checkHealthInterval_))
|
||||
if (!(++nodeCount % checkHealthInterval_))
|
||||
{
|
||||
if (health())
|
||||
return false;
|
||||
@@ -321,7 +304,7 @@ SHAMapStoreImp::copyNode (std::uint64_t& nodeCount,
|
||||
void
|
||||
SHAMapStoreImp::run()
|
||||
{
|
||||
beast::setCurrentThreadName ("SHAMapStore");
|
||||
beast::setCurrentThreadName("SHAMapStore");
|
||||
lastRotated_ = state_db_.getState().lastRotated;
|
||||
netOPs_ = &app_.getOPs();
|
||||
ledgerMaster_ = &app_.getLedgerMaster();
|
||||
@@ -331,7 +314,7 @@ SHAMapStoreImp::run()
|
||||
ledgerDb_ = &app_.getLedgerDB();
|
||||
|
||||
if (advisoryDelete_)
|
||||
canDelete_ = state_db_.getCanDelete ();
|
||||
canDelete_ = state_db_.getCanDelete();
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -339,7 +322,7 @@ SHAMapStoreImp::run()
|
||||
std::shared_ptr<Ledger const> validatedLedger;
|
||||
|
||||
{
|
||||
std::unique_lock <std::mutex> lock (mutex_);
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
working_ = false;
|
||||
rendezvous_.notify_all();
|
||||
if (stop_)
|
||||
@@ -347,7 +330,7 @@ SHAMapStoreImp::run()
|
||||
stopped();
|
||||
return;
|
||||
}
|
||||
cond_.wait (lock);
|
||||
cond_.wait(lock);
|
||||
if (newLedger_)
|
||||
{
|
||||
validatedLedger = std::move(newLedger_);
|
||||
@@ -360,16 +343,17 @@ SHAMapStoreImp::run()
|
||||
if (!lastRotated_)
|
||||
{
|
||||
lastRotated_ = validatedSeq;
|
||||
state_db_.setLastRotated (lastRotated_);
|
||||
state_db_.setLastRotated(lastRotated_);
|
||||
}
|
||||
|
||||
// will delete up to (not including) lastRotated_
|
||||
if (validatedSeq >= lastRotated_ + deleteInterval_
|
||||
&& canDelete_ >= lastRotated_ - 1)
|
||||
if (validatedSeq >= lastRotated_ + deleteInterval_ &&
|
||||
canDelete_ >= lastRotated_ - 1)
|
||||
{
|
||||
JLOG(journal_.warn()) << "rotating validatedSeq " << validatedSeq
|
||||
<< " lastRotated_ " << lastRotated_ << " deleteInterval "
|
||||
<< deleteInterval_ << " canDelete_ " << canDelete_;
|
||||
JLOG(journal_.warn())
|
||||
<< "rotating validatedSeq " << validatedSeq << " lastRotated_ "
|
||||
<< lastRotated_ << " deleteInterval " << deleteInterval_
|
||||
<< " canDelete_ " << canDelete_;
|
||||
|
||||
switch (health())
|
||||
{
|
||||
@@ -379,11 +363,10 @@ SHAMapStoreImp::run()
|
||||
case Health::unhealthy:
|
||||
continue;
|
||||
case Health::ok:
|
||||
default:
|
||||
;
|
||||
default:;
|
||||
}
|
||||
|
||||
clearPrior (lastRotated_);
|
||||
clearPrior(lastRotated_);
|
||||
switch (health())
|
||||
{
|
||||
case Health::stopping:
|
||||
@@ -392,17 +375,17 @@ SHAMapStoreImp::run()
|
||||
case Health::unhealthy:
|
||||
continue;
|
||||
case Health::ok:
|
||||
default:
|
||||
;
|
||||
default:;
|
||||
}
|
||||
|
||||
std::uint64_t nodeCount = 0;
|
||||
validatedLedger->stateMap().snapShot (
|
||||
false)->visitNodes (
|
||||
std::bind (&SHAMapStoreImp::copyNode, this,
|
||||
std::ref(nodeCount), std::placeholders::_1));
|
||||
validatedLedger->stateMap().snapShot(false)->visitNodes(std::bind(
|
||||
&SHAMapStoreImp::copyNode,
|
||||
this,
|
||||
std::ref(nodeCount),
|
||||
std::placeholders::_1));
|
||||
JLOG(journal_.debug()) << "copied ledger " << validatedSeq
|
||||
<< " nodecount " << nodeCount;
|
||||
<< " nodecount " << nodeCount;
|
||||
switch (health())
|
||||
{
|
||||
case Health::stopping:
|
||||
@@ -411,8 +394,7 @@ SHAMapStoreImp::run()
|
||||
case Health::unhealthy:
|
||||
continue;
|
||||
case Health::ok:
|
||||
default:
|
||||
;
|
||||
default:;
|
||||
}
|
||||
|
||||
freshenCaches();
|
||||
@@ -425,15 +407,14 @@ SHAMapStoreImp::run()
|
||||
case Health::unhealthy:
|
||||
continue;
|
||||
case Health::ok:
|
||||
default:
|
||||
;
|
||||
default:;
|
||||
}
|
||||
|
||||
auto newBackend = makeBackendRotating();
|
||||
JLOG(journal_.debug()) << validatedSeq << " new backend "
|
||||
<< newBackend->getName();
|
||||
JLOG(journal_.debug())
|
||||
<< validatedSeq << " new backend " << newBackend->getName();
|
||||
|
||||
clearCaches (validatedSeq);
|
||||
clearCaches(validatedSeq);
|
||||
switch (health())
|
||||
{
|
||||
case Health::stopping:
|
||||
@@ -442,8 +423,7 @@ SHAMapStoreImp::run()
|
||||
case Health::unhealthy:
|
||||
continue;
|
||||
case Health::ok:
|
||||
default:
|
||||
;
|
||||
default:;
|
||||
}
|
||||
|
||||
std::string nextArchiveDir =
|
||||
@@ -451,14 +431,13 @@ SHAMapStoreImp::run()
|
||||
lastRotated_ = validatedSeq;
|
||||
std::shared_ptr<NodeStore::Backend> oldBackend;
|
||||
{
|
||||
std::lock_guard lock (dbRotating_->peekMutex());
|
||||
std::lock_guard lock(dbRotating_->peekMutex());
|
||||
|
||||
state_db_.setState (SavedState {newBackend->getName(),
|
||||
nextArchiveDir, lastRotated_});
|
||||
clearCaches (validatedSeq);
|
||||
oldBackend = dbRotating_->rotateBackends(
|
||||
std::move(newBackend),
|
||||
lock);
|
||||
state_db_.setState(SavedState{
|
||||
newBackend->getName(), nextArchiveDir, lastRotated_});
|
||||
clearCaches(validatedSeq);
|
||||
oldBackend =
|
||||
dbRotating_->rotateBackends(std::move(newBackend), lock);
|
||||
}
|
||||
JLOG(journal_.warn()) << "finished rotation " << validatedSeq;
|
||||
|
||||
@@ -470,35 +449,33 @@ SHAMapStoreImp::run()
|
||||
void
|
||||
SHAMapStoreImp::dbPaths()
|
||||
{
|
||||
Section section {app_.config().section(ConfigSection::nodeDatabase())};
|
||||
Section section{app_.config().section(ConfigSection::nodeDatabase())};
|
||||
boost::filesystem::path dbPath = get<std::string>(section, "path");
|
||||
|
||||
if (boost::filesystem::exists (dbPath))
|
||||
if (boost::filesystem::exists(dbPath))
|
||||
{
|
||||
if (! boost::filesystem::is_directory (dbPath))
|
||||
if (!boost::filesystem::is_directory(dbPath))
|
||||
{
|
||||
journal_.error() << "node db path must be a directory. "
|
||||
<< dbPath.string();
|
||||
Throw<std::runtime_error> (
|
||||
"node db path must be a directory.");
|
||||
journal_.error()
|
||||
<< "node db path must be a directory. " << dbPath.string();
|
||||
Throw<std::runtime_error>("node db path must be a directory.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::filesystem::create_directories (dbPath);
|
||||
boost::filesystem::create_directories(dbPath);
|
||||
}
|
||||
|
||||
SavedState state = state_db_.getState();
|
||||
|
||||
{
|
||||
auto update = [&dbPath](std::string& sPath)
|
||||
{
|
||||
auto update = [&dbPath](std::string& sPath) {
|
||||
if (sPath.empty())
|
||||
return false;
|
||||
|
||||
// Check if configured "path" matches stored directory path
|
||||
using namespace boost::filesystem;
|
||||
auto const stored {path(sPath)};
|
||||
auto const stored{path(sPath)};
|
||||
if (stored.parent_path() == dbPath)
|
||||
return false;
|
||||
|
||||
@@ -516,50 +493,51 @@ SHAMapStoreImp::dbPaths()
|
||||
bool writableDbExists = false;
|
||||
bool archiveDbExists = false;
|
||||
|
||||
for (boost::filesystem::directory_iterator it (dbPath);
|
||||
it != boost::filesystem::directory_iterator(); ++it)
|
||||
for (boost::filesystem::directory_iterator it(dbPath);
|
||||
it != boost::filesystem::directory_iterator();
|
||||
++it)
|
||||
{
|
||||
if (! state.writableDb.compare (it->path().string()))
|
||||
if (!state.writableDb.compare(it->path().string()))
|
||||
writableDbExists = true;
|
||||
else if (! state.archiveDb.compare (it->path().string()))
|
||||
else if (!state.archiveDb.compare(it->path().string()))
|
||||
archiveDbExists = true;
|
||||
else if (! dbPrefix_.compare (it->path().stem().string()))
|
||||
boost::filesystem::remove_all (it->path());
|
||||
else if (!dbPrefix_.compare(it->path().stem().string()))
|
||||
boost::filesystem::remove_all(it->path());
|
||||
}
|
||||
|
||||
if ((!writableDbExists && state.writableDb.size()) ||
|
||||
(!archiveDbExists && state.archiveDb.size()) ||
|
||||
(writableDbExists != archiveDbExists) ||
|
||||
state.writableDb.empty() != state.archiveDb.empty())
|
||||
(!archiveDbExists && state.archiveDb.size()) ||
|
||||
(writableDbExists != archiveDbExists) ||
|
||||
state.writableDb.empty() != state.archiveDb.empty())
|
||||
{
|
||||
boost::filesystem::path stateDbPathName =
|
||||
app_.config().legacy("database_path");
|
||||
stateDbPathName /= dbName_;
|
||||
stateDbPathName += "*";
|
||||
|
||||
journal_.error() << "state db error:\n"
|
||||
<< " writableDbExists " << writableDbExists
|
||||
<< " archiveDbExists " << archiveDbExists << '\n'
|
||||
<< " writableDb '" << state.writableDb
|
||||
<< "' archiveDb '" << state.archiveDb << "\n\n"
|
||||
<< "The existing data is in a corrupted state.\n"
|
||||
<< "To resume operation, remove the files matching "
|
||||
<< stateDbPathName.string()
|
||||
<< " and contents of the directory "
|
||||
<< get<std::string>(section, "path") << '\n'
|
||||
<< "Optionally, you can move those files to another\n"
|
||||
<< "location if you wish to analyze or back up the data.\n"
|
||||
<< "However, there is no guarantee that the data in its\n"
|
||||
<< "existing form is usable.";
|
||||
journal_.error()
|
||||
<< "state db error:\n"
|
||||
<< " writableDbExists " << writableDbExists << " archiveDbExists "
|
||||
<< archiveDbExists << '\n'
|
||||
<< " writableDb '" << state.writableDb << "' archiveDb '"
|
||||
<< state.archiveDb << "\n\n"
|
||||
<< "The existing data is in a corrupted state.\n"
|
||||
<< "To resume operation, remove the files matching "
|
||||
<< stateDbPathName.string() << " and contents of the directory "
|
||||
<< get<std::string>(section, "path") << '\n'
|
||||
<< "Optionally, you can move those files to another\n"
|
||||
<< "location if you wish to analyze or back up the data.\n"
|
||||
<< "However, there is no guarantee that the data in its\n"
|
||||
<< "existing form is usable.";
|
||||
|
||||
Throw<std::runtime_error> ("state db error");
|
||||
Throw<std::runtime_error>("state db error");
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr <NodeStore::Backend>
|
||||
SHAMapStoreImp::makeBackendRotating (std::string path)
|
||||
std::unique_ptr<NodeStore::Backend>
|
||||
SHAMapStoreImp::makeBackendRotating(std::string path)
|
||||
{
|
||||
Section section {app_.config().section(ConfigSection::nodeDatabase())};
|
||||
Section section{app_.config().section(ConfigSection::nodeDatabase())};
|
||||
boost::filesystem::path newPath;
|
||||
|
||||
if (path.size())
|
||||
@@ -571,26 +549,27 @@ SHAMapStoreImp::makeBackendRotating (std::string path)
|
||||
boost::filesystem::path p = get<std::string>(section, "path");
|
||||
p /= dbPrefix_;
|
||||
p += ".%%%%";
|
||||
newPath = boost::filesystem::unique_path (p);
|
||||
newPath = boost::filesystem::unique_path(p);
|
||||
}
|
||||
section.set("path", newPath.string());
|
||||
|
||||
auto backend {NodeStore::Manager::instance().make_Backend(
|
||||
auto backend{NodeStore::Manager::instance().make_Backend(
|
||||
section, scheduler_, app_.logs().journal(nodeStoreName_))};
|
||||
backend->open();
|
||||
return backend;
|
||||
}
|
||||
|
||||
bool
|
||||
SHAMapStoreImp::clearSql (DatabaseCon& database,
|
||||
LedgerIndex lastRotated,
|
||||
std::string const& minQuery,
|
||||
std::string const& deleteQuery)
|
||||
SHAMapStoreImp::clearSql(
|
||||
DatabaseCon& database,
|
||||
LedgerIndex lastRotated,
|
||||
std::string const& minQuery,
|
||||
std::string const& deleteQuery)
|
||||
{
|
||||
LedgerIndex min = std::numeric_limits <LedgerIndex>::max();
|
||||
LedgerIndex min = std::numeric_limits<LedgerIndex>::max();
|
||||
|
||||
{
|
||||
auto db = database.checkoutDb ();
|
||||
auto db = database.checkoutDb();
|
||||
boost::optional<std::uint64_t> m;
|
||||
*db << minQuery, soci::into(m);
|
||||
if (!m)
|
||||
@@ -598,71 +577,76 @@ SHAMapStoreImp::clearSql (DatabaseCon& database,
|
||||
min = *m;
|
||||
}
|
||||
|
||||
if(min > lastRotated || health() != Health::ok)
|
||||
if (min > lastRotated || health() != Health::ok)
|
||||
return false;
|
||||
|
||||
boost::format formattedDeleteQuery (deleteQuery);
|
||||
boost::format formattedDeleteQuery(deleteQuery);
|
||||
|
||||
JLOG(journal_.debug()) <<
|
||||
"start: " << deleteQuery << " from " << min << " to " << lastRotated;
|
||||
JLOG(journal_.debug()) << "start: " << deleteQuery << " from " << min
|
||||
<< " to " << lastRotated;
|
||||
while (min < lastRotated)
|
||||
{
|
||||
min = std::min(lastRotated, min + deleteBatch_);
|
||||
{
|
||||
auto db = database.checkoutDb ();
|
||||
*db << boost::str (formattedDeleteQuery % min);
|
||||
auto db = database.checkoutDb();
|
||||
*db << boost::str(formattedDeleteQuery % min);
|
||||
}
|
||||
if (health())
|
||||
return true;
|
||||
if (min < lastRotated)
|
||||
std::this_thread::sleep_for (
|
||||
std::chrono::milliseconds (backOff_));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(backOff_));
|
||||
}
|
||||
JLOG(journal_.debug()) << "finished: " << deleteQuery;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapStoreImp::clearCaches (LedgerIndex validatedSeq)
|
||||
SHAMapStoreImp::clearCaches(LedgerIndex validatedSeq)
|
||||
{
|
||||
ledgerMaster_->clearLedgerCachePrior (validatedSeq);
|
||||
ledgerMaster_->clearLedgerCachePrior(validatedSeq);
|
||||
fullBelowCache_->clear();
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapStoreImp::freshenCaches()
|
||||
{
|
||||
if (freshenCache (dbRotating_->getPositiveCache()))
|
||||
if (freshenCache(dbRotating_->getPositiveCache()))
|
||||
return;
|
||||
if (freshenCache (*treeNodeCache_))
|
||||
if (freshenCache(*treeNodeCache_))
|
||||
return;
|
||||
if (freshenCache (app_.getMasterTransaction().getCache()))
|
||||
if (freshenCache(app_.getMasterTransaction().getCache()))
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapStoreImp::clearPrior (LedgerIndex lastRotated)
|
||||
SHAMapStoreImp::clearPrior(LedgerIndex lastRotated)
|
||||
{
|
||||
if (health())
|
||||
return;
|
||||
|
||||
ledgerMaster_->clearPriorLedgers (lastRotated);
|
||||
ledgerMaster_->clearPriorLedgers(lastRotated);
|
||||
if (health())
|
||||
return;
|
||||
|
||||
clearSql (*ledgerDb_, lastRotated,
|
||||
clearSql(
|
||||
*ledgerDb_,
|
||||
lastRotated,
|
||||
"SELECT MIN(LedgerSeq) FROM Ledgers;",
|
||||
"DELETE FROM Ledgers WHERE LedgerSeq < %u;");
|
||||
if (health())
|
||||
return;
|
||||
|
||||
clearSql (*transactionDb_, lastRotated,
|
||||
clearSql(
|
||||
*transactionDb_,
|
||||
lastRotated,
|
||||
"SELECT MIN(LedgerSeq) FROM Transactions;",
|
||||
"DELETE FROM Transactions WHERE LedgerSeq < %u;");
|
||||
if (health())
|
||||
return;
|
||||
|
||||
clearSql (*transactionDb_, lastRotated,
|
||||
clearSql(
|
||||
*transactionDb_,
|
||||
lastRotated,
|
||||
"SELECT MIN(LedgerSeq) FROM AccountTransactions;",
|
||||
"DELETE FROM AccountTransactions WHERE LedgerSeq < %u;");
|
||||
if (health())
|
||||
@@ -673,11 +657,11 @@ SHAMapStoreImp::Health
|
||||
SHAMapStoreImp::health()
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
if (stop_)
|
||||
return Health::stopping;
|
||||
}
|
||||
if (! netOPs_)
|
||||
if (!netOPs_)
|
||||
return Health::ok;
|
||||
|
||||
constexpr static std::chrono::seconds age_threshold(60);
|
||||
@@ -703,7 +687,7 @@ SHAMapStoreImp::onStop()
|
||||
if (deleteInterval_)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
stop_ = true;
|
||||
}
|
||||
cond_.notify_one();
|
||||
@@ -720,7 +704,7 @@ SHAMapStoreImp::onChildrenStopped()
|
||||
if (deleteInterval_)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
stop_ = true;
|
||||
}
|
||||
cond_.notify_one();
|
||||
@@ -743,4 +727,4 @@ make_SHAMapStore(
|
||||
return std::make_unique<SHAMapStoreImp>(app, parent, scheduler, journal);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef RIPPLE_APP_MISC_SHAMAPSTOREIMP_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_SHAMAPSTOREIMP_H_INCLUDED
|
||||
|
||||
#include <ripple/app/misc/SHAMapStore.h>
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/misc/SHAMapStore.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/nodestore/DatabaseRotating.h>
|
||||
|
||||
@@ -43,12 +43,7 @@ private:
|
||||
LedgerIndex lastRotated;
|
||||
};
|
||||
|
||||
enum Health : std::uint8_t
|
||||
{
|
||||
ok = 0,
|
||||
stopping,
|
||||
unhealthy
|
||||
};
|
||||
enum Health : std::uint8_t { ok = 0, stopping, unhealthy };
|
||||
|
||||
class SavedStateDB
|
||||
{
|
||||
@@ -59,18 +54,24 @@ private:
|
||||
|
||||
// Just instantiate without any logic in case online delete is not
|
||||
// configured
|
||||
explicit SavedStateDB()
|
||||
: journal_ {beast::Journal::getNullSink()}
|
||||
{ }
|
||||
explicit SavedStateDB() : journal_{beast::Journal::getNullSink()}
|
||||
{
|
||||
}
|
||||
|
||||
// opens database and, if necessary, creates & initializes its tables.
|
||||
void init (BasicConfig const& config, std::string const& dbName);
|
||||
void
|
||||
init(BasicConfig const& config, std::string const& dbName);
|
||||
// get/set the ledger index that we can delete up to and including
|
||||
LedgerIndex getCanDelete();
|
||||
LedgerIndex setCanDelete (LedgerIndex canDelete);
|
||||
SavedState getState();
|
||||
void setState (SavedState const& state);
|
||||
void setLastRotated (LedgerIndex seq);
|
||||
LedgerIndex
|
||||
getCanDelete();
|
||||
LedgerIndex
|
||||
setCanDelete(LedgerIndex canDelete);
|
||||
SavedState
|
||||
getState();
|
||||
void
|
||||
setState(SavedState const& state);
|
||||
void
|
||||
setLastRotated(LedgerIndex seq);
|
||||
};
|
||||
|
||||
Application& app_;
|
||||
@@ -91,7 +92,7 @@ private:
|
||||
// not including) this value. All ledgers past this value are accumulated
|
||||
// until the next online deletion. This value is persisted to SQLite
|
||||
// nearly immediately after modification.
|
||||
std::atomic<LedgerIndex> lastRotated_ {};
|
||||
std::atomic<LedgerIndex> lastRotated_{};
|
||||
|
||||
NodeStore::Scheduler& scheduler_;
|
||||
beast::Journal const journal_;
|
||||
@@ -105,7 +106,7 @@ private:
|
||||
mutable std::mutex mutex_;
|
||||
std::shared_ptr<Ledger const> newLedger_;
|
||||
std::atomic<bool> working_;
|
||||
std::atomic <LedgerIndex> canDelete_;
|
||||
std::atomic<LedgerIndex> canDelete_;
|
||||
int fdRequired_ = 0;
|
||||
|
||||
std::uint32_t deleteInterval_ = 0;
|
||||
@@ -139,21 +140,21 @@ public:
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
clampFetchDepth (std::uint32_t fetch_depth) const override
|
||||
clampFetchDepth(std::uint32_t fetch_depth) const override
|
||||
{
|
||||
return deleteInterval_ ? std::min (fetch_depth,
|
||||
deleteInterval_) : fetch_depth;
|
||||
return deleteInterval_ ? std::min(fetch_depth, deleteInterval_)
|
||||
: fetch_depth;
|
||||
}
|
||||
|
||||
std::unique_ptr <NodeStore::Database>
|
||||
std::unique_ptr<NodeStore::Database>
|
||||
makeNodeStore(std::string const& name, std::int32_t readThreads) override;
|
||||
|
||||
LedgerIndex
|
||||
setCanDelete (LedgerIndex seq) override
|
||||
setCanDelete(LedgerIndex seq) override
|
||||
{
|
||||
if (advisoryDelete_)
|
||||
canDelete_ = seq;
|
||||
return state_db_.setCanDelete (seq);
|
||||
return state_db_.setCanDelete(seq);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -178,30 +179,36 @@ public:
|
||||
return canDelete_;
|
||||
}
|
||||
|
||||
void onLedgerClosed (std::shared_ptr<Ledger const> const& ledger) override;
|
||||
void
|
||||
onLedgerClosed(std::shared_ptr<Ledger const> const& ledger) override;
|
||||
|
||||
void rendezvous() const override;
|
||||
int fdRequired() const override;
|
||||
void
|
||||
rendezvous() const override;
|
||||
int
|
||||
fdRequired() const override;
|
||||
|
||||
private:
|
||||
// callback for visitNodes
|
||||
bool copyNode (std::uint64_t& nodeCount, SHAMapAbstractNode const &node);
|
||||
void run();
|
||||
void dbPaths();
|
||||
bool
|
||||
copyNode(std::uint64_t& nodeCount, SHAMapAbstractNode const& node);
|
||||
void
|
||||
run();
|
||||
void
|
||||
dbPaths();
|
||||
|
||||
std::unique_ptr<NodeStore::Backend>
|
||||
makeBackendRotating (std::string path = std::string());
|
||||
makeBackendRotating(std::string path = std::string());
|
||||
|
||||
template <class CacheInstance>
|
||||
bool
|
||||
freshenCache (CacheInstance& cache)
|
||||
freshenCache(CacheInstance& cache)
|
||||
{
|
||||
std::uint64_t check = 0;
|
||||
|
||||
for (auto const& key: cache.getKeys())
|
||||
for (auto const& key : cache.getKeys())
|
||||
{
|
||||
dbRotating_->fetch(key, 0);
|
||||
if (! (++check % checkHealthInterval_) && health())
|
||||
if (!(++check % checkHealthInterval_) && health())
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -214,18 +221,26 @@ private:
|
||||
* @return true if any deletable rows were found (though not
|
||||
* necessarily deleted.
|
||||
*/
|
||||
bool clearSql (DatabaseCon& database, LedgerIndex lastRotated,
|
||||
std::string const& minQuery, std::string const& deleteQuery);
|
||||
void clearCaches (LedgerIndex validatedSeq);
|
||||
void freshenCaches();
|
||||
void clearPrior (LedgerIndex lastRotated);
|
||||
bool
|
||||
clearSql(
|
||||
DatabaseCon& database,
|
||||
LedgerIndex lastRotated,
|
||||
std::string const& minQuery,
|
||||
std::string const& deleteQuery);
|
||||
void
|
||||
clearCaches(LedgerIndex validatedSeq);
|
||||
void
|
||||
freshenCaches();
|
||||
void
|
||||
clearPrior(LedgerIndex lastRotated);
|
||||
|
||||
// If rippled is not healthy, defer rotate-delete.
|
||||
// If already unhealthy, do not change state on further check.
|
||||
// Assume that, once unhealthy, a necessary step has been
|
||||
// aborted, so the online-delete process needs to restart
|
||||
// at next ledger.
|
||||
Health health();
|
||||
Health
|
||||
health();
|
||||
//
|
||||
// Stoppable
|
||||
//
|
||||
@@ -238,16 +253,17 @@ private:
|
||||
onStart() override
|
||||
{
|
||||
if (deleteInterval_)
|
||||
thread_ = std::thread (&SHAMapStoreImp::run, this);
|
||||
thread_ = std::thread(&SHAMapStoreImp::run, this);
|
||||
}
|
||||
|
||||
// Called when the application begins shutdown
|
||||
void onStop() override;
|
||||
void
|
||||
onStop() override;
|
||||
// Called when all child Stoppable objects have stoped
|
||||
void onChildrenStopped() override;
|
||||
|
||||
void
|
||||
onChildrenStopped() override;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
#ifndef RIPPLE_APP_MISC_TRANSACTION_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_TRANSACTION_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/RangeSet.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/TER.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/basics/RangeSet.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
@@ -40,84 +40,95 @@ class Application;
|
||||
class Database;
|
||||
class Rules;
|
||||
|
||||
enum TransStatus
|
||||
{
|
||||
NEW = 0, // just received / generated
|
||||
INVALID = 1, // no valid signature, insufficient funds
|
||||
INCLUDED = 2, // added to the current ledger
|
||||
CONFLICTED = 3, // losing to a conflicting transaction
|
||||
COMMITTED = 4, // known to be in a ledger
|
||||
HELD = 5, // not valid now, maybe later
|
||||
REMOVED = 6, // taken out of a ledger
|
||||
OBSOLETE = 7, // a compatible transaction has taken precedence
|
||||
INCOMPLETE = 8 // needs more signatures
|
||||
enum TransStatus {
|
||||
NEW = 0, // just received / generated
|
||||
INVALID = 1, // no valid signature, insufficient funds
|
||||
INCLUDED = 2, // added to the current ledger
|
||||
CONFLICTED = 3, // losing to a conflicting transaction
|
||||
COMMITTED = 4, // known to be in a ledger
|
||||
HELD = 5, // not valid now, maybe later
|
||||
REMOVED = 6, // taken out of a ledger
|
||||
OBSOLETE = 7, // a compatible transaction has taken precedence
|
||||
INCOMPLETE = 8 // needs more signatures
|
||||
};
|
||||
|
||||
// This class is for constructing and examining transactions.
|
||||
// Transactions are static so manipulation functions are unnecessary.
|
||||
class Transaction
|
||||
: public std::enable_shared_from_this<Transaction>
|
||||
, public CountedObject <Transaction>
|
||||
class Transaction : public std::enable_shared_from_this<Transaction>,
|
||||
public CountedObject<Transaction>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "Transaction"; }
|
||||
static char const*
|
||||
getCountedObjectName()
|
||||
{
|
||||
return "Transaction";
|
||||
}
|
||||
|
||||
using pointer = std::shared_ptr<Transaction>;
|
||||
using ref = const pointer&;
|
||||
|
||||
Transaction (
|
||||
std::shared_ptr<STTx const> const&, std::string&, Application&) noexcept;
|
||||
Transaction(
|
||||
std::shared_ptr<STTx const> const&,
|
||||
std::string&,
|
||||
Application&) noexcept;
|
||||
|
||||
static
|
||||
Transaction::pointer
|
||||
transactionFromSQL (
|
||||
static Transaction::pointer
|
||||
transactionFromSQL(
|
||||
boost::optional<std::uint64_t> const& ledgerSeq,
|
||||
boost::optional<std::string> const& status,
|
||||
Blob const& rawTxn,
|
||||
Application& app);
|
||||
|
||||
static
|
||||
TransStatus
|
||||
static TransStatus
|
||||
sqlTransactionStatus(boost::optional<std::string> const& status);
|
||||
|
||||
std::shared_ptr<STTx const> const& getSTransaction ()
|
||||
std::shared_ptr<STTx const> const&
|
||||
getSTransaction()
|
||||
{
|
||||
return mTransaction;
|
||||
}
|
||||
|
||||
uint256 const& getID () const
|
||||
uint256 const&
|
||||
getID() const
|
||||
{
|
||||
return mTransactionID;
|
||||
}
|
||||
|
||||
LedgerIndex getLedger () const
|
||||
LedgerIndex
|
||||
getLedger() const
|
||||
{
|
||||
return mInLedger;
|
||||
}
|
||||
|
||||
TransStatus getStatus () const
|
||||
TransStatus
|
||||
getStatus() const
|
||||
{
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
TER getResult ()
|
||||
TER
|
||||
getResult()
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
|
||||
void setResult (TER terResult)
|
||||
void
|
||||
setResult(TER terResult)
|
||||
{
|
||||
mResult = terResult;
|
||||
}
|
||||
|
||||
void setStatus (TransStatus status, std::uint32_t ledgerSeq);
|
||||
void
|
||||
setStatus(TransStatus status, std::uint32_t ledgerSeq);
|
||||
|
||||
void setStatus (TransStatus status)
|
||||
void
|
||||
setStatus(TransStatus status)
|
||||
{
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
void setLedger (LedgerIndex ledger)
|
||||
void
|
||||
setLedger(LedgerIndex ledger)
|
||||
{
|
||||
mInLedger = ledger;
|
||||
}
|
||||
@@ -125,7 +136,8 @@ public:
|
||||
/**
|
||||
* Set this flag once added to a batch.
|
||||
*/
|
||||
void setApplying()
|
||||
void
|
||||
setApplying()
|
||||
{
|
||||
mApplying = true;
|
||||
}
|
||||
@@ -135,7 +147,8 @@ public:
|
||||
*
|
||||
* @return Whether transaction is being applied within a batch.
|
||||
*/
|
||||
bool getApplying()
|
||||
bool
|
||||
getApplying()
|
||||
{
|
||||
return mApplying;
|
||||
}
|
||||
@@ -143,7 +156,8 @@ public:
|
||||
/**
|
||||
* Indicate that transaction application has been attempted.
|
||||
*/
|
||||
void clearApplying()
|
||||
void
|
||||
clearApplying()
|
||||
{
|
||||
mApplying = false;
|
||||
}
|
||||
@@ -153,7 +167,8 @@ public:
|
||||
/**
|
||||
* @brief clear Clear all states
|
||||
*/
|
||||
void clear()
|
||||
void
|
||||
clear()
|
||||
{
|
||||
applied = false;
|
||||
broadcast = false;
|
||||
@@ -165,7 +180,8 @@ public:
|
||||
* @brief any Get true of any state is true
|
||||
* @return True if any state if true
|
||||
*/
|
||||
bool any() const
|
||||
bool
|
||||
any() const
|
||||
{
|
||||
return applied || broadcast || queued || kept;
|
||||
}
|
||||
@@ -180,7 +196,8 @@ public:
|
||||
* @brief getSubmitResult Return submit result
|
||||
* @return SubmitResult struct
|
||||
*/
|
||||
SubmitResult getSubmitResult() const
|
||||
SubmitResult
|
||||
getSubmitResult() const
|
||||
{
|
||||
return submitResult_;
|
||||
}
|
||||
@@ -188,7 +205,8 @@ public:
|
||||
/**
|
||||
* @brief clearSubmitResult Clear all flags in SubmitResult
|
||||
*/
|
||||
void clearSubmitResult()
|
||||
void
|
||||
clearSubmitResult()
|
||||
{
|
||||
submitResult_.clear();
|
||||
}
|
||||
@@ -196,7 +214,8 @@ public:
|
||||
/**
|
||||
* @brief setApplied Set this flag once was applied to open ledger
|
||||
*/
|
||||
void setApplied()
|
||||
void
|
||||
setApplied()
|
||||
{
|
||||
submitResult_.applied = true;
|
||||
}
|
||||
@@ -204,7 +223,8 @@ public:
|
||||
/**
|
||||
* @brief setQueued Set this flag once was put into heldtxns queue
|
||||
*/
|
||||
void setQueued()
|
||||
void
|
||||
setQueued()
|
||||
{
|
||||
submitResult_.queued = true;
|
||||
}
|
||||
@@ -212,7 +232,8 @@ public:
|
||||
/**
|
||||
* @brief setBroadcast Set this flag once was broadcasted via network
|
||||
*/
|
||||
void setBroadcast()
|
||||
void
|
||||
setBroadcast()
|
||||
{
|
||||
submitResult_.broadcast = true;
|
||||
}
|
||||
@@ -220,7 +241,8 @@ public:
|
||||
/**
|
||||
* @brief setKept Set this flag once was put to localtxns queue
|
||||
*/
|
||||
void setKept()
|
||||
void
|
||||
setKept()
|
||||
{
|
||||
submitResult_.kept = true;
|
||||
}
|
||||
@@ -275,37 +297,44 @@ public:
|
||||
validatedLedger, fee, accountSeq, availableSeq);
|
||||
}
|
||||
|
||||
Json::Value getJson (JsonOptions options, bool binary = false) const;
|
||||
Json::Value
|
||||
getJson(JsonOptions options, bool binary = false) const;
|
||||
|
||||
static pointer
|
||||
load (uint256 const& id, Application& app, error_code_i& ec);
|
||||
load(uint256 const& id, Application& app, error_code_i& ec);
|
||||
|
||||
static boost::variant<Transaction::pointer, bool>
|
||||
load (uint256 const& id, Application& app, ClosedInterval<uint32_t> const& range, error_code_i& ec);
|
||||
|
||||
private:
|
||||
|
||||
static boost::variant<Transaction::pointer, bool>
|
||||
load (uint256 const& id, Application& app, boost::optional<ClosedInterval<uint32_t>> const& range,
|
||||
load(
|
||||
uint256 const& id,
|
||||
Application& app,
|
||||
ClosedInterval<uint32_t> const& range,
|
||||
error_code_i& ec);
|
||||
|
||||
uint256 mTransactionID;
|
||||
private:
|
||||
static boost::variant<Transaction::pointer, bool>
|
||||
load(
|
||||
uint256 const& id,
|
||||
Application& app,
|
||||
boost::optional<ClosedInterval<uint32_t>> const& range,
|
||||
error_code_i& ec);
|
||||
|
||||
LedgerIndex mInLedger = 0;
|
||||
TransStatus mStatus = INVALID;
|
||||
TER mResult = temUNCERTAIN;
|
||||
bool mApplying = false;
|
||||
uint256 mTransactionID;
|
||||
|
||||
LedgerIndex mInLedger = 0;
|
||||
TransStatus mStatus = INVALID;
|
||||
TER mResult = temUNCERTAIN;
|
||||
bool mApplying = false;
|
||||
|
||||
/** different ways for transaction to be accepted */
|
||||
SubmitResult submitResult_;
|
||||
SubmitResult submitResult_;
|
||||
|
||||
boost::optional<CurrentLedgerState> currentLedgerState_;
|
||||
|
||||
std::shared_ptr<STTx const> mTransaction;
|
||||
Application& mApp;
|
||||
beast::Journal j_;
|
||||
std::shared_ptr<STTx const> mTransaction;
|
||||
Application& mApp;
|
||||
beast::Journal j_;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
#define RIPPLE_TXQ_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/applySteps.h>
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <ripple/ledger/ApplyView.h>
|
||||
#include <ripple/protocol/TER.h>
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <ripple/protocol/TER.h>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -55,7 +55,7 @@ class TxQ
|
||||
{
|
||||
public:
|
||||
/// Fee level for single-signed reference transaction.
|
||||
static constexpr FeeLevel64 baseLevel{ 256 };
|
||||
static constexpr FeeLevel64 baseLevel{256};
|
||||
|
||||
/**
|
||||
Structure used to customize @ref TxQ behavior.
|
||||
@@ -168,7 +168,7 @@ public:
|
||||
we can make this more complicated. But avoid
|
||||
bikeshedding for now.
|
||||
*/
|
||||
FeeLevel64 zeroBaseFeeTransactionFeeLevel{ 256000 };
|
||||
FeeLevel64 zeroBaseFeeTransactionFeeLevel{256000};
|
||||
/// Use standalone mode behavior.
|
||||
bool standAlone = false;
|
||||
};
|
||||
@@ -264,8 +264,7 @@ public:
|
||||
};
|
||||
|
||||
/// Constructor
|
||||
TxQ(Setup const& setup,
|
||||
beast::Journal j);
|
||||
TxQ(Setup const& setup, beast::Journal j);
|
||||
|
||||
/// Destructor
|
||||
virtual ~TxQ();
|
||||
@@ -280,9 +279,12 @@ public:
|
||||
will return `{ terQUEUED, false }`.
|
||||
*/
|
||||
std::pair<TER, bool>
|
||||
apply(Application& app, OpenView& view,
|
||||
apply(
|
||||
Application& app,
|
||||
OpenView& view,
|
||||
std::shared_ptr<STTx const> const& tx,
|
||||
ApplyFlags flags, beast::Journal j);
|
||||
ApplyFlags flags,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
Fill the new open ledger with transactions from the queue.
|
||||
@@ -311,11 +313,10 @@ public:
|
||||
that have no candidates under them are removed.
|
||||
*/
|
||||
void
|
||||
processClosedLedger(Application& app,
|
||||
ReadView const& view, bool timeLeap);
|
||||
processClosedLedger(Application& app, ReadView const& view, bool timeLeap);
|
||||
|
||||
/** Returns fee metrics in reference fee level units.
|
||||
*/
|
||||
*/
|
||||
Metrics
|
||||
getMetrics(OpenView const& view) const;
|
||||
|
||||
@@ -336,7 +337,8 @@ public:
|
||||
* and first available sequence
|
||||
*/
|
||||
FeeAndSeq
|
||||
getTxRequiredFeeAndSeq(OpenView const& view,
|
||||
getTxRequiredFeeAndSeq(
|
||||
OpenView const& view,
|
||||
std::shared_ptr<STTx const> const& tx) const;
|
||||
|
||||
/** Returns information about the transactions currently
|
||||
@@ -396,15 +398,19 @@ private:
|
||||
public:
|
||||
/// Constructor
|
||||
FeeMetrics(Setup const& setup, beast::Journal j)
|
||||
: minimumTxnCount_(setup.standAlone ?
|
||||
setup.minimumTxnInLedgerSA :
|
||||
setup.minimumTxnInLedger)
|
||||
, targetTxnCount_(setup.targetTxnInLedger < minimumTxnCount_ ?
|
||||
minimumTxnCount_ : setup.targetTxnInLedger)
|
||||
, maximumTxnCount_(setup.maximumTxnInLedger ?
|
||||
*setup.maximumTxnInLedger < targetTxnCount_ ?
|
||||
targetTxnCount_ : *setup.maximumTxnInLedger :
|
||||
boost::optional<std::size_t>(boost::none))
|
||||
: minimumTxnCount_(
|
||||
setup.standAlone ? setup.minimumTxnInLedgerSA
|
||||
: setup.minimumTxnInLedger)
|
||||
, targetTxnCount_(
|
||||
setup.targetTxnInLedger < minimumTxnCount_
|
||||
? minimumTxnCount_
|
||||
: setup.targetTxnInLedger)
|
||||
, maximumTxnCount_(
|
||||
setup.maximumTxnInLedger
|
||||
? *setup.maximumTxnInLedger < targetTxnCount_
|
||||
? targetTxnCount_
|
||||
: *setup.maximumTxnInLedger
|
||||
: boost::optional<std::size_t>(boost::none))
|
||||
, txnsExpected_(minimumTxnCount_)
|
||||
, recentTxnCounts_(setup.ledgersInQueue)
|
||||
, escalationMultiplier_(setup.minimumEscalationMultiplier)
|
||||
@@ -423,8 +429,10 @@ private:
|
||||
@param setup Customization params.
|
||||
*/
|
||||
std::size_t
|
||||
update(Application& app,
|
||||
ReadView const& view, bool timeLeap,
|
||||
update(
|
||||
Application& app,
|
||||
ReadView const& view,
|
||||
bool timeLeap,
|
||||
TxQ::Setup const& setup);
|
||||
|
||||
/// Snapshot of the externally relevant FeeMetrics
|
||||
@@ -444,10 +452,7 @@ private:
|
||||
Snapshot
|
||||
getSnapshot() const
|
||||
{
|
||||
return {
|
||||
txnsExpected_,
|
||||
escalationMultiplier_
|
||||
};
|
||||
return {txnsExpected_, escalationMultiplier_};
|
||||
}
|
||||
|
||||
/** Use the number of transactions in the current open ledger
|
||||
@@ -458,8 +463,7 @@ private:
|
||||
|
||||
@return A fee level value.
|
||||
*/
|
||||
static
|
||||
FeeLevel64
|
||||
static FeeLevel64
|
||||
scaleFeeLevel(Snapshot const& snapshot, OpenView const& view);
|
||||
|
||||
/**
|
||||
@@ -492,10 +496,12 @@ private:
|
||||
@return A `std::pair` as returned from @ref `mulDiv` indicating
|
||||
whether the calculation result overflows.
|
||||
*/
|
||||
static
|
||||
std::pair<bool, FeeLevel64>
|
||||
escalatedSeriesFeeLevel(Snapshot const& snapshot, OpenView const& view,
|
||||
std::size_t extraCount, std::size_t seriesSize);
|
||||
static std::pair<bool, FeeLevel64>
|
||||
escalatedSeriesFeeLevel(
|
||||
Snapshot const& snapshot,
|
||||
OpenView const& view,
|
||||
std::size_t extraCount,
|
||||
std::size_t seriesSize);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -578,10 +584,12 @@ private:
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
MaybeTx(std::shared_ptr<STTx const> const&,
|
||||
TxID const& txID, FeeLevel64 feeLevel,
|
||||
ApplyFlags const flags,
|
||||
PreflightResult const& pfresult);
|
||||
MaybeTx(
|
||||
std::shared_ptr<STTx const> const&,
|
||||
TxID const& txID,
|
||||
FeeLevel64 feeLevel,
|
||||
ApplyFlags const flags,
|
||||
PreflightResult const& pfresult);
|
||||
|
||||
/// Attempt to apply the queued transaction to the open ledger.
|
||||
std::pair<TER, bool>
|
||||
@@ -596,7 +604,8 @@ private:
|
||||
explicit GreaterFee() = default;
|
||||
|
||||
/// Is the fee level of `lhs` greater than the fee level of `rhs`?
|
||||
bool operator()(const MaybeTx& lhs, const MaybeTx& rhs) const
|
||||
bool
|
||||
operator()(const MaybeTx& lhs, const MaybeTx& rhs) const
|
||||
{
|
||||
return lhs.feeLevel > rhs.feeLevel;
|
||||
}
|
||||
@@ -608,7 +617,7 @@ private:
|
||||
class TxQAccount
|
||||
{
|
||||
public:
|
||||
using TxMap = std::map <TxSeq, MaybeTx>;
|
||||
using TxMap = std::map<TxSeq, MaybeTx>;
|
||||
|
||||
/// The account
|
||||
AccountID const account;
|
||||
@@ -662,15 +671,15 @@ private:
|
||||
remove(TxSeq const& sequence);
|
||||
};
|
||||
|
||||
using FeeHook = boost::intrusive::member_hook
|
||||
<MaybeTx, boost::intrusive::set_member_hook<>,
|
||||
using FeeHook = boost::intrusive::member_hook<
|
||||
MaybeTx,
|
||||
boost::intrusive::set_member_hook<>,
|
||||
&MaybeTx::byFeeListHook>;
|
||||
|
||||
using FeeMultiSet = boost::intrusive::multiset
|
||||
< MaybeTx, FeeHook,
|
||||
boost::intrusive::compare <GreaterFee> >;
|
||||
using FeeMultiSet = boost::intrusive::
|
||||
multiset<MaybeTx, FeeHook, boost::intrusive::compare<GreaterFee>>;
|
||||
|
||||
using AccountMap = std::map <AccountID, TxQAccount>;
|
||||
using AccountMap = std::map<AccountID, TxQAccount>;
|
||||
|
||||
/// Setup parameters used to control the behavior of the queue
|
||||
Setup const setup_;
|
||||
@@ -710,16 +719,20 @@ private:
|
||||
|
||||
private:
|
||||
/// Is the queue at least `fillPercentage` full?
|
||||
template<size_t fillPercentage = 100>
|
||||
template <size_t fillPercentage = 100>
|
||||
bool
|
||||
isFull() const;
|
||||
|
||||
/** Checks if the indicated transaction fits the conditions
|
||||
for being stored in the queue.
|
||||
*/
|
||||
bool canBeHeld(STTx const&, ApplyFlags const, OpenView const&,
|
||||
bool
|
||||
canBeHeld(
|
||||
STTx const&,
|
||||
ApplyFlags const,
|
||||
OpenView const&,
|
||||
AccountMap::iterator,
|
||||
boost::optional<FeeMultiSet::iterator>);
|
||||
boost::optional<FeeMultiSet::iterator>);
|
||||
|
||||
/// Erase and return the next entry in byFee_ (lower fee level)
|
||||
FeeMultiSet::iterator_type erase(FeeMultiSet::const_iterator_type);
|
||||
@@ -727,25 +740,32 @@ private:
|
||||
is higher), or next entry in byFee_ (lower fee level).
|
||||
Used to get the next "applyable" MaybeTx for accept().
|
||||
*/
|
||||
FeeMultiSet::iterator_type eraseAndAdvance(FeeMultiSet::const_iterator_type);
|
||||
FeeMultiSet::iterator_type eraseAndAdvance(
|
||||
FeeMultiSet::const_iterator_type);
|
||||
/// Erase a range of items, based on TxQAccount::TxMap iterators
|
||||
TxQAccount::TxMap::iterator
|
||||
erase(TxQAccount& txQAccount, TxQAccount::TxMap::const_iterator begin,
|
||||
erase(
|
||||
TxQAccount& txQAccount,
|
||||
TxQAccount::TxMap::const_iterator begin,
|
||||
TxQAccount::TxMap::const_iterator end);
|
||||
|
||||
/**
|
||||
All-or-nothing attempt to try to apply all the queued txs for `accountIter`
|
||||
up to and including `tx`.
|
||||
All-or-nothing attempt to try to apply all the queued txs for
|
||||
`accountIter` up to and including `tx`.
|
||||
*/
|
||||
std::pair<TER, bool>
|
||||
tryClearAccountQueue(Application& app, OpenView& view,
|
||||
STTx const& tx, AccountMap::iterator const& accountIter,
|
||||
TxQAccount::TxMap::iterator, FeeLevel64 feeLevelPaid,
|
||||
PreflightResult const& pfresult,
|
||||
std::size_t const txExtraCount, ApplyFlags flags,
|
||||
FeeMetrics::Snapshot const& metricsSnapshot,
|
||||
beast::Journal j);
|
||||
|
||||
tryClearAccountQueue(
|
||||
Application& app,
|
||||
OpenView& view,
|
||||
STTx const& tx,
|
||||
AccountMap::iterator const& accountIter,
|
||||
TxQAccount::TxMap::iterator,
|
||||
FeeLevel64 feeLevelPaid,
|
||||
PreflightResult const& pfresult,
|
||||
std::size_t const txExtraCount,
|
||||
ApplyFlags flags,
|
||||
FeeMetrics::Snapshot const& metricsSnapshot,
|
||||
beast::Journal j);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -760,20 +780,19 @@ setup_TxQ(Config const&);
|
||||
std::unique_ptr<TxQ>
|
||||
make_TxQ(TxQ::Setup const&, beast::Journal);
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
std::pair<bool, XRPAmount>
|
||||
toDrops(FeeLevel<T> const& level, XRPAmount const& baseFee)
|
||||
{
|
||||
return mulDiv(level, baseFee, TxQ::baseLevel);
|
||||
}
|
||||
|
||||
inline
|
||||
std::pair<bool, FeeLevel64>
|
||||
inline std::pair<bool, FeeLevel64>
|
||||
toFeeLevel(XRPAmount const& drops, XRPAmount const& baseFee)
|
||||
{
|
||||
return mulDiv(drops, TxQ::baseLevel, baseFee);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -43,13 +43,14 @@ public:
|
||||
|
||||
ValidatorKeys(Config const& config, beast::Journal j);
|
||||
|
||||
bool configInvalid() const
|
||||
bool
|
||||
configInvalid() const
|
||||
{
|
||||
return configInvalid_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool configInvalid_ = false; //< Set to true if config was invalid
|
||||
bool configInvalid_ = false; //< Set to true if config was invalid
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <numeric>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -39,8 +39,7 @@ namespace ripple {
|
||||
class Overlay;
|
||||
class HashRouter;
|
||||
|
||||
enum class ListDisposition
|
||||
{
|
||||
enum class ListDisposition {
|
||||
/// List is valid
|
||||
accepted = 0,
|
||||
|
||||
@@ -64,7 +63,7 @@ std::string
|
||||
to_string(ListDisposition disposition);
|
||||
|
||||
/** Changes in trusted nodes after updating validator list
|
||||
*/
|
||||
*/
|
||||
struct TrustChanges
|
||||
{
|
||||
explicit TrustChanges() = default;
|
||||
@@ -165,14 +164,14 @@ class ValidatorList
|
||||
static const std::string filePrefix_;
|
||||
|
||||
public:
|
||||
ValidatorList (
|
||||
ValidatorList(
|
||||
ManifestCache& validatorManifests,
|
||||
ManifestCache& publisherManifests,
|
||||
TimeKeeper& timeKeeper,
|
||||
std::string const& databasePath,
|
||||
beast::Journal j,
|
||||
boost::optional<std::size_t> minimumQuorum = boost::none);
|
||||
~ValidatorList () = default;
|
||||
~ValidatorList() = default;
|
||||
|
||||
/** Describes the result of processing a Validator List (UNL),
|
||||
including some of the information from the list which can
|
||||
@@ -181,17 +180,16 @@ public:
|
||||
*/
|
||||
struct PublisherListStats
|
||||
{
|
||||
explicit PublisherListStats(ListDisposition d)
|
||||
: disposition(d)
|
||||
explicit PublisherListStats(ListDisposition d) : disposition(d)
|
||||
{
|
||||
}
|
||||
|
||||
PublisherListStats(ListDisposition d, PublicKey key,
|
||||
bool avail, std::size_t seq)
|
||||
: disposition(d)
|
||||
, publisherKey(key)
|
||||
, available(avail)
|
||||
, sequence(seq)
|
||||
PublisherListStats(
|
||||
ListDisposition d,
|
||||
PublicKey key,
|
||||
bool avail,
|
||||
std::size_t seq)
|
||||
: disposition(d), publisherKey(key), available(avail), sequence(seq)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -219,7 +217,7 @@ public:
|
||||
@return `false` if an entry is invalid or unparsable
|
||||
*/
|
||||
bool
|
||||
load (
|
||||
load(
|
||||
PublicKey const& localSigningKey,
|
||||
std::vector<std::string> const& configKeys,
|
||||
std::vector<std::string> const& publisherKeys);
|
||||
@@ -252,7 +250,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
PublisherListStats
|
||||
applyListAndBroadcast (
|
||||
applyListAndBroadcast(
|
||||
std::string const& manifest,
|
||||
std::string const& blob,
|
||||
std::string const& signature,
|
||||
@@ -285,7 +283,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
PublisherListStats
|
||||
applyList (
|
||||
applyList(
|
||||
std::string const& manifest,
|
||||
std::string const& blob,
|
||||
std::string const& signature,
|
||||
@@ -321,7 +319,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
TrustChanges
|
||||
updateTrusted (hash_set<NodeID> const& seenValidators);
|
||||
updateTrusted(hash_set<NodeID> const& seenValidators);
|
||||
|
||||
/** Get quorum value for current trusted key set
|
||||
|
||||
@@ -337,7 +335,7 @@ public:
|
||||
@return quorum value
|
||||
*/
|
||||
std::size_t
|
||||
quorum () const
|
||||
quorum() const
|
||||
{
|
||||
return quorum_;
|
||||
}
|
||||
@@ -351,8 +349,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
bool
|
||||
trusted (
|
||||
PublicKey const& identity) const;
|
||||
trusted(PublicKey const& identity) const;
|
||||
|
||||
/** Returns `true` if public key is included on any lists
|
||||
|
||||
@@ -363,8 +360,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
bool
|
||||
listed (
|
||||
PublicKey const& identity) const;
|
||||
listed(PublicKey const& identity) const;
|
||||
|
||||
/** Returns master public key if public key is trusted
|
||||
|
||||
@@ -377,8 +373,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
boost::optional<PublicKey>
|
||||
getTrustedKey (
|
||||
PublicKey const& identity) const;
|
||||
getTrustedKey(PublicKey const& identity) const;
|
||||
|
||||
/** Returns listed master public if public key is included on any lists
|
||||
|
||||
@@ -391,8 +386,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
boost::optional<PublicKey>
|
||||
getListedKey (
|
||||
PublicKey const& identity) const;
|
||||
getListedKey(PublicKey const& identity) const;
|
||||
|
||||
/** Returns `true` if public key is a trusted publisher
|
||||
|
||||
@@ -403,8 +397,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
bool
|
||||
trustedPublisher (
|
||||
PublicKey const& identity) const;
|
||||
trustedPublisher(PublicKey const& identity) const;
|
||||
|
||||
/** Returns local validator public key
|
||||
|
||||
@@ -413,7 +406,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
PublicKey
|
||||
localPublicKey () const;
|
||||
localPublicKey() const;
|
||||
|
||||
/** Invokes the callback once for every listed validation public key.
|
||||
|
||||
@@ -431,8 +424,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
void
|
||||
for_each_listed (
|
||||
std::function<void(PublicKey const&, bool)> func) const;
|
||||
for_each_listed(std::function<void(PublicKey const&, bool)> func) const;
|
||||
|
||||
/** Invokes the callback once for every available publisher list's raw
|
||||
data members
|
||||
@@ -462,12 +454,14 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
void
|
||||
for_each_available (
|
||||
std::function<void(std::string const& manifest,
|
||||
std::string const& blob, std::string const& signature,
|
||||
std::uint32_t version,
|
||||
PublicKey const& pubKey, std::size_t sequence,
|
||||
uint256 const& hash)> func) const;
|
||||
for_each_available(std::function<void(
|
||||
std::string const& manifest,
|
||||
std::string const& blob,
|
||||
std::string const& signature,
|
||||
std::uint32_t version,
|
||||
PublicKey const& pubKey,
|
||||
std::size_t sequence,
|
||||
uint256 const& hash)> func) const;
|
||||
|
||||
/** Returns the current valid list for the given publisher key,
|
||||
if available, as a Json object.
|
||||
@@ -511,18 +505,16 @@ public:
|
||||
return {quorum_, trustedSigningKeys_};
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
/** Get the filename used for caching UNLs
|
||||
*/
|
||||
*/
|
||||
boost::filesystem::path
|
||||
GetCacheFileName(PublicKey const& pubKey);
|
||||
|
||||
/** Write a JSON UNL to a cache file
|
||||
*/
|
||||
*/
|
||||
void
|
||||
CacheValidatorFile(PublicKey const& pubKey,
|
||||
PublisherList const& publisher);
|
||||
CacheValidatorFile(PublicKey const& pubKey, PublisherList const& publisher);
|
||||
|
||||
/** Check response for trusted valid published list
|
||||
|
||||
@@ -533,7 +525,7 @@ private:
|
||||
Calling public member function is expected to lock mutex
|
||||
*/
|
||||
ListDisposition
|
||||
verify (
|
||||
verify(
|
||||
Json::Value& list,
|
||||
PublicKey& pubKey,
|
||||
std::string const& manifest,
|
||||
@@ -551,7 +543,7 @@ private:
|
||||
Calling public member function is expected to lock mutex
|
||||
*/
|
||||
bool
|
||||
removePublisherList (PublicKey const& publisherKey);
|
||||
removePublisherList(PublicKey const& publisherKey);
|
||||
|
||||
/** Return quorum for trusted validator set
|
||||
|
||||
@@ -560,9 +552,8 @@ private:
|
||||
@param seen Number of trusted validators that have signed
|
||||
recently received validations */
|
||||
std::size_t
|
||||
calculateQuorum (
|
||||
std::size_t trusted, std::size_t seen);
|
||||
calculateQuorum(std::size_t trusted, std::size_t seen);
|
||||
};
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
#ifndef RIPPLE_APP_MISC_VALIDATORSITE_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_VALIDATORSITE_H_INCLUDED
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/ValidatorList.h>
|
||||
#include <ripple/app/misc/detail/Work.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -133,11 +133,11 @@ private:
|
||||
const std::chrono::seconds requestTimeout_;
|
||||
|
||||
public:
|
||||
ValidatorSite (
|
||||
ValidatorSite(
|
||||
Application& app,
|
||||
boost::optional<beast::Journal> j = boost::none,
|
||||
std::chrono::seconds timeout = std::chrono::seconds{20});
|
||||
~ValidatorSite ();
|
||||
~ValidatorSite();
|
||||
|
||||
/** Load configured site URIs.
|
||||
|
||||
@@ -150,8 +150,7 @@ public:
|
||||
@return `false` if an entry is invalid or unparsable
|
||||
*/
|
||||
bool
|
||||
load (
|
||||
std::vector<std::string> const& siteURIs);
|
||||
load(std::vector<std::string> const& siteURIs);
|
||||
|
||||
/** Start fetching lists from sites
|
||||
|
||||
@@ -162,7 +161,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
void
|
||||
start ();
|
||||
start();
|
||||
|
||||
/** Wait for current fetches from sites to complete
|
||||
|
||||
@@ -171,7 +170,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
void
|
||||
join ();
|
||||
join();
|
||||
|
||||
/** Stop fetching lists from sites
|
||||
|
||||
@@ -182,7 +181,7 @@ public:
|
||||
May be called concurrently
|
||||
*/
|
||||
void
|
||||
stop ();
|
||||
stop();
|
||||
|
||||
/** Return JSON representation of configured validator sites
|
||||
*/
|
||||
@@ -193,23 +192,19 @@ private:
|
||||
/// Queue next site to be fetched
|
||||
/// lock over state_mutex_ required
|
||||
void
|
||||
setTimer (std::lock_guard<std::mutex>&);
|
||||
setTimer(std::lock_guard<std::mutex>&);
|
||||
|
||||
/// request took too long
|
||||
void
|
||||
onRequestTimeout (
|
||||
std::size_t siteIdx,
|
||||
error_code const& ec);
|
||||
onRequestTimeout(std::size_t siteIdx, error_code const& ec);
|
||||
|
||||
/// Fetch site whose time has come
|
||||
void
|
||||
onTimer (
|
||||
std::size_t siteIdx,
|
||||
error_code const& ec);
|
||||
onTimer(std::size_t siteIdx, error_code const& ec);
|
||||
|
||||
/// Store latest list fetched from site
|
||||
void
|
||||
onSiteFetch (
|
||||
onSiteFetch(
|
||||
boost::system::error_code const& ec,
|
||||
detail::response_type&& res,
|
||||
std::size_t siteIdx);
|
||||
@@ -224,7 +219,7 @@ private:
|
||||
/// Initiate request to given resource.
|
||||
/// lock over sites_mutex_ required
|
||||
void
|
||||
makeRequest (
|
||||
makeRequest(
|
||||
std::shared_ptr<Site::Resource> resource,
|
||||
std::size_t siteIdx,
|
||||
std::lock_guard<std::mutex>& lock);
|
||||
@@ -232,7 +227,7 @@ private:
|
||||
/// Parse json response from validator list site.
|
||||
/// lock over sites_mutex_ required
|
||||
void
|
||||
parseJsonResponse (
|
||||
parseJsonResponse(
|
||||
std::string const& res,
|
||||
std::size_t siteIdx,
|
||||
std::lock_guard<std::mutex>& lock);
|
||||
@@ -240,7 +235,7 @@ private:
|
||||
/// Interpret a redirect response.
|
||||
/// lock over sites_mutex_ required
|
||||
std::shared_ptr<Site::Resource>
|
||||
processRedirect (
|
||||
processRedirect(
|
||||
detail::response_type& res,
|
||||
std::size_t siteIdx,
|
||||
std::lock_guard<std::mutex>& lock);
|
||||
@@ -251,6 +246,6 @@ private:
|
||||
missingSite();
|
||||
};
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,13 +35,15 @@ class Work
|
||||
public:
|
||||
virtual ~Work() = default;
|
||||
|
||||
virtual void run() = 0;
|
||||
virtual void
|
||||
run() = 0;
|
||||
|
||||
virtual void cancel() = 0;
|
||||
virtual void
|
||||
cancel() = 0;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace detail
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,19 +22,18 @@
|
||||
|
||||
#include <ripple/app/misc/detail/Work.h>
|
||||
#include <ripple/protocol/BuildInfo.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/beast/core/multi_buffer.hpp>
|
||||
#include <boost/beast/http/empty_body.hpp>
|
||||
#include <boost/beast/http/read.hpp>
|
||||
#include <boost/beast/http/write.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Impl>
|
||||
class WorkBase
|
||||
: public Work
|
||||
class WorkBase : public Work
|
||||
{
|
||||
protected:
|
||||
using error_code = boost::system::error_code;
|
||||
@@ -42,6 +41,7 @@ protected:
|
||||
public:
|
||||
using callback_type =
|
||||
std::function<void(error_code const&, response_type&&)>;
|
||||
|
||||
protected:
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
@@ -64,9 +64,11 @@ protected:
|
||||
|
||||
public:
|
||||
WorkBase(
|
||||
std::string const& host, std::string const& path,
|
||||
std::string const& host,
|
||||
std::string const& path,
|
||||
std::string const& port,
|
||||
boost::asio::io_service& ios, callback_type cb);
|
||||
boost::asio::io_service& ios,
|
||||
callback_type cb);
|
||||
~WorkBase();
|
||||
|
||||
Impl&
|
||||
@@ -75,9 +77,11 @@ public:
|
||||
return *static_cast<Impl*>(this);
|
||||
}
|
||||
|
||||
void run() override;
|
||||
void
|
||||
run() override;
|
||||
|
||||
void cancel() override;
|
||||
void
|
||||
cancel() override;
|
||||
|
||||
void
|
||||
fail(error_code const& ec);
|
||||
@@ -97,10 +101,13 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Impl>
|
||||
WorkBase<Impl>::WorkBase(std::string const& host,
|
||||
std::string const& path, std::string const& port,
|
||||
boost::asio::io_service& ios, callback_type cb)
|
||||
template <class Impl>
|
||||
WorkBase<Impl>::WorkBase(
|
||||
std::string const& host,
|
||||
std::string const& path,
|
||||
std::string const& port,
|
||||
boost::asio::io_service& ios,
|
||||
callback_type cb)
|
||||
: host_(host)
|
||||
, path_(path)
|
||||
, port_(port)
|
||||
@@ -112,45 +119,47 @@ WorkBase<Impl>::WorkBase(std::string const& host,
|
||||
{
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
WorkBase<Impl>::~WorkBase()
|
||||
{
|
||||
if (cb_)
|
||||
cb_ (make_error_code(boost::system::errc::not_a_socket),
|
||||
cb_(make_error_code(boost::system::errc::not_a_socket),
|
||||
std::move(res_));
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
void
|
||||
WorkBase<Impl>::run()
|
||||
{
|
||||
if (! strand_.running_in_this_thread())
|
||||
return ios_.post(strand_.wrap (std::bind(
|
||||
&WorkBase::run, impl().shared_from_this())));
|
||||
if (!strand_.running_in_this_thread())
|
||||
return ios_.post(
|
||||
strand_.wrap(std::bind(&WorkBase::run, impl().shared_from_this())));
|
||||
|
||||
resolver_.async_resolve(
|
||||
query_type{host_, port_},
|
||||
strand_.wrap (std::bind(&WorkBase::onResolve, impl().shared_from_this(),
|
||||
strand_.wrap(std::bind(
|
||||
&WorkBase::onResolve,
|
||||
impl().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
void
|
||||
WorkBase<Impl>::cancel()
|
||||
{
|
||||
if (! strand_.running_in_this_thread())
|
||||
if (!strand_.running_in_this_thread())
|
||||
{
|
||||
return ios_.post(strand_.wrap (std::bind(
|
||||
&WorkBase::cancel, impl().shared_from_this())));
|
||||
return ios_.post(strand_.wrap(
|
||||
std::bind(&WorkBase::cancel, impl().shared_from_this())));
|
||||
}
|
||||
|
||||
error_code ec;
|
||||
resolver_.cancel();
|
||||
socket_.cancel (ec);
|
||||
socket_.cancel(ec);
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
void
|
||||
WorkBase<Impl>::fail(error_code const& ec)
|
||||
{
|
||||
@@ -161,47 +170,58 @@ WorkBase<Impl>::fail(error_code const& ec)
|
||||
}
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
void
|
||||
WorkBase<Impl>::onResolve(error_code const& ec, resolver_type::iterator it)
|
||||
{
|
||||
if (ec)
|
||||
return fail(ec);
|
||||
|
||||
socket_.async_connect(*it,
|
||||
strand_.wrap (std::bind(&Impl::onConnect, impl().shared_from_this(),
|
||||
socket_.async_connect(
|
||||
*it,
|
||||
strand_.wrap(std::bind(
|
||||
&Impl::onConnect,
|
||||
impl().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
void
|
||||
WorkBase<Impl>::onStart()
|
||||
{
|
||||
req_.method(boost::beast::http::verb::get);
|
||||
req_.target(path_.empty() ? "/" : path_);
|
||||
req_.version(11);
|
||||
req_.set (
|
||||
"Host", host_ + ":" + port_);
|
||||
req_.set ("User-Agent", BuildInfo::getFullVersionString());
|
||||
req_.set("Host", host_ + ":" + port_);
|
||||
req_.set("User-Agent", BuildInfo::getFullVersionString());
|
||||
req_.prepare_payload();
|
||||
boost::beast::http::async_write(impl().stream(), req_,
|
||||
strand_.wrap (std::bind (&WorkBase::onRequest,
|
||||
impl().shared_from_this(), std::placeholders::_1)));
|
||||
boost::beast::http::async_write(
|
||||
impl().stream(),
|
||||
req_,
|
||||
strand_.wrap(std::bind(
|
||||
&WorkBase::onRequest,
|
||||
impl().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
void
|
||||
WorkBase<Impl>::onRequest(error_code const& ec)
|
||||
{
|
||||
if (ec)
|
||||
return fail(ec);
|
||||
|
||||
boost::beast::http::async_read (impl().stream(), read_buf_, res_,
|
||||
strand_.wrap (std::bind (&WorkBase::onResponse,
|
||||
impl().shared_from_this(), std::placeholders::_1)));
|
||||
boost::beast::http::async_read(
|
||||
impl().stream(),
|
||||
read_buf_,
|
||||
res_,
|
||||
strand_.wrap(std::bind(
|
||||
&WorkBase::onResponse,
|
||||
impl().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
template <class Impl>
|
||||
void
|
||||
WorkBase<Impl>::onResponse(error_code const& ec)
|
||||
{
|
||||
@@ -213,8 +233,8 @@ WorkBase<Impl>::onResponse(error_code const& ec)
|
||||
cb_ = nullptr;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace detail
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,8 +31,7 @@ namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
// Work with files
|
||||
class WorkFile: public Work
|
||||
, public std::enable_shared_from_this<WorkFile>
|
||||
class WorkFile : public Work, public std::enable_shared_from_this<WorkFile>
|
||||
{
|
||||
protected:
|
||||
using error_code = boost::system::error_code;
|
||||
@@ -42,48 +41,49 @@ protected:
|
||||
public:
|
||||
using callback_type =
|
||||
std::function<void(error_code const&, response_type const&)>;
|
||||
|
||||
public:
|
||||
WorkFile(
|
||||
std::string const& path,
|
||||
boost::asio::io_service& ios, callback_type cb);
|
||||
boost::asio::io_service& ios,
|
||||
callback_type cb);
|
||||
~WorkFile();
|
||||
|
||||
void run() override;
|
||||
void
|
||||
run() override;
|
||||
|
||||
void cancel() override;
|
||||
void
|
||||
cancel() override;
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
callback_type cb_;
|
||||
boost::asio::io_service& ios_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
WorkFile::WorkFile(
|
||||
std::string const& path,
|
||||
boost::asio::io_service& ios, callback_type cb)
|
||||
: path_(path)
|
||||
, cb_(std::move(cb))
|
||||
, ios_(ios)
|
||||
, strand_(ios)
|
||||
boost::asio::io_service& ios,
|
||||
callback_type cb)
|
||||
: path_(path), cb_(std::move(cb)), ios_(ios), strand_(ios)
|
||||
{
|
||||
}
|
||||
|
||||
WorkFile::~WorkFile()
|
||||
{
|
||||
if (cb_)
|
||||
cb_ (make_error_code(boost::system::errc::interrupted), {});
|
||||
cb_(make_error_code(boost::system::errc::interrupted), {});
|
||||
}
|
||||
|
||||
void
|
||||
WorkFile::run()
|
||||
{
|
||||
if (! strand_.running_in_this_thread())
|
||||
return ios_.post(strand_.wrap (std::bind(
|
||||
&WorkFile::run, shared_from_this())));
|
||||
if (!strand_.running_in_this_thread())
|
||||
return ios_.post(
|
||||
strand_.wrap(std::bind(&WorkFile::run, shared_from_this())));
|
||||
|
||||
error_code ec;
|
||||
auto const fileContents = getFileContents(ec, path_, megabytes(1));
|
||||
@@ -99,9 +99,8 @@ WorkFile::cancel()
|
||||
// Nothing to do. Either it finished in run, or it didn't start.
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // detail
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,16 +27,18 @@ namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
// Work over TCP/IP
|
||||
class WorkPlain : public WorkBase<WorkPlain>
|
||||
, public std::enable_shared_from_this<WorkPlain>
|
||||
class WorkPlain : public WorkBase<WorkPlain>,
|
||||
public std::enable_shared_from_this<WorkPlain>
|
||||
{
|
||||
friend class WorkBase<WorkPlain>;
|
||||
|
||||
public:
|
||||
WorkPlain(
|
||||
std::string const& host,
|
||||
std::string const& path, std::string const& port,
|
||||
boost::asio::io_service& ios, callback_type cb);
|
||||
std::string const& path,
|
||||
std::string const& port,
|
||||
boost::asio::io_service& ios,
|
||||
callback_type cb);
|
||||
~WorkPlain() = default;
|
||||
|
||||
private:
|
||||
@@ -54,9 +56,11 @@ private:
|
||||
|
||||
WorkPlain::WorkPlain(
|
||||
std::string const& host,
|
||||
std::string const& path, std::string const& port,
|
||||
boost::asio::io_service& ios, callback_type cb)
|
||||
: WorkBase (host, path, port, ios, cb)
|
||||
std::string const& path,
|
||||
std::string const& port,
|
||||
boost::asio::io_service& ios,
|
||||
callback_type cb)
|
||||
: WorkBase(host, path, port, ios, cb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -66,11 +70,11 @@ WorkPlain::onConnect(error_code const& ec)
|
||||
if (ec)
|
||||
return fail(ec);
|
||||
|
||||
onStart ();
|
||||
onStart();
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace detail
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
// Work over SSL
|
||||
class WorkSSL : public WorkBase<WorkSSL>
|
||||
, public std::enable_shared_from_this<WorkSSL>
|
||||
class WorkSSL : public WorkBase<WorkSSL>,
|
||||
public std::enable_shared_from_this<WorkSSL>
|
||||
{
|
||||
friend class WorkBase<WorkSSL>;
|
||||
|
||||
@@ -85,8 +85,8 @@ WorkSSL::WorkSSL(
|
||||
{
|
||||
auto ec = context_.preConnectVerify(stream_, host_);
|
||||
if (ec)
|
||||
Throw<std::runtime_error> (
|
||||
boost::str (boost::format ("preConnectVerify: %s") % ec.message ()));
|
||||
Throw<std::runtime_error>(
|
||||
boost::str(boost::format("preConnectVerify: %s") % ec.message()));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -98,7 +98,9 @@ WorkSSL::onConnect(error_code const& ec)
|
||||
|
||||
stream_.async_handshake(
|
||||
boost::asio::ssl::stream_base::client,
|
||||
strand_.wrap (boost::bind(&WorkSSL::onHandshake, shared_from_this(),
|
||||
strand_.wrap(boost::bind(
|
||||
&WorkSSL::onHandshake,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
|
||||
@@ -108,11 +110,11 @@ WorkSSL::onHandshake(error_code const& ec)
|
||||
if (ec)
|
||||
return fail(ec);
|
||||
|
||||
onStart ();
|
||||
onStart();
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace detail
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/LedgerToJson.h>
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/ledger/LedgerToJson.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/misc/impl/AccountTxPaging.h>
|
||||
@@ -30,7 +30,7 @@
|
||||
namespace ripple {
|
||||
|
||||
void
|
||||
convertBlobsToTxResult (
|
||||
convertBlobsToTxResult(
|
||||
NetworkOPs::AccountTxs& to,
|
||||
std::uint32_t ledger_index,
|
||||
std::string const& status,
|
||||
@@ -38,23 +38,23 @@ convertBlobsToTxResult (
|
||||
Blob const& rawMeta,
|
||||
Application& app)
|
||||
{
|
||||
SerialIter it (makeSlice(rawTxn));
|
||||
auto txn = std::make_shared<STTx const> (it);
|
||||
SerialIter it(makeSlice(rawTxn));
|
||||
auto txn = std::make_shared<STTx const>(it);
|
||||
std::string reason;
|
||||
|
||||
auto tr = std::make_shared<Transaction> (txn, reason, app);
|
||||
auto tr = std::make_shared<Transaction>(txn, reason, app);
|
||||
|
||||
tr->setStatus (Transaction::sqlTransactionStatus(status));
|
||||
tr->setLedger (ledger_index);
|
||||
tr->setStatus(Transaction::sqlTransactionStatus(status));
|
||||
tr->setLedger(ledger_index);
|
||||
|
||||
auto metaset = std::make_shared<TxMeta> (
|
||||
tr->getID (), tr->getLedger (), rawMeta);
|
||||
auto metaset =
|
||||
std::make_shared<TxMeta>(tr->getID(), tr->getLedger(), rawMeta);
|
||||
|
||||
to.emplace_back(std::move(tr), metaset);
|
||||
};
|
||||
|
||||
void
|
||||
saveLedgerAsync (Application& app, std::uint32_t seq)
|
||||
saveLedgerAsync(Application& app, std::uint32_t seq)
|
||||
{
|
||||
if (auto l = app.getLedgerMaster().getLedgerBySeq(seq))
|
||||
pendSaveValidated(app, l, false, false);
|
||||
@@ -259,4 +259,4 @@ accountTxPage(
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
@@ -20,19 +20,18 @@
|
||||
#ifndef RIPPLE_APP_MISC_IMPL_ACCOUNTTXPAGING_H_INCLUDED
|
||||
#define RIPPLE_APP_MISC_IMPL_ACCOUNTTXPAGING_H_INCLUDED
|
||||
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ripple {
|
||||
|
||||
void
|
||||
convertBlobsToTxResult (
|
||||
convertBlobsToTxResult(
|
||||
NetworkOPs::AccountTxs& to,
|
||||
std::uint32_t ledger_index,
|
||||
std::string const& status,
|
||||
@@ -41,7 +40,7 @@ convertBlobsToTxResult (
|
||||
Application& app);
|
||||
|
||||
void
|
||||
saveLedgerAsync (Application& app, std::uint32_t seq);
|
||||
saveLedgerAsync(Application& app, std::uint32_t seq);
|
||||
|
||||
void
|
||||
accountTxPage(
|
||||
@@ -61,6 +60,6 @@ accountTxPage(
|
||||
int limit,
|
||||
bool bAdmin,
|
||||
std::uint32_t page_length);
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/AmendmentTable.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <algorithm>
|
||||
@@ -31,38 +31,36 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static
|
||||
std::vector<std::pair<uint256, std::string>>
|
||||
parseSection (Section const& section)
|
||||
static std::vector<std::pair<uint256, std::string>>
|
||||
parseSection(Section const& section)
|
||||
{
|
||||
static boost::regex const re1 (
|
||||
"^" // start of line
|
||||
"(?:\\s*)" // whitespace (optional)
|
||||
"([abcdefABCDEF0-9]{64})" // <hexadecimal amendment ID>
|
||||
"(?:\\s+)" // whitespace
|
||||
"(\\S+)" // <description>
|
||||
, boost::regex_constants::optimize
|
||||
);
|
||||
static boost::regex const re1(
|
||||
"^" // start of line
|
||||
"(?:\\s*)" // whitespace (optional)
|
||||
"([abcdefABCDEF0-9]{64})" // <hexadecimal amendment ID>
|
||||
"(?:\\s+)" // whitespace
|
||||
"(\\S+)" // <description>
|
||||
,
|
||||
boost::regex_constants::optimize);
|
||||
|
||||
std::vector<std::pair<uint256, std::string>> names;
|
||||
|
||||
for (auto const& line : section.lines ())
|
||||
for (auto const& line : section.lines())
|
||||
{
|
||||
boost::smatch match;
|
||||
|
||||
if (!boost::regex_match (line, match, re1))
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid entry '" + line +
|
||||
"' in [" + section.name () + "]");
|
||||
if (!boost::regex_match(line, match, re1))
|
||||
Throw<std::runtime_error>(
|
||||
"Invalid entry '" + line + "' in [" + section.name() + "]");
|
||||
|
||||
uint256 id;
|
||||
|
||||
if (!id.SetHexExact (match[1]))
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid amendment ID '" + match[1] +
|
||||
"' in [" + section.name () + "]");
|
||||
if (!id.SetHexExact(match[1]))
|
||||
Throw<std::runtime_error>(
|
||||
"Invalid amendment ID '" + match[1] + "' in [" +
|
||||
section.name() + "]");
|
||||
|
||||
names.push_back (std::make_pair (id, match[2]));
|
||||
names.push_back(std::make_pair(id, match[2]));
|
||||
}
|
||||
|
||||
return names;
|
||||
@@ -90,7 +88,7 @@ struct AmendmentState
|
||||
/** The name of this amendment, possibly empty. */
|
||||
std::string name;
|
||||
|
||||
explicit AmendmentState () = default;
|
||||
explicit AmendmentState() = default;
|
||||
};
|
||||
|
||||
/** The status of all amendments requested in a given window. */
|
||||
@@ -107,9 +105,10 @@ public:
|
||||
// number of votes needed
|
||||
int mThreshold = 0;
|
||||
|
||||
AmendmentSet () = default;
|
||||
AmendmentSet() = default;
|
||||
|
||||
void tally (std::set<uint256> const& amendments)
|
||||
void
|
||||
tally(std::set<uint256> const& amendments)
|
||||
{
|
||||
++mTrustedValidations;
|
||||
|
||||
@@ -117,9 +116,10 @@ public:
|
||||
++votes_[amendment];
|
||||
}
|
||||
|
||||
int votes (uint256 const& amendment) const
|
||||
int
|
||||
votes(uint256 const& amendment) const
|
||||
{
|
||||
auto const& it = votes_.find (amendment);
|
||||
auto const& it = votes_.find(amendment);
|
||||
|
||||
if (it == votes_.end())
|
||||
return 0;
|
||||
@@ -136,8 +136,7 @@ public:
|
||||
Amendments are proposed and then adopted or rejected by the network. An
|
||||
Amendment is uniquely identified by its AmendmentID, a 256-bit key.
|
||||
*/
|
||||
class AmendmentTableImpl final
|
||||
: public AmendmentTable
|
||||
class AmendmentTableImpl final : public AmendmentTable
|
||||
{
|
||||
protected:
|
||||
std::mutex mutex_;
|
||||
@@ -154,7 +153,7 @@ protected:
|
||||
|
||||
// The results of the last voting round - may be empty if
|
||||
// we haven't participated in one yet.
|
||||
std::unique_ptr <AmendmentSet> lastVote_;
|
||||
std::unique_ptr<AmendmentSet> lastVote_;
|
||||
|
||||
// True if an unsupported amendment is enabled
|
||||
bool unsupportedEnabled_;
|
||||
@@ -166,15 +165,18 @@ protected:
|
||||
beast::Journal const j_;
|
||||
|
||||
// Finds or creates state
|
||||
AmendmentState* add (uint256 const& amendment);
|
||||
AmendmentState*
|
||||
add(uint256 const& amendment);
|
||||
|
||||
// Finds existing state
|
||||
AmendmentState* get (uint256 const& amendment);
|
||||
AmendmentState*
|
||||
get(uint256 const& amendment);
|
||||
|
||||
void setJson (Json::Value& v, uint256 const& amendment, const AmendmentState&);
|
||||
void
|
||||
setJson(Json::Value& v, uint256 const& amendment, const AmendmentState&);
|
||||
|
||||
public:
|
||||
AmendmentTableImpl (
|
||||
AmendmentTableImpl(
|
||||
std::chrono::seconds majorityTime,
|
||||
int majorityFraction,
|
||||
Section const& supported,
|
||||
@@ -182,25 +184,36 @@ public:
|
||||
Section const& vetoed,
|
||||
beast::Journal journal);
|
||||
|
||||
uint256 find (std::string const& name) override;
|
||||
uint256
|
||||
find(std::string const& name) override;
|
||||
|
||||
bool veto (uint256 const& amendment) override;
|
||||
bool unVeto (uint256 const& amendment) override;
|
||||
bool
|
||||
veto(uint256 const& amendment) override;
|
||||
bool
|
||||
unVeto(uint256 const& amendment) override;
|
||||
|
||||
bool enable (uint256 const& amendment) override;
|
||||
bool disable (uint256 const& amendment) override;
|
||||
bool
|
||||
enable(uint256 const& amendment) override;
|
||||
bool
|
||||
disable(uint256 const& amendment) override;
|
||||
|
||||
bool isEnabled (uint256 const& amendment) override;
|
||||
bool isSupported (uint256 const& amendment) override;
|
||||
bool
|
||||
isEnabled(uint256 const& amendment) override;
|
||||
bool
|
||||
isSupported(uint256 const& amendment) override;
|
||||
|
||||
bool hasUnsupportedEnabled () override;
|
||||
bool
|
||||
hasUnsupportedEnabled() override;
|
||||
boost::optional<NetClock::time_point>
|
||||
firstUnsupportedExpected() override;
|
||||
|
||||
Json::Value getJson (int) override;
|
||||
Json::Value getJson (uint256 const&) override;
|
||||
Json::Value
|
||||
getJson(int) override;
|
||||
Json::Value
|
||||
getJson(uint256 const&) override;
|
||||
|
||||
bool needValidatedLedger (LedgerIndex seq) override;
|
||||
bool
|
||||
needValidatedLedger(LedgerIndex seq) override;
|
||||
|
||||
void
|
||||
doValidatedLedger(
|
||||
@@ -208,14 +221,14 @@ public:
|
||||
std::set<uint256> const& enabled,
|
||||
majorityAmendments_t const& majority) override;
|
||||
|
||||
std::vector <uint256>
|
||||
doValidation (std::set<uint256> const& enabledAmendments) override;
|
||||
std::vector<uint256>
|
||||
doValidation(std::set<uint256> const& enabledAmendments) override;
|
||||
|
||||
std::vector <uint256>
|
||||
getDesired () override;
|
||||
std::vector<uint256>
|
||||
getDesired() override;
|
||||
|
||||
std::map <uint256, std::uint32_t>
|
||||
doVoting (
|
||||
std::map<uint256, std::uint32_t>
|
||||
doVoting(
|
||||
NetClock::time_point closeTime,
|
||||
std::set<uint256> const& enabledAmendments,
|
||||
majorityAmendments_t const& majorityAmendments,
|
||||
@@ -224,45 +237,43 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
AmendmentTableImpl::AmendmentTableImpl (
|
||||
std::chrono::seconds majorityTime,
|
||||
int majorityFraction,
|
||||
Section const& supported,
|
||||
Section const& enabled,
|
||||
Section const& vetoed,
|
||||
beast::Journal journal)
|
||||
: lastUpdateSeq_ (0)
|
||||
, majorityTime_ (majorityTime)
|
||||
, majorityFraction_ (majorityFraction)
|
||||
, unsupportedEnabled_ (false)
|
||||
, j_ (journal)
|
||||
AmendmentTableImpl::AmendmentTableImpl(
|
||||
std::chrono::seconds majorityTime,
|
||||
int majorityFraction,
|
||||
Section const& supported,
|
||||
Section const& enabled,
|
||||
Section const& vetoed,
|
||||
beast::Journal journal)
|
||||
: lastUpdateSeq_(0)
|
||||
, majorityTime_(majorityTime)
|
||||
, majorityFraction_(majorityFraction)
|
||||
, unsupportedEnabled_(false)
|
||||
, j_(journal)
|
||||
{
|
||||
assert (majorityFraction_ != 0);
|
||||
assert(majorityFraction_ != 0);
|
||||
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
|
||||
for (auto const& a : parseSection(supported))
|
||||
{
|
||||
if (auto s = add (a.first))
|
||||
if (auto s = add(a.first))
|
||||
{
|
||||
JLOG (j_.debug()) <<
|
||||
"Amendment " << a.first << " is supported.";
|
||||
JLOG(j_.debug()) << "Amendment " << a.first << " is supported.";
|
||||
|
||||
if (!a.second.empty ())
|
||||
if (!a.second.empty())
|
||||
s->name = a.second;
|
||||
|
||||
s->supported = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& a : parseSection (enabled))
|
||||
for (auto const& a : parseSection(enabled))
|
||||
{
|
||||
if (auto s = add (a.first))
|
||||
if (auto s = add(a.first))
|
||||
{
|
||||
JLOG (j_.debug()) <<
|
||||
"Amendment " << a.first << " is enabled.";
|
||||
JLOG(j_.debug()) << "Amendment " << a.first << " is enabled.";
|
||||
|
||||
if (!a.second.empty ())
|
||||
if (!a.second.empty())
|
||||
s->name = a.second;
|
||||
|
||||
s->supported = true;
|
||||
@@ -270,15 +281,14 @@ AmendmentTableImpl::AmendmentTableImpl (
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& a : parseSection (vetoed))
|
||||
for (auto const& a : parseSection(vetoed))
|
||||
{
|
||||
// Unknown amendments are effectively vetoed already
|
||||
if (auto s = get (a.first))
|
||||
if (auto s = get(a.first))
|
||||
{
|
||||
JLOG (j_.info()) <<
|
||||
"Amendment " << a.first << " is vetoed.";
|
||||
JLOG(j_.info()) << "Amendment " << a.first << " is vetoed.";
|
||||
|
||||
if (!a.second.empty ())
|
||||
if (!a.second.empty())
|
||||
s->name = a.second;
|
||||
|
||||
s->vetoed = true;
|
||||
@@ -287,17 +297,17 @@ AmendmentTableImpl::AmendmentTableImpl (
|
||||
}
|
||||
|
||||
AmendmentState*
|
||||
AmendmentTableImpl::add (uint256 const& amendmentHash)
|
||||
AmendmentTableImpl::add(uint256 const& amendmentHash)
|
||||
{
|
||||
// call with the mutex held
|
||||
return &amendmentMap_[amendmentHash];
|
||||
}
|
||||
|
||||
AmendmentState*
|
||||
AmendmentTableImpl::get (uint256 const& amendmentHash)
|
||||
AmendmentTableImpl::get(uint256 const& amendmentHash)
|
||||
{
|
||||
// call with the mutex held
|
||||
auto ret = amendmentMap_.find (amendmentHash);
|
||||
auto ret = amendmentMap_.find(amendmentHash);
|
||||
|
||||
if (ret == amendmentMap_.end())
|
||||
return nullptr;
|
||||
@@ -306,9 +316,9 @@ AmendmentTableImpl::get (uint256 const& amendmentHash)
|
||||
}
|
||||
|
||||
uint256
|
||||
AmendmentTableImpl::find (std::string const& name)
|
||||
AmendmentTableImpl::find(std::string const& name)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
|
||||
for (auto const& e : amendmentMap_)
|
||||
{
|
||||
@@ -320,10 +330,10 @@ AmendmentTableImpl::find (std::string const& name)
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::veto (uint256 const& amendment)
|
||||
AmendmentTableImpl::veto(uint256 const& amendment)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
auto s = add (amendment);
|
||||
std::lock_guard sl(mutex_);
|
||||
auto s = add(amendment);
|
||||
|
||||
if (s->vetoed)
|
||||
return false;
|
||||
@@ -332,10 +342,10 @@ AmendmentTableImpl::veto (uint256 const& amendment)
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::unVeto (uint256 const& amendment)
|
||||
AmendmentTableImpl::unVeto(uint256 const& amendment)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
auto s = get (amendment);
|
||||
std::lock_guard sl(mutex_);
|
||||
auto s = get(amendment);
|
||||
|
||||
if (!s || !s->vetoed)
|
||||
return false;
|
||||
@@ -344,20 +354,20 @@ AmendmentTableImpl::unVeto (uint256 const& amendment)
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::enable (uint256 const& amendment)
|
||||
AmendmentTableImpl::enable(uint256 const& amendment)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
auto s = add (amendment);
|
||||
std::lock_guard sl(mutex_);
|
||||
auto s = add(amendment);
|
||||
|
||||
if (s->enabled)
|
||||
return false;
|
||||
|
||||
s->enabled = true;
|
||||
|
||||
if (! s->supported)
|
||||
if (!s->supported)
|
||||
{
|
||||
JLOG (j_.error()) <<
|
||||
"Unsupported amendment " << amendment << " activated.";
|
||||
JLOG(j_.error()) << "Unsupported amendment " << amendment
|
||||
<< " activated.";
|
||||
unsupportedEnabled_ = true;
|
||||
}
|
||||
|
||||
@@ -365,10 +375,10 @@ AmendmentTableImpl::enable (uint256 const& amendment)
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::disable (uint256 const& amendment)
|
||||
AmendmentTableImpl::disable(uint256 const& amendment)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
auto s = get (amendment);
|
||||
std::lock_guard sl(mutex_);
|
||||
auto s = get(amendment);
|
||||
|
||||
if (!s || !s->enabled)
|
||||
return false;
|
||||
@@ -378,25 +388,25 @@ AmendmentTableImpl::disable (uint256 const& amendment)
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::isEnabled (uint256 const& amendment)
|
||||
AmendmentTableImpl::isEnabled(uint256 const& amendment)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
auto s = get (amendment);
|
||||
std::lock_guard sl(mutex_);
|
||||
auto s = get(amendment);
|
||||
return s && s->enabled;
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::isSupported (uint256 const& amendment)
|
||||
AmendmentTableImpl::isSupported(uint256 const& amendment)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
auto s = get (amendment);
|
||||
std::lock_guard sl(mutex_);
|
||||
auto s = get(amendment);
|
||||
return s && s->supported;
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::hasUnsupportedEnabled ()
|
||||
AmendmentTableImpl::hasUnsupportedEnabled()
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
return unsupportedEnabled_;
|
||||
}
|
||||
|
||||
@@ -407,86 +417,82 @@ AmendmentTableImpl::firstUnsupportedExpected()
|
||||
return firstUnsupportedExpected_;
|
||||
}
|
||||
|
||||
std::vector <uint256>
|
||||
AmendmentTableImpl::doValidation (
|
||||
std::set<uint256> const& enabled)
|
||||
std::vector<uint256>
|
||||
AmendmentTableImpl::doValidation(std::set<uint256> const& enabled)
|
||||
{
|
||||
// Get the list of amendments we support and do not
|
||||
// veto, but that are not already enabled
|
||||
std::vector <uint256> amendments;
|
||||
amendments.reserve (amendmentMap_.size());
|
||||
std::vector<uint256> amendments;
|
||||
amendments.reserve(amendmentMap_.size());
|
||||
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
for (auto const& e : amendmentMap_)
|
||||
{
|
||||
if (e.second.supported && ! e.second.vetoed &&
|
||||
(enabled.count (e.first) == 0))
|
||||
if (e.second.supported && !e.second.vetoed &&
|
||||
(enabled.count(e.first) == 0))
|
||||
{
|
||||
amendments.push_back (e.first);
|
||||
amendments.push_back(e.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! amendments.empty())
|
||||
std::sort (amendments.begin (), amendments.end ());
|
||||
if (!amendments.empty())
|
||||
std::sort(amendments.begin(), amendments.end());
|
||||
|
||||
return amendments;
|
||||
}
|
||||
|
||||
std::vector <uint256>
|
||||
AmendmentTableImpl::getDesired ()
|
||||
std::vector<uint256>
|
||||
AmendmentTableImpl::getDesired()
|
||||
{
|
||||
// Get the list of amendments we support and do not veto
|
||||
return doValidation({});
|
||||
}
|
||||
|
||||
std::map <uint256, std::uint32_t>
|
||||
AmendmentTableImpl::doVoting (
|
||||
std::map<uint256, std::uint32_t>
|
||||
AmendmentTableImpl::doVoting(
|
||||
NetClock::time_point closeTime,
|
||||
std::set<uint256> const& enabledAmendments,
|
||||
majorityAmendments_t const& majorityAmendments,
|
||||
std::vector<STValidation::pointer> const& valSet)
|
||||
{
|
||||
JLOG (j_.trace()) <<
|
||||
"voting at " << closeTime.time_since_epoch().count() <<
|
||||
": " << enabledAmendments.size() <<
|
||||
", " << majorityAmendments.size() <<
|
||||
", " << valSet.size();
|
||||
JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count()
|
||||
<< ": " << enabledAmendments.size() << ", "
|
||||
<< majorityAmendments.size() << ", " << valSet.size();
|
||||
|
||||
auto vote = std::make_unique <AmendmentSet> ();
|
||||
auto vote = std::make_unique<AmendmentSet>();
|
||||
|
||||
// process validations for ledger before flag ledger
|
||||
for (auto const& val : valSet)
|
||||
{
|
||||
if (val->isTrusted ())
|
||||
if (val->isTrusted())
|
||||
{
|
||||
std::set<uint256> ballot;
|
||||
|
||||
if (val->isFieldPresent (sfAmendments))
|
||||
if (val->isFieldPresent(sfAmendments))
|
||||
{
|
||||
auto const choices =
|
||||
val->getFieldV256 (sfAmendments);
|
||||
ballot.insert (choices.begin (), choices.end ());
|
||||
auto const choices = val->getFieldV256(sfAmendments);
|
||||
ballot.insert(choices.begin(), choices.end());
|
||||
}
|
||||
|
||||
vote->tally (ballot);
|
||||
vote->tally(ballot);
|
||||
}
|
||||
}
|
||||
|
||||
vote->mThreshold = std::max(1,
|
||||
(vote->mTrustedValidations * majorityFraction_) / 256);
|
||||
vote->mThreshold =
|
||||
std::max(1, (vote->mTrustedValidations * majorityFraction_) / 256);
|
||||
|
||||
JLOG (j_.debug()) <<
|
||||
"Received " << vote->mTrustedValidations <<
|
||||
" trusted validations, threshold is: " << vote->mThreshold;
|
||||
JLOG(j_.debug()) << "Received " << vote->mTrustedValidations
|
||||
<< " trusted validations, threshold is: "
|
||||
<< vote->mThreshold;
|
||||
|
||||
// Map of amendments to the action to be taken for each one. The action is
|
||||
// the value of the flags in the pseudo-transaction
|
||||
std::map <uint256, std::uint32_t> actions;
|
||||
std::map<uint256, std::uint32_t> actions;
|
||||
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
|
||||
// process all amendments we know of
|
||||
for (auto const& entry : amendmentMap_)
|
||||
@@ -494,43 +500,41 @@ AmendmentTableImpl::doVoting (
|
||||
NetClock::time_point majorityTime = {};
|
||||
|
||||
bool const hasValMajority =
|
||||
(vote->votes (entry.first) >= vote->mThreshold);
|
||||
(vote->votes(entry.first) >= vote->mThreshold);
|
||||
|
||||
{
|
||||
auto const it = majorityAmendments.find (entry.first);
|
||||
if (it != majorityAmendments.end ())
|
||||
auto const it = majorityAmendments.find(entry.first);
|
||||
if (it != majorityAmendments.end())
|
||||
majorityTime = it->second;
|
||||
}
|
||||
|
||||
if (enabledAmendments.count (entry.first) != 0)
|
||||
if (enabledAmendments.count(entry.first) != 0)
|
||||
{
|
||||
JLOG (j_.debug()) <<
|
||||
entry.first << ": amendment already enabled";
|
||||
JLOG(j_.debug())
|
||||
<< entry.first << ": amendment already enabled";
|
||||
}
|
||||
else if (hasValMajority &&
|
||||
(majorityTime == NetClock::time_point{}) &&
|
||||
! entry.second.vetoed)
|
||||
else if (
|
||||
hasValMajority && (majorityTime == NetClock::time_point{}) &&
|
||||
!entry.second.vetoed)
|
||||
{
|
||||
// Ledger says no majority, validators say yes
|
||||
JLOG (j_.debug()) <<
|
||||
entry.first << ": amendment got majority";
|
||||
JLOG(j_.debug()) << entry.first << ": amendment got majority";
|
||||
actions[entry.first] = tfGotMajority;
|
||||
}
|
||||
else if (! hasValMajority &&
|
||||
(majorityTime != NetClock::time_point{}))
|
||||
else if (
|
||||
!hasValMajority && (majorityTime != NetClock::time_point{}))
|
||||
{
|
||||
// Ledger says majority, validators say no
|
||||
JLOG (j_.debug()) <<
|
||||
entry.first << ": amendment lost majority";
|
||||
JLOG(j_.debug()) << entry.first << ": amendment lost majority";
|
||||
actions[entry.first] = tfLostMajority;
|
||||
}
|
||||
else if ((majorityTime != NetClock::time_point{}) &&
|
||||
else if (
|
||||
(majorityTime != NetClock::time_point{}) &&
|
||||
((majorityTime + majorityTime_) <= closeTime) &&
|
||||
! entry.second.vetoed)
|
||||
!entry.second.vetoed)
|
||||
{
|
||||
// Ledger says majority held
|
||||
JLOG (j_.debug()) <<
|
||||
entry.first << ": amendment majority held";
|
||||
JLOG(j_.debug()) << entry.first << ": amendment majority held";
|
||||
actions[entry.first] = 0;
|
||||
}
|
||||
}
|
||||
@@ -543,9 +547,9 @@ AmendmentTableImpl::doVoting (
|
||||
}
|
||||
|
||||
bool
|
||||
AmendmentTableImpl::needValidatedLedger (LedgerIndex ledgerSeq)
|
||||
AmendmentTableImpl::needValidatedLedger(LedgerIndex ledgerSeq)
|
||||
{
|
||||
std::lock_guard sl (mutex_);
|
||||
std::lock_guard sl(mutex_);
|
||||
|
||||
// Is there a ledger in which an amendment could have been enabled
|
||||
// between these two ledger sequences?
|
||||
@@ -567,7 +571,7 @@ AmendmentTableImpl::doValidatedLedger(
|
||||
// it's currently set. If it's not set when the loop is done, then any
|
||||
// prior unknown amendments have lost majority.
|
||||
firstUnsupportedExpected_.reset();
|
||||
for (auto const& [ hash, time ] : majority)
|
||||
for (auto const& [hash, time] : majority)
|
||||
{
|
||||
auto s = add(hash);
|
||||
|
||||
@@ -577,7 +581,7 @@ AmendmentTableImpl::doValidatedLedger(
|
||||
if (!s->supported)
|
||||
{
|
||||
JLOG(j_.info()) << "Unsupported amendment " << hash
|
||||
<< " reached majority at " << to_string(time);
|
||||
<< " reached majority at " << to_string(time);
|
||||
if (!firstUnsupportedExpected_ || firstUnsupportedExpected_ > time)
|
||||
firstUnsupportedExpected_ = time;
|
||||
}
|
||||
@@ -587,7 +591,10 @@ AmendmentTableImpl::doValidatedLedger(
|
||||
}
|
||||
|
||||
void
|
||||
AmendmentTableImpl::setJson (Json::Value& v, const uint256& id, const AmendmentState& fs)
|
||||
AmendmentTableImpl::setJson(
|
||||
Json::Value& v,
|
||||
const uint256& id,
|
||||
const AmendmentState& fs)
|
||||
{
|
||||
if (!fs.name.empty())
|
||||
v[jss::name] = fs.name;
|
||||
@@ -600,7 +607,7 @@ AmendmentTableImpl::setJson (Json::Value& v, const uint256& id, const AmendmentS
|
||||
{
|
||||
auto const votesTotal = lastVote_->mTrustedValidations;
|
||||
auto const votesNeeded = lastVote_->mThreshold;
|
||||
auto const votesFor = lastVote_->votes (id);
|
||||
auto const votesFor = lastVote_->votes(id);
|
||||
|
||||
v[jss::count] = votesFor;
|
||||
v[jss::validations] = votesTotal;
|
||||
@@ -614,36 +621,37 @@ AmendmentTableImpl::setJson (Json::Value& v, const uint256& id, const AmendmentS
|
||||
}
|
||||
|
||||
Json::Value
|
||||
AmendmentTableImpl::getJson (int)
|
||||
AmendmentTableImpl::getJson(int)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
{
|
||||
std::lock_guard sl(mutex_);
|
||||
for (auto const& e : amendmentMap_)
|
||||
{
|
||||
setJson (ret[to_string (e.first)] = Json::objectValue,
|
||||
e.first, e.second);
|
||||
setJson(
|
||||
ret[to_string(e.first)] = Json::objectValue, e.first, e.second);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
AmendmentTableImpl::getJson (uint256 const& amendmentID)
|
||||
AmendmentTableImpl::getJson(uint256 const& amendmentID)
|
||||
{
|
||||
Json::Value ret = Json::objectValue;
|
||||
Json::Value& jAmendment = (ret[to_string (amendmentID)] = Json::objectValue);
|
||||
Json::Value& jAmendment = (ret[to_string(amendmentID)] = Json::objectValue);
|
||||
|
||||
{
|
||||
std::lock_guard sl(mutex_);
|
||||
auto a = add (amendmentID);
|
||||
setJson (jAmendment, amendmentID, *a);
|
||||
auto a = add(amendmentID);
|
||||
setJson(jAmendment, amendmentID, *a);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<AmendmentTable> make_AmendmentTable (
|
||||
std::unique_ptr<AmendmentTable>
|
||||
make_AmendmentTable(
|
||||
std::chrono::seconds majorityTime,
|
||||
int majorityFraction,
|
||||
Section const& supported,
|
||||
@@ -651,13 +659,8 @@ std::unique_ptr<AmendmentTable> make_AmendmentTable (
|
||||
Section const& vetoed,
|
||||
beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<AmendmentTableImpl> (
|
||||
majorityTime,
|
||||
majorityFraction,
|
||||
supported,
|
||||
enabled,
|
||||
vetoed,
|
||||
journal);
|
||||
return std::make_unique<AmendmentTableImpl>(
|
||||
majorityTime, majorityFraction, supported, enabled, vetoed, journal);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/FeeUnits.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/safe_cast.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
@@ -34,9 +34,9 @@
|
||||
namespace ripple {
|
||||
|
||||
bool
|
||||
LoadFeeTrack::raiseLocalFee ()
|
||||
LoadFeeTrack::raiseLocalFee()
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
|
||||
if (++raiseCount_ < 2)
|
||||
return false;
|
||||
@@ -56,20 +56,20 @@ LoadFeeTrack::raiseLocalFee ()
|
||||
if (origFee == localTxnLoadFee_)
|
||||
return false;
|
||||
|
||||
JLOG(j_.debug()) << "Local load fee raised from " <<
|
||||
origFee << " to " << localTxnLoadFee_;
|
||||
JLOG(j_.debug()) << "Local load fee raised from " << origFee << " to "
|
||||
<< localTxnLoadFee_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
LoadFeeTrack::lowerLocalFee ()
|
||||
LoadFeeTrack::lowerLocalFee()
|
||||
{
|
||||
std::lock_guard sl (lock_);
|
||||
std::lock_guard sl(lock_);
|
||||
std::uint32_t origFee = localTxnLoadFee_;
|
||||
raiseCount_ = 0;
|
||||
|
||||
// Reduce slowly
|
||||
localTxnLoadFee_ -= (localTxnLoadFee_ / lftFeeDecFraction );
|
||||
localTxnLoadFee_ -= (localTxnLoadFee_ / lftFeeDecFraction);
|
||||
|
||||
if (localTxnLoadFee_ < lftNormalFee)
|
||||
localTxnLoadFee_ = lftNormalFee;
|
||||
@@ -77,8 +77,8 @@ LoadFeeTrack::lowerLocalFee ()
|
||||
if (origFee == localTxnLoadFee_)
|
||||
return false;
|
||||
|
||||
JLOG(j_.debug()) << "Local load fee lowered from " <<
|
||||
origFee << " to " << localTxnLoadFee_;
|
||||
JLOG(j_.debug()) << "Local load fee lowered from " << origFee << " to "
|
||||
<< localTxnLoadFee_;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,19 +86,20 @@ LoadFeeTrack::lowerLocalFee ()
|
||||
|
||||
// Scale using load as well as base rate
|
||||
XRPAmount
|
||||
scaleFeeLoad(FeeUnit64 fee, LoadFeeTrack const& feeTrack,
|
||||
Fees const& fees, bool bUnlimited)
|
||||
scaleFeeLoad(
|
||||
FeeUnit64 fee,
|
||||
LoadFeeTrack const& feeTrack,
|
||||
Fees const& fees,
|
||||
bool bUnlimited)
|
||||
{
|
||||
if (fee == 0)
|
||||
return XRPAmount{0};
|
||||
|
||||
// Normally, types with different units wouldn't be mathematically
|
||||
// compatible. This function is an exception.
|
||||
auto lowestTerms = [](auto& a, auto& b)
|
||||
{
|
||||
auto value = [](auto val)
|
||||
{
|
||||
if constexpr(std::is_arithmetic_v<decltype(val)>)
|
||||
auto lowestTerms = [](auto& a, auto& b) {
|
||||
auto value = [](auto val) {
|
||||
if constexpr (std::is_arithmetic_v<decltype(val)>)
|
||||
return val;
|
||||
else
|
||||
return val.value();
|
||||
@@ -127,8 +128,8 @@ scaleFeeLoad(FeeUnit64 fee, LoadFeeTrack const& feeTrack,
|
||||
// The denominator of the fraction we're trying to compute.
|
||||
// fees.units and lftNormalFee are both 32 bit,
|
||||
// so the multiplication can't overflow.
|
||||
auto den = FeeUnit64{ fees.units }
|
||||
* safe_cast<std::uint64_t>(feeTrack.getLoadBase());
|
||||
auto den = FeeUnit64{fees.units} *
|
||||
safe_cast<std::uint64_t>(feeTrack.getLoadBase());
|
||||
// Reduce fee * baseFee * feeFactor / (fees.units * lftNormalFee)
|
||||
// to lowest terms.
|
||||
lowestTerms(fee, den);
|
||||
@@ -159,8 +160,8 @@ scaleFeeLoad(FeeUnit64 fee, LoadFeeTrack const& feeTrack,
|
||||
|
||||
auto const result = mulDiv(fee, baseFee, den);
|
||||
if (!result.first)
|
||||
Throw<std::overflow_error> ("scaleFeeLoad");
|
||||
Throw<std::overflow_error>("scaleFeeLoad");
|
||||
return result.second;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/misc/Manifest.h>
|
||||
#include <ripple/basics/base64.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/basics/base64.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/beast/rfc2616.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/json/json_reader.h>
|
||||
@@ -34,40 +34,41 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
boost::optional<Manifest> deserializeManifest(Slice s)
|
||||
boost::optional<Manifest>
|
||||
deserializeManifest(Slice s)
|
||||
{
|
||||
if (s.empty())
|
||||
return boost::none;
|
||||
|
||||
static SOTemplate const manifestFormat {
|
||||
// A manifest must include:
|
||||
// - the master public key
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
static SOTemplate const manifestFormat{
|
||||
// A manifest must include:
|
||||
// - the master public key
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
|
||||
// - a signature with that public key
|
||||
{sfMasterSignature, soeREQUIRED},
|
||||
// - a signature with that public key
|
||||
{sfMasterSignature, soeREQUIRED},
|
||||
|
||||
// - a sequence number
|
||||
{sfSequence, soeREQUIRED},
|
||||
// - a sequence number
|
||||
{sfSequence, soeREQUIRED},
|
||||
|
||||
// It may, optionally, contain:
|
||||
// - a version number which defaults to 0
|
||||
{sfVersion, soeDEFAULT},
|
||||
// It may, optionally, contain:
|
||||
// - a version number which defaults to 0
|
||||
{sfVersion, soeDEFAULT},
|
||||
|
||||
// - a domain name
|
||||
{sfDomain, soeOPTIONAL},
|
||||
// - a domain name
|
||||
{sfDomain, soeOPTIONAL},
|
||||
|
||||
// - an ephemeral signing key that can be changed as necessary
|
||||
{sfSigningPubKey, soeOPTIONAL},
|
||||
// - an ephemeral signing key that can be changed as necessary
|
||||
{sfSigningPubKey, soeOPTIONAL},
|
||||
|
||||
// - a signature using the ephemeral signing key, if it is present
|
||||
{sfSignature, soeOPTIONAL},
|
||||
};
|
||||
// - a signature using the ephemeral signing key, if it is present
|
||||
{sfSignature, soeOPTIONAL},
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
SerialIter sit{ s };
|
||||
STObject st{ sit, sfGeneric };
|
||||
SerialIter sit{s};
|
||||
STObject st{sit, sfGeneric};
|
||||
|
||||
st.applyTemplate(manifestFormat);
|
||||
|
||||
@@ -75,15 +76,15 @@ boost::optional<Manifest> deserializeManifest(Slice s)
|
||||
if (st.isFieldPresent(sfVersion) && st.getFieldU16(sfVersion) != 0)
|
||||
return boost::none;
|
||||
|
||||
auto const pk = st.getFieldVL (sfPublicKey);
|
||||
auto const pk = st.getFieldVL(sfPublicKey);
|
||||
|
||||
if (! publicKeyType (makeSlice(pk)))
|
||||
if (!publicKeyType(makeSlice(pk)))
|
||||
return boost::none;
|
||||
|
||||
Manifest m;
|
||||
m.serialized.assign(reinterpret_cast<char const*>(s.data()), s.size());
|
||||
m.masterKey = PublicKey(makeSlice(pk));
|
||||
m.sequence = st.getFieldU32 (sfSequence);
|
||||
m.sequence = st.getFieldU32(sfSequence);
|
||||
|
||||
if (st.isFieldPresent(sfDomain))
|
||||
{
|
||||
@@ -93,23 +94,24 @@ boost::optional<Manifest> deserializeManifest(Slice s)
|
||||
if (boost::algorithm::clamp(d.size(), 4, 128) != d.size())
|
||||
return boost::none;
|
||||
|
||||
m.domain.assign (reinterpret_cast<char const*>(d.data()), d.size());
|
||||
m.domain.assign(reinterpret_cast<char const*>(d.data()), d.size());
|
||||
|
||||
// This regular expression should do a decent job of weeding out
|
||||
// obviously wrong domain names but it isn't perfect. It does not
|
||||
// really support IDNs. If this turns out to be an issue, a more
|
||||
// thorough regex can be used or this check can just be removed.
|
||||
static boost::regex const re(
|
||||
"^" // Beginning of line
|
||||
"(" // Beginning of a segment
|
||||
"(?!-)" // - must not begin with '-'
|
||||
"[a-zA-Z0-9-]{1,63}" // - only alphanumeric and '-'
|
||||
"(?<!-)" // - must not end with '-'
|
||||
"\\." // segment separator
|
||||
")+" // 1 or more segments
|
||||
"[A-Za-z]{2,63}" // TLD
|
||||
"$" // End of line
|
||||
, boost::regex_constants::optimize);
|
||||
"^" // Beginning of line
|
||||
"(" // Beginning of a segment
|
||||
"(?!-)" // - must not begin with '-'
|
||||
"[a-zA-Z0-9-]{1,63}" // - only alphanumeric and '-'
|
||||
"(?<!-)" // - must not end with '-'
|
||||
"\\." // segment separator
|
||||
")+" // 1 or more segments
|
||||
"[A-Za-z]{2,63}" // TLD
|
||||
"$" // End of line
|
||||
,
|
||||
boost::regex_constants::optimize);
|
||||
|
||||
if (!boost::regex_match(m.domain, re))
|
||||
return boost::none;
|
||||
@@ -140,7 +142,7 @@ boost::optional<Manifest> deserializeManifest(Slice s)
|
||||
|
||||
auto const spk = st.getFieldVL(sfSigningPubKey);
|
||||
|
||||
if (!publicKeyType (makeSlice(spk)))
|
||||
if (!publicKeyType(makeSlice(spk)))
|
||||
return boost::none;
|
||||
|
||||
m.signingKey = PublicKey(makeSlice(spk));
|
||||
@@ -154,88 +156,92 @@ boost::optional<Manifest> deserializeManifest(Slice s)
|
||||
}
|
||||
}
|
||||
|
||||
template<class Stream>
|
||||
template <class Stream>
|
||||
Stream&
|
||||
logMftAct (
|
||||
logMftAct(
|
||||
Stream& s,
|
||||
std::string const& action,
|
||||
PublicKey const& pk,
|
||||
std::uint32_t seq)
|
||||
{
|
||||
s << "Manifest: " << action <<
|
||||
";Pk: " << toBase58 (TokenType::NodePublic, pk) <<
|
||||
";Seq: " << seq << ";";
|
||||
s << "Manifest: " << action
|
||||
<< ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq
|
||||
<< ";";
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Stream>
|
||||
Stream& logMftAct (
|
||||
template <class Stream>
|
||||
Stream&
|
||||
logMftAct(
|
||||
Stream& s,
|
||||
std::string const& action,
|
||||
PublicKey const& pk,
|
||||
std::uint32_t seq,
|
||||
std::uint32_t oldSeq)
|
||||
{
|
||||
s << "Manifest: " << action <<
|
||||
";Pk: " << toBase58 (TokenType::NodePublic, pk) <<
|
||||
";Seq: " << seq <<
|
||||
";OldSeq: " << oldSeq << ";";
|
||||
s << "Manifest: " << action
|
||||
<< ";Pk: " << toBase58(TokenType::NodePublic, pk) << ";Seq: " << seq
|
||||
<< ";OldSeq: " << oldSeq << ";";
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Manifest::verify () const
|
||||
bool
|
||||
Manifest::verify() const
|
||||
{
|
||||
STObject st (sfGeneric);
|
||||
SerialIter sit (serialized.data (), serialized.size ());
|
||||
st.set (sit);
|
||||
STObject st(sfGeneric);
|
||||
SerialIter sit(serialized.data(), serialized.size());
|
||||
st.set(sit);
|
||||
|
||||
// Signing key and signature are not required for
|
||||
// master key revocations
|
||||
if (! revoked () && ! ripple::verify (st, HashPrefix::manifest, signingKey))
|
||||
if (!revoked() && !ripple::verify(st, HashPrefix::manifest, signingKey))
|
||||
return false;
|
||||
|
||||
return ripple::verify (
|
||||
return ripple::verify(
|
||||
st, HashPrefix::manifest, masterKey, sfMasterSignature);
|
||||
}
|
||||
|
||||
uint256 Manifest::hash () const
|
||||
uint256
|
||||
Manifest::hash() const
|
||||
{
|
||||
STObject st (sfGeneric);
|
||||
SerialIter sit (serialized.data (), serialized.size ());
|
||||
st.set (sit);
|
||||
return st.getHash (HashPrefix::manifest);
|
||||
STObject st(sfGeneric);
|
||||
SerialIter sit(serialized.data(), serialized.size());
|
||||
st.set(sit);
|
||||
return st.getHash(HashPrefix::manifest);
|
||||
}
|
||||
|
||||
bool Manifest::revoked () const
|
||||
bool
|
||||
Manifest::revoked() const
|
||||
{
|
||||
/*
|
||||
The maximum possible sequence number means that the master key
|
||||
has been revoked.
|
||||
*/
|
||||
return sequence == std::numeric_limits<std::uint32_t>::max ();
|
||||
return sequence == std::numeric_limits<std::uint32_t>::max();
|
||||
}
|
||||
|
||||
boost::optional<Blob> Manifest::getSignature () const
|
||||
boost::optional<Blob>
|
||||
Manifest::getSignature() const
|
||||
{
|
||||
STObject st (sfGeneric);
|
||||
SerialIter sit (serialized.data (), serialized.size ());
|
||||
st.set (sit);
|
||||
STObject st(sfGeneric);
|
||||
SerialIter sit(serialized.data(), serialized.size());
|
||||
st.set(sit);
|
||||
if (!get(st, sfSignature))
|
||||
return boost::none;
|
||||
return st.getFieldVL (sfSignature);
|
||||
return st.getFieldVL(sfSignature);
|
||||
}
|
||||
|
||||
Blob Manifest::getMasterSignature () const
|
||||
Blob
|
||||
Manifest::getMasterSignature() const
|
||||
{
|
||||
STObject st (sfGeneric);
|
||||
SerialIter sit (serialized.data (), serialized.size ());
|
||||
st.set (sit);
|
||||
return st.getFieldVL (sfMasterSignature);
|
||||
STObject st(sfGeneric);
|
||||
SerialIter sit(serialized.data(), serialized.size());
|
||||
st.set(sit);
|
||||
return st.getFieldVL(sfMasterSignature);
|
||||
}
|
||||
|
||||
ValidatorToken::ValidatorToken(std::string const& m, SecretKey const& valSecret)
|
||||
: manifest(m)
|
||||
, validationSecret(valSecret)
|
||||
: manifest(m), validationSecret(valSecret)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -245,12 +251,13 @@ ValidatorToken::make_ValidatorToken(std::vector<std::string> const& tokenBlob)
|
||||
try
|
||||
{
|
||||
std::string tokenStr;
|
||||
tokenStr.reserve (
|
||||
std::accumulate (tokenBlob.cbegin(), tokenBlob.cend(), std::size_t(0),
|
||||
[] (std::size_t init, std::string const& s)
|
||||
{
|
||||
return init + s.size();
|
||||
}));
|
||||
tokenStr.reserve(std::accumulate(
|
||||
tokenBlob.cbegin(),
|
||||
tokenBlob.cend(),
|
||||
std::size_t(0),
|
||||
[](std::size_t init, std::string const& s) {
|
||||
return init + s.size();
|
||||
}));
|
||||
|
||||
for (auto const& line : tokenBlob)
|
||||
tokenStr += beast::rfc2616::trim(line);
|
||||
@@ -259,15 +266,16 @@ ValidatorToken::make_ValidatorToken(std::vector<std::string> const& tokenBlob)
|
||||
|
||||
Json::Reader r;
|
||||
Json::Value token;
|
||||
if (! r.parse (tokenStr, token))
|
||||
if (!r.parse(tokenStr, token))
|
||||
return boost::none;
|
||||
|
||||
if (token.isMember("manifest") && token["manifest"].isString() &&
|
||||
token.isMember("validation_secret_key") &&
|
||||
token["validation_secret_key"].isString())
|
||||
{
|
||||
auto const ret = strUnHex (token["validation_secret_key"].asString());
|
||||
if (! ret || ret->empty())
|
||||
auto const ret =
|
||||
strUnHex(token["validation_secret_key"].asString());
|
||||
if (!ret || ret->empty())
|
||||
return boost::none;
|
||||
|
||||
return ValidatorToken(
|
||||
@@ -286,79 +294,79 @@ ValidatorToken::make_ValidatorToken(std::vector<std::string> const& tokenBlob)
|
||||
}
|
||||
|
||||
PublicKey
|
||||
ManifestCache::getSigningKey (PublicKey const& pk) const
|
||||
ManifestCache::getSigningKey(PublicKey const& pk) const
|
||||
{
|
||||
std::lock_guard lock{read_mutex_};
|
||||
auto const iter = map_.find (pk);
|
||||
auto const iter = map_.find(pk);
|
||||
|
||||
if (iter != map_.end () && !iter->second.revoked ())
|
||||
if (iter != map_.end() && !iter->second.revoked())
|
||||
return iter->second.signingKey;
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
PublicKey
|
||||
ManifestCache::getMasterKey (PublicKey const& pk) const
|
||||
ManifestCache::getMasterKey(PublicKey const& pk) const
|
||||
{
|
||||
std::lock_guard lock{read_mutex_};
|
||||
auto const iter = signingToMasterKeys_.find (pk);
|
||||
auto const iter = signingToMasterKeys_.find(pk);
|
||||
|
||||
if (iter != signingToMasterKeys_.end ())
|
||||
if (iter != signingToMasterKeys_.end())
|
||||
return iter->second;
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
boost::optional<std::uint32_t>
|
||||
ManifestCache::getSequence (PublicKey const& pk) const
|
||||
ManifestCache::getSequence(PublicKey const& pk) const
|
||||
{
|
||||
std::lock_guard lock{read_mutex_};
|
||||
auto const iter = map_.find (pk);
|
||||
auto const iter = map_.find(pk);
|
||||
|
||||
if (iter != map_.end () && !iter->second.revoked ())
|
||||
if (iter != map_.end() && !iter->second.revoked())
|
||||
return iter->second.sequence;
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<std::string>
|
||||
ManifestCache::getDomain (PublicKey const& pk) const
|
||||
ManifestCache::getDomain(PublicKey const& pk) const
|
||||
{
|
||||
std::lock_guard lock{read_mutex_};
|
||||
auto const iter = map_.find (pk);
|
||||
auto const iter = map_.find(pk);
|
||||
|
||||
if (iter != map_.end () && !iter->second.revoked ())
|
||||
if (iter != map_.end() && !iter->second.revoked())
|
||||
return iter->second.domain;
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<std::string>
|
||||
ManifestCache::getManifest (PublicKey const& pk) const
|
||||
ManifestCache::getManifest(PublicKey const& pk) const
|
||||
{
|
||||
std::lock_guard lock{read_mutex_};
|
||||
auto const iter = map_.find (pk);
|
||||
auto const iter = map_.find(pk);
|
||||
|
||||
if (iter != map_.end () && !iter->second.revoked ())
|
||||
if (iter != map_.end() && !iter->second.revoked())
|
||||
return iter->second.serialized;
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
bool
|
||||
ManifestCache::revoked (PublicKey const& pk) const
|
||||
ManifestCache::revoked(PublicKey const& pk) const
|
||||
{
|
||||
std::lock_guard lock{read_mutex_};
|
||||
auto const iter = map_.find (pk);
|
||||
auto const iter = map_.find(pk);
|
||||
|
||||
if (iter != map_.end ())
|
||||
return iter->second.revoked ();
|
||||
if (iter != map_.end())
|
||||
return iter->second.revoked();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ManifestDisposition
|
||||
ManifestCache::applyManifest (Manifest m)
|
||||
ManifestCache::applyManifest(Manifest m)
|
||||
{
|
||||
std::lock_guard applyLock{apply_mutex_};
|
||||
|
||||
@@ -368,8 +376,7 @@ ManifestCache::applyManifest (Manifest m)
|
||||
*/
|
||||
auto const iter = map_.find(m.masterKey);
|
||||
|
||||
if (iter != map_.end() &&
|
||||
m.sequence <= iter->second.sequence)
|
||||
if (iter != map_.end() && m.sequence <= iter->second.sequence)
|
||||
{
|
||||
/*
|
||||
A manifest was received for a validator we're tracking, but
|
||||
@@ -378,11 +385,16 @@ ManifestCache::applyManifest (Manifest m)
|
||||
connects.
|
||||
*/
|
||||
if (auto stream = j_.debug())
|
||||
logMftAct(stream, "Stale", m.masterKey, m.sequence, iter->second.sequence);
|
||||
logMftAct(
|
||||
stream,
|
||||
"Stale",
|
||||
m.masterKey,
|
||||
m.sequence,
|
||||
iter->second.sequence);
|
||||
return ManifestDisposition::stale; // not a newer manifest, ignore
|
||||
}
|
||||
|
||||
if (! m.verify())
|
||||
if (!m.verify())
|
||||
{
|
||||
/*
|
||||
A manifest's signature is invalid.
|
||||
@@ -410,7 +422,7 @@ ManifestCache::applyManifest (Manifest m)
|
||||
logMftAct(stream, "Revoked", m.masterKey, m.sequence);
|
||||
}
|
||||
|
||||
if (iter == map_.end ())
|
||||
if (iter == map_.end())
|
||||
{
|
||||
/*
|
||||
This is the first received manifest for a trusted master key
|
||||
@@ -420,7 +432,7 @@ ManifestCache::applyManifest (Manifest m)
|
||||
if (auto stream = j_.info())
|
||||
logMftAct(stream, "AcceptedNew", m.masterKey, m.sequence);
|
||||
|
||||
if (! revoked)
|
||||
if (!revoked)
|
||||
signingToMasterKeys_[m.signingKey] = m.masterKey;
|
||||
|
||||
auto masterKey = m.masterKey;
|
||||
@@ -433,106 +445,104 @@ ManifestCache::applyManifest (Manifest m)
|
||||
This is expected, but should happen infrequently.
|
||||
*/
|
||||
if (auto stream = j_.info())
|
||||
logMftAct(stream, "AcceptedUpdate",
|
||||
m.masterKey, m.sequence, iter->second.sequence);
|
||||
logMftAct(
|
||||
stream,
|
||||
"AcceptedUpdate",
|
||||
m.masterKey,
|
||||
m.sequence,
|
||||
iter->second.sequence);
|
||||
|
||||
signingToMasterKeys_.erase (iter->second.signingKey);
|
||||
signingToMasterKeys_.erase(iter->second.signingKey);
|
||||
|
||||
if (! revoked)
|
||||
if (!revoked)
|
||||
signingToMasterKeys_[m.signingKey] = m.masterKey;
|
||||
|
||||
iter->second = std::move (m);
|
||||
iter->second = std::move(m);
|
||||
}
|
||||
|
||||
return ManifestDisposition::accepted;
|
||||
}
|
||||
|
||||
void
|
||||
ManifestCache::load (
|
||||
DatabaseCon& dbCon, std::string const& dbTable)
|
||||
ManifestCache::load(DatabaseCon& dbCon, std::string const& dbTable)
|
||||
{
|
||||
// Load manifests stored in database
|
||||
std::string const sql =
|
||||
"SELECT RawData FROM " + dbTable + ";";
|
||||
auto db = dbCon.checkoutDb ();
|
||||
soci::blob sociRawData (*db);
|
||||
soci::statement st =
|
||||
(db->prepare << sql,
|
||||
soci::into (sociRawData));
|
||||
st.execute ();
|
||||
while (st.fetch ())
|
||||
std::string const sql = "SELECT RawData FROM " + dbTable + ";";
|
||||
auto db = dbCon.checkoutDb();
|
||||
soci::blob sociRawData(*db);
|
||||
soci::statement st = (db->prepare << sql, soci::into(sociRawData));
|
||||
st.execute();
|
||||
while (st.fetch())
|
||||
{
|
||||
std::string serialized;
|
||||
convert (sociRawData, serialized);
|
||||
convert(sociRawData, serialized);
|
||||
if (auto mo = deserializeManifest(serialized))
|
||||
{
|
||||
if (!mo->verify())
|
||||
{
|
||||
JLOG(j_.warn())
|
||||
<< "Unverifiable manifest in db";
|
||||
JLOG(j_.warn()) << "Unverifiable manifest in db";
|
||||
continue;
|
||||
}
|
||||
|
||||
applyManifest (std::move(*mo));
|
||||
applyManifest(std::move(*mo));
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j_.warn())
|
||||
<< "Malformed manifest in database";
|
||||
JLOG(j_.warn()) << "Malformed manifest in database";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ManifestCache::load (
|
||||
DatabaseCon& dbCon, std::string const& dbTable,
|
||||
ManifestCache::load(
|
||||
DatabaseCon& dbCon,
|
||||
std::string const& dbTable,
|
||||
std::string const& configManifest,
|
||||
std::vector<std::string> const& configRevocation)
|
||||
{
|
||||
load (dbCon, dbTable);
|
||||
load(dbCon, dbTable);
|
||||
|
||||
if (! configManifest.empty())
|
||||
if (!configManifest.empty())
|
||||
{
|
||||
auto mo = deserializeManifest(base64_decode(configManifest));
|
||||
if (! mo)
|
||||
if (!mo)
|
||||
{
|
||||
JLOG (j_.error()) << "Malformed validator_token in config";
|
||||
JLOG(j_.error()) << "Malformed validator_token in config";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mo->revoked())
|
||||
{
|
||||
JLOG (j_.warn()) <<
|
||||
"Configured manifest revokes public key";
|
||||
JLOG(j_.warn()) << "Configured manifest revokes public key";
|
||||
}
|
||||
|
||||
if (applyManifest (std::move(*mo)) ==
|
||||
ManifestDisposition::invalid)
|
||||
if (applyManifest(std::move(*mo)) == ManifestDisposition::invalid)
|
||||
{
|
||||
JLOG (j_.error()) << "Manifest in config was rejected";
|
||||
JLOG(j_.error()) << "Manifest in config was rejected";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! configRevocation.empty())
|
||||
if (!configRevocation.empty())
|
||||
{
|
||||
std::string revocationStr;
|
||||
revocationStr.reserve (
|
||||
std::accumulate (configRevocation.cbegin(), configRevocation.cend(), std::size_t(0),
|
||||
[] (std::size_t init, std::string const& s)
|
||||
{
|
||||
return init + s.size();
|
||||
}));
|
||||
revocationStr.reserve(std::accumulate(
|
||||
configRevocation.cbegin(),
|
||||
configRevocation.cend(),
|
||||
std::size_t(0),
|
||||
[](std::size_t init, std::string const& s) {
|
||||
return init + s.size();
|
||||
}));
|
||||
|
||||
for (auto const& line : configRevocation)
|
||||
revocationStr += beast::rfc2616::trim(line);
|
||||
|
||||
auto mo = deserializeManifest(base64_decode(revocationStr));
|
||||
|
||||
if (! mo || ! mo->revoked() ||
|
||||
applyManifest (std::move(*mo)) == ManifestDisposition::invalid)
|
||||
if (!mo || !mo->revoked() ||
|
||||
applyManifest(std::move(*mo)) == ManifestDisposition::invalid)
|
||||
{
|
||||
JLOG (j_.error()) << "Invalid validator key revocation in config";
|
||||
JLOG(j_.error()) << "Invalid validator key revocation in config";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -540,13 +550,15 @@ ManifestCache::load (
|
||||
return true;
|
||||
}
|
||||
|
||||
void ManifestCache::save (
|
||||
DatabaseCon& dbCon, std::string const& dbTable,
|
||||
std::function <bool (PublicKey const&)> isTrusted)
|
||||
void
|
||||
ManifestCache::save(
|
||||
DatabaseCon& dbCon,
|
||||
std::string const& dbTable,
|
||||
std::function<bool(PublicKey const&)> isTrusted)
|
||||
{
|
||||
std::lock_guard lock{apply_mutex_};
|
||||
|
||||
auto db = dbCon.checkoutDb ();
|
||||
auto db = dbCon.checkoutDb();
|
||||
|
||||
soci::transaction tr(*db);
|
||||
*db << "DELETE FROM " << dbTable;
|
||||
@@ -556,11 +568,9 @@ void ManifestCache::save (
|
||||
{
|
||||
// Save all revocation manifests,
|
||||
// but only save trusted non-revocation manifests.
|
||||
if (! v.second.revoked() && ! isTrusted (v.second.masterKey))
|
||||
if (!v.second.revoked() && !isTrusted(v.second.masterKey))
|
||||
{
|
||||
|
||||
JLOG(j_.info())
|
||||
<< "Untrusted manifest in cache not saved to db";
|
||||
JLOG(j_.info()) << "Untrusted manifest in cache not saved to db";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -568,10 +578,9 @@ void ManifestCache::save (
|
||||
// Do not reuse blob because manifest ecdsa signatures vary in length
|
||||
// but blob write length is expected to be >= the last write
|
||||
soci::blob rawData(*db);
|
||||
convert (v.second.serialized, rawData);
|
||||
*db << sql,
|
||||
soci::use (rawData);
|
||||
convert(v.second.serialized, rawData);
|
||||
*db << sql, soci::use(rawData);
|
||||
}
|
||||
tr.commit ();
|
||||
}
|
||||
tr.commit();
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/HashRouter.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/safe_cast.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
@@ -32,16 +32,15 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Transaction::Transaction (std::shared_ptr<STTx const> const& stx,
|
||||
std::string& reason, Application& app)
|
||||
noexcept
|
||||
: mTransaction (stx)
|
||||
, mApp (app)
|
||||
, j_ (app.journal ("Ledger"))
|
||||
Transaction::Transaction(
|
||||
std::shared_ptr<STTx const> const& stx,
|
||||
std::string& reason,
|
||||
Application& app) noexcept
|
||||
: mTransaction(stx), mApp(app), j_(app.journal("Ledger"))
|
||||
{
|
||||
try
|
||||
{
|
||||
mTransactionID = mTransaction->getTransactionID ();
|
||||
mTransactionID = mTransaction->getTransactionID();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@@ -56,86 +55,100 @@ Transaction::Transaction (std::shared_ptr<STTx const> const& stx,
|
||||
// Misc.
|
||||
//
|
||||
|
||||
void Transaction::setStatus (TransStatus ts, std::uint32_t lseq)
|
||||
void
|
||||
Transaction::setStatus(TransStatus ts, std::uint32_t lseq)
|
||||
{
|
||||
mStatus = ts;
|
||||
mInLedger = lseq;
|
||||
mStatus = ts;
|
||||
mInLedger = lseq;
|
||||
}
|
||||
|
||||
TransStatus Transaction::sqlTransactionStatus(
|
||||
boost::optional<std::string> const& status)
|
||||
TransStatus
|
||||
Transaction::sqlTransactionStatus(boost::optional<std::string> const& status)
|
||||
{
|
||||
char const c = (status) ? (*status)[0] : safe_cast<char>(txnSqlUnknown);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case txnSqlNew: return NEW;
|
||||
case txnSqlConflict: return CONFLICTED;
|
||||
case txnSqlHeld: return HELD;
|
||||
case txnSqlValidated: return COMMITTED;
|
||||
case txnSqlIncluded: return INCLUDED;
|
||||
case txnSqlNew:
|
||||
return NEW;
|
||||
case txnSqlConflict:
|
||||
return CONFLICTED;
|
||||
case txnSqlHeld:
|
||||
return HELD;
|
||||
case txnSqlValidated:
|
||||
return COMMITTED;
|
||||
case txnSqlIncluded:
|
||||
return INCLUDED;
|
||||
}
|
||||
|
||||
assert (c == txnSqlUnknown);
|
||||
assert(c == txnSqlUnknown);
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
Transaction::pointer Transaction::transactionFromSQL (
|
||||
Transaction::pointer
|
||||
Transaction::transactionFromSQL(
|
||||
boost::optional<std::uint64_t> const& ledgerSeq,
|
||||
boost::optional<std::string> const& status,
|
||||
Blob const& rawTxn,
|
||||
Application& app)
|
||||
{
|
||||
std::uint32_t const inLedger =
|
||||
rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or (0));
|
||||
rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
|
||||
|
||||
SerialIter it (makeSlice(rawTxn));
|
||||
auto txn = std::make_shared<STTx const> (it);
|
||||
SerialIter it(makeSlice(rawTxn));
|
||||
auto txn = std::make_shared<STTx const>(it);
|
||||
std::string reason;
|
||||
auto tr = std::make_shared<Transaction> (
|
||||
txn, reason, app);
|
||||
auto tr = std::make_shared<Transaction>(txn, reason, app);
|
||||
|
||||
tr->setStatus (sqlTransactionStatus (status));
|
||||
tr->setLedger (inLedger);
|
||||
tr->setStatus(sqlTransactionStatus(status));
|
||||
tr->setLedger(inLedger);
|
||||
return tr;
|
||||
}
|
||||
|
||||
Transaction::pointer Transaction::load (uint256 const& id, Application& app, error_code_i& ec)
|
||||
Transaction::pointer
|
||||
Transaction::load(uint256 const& id, Application& app, error_code_i& ec)
|
||||
{
|
||||
return boost::get<pointer> (load (id, app, boost::none, ec));
|
||||
return boost::get<pointer>(load(id, app, boost::none, ec));
|
||||
}
|
||||
|
||||
boost::variant<Transaction::pointer, bool>
|
||||
Transaction::load (uint256 const& id, Application& app, ClosedInterval<uint32_t> const& range,
|
||||
Transaction::load(
|
||||
uint256 const& id,
|
||||
Application& app,
|
||||
ClosedInterval<uint32_t> const& range,
|
||||
error_code_i& ec)
|
||||
{
|
||||
using op = boost::optional<ClosedInterval<uint32_t>>;
|
||||
|
||||
return load (id, app, op {range}, ec);
|
||||
return load(id, app, op{range}, ec);
|
||||
}
|
||||
|
||||
boost::variant<Transaction::pointer, bool>
|
||||
Transaction::load (uint256 const& id, Application& app, boost::optional<ClosedInterval<uint32_t>> const& range,
|
||||
Transaction::load(
|
||||
uint256 const& id,
|
||||
Application& app,
|
||||
boost::optional<ClosedInterval<uint32_t>> const& range,
|
||||
error_code_i& ec)
|
||||
{
|
||||
std::string sql = "SELECT LedgerSeq,Status,RawTxn "
|
||||
"FROM Transactions WHERE TransID='";
|
||||
std::string sql =
|
||||
"SELECT LedgerSeq,Status,RawTxn "
|
||||
"FROM Transactions WHERE TransID='";
|
||||
|
||||
sql.append (to_string (id));
|
||||
sql.append ("';");
|
||||
sql.append(to_string(id));
|
||||
sql.append("';");
|
||||
|
||||
boost::optional<std::uint64_t> ledgerSeq;
|
||||
boost::optional<std::string> status;
|
||||
Blob rawTxn;
|
||||
{
|
||||
auto db = app.getTxnDB ().checkoutDb ();
|
||||
soci::blob sociRawTxnBlob (*db);
|
||||
auto db = app.getTxnDB().checkoutDb();
|
||||
soci::blob sociRawTxnBlob(*db);
|
||||
soci::indicator rti;
|
||||
|
||||
*db << sql, soci::into (ledgerSeq), soci::into (status),
|
||||
soci::into (sociRawTxnBlob, rti);
|
||||
*db << sql, soci::into(ledgerSeq), soci::into(status),
|
||||
soci::into(sociRawTxnBlob, rti);
|
||||
|
||||
auto const got_data = db->got_data ();
|
||||
auto const got_data = db->got_data();
|
||||
|
||||
if ((!got_data || rti != soci::i_ok) && !range)
|
||||
return nullptr;
|
||||
@@ -144,27 +157,23 @@ Transaction::load (uint256 const& id, Application& app, boost::optional<ClosedIn
|
||||
{
|
||||
uint64_t count = 0;
|
||||
|
||||
*db << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE LedgerSeq BETWEEN "
|
||||
<< range->first ()
|
||||
<< " AND "
|
||||
<< range->last ()
|
||||
<< ";",
|
||||
soci::into (count, rti);
|
||||
*db << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
|
||||
"LedgerSeq BETWEEN "
|
||||
<< range->first() << " AND " << range->last() << ";",
|
||||
soci::into(count, rti);
|
||||
|
||||
if (!db->got_data () || rti != soci::i_ok)
|
||||
if (!db->got_data() || rti != soci::i_ok)
|
||||
return false;
|
||||
|
||||
return count == (range->last () - range->first () + 1);
|
||||
return count == (range->last() - range->first() + 1);
|
||||
}
|
||||
|
||||
convert (sociRawTxnBlob, rawTxn);
|
||||
convert(sociRawTxnBlob, rawTxn);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Transaction::transactionFromSQL(
|
||||
ledgerSeq, status,
|
||||
rawTxn, app);
|
||||
return Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@@ -179,19 +188,19 @@ Transaction::load (uint256 const& id, Application& app, boost::optional<ClosedIn
|
||||
}
|
||||
|
||||
// options 1 to include the date of the transaction
|
||||
Json::Value Transaction::getJson (JsonOptions options, bool binary) const
|
||||
Json::Value
|
||||
Transaction::getJson(JsonOptions options, bool binary) const
|
||||
{
|
||||
Json::Value ret (mTransaction->getJson (JsonOptions::none, binary));
|
||||
Json::Value ret(mTransaction->getJson(JsonOptions::none, binary));
|
||||
|
||||
if (mInLedger)
|
||||
{
|
||||
ret[jss::inLedger] = mInLedger; // Deprecated.
|
||||
ret[jss::inLedger] = mInLedger; // Deprecated.
|
||||
ret[jss::ledger_index] = mInLedger;
|
||||
|
||||
if (options == JsonOptions::include_date)
|
||||
{
|
||||
auto ct = mApp.getLedgerMaster().
|
||||
getCloseTimeBySeq (mInLedger);
|
||||
auto ct = mApp.getLedgerMaster().getCloseTimeBySeq(mInLedger);
|
||||
if (ct)
|
||||
ret[jss::date] = ct->time_since_epoch().count();
|
||||
}
|
||||
@@ -200,4 +209,4 @@ Json::Value Transaction::getJson (JsonOptions options, bool binary) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // namespace ripple
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user