Quick fix for the bug that was causing ledgers to diverge.

LES used an unordered map, causing the traverse of modified ledger nodes to
be in random order. This meant different nodes would thread transactions
differently, causing ledger divergence. This change switches the LES code to
use a standard map. This adds more overhead to LES search functions (because
ordered map operations like search and insert are more expensive than
unordered map opreations, so it may be worth a separate ordering step just
for calcRawMeta instead.
This commit is contained in:
JoelKatz
2012-10-12 17:01:37 -07:00
parent b2481f3c49
commit 19b518a0af
4 changed files with 22 additions and 20 deletions

View File

@@ -18,7 +18,7 @@
#define TRUST_NETWORK
// #define LC_DEBUG
#define LC_DEBUG
typedef std::pair<const uint160, LedgerProposal::pointer> u160_prop_pair;
typedef std::pair<const uint256, LCTransaction::pointer> u256_lct_pair;

View File

@@ -51,7 +51,7 @@ void LedgerEntrySet::swapWith(LedgerEntrySet& e)
// This is basically: copy-on-read.
SLE::pointer LedgerEntrySet::getEntry(const uint256& index, LedgerEntryAction& action)
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(index);
std::map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(index);
if (it == mEntries.end())
{
action = taaNONE;
@@ -98,7 +98,7 @@ SLE::pointer LedgerEntrySet::entryCache(LedgerEntryType letType, const uint256&
LedgerEntryAction LedgerEntrySet::hasEntry(const uint256& index) const
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.find(index);
std::map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.find(index);
if (it == mEntries.end())
return taaNONE;
return it->second.mAction;
@@ -106,7 +106,7 @@ LedgerEntryAction LedgerEntrySet::hasEntry(const uint256& index) const
void LedgerEntrySet::entryCache(SLE::ref sle)
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
std::map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
if (it == mEntries.end())
{
mEntries.insert(std::make_pair(sle->getIndex(), LedgerEntrySetEntry(sle, taaCACHED, mSeq)));
@@ -127,7 +127,7 @@ void LedgerEntrySet::entryCache(SLE::ref sle)
void LedgerEntrySet::entryCreate(SLE::ref sle)
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
std::map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
if (it == mEntries.end())
{
mEntries.insert(std::make_pair(sle->getIndex(), LedgerEntrySetEntry(sle, taaCREATE, mSeq)));
@@ -157,7 +157,7 @@ void LedgerEntrySet::entryCreate(SLE::ref sle)
void LedgerEntrySet::entryModify(SLE::ref sle)
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
std::map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
if (it == mEntries.end())
{
mEntries.insert(std::make_pair(sle->getIndex(), LedgerEntrySetEntry(sle, taaMODIFY, mSeq)));
@@ -192,7 +192,7 @@ void LedgerEntrySet::entryModify(SLE::ref sle)
void LedgerEntrySet::entryDelete(SLE::ref sle)
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
std::map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(sle->getIndex());
if (it == mEntries.end())
{
mEntries.insert(std::make_pair(sle->getIndex(), LedgerEntrySetEntry(sle, taaDELETE, mSeq)));
@@ -233,7 +233,7 @@ Json::Value LedgerEntrySet::getJson(int) const
Json::Value ret(Json::objectValue);
Json::Value nodes(Json::arrayValue);
for (boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.begin(),
for (std::map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.begin(),
end = mEntries.end(); it != end; ++it)
{
Json::Value entry(Json::objectValue);
@@ -269,7 +269,7 @@ Json::Value LedgerEntrySet::getJson(int) const
SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(node);
std::map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(node);
if (it != mEntries.end())
{
if (it->second.mAction == taaDELETE)
@@ -351,7 +351,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
// Entries modified only as a result of building the transaction metadata
boost::unordered_map<uint256, SLE::pointer> newMod;
for (boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.begin(),
for (std::map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.begin(),
end = mEntries.end(); it != end; ++it)
{
int nType = TMNEndOfMetadata;
@@ -410,8 +410,10 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
if (origNode->getType() == ltRIPPLE_STATE)
{
metaNode.addAccount(TMSLowID, NewcoinAddress::createAccountID(origNode->getFieldAmount(sfLowLimit).getIssuer()));
metaNode.addAccount(TMSHighID, NewcoinAddress::createAccountID(origNode->getFieldAmount(sfHighLimit).getIssuer()));
metaNode.addAccount(TMSLowID,
NewcoinAddress::createAccountID(origNode->getFieldAmount(sfLowLimit).getIssuer()));
metaNode.addAccount(TMSHighID,
NewcoinAddress::createAccountID(origNode->getFieldAmount(sfHighLimit).getIssuer()));
}
}

View File

@@ -32,11 +32,11 @@ class LedgerEntrySet
{
protected:
Ledger::pointer mLedger;
boost::unordered_map<uint256, LedgerEntrySetEntry> mEntries;
std::map<uint256, LedgerEntrySetEntry> mEntries; // cannot be unordered!
TransactionMetaSet mSet;
int mSeq;
LedgerEntrySet(Ledger::ref ledger, const boost::unordered_map<uint256, LedgerEntrySetEntry> &e,
LedgerEntrySet(Ledger::ref ledger, const std::map<uint256, LedgerEntrySetEntry> &e,
const TransactionMetaSet& s, int m) : mLedger(ledger), mEntries(e), mSet(s), mSeq(m) { ; }
SLE::pointer getForMod(const uint256& node, Ledger::ref ledger,
@@ -123,11 +123,11 @@ public:
void calcRawMeta(Serializer&);
// iterator functions
bool isEmpty() const { return mEntries.empty(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator begin() const { return mEntries.begin(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator end() const { return mEntries.end(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator begin() { return mEntries.begin(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator end() { return mEntries.end(); }
bool isEmpty() const { return mEntries.empty(); }
std::map<uint256, LedgerEntrySetEntry>::const_iterator begin() const { return mEntries.begin(); }
std::map<uint256, LedgerEntrySetEntry>::const_iterator end() const { return mEntries.end(); }
std::map<uint256, LedgerEntrySetEntry>::iterator begin() { return mEntries.begin(); }
std::map<uint256, LedgerEntrySetEntry>::iterator end() { return mEntries.end(); }
static bool intersect(const LedgerEntrySet& lesLeft, const LedgerEntrySet& lesRight);
};

View File

@@ -18,7 +18,7 @@ SETUP_LOG();
void TransactionEngine::txnWrite()
{
// Write back the account states
for (boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mNodes.begin(), end = mNodes.end();
for (std::map<uint256, LedgerEntrySetEntry>::iterator it = mNodes.begin(), end = mNodes.end();
it != end; ++it)
{
const SLE::pointer& sleEntry = it->second.mEntry;