Merge branch 'continuousClose'

Conflicts:
	src/LedgerAcquire.cpp
	src/NetworkOPs.h

Merge continuous ledger close into main branch. YAY!
This commit is contained in:
JoelKatz
2012-07-16 14:48:21 -07:00
35 changed files with 750 additions and 546 deletions

View File

@@ -129,6 +129,7 @@ void Application::run()
Log(lsINFO) << "Root master seed: " << rootSeedMaster.humanSeed();
Log(lsINFO) << "Root account: " << rootAddress.humanAccountID();
{
Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, SYSTEM_CURRENCY_START);
assert(!!firstLedger->getAccountState(rootAddress));
firstLedger->updateHash();
@@ -137,11 +138,14 @@ void Application::run()
mMasterLedger.pushLedger(firstLedger);
Ledger::pointer secondLedger = boost::make_shared<Ledger>(true, boost::ref(*firstLedger));
mMasterLedger.pushLedger(secondLedger);
secondLedger->setClosed();
secondLedger->setAccepted();
mMasterLedger.pushLedger(secondLedger, boost::make_shared<Ledger>(true, boost::ref(*secondLedger)));
assert(!!secondLedger->getAccountState(rootAddress));
// temporary
mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC());
}
mNetOps.setStateTimer(0);
mNetOps.setStateTimer();
mIOService.run(); // This blocks

View File

@@ -1,15 +0,0 @@
#ifndef __BINARYFORMATS__
#define __BINARYFORMATS__
// ledger (note: fields after the timestamp are not part of the hash)
const int BLgSize=190;
const int BLgPIndex=0, BLgLIndex=4; // ledger index
const int BLgPTotCoins=4, BLgLTotCoins=8; // total native coins
const int BLgPPrevLg=12, BLgLPrevLg=32; // previous ledger hash
const int BLgPTxT=44, BLgLTxT=32; // transaction tree hash
const int BLgPAcT=76, BLgLPAct=32; // account state hash
const int BLgPClTs=108, BLgLClTs=8; // closing timestamp
const int BLgPNlIn=116, BLgLNlIn=2;
const int BLgPSig=118, BLgLSig=72; // signature
#endif

View File

@@ -43,7 +43,10 @@ const char *LedgerDBInit[] = {
LedgerSeq BIGINT UNSIGNED, \
PrevHash CHARACTER(64), \
TotalCoins BIGINT UNSIGNED, \
ClosingTime BIGINT UNSINGED, \
ClosingTime BIGINT UNSIGNED, \
PrevClosingTime BIGINT UNSIGNED, \
CloseTimeRes BIGINT UNSIGNED, \
CloseFlags, BIGINT UNSIGNED, \
AccountSetHash CHARACTER(64), \
TransSetHash CHARACTER(64) \
);",

View File

@@ -3,25 +3,28 @@
#include "types.h"
// TXN
// TXN - Hash of transaction plus signature to give transaction ID
const uint32 sHP_TransactionID = 0x54584E00;
// STX
// STX - Hash of inner transaction to sign
const uint32 sHP_TransactionSign = 0x53545800;
// MLN
// TND - Hash of transaction plus metadata
const uint32 sHP_TransactionNode = 0x534E4400;
// MLN - Hash of account state
const uint32 sHP_LeafNode = 0x4D4C4E00;
// MIN
// MIN - Hash of inner node in tree
const uint32 sHP_InnerNode = 0x4D494E00;
// LGR
// LGR - Hash of ledger master data for signing
const uint32 sHP_Ledger = 0x4C575200;
// VAL
// VAL - Hash of validation for signing
const uint32 sHP_Validation = 0x56414C00;
// PRP
// PRP - Hash of proposal for signing
const uint32 sHP_Proposal = 0x50525000;
#endif

View File

@@ -16,14 +16,14 @@
#include "Conversion.h"
#include "BitcoinUtil.h"
#include "Wallet.h"
#include "BinaryFormats.h"
#include "LedgerTiming.h"
#include "HashPrefixes.h"
#include "Log.h"
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount),
mCloseTime(0), mLedgerSeq(0), mLedgerInterval(LEDGER_INTERVAL), mClosed(false), mValidHash(false),
mAccepted(false), mImmutable(false), mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap())
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(0),
mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap())
{
// special case: put coins in root account
AccountState::pointer startAccount = boost::make_shared<AccountState>(masterID);
@@ -37,16 +37,18 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s
}
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq)
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash),
mTotCoins(totCoins), mCloseTime(timeStamp), mLedgerSeq(ledgerSeq), mLedgerInterval(LEDGER_INTERVAL),
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq)
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), mTotCoins(totCoins),
mLedgerSeq(ledgerSeq), mCloseTime(closeTime), mParentCloseTime(parentCloseTime),
mCloseResolution(closeResolution), mCloseFlags(closeFlags),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false)
{
updateHash();
}
Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins),
mLedgerSeq(ledger.mLedgerSeq), mLedgerInterval(ledger.mLedgerInterval),
Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mLedgerSeq(ledger.mLedgerSeq),
mCloseTime(ledger.mCloseTime), mParentCloseTime(ledger.mParentCloseTime),
mCloseResolution(ledger.mCloseResolution), mCloseFlags(ledger.mCloseFlags),
mClosed(ledger.mClosed), mValidHash(false), mAccepted(ledger.mAccepted), mImmutable(!isMutable),
mTransactionMap(ledger.mTransactionMap->snapShot(isMutable)),
mAccountStateMap(ledger.mAccountStateMap->snapShot(isMutable))
@@ -55,55 +57,37 @@ Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins),
}
Ledger::Ledger(bool, Ledger& prevLedger) : mTotCoins(prevLedger.mTotCoins),
mLedgerSeq(prevLedger.mLedgerSeq + 1), mLedgerInterval(prevLedger.mLedgerInterval),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
Ledger::Ledger(bool dummy, Ledger& prevLedger) :
mTotCoins(prevLedger.mTotCoins), mLedgerSeq(prevLedger.mLedgerSeq + 1),
mParentCloseTime(prevLedger.mCloseTime), mCloseResolution(prevLedger.mCloseResolution),
mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true))
{ // Create a new ledger that follows this one
prevLedger.updateHash();
mParentHash = prevLedger.getHash();
assert(mParentHash.isNonZero());
mCloseTime = prevLedger.getNextLedgerClose();
mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution(prevLedger.mCloseResolution,
prevLedger.getCloseAgree(), mLedgerSeq);
if (prevLedger.mCloseTime == 0)
{
mCloseTime = theApp->getOPs().getNetworkTimeNC();
mCloseTime -= (mCloseTime % mCloseResolution);
}
else
mCloseTime = prevLedger.mCloseTime + mCloseResolution;
}
Ledger::Ledger(const std::vector<unsigned char>& rawLedger) : mCloseTime(0),
mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
Ledger::Ledger(const std::vector<unsigned char>& rawLedger) :
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
{
Serializer s(rawLedger);
// 32seq, 64fee, 256phash, 256thash, 256ahash, 64ts
if (!s.get32(mLedgerSeq, BLgPIndex)) return;
if (!s.get64(mTotCoins, BLgPTotCoins)) return;
if (!s.get256(mParentHash, BLgPPrevLg)) return;
if (!s.get256(mTransHash, BLgPTxT)) return;
if (!s.get256(mAccountHash, BLgPAcT)) return;
if (!s.get64(mCloseTime, BLgPClTs)) return;
if (!s.get16(mLedgerInterval, BLgPNlIn)) return;
updateHash();
if(mValidHash)
{
mTransactionMap = boost::make_shared<SHAMap>();
mAccountStateMap = boost::make_shared<SHAMap>();
}
setRaw(Serializer(rawLedger));
}
Ledger::Ledger(const std::string& rawLedger) : mCloseTime(0),
mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
Ledger::Ledger(const std::string& rawLedger) :
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
{
Serializer s(rawLedger);
// 32seq, 64fee, 256phash, 256thash, 256ahash, 64ts
if (!s.get32(mLedgerSeq, BLgPIndex)) return;
if (!s.get64(mTotCoins, BLgPTotCoins)) return;
if (!s.get256(mParentHash, BLgPPrevLg)) return;
if (!s.get256(mTransHash, BLgPTxT)) return;
if (!s.get256(mAccountHash, BLgPAcT)) return;
if (!s.get64(mCloseTime, BLgPClTs)) return;
if (!s.get16(mLedgerInterval, BLgPNlIn)) return;
updateHash();
if(mValidHash)
{
mTransactionMap = boost::make_shared<SHAMap>();
mAccountStateMap = boost::make_shared<SHAMap>();
}
setRaw(Serializer(rawLedger));
}
void Ledger::updateHash()
@@ -116,22 +100,64 @@ void Ledger::updateHash()
else mAccountHash.zero();
}
Serializer s(116);
Serializer s(118);
s.add32(sHP_Ledger);
addRaw(s);
mHash = s.getSHA512Half();
mValidHash = true;
}
void Ledger::addRaw(Serializer &s)
void Ledger::setRaw(const Serializer &s)
{
SerializerIterator sit(s);
mLedgerSeq = sit.get32();
mTotCoins = sit.get64();
mParentHash = sit.get256();
mTransHash = sit.get256();
mAccountHash = sit.get256();
mParentCloseTime = sit.get32();
mCloseTime = sit.get32();
mCloseResolution = sit.get8();
mCloseFlags = sit.get8();
updateHash();
if(mValidHash)
{
mTransactionMap = boost::make_shared<SHAMap>(mTransHash);
mAccountStateMap = boost::make_shared<SHAMap>(mAccountHash);
}
}
void Ledger::addRaw(Serializer &s) const
{
s.add32(mLedgerSeq);
s.add64(mTotCoins);
s.add256(mParentHash);
s.add256(mTransHash);
s.add256(mAccountHash);
s.add64(mCloseTime);
s.add16(mLedgerInterval);
s.add32(mParentCloseTime);
s.add32(mCloseTime);
s.add8(mCloseResolution);
s.add8(mCloseFlags);
}
void Ledger::setAccepted(uint32 closeTime, int closeResolution, bool correctCloseTime)
{ // used when we witnessed the consensus
assert(mClosed && !mAccepted);
mCloseTime = closeTime - (closeTime % closeResolution);
mCloseResolution = closeResolution;
mCloseFlags = correctCloseTime ? 0 : sLCF_NoConsensusTime;
updateHash();
mAccepted = true;
mImmutable = true;
}
void Ledger::setAccepted()
{ // used when we acquired the ledger
assert(mClosed && (mCloseResolution != 0) && (mCloseResolution != 0));
mCloseTime -= mCloseTime % mCloseResolution;
updateHash();
mAccepted = true;
mImmutable = true;
}
AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
@@ -191,14 +217,16 @@ bool Ledger::addTransaction(Transaction::pointer trans)
Serializer s;
trans->getSTransaction()->add(s);
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(trans->getID(), s.peekData());
if (!mTransactionMap->addGiveItem(item, true)) return false;
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
return false;
return true;
}
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn)
{ // low-level - just add to table
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, txn.peekData());
if (!mTransactionMap->addGiveItem(item, true)) return false;
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
return false;
return true;
}
@@ -241,28 +269,18 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransId = '%s';");
static boost::format transExists("SELECT Status FROM Transactions WHERE TransID = '%s';");
static boost::format updateTx("UPDATE Transactions SET LedgerSeq = %d, Status = '%c' WHERE TransID = '%s';");
std::string sql="INSERT INTO Ledgers "
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,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->mTotCoins));
sql.append("','");
sql.append(boost::lexical_cast<std::string>(ledger->mCloseTime));
sql.append("','");
sql.append(ledger->mAccountHash.GetHex());
sql.append("','");
sql.append(ledger->mTransHash.GetHex());
sql.append("');");
static boost::format addLedger("INSERT INTO Ledgers "
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,"
"AccountSetHash,TransSetHash) VALUES ('%s','%u','%s','%s','%u','%u','%d','%u','%s','%s');");
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
if (SQL_EXISTS(theApp->getLedgerDB()->getDB(), boost::str(ledgerExists % ledger->mLedgerSeq)))
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(deleteLedger % ledger->mLedgerSeq));
theApp->getLedgerDB()->getDB()->executeSQL(sql);
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(addLedger %
ledger->getHash().GetHex() % ledger->mLedgerSeq % ledger->mParentHash.GetHex() %
boost::lexical_cast<std::string>(ledger->mTotCoins) % ledger->mCloseTime % ledger->mParentCloseTime %
ledger->mCloseResolution % ledger->mCloseFlags %
ledger->mAccountHash.GetHex() % ledger->mTransHash.GetHex()));
// write out dirty nodes
while(ledger->mTransactionMap->flushDirty(256, TRANSACTION_NODE, ledger->mLedgerSeq))
@@ -331,8 +349,10 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
Ledger::pointer Ledger::getSQL(const std::string& sql)
{
uint256 ledgerHash, prevHash, accountHash, transHash;
uint64 totCoins, closingTime;
uint32 ledgerSeq;
uint64 totCoins;
uint32 closingTime, prevClosingTime, ledgerSeq;
int closeResolution;
unsigned closeFlags;
std::string hash;
{
@@ -352,12 +372,16 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
transHash.SetHex(hash);
totCoins = db->getBigInt("TotalCoins");
closingTime = db->getBigInt("ClosingTime");
prevClosingTime = db->getBigInt("PrevClosingTime");
closeResolution = db->getBigInt("CloseTimeRes");
closeFlags = db->getBigInt("CloseFlags");
ledgerSeq = db->getBigInt("LedgerSeq");
db->endIterRows();
}
Ledger::pointer ret =
boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, ledgerSeq);
boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, prevClosingTime,
closeFlags, closeResolution, ledgerSeq);
if (ret->getHash() != ledgerHash)
{
Json::StyledStreamWriter ssw;
@@ -400,9 +424,16 @@ void Ledger::addJson(Json::Value& ret, int options)
ledger["hash"] = mHash.GetHex();
ledger["transactionHash"] = mTransHash.GetHex();
ledger["accountHash"] = mAccountHash.GetHex();
ledger["closed"] = true;
if (mClosed) ledger["closed"] = true;
ledger["accepted"] = mAccepted;
ledger["totalCoins"] = boost::lexical_cast<std::string>(mTotCoins);
if ((mCloseFlags & sLCF_NoConsensusTime) != 0)
ledger["closeTimeEstimate"] = mCloseTime;
else
{
ledger["closeTime"] = mCloseTime;
ledger["closeTimeResolution"] = mCloseResolution;
}
}
else ledger["closed"] = false;
if (mCloseTime != 0)
@@ -473,23 +504,8 @@ boost::posix_time::ptime Ledger::getCloseTime() const
void Ledger::setCloseTime(boost::posix_time::ptime ptm)
{
assert(!mImmutable);
mCloseTime = iToSeconds(ptm);
}
uint64 Ledger::sGenesisClose = 0;
uint64 Ledger::getNextLedgerClose() const
{
if (mCloseTime == 0)
{
if (sGenesisClose == 0)
{
uint64 closeTime = theApp->getOPs().getNetworkTimeNC() + mLedgerInterval - 1;
sGenesisClose = closeTime - (closeTime % mLedgerInterval);
}
return sGenesisClose;
}
return mCloseTime + mLedgerInterval;
}
// vim:ts=4

