mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
Logic to 'rebase' a ledger to a different previous ledger.
This code does not assume the new previous ledger is valid or trusted. 1) Validate sequence numbers and basic information. 2) Create a new ledger based on the new previous ledger. 3) Compare the old previous ledger and the new previous ledger. 4) Try to include any missing, valid transactions in the current ledger. 5) Traverse the old ledger based on the old previous ledger, try to import any transactions into the new ledger.
This commit is contained in:
70
Ledger.cpp
70
Ledger.cpp
@@ -433,3 +433,73 @@ void Ledger::addJson(Json::Value& ret)
|
||||
else ledger["Closed"]=false;
|
||||
ret[boost::lexical_cast<std::string>(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<uint256, std::pair<Transaction::pointer, Transaction::pointer> > 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<uint256, std::pair<Transaction::pointer, Transaction::pointer> >::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<uint256, Transaction::pointer> 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<uint256, Transaction::pointer>::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);
|
||||
}
|
||||
|
||||
1
Ledger.h
1
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);
|
||||
|
||||
@@ -389,9 +389,6 @@ SHAMapLeafNode::pointer SHAMap::createLeaf(const SHAMapInnerNode& lowestParent,
|
||||
for(int depth=lowestParent.getDepth()+1; depth<SHAMapNode::leafDepth; depth++)
|
||||
{
|
||||
SHAMapInnerNode::pointer newNode(new SHAMapInnerNode(SHAMapNode(depth, id), mSeq));
|
||||
#ifdef DEBUG
|
||||
std::cerr << "create node " << newNode->getString() << std::endl;
|
||||
#endif
|
||||
mInnerNodeByID[*newNode]=newNode;
|
||||
}
|
||||
SHAMapLeafNode::pointer newLeaf(new SHAMapLeafNode(SHAMapNode(SHAMapNode::leafDepth, id), mSeq));
|
||||
|
||||
@@ -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<uint256, std::pair<SHAMapItem::pointer, SHAMapItem::pointer> >& inMap,
|
||||
bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::SHAMapDiff& inMap,
|
||||
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >& 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<uint256, std::pair<SHAMapItem::pointer, SHAMapItem::pointer> >::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<Transaction::pointer, Transaction::pointer>(firstTrans, secondTrans);
|
||||
}
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isHex(char j)
|
||||
|
||||
@@ -88,8 +88,7 @@ public:
|
||||
|
||||
// conversion function
|
||||
static bool convertToTransactions(uint32 ourLedgerSeq, uint32 otherLedgerSeq,
|
||||
bool checkFirstTransactions, bool checkSecondTransactions,
|
||||
const std::map<uint256, std::pair<SHAMapItem::pointer,SHAMapItem::pointer> >& inMap,
|
||||
bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::SHAMapDiff& inMap,
|
||||
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >& outMap);
|
||||
|
||||
bool operator<(const Transaction&) const;
|
||||
|
||||
Reference in New Issue
Block a user