@@ -123,6 +123,86 @@ Ledger::pointer LedgerHistory::getLedgerByHash (uint256 const& hash)
123
123
return ret;
124
124
}
125
125
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
+
126
206
void LedgerHistory::builtLedger (Ledger::ref ledger)
127
207
{
128
208
LedgerIndex index = ledger->getLedgerSeq ();
@@ -150,7 +230,7 @@ void LedgerHistory::builtLedger (Ledger::ref ledger)
150
230
}
151
231
152
232
if (mismatch)
153
- ++mismatch_counter_ ;
233
+ handleMismatch (hash, entry-> first ) ;
154
234
155
235
entry->first = hash;
156
236
}
@@ -184,7 +264,7 @@ void LedgerHistory::validatedLedger (Ledger::ref ledger)
184
264
}
185
265
186
266
if (mismatch)
187
- ++mismatch_counter_ ;
267
+ handleMismatch (entry-> second , hash) ;
188
268
189
269
entry->second = hash;
190
270
}
0 commit comments