View File

@@ -58,16 +58,18 @@ public:
TR_TOOSMALL = 9, // amount is less than Tx fee
};
// ledger close flags
static const uint32 sLCF_NoConsensusTime = 1;
private:
static uint64 sGenesisClose;
uint256 mHash, mParentHash, mTransHash, mAccountHash;
uint64 mTotCoins;
uint64 mCloseTime; // when this ledger closes
uint64 mParentCloseTime;
uint32 mLedgerSeq;
uint16 mLedgerInterval;
uint32 mCloseTime; // when this ledger closed
uint32 mParentCloseTime; // when the previous ledger closed
int mCloseResolution; // the resolution for this ledger close time (2-120 seconds)
uint32 mCloseFlags; // flags indicating how this ledger close took place
bool mClosed, mValidHash, mAccepted, mImmutable;
SHAMap::pointer mTransactionMap, mAccountStateMap;
@@ -84,21 +86,27 @@ protected:
static Ledger::pointer getSQL(const std::string& sqlStatement);
SLE::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID,
LedgerEntryType let);
SLE::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID, LedgerEntryType let);
public:
Ledger(const NewcoinAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger
Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq); // used for database ledgers
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution,
uint32 ledgerSeq); // used for database ledgers
Ledger(const std::vector<unsigned char>& rawLedger);
Ledger(const std::string& rawLedger);
Ledger(bool fromAccepted, Ledger& previous); // ledger after this one
Ledger(bool dummy, Ledger& previous); // ledger after this one
Ledger(Ledger& target, bool isMutable); // snapshot
void updateHash();
void setClosed() { mClosed = true; }
void setAccepted() { mAccepted = true; }
void setAccepted(uint32 closeTime, int closeResolution, bool correctCloseTime);
void setAccepted();
void setImmutable() { updateHash(); mImmutable = true; }
bool isClosed() { return mClosed; }
bool isAccepted() { return mAccepted; }
@@ -111,7 +119,8 @@ public:
void bumpSeq() { mClosed = true; mLedgerSeq++; }
// ledger signature operations
void addRaw(Serializer &s);
void addRaw(Serializer &s) const;
void setRaw(const Serializer& s);
uint256 getHash();
const uint256& getParentHash() const { return mParentHash; }
@@ -119,15 +128,16 @@ public:
const uint256& getAccountHash() const { return mAccountHash; }
uint64 getTotalCoins() const { return mTotCoins; }
void destroyCoins(uint64 fee) { mTotCoins -= fee; }
uint64 getCloseTimeNC() const { return mCloseTime; }
uint64 getParentCloseTimeNC() const { return mParentCloseTime; }
uint32 getCloseTimeNC() const { return mCloseTime; }
uint32 getParentCloseTimeNC() const { return mParentCloseTime; }
uint32 getLedgerSeq() const { return mLedgerSeq; }
uint16 getInterval() const { return mLedgerInterval; }
int getCloseResolution() const { return mCloseResolution; }
bool getCloseAgree() const { return (mCloseFlags & sLCF_NoConsensusTime) == 0; }
// close time functions
boost::posix_time::ptime getCloseTime() const;
void setCloseTime(uint32 ct) { assert(!mImmutable); mCloseTime = ct; }
void setCloseTime(boost::posix_time::ptime);
uint64 getNextLedgerClose() const;
boost::posix_time::ptime getCloseTime() const;
// low level functions
SHAMap::pointer peekTransactionMap() { return mTransactionMap; }

View File

