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,19 +129,23 @@ void Application::run()
Log(lsINFO) << "Root master seed: " << rootSeedMaster.humanSeed(); Log(lsINFO) << "Root master seed: " << rootSeedMaster.humanSeed();
Log(lsINFO) << "Root account: " << rootAddress.humanAccountID(); Log(lsINFO) << "Root account: " << rootAddress.humanAccountID();
Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, SYSTEM_CURRENCY_START); {
assert(!!firstLedger->getAccountState(rootAddress)); Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, SYSTEM_CURRENCY_START);
firstLedger->updateHash(); assert(!!firstLedger->getAccountState(rootAddress));
firstLedger->setClosed(); firstLedger->updateHash();
firstLedger->setAccepted(); firstLedger->setClosed();
mMasterLedger.pushLedger(firstLedger); firstLedger->setAccepted();
mMasterLedger.pushLedger(firstLedger);
Ledger::pointer secondLedger = boost::make_shared<Ledger>(true, boost::ref(*firstLedger)); Ledger::pointer secondLedger = boost::make_shared<Ledger>(true, boost::ref(*firstLedger));
mMasterLedger.pushLedger(secondLedger); secondLedger->setClosed();
assert(!!secondLedger->getAccountState(rootAddress)); secondLedger->setAccepted();
// temporary mMasterLedger.pushLedger(secondLedger, boost::make_shared<Ledger>(true, boost::ref(*secondLedger)));
assert(!!secondLedger->getAccountState(rootAddress));
mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC());
}
mNetOps.setStateTimer(0); mNetOps.setStateTimer();
mIOService.run(); // This blocks 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, \ LedgerSeq BIGINT UNSIGNED, \
PrevHash CHARACTER(64), \ PrevHash CHARACTER(64), \
TotalCoins BIGINT UNSIGNED, \ TotalCoins BIGINT UNSIGNED, \
ClosingTime BIGINT UNSINGED, \ ClosingTime BIGINT UNSIGNED, \
PrevClosingTime BIGINT UNSIGNED, \
CloseTimeRes BIGINT UNSIGNED, \
CloseFlags, BIGINT UNSIGNED, \
AccountSetHash CHARACTER(64), \ AccountSetHash CHARACTER(64), \
TransSetHash CHARACTER(64) \ TransSetHash CHARACTER(64) \
);", );",

View File

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

View File

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

View File

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

View File

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

View File

