diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj
index 41e7f2c636..3d982a810c 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj
+++ b/Builds/VisualStudio2015/RippleD.vcxproj
@@ -4697,6 +4697,10 @@
True
True
+
+ True
+ True
+
True
True
diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters
index 2c9ad27fcf..d8a7c1a1ee 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters
@@ -5637,6 +5637,9 @@
test\app
+
+ test\app
+
test\app
diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/ripple/app/consensus/RCLConsensus.cpp
index 1cc1119465..bf25128cc9 100644
--- a/src/ripple/app/consensus/RCLConsensus.cpp
+++ b/src/ripple/app/consensus/RCLConsensus.cpp
@@ -205,17 +205,17 @@ RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal)
}
void
-RCLConsensus::Adaptor::share(RCLTxSet const& set)
+RCLConsensus::Adaptor::share(RCLTxSet const& txns)
{
- inboundTransactions_.giveSet(set.id(), set.map_, false);
+ inboundTransactions_.giveSet(txns.id(), txns.map_, false);
}
boost::optional
RCLConsensus::Adaptor::acquireTxSet(RCLTxSet::ID const& setId)
{
- if (auto set = inboundTransactions_.getSet(setId, true))
+ if (auto txns = inboundTransactions_.getSet(setId, true))
{
- return RCLTxSet{std::move(set)};
+ return RCLTxSet{std::move(txns)};
}
return boost::none;
}
@@ -422,11 +422,11 @@ RCLConsensus::Adaptor::doAccept(
//--------------------------------------------------------------------------
// Put transactions into a deterministic, but unpredictable, order
- CanonicalTXSet retriableTxs{result.set.id()};
+ CanonicalTXSet retriableTxs{result.txns.id()};
auto sharedLCL = buildLCL(
prevLedger,
- result.set,
+ result.txns,
consensusCloseTime,
closeTimeCorrect,
closeResolution,
@@ -449,14 +449,15 @@ RCLConsensus::Adaptor::doAccept(
if (validating_ && !consensusFail &&
app_.getValidations().canValidateSeq(sharedLCL.seq()))
{
- validate(sharedLCL, proposing);
+ validate(sharedLCL, result.txns, proposing);
JLOG(j_.info()) << "CNF Val " << newLCLHash;
}
else
JLOG(j_.info()) << "CNF buildLCL " << newLCLHash;
// See if we can accept a ledger as fully-validated
- ledgerMaster_.consensusBuilt(sharedLCL.ledger_, std::move(consensusJson));
+ ledgerMaster_.consensusBuilt(
+ sharedLCL.ledger_, result.txns.id(), std::move(consensusJson));
//-------------------------------------------------------------------------
{
@@ -636,7 +637,7 @@ RCLConsensus::Adaptor::notify(
Typically the txFilter is used to reject transactions
that already accepted in the prior ledger.
- @param set set of transactions to apply
+ @param txns set of transactions to apply
@param view ledger to apply to
@param txFilter callback, return false to reject txn
@return retriable transactions
@@ -645,13 +646,13 @@ RCLConsensus::Adaptor::notify(
CanonicalTXSet
applyTransactions(
Application& app,
- RCLTxSet const& cSet,
+ RCLTxSet const& txns,
OpenView& view,
std::function txFilter)
{
auto j = app.journal("LedgerConsensus");
- auto& set = *(cSet.map_);
+ auto& set = *(txns.map_);
CanonicalTXSet retriableTxs(set.getHash().as_uint256());
for (auto const& item : set)
@@ -731,7 +732,7 @@ applyTransactions(
RCLCxLedger
RCLConsensus::Adaptor::buildLCL(
RCLCxLedger const& previousLedger,
- RCLTxSet const& set,
+ RCLTxSet const& txns,
NetClock::time_point closeTime,
bool closeTimeCorrect,
NetClock::duration closeResolution,
@@ -746,9 +747,9 @@ RCLConsensus::Adaptor::buildLCL(
closeTimeCorrect = ((replay->closeFlags_ & sLCF_NoConsensusTime) == 0);
}
- JLOG(j_.debug()) << "Report: TxSt = " << set.id() << ", close "
+ JLOG(j_.debug()) << "Report: TxSt = " << txns.id() << ", close "
<< closeTime.time_since_epoch().count()
- << (closeTimeCorrect ? "" : "X");
+ << (closeTimeCorrect ? "" : " (incorrect)");
// Build the new last closed ledger
auto buildLCL =
@@ -765,7 +766,7 @@ RCLConsensus::Adaptor::buildLCL(
// Set up to write SHAMap changes to our database,
// perform updates, extract changes
- JLOG(j_.debug()) << "Applying consensus set transactions to the"
+ JLOG(j_.debug()) << "Applying consensus txns transactions to the"
<< " last closed ledger";
{
@@ -782,7 +783,7 @@ RCLConsensus::Adaptor::buildLCL(
{
// Normal case, we are not replaying a ledger close
retriableTxs = applyTransactions(
- app_, set, accum, [&buildLCL](uint256 const& txID) {
+ app_, txns, accum, [&buildLCL](uint256 const& txID) {
return !buildLCL->txExists(txID);
});
}
@@ -825,7 +826,9 @@ RCLConsensus::Adaptor::buildLCL(
}
void
-RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger, bool proposing)
+RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger,
+ RCLTxSet const& txns,
+ bool proposing)
{
auto validationTime = app_.timeKeeper().closeTime();
if (validationTime <= lastValidationTime_)
@@ -835,6 +838,7 @@ RCLConsensus::Adaptor::validate(RCLCxLedger const& ledger, bool proposing)
// Build validation
auto v = std::make_shared(
ledger.id(),
+ txns.id(),
validationTime,
valPublic_,
nodeID_,
diff --git a/src/ripple/app/consensus/RCLConsensus.h b/src/ripple/app/consensus/RCLConsensus.h
index db6047fa27..e4ffef0745 100644
--- a/src/ripple/app/consensus/RCLConsensus.h
+++ b/src/ripple/app/consensus/RCLConsensus.h
@@ -218,10 +218,10 @@ class RCLConsensus
/** Share the given tx set to peers.
- @param set The TxSet to share.
+ @param txns The TxSet to share.
*/
void
- share(RCLTxSet const& set);
+ share(RCLTxSet const& txns);
/** Get the ID of the previous ledger/last closed ledger(LCL) on the
network
@@ -332,7 +332,7 @@ class RCLConsensus
can be retried in the next round.
@param previousLedger Prior ledger building upon
- @param set The set of transactions to apply to the ledger
+ @param txns The set of transactions to apply to the ledger
@param closeTime The the ledger closed
@param closeTimeCorrect Whether consensus agreed on close time
@param closeResolution Resolution used to determine consensus close
@@ -345,7 +345,7 @@ class RCLConsensus
RCLCxLedger
buildLCL(
RCLCxLedger const& previousLedger,
- RCLTxSet const& set,
+ RCLTxSet const& txns,
NetClock::time_point closeTime,
bool closeTimeCorrect,
NetClock::duration closeResolution,
@@ -355,6 +355,7 @@ class RCLConsensus
/** Validate the given ledger and share with peers as necessary
@param ledger The ledger to validate
+ @param txns The consensus transaction set
@param proposing Whether we were proposing transactions while
generating this ledger. If we are not proposing,
a validation can still be sent to inform peers that
@@ -362,7 +363,7 @@ class RCLConsensus
but are still around and trying to catch up.
*/
void
- validate(RCLCxLedger const& ledger, bool proposing);
+ validate(RCLCxLedger const& ledger, RCLTxSet const& txns, bool proposing);
};
diff --git a/src/ripple/app/ledger/LedgerHistory.cpp b/src/ripple/app/ledger/LedgerHistory.cpp
index 9a7da8fcd5..28285c9d7b 100644
--- a/src/ripple/app/ledger/LedgerHistory.cpp
+++ b/src/ripple/app/ledger/LedgerHistory.cpp
@@ -312,9 +312,12 @@ leaves (SHAMap const& sm)
return v;
}
-void LedgerHistory::handleMismatch (
+void
+LedgerHistory::handleMismatch(
LedgerHash const& built,
LedgerHash const& valid,
+ boost::optional const& builtConsensusHash,
+ boost::optional const& validatedConsensusHash,
Json::Value const& consensus)
{
assert (built != valid);
@@ -357,6 +360,18 @@ void LedgerHistory::handleMismatch (
return;
}
+ if (builtConsensusHash && validatedConsensusHash)
+ {
+ if (builtConsensusHash != validatedConsensusHash)
+ JLOG(j_.error())
+ << "MISMATCH on consensus transaction set "
+ << " built: " << to_string(*builtConsensusHash)
+ << " validated: " << to_string(*validatedConsensusHash);
+ else
+ JLOG(j_.error()) << "MISMATCH with same consensus transaction set: "
+ << to_string(*builtConsensusHash);
+ }
+
// Find differences between built and valid ledgers
auto const builtTx = leaves(builtLedger->txMap());
auto const validTx = leaves(validLedger->txMap());
@@ -409,6 +424,7 @@ void LedgerHistory::handleMismatch (
void LedgerHistory::builtLedger (
std::shared_ptr const& ledger,
+ uint256 const& consensusHash,
Json::Value consensus)
{
LedgerIndex index = ledger->info().seq;
@@ -428,7 +444,12 @@ void LedgerHistory::builtLedger (
JLOG (j_.error()) << "MISMATCH: seq=" << index
<< " validated:" << entry->validated.get()
<< " then:" << hash;
- handleMismatch (hash, entry->validated.get(), consensus);
+ handleMismatch(
+ hash,
+ entry->validated.get(),
+ consensusHash,
+ entry->validatedConsensusHash,
+ consensus);
}
else
{
@@ -438,11 +459,13 @@ void LedgerHistory::builtLedger (
}
entry->built.emplace (hash);
+ entry->builtConsensusHash.emplace(consensusHash);
entry->consensus.emplace (std::move (consensus));
}
void LedgerHistory::validatedLedger (
- std::shared_ptr const& ledger)
+ std::shared_ptr const& ledger,
+ boost::optional const& consensusHash)
{
LedgerIndex index = ledger->info().seq;
LedgerHash hash = ledger->info().hash;
@@ -461,7 +484,12 @@ void LedgerHistory::validatedLedger (
JLOG (j_.error()) << "MISMATCH: seq=" << index
<< " built:" << entry->built.get()
<< " then:" << hash;
- handleMismatch (entry->built.get(), hash, entry->consensus.get());
+ handleMismatch(
+ entry->built.get(),
+ hash,
+ entry->builtConsensusHash,
+ consensusHash,
+ entry->consensus.get());
}
else
{
@@ -471,6 +499,7 @@ void LedgerHistory::validatedLedger (
}
entry->validated.emplace (hash);
+ entry->validatedConsensusHash = consensusHash;
}
/** Ensure m_ledgers_by_hash doesn't have the wrong hash for a particular index
diff --git a/src/ripple/app/ledger/LedgerHistory.h b/src/ripple/app/ledger/LedgerHistory.h
index 8c5ece0b9f..a3a3f9cfdd 100644
--- a/src/ripple/app/ledger/LedgerHistory.h
+++ b/src/ripple/app/ledger/LedgerHistory.h
@@ -51,7 +51,7 @@ public:
return m_ledgers_by_hash.getHitRate ();
}
- /** Get a ledger given its squence number */
+ /** Get a ledger given its sequence number */
std::shared_ptr
getLedgerBySeq (LedgerIndex ledgerIndex);
@@ -65,7 +65,7 @@ public:
*/
LedgerHash getLedgerHash (LedgerIndex ledgerIndex);
- /** Set the history cache's paramters
+ /** Set the history cache's parameters
@param size The target size of the cache
@param age The target age of the cache, in seconds
*/
@@ -82,11 +82,13 @@ public:
/** Report that we have locally built a particular ledger */
void builtLedger (
std::shared_ptr const&,
+ uint256 const& consensusHash,
Json::Value);
/** Report that we have validated a particular ledger */
void validatedLedger (
- std::shared_ptr const&);
+ std::shared_ptr const&,
+ boost::optional const& consensusHash);
/** Repair a hash to index mapping
@param ledgerIndex The index whose mapping is to be repaired
@@ -103,9 +105,18 @@ private:
validate a different one.
@param built The hash of the ledger we built
@param valid The hash of the ledger we deemed fully valid
+ @param builtConsensusHash The hash of the consensus transaction for the
+ ledger we built
+ @param validatedConsensusHash The hash of the validated ledger's
+ consensus transaction set
@param consensus The status of the consensus round
*/
- void handleMismatch (LedgerHash const& built, LedgerHash const& valid,
+ void
+ handleMismatch(
+ LedgerHash const& built,
+ LedgerHash const& valid,
+ boost::optional const& builtConsensusHash,
+ boost::optional const& validatedConsensusHash,
Json::Value const& consensus);
Application& app_;
@@ -120,8 +131,15 @@ private:
// For debug and logging purposes
struct cv_entry
{
+ // Hash of locally built ledger
boost::optional built;
+ // Hash of the validated ledger
boost::optional validated;
+ // Hash of locally accepted consensus transaction set
+ boost::optional builtConsensusHash;
+ // Hash of validated consensus transaction set
+ boost::optional validatedConsensusHash;
+ // Consensus metadata of built ledger
boost::optional consensus;
};
using ConsensusValidated = TaggedCache ;
diff --git a/src/ripple/app/ledger/LedgerMaster.h b/src/ripple/app/ledger/LedgerMaster.h
index 2b25886f07..55ab6c9187 100644
--- a/src/ripple/app/ledger/LedgerMaster.h
+++ b/src/ripple/app/ledger/LedgerMaster.h
@@ -199,7 +199,11 @@ public:
void checkAccept (std::shared_ptr const& ledger);
void checkAccept (uint256 const& hash, std::uint32_t seq);
- void consensusBuilt (std::shared_ptr const& ledger, Json::Value consensus);
+ void
+ consensusBuilt(
+ std::shared_ptr const& ledger,
+ uint256 const& consensusHash,
+ Json::Value consensus);
LedgerIndex getBuildingLedger ();
void setBuildingLedger (LedgerIndex index);
diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp
index 2276edf6c1..98ff1b31b9 100644
--- a/src/ripple/app/ledger/impl/LedgerMaster.cpp
+++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp
@@ -182,12 +182,19 @@ void
LedgerMaster::setValidLedger(
std::shared_ptr const& l)
{
+
std::vector times;
+ boost::optional consensusHash;
if (! standalone_)
{
- times = app_.getValidations().getTrustedValidationTimes(
- l->info().hash);
+ auto const vals = app_.getValidations().getTrustedForLedger(l->info().hash);
+ times.reserve(vals.size());
+ for(auto const& val: vals)
+ times.push_back(val->getSignTime());
+
+ if(!vals.empty())
+ consensusHash = vals.front()->getConsensusHash();
}
NetClock::time_point signTime;
@@ -216,7 +223,7 @@ LedgerMaster::setValidLedger(
app_.getOPs().updateLocalTx (*l);
app_.getSHAMapStore().onLedgerClosed (getValidatedLedger());
- mLedgerHistory.validatedLedger (l);
+ mLedgerHistory.validatedLedger (l, consensusHash);
app_.getAmendmentTable().doValidatedLedger (l);
if (!app_.getOPs().isAmendmentBlocked() &&
app_.getAmendmentTable().hasUnsupportedEnabled ())
@@ -804,7 +811,9 @@ LedgerMaster::checkAccept (
/** Report that the consensus process built a particular ledger */
void
LedgerMaster::consensusBuilt(
- std::shared_ptr const& ledger, Json::Value consensus)
+ std::shared_ptr const& ledger,
+ uint256 const& consensusHash,
+ Json::Value consensus)
{
// Because we just built a ledger, we are no longer building one
@@ -814,7 +823,7 @@ LedgerMaster::consensusBuilt(
if (standalone_)
return;
- mLedgerHistory.builtLedger (ledger, std::move (consensus));
+ mLedgerHistory.builtLedger (ledger, consensusHash, std::move (consensus));
if (ledger->info().seq <= mValidLedgerSeq)
{
diff --git a/src/ripple/consensus/Consensus.h b/src/ripple/consensus/Consensus.h
index 3ddf101ad4..621e026505 100644
--- a/src/ripple/consensus/Consensus.h
+++ b/src/ripple/consensus/Consensus.h
@@ -1167,8 +1167,8 @@ Consensus::closeLedger()
result_->roundTime.reset(clock_.now());
// Share the newly created transaction set if we haven't already
// received it from a peer
- if (acquired_.emplace(result_->set.id(), result_->set).second)
- adaptor_.share(result_->set);
+ if (acquired_.emplace(result_->txns.id(), result_->txns).second)
+ adaptor_.share(result_->txns);
if (mode_.get() == ConsensusMode::proposing)
adaptor_.propose(result_->position);
@@ -1258,7 +1258,7 @@ Consensus::updateOurPositions()
parms))
{
if (!mutableSet)
- mutableSet.emplace(result_->set);
+ mutableSet.emplace(result_->txns);
if (it.second.getOurVote())
{
@@ -1352,14 +1352,14 @@ Consensus::updateOurPositions()
result_->position.isStale(ourCutoff)))
{
// close time changed or our position is stale
- ourNewSet.emplace(result_->set);
+ ourNewSet.emplace(result_->txns);
}
if (ourNewSet)
{
auto newID = ourNewSet->id();
- result_->set = std::move(*ourNewSet);
+ result_->txns = std::move(*ourNewSet);
JLOG(j_.info()) << "Position change: CTime "
<< consensusCloseTime.time_since_epoch().count()
@@ -1369,16 +1369,16 @@ Consensus::updateOurPositions()
// Share our new transaction set and update disputes
// if we haven't already received it
- if (acquired_.emplace(newID, result_->set).second)
+ if (acquired_.emplace(newID, result_->txns).second)
{
if (!result_->position.isBowOut())
- adaptor_.share(result_->set);
+ adaptor_.share(result_->txns);
for (auto const& it : currPeerPositions_)
{
Proposal_t const& p = it.second.proposal();
if (p.position() == newID)
- updateDisputes(it.first, result_->set);
+ updateDisputes(it.first, result_->txns);
}
}
@@ -1479,13 +1479,13 @@ Consensus::createDisputes(TxSet_t const& o)
return;
// Nothing to dispute if we agree
- if (result_->set.id() == o.id())
+ if (result_->txns.id() == o.id())
return;
- JLOG(j_.debug()) << "createDisputes " << result_->set.id() << " to "
+ JLOG(j_.debug()) << "createDisputes " << result_->txns.id() << " to "
<< o.id();
- auto differences = result_->set.compare(o);
+ auto differences = result_->txns.compare(o);
int dc = 0;
@@ -1494,10 +1494,10 @@ Consensus::createDisputes(TxSet_t const& o)
++dc;
// create disputed transactions (from the ledger that has them)
assert(
- (id.second && result_->set.find(id.first) && !o.find(id.first)) ||
- (!id.second && !result_->set.find(id.first) && o.find(id.first)));
+ (id.second && result_->txns.find(id.first) && !o.find(id.first)) ||
+ (!id.second && !result_->txns.find(id.first) && o.find(id.first)));
- Tx_t tx = id.second ? *result_->set.find(id.first) : *o.find(id.first);
+ Tx_t tx = id.second ? *result_->txns.find(id.first) : *o.find(id.first);
auto txID = tx.id();
if (result_->disputes.find(txID) != result_->disputes.end())
@@ -1505,7 +1505,7 @@ Consensus::createDisputes(TxSet_t const& o)
JLOG(j_.debug()) << "Transaction " << txID << " is disputed";
- typename Result::Dispute_t dtx{tx, result_->set.exists(txID),
+ typename Result::Dispute_t dtx{tx, result_->txns.exists(txID),
std::max(prevProposers_, currPeerPositions_.size()), j_};
// Update all of the available peer's votes on the disputed transaction
diff --git a/src/ripple/consensus/ConsensusTypes.h b/src/ripple/consensus/ConsensusTypes.h
index c570b4fded..04ddb25a77 100644
--- a/src/ripple/consensus/ConsensusTypes.h
+++ b/src/ripple/consensus/ConsensusTypes.h
@@ -169,7 +169,7 @@ public:
The initial consensus proposal from each peer has that peer's view of
when the ledger closed. This object stores all those close times for
- analysis of clock drift between peerss.
+ analysis of clock drift between peers.
*/
struct ConsensusCloseTimes
{
@@ -210,13 +210,13 @@ struct ConsensusResult
using Dispute_t = DisputedTx;
ConsensusResult(TxSet_t&& s, Proposal_t&& p)
- : set{std::move(s)}, position{std::move(p)}
+ : txns{std::move(s)}, position{std::move(p)}
{
- assert(set.id() == position.position());
+ assert(txns.id() == position.position());
}
//! The set of transactions consensus agrees go in the ledger
- TxSet_t set;
+ TxSet_t txns;
//! Our proposed position on transactions/close time
Proposal_t position;
diff --git a/src/ripple/consensus/Validations.h b/src/ripple/consensus/Validations.h
index 75406e05b0..bf2dd4bdf7 100644
--- a/src/ripple/consensus/Validations.h
+++ b/src/ripple/consensus/Validations.h
@@ -918,27 +918,6 @@ public:
return res;
}
- /** Return the sign times of all trusted full validations
-
- @param ledgerID The identifier of ledger of interest
- @return Vector of times
- */
- std::vector
- getTrustedValidationTimes(ID const& ledgerID)
- {
- std::vector times;
- ScopedLock lock{mutex_};
- byLedger(
- lock,
- ledgerID,
- [&](std::size_t numValidations) { times.reserve(numValidations); },
- [&](NodeID const&, Validation const& v) {
- if (v.trusted() && v.full())
- times.emplace_back(v.signTime());
- });
- return times;
- }
-
/** Returns fees reported by trusted full validators in the given ledger
@param ledgerID The identifier of ledger of interest
diff --git a/src/ripple/protocol/STValidation.h b/src/ripple/protocol/STValidation.h
index 37382daa3b..f338e99e5a 100644
--- a/src/ripple/protocol/STValidation.h
+++ b/src/ripple/protocol/STValidation.h
@@ -88,6 +88,7 @@ public:
signed before sharing with other nodes.
@param ledgerHash The hash of the validated ledger
+ @param consensusHash The hash of the consensus transaction set
@param signTime When the validation is signed
@param publicKey The current signing public key
@param nodeID ID corresponding to node's public master key
@@ -97,6 +98,7 @@ public:
STValidation(
uint256 const& ledgerHash,
+ uint256 const& consensusHash,
NetClock::time_point signTime,
PublicKey const& publicKey,
NodeID const& nodeID,
@@ -114,9 +116,14 @@ public:
return emplace(n, buf, std::move(*this));
}
+ // Hash of the validated ledger
uint256
getLedgerHash() const;
+ // Hash of consensus transaction set used to generate ledger
+ uint256
+ getConsensusHash() const;
+
NetClock::time_point
getSignTime() const;
diff --git a/src/ripple/protocol/impl/STValidation.cpp b/src/ripple/protocol/impl/STValidation.cpp
index d1242d7edf..1a09c098f4 100644
--- a/src/ripple/protocol/impl/STValidation.cpp
+++ b/src/ripple/protocol/impl/STValidation.cpp
@@ -28,6 +28,7 @@ namespace ripple {
STValidation::STValidation(
uint256 const& ledgerHash,
+ uint256 const& consensusHash,
NetClock::time_point signTime,
PublicKey const& publicKey,
NodeID const& nodeID,
@@ -36,6 +37,7 @@ STValidation::STValidation(
{
// Does not sign
setFieldH256 (sfLedgerHash, ledgerHash);
+ setFieldH256 (sfConsensusHash, consensusHash);
setFieldU32 (sfSigningTime, signTime.time_since_epoch().count());
setFieldVL (sfSigningPubKey, publicKey.slice());
@@ -65,6 +67,11 @@ uint256 STValidation::getLedgerHash () const
return getFieldH256 (sfLedgerHash);
}
+uint256 STValidation::getConsensusHash () const
+{
+ return getFieldH256 (sfConsensusHash);
+}
+
NetClock::time_point
STValidation::getSignTime () const
{
diff --git a/src/test/app/AmendmentTable_test.cpp b/src/test/app/AmendmentTable_test.cpp
index 222f13c175..6388370443 100644
--- a/src/test/app/AmendmentTable_test.cpp
+++ b/src/test/app/AmendmentTable_test.cpp
@@ -378,8 +378,8 @@ public:
int i = 0;
for (auto const& val : validators)
{
- auto v = std::make_shared (
- uint256(), roundTime, val, calcNodeID(val), true);
+ auto v = std::make_shared(
+ uint256(), uint256(), roundTime, val, calcNodeID(val), true);
++i;
STVector256 field (sfAmendments);
diff --git a/src/test/app/LedgerHistory_test.cpp b/src/test/app/LedgerHistory_test.cpp
new file mode 100644
index 0000000000..c51d8ef97b
--- /dev/null
+++ b/src/test/app/LedgerHistory_test.cpp
@@ -0,0 +1,252 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2018 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ripple {
+namespace test {
+
+class LedgerHistory_test : public beast::unit_test::suite
+{
+public:
+ /** Log manager that searches for a specific message substring
+ */
+ class CheckMessageLogs : public Logs
+ {
+ std::string msg_;
+ bool& found_;
+
+ class CheckMessageSink : public beast::Journal::Sink
+ {
+ CheckMessageLogs& owner_;
+
+ public:
+ CheckMessageSink(
+ beast::severities::Severity threshold,
+ CheckMessageLogs& owner)
+ : beast::Journal::Sink(threshold, false), owner_(owner)
+ {
+ }
+
+ void
+ write(beast::severities::Severity level, std::string const& text)
+ override
+ {
+ if (text.find(owner_.msg_) != std::string::npos)
+ owner_.found_ = true;
+ }
+ };
+
+ public:
+ /** Constructor
+
+ @param msg The message string to search for
+ @param found The variable to set to true if the message is found
+ */
+ CheckMessageLogs(std::string msg, bool& found)
+ : Logs{beast::severities::kDebug}
+ , msg_{std::move(msg)}
+ , found_{found}
+ {
+ }
+
+ std::unique_ptr
+ makeSink(
+ std::string const& partition,
+ beast::severities::Severity threshold) override
+ {
+ return std::make_unique(threshold, *this);
+ }
+ };
+
+ /** Generate a new ledger by hand, applying a specific close time offset
+ and optionally inserting a transaction.
+
+ If prev is nullptr, then the genesis ledger is made and no offset or
+ transaction is applied.
+
+ */
+ static std::shared_ptr
+ makeLedger(
+ std::shared_ptr const& prev,
+ jtx::Env& env,
+ LedgerHistory& lh,
+ NetClock::duration closeOffset,
+ std::shared_ptr stx = {})
+ {
+ if (!prev)
+ {
+ assert(!stx);
+ return std::make_shared(
+ create_genesis,
+ env.app().config(),
+ std::vector{},
+ env.app().family());
+ }
+ auto res = std::make_shared(
+ *prev, prev->info().closeTime + closeOffset);
+
+ if (stx)
+ {
+ OpenView accum(&*res);
+ applyTransaction(
+ env.app(), accum, *stx, false, tapNO_CHECK_SIGN, env.journal);
+ accum.apply(*res);
+ }
+ res->updateSkipList();
+
+ {
+ res->stateMap().flushDirty(hotACCOUNT_NODE, res->info().seq);
+ res->txMap().flushDirty(hotTRANSACTION_NODE, res->info().seq);
+ }
+ res->unshare();
+
+ // Accept ledger
+ res->setAccepted(
+ res->info().closeTime,
+ res->info().closeTimeResolution,
+ true /* close time correct*/,
+ env.app().config());
+ lh.insert(res, false);
+ return res;
+ }
+
+ void
+ testHandleMismatch()
+ {
+ testcase("LedgerHistory mismatch");
+ using namespace jtx;
+ using namespace std::chrono;
+
+ // No mismatch
+ {
+ bool found = false;
+ Env env{*this,
+ envconfig(),
+ std::make_unique("MISMATCH ", found)};
+ LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
+ auto const genesis = makeLedger({}, env, lh, 0s);
+ uint256 const dummyTxHash{1};
+ lh.builtLedger(genesis, dummyTxHash, {});
+ lh.validatedLedger(genesis, dummyTxHash);
+
+ BEAST_EXPECT(!found);
+ }
+
+ // Close time mismatch
+ {
+ bool found = false;
+ Env env{*this,
+ envconfig(),
+ std::make_unique(
+ "MISMATCH on close time", found)};
+ LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
+ auto const genesis = makeLedger({}, env, lh, 0s);
+ auto const ledgerA = makeLedger(genesis, env, lh, 4s);
+ auto const ledgerB = makeLedger(genesis, env, lh, 40s);
+
+ uint256 const dummyTxHash{1};
+ lh.builtLedger(ledgerA, dummyTxHash, {});
+ lh.validatedLedger(ledgerB, dummyTxHash);
+
+ BEAST_EXPECT(found);
+ }
+
+ // Prior ledger mismatch
+ {
+ bool found = false;
+ Env env{*this,
+ envconfig(),
+ std::make_unique(
+ "MISMATCH on prior ledger", found)};
+ LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
+ auto const genesis = makeLedger({}, env, lh, 0s);
+ auto const ledgerA = makeLedger(genesis, env, lh, 4s);
+ auto const ledgerB = makeLedger(genesis, env, lh, 40s);
+ auto const ledgerAC = makeLedger(ledgerA, env, lh, 4s);
+ auto const ledgerBD = makeLedger(ledgerB, env, lh, 4s);
+
+ uint256 const dummyTxHash{1};
+ lh.builtLedger(ledgerAC, dummyTxHash, {});
+ lh.validatedLedger(ledgerBD, dummyTxHash);
+
+ BEAST_EXPECT(found);
+ }
+
+ // Simulate a bug in which consensus may agree on transactions, but
+ // somehow generate different ledgers
+ for (bool const txBug : {true, false})
+ {
+ std::string const msg = txBug
+ ? "MISMATCH with same consensus transaction set"
+ : "MISMATCH on consensus transaction set";
+ bool found = false;
+ Env env{*this,
+ envconfig(),
+ std::make_unique(msg, found)};
+ LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
+
+ Account alice{"A1"};
+ Account bob{"A2"};
+ env.fund(XRP(1000), alice, bob);
+ env.close();
+
+ auto const ledgerBase =
+ env.app().getLedgerMaster().getClosedLedger();
+
+ JTx txAlice = env.jt(noop(alice));
+ auto const ledgerA =
+ makeLedger(ledgerBase, env, lh, 4s, txAlice.stx);
+
+ JTx txBob = env.jt(noop(bob));
+ auto const ledgerB = makeLedger(ledgerBase, env, lh, 4s, txBob.stx);
+
+ lh.builtLedger(ledgerA, txAlice.stx->getTransactionID(), {});
+ // Simulate the bug by claiming ledgerB had the same consensus hash
+ // as ledgerA, but somehow generated different ledgers
+ lh.validatedLedger(
+ ledgerB,
+ txBug ? txAlice.stx->getTransactionID()
+ : txBob.stx->getTransactionID());
+
+ BEAST_EXPECT(found);
+ }
+ }
+
+ void
+ run()
+ {
+ testHandleMismatch();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(LedgerHistory, app, ripple);
+
+} // namespace test
+} // namespace ripple
diff --git a/src/test/app/RCLValidations_test.cpp b/src/test/app/RCLValidations_test.cpp
index ce2a38f9ae..fe5094f4bd 100644
--- a/src/test/app/RCLValidations_test.cpp
+++ b/src/test/app/RCLValidations_test.cpp
@@ -36,8 +36,8 @@ class RCLValidations_test : public beast::unit_test::suite
{
testcase("Change validation trusted status");
PublicKey key = derivePublicKey(KeyType::ed25519, randomSecretKey());
- auto v = std::make_shared(
- uint256(), NetClock::time_point(), key, calcNodeID(key), true);
+ auto v = std::make_shared(uint256(), uint256(),
+ NetClock::time_point(), key, calcNodeID(key), true);
BEAST_EXPECT(!v->isTrusted());
v->setTrusted();
diff --git a/src/test/consensus/Validations_test.cpp b/src/test/consensus/Validations_test.cpp
index 4bb7092b05..4301a3bbd4 100644
--- a/src/test/consensus/Validations_test.cpp
+++ b/src/test/consensus/Validations_test.cpp
@@ -683,12 +683,10 @@ class Validations_test : public beast::unit_test::suite
sorted(harness.vals().getTrustedForLedger(id)) ==
sorted(expectedValidations));
- std::vector expectedTimes;
std::uint32_t baseFee = 0;
std::vector expectedFees;
for (auto const& val : expectedValidations)
{
- expectedTimes.push_back(val.signTime());
expectedFees.push_back(val.loadFee().value_or(baseFee));
}
@@ -696,9 +694,6 @@ class Validations_test : public beast::unit_test::suite
sorted(harness.vals().fees(id, baseFee)) ==
sorted(expectedFees));
- BEAST_EXPECT(
- sorted(harness.vals().getTrustedValidationTimes(id)) ==
- sorted(expectedTimes));
}
};
diff --git a/src/test/csf/Peer.h b/src/test/csf/Peer.h
index 93d6e4de5d..91536d232c 100644
--- a/src/test/csf/Peer.h
+++ b/src/test/csf/Peer.h
@@ -549,7 +549,7 @@ struct Peer
const bool proposing = mode == ConsensusMode::proposing;
const bool consensusFail = result.state == ConsensusState::MovedOn;
- TxSet const acceptedTxs = injectTxs(prevLedger, result.set);
+ TxSet const acceptedTxs = injectTxs(prevLedger, result.txns);
Ledger const newLedger = oracle.accept(
prevLedger,
acceptedTxs.txs(),
diff --git a/src/test/csf/Validation.h b/src/test/csf/Validation.h
index 0935f76333..a65e67b275 100644
--- a/src/test/csf/Validation.h
+++ b/src/test/csf/Validation.h
@@ -138,6 +138,9 @@ public:
Validation const&
unwrap() const
{
+ // For the rippled implementation in which RCLValidation wraps
+ // STValidation, the csf::Validation has no more specific type it
+ // wraps, so csf::Validation unwraps to itself
return *this;
}
diff --git a/src/test/unity/app_test_unity1.cpp b/src/test/unity/app_test_unity1.cpp
index 374f88dcb9..342cfa05ee 100644
--- a/src/test/unity/app_test_unity1.cpp
+++ b/src/test/unity/app_test_unity1.cpp
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
#include