@@ -12,6 +12,7 @@
#define LA_DEBUG
#define LEDGER_ACQUIRE_TIMEOUT 2
#define TRUST_NETWORK
PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0),
mComplete(false), mFailed(false), mProgress(true), mTimer(theApp->getIOService())
@@ -28,7 +29,8 @@ void PeerSet::peerHas(Peer::pointer ptr)
it = mPeers.erase(it);
else
{
if (pr->samePeer(ptr)) return; // we already have this peer
if (pr->samePeer(ptr))
return; // we already have this peer
++it;
}
}
@@ -77,14 +79,16 @@ void PeerSet::invokeOnTimer()
void PeerSet::TimerEntry(boost::weak_ptr<PeerSet> wptr, const boost::system::error_code& result)
{
if (result == boost::asio::error::operation_aborted) return;
if (result == boost::asio::error::operation_aborted)
return;
boost::shared_ptr<PeerSet> ptr = wptr.lock();
if (!ptr) return;
if (!ptr)
return;
ptr->invokeOnTimer();
}
LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT),
mHaveBase(false), mHaveState(false), mHaveTransactions(false)
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false)
{
#ifdef LA_DEBUG
Log(lsTRACE) << "Acquiring ledger " << mHash.GetHex();
@@ -109,7 +113,9 @@ void LedgerAcquire::done()
mOnComplete.empty();
mLock.unlock();
for (unsigned int i = 0; i < triggers.size(); ++i)
theApp->getMasterLedger().storeLedger(mLedger);
for (int i = 0; i < triggers.size(); ++i)
triggers[i](shared_from_this());
}
@@ -122,6 +128,8 @@ void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)>
void LedgerAcquire::trigger(Peer::pointer peer)
{
if (mAborted)
return;
#ifdef LA_DEBUG
if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP();
else Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex();
@@ -299,6 +307,9 @@ bool LedgerAcquire::takeBase(const std::string& data)
Log(lsWARNING) << "Acquire hash mismatch";
Log(lsWARNING) << mLedger->getHash().GetHex() << "!=" << mHash.GetHex();
mLedger = Ledger::pointer();
#ifdef TRUST_NETWORK
assert(false);
#endif
return false;
}
mHaveBase = true;
@@ -337,7 +348,11 @@ bool LedgerAcquire::takeTxNode(const std::list<SHAMapNode>& nodeIDs,
if (!mLedger->peekTransactionMap()->isSynching())
{
mHaveTransactions = true;
if (mHaveState) mComplete = true;
if (mHaveState)
{
mComplete = true;
done();
}
}
progress();
return true;
@@ -368,7 +383,11 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
if (!mLedger->peekAccountStateMap()->isSynching())
{
mHaveState = true;
if (mHaveTransactions) mComplete = true;
if (mHaveTransactions)
{
mComplete = true;
done();
}
}
progress();
return true;
@@ -388,6 +407,7 @@ bool LedgerAcquire::takeTxRootNode(const std::vector<unsigned char>& data)
LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
{
assert(hash.isNonZero());
boost::mutex::scoped_lock sl(mLock);
LedgerAcquire::pointer& ptr = mLedgers[hash];
if (ptr) return ptr;
@@ -399,6 +419,7 @@ LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash)
{
assert(hash.isNonZero());
boost::mutex::scoped_lock sl(mLock);
std::map<uint256, LedgerAcquire::pointer>::iterator it = mLedgers.find(hash);
if (it != mLedgers.end()) return it->second;
@@ -407,12 +428,14 @@ LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash)
bool LedgerAcquireMaster::hasLedger(const uint256& hash)
{
assert(hash.isNonZero());
boost::mutex::scoped_lock sl(mLock);
return mLedgers.find(hash) != mLedgers.end();
}
void LedgerAcquireMaster::dropLedger(const uint256& hash)
{
assert(hash.isNonZero());
boost::mutex::scoped_lock sl(mLock);
mLedgers.erase(hash);
}

View File

@@ -65,7 +65,7 @@ public:
protected:
Ledger::pointer mLedger;
bool mHaveBase, mHaveState, mHaveTransactions;
bool mHaveBase, mHaveState, mHaveTransactions, mAborted;
std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete;
@@ -83,6 +83,7 @@ public:
bool isAcctStComplete() const { return mHaveState; }
bool isTransComplete() const { return mHaveTransactions; }
Ledger::pointer getLedger() { return mLedger; }
void abort() { mAborted = true; }
void addOnComplete(boost::function<void (LedgerAcquire::pointer)>);

View File

@@ -155,7 +155,7 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes)
}
}
bool LCTransaction::updatePosition(int seconds, bool proposing)
bool LCTransaction::updatePosition(int percentTime, bool proposing)
{ // this many seconds after close, should our position change
if (mOurPosition && (mNays == 0))
return false;
@@ -169,9 +169,9 @@ bool LCTransaction::updatePosition(int seconds, bool proposing)
int weight = (mYays * 100 + (mOurPosition ? 100 : 0)) / (mNays + mYays + 1);
// To prevent avalanche stalls, we increase the needed weight slightly over time
if (seconds <= LEDGER_ACCEL_CONVERGE) newPosition = weight > AV_MIN_CONSENSUS;
else if (seconds >= LEDGER_CONVERGE) newPosition = weight > AV_AVG_CONSENSUS;
else newPosition = weight > AV_MAX_CONSENSUS;
if (percentTime < AV_MID_CONSENSUS_TIME) newPosition = weight > AV_INIT_CONSENSUS_PCT;
else if (percentTime < AV_LATE_CONSENSUS_TIME) newPosition = weight > AV_MID_CONSENSUS_PCT;
else newPosition = weight > AV_LATE_CONSENSUS_PCT;
}
else // don't let us outweight a proposing node, just recognize consensus
newPosition = mYays > mNays;
@@ -189,26 +189,41 @@ bool LCTransaction::updatePosition(int seconds, bool proposing)
return true;
}
int LCTransaction::getAgreeLevel()
{ // how much do nodes agree with us
if (mOurPosition) return (mYays * 100 + 100) / (mYays + mNays + 1);
return (mNays * 100 + 100) / (mYays + mNays + 1);
}
LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime)
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger)
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger),
mCurrentSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false)
{
mValSeed = theConfig.VALIDATION_SEED;
Log(lsDEBUG) << "Creating consensus object";
Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime;
if (previousLedger->getHash() != prevLCLHash)
mPreviousProposers = theApp->getOPs().getPreviousProposers();
mPreviousSeconds = theApp->getOPs().getPreviousSeconds();
assert(mPreviousSeconds);
mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution(
previousLedger->getCloseResolution(), previousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1);
mHaveCorrectLCL = previousLedger->getHash() == prevLCLHash;
if (!mHaveCorrectLCL)
{
mHaveCorrectLCL = mProposing = mValidating = false;
mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash);
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
if ((*it)->hasLedger(prevLCLHash))
mAcquiringLedger->peerHas(*it);
}
else if (mValSeed.isValid())
{
mValidating = true;
mHaveCorrectLCL = mValidating = true;
mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL;
}
else mProposing = mValidating = false;
else
{
mHaveCorrectLCL = true;
mProposing = mValidating = false;
}
}
void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
@@ -233,9 +248,9 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
if (mValidating)
mOurPosition = boost::make_shared<LedgerProposal>
(mValSeed, initialLedger->getParentHash(), txSet);
(mValSeed, initialLedger->getParentHash(), txSet, mCloseTime);
else
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet);
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet, mCloseTime);
mapComplete(txSet, initialSet, false);
if (mProposing) propose(std::vector<uint256>(), std::vector<uint256>());
}
@@ -342,84 +357,70 @@ void LedgerConsensus::statusChange(newcoin::NodeEvent event, Ledger::pointer led
Log(lsINFO) << "send status change to peer";
}
void LedgerConsensus::abort()
{
Log(lsWARNING) << "consensus aborted";
mState = lcsABORTED;
}
int LedgerConsensus::startup()
{
// create wobble ledger in case peers target transactions to it
theApp->getMasterLedger().beginWobble();
return 1;
}
int LedgerConsensus::statePreClose(int secondsSinceClose)
void LedgerConsensus::statePreClose()
{ // it is shortly before ledger close time
if (secondsSinceClose >= 0)
{ // it is time to close the ledger (swap default and wobble ledgers)
Log(lsINFO) << "Closing ledger";
mState = lcsPOST_CLOSE;
theApp->getMasterLedger().closeTime();
statusChange(newcoin::neCLOSING_LEDGER, mPreviousLedger);
}
return 1;
}
bool anyTransactions = theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap()->getHash().isNonZero();
int proposersClosed = mPeerPositions.size();
int LedgerConsensus::statePostClose(int secondsSinceClose)
{ // we are in the transaction wobble time
if (secondsSinceClose > LEDGER_WOBBLE_TIME)
{
Log(lsINFO) << "Wobble is over, it's consensus time";
int sinceClose = theApp->getOPs().getNetworkTimeNC() - theApp->getOPs().getLastCloseNetTime();
if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed,
mPreviousSeconds, sinceClose))
{ // it is time to close the ledger (swap default and wobble ledgers)
Log(lsINFO) << "CLC:: closing ledger";
mState = lcsESTABLISH;
Ledger::pointer initial = theApp->getMasterLedger().endWobble();
mConsensusStartTime = boost::posix_time::second_clock::universal_time();
mCloseTime = theApp->getOPs().getNetworkTimeNC();
theApp->getOPs().setLastCloseNetTime(mCloseTime);
statusChange(newcoin::neCLOSING_LEDGER, mPreviousLedger);
Ledger::pointer initial = theApp->getMasterLedger().closeLedger();
assert (initial->getParentHash() == mPreviousLedger->getHash());
takeInitialPosition(initial);
}
return 1;
}
int LedgerConsensus::stateEstablish(int secondsSinceClose)
void LedgerConsensus::stateEstablish()
{ // we are establishing consensus
if (mProposing)
updateOurPositions(secondsSinceClose);
if (secondsSinceClose > LEDGER_MAX_CONVERGE)
if (mCurrentSeconds < LEDGER_MIN_CONSENSUS)
return;
updateOurPositions();
if (!mHaveCloseTimeConsensus)
{
Log(lsINFO) << "No close time consensus";
}
else if (haveConsensus())
{
Log(lsINFO) << "Converge cutoff";
mState = lcsCUTOFF;
}
return 1;
}
int LedgerConsensus::stateCutoff(int secondsSinceClose)
{ // we are making sure everyone else agrees
bool haveConsensus = updateOurPositions(secondsSinceClose);
if (haveConsensus || (secondsSinceClose > LEDGER_CONVERGE))
{
Log(lsINFO) << "Consensus complete (" << haveConsensus << ")";
mState = lcsFINISHED;
beginAccept();
}
return 1;
}
int LedgerConsensus::stateFinished(int secondsSinceClose)
void LedgerConsensus::stateFinished()
{ // we are processing the finished ledger
// logic of calculating next ledger advances us out of this state
return 1;
// CHECKME: Should we count proposers that didn't converge to our consensus set?
int convergeTime = (boost::posix_time::second_clock::universal_time() - mConsensusStartTime).seconds();
if (convergeTime <= 0) convergeTime = 1;
theApp->getOPs().newLCL(mPeerPositions.size(), convergeTime, mNewLedgerHash);
}
int LedgerConsensus::stateAccepted(int secondsSinceClose)
void LedgerConsensus::stateAccepted()
{ // we have accepted a new ledger
endConsensus();
return 4;
}
int LedgerConsensus::timerEntry()
void LedgerConsensus::timerEntry()
{
if (!mHaveCorrectLCL)
{
Log(lsINFO) << "Checking for consensus ledger " << mPrevLedgerHash.GetHex();
Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash);
if (consensus)
{
@@ -429,45 +430,42 @@ int LedgerConsensus::timerEntry()
mPreviousLedger = consensus;
mHaveCorrectLCL = true;
}
else Log(lsINFO) << "We still don't have it";
}
int sinceClose = theApp->getOPs().getNetworkTimeNC() - mCloseTime;
mCurrentSeconds = (mCloseTime != 0) ? (theApp->getOPs().getNetworkTimeNC() - mCloseTime) : 0;
mClosePercent = mCurrentSeconds * 100 / mPreviousSeconds;
switch (mState)
{
case lcsPRE_CLOSE: return statePreClose(sinceClose);
case lcsPOST_CLOSE: return statePostClose(sinceClose);
case lcsESTABLISH: return stateEstablish(sinceClose);
case lcsCUTOFF: return stateCutoff(sinceClose);
case lcsFINISHED: return stateFinished(sinceClose);
case lcsACCEPTED: return stateAccepted(sinceClose);
case lcsABORTED: return 1;
case lcsPRE_CLOSE: statePreClose(); return;
case lcsESTABLISH: stateEstablish(); return;
case lcsFINISHED: stateFinished(); return;
case lcsACCEPTED: stateAccepted(); return;
}
assert(false);
return 1;
}
bool LedgerConsensus::updateOurPositions(int sinceClose)
{ // returns true if the network has consensus
void LedgerConsensus::updateOurPositions()
{
Log(lsINFO) << "Updating our positions";
bool changes = false;
bool stable = true;
SHAMap::pointer ourPosition;
std::vector<uint256> addedTx, removedTx;
for(boost::unordered_map<uint256, LCTransaction::pointer>::iterator it = mDisputes.begin(),
end = mDisputes.end(); it != end; ++it)
{
if (it->second->updatePosition(sinceClose, mProposing))
if (it->second->updatePosition(mClosePercent, mProposing))
{
if (!changes)
{
ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true);
changes = true;
stable = false;
}
if (it->second->getOurPosition()) // now a yes
{
ourPosition->addItem(SHAMapItem(it->first, it->second->peekTransaction()), true);
ourPosition->addItem(SHAMapItem(it->first, it->second->peekTransaction()), true, false);
addedTx.push_back(it->first);
}
else // now a no
@@ -476,20 +474,60 @@ bool LedgerConsensus::updateOurPositions(int sinceClose)
removedTx.push_back(it->first);
}
}
else if (it->second->getAgreeLevel() < AV_PCT_STOP)
stable = false;
}
std::map<uint32, int> closeTimes;
for (boost::unordered_map<uint160, LedgerProposal::pointer>::iterator it = mPeerPositions.begin(),
end = mPeerPositions.end(); it != end; ++it)
++closeTimes[it->second->getCloseTime() - (it->second->getCloseTime() % mCloseResolution)];
++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)];
int neededWeight;
if (mClosePercent < AV_MID_CONSENSUS_TIME)
neededWeight = AV_INIT_CONSENSUS_PCT;
else if (mClosePercent < AV_LATE_CONSENSUS_TIME)
neededWeight = AV_MID_CONSENSUS_PCT;
else neededWeight = AV_LATE_CONSENSUS_PCT;
int thresh = mPeerPositions.size() * neededWeight / 100;
uint32 closeTime = 0;
for (std::map<uint32, int>::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it)
{
if (it->second > thresh)
{
mHaveCloseTimeConsensus = true;
closeTime = it->first;
}
}
if (closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)))
changes = true;
if (changes)
{
uint256 newHash = ourPosition->getHash();
mOurPosition->changePosition(newHash);
mOurPosition->changePosition(newHash, closeTime);
if (mProposing) propose(addedTx, removedTx);
mapComplete(newHash, ourPosition, false);
Log(lsINFO) << "We change our position to " << newHash.GetHex();
}
}
return stable;
bool LedgerConsensus::haveConsensus()
{
int agree = 0, disagree = 0;
uint256 ourPosition = mOurPosition->getCurrentHash();
for (boost::unordered_map<uint160, LedgerProposal::pointer>::iterator it = mPeerPositions.begin(),
end = mPeerPositions.end(); it != end; ++it)
{
if (it->second->getCurrentHash() == ourPosition)
++agree;
else
++disagree;
}
int currentValidations = theApp->getValidations().getCurrentValidationCount(mPreviousLedger->getCloseTimeNC());
return ContinuousLedgerTiming::haveConsensus(mPreviousProposers, agree + disagree, agree, currentValidations,
mPreviousSeconds, mCurrentSeconds);
}
SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire)
@@ -546,6 +584,7 @@ void LedgerConsensus::propose(const std::vector<uint256>& added, const std::vect
newcoin::TMProposeSet prop;
prop.set_currenttxhash(mOurPosition->getCurrentHash().begin(), 256 / 8);
prop.set_proposeseq(mOurPosition->getProposeSeq());
prop.set_closetime(mOurPosition->getCloseTime());
std::vector<unsigned char> pubKey = mOurPosition->getPubKey();
std::vector<unsigned char> sig = mOurPosition->sign();
@@ -586,6 +625,7 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
{
LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()];
if (currentPosition)
{
assert(newPosition->getPeerID() == currentPosition->getPeerID());
@@ -598,6 +638,10 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
return true;
}
}
else if (newPosition->getProposeSeq() == 0)
{ // new initial close time estimate
++mCloseTimes[newPosition->getCloseTime()];
}
Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/"
<< newPosition->getCurrentHash().GetHex();
currentPosition = newPosition;
@@ -666,7 +710,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran
try
{
#endif
TransactionEngineResult result = engine.applyTransaction(*txn, parms, 0);
TransactionEngineResult result = engine.applyTransaction(*txn, parms);
if (result > 0)
{
Log(lsINFO) << " retry";
@@ -725,7 +769,7 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer led
{
try
{
TransactionEngineResult result = engine.applyTransaction(*it->second, parms, 0);
TransactionEngineResult result = engine.applyTransaction(*it->second, parms);
if (result <= 0)
{
if (result == 0) ++successes;
@@ -758,7 +802,16 @@ void LedgerConsensus::accept(SHAMap::pointer set)
CanonicalTXSet failedTransactions(set->getHash());
applyTransactions(set, newLCL, failedTransactions, true);
newLCL->setClosed();
newLCL->setAccepted();
uint32 closeTime = mOurPosition->getCloseTime();
bool closeTimeCorrect = true;
if (closeTime == 0)
{ // we didn't agree
closeTimeCorrect = false;
closeTime = mPreviousLedger->getCloseTimeNC() + 1;
}
newLCL->setAccepted(closeTime, mCloseResolution, closeTimeCorrect);
newLCL->updateHash();
uint256 newLCLHash = newLCL->getHash();
Log(lsTRACE) << "newLCL " << newLCLHash.GetHex();
@@ -804,6 +857,7 @@ void LedgerConsensus::accept(SHAMap::pointer set)
applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL,
failedTransactions, false);
theApp->getMasterLedger().pushLedger(newLCL, newOL);
mNewLedgerHash = newLCL->getHash();
mState = lcsACCEPTED;
sl.unlock();

View File

@@ -2,6 +2,7 @@
#define __LEDGER_CONSENSUS__
#include <list>
#include <map>
#include <boost/weak_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
@@ -62,32 +63,36 @@ public:
void setVote(const uint160& peer, bool votesYes);
bool updatePosition(int timePassed, bool proposing);
int getAgreeLevel();
bool updatePosition(int percentTime, bool proposing);
};
enum LCState
{
lcsPRE_CLOSE, // We haven't closed our ledger yet, but others might have
lcsPOST_CLOSE, // Ledger closed, but wobble time
lcsESTABLISH, // Establishing consensus
lcsCUTOFF, // Past the cutoff for consensus
lcsFINISHED, // We have closed on a transaction set
lcsACCEPTED, // We have accepted/validated a new last closed ledger
lcsABORTED // Abandoned
};
class LedgerConsensus : public boost::enable_shared_from_this<LedgerConsensus>
{
protected:
LCState mState;
uint32 mCloseTime;
uint256 mPrevLedgerHash;
uint32 mCloseTime; // The wall time this ledger closed
uint256 mPrevLedgerHash, mNewLedgerHash;
Ledger::pointer mPreviousLedger;
LedgerAcquire::pointer mAcquiringLedger;
LedgerProposal::pointer mOurPosition;
NewcoinAddress mValSeed;
bool mProposing, mValidating, mHaveCorrectLCL;
int mCurrentSeconds, mClosePercent, mCloseResolution;
bool mHaveCloseTimeConsensus;
boost::posix_time::ptime mConsensusStartTime;
int mPreviousProposers;
int mPreviousSeconds;
// Convergence tracking, trusted peers indexed by hash of public key
boost::unordered_map<uint160, LedgerProposal::pointer> mPeerPositions;
@@ -101,6 +106,9 @@ protected:
// Disputed transactions
boost::unordered_map<uint256, LCTransaction::pointer> mDisputes;
// Close time estimates
std::map<uint32, int> mCloseTimes;
// final accept logic
static void Saccept(boost::shared_ptr<LedgerConsensus> This, SHAMap::pointer txSet);
void accept(SHAMap::pointer txSet);
@@ -123,9 +131,9 @@ protected:
CanonicalTXSet& failedTransactions, bool final);
// manipulating our own position
void takeInitialPosition(Ledger::pointer initialLedger);
bool updateOurPositions(int sinceClose);
void statusChange(newcoin::NodeEvent, Ledger::pointer ledger);
void takeInitialPosition(Ledger::pointer initialLedger);
void updateOurPositions();
int getThreshold();
void beginAccept();
void endConsensus();
@@ -142,16 +150,16 @@ public:
TransactionAcquire::pointer getAcquiring(const uint256& hash);
void mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired);
void abort();
int timerEntry();
void timerEntry();
// state handlers
int statePreClose(int secondsSinceClose);
int statePostClose(int secondsSinceClose);
int stateEstablish(int secondsSinceClose);
int stateCutoff(int secondsSinceClose);
int stateFinished(int secondsSinceClose);
int stateAccepted(int secondsSinceClose);
void statePreClose();
void stateEstablish();
void stateCutoff();
void stateFinished();
void stateAccepted();
bool haveConsensus();
bool peerPosition(LedgerProposal::pointer);

View File

@@ -42,8 +42,8 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL)
if (newLCL->isAccepted())
{
mLedgerHistory.addAcceptedLedger(mFinalizedLedger);
Log(lsINFO) << "StashAccepted: " << mFinalizedLedger->getHash().GetHex();
mLedgerHistory.addAcceptedLedger(newLCL);
Log(lsINFO) << "StashAccepted: " << newLCL->getHash().GetHex();
}
mFinalizedLedger = newLCL;
@@ -54,6 +54,7 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL)
void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer current)
{
assert(lastClosed && current);
mFinalizedLedger = lastClosed;
mFinalizedLedger->setClosed();
mFinalizedLedger->setAccepted();
@@ -63,40 +64,25 @@ void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer cur
mEngine.setLedger(mCurrentLedger);
}
void LedgerMaster::beginWobble()
void LedgerMaster::storeLedger(Ledger::pointer ledger)
{
boost::recursive_mutex::scoped_lock sl(mLock);
assert(!mWobbleLedger);
mWobbleLedger = boost::make_shared<Ledger>(boost::ref(*mCurrentLedger), true);
mEngine.setDefaultLedger(mCurrentLedger);
mEngine.setAlternateLedger(mWobbleLedger);
mLedgerHistory.addLedger(ledger);
}
void LedgerMaster::closeTime()
{ // swap current and wobble ledgers
boost::recursive_mutex::scoped_lock sl(mLock);
assert(mCurrentLedger && mWobbleLedger);
std::swap(mCurrentLedger, mWobbleLedger);
mEngine.setDefaultLedger(mCurrentLedger);
mEngine.setAlternateLedger(mWobbleLedger);
}
Ledger::pointer LedgerMaster::endWobble()
Ledger::pointer LedgerMaster::closeLedger()
{
boost::recursive_mutex::scoped_lock sl(mLock);
assert(mWobbleLedger && mCurrentLedger);
Ledger::pointer ret = mWobbleLedger;
mWobbleLedger = Ledger::pointer();
mEngine.setAlternateLedger(Ledger::pointer());
return ret;
Ledger::pointer closingLedger = mCurrentLedger;
mCurrentLedger = boost::make_shared<Ledger>(boost::ref(*closingLedger), true);
mEngine.setLedger(mCurrentLedger);
return closingLedger;
}
TransactionEngineResult LedgerMaster::doTransaction(const SerializedTransaction& txn, uint32 targetLedger,
TransactionEngineParams params)
{
Ledger::pointer ledger = mEngine.getTransactionLedger(targetLedger);
TransactionEngineResult result = mEngine.applyTransaction(txn, params, ledger);
theApp->getOPs().pubTransaction(ledger, txn, result);
TransactionEngineResult result = mEngine.applyTransaction(txn, params);
theApp->getOPs().pubTransaction(mEngine.getLedger(), txn, result);
return result;
}

