Skip to content

Commit ea61df1

Browse files
committed
Distinguish Byzantine failure from tx bug (RIPD-523)
1 parent d78f740 commit ea61df1

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

src/ripple/app/ledger/LedgerHistory.cpp

+82-2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,86 @@ Ledger::pointer LedgerHistory::getLedgerByHash (uint256 const& hash)
123123
return ret;
124124
}
125125

126+
static void addLeaf (std::vector <uint256> &vec, SHAMapItem::ref item)
127+
{
128+
vec.push_back (item->getTag ());
129+
}
130+
131+
void LedgerHistory::handleMismatch (LedgerHash const& built, LedgerHash const& valid)
132+
{
133+
assert (built != valid);
134+
++mismatch_counter_;
135+
136+
Ledger::pointer builtLedger = getLedgerByHash (built);
137+
Ledger::pointer validLedger = getLedgerByHash (valid);
138+
139+
if (builtLedger && validLedger)
140+
{
141+
assert (builtLedger->getLedgerSeq() != validLedger->getLedgerSeq());
142+
143+
// Determine the mismatch reason
144+
// Distinguish Byzantine failure from transaction processing difference
145+
146+
if (builtLedger->getParentHash() != validLedger->getParentHash())
147+
{
148+
// Disagreement over prior ledger indicates sync issue
149+
WriteLog (lsERROR, LedgerMaster) << "MISMATCH on prior ledger";
150+
}
151+
else if (builtLedger->getCloseTimeNC() != validLedger->getCloseTimeNC())
152+
{
153+
// Disagreement over close time indicates Byzantine failure
154+
WriteLog (lsERROR, LedgerMaster) << "MISMATCH on close time";
155+
}
156+
else
157+
{
158+
std::vector <uint256> builtTx, validTx;
159+
builtLedger->peekTransactionMap()->visitLeaves(
160+
std::bind (&addLeaf, std::ref (builtTx), std::placeholders::_1));
161+
validLedger->peekTransactionMap()->visitLeaves(
162+
std::bind (&addLeaf, std::ref (validTx), std::placeholders::_1));
163+
std::sort (builtTx.begin(), builtTx.end());
164+
std::sort (validTx.begin(), validTx.end());
165+
166+
if (builtTx == validTx)
167+
{
168+
// Disagreement with same prior ledger, close time, and transactions
169+
// indicates a transaction processing difference
170+
WriteLog (lsERROR, LedgerMaster) <<
171+
"MISMATCH with same " << builtTx.size() << " tx";
172+
}
173+
else
174+
{
175+
std::vector <uint256> notBuilt, notValid;
176+
std::set_difference (
177+
validTx.begin(), validTx.end(),
178+
builtTx.begin(), builtTx.end(),
179+
std::inserter (notBuilt, notBuilt.begin()));
180+
std::set_difference (
181+
builtTx.begin(), builtTx.end(),
182+
validTx.begin(), validTx.end(),
183+
std::inserter (notValid, notValid.begin()));
184+
185+
// This can be either a disagreement over the consensus
186+
// set or difference in which transactions were rejected
187+
// as invalid
188+
189+
WriteLog (lsERROR, LedgerMaster) << "MISMATCH tx differ "
190+
<< builtTx.size() << " built, " << validTx.size() << " valid";
191+
for (auto const& t : notBuilt)
192+
{
193+
WriteLog (lsERROR, LedgerMaster) << "MISMATCH built without " << t;
194+
}
195+
for (auto const& t : notValid)
196+
{
197+
WriteLog (lsERROR, LedgerMaster) << "MISMATCH valid without " << t;
198+
}
199+
}
200+
}
201+
}
202+
else
203+
WriteLog (lsERROR, LedgerMaster) << "MISMATCH cannot be analyzed";
204+
}
205+
126206
void LedgerHistory::builtLedger (Ledger::ref ledger)
127207
{
128208
LedgerIndex index = ledger->getLedgerSeq();
@@ -150,7 +230,7 @@ void LedgerHistory::builtLedger (Ledger::ref ledger)
150230
}
151231

152232
if (mismatch)
153-
++mismatch_counter_;
233+
handleMismatch (hash, entry->first);
154234

155235
entry->first = hash;
156236
}
@@ -184,7 +264,7 @@ void LedgerHistory::validatedLedger (Ledger::ref ledger)
184264
}
185265

186266
if (mismatch)
187-
++mismatch_counter_;
267+
handleMismatch (entry->second, hash);
188268

189269
entry->second = hash;
190270
}

src/ripple/app/ledger/LedgerHistory.h

+8
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ class LedgerHistory : beast::LeakChecked <LedgerHistory>
9393
bool fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash);
9494

9595
private:
96+
97+
/** Log details in the case where we build one ledger but
98+
validate a different one.
99+
@param built The hash of the ledger we built
100+
@param valid The hash of the ledger we deemed fully valid
101+
*/
102+
void handleMismatch (LedgerHash const& built, LedgerHash const& valid);
103+
96104
beast::insight::Collector::ptr collector_;
97105
beast::insight::Counter mismatch_counter_;
98106

0 commit comments

Comments
 (0)