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.
This commit is contained in:
JoelKatz
2011-12-13 18:05:29 -08:00
parent 80a6f7e5ad
commit 4b5bc85a0d
6 changed files with 169 additions and 30 deletions

View File

@@ -1,3 +1,10 @@
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#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 <boost/foreach.hpp>
#include <iostream>
#include <fstream>
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<std::string>(ledger->mLedgerSeq));
sql.append("','");
sql.append(ledger->mParentHash.GetHex());
sql.append("','");
sql.append(boost::lexical_cast<std::string>(ledger->mFeeHeld));
sql.append("','");
sql.append(boost::lexical_cast<std::string>(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();

View File

@@ -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<Ledger> other);
bool signLedger(std::vector<unsigned char> &signature, const LocalHanko &hanko);
static bool unitTest(void);
static bool unitTest();
};
#endif

View File

@@ -1,7 +1,78 @@
#include <string>
#include "boost/bind.hpp"
#include "LedgerHistory.h"
#include "Config.h"
#include "Application.h"
#include <string>
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)

View File

@@ -5,12 +5,11 @@
class LedgerHistory
{
boost::recursive_mutex mLock;
std::map<uint32, Ledger::pointer> mLedgersByIndex;
std::map<uint256, Ledger::pointer> 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

View File

@@ -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

View File

@@ -13,6 +13,7 @@
class LedgerMaster
{
boost::recursive_mutex mLock;
bool mIsSynced;
Ledger::pointer mCurrentLedger;
@@ -32,12 +33,14 @@ 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)
{
if(mCurrentLedger && (mCurrentLedger->getLedgerSeq()==index)) return mCurrentLedger;