View File

@@ -19,7 +19,6 @@ class LedgerMaster
TransactionEngine mEngine;
Ledger::pointer mCurrentLedger; // The ledger we are currently processiong
Ledger::pointer mWobbleLedger; // A ledger past its close time
Ledger::pointer mFinalizedLedger; // The ledger that most recently closed
LedgerHistory mLedgerHistory;
@@ -41,9 +40,6 @@ public:
// The current ledger is the ledger we believe new transactions should go in
Ledger::pointer getCurrentLedger() { return mCurrentLedger; }
// The wobble ledger is a ledger that new transactions can go in if requested
Ledger::pointer getWobbleLedger() { return mWobbleLedger; }
// The finalized ledger is the last closed/accepted ledger
Ledger::pointer getClosedLedger() { return mFinalizedLedger; }
@@ -52,12 +48,11 @@ public:
void pushLedger(Ledger::pointer newLedger);
void pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL);
void storeLedger(Ledger::pointer);
void switchLedgers(Ledger::pointer lastClosed, Ledger::pointer newCurrent);
void closeTime();
void beginWobble();
Ledger::pointer endWobble();
Ledger::pointer closeLedger();
Ledger::pointer getLedgerBySeq(uint32 index)
{

View File

@@ -29,8 +29,7 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry)
if (create)
{
assert(!mAccountStateMap->hasItem(entry->getIndex()));
if (!mAccountStateMap->addGiveItem(item, false))
if(!mAccountStateMap->addGiveItem(item, false, false)) // FIXME: TX metadata
{
assert(false);
return lepERROR;
@@ -38,7 +37,7 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry)
return lepCREATED;
}
if (!mAccountStateMap->updateGiveItem(item, false))
if (!mAccountStateMap->updateGiveItem(item, false, false)) // FIXME: TX metadata
{
assert(false);
return lepERROR;

View File

@@ -7,39 +7,41 @@
#include "Application.h"
#include "HashPrefixes.h"
LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& tx, const NewcoinAddress& naPeerPublic) :
mPreviousLedger(pLgr), mCurrentHash(tx), mProposeSeq(seq)
LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& tx, uint32 closeTime,
const NewcoinAddress& naPeerPublic) :
mPreviousLedger(pLgr), mCurrentHash(tx), mCloseTime(closeTime), mProposeSeq(seq)
{
mPublicKey = naPeerPublic;
// XXX Validate key.
// if (!mKey->SetPubKey(pubKey))
// throw std::runtime_error("Invalid public key in proposal");
mPreviousLedger = theApp->getMasterLedger().getClosedLedger()->getHash();
mPeerID = mPublicKey.getNodeID();
}
LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prevLgr, const uint256& position) :
mPreviousLedger(prevLgr), mCurrentHash(position), mProposeSeq(0)
LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prevLgr,
const uint256& position, uint32 closeTime) :
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0)
{
mPublicKey = NewcoinAddress::createNodePublic(naSeed);
mPrivateKey = NewcoinAddress::createNodePrivate(naSeed);
mPeerID = mPublicKey.getNodeID();
}
LedgerProposal::LedgerProposal(const uint256& prevLgr, const uint256& position) :
mPreviousLedger(prevLgr), mCurrentHash(position), mProposeSeq(0)
LedgerProposal::LedgerProposal(const uint256& prevLgr, const uint256& position, uint32 closeTime) :
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0)
{
;
}
uint256 LedgerProposal::getSigningHash() const
{
Serializer s(72);
Serializer s((32 + 32 + 32 + 256 + 256) / 8);
s.add32(sHP_Proposal);
s.add32(mProposeSeq);
s.add32(mCloseTime);
s.add256(mPreviousLedger);
s.add256(mCurrentHash);
@@ -51,9 +53,10 @@ bool LedgerProposal::checkSign(const std::string& signature, const uint256& sign
return mPublicKey.verifyNodePublic(signingHash, signature);
}
void LedgerProposal::changePosition(const uint256& newPosition)
void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime)
{
mCurrentHash = newPosition;
mCloseTime = closeTime;
++mProposeSeq;
}

