diff --git a/Ledger.cpp b/Ledger.cpp index f1eba373a..d09612f17 100644 --- a/Ledger.cpp +++ b/Ledger.cpp @@ -433,3 +433,73 @@ void Ledger::addJson(Json::Value& ret) else ledger["Closed"]=false; ret[boost::lexical_cast(mLedgerSeq)]=ledger; } + +Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger::pointer newPrevious, int limit) +{ + // Build a new ledger that can replace this ledger as the active ledger, + // with a different previous ledger. We assume our ledger is trusted, as is its + // previous ledger. We make no assumptions about the new previous ledger. + + int count; + + // 1) Validate sequences and make sure the specified ledger is a valid prior ledger + if(newPrevious->getLedgerSeq()!=oldPrevious->getLedgerSeq()) return Ledger::pointer(); + + // 2) Begin building a new ledger with the specified ledger as previous. + Ledger* newLedger=new Ledger(*newPrevious, mTimeStamp); + + // 3) For any transactions in our previous ledger but not in the new previous ledger, add them to the set + SHAMap::SHAMapDiff mapDifferences; + std::map > TxnDiff; + if(!newPrevious->mTransactionMap->compare(oldPrevious->mTransactionMap, mapDifferences, limit)) + return Ledger::pointer(); + if(!Transaction::convertToTransactions(oldPrevious->getLedgerSeq(), newPrevious->getLedgerSeq(), + false, true, mapDifferences, TxnDiff)) + return Ledger::pointer(); // new previous ledger contains invalid transactions + + // 4) Try to add those transactions to the new ledger. + do + { + count=0; + std::map >::iterator it=TxnDiff.begin(); + while(it!=TxnDiff.end()) + { + Transaction::pointer& tx=it->second.second; + if(!tx || newLedger->addTransaction(tx)) + { + count++; + TxnDiff.erase(++it); + } + else ++it; + } + } while(count!=0); + + // WRITEME: Handle rejected transactions left in TxnDiff + + // 5) Try to add transactions from this ledger to the new ledger. + // OPTIMIZME: This should use the transaction canonicalizer, rather than creating transactions + std::map txnMap; + for(SHAMapItem::pointer mit=peekTransactionMap()->peekFirstItem(); + !!mit; + mit=peekTransactionMap()->peekNextItem(mit->getTag())) + txnMap.insert(std::make_pair(mit->getTag(), Transaction::pointer(new Transaction(mit->peekData(), false)))); + do + { + count=0; + std::map::iterator it=txnMap.begin(); + while(it!=txnMap.end()) + { + if(newLedger->addTransaction(it->second)) + { + count++; + txnMap.erase(++it); + } + else ++it; + } + } while(count!=0); + + + // WRITEME: Handle rejected transactions left in txnMap + + return Ledger::pointer(newLedger); +} diff --git a/Ledger.h b/Ledger.h index 955fef9c9..953aafa4c 100644 --- a/Ledger.h +++ b/Ledger.h @@ -96,6 +96,7 @@ public: TransResult applyTransaction(Transaction::pointer trans); TransResult removeTransaction(Transaction::pointer trans); TransResult hasTransaction(Transaction::pointer trans); + Ledger::pointer switchPreviousLedger(Ledger::pointer oldPrevious, Ledger::pointer newPrevious, int limit); // database functions static void saveAcceptedLedger(Ledger::pointer); diff --git a/SHAMap.cpp b/SHAMap.cpp index f660b9d99..92f7b2a38 100644 --- a/SHAMap.cpp +++ b/SHAMap.cpp @@ -389,9 +389,6 @@ SHAMapLeafNode::pointer SHAMap::createLeaf(const SHAMapInnerNode& lowestParent, for(int depth=lowestParent.getDepth()+1; depthgetString() << std::endl; -#endif mInnerNodeByID[*newNode]=newNode; } SHAMapLeafNode::pointer newLeaf(new SHAMapLeafNode(SHAMapNode(SHAMapNode::leafDepth, id), mSeq)); diff --git a/Transaction.cpp b/Transaction.cpp index 44c2dd229..52c98e3d4 100644 --- a/Transaction.cpp +++ b/Transaction.cpp @@ -274,12 +274,10 @@ Transaction::pointer Transaction::findFrom(const uint160& fromID, uint32 seq) } bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedgerSeq, - bool checkFirstTransactions, bool checkSecondTransactions, - const std::map >& inMap, + bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::SHAMapDiff& inMap, std::map >& outMap) { // convert a straight SHAMap payload difference to a transaction difference table // return value: true=ledgers are valid, false=a ledger is invalid - bool ret=true; std::map >::const_iterator it; for(it=inMap.begin(); it!=inMap.end(); ++it) { @@ -294,7 +292,7 @@ bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedg if( (firstTrans->getStatus()==INVALID) || (firstTrans->getID()!=id) ) { firstTrans->setStatus(INVALID, firstLedgerSeq); - ret=false; + return false; } else firstTrans->setStatus(INCLUDED, firstLedgerSeq); } @@ -305,17 +303,17 @@ bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedg if( (secondTrans->getStatus()==INVALID) || (secondTrans->getID()!=id) ) { secondTrans->setStatus(INVALID, secondLedgerSeq); - ret=false; + return false; } else secondTrans->setStatus(INCLUDED, secondLedgerSeq); } assert(firstTrans || secondTrans); if(firstTrans && secondTrans && (firstTrans->getStatus()!=INVALID) && (secondTrans->getStatus()!=INVALID)) - ret=false; // one or the other SHAMap is structurally invalid or a miracle has happened + return false; // one or the other SHAMap is structurally invalid or a miracle has happened outMap[id]=std::pair(firstTrans, secondTrans); } - return ret; + return true; } static bool isHex(char j) diff --git a/Transaction.h b/Transaction.h index 7de515084..d11121b04 100644 --- a/Transaction.h +++ b/Transaction.h @@ -88,8 +88,7 @@ public: // conversion function static bool convertToTransactions(uint32 ourLedgerSeq, uint32 otherLedgerSeq, - bool checkFirstTransactions, bool checkSecondTransactions, - const std::map >& inMap, + bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::SHAMapDiff& inMap, std::map >& outMap); bool operator<(const Transaction&) const;