Be paranoid about ledger compatibility:

* Consider ledgers incompatible based on last valid ledger
* Test against even ledgers not acquired yet
* Don't validate an incompatible ledger
* Don't switch to an incompatible ledger
* Protect against an unreasonably small quorum
This commit is contained in:
JoelKatz
2015-07-28 15:14:51 -07:00
committed by Nik Bougalis
parent 38c6083a2f
commit 0bb570a36d
6 changed files with 183 additions and 11 deletions

View File

@@ -169,6 +169,17 @@ getCandidateLedger (LedgerIndex requested)
return (requested + 255) & (~255);
}
/** Return false if the test ledger is provably incompatible
with the valid ledger, that is, they could not possibly
both be valid. Use the first form if you have both ledgers,
use the second form if you have not acquired the valid ledger yet
*/
bool areCompatible (ReadView const& validLedger, ReadView const& testLedger,
beast::Journal::Stream& s, const char* reason);
bool areCompatible (uint256 const& validHash, LedgerIndex validIndex,
ReadView const& testLedger, beast::Journal::Stream& s, const char* reason);
//------------------------------------------------------------------------------
//
// Modifiers

View File

@@ -307,6 +307,99 @@ rippleTransferRate (ReadView const& view,
: rippleTransferRate(view, issuer);
}
bool
areCompatible (ReadView const& validLedger, ReadView const& testLedger,
beast::Journal::Stream& s, const char* reason)
{
bool ret = true;
if (validLedger.info().seq < testLedger.info().seq)
{
// valid -> ... -> test
auto hash = hashOfSeq (testLedger, validLedger.info().seq,
beast::Journal());
if (hash && (*hash != validLedger.info().hash))
{
JLOG(s) << reason << " incompatible with valid ledger";
JLOG(s) << "Hash(VSeq): " << to_string (*hash);
ret = false;
}
}
else if (validLedger.info().seq > testLedger.info().seq)
{
// test -> ... -> valid
auto hash = hashOfSeq (validLedger, testLedger.info().seq,
beast::Journal());
if (hash && (*hash != testLedger.info().hash))
{
JLOG(s) << reason << " incompatible preceding ledger";
JLOG(s) << "Hash(NSeq): " << to_string (*hash);
ret = false;
}
}
else if ((validLedger.info().seq == testLedger.info().seq) &&
(validLedger.info().hash != testLedger.info().hash))
{
// Same sequence number, different hash
JLOG(s) << reason << " incompatible ledger";
ret = false;
}
if (! ret)
{
JLOG(s) << "Val: " << validLedger.info().seq <<
" " << to_string (validLedger.info().hash);
JLOG(s) << "New: " << testLedger.info().seq <<
" " << to_string (testLedger.info().hash);
}
return ret;
}
bool areCompatible (uint256 const& validHash, LedgerIndex validIndex,
ReadView const& testLedger, beast::Journal::Stream& s, const char* reason)
{
bool ret = true;
if (testLedger.info().seq > validIndex)
{
// Ledger we are testing follows last valid ledger
auto hash = hashOfSeq (testLedger, validIndex,
beast::Journal());
if (hash && (*hash != validHash))
{
JLOG(s) << reason << " incompatible following ledger";
JLOG(s) << "Hash(VSeq): " << to_string (*hash);
ret = false;
}
}
else if ((validIndex == testLedger.info().seq) &&
(testLedger.info().hash != validHash))
{
JLOG(s) << reason << " incompatible ledger";
ret = false;
}
if (! ret)
{
JLOG(s) << "Val: " << validIndex <<
" " << to_string (validHash);
JLOG(s) << "New: " << testLedger.info().seq <<
" " << to_string (testLedger.info().hash);
}
return ret;
}
bool
dirIsEmpty (ReadView const& view,
Keylet const& k)