View File

@@ -13,7 +13,7 @@ class LedgerProposal
protected:
uint256 mPreviousLedger, mCurrentHash;
uint32 mProposeSeq;
uint32 mCloseTime, mProposeSeq;
uint160 mPeerID;
NewcoinAddress mPublicKey;
@@ -25,13 +25,14 @@ public:
// proposal from peer
LedgerProposal(const uint256& prevLgr, uint32 proposeSeq, const uint256& propose,
const NewcoinAddress& naPeerPublic);
uint32 closeTime, const NewcoinAddress& naPeerPublic);
// our first proposal
LedgerProposal(const NewcoinAddress& privKey, const uint256& prevLedger, const uint256& position);
LedgerProposal(const NewcoinAddress& privKey, const uint256& prevLedger, const uint256& position,
uint32 closeTime);
// an unsigned proposal
LedgerProposal(const uint256& prevLedger, const uint256& position);
// an unsigned "dummy" proposal for nodes not validating
LedgerProposal(const uint256& prevLedger, const uint256& position, uint32 closeTime);
uint256 getSigningHash() const;
bool checkSign(const std::string& signature, const uint256& signingHash);
@@ -41,11 +42,12 @@ public:
const uint256& getCurrentHash() const { return mCurrentHash; }
const uint256& getPrevLedger() const { return mPreviousLedger; }
uint32 getProposeSeq() const { return mProposeSeq; }
uint32 getCloseTime() const { return mCloseTime; }
const NewcoinAddress& peekPublic() const { return mPublicKey; }
std::vector<unsigned char> getPubKey() const { return mPublicKey.getNodePublic(); }
std::vector<unsigned char> sign();
void changePosition(const uint256& newPosition);
void changePosition(const uint256& newPosition, uint32 newCloseTime);
};
#endif

View File

@@ -1,34 +1,55 @@
#include "LedgerTiming.h"
#include <cassert>
// Returns the number of seconds the ledger should be be open.
int ContinuousLedgerTiming::shouldClose( // How many:
#include <boost/format.hpp>
#include "Log.h"
// NOTE: First and last times must be repeated
int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 120, 120 };
// Called when a ledger is open and no close is in progress -- when a transaction is received and no close
// is in process, or when a close completes. Returns the number of seconds the ledger should be be open.
int ContinuousLedgerTiming::shouldClose(
bool anyTransactions,
int previousProposers, // proposers there were in the last closing
int proposersClosed, // proposers who have currently closed their ledgers
int previousOpenSeconds, // seconds the previous ledger was open
int currentOpenSeconds) // seconds since the previous ledger closed
int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed this ledgers
int previousSeconds, // seconds the previous ledger took to reach consensus
int currentSeconds) // seconds since the previous ledger closed
{
assert((previousSeconds > 0) && (previousSeconds < 600));
assert((currentSeconds >= 0) && (currentSeconds < 600));
#if 0
Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") %
(anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentSeconds % previousSeconds);
#endif
if (!anyTransactions)
{ // no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
return currentOpenSeconds;
if (previousOpenSeconds > (LEDGER_IDLE_INTERVAL + 2)) // the last ledger was very slow to close
return previousOpenSeconds - 1;
{
Log(lsTRACE) << "no transactions, many proposers: now";
return currentSeconds;
}
if (previousSeconds > (LEDGER_IDLE_INTERVAL + 2)) // the last ledger was very slow to close
{
Log(lsTRACE) << "slow to close";
return previousSeconds - 1;
}
return LEDGER_IDLE_INTERVAL; // normal idle
}
if (previousOpenSeconds == LEDGER_IDLE_INTERVAL) // coming out of idle, close now
return currentOpenSeconds;
if (previousSeconds == LEDGER_IDLE_INTERVAL) // coming out of idle, close now
{
Log(lsTRACE) << "leaving idle, close now";
return currentSeconds;
}
// If the network is slow, try to synchronize close times
if (previousOpenSeconds > 8)
return (currentOpenSeconds - currentOpenSeconds % 4);
else if (previousOpenSeconds > 4)
return (currentOpenSeconds - currentOpenSeconds % 2);
return currentOpenSeconds; // this ledger should close now
Log(lsTRACE) << "close now";
return currentSeconds; // this ledger should close now
}
// Returns whether we have a consensus or not. If so, we expect all honest nodes
@@ -41,21 +62,59 @@ bool ContinuousLedgerTiming::haveConsensus(
int previousAgreeTime, // how long it took to agree on the last ledger
int currentAgreeTime) // how long we've been trying to agree
{
if (currentProposers < (previousProposers * 3 / 4))
{ // Less than 3/4 of the validators are present, slow down
if (currentAgreeTime < (previousAgreeTime + 2))
Log(lsTRACE) << boost::str(boost::format("CLC::haveConsensus: prop=%d/%d agree=%d closed=%d time=%d/%d") %
currentProposers % previousProposers % currentAgree % currentClosed % currentAgreeTime % previousAgreeTime);
if (currentAgreeTime <= LEDGER_MIN_CONSENSUS)
return false;
if (currentProposers < (previousProposers * 3 / 4))
{ // Less than 3/4 of the last ledger's proposers are present, we may need more time
if (currentAgreeTime < (previousAgreeTime + 2))
{
Log(lsTRACE) << "too fast, not enough proposers";
return false;
}
}
// If 80% of current proposers (plus us) agree on a set, we have consensus
int agreeWeight = (currentAgree * 100 + 100) / (currentProposers + 1);
if (agreeWeight > 80)
if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
{
Log(lsTRACE) << "normal consensus";
return true;
}
// If 50% of the nodes on your UNL (minus us) have closed, you should close
int closeWeight = (currentClosed * 100 - 100) / (currentProposers + 1);
if (closeWeight > 50)
if (((currentClosed * 100 - 100) / (currentProposers + 1)) > 50)
{
Log(lsTRACE) << "many closers";
return true;
}
// no consensus yet
Log(lsTRACE) << "no consensus";
return false;
}
int ContinuousLedgerTiming::getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq)
{
assert(ledgerSeq);
assert(previousAgree); // TEMPORARY
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
{ // reduce resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i + 1];
}
if ((previousAgree) && ((ledgerSeq % LEDGER_RES_INCREASE) == 0))
{ // increase resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i - 1];
}
return previousResolution;
}

View File

@@ -1,66 +1,53 @@
#ifndef __LEDGERTIMING__
#define __LEDGERTIMING__
#define LEDGER_CLOSE_FAST
// #define LEDGER_CLOSE_SLOW
#ifdef LEDGER_CLOSE_FAST
// Time between one ledger close and the next ledger close
# define LEDGER_INTERVAL 30
// Time before we take a position
# define LEDGER_WOBBLE_TIME 1
// Time we acceleratet avalanche
# define LEDGER_ACCEL_CONVERGE 10
// Time we permit avalanche to finish
# define LEDGER_CONVERGE 14
// Maximum converge time
# define LEDGER_MAX_CONVERGE 20
#define AV_PCT_STOP 85
#endif
// BEGIN LEDGER_CLOSE_CONTINUOUS
// The number of seconds a ledger may remain idle before closing
# define LEDGER_IDLE_INTERVAL 15
// How long we wait to transition from inactive to active
# define LEDGER_IDLE_SPIN_TIME 2
// The number of seconds a validation remains current
# define LEDGER_MAX_INTERVAL 60
// Avalance tuning (percent of UNL voting yes for us to vote yes)
#define AV_MIN_CONSENSUS 55
#define AV_AVG_CONSENSUS 65
#define AV_MAX_CONSENSUS 70
// The number of seconds we wait minimum to ensure participation
# define LEDGER_MIN_CONSENSUS 2
// Initial resolution of ledger close time
# define LEDGER_TIME_ACCURACY 30
// How often to increase resolution
# define LEDGER_RES_INCREASE 8
// How often to decrease resolution
# define LEDGER_RES_DECREASE 1
// Avalanche tuning
#define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
#define AV_MID_CONSENSUS_TIME 50 // percentage of previous close time before we advance
#define AV_MID_CONSENSUS_PCT 65 // percentage of nodes that most vote yes after advancing
#define AV_LATE_CONSENSUS_TIME 85 // percentage of previous close time before we advance
#define AV_LATE_CONSENSUS_PCT 70 // percentage of nodes that most vote yes after advancing
class ContinuousLedgerTiming
{
public:
static int LedgerTimeResolution[];
// Returns the number of seconds the ledger was or should be open
// Call when a consensus is reached and when any transaction is relayed to be added
static int shouldClose(
bool anyTransactions,
int previousProposers, int proposersClosed,
int previousOpenSeconds, int currentOpenSeconds);
int previousSeconds, int currentSeconds);
static bool haveConsensus(
int previousProposers, int currentProposers,
int currentAgree, int currentClosed,
int previousAgreeTime, int currentAgreeTime);
static int getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq);
};
// END LEDGER_CLOSE_CONTINUOUS
#endif

View File

