From 4b5bc85a0d4f58e8f7a8e8732b70db7f7aeae09a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 13 Dec 2011 18:05:29 -0800 Subject: [PATCH] More work on ledger sequencing: Track whether ledger is accepted. Assert on modifications to an accepted ledger. Save accepted ledgers to DB. Load ledger by hash/index. Ledger history functions, ledger canonicalization. 'Push' ledger to history. --- Ledger.cpp | 79 +++++++++++++++++++++++++++++++++++------------ Ledger.h | 17 +++++++--- LedgerHistory.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++- LedgerHistory.h | 6 ++-- LedgerMaster.cpp | 17 ++++++++++ LedgerMaster.h | 7 +++-- 6 files changed, 169 insertions(+), 30 deletions(-) diff --git a/Ledger.cpp b/Ledger.cpp index 3535f59630..e0b2bff888 100644 --- a/Ledger.cpp +++ b/Ledger.cpp @@ -1,3 +1,10 @@ + +#include +#include + +#include + +#include "Application.h" #include "Ledger.h" #include "newcoin.pb.h" #include "PackedMessage.h" @@ -5,15 +12,10 @@ #include "Conversion.h" #include "BitcoinUtil.h" #include "Wallet.h" -#include -#include -#include - -using namespace boost; -using namespace std; Ledger::Ledger(const uint160& masterID, uint64 startAmount) : - mFeeHeld(0), mTimeStamp(0), mLedgerSeq(0), mClosed(false) + mFeeHeld(0), mTimeStamp(0), mLedgerSeq(0), + mClosed(false), mValidHash(false), mAccepted(false) { mTransactionMap=SHAMap::pointer(new SHAMap()); mAccountStateMap=SHAMap::pointer(new SHAMap()); @@ -27,16 +29,17 @@ Ledger::Ledger(const uint160& masterID, uint64 startAmount) : Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, uint64 feeHeld, uint64 timeStamp, uint32 ledgerSeq) : mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), - mFeeHeld(feeHeld), mTimeStamp(timeStamp), mLedgerSeq(ledgerSeq), mClosed(false) + mFeeHeld(feeHeld), mTimeStamp(timeStamp), mLedgerSeq(ledgerSeq), + mClosed(false), mValidHash(false), mAccepted(false) { updateHash(); } -Ledger::Ledger(Ledger &prevLedger, uint64 ts) : mTimeStamp(ts), mClosed(false), - mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap) +Ledger::Ledger(Ledger &prevLedger, uint64 ts) : mTimeStamp(ts), + mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap), + mClosed(false), mValidHash(false), mAccepted(false) { - prevLedger.updateHash(); - mParentHash=prevLedger.mHash; + mParentHash=prevLedger.getHash(); mLedgerSeq=prevLedger.mLedgerSeq+1; } @@ -45,6 +48,7 @@ void Ledger::updateHash() Serializer s(116); addRaw(s); mHash=s.getSHA512Half(); + mValidHash=true; } void Ledger::addRaw(Serializer &s) @@ -84,18 +88,21 @@ uint64 Ledger::getBalance(const uint160& accountID) bool Ledger::updateAccountState(AccountState::pointer state) { + assert(!mAccepted); SHAMapItem::pointer item(new SHAMapItem(state->getAccountID(), state->getRaw())); return mAccountStateMap->updateGiveItem(item); } bool Ledger::addAccountState(AccountState::pointer state) { + assert(!mAccepted); SHAMapItem::pointer item(new SHAMapItem(state->getAccountID(), state->getRaw())); return mAccountStateMap->addGiveItem(item); } bool Ledger::addTransaction(Transaction::pointer trans) { // low-level - just add to table + assert(!mAccepted); assert(!!trans->getID()); SHAMapItem::pointer item(new SHAMapItem(trans->getID(), trans->getSigned()->getData())); return mTransactionMap->addGiveItem(item); @@ -103,6 +110,7 @@ bool Ledger::addTransaction(Transaction::pointer trans) bool Ledger::delTransaction(const uint256& transID) { + assert(!mAccepted); return mTransactionMap->delItem(transID); } @@ -118,6 +126,7 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) Ledger::TransResult Ledger::applyTransaction(Transaction::pointer trans) { + assert(!mAccepted); boost::recursive_mutex::scoped_lock sl(mLock); if(trans->getSourceLedger()>mLedgerSeq) return TR_BADLSEQ; @@ -187,6 +196,7 @@ Ledger::TransResult Ledger::applyTransaction(Transaction::pointer trans) Ledger::TransResult Ledger::removeTransaction(Transaction::pointer trans) { // high-level - reverse application of transaction + assert(!mAccepted); boost::recursive_mutex::scoped_lock sl(mLock); if(!mTransactionMap || !mAccountStateMap) return TR_ERROR; try @@ -247,7 +257,7 @@ Ledger::pointer Ledger::closeLedger(uint64 timeStamp) return Ledger::pointer(new Ledger(*this, timeStamp)); } -bool Ledger::unitTest(void) +bool Ledger::unitTest() { LocalAccount l1(true), l2(true); assert(l1.peekPubKey()); @@ -283,6 +293,43 @@ bool Ledger::unitTest(void) } +uint256 Ledger::getHash() +{ + if(!mValidHash) updateHash(); + return(mHash); +} + +void Ledger::saveAcceptedLedger(Ledger::pointer ledger) +{ + std::string sql="INSERT INTO Ledgers " + "(LedgerHash,LedgerSeq,PrevHash,FeeHeld,ClosingTime,AccountSetHash,TransSetHash) VALUES ('"; + sql.append(ledger->getHash().GetHex()); + sql.append("','"); + sql.append(boost::lexical_cast(ledger->mLedgerSeq)); + sql.append("','"); + sql.append(ledger->mParentHash.GetHex()); + sql.append("','"); + sql.append(boost::lexical_cast(ledger->mFeeHeld)); + sql.append("','"); + sql.append(boost::lexical_cast(ledger->mTimeStamp)); + sql.append("','"); + sql.append(ledger->mAccountHash.GetHex()); + sql.append("','"); + sql.append(ledger->mTransHash.GetHex()); + sql.append("');"); + + ScopedLock sl(theApp->getDBLock()); + theApp->getDB()->executeSQL(sql.c_str()); +} + +Ledger::pointer Ledger::loadByIndex(uint32 ledgerIndex) +{ +} + +Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash) +{ +} + #if 0 Ledger::pointer Ledger::getParent() @@ -421,12 +468,6 @@ Ledger::Account* Ledger::getAccount(const uint160& address) return(NULL); } -uint256& Ledger::getHash() -{ - if(!mValidHash) hash(); - return(mHash); -} - uint256& Ledger::getSignature() { if(!mValidSig) sign(); diff --git a/Ledger.h b/Ledger.h index ba1b6fabc1..b2bd82a78d 100644 --- a/Ledger.h +++ b/Ledger.h @@ -41,7 +41,7 @@ private: uint256 mHash, mParentHash, mTransHash, mAccountHash; uint64 mFeeHeld, mTimeStamp; uint32 mLedgerSeq; - bool mClosed; + bool mClosed, mValidHash, mAccepted; SHAMap::pointer mTransactionMap, mAccountStateMap; @@ -64,13 +64,15 @@ public: Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, uint64 feeHeld, uint64 timeStamp, uint32 ledgerSeq); // used for received ledgers - void setClosed(void) { mClosed=true; } - bool isClosed(void) { return mClosed; } + void setClosed() { mClosed=true; } + void setAccepted() { mAccepted=true; } + bool isClosed() { return mClosed; } + bool isAccepted() { mAccepted=true; } // ledger signature operations void addRaw(Serializer &s); - uint256 getHash() const; + uint256 getHash(); const uint256& getParentHash() const { return mParentHash; } const uint256& getTransHash() const { return mTransHash; } const uint256& getAccountHash() const { return mAccountHash; } @@ -92,11 +94,16 @@ public: TransResult removeTransaction(Transaction::pointer trans); TransResult hasTransaction(Transaction::pointer trans); + // database functions + static void saveAcceptedLedger(Ledger::pointer); + static Ledger::pointer loadByIndex(uint32 ledgerIndex); + static Ledger::pointer loadByHash(const uint256& ledgerHash); + Ledger::pointer closeLedger(uint64 timestamp); bool isCompatible(boost::shared_ptr other); bool signLedger(std::vector &signature, const LocalHanko &hanko); - static bool unitTest(void); + static bool unitTest(); }; #endif diff --git a/LedgerHistory.cpp b/LedgerHistory.cpp index 82c8b12820..2ae5ba12c1 100644 --- a/LedgerHistory.cpp +++ b/LedgerHistory.cpp @@ -1,7 +1,78 @@ + +#include + +#include "boost/bind.hpp" + #include "LedgerHistory.h" #include "Config.h" #include "Application.h" -#include + +void LedgerHistory::addLedger(Ledger::pointer ledger) +{ + uint256 h(ledger->getHash()); + boost::recursive_mutex::scoped_lock sl(mLock); + if(!mLedgersByHash[h]) mLedgersByHash[h]=ledger; +} + +void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) +{ + assert(ledger && ledger->isAccepted()); + uint256 h(ledger->getHash()); + boost::recursive_mutex::scoped_lock sl(mLock); + if(!!mLedgersByHash[h]) return; + mLedgersByHash[h]=ledger; + mLedgersByIndex[ledger->getLedgerSeq()]=ledger; + + theApp->getIOService().post(boost::bind(&Ledger::saveAcceptedLedger, ledger)); +} + +Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index) +{ + boost::recursive_mutex::scoped_lock sl(mLock); + Ledger::pointer ret(mLedgersByIndex[index]); + if(ret) return ret; + sl.unlock(); + ret=Ledger::loadByIndex(index); + if(!ret) return ret; + + assert(ret->getLedgerSeq()==index); + uint256 h=ret->getHash(); + sl.lock(); + mLedgersByIndex[index]=ret; + mLedgersByHash[h]=ret; + return ret; +} + +Ledger::pointer LedgerHistory::getLedgerByHash(const uint256& hash) +{ + boost::recursive_mutex::scoped_lock sl(mLock); + Ledger::pointer ret(mLedgersByHash[hash]); + if(ret) return ret; + + sl.unlock(); + ret=Ledger::loadByHash(hash); + if(!ret) return ret; + + assert(ret->getHash()==hash); + sl.lock(); + mLedgersByHash[hash]=ret; + if(ret->isAccepted()) mLedgersByIndex[ret->getLedgerSeq()]=ret; + return ret; +} + +Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool save) +{ + uint256 h(ledger->getHash()); + + boost::recursive_mutex::scoped_lock sl(mLock); + Ledger::pointer ret(mLedgersByHash[h]); + if(ret) return ret; + if(!save) return ledger; + assert(ret->getHash()==h); + mLedgersByHash[h]=ledger; + if(ret->isAccepted()) mLedgersByIndex[ret->getLedgerSeq()]=ledger; + return ledger; +} #if 0 bool LedgerHistory::loadLedger(const uint256& hash) diff --git a/LedgerHistory.h b/LedgerHistory.h index 44522bec39..205a2a7bbe 100644 --- a/LedgerHistory.h +++ b/LedgerHistory.h @@ -5,12 +5,11 @@ class LedgerHistory { + boost::recursive_mutex mLock; + std::map mLedgersByIndex; std::map mLedgersByHash; - bool loadClosedLedger(uint32 index); - bool loadLedger(const uint256& hash); - public: LedgerHistory() { ; } @@ -19,6 +18,7 @@ public: Ledger::pointer getLedgerBySeq(uint32 index); Ledger::pointer getLedgerByHash(const uint256& hash); + Ledger::pointer canonicalizeLedger(Ledger::pointer, bool cache); }; #endif \ No newline at end of file diff --git a/LedgerMaster.cpp b/LedgerMaster.cpp index 67cd5557a0..85b65984c8 100644 --- a/LedgerMaster.cpp +++ b/LedgerMaster.cpp @@ -24,6 +24,23 @@ uint64 LedgerMaster::getBalance(std::string& addr) return mCurrentLedger->getBalance(humanTo160(addr)); } +bool LedgerMaster::addTransaction(Transaction::pointer transaction) +{ + return mCurrentLedger->applyTransaction(transaction)==Ledger::TR_SUCCESS; +} + +void LedgerMaster::pushLedger(Ledger::pointer newLedger) +{ + ScopedLock sl(mLock); + if(!!mFinalizingLedger) + { + mFinalizingLedger->setClosed(); + mFinalizingLedger->setAccepted(); + mLedgerHistory.addAcceptedLedger(mFinalizingLedger); + } + mFinalizingLedger=mCurrentLedger; + mCurrentLedger=newLedger; +} #if 0 diff --git a/LedgerMaster.h b/LedgerMaster.h index 395eb9432e..20fcfc40ab 100644 --- a/LedgerMaster.h +++ b/LedgerMaster.h @@ -13,6 +13,7 @@ class LedgerMaster { + boost::recursive_mutex mLock; bool mIsSynced; Ledger::pointer mCurrentLedger; @@ -32,11 +33,13 @@ public: LedgerMaster(); uint32 getCurrentLedgerIndex(); - bool IsSynced(void) { return mIsSynced; } - void SetSynced(void) { mIsSynced=true; } + bool IsSynced() { return mIsSynced; } + void SetSynced() { mIsSynced=true; } Ledger::pointer getCurrentLedger() { return mCurrentLedger; } Ledger::pointer getClosingLedger() { return mFinalizingLedger; } + + void pushLedger(Ledger::pointer newLedger); Ledger::pointer getLedgerBySeq(uint32 index) {