@@ -65,7 +65,7 @@ public:
protected: protected:
Ledger::pointer mLedger; Ledger::pointer mLedger;
bool mHaveBase, mHaveState, mHaveTransactions; bool mHaveBase, mHaveState, mHaveTransactions, mAborted;
std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete; std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete;
@@ -83,6 +83,7 @@ public:
bool isAcctStComplete() const { return mHaveState; } bool isAcctStComplete() const { return mHaveState; }
bool isTransComplete() const { return mHaveTransactions; } bool isTransComplete() const { return mHaveTransactions; }
Ledger::pointer getLedger() { return mLedger; } Ledger::pointer getLedger() { return mLedger; }
void abort() { mAborted = true; }
void addOnComplete(boost::function<void (LedgerAcquire::pointer)>); 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 { // this many seconds after close, should our position change
if (mOurPosition && (mNays == 0)) if (mOurPosition && (mNays == 0))
return false; return false;
@@ -169,9 +169,9 @@ bool LCTransaction::updatePosition(int seconds, bool proposing)
int weight = (mYays * 100 + (mOurPosition ? 100 : 0)) / (mNays + mYays + 1); int weight = (mYays * 100 + (mOurPosition ? 100 : 0)) / (mNays + mYays + 1);
// To prevent avalanche stalls, we increase the needed weight slightly over time // To prevent avalanche stalls, we increase the needed weight slightly over time
if (seconds <= LEDGER_ACCEL_CONVERGE) newPosition = weight > AV_MIN_CONSENSUS; if (percentTime < AV_MID_CONSENSUS_TIME) newPosition = weight > AV_INIT_CONSENSUS_PCT;
else if (seconds >= LEDGER_CONVERGE) newPosition = weight > AV_AVG_CONSENSUS; else if (percentTime < AV_LATE_CONSENSUS_TIME) newPosition = weight > AV_MID_CONSENSUS_PCT;
else newPosition = weight > AV_MAX_CONSENSUS; else newPosition = weight > AV_LATE_CONSENSUS_PCT;
} }
else // don't let us outweight a proposing node, just recognize consensus else // don't let us outweight a proposing node, just recognize consensus
newPosition = mYays > mNays; newPosition = mYays > mNays;
@@ -189,26 +189,41 @@ bool LCTransaction::updatePosition(int seconds, bool proposing)
return true; 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) 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; mValSeed = theConfig.VALIDATION_SEED;
Log(lsDEBUG) << "Creating consensus object"; Log(lsDEBUG) << "Creating consensus object";
Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime; 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; 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()) else if (mValSeed.isValid())
{ {
mValidating = true; mHaveCorrectLCL = mValidating = true;
mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL; mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL;
} }
else mProposing = mValidating = false; else
{
mHaveCorrectLCL = true;
mProposing = mValidating = false;
}
} }
void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger) void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
@@ -233,9 +248,9 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
if (mValidating) if (mValidating)
mOurPosition = boost::make_shared<LedgerProposal> mOurPosition = boost::make_shared<LedgerProposal>
(mValSeed, initialLedger->getParentHash(), txSet); (mValSeed, initialLedger->getParentHash(), txSet, mCloseTime);
else else
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet); mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet, mCloseTime);
mapComplete(txSet, initialSet, false); mapComplete(txSet, initialSet, false);
if (mProposing) propose(std::vector<uint256>(), std::vector<uint256>()); 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"; Log(lsINFO) << "send status change to peer";
} }
void LedgerConsensus::abort()
{
Log(lsWARNING) << "consensus aborted";
mState = lcsABORTED;
}
int LedgerConsensus::startup() int LedgerConsensus::startup()
{ {
// create wobble ledger in case peers target transactions to it
theApp->getMasterLedger().beginWobble();
return 1; return 1;
} }
int LedgerConsensus::statePreClose(int secondsSinceClose) void LedgerConsensus::statePreClose()
{ // it is shortly before ledger close time { // it is shortly before ledger close time
if (secondsSinceClose >= 0) bool anyTransactions = theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap()->getHash().isNonZero();
{ // it is time to close the ledger (swap default and wobble ledgers) int proposersClosed = mPeerPositions.size();
Log(lsINFO) << "Closing ledger";
mState = lcsPOST_CLOSE;
theApp->getMasterLedger().closeTime();
statusChange(newcoin::neCLOSING_LEDGER, mPreviousLedger);
}
return 1;
}
int LedgerConsensus::statePostClose(int secondsSinceClose) int sinceClose = theApp->getOPs().getNetworkTimeNC() - theApp->getOPs().getLastCloseNetTime();
{ // we are in the transaction wobble time
if (secondsSinceClose > LEDGER_WOBBLE_TIME) if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed,
{ mPreviousSeconds, sinceClose))
Log(lsINFO) << "Wobble is over, it's consensus time"; { // it is time to close the ledger (swap default and wobble ledgers)
Log(lsINFO) << "CLC:: closing ledger";
mState = lcsESTABLISH; 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()); assert (initial->getParentHash() == mPreviousLedger->getHash());
takeInitialPosition(initial); takeInitialPosition(initial);
} }
return 1;
} }
int LedgerConsensus::stateEstablish(int secondsSinceClose) void LedgerConsensus::stateEstablish()
{ // we are establishing consensus { // we are establishing consensus
if (mProposing) if (mCurrentSeconds < LEDGER_MIN_CONSENSUS)
updateOurPositions(secondsSinceClose); return;
if (secondsSinceClose > LEDGER_MAX_CONVERGE) updateOurPositions();
if (!mHaveCloseTimeConsensus)
{
Log(lsINFO) << "No close time consensus";
}
else if (haveConsensus())
{ {
Log(lsINFO) << "Converge cutoff"; 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; mState = lcsFINISHED;
beginAccept(); beginAccept();
} }
return 1;
} }
int LedgerConsensus::stateFinished(int secondsSinceClose) void LedgerConsensus::stateFinished()
{ // we are processing the finished ledger { // we are processing the finished ledger
// logic of calculating next ledger advances us out of this state // 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 { // we have accepted a new ledger
endConsensus(); endConsensus();
return 4;
} }
int LedgerConsensus::timerEntry() void LedgerConsensus::timerEntry()
{ {
if (!mHaveCorrectLCL) if (!mHaveCorrectLCL)
{ {
Log(lsINFO) << "Checking for consensus ledger " << mPrevLedgerHash.GetHex();
Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash); Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash);
if (consensus) if (consensus)
{ {
@@ -429,45 +430,42 @@ int LedgerConsensus::timerEntry()
mPreviousLedger = consensus; mPreviousLedger = consensus;
mHaveCorrectLCL = true; 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) switch (mState)
{ {
case lcsPRE_CLOSE: return statePreClose(sinceClose); case lcsPRE_CLOSE: statePreClose(); return;
case lcsPOST_CLOSE: return statePostClose(sinceClose); case lcsESTABLISH: stateEstablish(); return;
case lcsESTABLISH: return stateEstablish(sinceClose); case lcsFINISHED: stateFinished(); return;
case lcsCUTOFF: return stateCutoff(sinceClose); case lcsACCEPTED: stateAccepted(); return;
case lcsFINISHED: return stateFinished(sinceClose);
case lcsACCEPTED: return stateAccepted(sinceClose);
case lcsABORTED: return 1;
} }
assert(false); assert(false);
return 1;
} }
bool LedgerConsensus::updateOurPositions(int sinceClose) void LedgerConsensus::updateOurPositions()
{ // returns true if the network has consensus {
Log(lsINFO) << "Updating our positions";
bool changes = false; bool changes = false;
bool stable = true;
SHAMap::pointer ourPosition; SHAMap::pointer ourPosition;
std::vector<uint256> addedTx, removedTx; std::vector<uint256> addedTx, removedTx;
for(boost::unordered_map<uint256, LCTransaction::pointer>::iterator it = mDisputes.begin(), for(boost::unordered_map<uint256, LCTransaction::pointer>::iterator it = mDisputes.begin(),
end = mDisputes.end(); it != end; ++it) end = mDisputes.end(); it != end; ++it)
{ {
if (it->second->updatePosition(sinceClose, mProposing)) if (it->second->updatePosition(mClosePercent, mProposing))
{ {
if (!changes) if (!changes)
{ {
ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true);
changes = true; changes = true;
stable = false;
} }
if (it->second->getOurPosition()) // now a yes 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); addedTx.push_back(it->first);
} }
else // now a no else // now a no
@@ -476,20 +474,60 @@ bool LedgerConsensus::updateOurPositions(int sinceClose)
removedTx.push_back(it->first); 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) if (changes)
{ {
uint256 newHash = ourPosition->getHash(); uint256 newHash = ourPosition->getHash();
mOurPosition->changePosition(newHash); mOurPosition->changePosition(newHash, closeTime);
if (mProposing) propose(addedTx, removedTx); if (mProposing) propose(addedTx, removedTx);
mapComplete(newHash, ourPosition, false); mapComplete(newHash, ourPosition, false);
Log(lsINFO) << "We change our position to " << newHash.GetHex(); 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) 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; newcoin::TMProposeSet prop;
prop.set_currenttxhash(mOurPosition->getCurrentHash().begin(), 256 / 8); prop.set_currenttxhash(mOurPosition->getCurrentHash().begin(), 256 / 8);
prop.set_proposeseq(mOurPosition->getProposeSeq()); prop.set_proposeseq(mOurPosition->getProposeSeq());
prop.set_closetime(mOurPosition->getCloseTime());
std::vector<unsigned char> pubKey = mOurPosition->getPubKey(); std::vector<unsigned char> pubKey = mOurPosition->getPubKey();
std::vector<unsigned char> sig = mOurPosition->sign(); 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) bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
{ {
LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()]; LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()];
if (currentPosition) if (currentPosition)
{ {
assert(newPosition->getPeerID() == currentPosition->getPeerID()); assert(newPosition->getPeerID() == currentPosition->getPeerID());
@@ -598,6 +638,10 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
return true; return true;
} }
} }
else if (newPosition->getProposeSeq() == 0)
{ // new initial close time estimate
++mCloseTimes[newPosition->getCloseTime()];
}
Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/" Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/"
<< newPosition->getCurrentHash().GetHex(); << newPosition->getCurrentHash().GetHex();
currentPosition = newPosition; currentPosition = newPosition;
@@ -666,7 +710,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran
try try
{ {
#endif #endif
TransactionEngineResult result = engine.applyTransaction(*txn, parms, 0); TransactionEngineResult result = engine.applyTransaction(*txn, parms);
if (result > 0) if (result > 0)
{ {
Log(lsINFO) << " retry"; Log(lsINFO) << " retry";
@@ -725,7 +769,7 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer led
{ {
try try
{ {
TransactionEngineResult result = engine.applyTransaction(*it->second, parms, 0); TransactionEngineResult result = engine.applyTransaction(*it->second, parms);
if (result <= 0) if (result <= 0)
{ {
if (result == 0) ++successes; if (result == 0) ++successes;
@@ -758,7 +802,16 @@ void LedgerConsensus::accept(SHAMap::pointer set)
CanonicalTXSet failedTransactions(set->getHash()); CanonicalTXSet failedTransactions(set->getHash());
applyTransactions(set, newLCL, failedTransactions, true); applyTransactions(set, newLCL, failedTransactions, true);
newLCL->setClosed(); 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(); newLCL->updateHash();
uint256 newLCLHash = newLCL->getHash(); uint256 newLCLHash = newLCL->getHash();
Log(lsTRACE) << "newLCL " << newLCLHash.GetHex(); Log(lsTRACE) << "newLCL " << newLCLHash.GetHex();
@@ -804,6 +857,7 @@ void LedgerConsensus::accept(SHAMap::pointer set)
applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL, applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL,
failedTransactions, false); failedTransactions, false);
theApp->getMasterLedger().pushLedger(newLCL, newOL); theApp->getMasterLedger().pushLedger(newLCL, newOL);
mNewLedgerHash = newLCL->getHash();
mState = lcsACCEPTED; mState = lcsACCEPTED;
sl.unlock(); sl.unlock();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,34 +1,55 @@
#include "LedgerTiming.h" #include "LedgerTiming.h"
#include <cassert>
// Returns the number of seconds the ledger should be be open. #include <boost/format.hpp>
int ContinuousLedgerTiming::shouldClose( // How many:
#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, bool anyTransactions,
int previousProposers, // proposers there were in the last closing int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed their ledgers int proposersClosed, // proposers who have currently closed this ledgers
int previousOpenSeconds, // seconds the previous ledger was open int previousSeconds, // seconds the previous ledger took to reach consensus
int currentOpenSeconds) // seconds since the previous ledger closed 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) if (!anyTransactions)
{ // no transactions so far this interval { // no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction? 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 Log(lsTRACE) << "no transactions, many proposers: now";
return previousOpenSeconds - 1; 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 return LEDGER_IDLE_INTERVAL; // normal idle
} }
if (previousOpenSeconds == LEDGER_IDLE_INTERVAL) // coming out of idle, close now if (previousSeconds == LEDGER_IDLE_INTERVAL) // coming out of idle, close now
return currentOpenSeconds; {
Log(lsTRACE) << "leaving idle, close now";
return currentSeconds;
}
// If the network is slow, try to synchronize close times Log(lsTRACE) << "close now";
if (previousOpenSeconds > 8) return currentSeconds; // this ledger should close now
return (currentOpenSeconds - currentOpenSeconds % 4);
else if (previousOpenSeconds > 4)
return (currentOpenSeconds - currentOpenSeconds % 2);
return currentOpenSeconds; // this ledger should close now
} }
// Returns whether we have a consensus or not. If so, we expect all honest nodes // 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 previousAgreeTime, // how long it took to agree on the last ledger
int currentAgreeTime) // how long we've been trying to agree int currentAgreeTime) // how long we've been trying to agree
{ {
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)) if (currentProposers < (previousProposers * 3 / 4))
{ // Less than 3/4 of the validators are present, slow down { // Less than 3/4 of the last ledger's proposers are present, we may need more time
if (currentAgreeTime < (previousAgreeTime + 2)) if (currentAgreeTime < (previousAgreeTime + 2))
{
Log(lsTRACE) << "too fast, not enough proposers";
return false; return false;
}
} }
// If 80% of current proposers (plus us) agree on a set, we have consensus // If 80% of current proposers (plus us) agree on a set, we have consensus
int agreeWeight = (currentAgree * 100 + 100) / (currentProposers + 1); if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
if (agreeWeight > 80) {
Log(lsTRACE) << "normal consensus";
return true; return true;
}
// If 50% of the nodes on your UNL (minus us) have closed, you should close // If 50% of the nodes on your UNL (minus us) have closed, you should close
int closeWeight = (currentClosed * 100 - 100) / (currentProposers + 1); if (((currentClosed * 100 - 100) / (currentProposers + 1)) > 50)
if (closeWeight > 50) {
Log(lsTRACE) << "many closers";
return true; return true;
}
// no consensus yet
Log(lsTRACE) << "no consensus";
return false; 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__ #ifndef __LEDGERTIMING__
#define __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 // The number of seconds a ledger may remain idle before closing
# define LEDGER_IDLE_INTERVAL 15 # define LEDGER_IDLE_INTERVAL 15
// How long we wait to transition from inactive to active // The number of seconds a validation remains current
# define LEDGER_IDLE_SPIN_TIME 2 # define LEDGER_MAX_INTERVAL 60
// Avalance tuning (percent of UNL voting yes for us to vote yes) // The number of seconds we wait minimum to ensure participation
#define AV_MIN_CONSENSUS 55 # define LEDGER_MIN_CONSENSUS 2
#define AV_AVG_CONSENSUS 65
#define AV_MAX_CONSENSUS 70 // 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 class ContinuousLedgerTiming
{ {
public: public:
static int LedgerTimeResolution[];
// Returns the number of seconds the ledger was or should be open // 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 // Call when a consensus is reached and when any transaction is relayed to be added
static int shouldClose( static int shouldClose(
bool anyTransactions, bool anyTransactions,
int previousProposers, int proposersClosed, int previousProposers, int proposersClosed,
int previousOpenSeconds, int currentOpenSeconds); int previousSeconds, int currentSeconds);
static bool haveConsensus( static bool haveConsensus(
int previousProposers, int currentProposers, int previousProposers, int currentProposers,
int currentAgree, int currentClosed, int currentAgree, int currentClosed,
int previousAgreeTime, int currentAgreeTime); int previousAgreeTime, int currentAgreeTime);
static int getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq);
}; };
// END LEDGER_CLOSE_CONTINUOUS
#endif #endif

View File

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

View File

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

View File

@@ -571,14 +571,15 @@ void Peer::recvHello(newcoin::TMHello& packet)
// Cancel verification timeout. // Cancel verification timeout.
(void) mVerifyTimer.cancel(); (void) mVerifyTimer.cancel();
uint64 minTime = theApp->getOPs().getNetworkTimeNC() - 4; uint32 minTime = theApp->getOPs().getNetworkTimeNC() - 4;
uint64 maxTime = minTime + 8; uint32 maxTime = minTime + 8;
if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime))) 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 " << Log(lsINFO) << "Recv(Hello): Server requires protocol version " <<
GET_VERSION_MAJOR(packet.protoversion()) << "." << GET_VERSION_MINOR(packet.protoversion()) GET_VERSION_MAJOR(packet.protoversion()) << "." << GET_VERSION_MINOR(packet.protoversion())
@@ -716,7 +717,8 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet)
uint256 currentTxHash; uint256 currentTxHash;
memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32); 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 { // FIXME: Not all nodes will want proposals
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, newcoin::mtPROPOSE_LEDGER); PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, newcoin::mtPROPOSE_LEDGER);
theApp->getConnectionPool().relayMessage(this, message); theApp->getConnectionPool().relayMessage(this, message);
@@ -889,7 +891,7 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet)
if (packet.newevent() == newcoin::neLOST_SYNC) if (packet.newevent() == newcoin::neLOST_SYNC)
{ {
Log(lsTRACE) << "peer has lost sync" << getIP(); Log(lsTRACE) << "peer has lost sync " << getIP();
mPreviousLedgerHash.zero(); mPreviousLedgerHash.zero();
mClosedLedgerHash.zero(); mClosedLedgerHash.zero();
return; return;
@@ -1111,6 +1113,11 @@ void Peer::recvLedger(newcoin::TMLedgerData& packet)
punishPeer(PP_UNWANTED_DATA); 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. // Get session information we can sign to prevent man in the middle attack.
// (both sides get the same information, neither side controls it) // (both sides get the same information, neither side controls it)
void Peer::getSessionCookie(std::string& strDst) void Peer::getSessionCookie(std::string& strDst)

View File

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

View File

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

View File

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

View File

@@ -197,7 +197,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
Serializer s(rawNode); Serializer s(rawNode);
int type = s.removeLastByte(); int type = s.removeLastByte();
int len = s.getLength(); int len = s.getLength();
if ((type < 0) || (type > 3)) if ((type < 0) || (type > 4))
{ {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "Invalid wire format node" << std::endl; std::cerr << "Invalid wire format node" << std::endl;
@@ -210,14 +210,14 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
if (type == 0) if (type == 0)
{ // transaction { // transaction
mItem = boost::make_shared<SHAMapItem>(s.getPrefixHash(sHP_TransactionID), s.peekData()); mItem = boost::make_shared<SHAMapItem>(s.getPrefixHash(sHP_TransactionID), s.peekData());
mType = tnTRANSACTION; mType = tnTRANSACTION_NM;
} }
else if (type == 1) else if (type == 1)
{ // account state { // account state
if (len < (256 / 8)) if (len < (256 / 8))
throw std::runtime_error("short AS node"); throw std::runtime_error("short AS node");
uint256 u; uint256 u;
s.get256(u, len - 32); s.get256(u, len - (256 / 8));
s.chop(256 / 8); s.chop(256 / 8);
if (u.isZero()) throw std::runtime_error("invalid AS node"); if (u.isZero()) throw std::runtime_error("invalid AS node");
mItem = boost::make_shared<SHAMapItem>(u, s.peekData()); mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
@@ -242,6 +242,18 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
} }
mType = tnINNER; 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) if (format == STN_ARF_PREFIXED)
@@ -258,8 +270,8 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
if (prefix == sHP_TransactionID) if (prefix == sHP_TransactionID)
{ {
mItem = boost::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData()); mItem = boost::make_shared<SHAMapItem>(Serializer::getSHA512Half(rawNode), s.peekData());
mType = tnTRANSACTION; mType = tnTRANSACTION_NM;
} }
else if (prefix == sHP_LeafNode) else if (prefix == sHP_LeafNode)
{ {
@@ -271,7 +283,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
Log(lsINFO) << "invalid PLN node"; Log(lsINFO) << "invalid PLN node";
throw std::runtime_error("invalid PLN node"); throw std::runtime_error("invalid PLN node");
} }
mItem = boost::make_shared<SHAMapItem>(u, s.peekData()); mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
mType = tnACCOUNT_STATE; mType = tnACCOUNT_STATE;
} }
else if (prefix == sHP_InnerNode) else if (prefix == sHP_InnerNode)
@@ -282,6 +294,13 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
s.get256(mHashes[i] , i * 32); s.get256(mHashes[i] , i * 32);
mType = tnINNER; 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 else
{ {
Log(lsINFO) << "Unknown node prefix " << std::hex << prefix << std::dec; Log(lsINFO) << "Unknown node prefix " << std::hex << prefix << std::dec;
@@ -310,16 +329,20 @@ bool SHAMapTreeNode::updateHash()
} }
else if (mType == tnACCOUNT_STATE) else if (mType == tnACCOUNT_STATE)
{ {
Serializer s; Serializer s((256 + 32) / 8 + mItem->peekData().size());
s.add32(sHP_LeafNode); s.add32(sHP_LeafNode);
mItem->addRaw(s); mItem->addRaw(s);
s.add256(mItem->getTag()); s.add256(mItem->getTag());
nh = s.getSHA512Half(); nh = s.getSHA512Half();
} }
else if (mType == tnTRANSACTION) else if (mType == tnTRANSACTION_NM)
{ {
nh = Serializer::getPrefixHash(sHP_TransactionID, mItem->peekData()); nh = Serializer::getPrefixHash(sHP_TransactionID, mItem->peekData());
} }
else if (mType == tnTRANSACTION_MD)
{
nh = Serializer::getPrefixHash(sHP_TransactionNode, mItem->peekData());
}
else assert(false); else assert(false);
if (nh == mHash) return false; if (nh == mHash) return false;
@@ -375,7 +398,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
s.add8(1); s.add8(1);
} }
} }
else if (mType == tnTRANSACTION) else if (mType == tnTRANSACTION_NM)
{ {
if (format == STN_ARF_PREFIXED) if (format == STN_ARF_PREFIXED)
{ {
@@ -388,7 +411,22 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
s.add8(0); 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) 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(); SHAMapItem::pointer item = makeRandomAS();
items.push_back(item->getTag()); items.push_back(item->getTag());
if (!map.addItem(*item, false)) if (!map.addItem(*item, false, false))
{ {
Log(lsFATAL) << "Unable to add item to map"; Log(lsFATAL) << "Unable to add item to map";
return false; return false;
@@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test )
Log(lsTRACE) << "Adding random data"; Log(lsTRACE) << "Adding random data";
int items = 10000; int items = 10000;
for (int i = 0; i < items; ++i) for (int i = 0; i < items; ++i)
source.addItem(*makeRandomAS(), false); source.addItem(*makeRandomAS(), false, false);
Log(lsTRACE) << "Adding items, then removing them"; Log(lsTRACE) << "Adding items, then removing them";
if (!confuseMap(source, 500)) BOOST_FAIL("ConfuseMap"); if (!confuseMap(source, 500)) BOOST_FAIL("ConfuseMap");

View File

@@ -6,10 +6,8 @@
SOElement SerializedValidation::sValidationFormat[] = { SOElement SerializedValidation::sValidationFormat[] = {
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 }, { sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
{ sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 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 }, { 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 }, { 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"); 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) const NewcoinAddress& naSeed, bool isFull)
: STObject(sValidationFormat), mSignature("Signature"), mTrusted(false) : STObject(sValidationFormat), mSignature("Signature"), mTrusted(false)
{ {
setValueFieldH256(sfLedgerHash, ledgerHash); setValueFieldH256(sfLedgerHash, ledgerHash);
setValueFieldU64(sfCloseTime, closeTime); setValueFieldU32(sfCloseTime, closeTime);
if (naSeed.isValid()) if (naSeed.isValid())
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic()); setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
if (!isFull) setFlag(sFullFlag); if (!isFull) setFlag(sFullFlag);
@@ -52,9 +50,9 @@ uint256 SerializedValidation::getLedgerHash() const
return getValueFieldH256(sfLedgerHash); return getValueFieldH256(sfLedgerHash);
} }
uint64 SerializedValidation::getCloseTime() const uint32 SerializedValidation::getCloseTime() const
{ {
return getValueFieldU64(sfCloseTime); return getValueFieldU32(sfCloseTime);
} }
bool SerializedValidation::isValid() const bool SerializedValidation::isValid() const

View File

@@ -22,10 +22,10 @@ public:
SerializedValidation(SerializerIterator& sit, bool checkSignature = true); SerializedValidation(SerializerIterator& sit, bool checkSignature = true);
SerializedValidation(const Serializer& s, 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; uint256 getLedgerHash() const;
uint64 getCloseTime() const; uint32 getCloseTime() const;
NewcoinAddress getSignerPublic() const; NewcoinAddress getSignerPublic() const;
bool isValid() const; bool isValid() const;
bool isFull() const; bool isFull() const;

View File

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

View File

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

View File

@@ -155,7 +155,6 @@ private:
STAmount& saTakerGot); STAmount& saTakerGot);
protected: protected:
Ledger::pointer mDefaultLedger, mAlternateLedger;
Ledger::pointer mLedger; Ledger::pointer mLedger;
uint64 mLedgerParentCloseTime; uint64 mLedgerParentCloseTime;
@@ -189,20 +188,12 @@ protected:
public: public:
TransactionEngine() { ; } TransactionEngine() { ; }
TransactionEngine(Ledger::pointer ledger) : mDefaultLedger(ledger) { ; } TransactionEngine(Ledger::pointer ledger) : mLedger(ledger) { ; }
Ledger::pointer getDefaultLedger() { return mDefaultLedger; } Ledger::pointer getLedger() { return mLedger; }
void setDefaultLedger(Ledger::pointer ledger) { mDefaultLedger = ledger; } void setLedger(Ledger::pointer ledger) { assert(ledger); mLedger = 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 getTransactionLedger(uint32 targetLedger); TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams);
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams,
Ledger::pointer ledger);
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams,
uint32 targetLedger);
}; };
inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2) 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())) if (theApp->getUNL().nodeInUNL(val->getSignerPublic()))
{ {
val->setTrusted(); val->setTrusted();
uint64 now = theApp->getOPs().getNetworkTimeNC(); uint32 now = theApp->getOPs().getNetworkTimeNC();
uint64 valClose = val->getCloseTime(); uint32 valClose = val->getCloseTime();
if ((now > valClose) && (now < (valClose + LEDGER_INTERVAL))) if ((now > valClose) && (now < (valClose + LEDGER_MAX_INTERVAL)))
isCurrent = true; isCurrent = true;
else else
Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose;
@@ -55,19 +55,19 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren
trusted = untrusted = 0; trusted = untrusted = 0;
boost::mutex::scoped_lock sl(mValidationLock); boost::mutex::scoped_lock sl(mValidationLock);
boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger); boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger);
uint64 now = theApp->getOPs().getNetworkTimeNC(); uint32 now = theApp->getOPs().getNetworkTimeNC();
if (it != mValidations.end()) if (it != mValidations.end())
{ {
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit) for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
{ {
bool trusted = vit->second->isTrusted(); bool isTrusted = vit->second->isTrusted();
if (trusted && currentOnly) if (isTrusted && currentOnly)
{ {
uint64 closeTime = vit->second->getCloseTime(); uint32 closeTime = vit->second->getCloseTime();
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_INTERVAL))) if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_MAX_INTERVAL)))
trusted = false; trusted = false;
} }
if (trusted) if (isTrusted)
++trusted; ++trusted;
else else
++untrusted; ++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() boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
{ {
uint64 now = theApp->getOPs().getNetworkTimeNC(); uint32 now = theApp->getOPs().getNetworkTimeNC();
boost::unordered_map<uint256, int> ret; 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(); boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
while (it != mCurrentValidations.end()) while (it != mCurrentValidations.end())
{ {
if (now > (it->second->getCloseTime() + LEDGER_INTERVAL)) if (now > (it->second->getCloseTime() + LEDGER_MAX_INTERVAL))
{
Log(lsTRACE) << "Erasing validation for " << it->second->getLedgerHash().GetHex();
it = mCurrentValidations.erase(it); it = mCurrentValidations.erase(it);
}
else else
{ {
Log(lsTRACE) << "Counting validation for " << it->second->getLedgerHash().GetHex();
++ret[it->second->getLedgerHash()]; ++ret[it->second->getLedgerHash()];
++it; ++it;
} }

View File

@@ -24,6 +24,8 @@ public:
bool addValidation(SerializedValidation::pointer); bool addValidation(SerializedValidation::pointer);
ValidationSet getValidations(const uint256& ledger); ValidationSet getValidations(const uint256& ledger);
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); 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(); boost::unordered_map<uint256, int> getCurrentValidations();
}; };

View File

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

View File

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

View File

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