@@ -24,7 +24,8 @@
// there's a functional network.
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster)
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster),
mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL)
{
}
@@ -33,7 +34,7 @@ boost::posix_time::ptime NetworkOPs::getNetworkTimePT()
return boost::posix_time::second_clock::universal_time();
}
uint64 NetworkOPs::getNetworkTimeNC()
uint32 NetworkOPs::getNetworkTimeNC()
{
return iToSeconds(getNetworkTimePT());
}
@@ -277,17 +278,9 @@ RippleState::pointer NetworkOPs::getRippleState(const uint256& uLedger, const ui
// Other
//
void NetworkOPs::setStateTimer(int sec)
void NetworkOPs::setStateTimer()
{ // set timer early if ledger is closing
if (!mConsensus && ((mMode == omFULL) || (mMode == omTRACKING)))
{
uint64 consensusTime = mLedgerMaster->getCurrentLedger()->getCloseTimeNC() - LEDGER_WOBBLE_TIME;
uint64 now = getNetworkTimeNC();
if (now >= consensusTime) sec = 1;
else if (sec > (consensusTime - now)) sec = (consensusTime - now);
}
mNetTimer.expires_from_now(boost::posix_time::seconds(sec));
mNetTimer.expires_from_now(boost::posix_time::seconds(1));
mNetTimer.async_wait(boost::bind(&NetworkOPs::checkState, this, boost::asio::placeholders::error));
}
@@ -324,7 +317,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
Log(lsWARNING) << "Node count (" << peerList.size() <<
") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ").";
}
setStateTimer(5);
setStateTimer();
return;
}
if (mMode == omDISCONNECTED)
@@ -335,7 +328,8 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
if (mConsensus)
{
setStateTimer(mConsensus->timerEntry());
mConsensus->timerEntry();
setStateTimer();
return;
}
@@ -343,6 +337,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
// If full or tracking, check only at wobble time!
uint256 networkClosed;
bool ledgerChange = checkLastClosedLedger(peerList, networkClosed);
assert(networkClosed.isNonZero());
// WRITEME: Unless we are in omFULL and in the process of doing a consensus,
// we must count how many nodes share our LCL, how many nodes disagree with our LCL,
@@ -365,7 +360,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
(theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4))
setMode(omFULL);
else
Log(lsWARNING) << "Too late to go to full, will try in consensus window";
Log(lsINFO) << "Will try to go to FULL in consensus window";
}
if (mMode == omFULL)
@@ -373,13 +368,11 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
// check if the ledger is bad enough to go to omTRACKING
}
int secondsToClose = theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() -
theApp->getOPs().getNetworkTimeNC();
if ((!mConsensus) && (secondsToClose < LEDGER_WOBBLE_TIME)) // pre close wobble
if ((!mConsensus) && (mMode != omDISCONNECTED))
beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger());
if (mConsensus)
setStateTimer(mConsensus->timerEntry());
else setStateTimer(4);
mConsensus->timerEntry();
setStateTimer();
}
bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerList, uint256& networkClosed)
@@ -401,11 +394,11 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
}
Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger();
uint256 closedLedger=0;
if(theConfig.LEDGER_CREATOR || ourClosed->getLedgerSeq() > 100)
{
closedLedger = ourClosed->getHash();
uint256 closedLedger = ourClosed->getHash();
ValidationCount& ourVC = ledgers[closedLedger];
if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING))
{
++ourVC.nodesUsing;
ourVC.highNode = theApp->getWallet().getNodePublic();
}
@@ -449,25 +442,34 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
networkClosed = closedLedger;
if (!switchLedgers)
{
if (mAcquiringLedger)
{
mAcquiringLedger->abort();
theApp->getMasterLedgerAcquire().dropLedger(mAcquiringLedger->getHash());
mAcquiringLedger = LedgerAcquire::pointer();
}
return false;
}
Log(lsWARNING) << "We are not running on the consensus ledger";
Log(lsINFO) << "Our LCL " << ourClosed->getHash().GetHex();
Log(lsINFO) << "Net LCL " << closedLedger.GetHex();
if ((mMode == omTRACKING) || (mMode == omFULL)) setMode(omCONNECTED);
if ((mMode == omTRACKING) || (mMode == omFULL))
setMode(omCONNECTED);
Ledger::pointer consensus = mLedgerMaster->getLedgerByHash(closedLedger);
if (!consensus)
{
Log(lsINFO) << "Acquiring consensus ledger";
LedgerAcquire::pointer acq = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
if (!acq || acq->isFailed())
Log(lsINFO) << "Acquiring consensus ledger " << closedLedger.GetHex();
LedgerAcquire::pointer mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
if (!mAcquiringLedger || mAcquiringLedger->isFailed())
{
theApp->getMasterLedgerAcquire().dropLedger(closedLedger);
Log(lsERROR) << "Network ledger cannot be acquired";
return true;
}
if (!acq->isComplete())
if (!mAcquiringLedger->isComplete())
{ // add more peers
int count = 0;
std::vector<Peer::pointer> peers=theApp->getConnectionPool().getPeerVector();
@@ -477,7 +479,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
if ((*it)->getClosedLedgerHash() == closedLedger)
{
++count;
acq->peerHas(*it);
mAcquiringLedger->peerHas(*it);
}
}
if (!count)
@@ -486,12 +488,12 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
it != end; ++it)
{
if ((*it)->isConnected())
acq->peerHas(*it);
mAcquiringLedger->peerHas(*it);
}
}
return true;
}
consensus = acq->getLedger();
consensus = mAcquiringLedger->getLedger();
}
// FIXME: If this rewinds the ledger sequence, or has the same sequence, we should update the status on
@@ -506,12 +508,6 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
Log(lsERROR) << "ABNORMAL Switching last closed ledger to " << newLedger->getHash().GetHex();
if (mConsensus)
{
mConsensus->abort();
mConsensus = boost::shared_ptr<LedgerConsensus>();
}
newLedger->setClosed();
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*newLedger));
mLedgerMaster->switchLedgers(newLedger, openLedger);
@@ -530,7 +526,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger)
{
Log(lsINFO) << "Ledger close time for ledger " << closingLedger->getLedgerSeq();
Log(lsINFO) << "Consensus time for ledger " << closingLedger->getLedgerSeq();
Log(lsINFO) << " LCL is " << closingLedger->getParentHash().GetHex();
Ledger::pointer prevLedger = mLedgerMaster->getLedgerByHash(closingLedger->getParentHash());
@@ -544,19 +540,17 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo
assert(closingLedger->getParentHash() == mLedgerMaster->getClosedLedger()->getHash());
// Create a consensus object to get consensus on this ledger
if (!!mConsensus)
mConsensus->abort();
assert(!mConsensus);
prevLedger->setImmutable();
mConsensus = boost::make_shared<LedgerConsensus>(
networkClosed,
prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
networkClosed, prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
Log(lsDEBUG) << "Pre-close time, initiating consensus engine";
Log(lsDEBUG) << "Initiating consensus engine";
return mConsensus->startup();
}
// <-- bool: true to relay
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime,
const std::string& pubKey, const std::string& signature)
{
// JED: does mConsensus need to be locked?
@@ -565,7 +559,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
// XXX Take a vuc for pubkey.
// Get a preliminary hash to use to suppress duplicates
Serializer s;
Serializer s(128);
s.add32(proposeSeq);
s.add32(getCurrentLedgerID());
s.addRaw(pubKey);
@@ -579,14 +573,14 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
}
if (!mConsensus)
{
{ // FIXME: CLC
Log(lsWARNING) << "Received proposal when full but not during consensus window";
return false;
}
NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey));
LedgerProposal::pointer proposal =
boost::make_shared<LedgerProposal>(mConsensus->getLCL(), proposeSeq, proposeHash, naPeerPublic);
boost::make_shared<LedgerProposal>(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, naPeerPublic);
if (!proposal->checkSign(signature))
{ // Note that if the LCL is different, the signature check will fail
Log(lsWARNING) << "Ledger proposal fails signature check";
@@ -594,7 +588,6 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
}
// Is this node on our UNL?
// XXX Is this right?
if (!theApp->getUNL().nodeInUNL(proposal->peekPublic()))
{
Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " <<
@@ -647,14 +640,8 @@ void NetworkOPs::endConsensus()
void NetworkOPs::setMode(OperatingMode om)
{
if (mMode == om) return;
if (mMode == omFULL)
{
if (mConsensus)
{
mConsensus->abort();
mConsensus = boost::shared_ptr<LedgerConsensus>();
}
}
if ((om >= omCONNECTED) && (mMode == omDISCONNECTED))
mConnectTime = boost::posix_time::second_clock::universal_time();
Log l((om < mMode) ? lsWARNING : lsINFO);
if (om == omDISCONNECTED) l << "STATE->Disonnected";
else if (om == omCONNECTED) l << "STATE->Connected";
@@ -1064,6 +1051,15 @@ void NetworkOPs::unsubAccountTransaction(InfoSub* ispListener, const boost::unor
}
}
void NetworkOPs::newLCL(int proposers, int convergeTime, const uint256& ledgerHash)
{
assert(convergeTime);
mLastCloseProposers = proposers;
mLastCloseConvergeTime = convergeTime;
mLastCloseHash = ledgerHash;
}
#if 0
void NetworkOPs::subAccountChanges(InfoSub* ispListener, const uint256 uLedgerHash)
{

View File

@@ -6,6 +6,7 @@
#include "NicknameState.h"
#include "RippleState.h"
#include "SerializedValidation.h"
#include "LedgerAcquire.h"
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
@@ -46,10 +47,12 @@ public:
protected:
OperatingMode mMode;
boost::posix_time::ptime mConnectTime;
boost::asio::deadline_timer mNetTimer;
boost::shared_ptr<LedgerConsensus> mConsensus;
LedgerMaster* mLedgerMaster;
LedgerAcquire::pointer mAcquiringLedger;
void setMode(OperatingMode);
@@ -57,6 +60,11 @@ protected:
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::value_type subInfoMapValue;
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::iterator subInfoMapIterator;
// last ledger close
int mLastCloseProposers, mLastCloseConvergeTime;
uint256 mLastCloseHash;
uint32 mLastCloseNetTime;
// XXX Split into more locks.
boost::interprocess::interprocess_upgradable_mutex mMonitorLock;
subInfoMapType mBootAccountInfo;
@@ -77,7 +85,7 @@ public:
NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster);
// network information
uint64 getNetworkTimeNC();
uint32 getNetworkTimeNC();
boost::posix_time::ptime getNetworkTimePT();
uint32 getCurrentLedgerID();
OperatingMode getOperatingMode() { return mMode; }
@@ -156,7 +164,7 @@ public:
const std::vector<unsigned char>& myNode, std::list< std::vector<unsigned char> >& newNodes);
// ledger proposal/close functions
bool recvPropose(uint32 proposeSeq, const uint256& proposeHash,
bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime,
const std::string& pubKey, const std::string& signature);
bool gotTXData(boost::shared_ptr<Peer> peer, const uint256& hash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
@@ -171,7 +179,12 @@ public:
bool checkLastClosedLedger(const std::vector<Peer::pointer>&, uint256& networkClosed);
int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger);
void endConsensus();
void setStateTimer(int seconds);
void setStateTimer();
void newLCL(int proposers, int convergeTime, const uint256& ledgerHash);
int getPreviousProposers() { return mLastCloseProposers; }
int getPreviousSeconds() { return mLastCloseConvergeTime; }
uint32 getLastCloseNetTime() { return mLastCloseNetTime; }
void setLastCloseNetTime(uint32 t) { mLastCloseNetTime = t; }
Json::Value getServerInfo();
// client information retrieval functions

View File

@@ -571,14 +571,15 @@ void Peer::recvHello(newcoin::TMHello& packet)
// Cancel verification timeout.
(void) mVerifyTimer.cancel();
uint64 minTime = theApp->getOPs().getNetworkTimeNC() - 4;
uint64 maxTime = minTime + 8;
uint32 minTime = theApp->getOPs().getNetworkTimeNC() - 4;
uint32 maxTime = minTime + 8;
if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime)))
{
Log(lsINFO) << "Recv(Hello): Disconnect: Clocks are too far off";
Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off";
}
else if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR))
if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR))
{
Log(lsINFO) << "Recv(Hello): Server requires protocol version " <<
GET_VERSION_MAJOR(packet.protoversion()) << "." << GET_VERSION_MINOR(packet.protoversion())
@@ -716,7 +717,8 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet)
uint256 currentTxHash;
memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32);
if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.nodepubkey(), packet.signature()))
if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.closetime(),
packet.nodepubkey(), packet.signature()))
{ // FIXME: Not all nodes will want proposals
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, newcoin::mtPROPOSE_LEDGER);
theApp->getConnectionPool().relayMessage(this, message);
@@ -1111,6 +1113,11 @@ void Peer::recvLedger(newcoin::TMLedgerData& packet)
punishPeer(PP_UNWANTED_DATA);
}
bool Peer::hasLedger(const uint256& hash) const
{
return (hash == mClosedLedgerHash) || (hash == mPreviousLedgerHash);
}
// Get session information we can sign to prevent man in the middle attack.
// (both sides get the same information, neither side controls it)
void Peer::getSessionCookie(std::string& strDst)

View File

@@ -159,6 +159,7 @@ public:
static PackedMessage::pointer createGetFullLedger(uint256& hash);
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
bool hasLedger(const uint256& hash) const;
NewcoinAddress getNodePublic() const { return mNodePublic; }
void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); }
};

View File

@@ -46,6 +46,13 @@ SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(Modifying)
mTNByID[*root] = root;
}
SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(Synching)
{ // FIXME: Need to acquire root node
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
root->makeInner();
mTNByID[*root] = root;
}
SHAMap::pointer SHAMap::snapShot(bool isMutable)
{ // Return a new SHAMap that is an immutable snapshot of this one
// Initially nodes are shared, but CoW is forced on both ledgers
@@ -158,7 +165,7 @@ SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify)
SHAMapTreeNode* SHAMap::walkToPointer(const uint256& id)
{
SHAMapTreeNode* inNode = &*root;
SHAMapTreeNode* inNode = root.get();
while (!inNode->isLeaf())
{
int branch = inNode->selectBranch(id);
@@ -201,12 +208,12 @@ SHAMapTreeNode* SHAMap::getNodePointer(const SHAMapNode& id, const uint256& hash
{ // fast, but you do not hold a reference
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = mTNByID.find(id);
if (it != mTNByID.end())
return &*it->second;
return it->second.get();
SHAMapTreeNode::pointer node = fetchNodeExternal(id, hash);
if (!mTNByID.insert(std::make_pair(id, node)).second)
assert(false);
return &*node;
return node.get();
}
void SHAMap::returnNode(SHAMapTreeNode::pointer& node, bool modify)
@@ -338,13 +345,13 @@ void SHAMap::eraseChildren(SHAMapTreeNode::pointer node)
SHAMapItem::pointer SHAMap::peekFirstItem()
{
boost::recursive_mutex::scoped_lock sl(mLock);
return firstBelow(&*root);
return firstBelow(root.get());
}
SHAMapItem::pointer SHAMap::peekLastItem()
{
boost::recursive_mutex::scoped_lock sl(mLock);
return lastBelow(&*root);
return lastBelow(root.get());
}
SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
@@ -366,7 +373,7 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
if(!node->isEmptyBranch(i))
{
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
SHAMapItem::pointer item = firstBelow(&*node);
SHAMapItem::pointer item = firstBelow(node.get());
if (!item) throw std::runtime_error("missing node");
return item;
}
@@ -394,7 +401,7 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id)
if(!node->isEmptyBranch(i))
{
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
SHAMapItem::pointer item = firstBelow(&*node);
SHAMapItem::pointer item = firstBelow(node.get());
if (!item) throw std::runtime_error("missing node");
return item;
}
@@ -465,7 +472,7 @@ bool SHAMap::delItem(const uint256& id)
}
else if(bc==1)
{ // pull up on the thread
SHAMapItem::pointer item = onlyBelow(&*node);
SHAMapItem::pointer item = onlyBelow(node.get());
if(item)
{
eraseChildren(node);
@@ -488,14 +495,15 @@ bool SHAMap::delItem(const uint256& id)
return true;
}
bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction)
bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta)
{ // add the specified item, does not update
#ifdef ST_DEBUG
std::cerr << "aGI " << item->getTag().GetHex() << std::endl;
#endif
uint256 tag = item->getTag();
SHAMapTreeNode::TNType type = isTransaction ? SHAMapTreeNode::tnTRANSACTION : SHAMapTreeNode::tnACCOUNT_STATE;
SHAMapTreeNode::TNType type = !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE :
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM);
boost::recursive_mutex::scoped_lock sl(mLock);
assert(mState != Immutable);
@@ -580,12 +588,12 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction)
return true;
}
bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction)
bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction, bool hasMetaData)
{
return addGiveItem(boost::make_shared<SHAMapItem>(i), isTransaction);
return addGiveItem(boost::make_shared<SHAMapItem>(i), isTransaction, hasMetaData);
}
bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction)
bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta)
{ // can't change the tag but can change the hash
uint256 tag = item->getTag();
@@ -605,7 +613,8 @@ bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction)
}
returnNode(node, true);
if (!node->setItem(item, isTransaction ? SHAMapTreeNode::tnTRANSACTION : SHAMapTreeNode::tnACCOUNT_STATE))
if (!node->setItem(item, !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE :
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM)))
{
Log(lsWARNING) << "SHAMap setItem, no change";
return true;
@@ -747,8 +756,8 @@ BOOST_AUTO_TEST_CASE( SHAMap_test )
SHAMap sMap;
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
if(!sMap.addItem(i2, true)) BOOST_FAIL("no add");
if(!sMap.addItem(i1, true)) BOOST_FAIL("no add");
if(!sMap.addItem(i2, true, false)) BOOST_FAIL("no add");
if(!sMap.addItem(i1, true, false)) BOOST_FAIL("no add");
SHAMapItem::pointer i;
@@ -759,9 +768,9 @@ BOOST_AUTO_TEST_CASE( SHAMap_test )
i = sMap.peekNextItem(i->getTag());
if (i) BOOST_FAIL("bad traverse");
sMap.addItem(i4, true);
sMap.addItem(i4, true, false);
sMap.delItem(i2.getTag());
sMap.addItem(i3, true);
sMap.addItem(i3, true, false);
i = sMap.peekFirstItem();
if (!i || (*i != i1)) BOOST_FAIL("bad traverse");

View File

@@ -135,8 +135,9 @@ public:
{
tnERROR = 0,
tnINNER = 1,
tnTRANSACTION = 2,
tnACCOUNT_STATE = 3
tnTRANSACTION_NM = 2, // transaction, no metadata
tnTRANSACTION_MD = 3, // transaction, with metadata
tnACCOUNT_STATE = 4
};
private:
@@ -173,11 +174,13 @@ public:
TNType getType() const { return mType; }
// type functions
bool isLeaf() const { return (mType == tnTRANSACTION) || (mType == tnACCOUNT_STATE); }
bool isLeaf() const { return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD) ||
(mType == tnACCOUNT_STATE); }
bool isInner() const { return mType == tnINNER; }
bool isValid() const { return mType != tnERROR; }
bool isTransaction() const { return mType != tnTRANSACTION; }
bool isAccountState() const { return mType != tnACCOUNT_STATE; }
bool isTransaction() const { return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD); }
bool hasMetaData() const { return mType == tnTRANSACTION_MD; }
bool isAccountState() const { return mType == tnACCOUNT_STATE; }
// inner node functions
bool isInnerNode() const { return !mItem; }
@@ -287,6 +290,7 @@ public:
// build new map
SHAMap(uint32 seq = 0);
SHAMap(const uint256& hash);
// Returns a new map that's a snapshot of this one. Force CoW
SHAMap::pointer snapShot(bool isMutable);
@@ -299,15 +303,15 @@ public:
// normal hash access functions
bool hasItem(const uint256& id);
bool delItem(const uint256& id);
bool addItem(const SHAMapItem& i, bool isTransaction);
bool updateItem(const SHAMapItem& i, bool isTransaction);
bool addItem(const SHAMapItem& i, bool isTransaction, bool hasMeta);
bool updateItem(const SHAMapItem& i, bool isTransaction, bool hasMeta);
SHAMapItem getItem(const uint256& id);
uint256 getHash() const { return root->getNodeHash(); }
uint256 getHash() { return root->getNodeHash(); }
// save a copy if you have a temporary anyway
bool updateGiveItem(SHAMapItem::pointer, bool isTransaction);
bool addGiveItem(SHAMapItem::pointer, bool isTransaction);
bool updateGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta);
bool addGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta);
// save a copy if you only need a temporary
SHAMapItem::pointer peekItem(const uint256& id);

View File

@@ -197,7 +197,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
Serializer s(rawNode);
int type = s.removeLastByte();
int len = s.getLength();
if ((type < 0) || (type > 3))
if ((type < 0) || (type > 4))
{
#ifdef DEBUG
std::cerr << "Invalid wire format node" << std::endl;
@@ -210,14 +210,14 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
if (type == 0)
{ // transaction
mItem = boost::make_shared<SHAMapItem>(s.getPrefixHash(sHP_TransactionID), s.peekData());
mType = tnTRANSACTION;
mType = tnTRANSACTION_NM;
}
else if (type == 1)
{ // account state
if (len < (256 / 8))
throw std::runtime_error("short AS node");
uint256 u;
s.get256(u, len - 32);
s.get256(u, len - (256 / 8));
s.chop(256 / 8);
if (u.isZero()) throw std::runtime_error("invalid AS node");
mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
@@ -242,6 +242,18 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
}
mType = tnINNER;
}
else if (type == 4)
{ // transaction with metadata
if (len < (256 / 8))
throw std::runtime_error("short TM node");
uint256 u;
s.get256(u, len - (256 / 8));
s.chop(256 / 8);
if (u.isZero())
throw std::runtime_error("invalid TM node");
mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
mType = tnTRANSACTION_MD;
}
}
if (format == STN_ARF_PREFIXED)
@@ -258,8 +270,8 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
if (prefix == sHP_TransactionID)
{
mItem = boost::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData());
mType = tnTRANSACTION;
mItem = boost::make_shared<SHAMapItem>(Serializer::getSHA512Half(rawNode), s.peekData());
mType = tnTRANSACTION_NM;
}
else if (prefix == sHP_LeafNode)
{
@@ -282,6 +294,13 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
s.get256(mHashes[i] , i * 32);
mType = tnINNER;
}
else if (prefix == sHP_TransactionNode)
{
uint256 txID; // WRITEME: Need code to extract transaction ID from TX+MD
assert(false);
mItem = boost::make_shared<SHAMapItem>(txID, s.peekData());
mType = tnTRANSACTION_MD;
}
else
{
Log(lsINFO) << "Unknown node prefix " << std::hex << prefix << std::dec;
@@ -310,16 +329,20 @@ bool SHAMapTreeNode::updateHash()
}
else if (mType == tnACCOUNT_STATE)
{
Serializer s;
Serializer s((256 + 32) / 8 + mItem->peekData().size());
s.add32(sHP_LeafNode);
mItem->addRaw(s);
s.add256(mItem->getTag());
nh = s.getSHA512Half();
}
else if (mType == tnTRANSACTION)
else if (mType == tnTRANSACTION_NM)
{
nh = Serializer::getPrefixHash(sHP_TransactionID, mItem->peekData());
}
else if (mType == tnTRANSACTION_MD)
{
nh = Serializer::getPrefixHash(sHP_TransactionNode, mItem->peekData());
}
else assert(false);
if (nh == mHash) return false;
@@ -375,7 +398,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
s.add8(1);
}
}
else if (mType == tnTRANSACTION)
else if (mType == tnTRANSACTION_NM)
{
if (format == STN_ARF_PREFIXED)
{
@@ -388,7 +411,22 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
s.add8(0);
}
}
else assert(false);
else if (mType == tnTRANSACTION_MD)
{
if (format == STN_ARF_PREFIXED)
{
s.add32(sHP_TransactionNode);
mItem->addRaw(s);
}
else
{
mItem->addRaw(s);
s.add256(mItem->getTag());
s.add8(4);
}
}
else
assert(false);
}
bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type)

View File

@@ -362,7 +362,7 @@ static bool confuseMap(SHAMap &map, int count)
{
SHAMapItem::pointer item = makeRandomAS();
items.push_back(item->getTag());
if (!map.addItem(*item, false))
if (!map.addItem(*item, false, false))
{
Log(lsFATAL) << "Unable to add item to map";
return false;
@@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test )
Log(lsTRACE) << "Adding random data";
int items = 10000;
for (int i = 0; i < items; ++i)
source.addItem(*makeRandomAS(), false);
source.addItem(*makeRandomAS(), false, false);
Log(lsTRACE) << "Adding items, then removing them";
if (!confuseMap(source, 500)) BOOST_FAIL("ConfuseMap");

View File

@@ -6,10 +6,8 @@
SOElement SerializedValidation::sValidationFormat[] = {
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
{ sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 },
{ sfCloseTime, "CloseTime", STI_UINT64, SOE_REQUIRED, 0 },
{ sfCloseTime, "CloseTime", STI_UINT32, SOE_REQUIRED, 0 },
{ sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 },
{ sfVersion, "Version", STI_UINT32, SOE_IFFLAG, 1 },
{ sfExtensions, "Extensions", STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 },
};
@@ -21,12 +19,12 @@ SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSi
if (checkSignature && !isValid()) throw std::runtime_error("Invalid validation");
}
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint64 closeTime,
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 closeTime,
const NewcoinAddress& naSeed, bool isFull)
: STObject(sValidationFormat), mSignature("Signature"), mTrusted(false)
{
setValueFieldH256(sfLedgerHash, ledgerHash);
setValueFieldU64(sfCloseTime, closeTime);
setValueFieldU32(sfCloseTime, closeTime);
if (naSeed.isValid())
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
if (!isFull) setFlag(sFullFlag);
@@ -52,9 +50,9 @@ uint256 SerializedValidation::getLedgerHash() const
return getValueFieldH256(sfLedgerHash);
}
uint64 SerializedValidation::getCloseTime() const
uint32 SerializedValidation::getCloseTime() const
{
return getValueFieldU64(sfCloseTime);
return getValueFieldU32(sfCloseTime);
}
bool SerializedValidation::isValid() const

View File

@@ -22,10 +22,10 @@ public:
SerializedValidation(SerializerIterator& sit, bool checkSignature = true);
SerializedValidation(const Serializer& s, bool checkSignature = true);
SerializedValidation(const uint256& ledgerHash, uint64 closeTime, const NewcoinAddress& naSeed, bool isFull);
SerializedValidation(const uint256& ledgerHash, uint32 closeTime, const NewcoinAddress& naSeed, bool isFull);
uint256 getLedgerHash() const;
uint64 getCloseTime() const;
uint32 getCloseTime() const;
NewcoinAddress getSignerPublic() const;
bool isValid() const;
bool isFull() const;

View File

@@ -32,8 +32,8 @@ public:
// assemble functions
int add8(unsigned char byte);
int add16(uint16);
int add32(uint32); // ledger indexes, account sequence
int add64(uint64); // timestamps, amounts
int add32(uint32); // ledger indexes, account sequence, timestamps
int add64(uint64); // native currency amounts
int add128(const uint128&); // private key generators
int add160(const uint160&); // account names, hankos
int add256(const uint256&); // transaction and ledger hashes

View File

@@ -476,18 +476,6 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac
return terSUCCESS;
}
Ledger::pointer TransactionEngine::getTransactionLedger(uint32 targetLedger)
{
Ledger::pointer ledger = mDefaultLedger;
if (mAlternateLedger && (targetLedger != 0) &&
(targetLedger != mLedger->getLedgerSeq()) && (targetLedger == mAlternateLedger->getLedgerSeq()))
{
Log(lsINFO) << "Transaction goes into wobble ledger";
ledger = mAlternateLedger;
}
return ledger;
}
bool TransactionEngine::entryExists(SLE::pointer sleEntry)
{
return mEntries.find(sleEntry) != mEntries.end();
@@ -576,16 +564,10 @@ void TransactionEngine::entryUnfunded(SLE::pointer sleEntry)
}
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
TransactionEngineParams params, uint32 targetLedger)
{
return applyTransaction(txn, params, getTransactionLedger(targetLedger));
}
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
TransactionEngineParams params, Ledger::pointer ledger)
TransactionEngineParams params)
{
Log(lsTRACE) << "applyTransaction>";
mLedger = ledger;
assert(mLedger);
mLedgerParentCloseTime = mLedger->getParentCloseTimeNC();
#ifdef DEBUG
@@ -724,12 +706,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
}
if (terSUCCESS != terResult)
{
// Avoid unnecessary locking.
mLedger = Ledger::pointer();
return terResult;
}
boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
@@ -1072,7 +1049,6 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
mLedger->destroyCoins(saPaid.getNValue());
}
mLedger = Ledger::pointer();
mEntries.clear();
return terResult;

View File

@@ -155,7 +155,6 @@ private:
STAmount& saTakerGot);
protected:
Ledger::pointer mDefaultLedger, mAlternateLedger;
Ledger::pointer mLedger;
uint64 mLedgerParentCloseTime;
@@ -189,20 +188,12 @@ protected:
public:
TransactionEngine() { ; }
TransactionEngine(Ledger::pointer ledger) : mDefaultLedger(ledger) { ; }
TransactionEngine(Ledger::pointer ledger) : mLedger(ledger) { ; }
Ledger::pointer getDefaultLedger() { return mDefaultLedger; }
void setDefaultLedger(Ledger::pointer ledger) { mDefaultLedger = ledger; }
Ledger::pointer getAlternateLedger() { return mAlternateLedger; }
void setAlternateLedger(Ledger::pointer ledger) { mAlternateLedger = ledger; }
void setLedger(Ledger::pointer ledger) { mDefaultLedger = ledger;
mAlternateLedger = Ledger::pointer(); }
Ledger::pointer getLedger() { return mLedger; }
void setLedger(Ledger::pointer ledger) { assert(ledger); mLedger = ledger; }
Ledger::pointer getTransactionLedger(uint32 targetLedger);
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams,
Ledger::pointer ledger);
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams,
uint32 targetLedger);
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams);
};
inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2)

View File

@@ -11,9 +11,9 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val)
if (theApp->getUNL().nodeInUNL(val->getSignerPublic()))
{
val->setTrusted();
uint64 now = theApp->getOPs().getNetworkTimeNC();
uint64 valClose = val->getCloseTime();
if ((now > valClose) && (now < (valClose + LEDGER_INTERVAL)))
uint32 now = theApp->getOPs().getNetworkTimeNC();
uint32 valClose = val->getCloseTime();
if ((now > valClose) && (now < (valClose + LEDGER_MAX_INTERVAL)))
isCurrent = true;
else
Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose;
@@ -55,19 +55,19 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren
trusted = untrusted = 0;
boost::mutex::scoped_lock sl(mValidationLock);
boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger);
uint64 now = theApp->getOPs().getNetworkTimeNC();
uint32 now = theApp->getOPs().getNetworkTimeNC();
if (it != mValidations.end())
{
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
{
bool trusted = vit->second->isTrusted();
if (trusted && currentOnly)
bool isTrusted = vit->second->isTrusted();
if (isTrusted && currentOnly)
{
uint64 closeTime = vit->second->getCloseTime();
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_INTERVAL)))
uint32 closeTime = vit->second->getCloseTime();
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_MAX_INTERVAL)))
trusted = false;
}
if (trusted)
if (isTrusted)
++trusted;
else
++untrusted;
@@ -75,9 +75,38 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren
}
}
int ValidationCollection::getTrustedValidationCount(const uint256& ledger)
{
int trusted = 0;
boost::mutex::scoped_lock sl(mValidationLock);
for (boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger),
end = mValidations.end(); it != end; ++it)
{
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
{
if (vit->second->isTrusted())
++trusted;
}
}
return trusted;
}
int ValidationCollection::getCurrentValidationCount(uint32 afterTime)
{
int count = 0;
boost::mutex::scoped_lock sl(mValidationLock);
for (boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin(),
end = mCurrentValidations.end(); it != end; ++it)
{
if (it->second->isTrusted() && (it->second->getCloseTime() > afterTime))
++count;
}
return count;
}
boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
{
uint64 now = theApp->getOPs().getNetworkTimeNC();
uint32 now = theApp->getOPs().getNetworkTimeNC();
boost::unordered_map<uint256, int> ret;
{
@@ -85,14 +114,10 @@ boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
while (it != mCurrentValidations.end())
{
if (now > (it->second->getCloseTime() + LEDGER_INTERVAL))
{
Log(lsTRACE) << "Erasing validation for " << it->second->getLedgerHash().GetHex();
if (now > (it->second->getCloseTime() + LEDGER_MAX_INTERVAL))
it = mCurrentValidations.erase(it);
}
else
{
Log(lsTRACE) << "Counting validation for " << it->second->getLedgerHash().GetHex();
++ret[it->second->getLedgerHash()];
++it;
}

View File

@@ -24,6 +24,8 @@ public:
bool addValidation(SerializedValidation::pointer);
ValidationSet getValidations(const uint256& ledger);
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted);
int getTrustedValidationCount(const uint256& ledger);
int getCurrentValidationCount(uint32 afterTime);
boost::unordered_map<uint256, int> getCurrentValidations();
};

View File

@@ -4,9 +4,8 @@
// Versions
//
// Version of this software:
#define SERVER_VERSION_MAJOR 0
#define SERVER_VERSION_MINOR 1
#define SERVER_VERSION_MINOR 3
#define SERVER_VERSION_SUB "-a"
#define SERVER_NAME "NewCoin"
@@ -17,11 +16,11 @@
// Version we prefer to speak:
#define PROTO_VERSION_MAJOR 0
#define PROTO_VERSION_MINOR 2
#define PROTO_VERSION_MINOR 3
// Version we wil speak to:
#define MIN_PROTO_MAJOR 0
#define MIN_PROTO_MINOR 2
#define MIN_PROTO_MINOR 3
#define MAKE_VERSION_INT(maj,min) ((maj << 16) | min)
#define GET_VERSION_MAJOR(ver) (ver >> 16)

View File

@@ -91,6 +91,7 @@ int main(int argc, char* argv[])
("rpc", "Perform rpc command (default).")
("test,t", "Perform unit tests.")
("parameters", po::value< vector<string> >(), "Specify comma separated parameters.")
("verbose,v", "Increase log level")
;
// Interpret positional arguments as --parameters.
@@ -132,6 +133,11 @@ int main(int argc, char* argv[])
}
}
if (vm.count("verbose"))
{
Log::setMinSeverity(lsTRACE);
}
if (!iResult)
{
theConfig.setup(vm.count("conf") ? vm["conf"].as<std::string>() : "");

View File

@@ -105,9 +105,10 @@ message TMProposeSet {
required uint32 proposeSeq = 1;
required bytes currentTxHash = 2; // the hash of the ledger we are proposing
required bytes nodePubKey = 3;
required bytes signature = 4; // signature of above fields
repeated bytes addedTransactions = 5; // not required if number is large
repeated bytes removedTransactions = 6; // not required if number is large
required uint32 closeTime = 4;
required bytes signature = 5; // signature of above fields
repeated bytes addedTransactions = 6; // not required if number is large
repeated bytes removedTransactions = 7; // not required if number is large
}
enum TxSetStatus {