mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'continuousClose'
Conflicts: src/LedgerAcquire.cpp src/NetworkOPs.h Merge continuous ledger close into main branch. YAY!
This commit is contained in:
@@ -129,6 +129,7 @@ void Application::run()
|
||||
Log(lsINFO) << "Root master seed: " << rootSeedMaster.humanSeed();
|
||||
Log(lsINFO) << "Root account: " << rootAddress.humanAccountID();
|
||||
|
||||
{
|
||||
Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, SYSTEM_CURRENCY_START);
|
||||
assert(!!firstLedger->getAccountState(rootAddress));
|
||||
firstLedger->updateHash();
|
||||
@@ -137,11 +138,14 @@ void Application::run()
|
||||
mMasterLedger.pushLedger(firstLedger);
|
||||
|
||||
Ledger::pointer secondLedger = boost::make_shared<Ledger>(true, boost::ref(*firstLedger));
|
||||
mMasterLedger.pushLedger(secondLedger);
|
||||
secondLedger->setClosed();
|
||||
secondLedger->setAccepted();
|
||||
mMasterLedger.pushLedger(secondLedger, boost::make_shared<Ledger>(true, boost::ref(*secondLedger)));
|
||||
assert(!!secondLedger->getAccountState(rootAddress));
|
||||
// temporary
|
||||
mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC());
|
||||
}
|
||||
|
||||
mNetOps.setStateTimer(0);
|
||||
mNetOps.setStateTimer();
|
||||
|
||||
mIOService.run(); // This blocks
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -43,7 +43,10 @@ const char *LedgerDBInit[] = {
|
||||
LedgerSeq BIGINT UNSIGNED, \
|
||||
PrevHash CHARACTER(64), \
|
||||
TotalCoins BIGINT UNSIGNED, \
|
||||
ClosingTime BIGINT UNSINGED, \
|
||||
ClosingTime BIGINT UNSIGNED, \
|
||||
PrevClosingTime BIGINT UNSIGNED, \
|
||||
CloseTimeRes BIGINT UNSIGNED, \
|
||||
CloseFlags, BIGINT UNSIGNED, \
|
||||
AccountSetHash CHARACTER(64), \
|
||||
TransSetHash CHARACTER(64) \
|
||||
);",
|
||||
|
||||
@@ -3,25 +3,28 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// TXN
|
||||
// TXN - Hash of transaction plus signature to give transaction ID
|
||||
const uint32 sHP_TransactionID = 0x54584E00;
|
||||
|
||||
// STX
|
||||
// STX - Hash of inner transaction to sign
|
||||
const uint32 sHP_TransactionSign = 0x53545800;
|
||||
|
||||
// MLN
|
||||
// TND - Hash of transaction plus metadata
|
||||
const uint32 sHP_TransactionNode = 0x534E4400;
|
||||
|
||||
// MLN - Hash of account state
|
||||
const uint32 sHP_LeafNode = 0x4D4C4E00;
|
||||
|
||||
// MIN
|
||||
// MIN - Hash of inner node in tree
|
||||
const uint32 sHP_InnerNode = 0x4D494E00;
|
||||
|
||||
// LGR
|
||||
// LGR - Hash of ledger master data for signing
|
||||
const uint32 sHP_Ledger = 0x4C575200;
|
||||
|
||||
// VAL
|
||||
// VAL - Hash of validation for signing
|
||||
const uint32 sHP_Validation = 0x56414C00;
|
||||
|
||||
// PRP
|
||||
// PRP - Hash of proposal for signing
|
||||
const uint32 sHP_Proposal = 0x50525000;
|
||||
|
||||
#endif
|
||||
|
||||
198
src/Ledger.cpp
198
src/Ledger.cpp
@@ -16,14 +16,14 @@
|
||||
#include "Conversion.h"
|
||||
#include "BitcoinUtil.h"
|
||||
#include "Wallet.h"
|
||||
#include "BinaryFormats.h"
|
||||
#include "LedgerTiming.h"
|
||||
#include "HashPrefixes.h"
|
||||
#include "Log.h"
|
||||
|
||||
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount),
|
||||
mCloseTime(0), mLedgerSeq(0), mLedgerInterval(LEDGER_INTERVAL), mClosed(false), mValidHash(false),
|
||||
mAccepted(false), mImmutable(false), mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap())
|
||||
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(0),
|
||||
mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0),
|
||||
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
|
||||
mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap())
|
||||
{
|
||||
// special case: put coins in root account
|
||||
AccountState::pointer startAccount = boost::make_shared<AccountState>(masterID);
|
||||
@@ -37,16 +37,18 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s
|
||||
}
|
||||
|
||||
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
|
||||
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq)
|
||||
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash),
|
||||
mTotCoins(totCoins), mCloseTime(timeStamp), mLedgerSeq(ledgerSeq), mLedgerInterval(LEDGER_INTERVAL),
|
||||
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq)
|
||||
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), mTotCoins(totCoins),
|
||||
mLedgerSeq(ledgerSeq), mCloseTime(closeTime), mParentCloseTime(parentCloseTime),
|
||||
mCloseResolution(closeResolution), mCloseFlags(closeFlags),
|
||||
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false)
|
||||
{
|
||||
updateHash();
|
||||
}
|
||||
|
||||
Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins),
|
||||
mLedgerSeq(ledger.mLedgerSeq), mLedgerInterval(ledger.mLedgerInterval),
|
||||
Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mLedgerSeq(ledger.mLedgerSeq),
|
||||
mCloseTime(ledger.mCloseTime), mParentCloseTime(ledger.mParentCloseTime),
|
||||
mCloseResolution(ledger.mCloseResolution), mCloseFlags(ledger.mCloseFlags),
|
||||
mClosed(ledger.mClosed), mValidHash(false), mAccepted(ledger.mAccepted), mImmutable(!isMutable),
|
||||
mTransactionMap(ledger.mTransactionMap->snapShot(isMutable)),
|
||||
mAccountStateMap(ledger.mAccountStateMap->snapShot(isMutable))
|
||||
@@ -55,55 +57,37 @@ Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins),
|
||||
}
|
||||
|
||||
|
||||
Ledger::Ledger(bool, Ledger& prevLedger) : mTotCoins(prevLedger.mTotCoins),
|
||||
mLedgerSeq(prevLedger.mLedgerSeq + 1), mLedgerInterval(prevLedger.mLedgerInterval),
|
||||
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
|
||||
Ledger::Ledger(bool dummy, Ledger& prevLedger) :
|
||||
mTotCoins(prevLedger.mTotCoins), mLedgerSeq(prevLedger.mLedgerSeq + 1),
|
||||
mParentCloseTime(prevLedger.mCloseTime), mCloseResolution(prevLedger.mCloseResolution),
|
||||
mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
|
||||
mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true))
|
||||
{ // Create a new ledger that follows this one
|
||||
prevLedger.updateHash();
|
||||
mParentHash = prevLedger.getHash();
|
||||
assert(mParentHash.isNonZero());
|
||||
mCloseTime = prevLedger.getNextLedgerClose();
|
||||
|
||||
mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution(prevLedger.mCloseResolution,
|
||||
prevLedger.getCloseAgree(), mLedgerSeq);
|
||||
if (prevLedger.mCloseTime == 0)
|
||||
{
|
||||
mCloseTime = theApp->getOPs().getNetworkTimeNC();
|
||||
mCloseTime -= (mCloseTime % mCloseResolution);
|
||||
}
|
||||
else
|
||||
mCloseTime = prevLedger.mCloseTime + mCloseResolution;
|
||||
}
|
||||
|
||||
Ledger::Ledger(const std::vector<unsigned char>& rawLedger) : mCloseTime(0),
|
||||
mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
|
||||
Ledger::Ledger(const std::vector<unsigned char>& rawLedger) :
|
||||
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
|
||||
{
|
||||
Serializer s(rawLedger);
|
||||
// 32seq, 64fee, 256phash, 256thash, 256ahash, 64ts
|
||||
if (!s.get32(mLedgerSeq, BLgPIndex)) return;
|
||||
if (!s.get64(mTotCoins, BLgPTotCoins)) return;
|
||||
if (!s.get256(mParentHash, BLgPPrevLg)) return;
|
||||
if (!s.get256(mTransHash, BLgPTxT)) return;
|
||||
if (!s.get256(mAccountHash, BLgPAcT)) return;
|
||||
if (!s.get64(mCloseTime, BLgPClTs)) return;
|
||||
if (!s.get16(mLedgerInterval, BLgPNlIn)) return;
|
||||
updateHash();
|
||||
if(mValidHash)
|
||||
{
|
||||
mTransactionMap = boost::make_shared<SHAMap>();
|
||||
mAccountStateMap = boost::make_shared<SHAMap>();
|
||||
}
|
||||
setRaw(Serializer(rawLedger));
|
||||
}
|
||||
|
||||
Ledger::Ledger(const std::string& rawLedger) : mCloseTime(0),
|
||||
mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
|
||||
Ledger::Ledger(const std::string& rawLedger) :
|
||||
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
|
||||
{
|
||||
Serializer s(rawLedger);
|
||||
// 32seq, 64fee, 256phash, 256thash, 256ahash, 64ts
|
||||
if (!s.get32(mLedgerSeq, BLgPIndex)) return;
|
||||
if (!s.get64(mTotCoins, BLgPTotCoins)) return;
|
||||
if (!s.get256(mParentHash, BLgPPrevLg)) return;
|
||||
if (!s.get256(mTransHash, BLgPTxT)) return;
|
||||
if (!s.get256(mAccountHash, BLgPAcT)) return;
|
||||
if (!s.get64(mCloseTime, BLgPClTs)) return;
|
||||
if (!s.get16(mLedgerInterval, BLgPNlIn)) return;
|
||||
updateHash();
|
||||
if(mValidHash)
|
||||
{
|
||||
mTransactionMap = boost::make_shared<SHAMap>();
|
||||
mAccountStateMap = boost::make_shared<SHAMap>();
|
||||
}
|
||||
setRaw(Serializer(rawLedger));
|
||||
}
|
||||
|
||||
void Ledger::updateHash()
|
||||
@@ -116,22 +100,64 @@ void Ledger::updateHash()
|
||||
else mAccountHash.zero();
|
||||
}
|
||||
|
||||
Serializer s(116);
|
||||
Serializer s(118);
|
||||
s.add32(sHP_Ledger);
|
||||
addRaw(s);
|
||||
mHash = s.getSHA512Half();
|
||||
mValidHash = true;
|
||||
}
|
||||
|
||||
void Ledger::addRaw(Serializer &s)
|
||||
void Ledger::setRaw(const Serializer &s)
|
||||
{
|
||||
SerializerIterator sit(s);
|
||||
mLedgerSeq = sit.get32();
|
||||
mTotCoins = sit.get64();
|
||||
mParentHash = sit.get256();
|
||||
mTransHash = sit.get256();
|
||||
mAccountHash = sit.get256();
|
||||
mParentCloseTime = sit.get32();
|
||||
mCloseTime = sit.get32();
|
||||
mCloseResolution = sit.get8();
|
||||
mCloseFlags = sit.get8();
|
||||
updateHash();
|
||||
if(mValidHash)
|
||||
{
|
||||
mTransactionMap = boost::make_shared<SHAMap>(mTransHash);
|
||||
mAccountStateMap = boost::make_shared<SHAMap>(mAccountHash);
|
||||
}
|
||||
}
|
||||
|
||||
void Ledger::addRaw(Serializer &s) const
|
||||
{
|
||||
s.add32(mLedgerSeq);
|
||||
s.add64(mTotCoins);
|
||||
s.add256(mParentHash);
|
||||
s.add256(mTransHash);
|
||||
s.add256(mAccountHash);
|
||||
s.add64(mCloseTime);
|
||||
s.add16(mLedgerInterval);
|
||||
s.add32(mParentCloseTime);
|
||||
s.add32(mCloseTime);
|
||||
s.add8(mCloseResolution);
|
||||
s.add8(mCloseFlags);
|
||||
}
|
||||
|
||||
void Ledger::setAccepted(uint32 closeTime, int closeResolution, bool correctCloseTime)
|
||||
{ // used when we witnessed the consensus
|
||||
assert(mClosed && !mAccepted);
|
||||
mCloseTime = closeTime - (closeTime % closeResolution);
|
||||
mCloseResolution = closeResolution;
|
||||
mCloseFlags = correctCloseTime ? 0 : sLCF_NoConsensusTime;
|
||||
updateHash();
|
||||
mAccepted = true;
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
void Ledger::setAccepted()
|
||||
{ // used when we acquired the ledger
|
||||
assert(mClosed && (mCloseResolution != 0) && (mCloseResolution != 0));
|
||||
mCloseTime -= mCloseTime % mCloseResolution;
|
||||
updateHash();
|
||||
mAccepted = true;
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
|
||||
@@ -191,14 +217,16 @@ bool Ledger::addTransaction(Transaction::pointer trans)
|
||||
Serializer s;
|
||||
trans->getSTransaction()->add(s);
|
||||
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(trans->getID(), s.peekData());
|
||||
if (!mTransactionMap->addGiveItem(item, true)) return false;
|
||||
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn)
|
||||
{ // low-level - just add to table
|
||||
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, txn.peekData());
|
||||
if (!mTransactionMap->addGiveItem(item, true)) return false;
|
||||
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -241,28 +269,18 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
|
||||
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransId = '%s';");
|
||||
static boost::format transExists("SELECT Status FROM Transactions WHERE TransID = '%s';");
|
||||
static boost::format updateTx("UPDATE Transactions SET LedgerSeq = %d, Status = '%c' WHERE TransID = '%s';");
|
||||
|
||||
std::string sql="INSERT INTO Ledgers "
|
||||
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,AccountSetHash,TransSetHash) VALUES ('";
|
||||
sql.append(ledger->getHash().GetHex());
|
||||
sql.append("','");
|
||||
sql.append(boost::lexical_cast<std::string>(ledger->mLedgerSeq));
|
||||
sql.append("','");
|
||||
sql.append(ledger->mParentHash.GetHex());
|
||||
sql.append("','");
|
||||
sql.append(boost::lexical_cast<std::string>(ledger->mTotCoins));
|
||||
sql.append("','");
|
||||
sql.append(boost::lexical_cast<std::string>(ledger->mCloseTime));
|
||||
sql.append("','");
|
||||
sql.append(ledger->mAccountHash.GetHex());
|
||||
sql.append("','");
|
||||
sql.append(ledger->mTransHash.GetHex());
|
||||
sql.append("');");
|
||||
static boost::format addLedger("INSERT INTO Ledgers "
|
||||
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,"
|
||||
"AccountSetHash,TransSetHash) VALUES ('%s','%u','%s','%s','%u','%u','%d','%u','%s','%s');");
|
||||
|
||||
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
|
||||
if (SQL_EXISTS(theApp->getLedgerDB()->getDB(), boost::str(ledgerExists % ledger->mLedgerSeq)))
|
||||
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(deleteLedger % ledger->mLedgerSeq));
|
||||
theApp->getLedgerDB()->getDB()->executeSQL(sql);
|
||||
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(addLedger %
|
||||
ledger->getHash().GetHex() % ledger->mLedgerSeq % ledger->mParentHash.GetHex() %
|
||||
boost::lexical_cast<std::string>(ledger->mTotCoins) % ledger->mCloseTime % ledger->mParentCloseTime %
|
||||
ledger->mCloseResolution % ledger->mCloseFlags %
|
||||
ledger->mAccountHash.GetHex() % ledger->mTransHash.GetHex()));
|
||||
|
||||
// write out dirty nodes
|
||||
while(ledger->mTransactionMap->flushDirty(256, TRANSACTION_NODE, ledger->mLedgerSeq))
|
||||
@@ -331,8 +349,10 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
|
||||
Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
{
|
||||
uint256 ledgerHash, prevHash, accountHash, transHash;
|
||||
uint64 totCoins, closingTime;
|
||||
uint32 ledgerSeq;
|
||||
uint64 totCoins;
|
||||
uint32 closingTime, prevClosingTime, ledgerSeq;
|
||||
int closeResolution;
|
||||
unsigned closeFlags;
|
||||
std::string hash;
|
||||
|
||||
{
|
||||
@@ -352,12 +372,16 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
transHash.SetHex(hash);
|
||||
totCoins = db->getBigInt("TotalCoins");
|
||||
closingTime = db->getBigInt("ClosingTime");
|
||||
prevClosingTime = db->getBigInt("PrevClosingTime");
|
||||
closeResolution = db->getBigInt("CloseTimeRes");
|
||||
closeFlags = db->getBigInt("CloseFlags");
|
||||
ledgerSeq = db->getBigInt("LedgerSeq");
|
||||
db->endIterRows();
|
||||
}
|
||||
|
||||
Ledger::pointer ret =
|
||||
boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, ledgerSeq);
|
||||
boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, prevClosingTime,
|
||||
closeFlags, closeResolution, ledgerSeq);
|
||||
if (ret->getHash() != ledgerHash)
|
||||
{
|
||||
Json::StyledStreamWriter ssw;
|
||||
@@ -400,9 +424,16 @@ void Ledger::addJson(Json::Value& ret, int options)
|
||||
ledger["hash"] = mHash.GetHex();
|
||||
ledger["transactionHash"] = mTransHash.GetHex();
|
||||
ledger["accountHash"] = mAccountHash.GetHex();
|
||||
ledger["closed"] = true;
|
||||
if (mClosed) ledger["closed"] = true;
|
||||
ledger["accepted"] = mAccepted;
|
||||
ledger["totalCoins"] = boost::lexical_cast<std::string>(mTotCoins);
|
||||
if ((mCloseFlags & sLCF_NoConsensusTime) != 0)
|
||||
ledger["closeTimeEstimate"] = mCloseTime;
|
||||
else
|
||||
{
|
||||
ledger["closeTime"] = mCloseTime;
|
||||
ledger["closeTimeResolution"] = mCloseResolution;
|
||||
}
|
||||
}
|
||||
else ledger["closed"] = false;
|
||||
if (mCloseTime != 0)
|
||||
@@ -473,23 +504,8 @@ boost::posix_time::ptime Ledger::getCloseTime() const
|
||||
|
||||
void Ledger::setCloseTime(boost::posix_time::ptime ptm)
|
||||
{
|
||||
assert(!mImmutable);
|
||||
mCloseTime = iToSeconds(ptm);
|
||||
}
|
||||
|
||||
uint64 Ledger::sGenesisClose = 0;
|
||||
|
||||
uint64 Ledger::getNextLedgerClose() const
|
||||
{
|
||||
if (mCloseTime == 0)
|
||||
{
|
||||
if (sGenesisClose == 0)
|
||||
{
|
||||
uint64 closeTime = theApp->getOPs().getNetworkTimeNC() + mLedgerInterval - 1;
|
||||
sGenesisClose = closeTime - (closeTime % mLedgerInterval);
|
||||
}
|
||||
return sGenesisClose;
|
||||
}
|
||||
return mCloseTime + mLedgerInterval;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
40
src/Ledger.h
40
src/Ledger.h
@@ -58,16 +58,18 @@ public:
|
||||
TR_TOOSMALL = 9, // amount is less than Tx fee
|
||||
};
|
||||
|
||||
// ledger close flags
|
||||
static const uint32 sLCF_NoConsensusTime = 1;
|
||||
|
||||
private:
|
||||
static uint64 sGenesisClose;
|
||||
|
||||
uint256 mHash, mParentHash, mTransHash, mAccountHash;
|
||||
uint64 mTotCoins;
|
||||
uint64 mCloseTime; // when this ledger closes
|
||||
uint64 mParentCloseTime;
|
||||
uint32 mLedgerSeq;
|
||||
uint16 mLedgerInterval;
|
||||
uint32 mCloseTime; // when this ledger closed
|
||||
uint32 mParentCloseTime; // when the previous ledger closed
|
||||
int mCloseResolution; // the resolution for this ledger close time (2-120 seconds)
|
||||
uint32 mCloseFlags; // flags indicating how this ledger close took place
|
||||
bool mClosed, mValidHash, mAccepted, mImmutable;
|
||||
|
||||
SHAMap::pointer mTransactionMap, mAccountStateMap;
|
||||
@@ -84,21 +86,27 @@ protected:
|
||||
|
||||
static Ledger::pointer getSQL(const std::string& sqlStatement);
|
||||
|
||||
SLE::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID,
|
||||
LedgerEntryType let);
|
||||
SLE::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID, LedgerEntryType let);
|
||||
|
||||
public:
|
||||
Ledger(const NewcoinAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger
|
||||
|
||||
Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
|
||||
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq); // used for database ledgers
|
||||
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution,
|
||||
uint32 ledgerSeq); // used for database ledgers
|
||||
|
||||
Ledger(const std::vector<unsigned char>& rawLedger);
|
||||
|
||||
Ledger(const std::string& rawLedger);
|
||||
Ledger(bool fromAccepted, Ledger& previous); // ledger after this one
|
||||
|
||||
Ledger(bool dummy, Ledger& previous); // ledger after this one
|
||||
|
||||
Ledger(Ledger& target, bool isMutable); // snapshot
|
||||
|
||||
void updateHash();
|
||||
void setClosed() { mClosed = true; }
|
||||
void setAccepted() { mAccepted = true; }
|
||||
void setAccepted(uint32 closeTime, int closeResolution, bool correctCloseTime);
|
||||
void setAccepted();
|
||||
void setImmutable() { updateHash(); mImmutable = true; }
|
||||
bool isClosed() { return mClosed; }
|
||||
bool isAccepted() { return mAccepted; }
|
||||
@@ -111,7 +119,8 @@ public:
|
||||
void bumpSeq() { mClosed = true; mLedgerSeq++; }
|
||||
|
||||
// ledger signature operations
|
||||
void addRaw(Serializer &s);
|
||||
void addRaw(Serializer &s) const;
|
||||
void setRaw(const Serializer& s);
|
||||
|
||||
uint256 getHash();
|
||||
const uint256& getParentHash() const { return mParentHash; }
|
||||
@@ -119,15 +128,16 @@ public:
|
||||
const uint256& getAccountHash() const { return mAccountHash; }
|
||||
uint64 getTotalCoins() const { return mTotCoins; }
|
||||
void destroyCoins(uint64 fee) { mTotCoins -= fee; }
|
||||
uint64 getCloseTimeNC() const { return mCloseTime; }
|
||||
uint64 getParentCloseTimeNC() const { return mParentCloseTime; }
|
||||
uint32 getCloseTimeNC() const { return mCloseTime; }
|
||||
uint32 getParentCloseTimeNC() const { return mParentCloseTime; }
|
||||
uint32 getLedgerSeq() const { return mLedgerSeq; }
|
||||
uint16 getInterval() const { return mLedgerInterval; }
|
||||
int getCloseResolution() const { return mCloseResolution; }
|
||||
bool getCloseAgree() const { return (mCloseFlags & sLCF_NoConsensusTime) == 0; }
|
||||
|
||||
// close time functions
|
||||
boost::posix_time::ptime getCloseTime() const;
|
||||
void setCloseTime(uint32 ct) { assert(!mImmutable); mCloseTime = ct; }
|
||||
void setCloseTime(boost::posix_time::ptime);
|
||||
uint64 getNextLedgerClose() const;
|
||||
boost::posix_time::ptime getCloseTime() const;
|
||||
|
||||
// low level functions
|
||||
SHAMap::pointer peekTransactionMap() { return mTransactionMap; }
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#define LA_DEBUG
|
||||
#define LEDGER_ACQUIRE_TIMEOUT 2
|
||||
#define TRUST_NETWORK
|
||||
|
||||
PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0),
|
||||
mComplete(false), mFailed(false), mProgress(true), mTimer(theApp->getIOService())
|
||||
@@ -28,7 +29,8 @@ void PeerSet::peerHas(Peer::pointer ptr)
|
||||
it = mPeers.erase(it);
|
||||
else
|
||||
{
|
||||
if (pr->samePeer(ptr)) return; // we already have this peer
|
||||
if (pr->samePeer(ptr))
|
||||
return; // we already have this peer
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -77,14 +79,16 @@ void PeerSet::invokeOnTimer()
|
||||
|
||||
void PeerSet::TimerEntry(boost::weak_ptr<PeerSet> wptr, const boost::system::error_code& result)
|
||||
{
|
||||
if (result == boost::asio::error::operation_aborted) return;
|
||||
if (result == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
boost::shared_ptr<PeerSet> ptr = wptr.lock();
|
||||
if (!ptr) return;
|
||||
if (!ptr)
|
||||
return;
|
||||
ptr->invokeOnTimer();
|
||||
}
|
||||
|
||||
LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT),
|
||||
mHaveBase(false), mHaveState(false), mHaveTransactions(false)
|
||||
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "Acquiring ledger " << mHash.GetHex();
|
||||
@@ -109,7 +113,9 @@ void LedgerAcquire::done()
|
||||
mOnComplete.empty();
|
||||
mLock.unlock();
|
||||
|
||||
for (unsigned int i = 0; i < triggers.size(); ++i)
|
||||
theApp->getMasterLedger().storeLedger(mLedger);
|
||||
|
||||
for (int i = 0; i < triggers.size(); ++i)
|
||||
triggers[i](shared_from_this());
|
||||
}
|
||||
|
||||
@@ -122,6 +128,8 @@ void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)>
|
||||
|
||||
void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
{
|
||||
if (mAborted)
|
||||
return;
|
||||
#ifdef LA_DEBUG
|
||||
if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP();
|
||||
else Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex();
|
||||
@@ -299,6 +307,9 @@ bool LedgerAcquire::takeBase(const std::string& data)
|
||||
Log(lsWARNING) << "Acquire hash mismatch";
|
||||
Log(lsWARNING) << mLedger->getHash().GetHex() << "!=" << mHash.GetHex();
|
||||
mLedger = Ledger::pointer();
|
||||
#ifdef TRUST_NETWORK
|
||||
assert(false);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
mHaveBase = true;
|
||||
@@ -337,7 +348,11 @@ bool LedgerAcquire::takeTxNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
if (!mLedger->peekTransactionMap()->isSynching())
|
||||
{
|
||||
mHaveTransactions = true;
|
||||
if (mHaveState) mComplete = true;
|
||||
if (mHaveState)
|
||||
{
|
||||
mComplete = true;
|
||||
done();
|
||||
}
|
||||
}
|
||||
progress();
|
||||
return true;
|
||||
@@ -368,7 +383,11 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
if (!mLedger->peekAccountStateMap()->isSynching())
|
||||
{
|
||||
mHaveState = true;
|
||||
if (mHaveTransactions) mComplete = true;
|
||||
if (mHaveTransactions)
|
||||
{
|
||||
mComplete = true;
|
||||
done();
|
||||
}
|
||||
}
|
||||
progress();
|
||||
return true;
|
||||
@@ -388,6 +407,7 @@ bool LedgerAcquire::takeTxRootNode(const std::vector<unsigned char>& data)
|
||||
|
||||
LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
|
||||
{
|
||||
assert(hash.isNonZero());
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
LedgerAcquire::pointer& ptr = mLedgers[hash];
|
||||
if (ptr) return ptr;
|
||||
@@ -399,6 +419,7 @@ LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
|
||||
|
||||
LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash)
|
||||
{
|
||||
assert(hash.isNonZero());
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
std::map<uint256, LedgerAcquire::pointer>::iterator it = mLedgers.find(hash);
|
||||
if (it != mLedgers.end()) return it->second;
|
||||
@@ -407,12 +428,14 @@ LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash)
|
||||
|
||||
bool LedgerAcquireMaster::hasLedger(const uint256& hash)
|
||||
{
|
||||
assert(hash.isNonZero());
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
return mLedgers.find(hash) != mLedgers.end();
|
||||
}
|
||||
|
||||
void LedgerAcquireMaster::dropLedger(const uint256& hash)
|
||||
{
|
||||
assert(hash.isNonZero());
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
mLedgers.erase(hash);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
|
||||
protected:
|
||||
Ledger::pointer mLedger;
|
||||
bool mHaveBase, mHaveState, mHaveTransactions;
|
||||
bool mHaveBase, mHaveState, mHaveTransactions, mAborted;
|
||||
|
||||
std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete;
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
bool isAcctStComplete() const { return mHaveState; }
|
||||
bool isTransComplete() const { return mHaveTransactions; }
|
||||
Ledger::pointer getLedger() { return mLedger; }
|
||||
void abort() { mAborted = true; }
|
||||
|
||||
void addOnComplete(boost::function<void (LedgerAcquire::pointer)>);
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes)
|
||||
}
|
||||
}
|
||||
|
||||
bool LCTransaction::updatePosition(int seconds, bool proposing)
|
||||
bool LCTransaction::updatePosition(int percentTime, bool proposing)
|
||||
{ // this many seconds after close, should our position change
|
||||
if (mOurPosition && (mNays == 0))
|
||||
return false;
|
||||
@@ -169,9 +169,9 @@ bool LCTransaction::updatePosition(int seconds, bool proposing)
|
||||
int weight = (mYays * 100 + (mOurPosition ? 100 : 0)) / (mNays + mYays + 1);
|
||||
|
||||
// To prevent avalanche stalls, we increase the needed weight slightly over time
|
||||
if (seconds <= LEDGER_ACCEL_CONVERGE) newPosition = weight > AV_MIN_CONSENSUS;
|
||||
else if (seconds >= LEDGER_CONVERGE) newPosition = weight > AV_AVG_CONSENSUS;
|
||||
else newPosition = weight > AV_MAX_CONSENSUS;
|
||||
if (percentTime < AV_MID_CONSENSUS_TIME) newPosition = weight > AV_INIT_CONSENSUS_PCT;
|
||||
else if (percentTime < AV_LATE_CONSENSUS_TIME) newPosition = weight > AV_MID_CONSENSUS_PCT;
|
||||
else newPosition = weight > AV_LATE_CONSENSUS_PCT;
|
||||
}
|
||||
else // don't let us outweight a proposing node, just recognize consensus
|
||||
newPosition = mYays > mNays;
|
||||
@@ -189,26 +189,41 @@ bool LCTransaction::updatePosition(int seconds, bool proposing)
|
||||
return true;
|
||||
}
|
||||
|
||||
int LCTransaction::getAgreeLevel()
|
||||
{ // how much do nodes agree with us
|
||||
if (mOurPosition) return (mYays * 100 + 100) / (mYays + mNays + 1);
|
||||
return (mNays * 100 + 100) / (mYays + mNays + 1);
|
||||
}
|
||||
|
||||
LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime)
|
||||
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger)
|
||||
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger),
|
||||
mCurrentSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false)
|
||||
{
|
||||
mValSeed = theConfig.VALIDATION_SEED;
|
||||
Log(lsDEBUG) << "Creating consensus object";
|
||||
Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime;
|
||||
if (previousLedger->getHash() != prevLCLHash)
|
||||
mPreviousProposers = theApp->getOPs().getPreviousProposers();
|
||||
mPreviousSeconds = theApp->getOPs().getPreviousSeconds();
|
||||
assert(mPreviousSeconds);
|
||||
|
||||
mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution(
|
||||
previousLedger->getCloseResolution(), previousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1);
|
||||
|
||||
mHaveCorrectLCL = previousLedger->getHash() == prevLCLHash;
|
||||
|
||||
if (!mHaveCorrectLCL)
|
||||
{
|
||||
mHaveCorrectLCL = mProposing = mValidating = false;
|
||||
mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash);
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||
if ((*it)->hasLedger(prevLCLHash))
|
||||
mAcquiringLedger->peerHas(*it);
|
||||
}
|
||||
else if (mValSeed.isValid())
|
||||
{
|
||||
mValidating = true;
|
||||
mHaveCorrectLCL = mValidating = true;
|
||||
mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL;
|
||||
}
|
||||
else mProposing = mValidating = false;
|
||||
else
|
||||
{
|
||||
mHaveCorrectLCL = true;
|
||||
mProposing = mValidating = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
|
||||
@@ -233,9 +248,9 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
|
||||
|
||||
if (mValidating)
|
||||
mOurPosition = boost::make_shared<LedgerProposal>
|
||||
(mValSeed, initialLedger->getParentHash(), txSet);
|
||||
(mValSeed, initialLedger->getParentHash(), txSet, mCloseTime);
|
||||
else
|
||||
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet);
|
||||
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet, mCloseTime);
|
||||
mapComplete(txSet, initialSet, false);
|
||||
if (mProposing) propose(std::vector<uint256>(), std::vector<uint256>());
|
||||
}
|
||||
@@ -342,84 +357,70 @@ void LedgerConsensus::statusChange(newcoin::NodeEvent event, Ledger::pointer led
|
||||
Log(lsINFO) << "send status change to peer";
|
||||
}
|
||||
|
||||
void LedgerConsensus::abort()
|
||||
{
|
||||
Log(lsWARNING) << "consensus aborted";
|
||||
mState = lcsABORTED;
|
||||
}
|
||||
|
||||
int LedgerConsensus::startup()
|
||||
{
|
||||
// create wobble ledger in case peers target transactions to it
|
||||
theApp->getMasterLedger().beginWobble();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LedgerConsensus::statePreClose(int secondsSinceClose)
|
||||
void LedgerConsensus::statePreClose()
|
||||
{ // it is shortly before ledger close time
|
||||
if (secondsSinceClose >= 0)
|
||||
{ // it is time to close the ledger (swap default and wobble ledgers)
|
||||
Log(lsINFO) << "Closing ledger";
|
||||
mState = lcsPOST_CLOSE;
|
||||
theApp->getMasterLedger().closeTime();
|
||||
statusChange(newcoin::neCLOSING_LEDGER, mPreviousLedger);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
bool anyTransactions = theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap()->getHash().isNonZero();
|
||||
int proposersClosed = mPeerPositions.size();
|
||||
|
||||
int LedgerConsensus::statePostClose(int secondsSinceClose)
|
||||
{ // we are in the transaction wobble time
|
||||
if (secondsSinceClose > LEDGER_WOBBLE_TIME)
|
||||
{
|
||||
Log(lsINFO) << "Wobble is over, it's consensus time";
|
||||
int sinceClose = theApp->getOPs().getNetworkTimeNC() - theApp->getOPs().getLastCloseNetTime();
|
||||
|
||||
if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed,
|
||||
mPreviousSeconds, sinceClose))
|
||||
{ // it is time to close the ledger (swap default and wobble ledgers)
|
||||
Log(lsINFO) << "CLC:: closing ledger";
|
||||
mState = lcsESTABLISH;
|
||||
Ledger::pointer initial = theApp->getMasterLedger().endWobble();
|
||||
mConsensusStartTime = boost::posix_time::second_clock::universal_time();
|
||||
mCloseTime = theApp->getOPs().getNetworkTimeNC();
|
||||
theApp->getOPs().setLastCloseNetTime(mCloseTime);
|
||||
statusChange(newcoin::neCLOSING_LEDGER, mPreviousLedger);
|
||||
Ledger::pointer initial = theApp->getMasterLedger().closeLedger();
|
||||
assert (initial->getParentHash() == mPreviousLedger->getHash());
|
||||
takeInitialPosition(initial);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LedgerConsensus::stateEstablish(int secondsSinceClose)
|
||||
void LedgerConsensus::stateEstablish()
|
||||
{ // we are establishing consensus
|
||||
if (mProposing)
|
||||
updateOurPositions(secondsSinceClose);
|
||||
if (secondsSinceClose > LEDGER_MAX_CONVERGE)
|
||||
if (mCurrentSeconds < LEDGER_MIN_CONSENSUS)
|
||||
return;
|
||||
updateOurPositions();
|
||||
if (!mHaveCloseTimeConsensus)
|
||||
{
|
||||
Log(lsINFO) << "No close time consensus";
|
||||
}
|
||||
else if (haveConsensus())
|
||||
{
|
||||
Log(lsINFO) << "Converge cutoff";
|
||||
mState = lcsCUTOFF;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LedgerConsensus::stateCutoff(int secondsSinceClose)
|
||||
{ // we are making sure everyone else agrees
|
||||
bool haveConsensus = updateOurPositions(secondsSinceClose);
|
||||
if (haveConsensus || (secondsSinceClose > LEDGER_CONVERGE))
|
||||
{
|
||||
Log(lsINFO) << "Consensus complete (" << haveConsensus << ")";
|
||||
mState = lcsFINISHED;
|
||||
beginAccept();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LedgerConsensus::stateFinished(int secondsSinceClose)
|
||||
void LedgerConsensus::stateFinished()
|
||||
{ // we are processing the finished ledger
|
||||
// logic of calculating next ledger advances us out of this state
|
||||
return 1;
|
||||
|
||||
// CHECKME: Should we count proposers that didn't converge to our consensus set?
|
||||
int convergeTime = (boost::posix_time::second_clock::universal_time() - mConsensusStartTime).seconds();
|
||||
if (convergeTime <= 0) convergeTime = 1;
|
||||
theApp->getOPs().newLCL(mPeerPositions.size(), convergeTime, mNewLedgerHash);
|
||||
}
|
||||
|
||||
int LedgerConsensus::stateAccepted(int secondsSinceClose)
|
||||
void LedgerConsensus::stateAccepted()
|
||||
{ // we have accepted a new ledger
|
||||
endConsensus();
|
||||
return 4;
|
||||
}
|
||||
|
||||
int LedgerConsensus::timerEntry()
|
||||
void LedgerConsensus::timerEntry()
|
||||
{
|
||||
if (!mHaveCorrectLCL)
|
||||
{
|
||||
Log(lsINFO) << "Checking for consensus ledger " << mPrevLedgerHash.GetHex();
|
||||
Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash);
|
||||
if (consensus)
|
||||
{
|
||||
@@ -429,45 +430,42 @@ int LedgerConsensus::timerEntry()
|
||||
mPreviousLedger = consensus;
|
||||
mHaveCorrectLCL = true;
|
||||
}
|
||||
else Log(lsINFO) << "We still don't have it";
|
||||
}
|
||||
|
||||
int sinceClose = theApp->getOPs().getNetworkTimeNC() - mCloseTime;
|
||||
mCurrentSeconds = (mCloseTime != 0) ? (theApp->getOPs().getNetworkTimeNC() - mCloseTime) : 0;
|
||||
mClosePercent = mCurrentSeconds * 100 / mPreviousSeconds;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case lcsPRE_CLOSE: return statePreClose(sinceClose);
|
||||
case lcsPOST_CLOSE: return statePostClose(sinceClose);
|
||||
case lcsESTABLISH: return stateEstablish(sinceClose);
|
||||
case lcsCUTOFF: return stateCutoff(sinceClose);
|
||||
case lcsFINISHED: return stateFinished(sinceClose);
|
||||
case lcsACCEPTED: return stateAccepted(sinceClose);
|
||||
case lcsABORTED: return 1;
|
||||
case lcsPRE_CLOSE: statePreClose(); return;
|
||||
case lcsESTABLISH: stateEstablish(); return;
|
||||
case lcsFINISHED: stateFinished(); return;
|
||||
case lcsACCEPTED: stateAccepted(); return;
|
||||
}
|
||||
assert(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool LedgerConsensus::updateOurPositions(int sinceClose)
|
||||
{ // returns true if the network has consensus
|
||||
void LedgerConsensus::updateOurPositions()
|
||||
{
|
||||
Log(lsINFO) << "Updating our positions";
|
||||
bool changes = false;
|
||||
bool stable = true;
|
||||
SHAMap::pointer ourPosition;
|
||||
std::vector<uint256> addedTx, removedTx;
|
||||
|
||||
for(boost::unordered_map<uint256, LCTransaction::pointer>::iterator it = mDisputes.begin(),
|
||||
end = mDisputes.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second->updatePosition(sinceClose, mProposing))
|
||||
if (it->second->updatePosition(mClosePercent, mProposing))
|
||||
{
|
||||
if (!changes)
|
||||
{
|
||||
ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true);
|
||||
changes = true;
|
||||
stable = false;
|
||||
}
|
||||
if (it->second->getOurPosition()) // now a yes
|
||||
{
|
||||
ourPosition->addItem(SHAMapItem(it->first, it->second->peekTransaction()), true);
|
||||
ourPosition->addItem(SHAMapItem(it->first, it->second->peekTransaction()), true, false);
|
||||
addedTx.push_back(it->first);
|
||||
}
|
||||
else // now a no
|
||||
@@ -476,20 +474,60 @@ bool LedgerConsensus::updateOurPositions(int sinceClose)
|
||||
removedTx.push_back(it->first);
|
||||
}
|
||||
}
|
||||
else if (it->second->getAgreeLevel() < AV_PCT_STOP)
|
||||
stable = false;
|
||||
}
|
||||
|
||||
std::map<uint32, int> closeTimes;
|
||||
for (boost::unordered_map<uint160, LedgerProposal::pointer>::iterator it = mPeerPositions.begin(),
|
||||
end = mPeerPositions.end(); it != end; ++it)
|
||||
++closeTimes[it->second->getCloseTime() - (it->second->getCloseTime() % mCloseResolution)];
|
||||
++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)];
|
||||
|
||||
|
||||
int neededWeight;
|
||||
if (mClosePercent < AV_MID_CONSENSUS_TIME)
|
||||
neededWeight = AV_INIT_CONSENSUS_PCT;
|
||||
else if (mClosePercent < AV_LATE_CONSENSUS_TIME)
|
||||
neededWeight = AV_MID_CONSENSUS_PCT;
|
||||
else neededWeight = AV_LATE_CONSENSUS_PCT;
|
||||
|
||||
int thresh = mPeerPositions.size() * neededWeight / 100;
|
||||
uint32 closeTime = 0;
|
||||
for (std::map<uint32, int>::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second > thresh)
|
||||
{
|
||||
mHaveCloseTimeConsensus = true;
|
||||
closeTime = it->first;
|
||||
}
|
||||
}
|
||||
if (closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)))
|
||||
changes = true;
|
||||
|
||||
if (changes)
|
||||
{
|
||||
uint256 newHash = ourPosition->getHash();
|
||||
mOurPosition->changePosition(newHash);
|
||||
mOurPosition->changePosition(newHash, closeTime);
|
||||
if (mProposing) propose(addedTx, removedTx);
|
||||
mapComplete(newHash, ourPosition, false);
|
||||
Log(lsINFO) << "We change our position to " << newHash.GetHex();
|
||||
}
|
||||
}
|
||||
|
||||
return stable;
|
||||
bool LedgerConsensus::haveConsensus()
|
||||
{
|
||||
int agree = 0, disagree = 0;
|
||||
uint256 ourPosition = mOurPosition->getCurrentHash();
|
||||
for (boost::unordered_map<uint160, LedgerProposal::pointer>::iterator it = mPeerPositions.begin(),
|
||||
end = mPeerPositions.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second->getCurrentHash() == ourPosition)
|
||||
++agree;
|
||||
else
|
||||
++disagree;
|
||||
}
|
||||
int currentValidations = theApp->getValidations().getCurrentValidationCount(mPreviousLedger->getCloseTimeNC());
|
||||
return ContinuousLedgerTiming::haveConsensus(mPreviousProposers, agree + disagree, agree, currentValidations,
|
||||
mPreviousSeconds, mCurrentSeconds);
|
||||
}
|
||||
|
||||
SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire)
|
||||
@@ -546,6 +584,7 @@ void LedgerConsensus::propose(const std::vector<uint256>& added, const std::vect
|
||||
newcoin::TMProposeSet prop;
|
||||
prop.set_currenttxhash(mOurPosition->getCurrentHash().begin(), 256 / 8);
|
||||
prop.set_proposeseq(mOurPosition->getProposeSeq());
|
||||
prop.set_closetime(mOurPosition->getCloseTime());
|
||||
|
||||
std::vector<unsigned char> pubKey = mOurPosition->getPubKey();
|
||||
std::vector<unsigned char> sig = mOurPosition->sign();
|
||||
@@ -586,6 +625,7 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
|
||||
bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
|
||||
{
|
||||
LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()];
|
||||
|
||||
if (currentPosition)
|
||||
{
|
||||
assert(newPosition->getPeerID() == currentPosition->getPeerID());
|
||||
@@ -598,6 +638,10 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (newPosition->getProposeSeq() == 0)
|
||||
{ // new initial close time estimate
|
||||
++mCloseTimes[newPosition->getCloseTime()];
|
||||
}
|
||||
Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/"
|
||||
<< newPosition->getCurrentHash().GetHex();
|
||||
currentPosition = newPosition;
|
||||
@@ -666,7 +710,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran
|
||||
try
|
||||
{
|
||||
#endif
|
||||
TransactionEngineResult result = engine.applyTransaction(*txn, parms, 0);
|
||||
TransactionEngineResult result = engine.applyTransaction(*txn, parms);
|
||||
if (result > 0)
|
||||
{
|
||||
Log(lsINFO) << " retry";
|
||||
@@ -725,7 +769,7 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer led
|
||||
{
|
||||
try
|
||||
{
|
||||
TransactionEngineResult result = engine.applyTransaction(*it->second, parms, 0);
|
||||
TransactionEngineResult result = engine.applyTransaction(*it->second, parms);
|
||||
if (result <= 0)
|
||||
{
|
||||
if (result == 0) ++successes;
|
||||
@@ -758,7 +802,16 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
CanonicalTXSet failedTransactions(set->getHash());
|
||||
applyTransactions(set, newLCL, failedTransactions, true);
|
||||
newLCL->setClosed();
|
||||
newLCL->setAccepted();
|
||||
|
||||
uint32 closeTime = mOurPosition->getCloseTime();
|
||||
bool closeTimeCorrect = true;
|
||||
if (closeTime == 0)
|
||||
{ // we didn't agree
|
||||
closeTimeCorrect = false;
|
||||
closeTime = mPreviousLedger->getCloseTimeNC() + 1;
|
||||
}
|
||||
|
||||
newLCL->setAccepted(closeTime, mCloseResolution, closeTimeCorrect);
|
||||
newLCL->updateHash();
|
||||
uint256 newLCLHash = newLCL->getHash();
|
||||
Log(lsTRACE) << "newLCL " << newLCLHash.GetHex();
|
||||
@@ -804,6 +857,7 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL,
|
||||
failedTransactions, false);
|
||||
theApp->getMasterLedger().pushLedger(newLCL, newOL);
|
||||
mNewLedgerHash = newLCL->getHash();
|
||||
mState = lcsACCEPTED;
|
||||
sl.unlock();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __LEDGER_CONSENSUS__
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
@@ -62,32 +63,36 @@ public:
|
||||
|
||||
void setVote(const uint160& peer, bool votesYes);
|
||||
|
||||
bool updatePosition(int timePassed, bool proposing);
|
||||
int getAgreeLevel();
|
||||
bool updatePosition(int percentTime, bool proposing);
|
||||
};
|
||||
|
||||
enum LCState
|
||||
{
|
||||
lcsPRE_CLOSE, // We haven't closed our ledger yet, but others might have
|
||||
lcsPOST_CLOSE, // Ledger closed, but wobble time
|
||||
lcsESTABLISH, // Establishing consensus
|
||||
lcsCUTOFF, // Past the cutoff for consensus
|
||||
lcsFINISHED, // We have closed on a transaction set
|
||||
lcsACCEPTED, // We have accepted/validated a new last closed ledger
|
||||
lcsABORTED // Abandoned
|
||||
};
|
||||
|
||||
class LedgerConsensus : public boost::enable_shared_from_this<LedgerConsensus>
|
||||
{
|
||||
protected:
|
||||
LCState mState;
|
||||
uint32 mCloseTime;
|
||||
uint256 mPrevLedgerHash;
|
||||
uint32 mCloseTime; // The wall time this ledger closed
|
||||
uint256 mPrevLedgerHash, mNewLedgerHash;
|
||||
Ledger::pointer mPreviousLedger;
|
||||
LedgerAcquire::pointer mAcquiringLedger;
|
||||
LedgerProposal::pointer mOurPosition;
|
||||
NewcoinAddress mValSeed;
|
||||
bool mProposing, mValidating, mHaveCorrectLCL;
|
||||
|
||||
int mCurrentSeconds, mClosePercent, mCloseResolution;
|
||||
bool mHaveCloseTimeConsensus;
|
||||
|
||||
boost::posix_time::ptime mConsensusStartTime;
|
||||
int mPreviousProposers;
|
||||
int mPreviousSeconds;
|
||||
|
||||
// Convergence tracking, trusted peers indexed by hash of public key
|
||||
boost::unordered_map<uint160, LedgerProposal::pointer> mPeerPositions;
|
||||
|
||||
@@ -101,6 +106,9 @@ protected:
|
||||
// Disputed transactions
|
||||
boost::unordered_map<uint256, LCTransaction::pointer> mDisputes;
|
||||
|
||||
// Close time estimates
|
||||
std::map<uint32, int> mCloseTimes;
|
||||
|
||||
// final accept logic
|
||||
static void Saccept(boost::shared_ptr<LedgerConsensus> This, SHAMap::pointer txSet);
|
||||
void accept(SHAMap::pointer txSet);
|
||||
@@ -123,9 +131,9 @@ protected:
|
||||
CanonicalTXSet& failedTransactions, bool final);
|
||||
|
||||
// manipulating our own position
|
||||
void takeInitialPosition(Ledger::pointer initialLedger);
|
||||
bool updateOurPositions(int sinceClose);
|
||||
void statusChange(newcoin::NodeEvent, Ledger::pointer ledger);
|
||||
void takeInitialPosition(Ledger::pointer initialLedger);
|
||||
void updateOurPositions();
|
||||
int getThreshold();
|
||||
void beginAccept();
|
||||
void endConsensus();
|
||||
@@ -142,16 +150,16 @@ public:
|
||||
TransactionAcquire::pointer getAcquiring(const uint256& hash);
|
||||
void mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired);
|
||||
|
||||
void abort();
|
||||
int timerEntry();
|
||||
void timerEntry();
|
||||
|
||||
// state handlers
|
||||
int statePreClose(int secondsSinceClose);
|
||||
int statePostClose(int secondsSinceClose);
|
||||
int stateEstablish(int secondsSinceClose);
|
||||
int stateCutoff(int secondsSinceClose);
|
||||
int stateFinished(int secondsSinceClose);
|
||||
int stateAccepted(int secondsSinceClose);
|
||||
void statePreClose();
|
||||
void stateEstablish();
|
||||
void stateCutoff();
|
||||
void stateFinished();
|
||||
void stateAccepted();
|
||||
|
||||
bool haveConsensus();
|
||||
|
||||
bool peerPosition(LedgerProposal::pointer);
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL)
|
||||
|
||||
if (newLCL->isAccepted())
|
||||
{
|
||||
mLedgerHistory.addAcceptedLedger(mFinalizedLedger);
|
||||
Log(lsINFO) << "StashAccepted: " << mFinalizedLedger->getHash().GetHex();
|
||||
mLedgerHistory.addAcceptedLedger(newLCL);
|
||||
Log(lsINFO) << "StashAccepted: " << newLCL->getHash().GetHex();
|
||||
}
|
||||
|
||||
mFinalizedLedger = newLCL;
|
||||
@@ -54,6 +54,7 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL)
|
||||
|
||||
void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer current)
|
||||
{
|
||||
assert(lastClosed && current);
|
||||
mFinalizedLedger = lastClosed;
|
||||
mFinalizedLedger->setClosed();
|
||||
mFinalizedLedger->setAccepted();
|
||||
@@ -63,40 +64,25 @@ void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer cur
|
||||
mEngine.setLedger(mCurrentLedger);
|
||||
}
|
||||
|
||||
void LedgerMaster::beginWobble()
|
||||
void LedgerMaster::storeLedger(Ledger::pointer ledger)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
assert(!mWobbleLedger);
|
||||
mWobbleLedger = boost::make_shared<Ledger>(boost::ref(*mCurrentLedger), true);
|
||||
mEngine.setDefaultLedger(mCurrentLedger);
|
||||
mEngine.setAlternateLedger(mWobbleLedger);
|
||||
mLedgerHistory.addLedger(ledger);
|
||||
}
|
||||
|
||||
void LedgerMaster::closeTime()
|
||||
{ // swap current and wobble ledgers
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
assert(mCurrentLedger && mWobbleLedger);
|
||||
std::swap(mCurrentLedger, mWobbleLedger);
|
||||
mEngine.setDefaultLedger(mCurrentLedger);
|
||||
mEngine.setAlternateLedger(mWobbleLedger);
|
||||
}
|
||||
|
||||
Ledger::pointer LedgerMaster::endWobble()
|
||||
Ledger::pointer LedgerMaster::closeLedger()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
assert(mWobbleLedger && mCurrentLedger);
|
||||
Ledger::pointer ret = mWobbleLedger;
|
||||
mWobbleLedger = Ledger::pointer();
|
||||
mEngine.setAlternateLedger(Ledger::pointer());
|
||||
return ret;
|
||||
Ledger::pointer closingLedger = mCurrentLedger;
|
||||
mCurrentLedger = boost::make_shared<Ledger>(boost::ref(*closingLedger), true);
|
||||
mEngine.setLedger(mCurrentLedger);
|
||||
return closingLedger;
|
||||
}
|
||||
|
||||
TransactionEngineResult LedgerMaster::doTransaction(const SerializedTransaction& txn, uint32 targetLedger,
|
||||
TransactionEngineParams params)
|
||||
{
|
||||
Ledger::pointer ledger = mEngine.getTransactionLedger(targetLedger);
|
||||
TransactionEngineResult result = mEngine.applyTransaction(txn, params, ledger);
|
||||
theApp->getOPs().pubTransaction(ledger, txn, result);
|
||||
TransactionEngineResult result = mEngine.applyTransaction(txn, params);
|
||||
theApp->getOPs().pubTransaction(mEngine.getLedger(), txn, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ class LedgerMaster
|
||||
TransactionEngine mEngine;
|
||||
|
||||
Ledger::pointer mCurrentLedger; // The ledger we are currently processiong
|
||||
Ledger::pointer mWobbleLedger; // A ledger past its close time
|
||||
Ledger::pointer mFinalizedLedger; // The ledger that most recently closed
|
||||
|
||||
LedgerHistory mLedgerHistory;
|
||||
@@ -41,9 +40,6 @@ public:
|
||||
// The current ledger is the ledger we believe new transactions should go in
|
||||
Ledger::pointer getCurrentLedger() { return mCurrentLedger; }
|
||||
|
||||
// The wobble ledger is a ledger that new transactions can go in if requested
|
||||
Ledger::pointer getWobbleLedger() { return mWobbleLedger; }
|
||||
|
||||
// The finalized ledger is the last closed/accepted ledger
|
||||
Ledger::pointer getClosedLedger() { return mFinalizedLedger; }
|
||||
|
||||
@@ -52,12 +48,11 @@ public:
|
||||
|
||||
void pushLedger(Ledger::pointer newLedger);
|
||||
void pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL);
|
||||
void storeLedger(Ledger::pointer);
|
||||
|
||||
void switchLedgers(Ledger::pointer lastClosed, Ledger::pointer newCurrent);
|
||||
|
||||
void closeTime();
|
||||
void beginWobble();
|
||||
Ledger::pointer endWobble();
|
||||
Ledger::pointer closeLedger();
|
||||
|
||||
Ledger::pointer getLedgerBySeq(uint32 index)
|
||||
{
|
||||
|
||||
@@ -29,8 +29,7 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry)
|
||||
if (create)
|
||||
{
|
||||
assert(!mAccountStateMap->hasItem(entry->getIndex()));
|
||||
|
||||
if (!mAccountStateMap->addGiveItem(item, false))
|
||||
if(!mAccountStateMap->addGiveItem(item, false, false)) // FIXME: TX metadata
|
||||
{
|
||||
assert(false);
|
||||
return lepERROR;
|
||||
@@ -38,7 +37,7 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry)
|
||||
return lepCREATED;
|
||||
}
|
||||
|
||||
if (!mAccountStateMap->updateGiveItem(item, false))
|
||||
if (!mAccountStateMap->updateGiveItem(item, false, false)) // FIXME: TX metadata
|
||||
{
|
||||
assert(false);
|
||||
return lepERROR;
|
||||
|
||||
@@ -7,39 +7,41 @@
|
||||
#include "Application.h"
|
||||
#include "HashPrefixes.h"
|
||||
|
||||
LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& tx, const NewcoinAddress& naPeerPublic) :
|
||||
mPreviousLedger(pLgr), mCurrentHash(tx), mProposeSeq(seq)
|
||||
LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& tx, uint32 closeTime,
|
||||
const NewcoinAddress& naPeerPublic) :
|
||||
mPreviousLedger(pLgr), mCurrentHash(tx), mCloseTime(closeTime), mProposeSeq(seq)
|
||||
{
|
||||
mPublicKey = naPeerPublic;
|
||||
// XXX Validate key.
|
||||
// if (!mKey->SetPubKey(pubKey))
|
||||
// throw std::runtime_error("Invalid public key in proposal");
|
||||
|
||||
mPreviousLedger = theApp->getMasterLedger().getClosedLedger()->getHash();
|
||||
mPeerID = mPublicKey.getNodeID();
|
||||
}
|
||||
|
||||
|
||||
LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prevLgr, const uint256& position) :
|
||||
mPreviousLedger(prevLgr), mCurrentHash(position), mProposeSeq(0)
|
||||
LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prevLgr,
|
||||
const uint256& position, uint32 closeTime) :
|
||||
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0)
|
||||
{
|
||||
mPublicKey = NewcoinAddress::createNodePublic(naSeed);
|
||||
mPrivateKey = NewcoinAddress::createNodePrivate(naSeed);
|
||||
mPeerID = mPublicKey.getNodeID();
|
||||
}
|
||||
|
||||
LedgerProposal::LedgerProposal(const uint256& prevLgr, const uint256& position) :
|
||||
mPreviousLedger(prevLgr), mCurrentHash(position), mProposeSeq(0)
|
||||
LedgerProposal::LedgerProposal(const uint256& prevLgr, const uint256& position, uint32 closeTime) :
|
||||
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
uint256 LedgerProposal::getSigningHash() const
|
||||
{
|
||||
Serializer s(72);
|
||||
Serializer s((32 + 32 + 32 + 256 + 256) / 8);
|
||||
|
||||
s.add32(sHP_Proposal);
|
||||
s.add32(mProposeSeq);
|
||||
s.add32(mCloseTime);
|
||||
s.add256(mPreviousLedger);
|
||||
s.add256(mCurrentHash);
|
||||
|
||||
@@ -51,9 +53,10 @@ bool LedgerProposal::checkSign(const std::string& signature, const uint256& sign
|
||||
return mPublicKey.verifyNodePublic(signingHash, signature);
|
||||
}
|
||||
|
||||
void LedgerProposal::changePosition(const uint256& newPosition)
|
||||
void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime)
|
||||
{
|
||||
mCurrentHash = newPosition;
|
||||
mCloseTime = closeTime;
|
||||
++mProposeSeq;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class LedgerProposal
|
||||
protected:
|
||||
|
||||
uint256 mPreviousLedger, mCurrentHash;
|
||||
uint32 mProposeSeq;
|
||||
uint32 mCloseTime, mProposeSeq;
|
||||
|
||||
uint160 mPeerID;
|
||||
NewcoinAddress mPublicKey;
|
||||
@@ -25,13 +25,14 @@ public:
|
||||
|
||||
// proposal from peer
|
||||
LedgerProposal(const uint256& prevLgr, uint32 proposeSeq, const uint256& propose,
|
||||
const NewcoinAddress& naPeerPublic);
|
||||
uint32 closeTime, const NewcoinAddress& naPeerPublic);
|
||||
|
||||
// our first proposal
|
||||
LedgerProposal(const NewcoinAddress& privKey, const uint256& prevLedger, const uint256& position);
|
||||
LedgerProposal(const NewcoinAddress& privKey, const uint256& prevLedger, const uint256& position,
|
||||
uint32 closeTime);
|
||||
|
||||
// an unsigned proposal
|
||||
LedgerProposal(const uint256& prevLedger, const uint256& position);
|
||||
// an unsigned "dummy" proposal for nodes not validating
|
||||
LedgerProposal(const uint256& prevLedger, const uint256& position, uint32 closeTime);
|
||||
|
||||
uint256 getSigningHash() const;
|
||||
bool checkSign(const std::string& signature, const uint256& signingHash);
|
||||
@@ -41,11 +42,12 @@ public:
|
||||
const uint256& getCurrentHash() const { return mCurrentHash; }
|
||||
const uint256& getPrevLedger() const { return mPreviousLedger; }
|
||||
uint32 getProposeSeq() const { return mProposeSeq; }
|
||||
uint32 getCloseTime() const { return mCloseTime; }
|
||||
const NewcoinAddress& peekPublic() const { return mPublicKey; }
|
||||
std::vector<unsigned char> getPubKey() const { return mPublicKey.getNodePublic(); }
|
||||
std::vector<unsigned char> sign();
|
||||
|
||||
void changePosition(const uint256& newPosition);
|
||||
void changePosition(const uint256& newPosition, uint32 newCloseTime);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,34 +1,55 @@
|
||||
|
||||
#include "LedgerTiming.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// Returns the number of seconds the ledger should be be open.
|
||||
int ContinuousLedgerTiming::shouldClose( // How many:
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
// NOTE: First and last times must be repeated
|
||||
int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 120, 120 };
|
||||
|
||||
// Called when a ledger is open and no close is in progress -- when a transaction is received and no close
|
||||
// is in process, or when a close completes. Returns the number of seconds the ledger should be be open.
|
||||
int ContinuousLedgerTiming::shouldClose(
|
||||
bool anyTransactions,
|
||||
int previousProposers, // proposers there were in the last closing
|
||||
int proposersClosed, // proposers who have currently closed their ledgers
|
||||
int previousOpenSeconds, // seconds the previous ledger was open
|
||||
int currentOpenSeconds) // seconds since the previous ledger closed
|
||||
int previousProposers, // proposers in the last closing
|
||||
int proposersClosed, // proposers who have currently closed this ledgers
|
||||
int previousSeconds, // seconds the previous ledger took to reach consensus
|
||||
int currentSeconds) // seconds since the previous ledger closed
|
||||
{
|
||||
assert((previousSeconds > 0) && (previousSeconds < 600));
|
||||
assert((currentSeconds >= 0) && (currentSeconds < 600));
|
||||
|
||||
#if 0
|
||||
Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") %
|
||||
(anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentSeconds % previousSeconds);
|
||||
#endif
|
||||
|
||||
if (!anyTransactions)
|
||||
{ // no transactions so far this interval
|
||||
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
|
||||
return currentOpenSeconds;
|
||||
if (previousOpenSeconds > (LEDGER_IDLE_INTERVAL + 2)) // the last ledger was very slow to close
|
||||
return previousOpenSeconds - 1;
|
||||
{
|
||||
Log(lsTRACE) << "no transactions, many proposers: now";
|
||||
return currentSeconds;
|
||||
}
|
||||
if (previousSeconds > (LEDGER_IDLE_INTERVAL + 2)) // the last ledger was very slow to close
|
||||
{
|
||||
Log(lsTRACE) << "slow to close";
|
||||
return previousSeconds - 1;
|
||||
}
|
||||
return LEDGER_IDLE_INTERVAL; // normal idle
|
||||
}
|
||||
|
||||
if (previousOpenSeconds == LEDGER_IDLE_INTERVAL) // coming out of idle, close now
|
||||
return currentOpenSeconds;
|
||||
if (previousSeconds == LEDGER_IDLE_INTERVAL) // coming out of idle, close now
|
||||
{
|
||||
Log(lsTRACE) << "leaving idle, close now";
|
||||
return currentSeconds;
|
||||
}
|
||||
|
||||
// If the network is slow, try to synchronize close times
|
||||
if (previousOpenSeconds > 8)
|
||||
return (currentOpenSeconds - currentOpenSeconds % 4);
|
||||
else if (previousOpenSeconds > 4)
|
||||
return (currentOpenSeconds - currentOpenSeconds % 2);
|
||||
|
||||
return currentOpenSeconds; // this ledger should close now
|
||||
Log(lsTRACE) << "close now";
|
||||
return currentSeconds; // this ledger should close now
|
||||
}
|
||||
|
||||
// Returns whether we have a consensus or not. If so, we expect all honest nodes
|
||||
@@ -41,21 +62,59 @@ bool ContinuousLedgerTiming::haveConsensus(
|
||||
int previousAgreeTime, // how long it took to agree on the last ledger
|
||||
int currentAgreeTime) // how long we've been trying to agree
|
||||
{
|
||||
if (currentProposers < (previousProposers * 3 / 4))
|
||||
{ // Less than 3/4 of the validators are present, slow down
|
||||
if (currentAgreeTime < (previousAgreeTime + 2))
|
||||
Log(lsTRACE) << boost::str(boost::format("CLC::haveConsensus: prop=%d/%d agree=%d closed=%d time=%d/%d") %
|
||||
currentProposers % previousProposers % currentAgree % currentClosed % currentAgreeTime % previousAgreeTime);
|
||||
|
||||
if (currentAgreeTime <= LEDGER_MIN_CONSENSUS)
|
||||
return false;
|
||||
|
||||
if (currentProposers < (previousProposers * 3 / 4))
|
||||
{ // Less than 3/4 of the last ledger's proposers are present, we may need more time
|
||||
if (currentAgreeTime < (previousAgreeTime + 2))
|
||||
{
|
||||
Log(lsTRACE) << "too fast, not enough proposers";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If 80% of current proposers (plus us) agree on a set, we have consensus
|
||||
int agreeWeight = (currentAgree * 100 + 100) / (currentProposers + 1);
|
||||
if (agreeWeight > 80)
|
||||
if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
|
||||
{
|
||||
Log(lsTRACE) << "normal consensus";
|
||||
return true;
|
||||
}
|
||||
|
||||
// If 50% of the nodes on your UNL (minus us) have closed, you should close
|
||||
int closeWeight = (currentClosed * 100 - 100) / (currentProposers + 1);
|
||||
if (closeWeight > 50)
|
||||
if (((currentClosed * 100 - 100) / (currentProposers + 1)) > 50)
|
||||
{
|
||||
Log(lsTRACE) << "many closers";
|
||||
return true;
|
||||
}
|
||||
|
||||
// no consensus yet
|
||||
Log(lsTRACE) << "no consensus";
|
||||
return false;
|
||||
}
|
||||
|
||||
int ContinuousLedgerTiming::getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq)
|
||||
{
|
||||
assert(ledgerSeq);
|
||||
assert(previousAgree); // TEMPORARY
|
||||
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
|
||||
{ // reduce resolution
|
||||
int i = 1;
|
||||
while (LedgerTimeResolution[i] != previousResolution)
|
||||
++i;
|
||||
return LedgerTimeResolution[i + 1];
|
||||
}
|
||||
|
||||
if ((previousAgree) && ((ledgerSeq % LEDGER_RES_INCREASE) == 0))
|
||||
{ // increase resolution
|
||||
int i = 1;
|
||||
while (LedgerTimeResolution[i] != previousResolution)
|
||||
++i;
|
||||
return LedgerTimeResolution[i - 1];
|
||||
}
|
||||
|
||||
return previousResolution;
|
||||
}
|
||||
|
||||
@@ -1,66 +1,53 @@
|
||||
#ifndef __LEDGERTIMING__
|
||||
#define __LEDGERTIMING__
|
||||
|
||||
#define LEDGER_CLOSE_FAST
|
||||
// #define LEDGER_CLOSE_SLOW
|
||||
|
||||
#ifdef LEDGER_CLOSE_FAST
|
||||
|
||||
// Time between one ledger close and the next ledger close
|
||||
# define LEDGER_INTERVAL 30
|
||||
|
||||
// Time before we take a position
|
||||
# define LEDGER_WOBBLE_TIME 1
|
||||
|
||||
// Time we acceleratet avalanche
|
||||
# define LEDGER_ACCEL_CONVERGE 10
|
||||
|
||||
// Time we permit avalanche to finish
|
||||
# define LEDGER_CONVERGE 14
|
||||
|
||||
// Maximum converge time
|
||||
# define LEDGER_MAX_CONVERGE 20
|
||||
|
||||
#define AV_PCT_STOP 85
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// BEGIN LEDGER_CLOSE_CONTINUOUS
|
||||
|
||||
// The number of seconds a ledger may remain idle before closing
|
||||
# define LEDGER_IDLE_INTERVAL 15
|
||||
|
||||
// How long we wait to transition from inactive to active
|
||||
# define LEDGER_IDLE_SPIN_TIME 2
|
||||
// The number of seconds a validation remains current
|
||||
# define LEDGER_MAX_INTERVAL 60
|
||||
|
||||
// Avalance tuning (percent of UNL voting yes for us to vote yes)
|
||||
#define AV_MIN_CONSENSUS 55
|
||||
#define AV_AVG_CONSENSUS 65
|
||||
#define AV_MAX_CONSENSUS 70
|
||||
// The number of seconds we wait minimum to ensure participation
|
||||
# define LEDGER_MIN_CONSENSUS 2
|
||||
|
||||
// Initial resolution of ledger close time
|
||||
# define LEDGER_TIME_ACCURACY 30
|
||||
|
||||
// How often to increase resolution
|
||||
# define LEDGER_RES_INCREASE 8
|
||||
|
||||
// How often to decrease resolution
|
||||
# define LEDGER_RES_DECREASE 1
|
||||
|
||||
// Avalanche tuning
|
||||
#define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
|
||||
|
||||
#define AV_MID_CONSENSUS_TIME 50 // percentage of previous close time before we advance
|
||||
#define AV_MID_CONSENSUS_PCT 65 // percentage of nodes that most vote yes after advancing
|
||||
|
||||
#define AV_LATE_CONSENSUS_TIME 85 // percentage of previous close time before we advance
|
||||
#define AV_LATE_CONSENSUS_PCT 70 // percentage of nodes that most vote yes after advancing
|
||||
|
||||
|
||||
class ContinuousLedgerTiming
|
||||
{
|
||||
public:
|
||||
|
||||
static int LedgerTimeResolution[];
|
||||
|
||||
// Returns the number of seconds the ledger was or should be open
|
||||
// Call when a consensus is reached and when any transaction is relayed to be added
|
||||
static int shouldClose(
|
||||
bool anyTransactions,
|
||||
int previousProposers, int proposersClosed,
|
||||
int previousOpenSeconds, int currentOpenSeconds);
|
||||
int previousSeconds, int currentSeconds);
|
||||
|
||||
static bool haveConsensus(
|
||||
int previousProposers, int currentProposers,
|
||||
int currentAgree, int currentClosed,
|
||||
int previousAgreeTime, int currentAgreeTime);
|
||||
|
||||
static int getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq);
|
||||
};
|
||||
|
||||
// END LEDGER_CLOSE_CONTINUOUS
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
// there's a functional network.
|
||||
|
||||
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
|
||||
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster)
|
||||
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster),
|
||||
mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -33,7 +34,7 @@ boost::posix_time::ptime NetworkOPs::getNetworkTimePT()
|
||||
return boost::posix_time::second_clock::universal_time();
|
||||
}
|
||||
|
||||
uint64 NetworkOPs::getNetworkTimeNC()
|
||||
uint32 NetworkOPs::getNetworkTimeNC()
|
||||
{
|
||||
return iToSeconds(getNetworkTimePT());
|
||||
}
|
||||
@@ -277,17 +278,9 @@ RippleState::pointer NetworkOPs::getRippleState(const uint256& uLedger, const ui
|
||||
// Other
|
||||
//
|
||||
|
||||
void NetworkOPs::setStateTimer(int sec)
|
||||
void NetworkOPs::setStateTimer()
|
||||
{ // set timer early if ledger is closing
|
||||
if (!mConsensus && ((mMode == omFULL) || (mMode == omTRACKING)))
|
||||
{
|
||||
uint64 consensusTime = mLedgerMaster->getCurrentLedger()->getCloseTimeNC() - LEDGER_WOBBLE_TIME;
|
||||
uint64 now = getNetworkTimeNC();
|
||||
|
||||
if (now >= consensusTime) sec = 1;
|
||||
else if (sec > (consensusTime - now)) sec = (consensusTime - now);
|
||||
}
|
||||
mNetTimer.expires_from_now(boost::posix_time::seconds(sec));
|
||||
mNetTimer.expires_from_now(boost::posix_time::seconds(1));
|
||||
mNetTimer.async_wait(boost::bind(&NetworkOPs::checkState, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
@@ -324,7 +317,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
Log(lsWARNING) << "Node count (" << peerList.size() <<
|
||||
") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ").";
|
||||
}
|
||||
setStateTimer(5);
|
||||
setStateTimer();
|
||||
return;
|
||||
}
|
||||
if (mMode == omDISCONNECTED)
|
||||
@@ -335,7 +328,8 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
|
||||
if (mConsensus)
|
||||
{
|
||||
setStateTimer(mConsensus->timerEntry());
|
||||
mConsensus->timerEntry();
|
||||
setStateTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -343,6 +337,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
// If full or tracking, check only at wobble time!
|
||||
uint256 networkClosed;
|
||||
bool ledgerChange = checkLastClosedLedger(peerList, networkClosed);
|
||||
assert(networkClosed.isNonZero());
|
||||
|
||||
// WRITEME: Unless we are in omFULL and in the process of doing a consensus,
|
||||
// we must count how many nodes share our LCL, how many nodes disagree with our LCL,
|
||||
@@ -365,7 +360,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
(theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4))
|
||||
setMode(omFULL);
|
||||
else
|
||||
Log(lsWARNING) << "Too late to go to full, will try in consensus window";
|
||||
Log(lsINFO) << "Will try to go to FULL in consensus window";
|
||||
}
|
||||
|
||||
if (mMode == omFULL)
|
||||
@@ -373,13 +368,11 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
// check if the ledger is bad enough to go to omTRACKING
|
||||
}
|
||||
|
||||
int secondsToClose = theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() -
|
||||
theApp->getOPs().getNetworkTimeNC();
|
||||
if ((!mConsensus) && (secondsToClose < LEDGER_WOBBLE_TIME)) // pre close wobble
|
||||
if ((!mConsensus) && (mMode != omDISCONNECTED))
|
||||
beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger());
|
||||
if (mConsensus)
|
||||
setStateTimer(mConsensus->timerEntry());
|
||||
else setStateTimer(4);
|
||||
mConsensus->timerEntry();
|
||||
setStateTimer();
|
||||
}
|
||||
|
||||
bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerList, uint256& networkClosed)
|
||||
@@ -401,11 +394,11 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
}
|
||||
|
||||
Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger();
|
||||
uint256 closedLedger=0;
|
||||
if(theConfig.LEDGER_CREATOR || ourClosed->getLedgerSeq() > 100)
|
||||
{
|
||||
closedLedger = ourClosed->getHash();
|
||||
uint256 closedLedger = ourClosed->getHash();
|
||||
ValidationCount& ourVC = ledgers[closedLedger];
|
||||
|
||||
if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING))
|
||||
{
|
||||
++ourVC.nodesUsing;
|
||||
ourVC.highNode = theApp->getWallet().getNodePublic();
|
||||
}
|
||||
@@ -449,25 +442,34 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
networkClosed = closedLedger;
|
||||
|
||||
if (!switchLedgers)
|
||||
{
|
||||
if (mAcquiringLedger)
|
||||
{
|
||||
mAcquiringLedger->abort();
|
||||
theApp->getMasterLedgerAcquire().dropLedger(mAcquiringLedger->getHash());
|
||||
mAcquiringLedger = LedgerAcquire::pointer();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Log(lsWARNING) << "We are not running on the consensus ledger";
|
||||
Log(lsINFO) << "Our LCL " << ourClosed->getHash().GetHex();
|
||||
Log(lsINFO) << "Net LCL " << closedLedger.GetHex();
|
||||
if ((mMode == omTRACKING) || (mMode == omFULL)) setMode(omCONNECTED);
|
||||
if ((mMode == omTRACKING) || (mMode == omFULL))
|
||||
setMode(omCONNECTED);
|
||||
|
||||
Ledger::pointer consensus = mLedgerMaster->getLedgerByHash(closedLedger);
|
||||
if (!consensus)
|
||||
{
|
||||
Log(lsINFO) << "Acquiring consensus ledger";
|
||||
LedgerAcquire::pointer acq = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
|
||||
if (!acq || acq->isFailed())
|
||||
Log(lsINFO) << "Acquiring consensus ledger " << closedLedger.GetHex();
|
||||
LedgerAcquire::pointer mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
|
||||
if (!mAcquiringLedger || mAcquiringLedger->isFailed())
|
||||
{
|
||||
theApp->getMasterLedgerAcquire().dropLedger(closedLedger);
|
||||
Log(lsERROR) << "Network ledger cannot be acquired";
|
||||
return true;
|
||||
}
|
||||
if (!acq->isComplete())
|
||||
if (!mAcquiringLedger->isComplete())
|
||||
{ // add more peers
|
||||
int count = 0;
|
||||
std::vector<Peer::pointer> peers=theApp->getConnectionPool().getPeerVector();
|
||||
@@ -477,7 +479,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
if ((*it)->getClosedLedgerHash() == closedLedger)
|
||||
{
|
||||
++count;
|
||||
acq->peerHas(*it);
|
||||
mAcquiringLedger->peerHas(*it);
|
||||
}
|
||||
}
|
||||
if (!count)
|
||||
@@ -486,12 +488,12 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
it != end; ++it)
|
||||
{
|
||||
if ((*it)->isConnected())
|
||||
acq->peerHas(*it);
|
||||
mAcquiringLedger->peerHas(*it);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
consensus = acq->getLedger();
|
||||
consensus = mAcquiringLedger->getLedger();
|
||||
}
|
||||
|
||||
// FIXME: If this rewinds the ledger sequence, or has the same sequence, we should update the status on
|
||||
@@ -506,12 +508,6 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
|
||||
|
||||
Log(lsERROR) << "ABNORMAL Switching last closed ledger to " << newLedger->getHash().GetHex();
|
||||
|
||||
if (mConsensus)
|
||||
{
|
||||
mConsensus->abort();
|
||||
mConsensus = boost::shared_ptr<LedgerConsensus>();
|
||||
}
|
||||
|
||||
newLedger->setClosed();
|
||||
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*newLedger));
|
||||
mLedgerMaster->switchLedgers(newLedger, openLedger);
|
||||
@@ -530,7 +526,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
|
||||
|
||||
int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger)
|
||||
{
|
||||
Log(lsINFO) << "Ledger close time for ledger " << closingLedger->getLedgerSeq();
|
||||
Log(lsINFO) << "Consensus time for ledger " << closingLedger->getLedgerSeq();
|
||||
Log(lsINFO) << " LCL is " << closingLedger->getParentHash().GetHex();
|
||||
|
||||
Ledger::pointer prevLedger = mLedgerMaster->getLedgerByHash(closingLedger->getParentHash());
|
||||
@@ -544,19 +540,17 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo
|
||||
assert(closingLedger->getParentHash() == mLedgerMaster->getClosedLedger()->getHash());
|
||||
|
||||
// Create a consensus object to get consensus on this ledger
|
||||
if (!!mConsensus)
|
||||
mConsensus->abort();
|
||||
assert(!mConsensus);
|
||||
prevLedger->setImmutable();
|
||||
mConsensus = boost::make_shared<LedgerConsensus>(
|
||||
networkClosed,
|
||||
prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
|
||||
networkClosed, prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
|
||||
|
||||
Log(lsDEBUG) << "Pre-close time, initiating consensus engine";
|
||||
Log(lsDEBUG) << "Initiating consensus engine";
|
||||
return mConsensus->startup();
|
||||
}
|
||||
|
||||
// <-- bool: true to relay
|
||||
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
|
||||
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime,
|
||||
const std::string& pubKey, const std::string& signature)
|
||||
{
|
||||
// JED: does mConsensus need to be locked?
|
||||
@@ -565,7 +559,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
|
||||
// XXX Take a vuc for pubkey.
|
||||
|
||||
// Get a preliminary hash to use to suppress duplicates
|
||||
Serializer s;
|
||||
Serializer s(128);
|
||||
s.add32(proposeSeq);
|
||||
s.add32(getCurrentLedgerID());
|
||||
s.addRaw(pubKey);
|
||||
@@ -579,14 +573,14 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
|
||||
}
|
||||
|
||||
if (!mConsensus)
|
||||
{
|
||||
{ // FIXME: CLC
|
||||
Log(lsWARNING) << "Received proposal when full but not during consensus window";
|
||||
return false;
|
||||
}
|
||||
|
||||
NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey));
|
||||
LedgerProposal::pointer proposal =
|
||||
boost::make_shared<LedgerProposal>(mConsensus->getLCL(), proposeSeq, proposeHash, naPeerPublic);
|
||||
boost::make_shared<LedgerProposal>(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, naPeerPublic);
|
||||
if (!proposal->checkSign(signature))
|
||||
{ // Note that if the LCL is different, the signature check will fail
|
||||
Log(lsWARNING) << "Ledger proposal fails signature check";
|
||||
@@ -594,7 +588,6 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
|
||||
}
|
||||
|
||||
// Is this node on our UNL?
|
||||
// XXX Is this right?
|
||||
if (!theApp->getUNL().nodeInUNL(proposal->peekPublic()))
|
||||
{
|
||||
Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " <<
|
||||
@@ -647,14 +640,8 @@ void NetworkOPs::endConsensus()
|
||||
void NetworkOPs::setMode(OperatingMode om)
|
||||
{
|
||||
if (mMode == om) return;
|
||||
if (mMode == omFULL)
|
||||
{
|
||||
if (mConsensus)
|
||||
{
|
||||
mConsensus->abort();
|
||||
mConsensus = boost::shared_ptr<LedgerConsensus>();
|
||||
}
|
||||
}
|
||||
if ((om >= omCONNECTED) && (mMode == omDISCONNECTED))
|
||||
mConnectTime = boost::posix_time::second_clock::universal_time();
|
||||
Log l((om < mMode) ? lsWARNING : lsINFO);
|
||||
if (om == omDISCONNECTED) l << "STATE->Disonnected";
|
||||
else if (om == omCONNECTED) l << "STATE->Connected";
|
||||
@@ -1064,6 +1051,15 @@ void NetworkOPs::unsubAccountTransaction(InfoSub* ispListener, const boost::unor
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkOPs::newLCL(int proposers, int convergeTime, const uint256& ledgerHash)
|
||||
{
|
||||
assert(convergeTime);
|
||||
mLastCloseProposers = proposers;
|
||||
mLastCloseConvergeTime = convergeTime;
|
||||
mLastCloseHash = ledgerHash;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void NetworkOPs::subAccountChanges(InfoSub* ispListener, const uint256 uLedgerHash)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "NicknameState.h"
|
||||
#include "RippleState.h"
|
||||
#include "SerializedValidation.h"
|
||||
#include "LedgerAcquire.h"
|
||||
|
||||
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
|
||||
#include <boost/interprocess/sync/sharable_lock.hpp>
|
||||
@@ -46,10 +47,12 @@ public:
|
||||
|
||||
protected:
|
||||
OperatingMode mMode;
|
||||
boost::posix_time::ptime mConnectTime;
|
||||
boost::asio::deadline_timer mNetTimer;
|
||||
boost::shared_ptr<LedgerConsensus> mConsensus;
|
||||
|
||||
LedgerMaster* mLedgerMaster;
|
||||
LedgerAcquire::pointer mAcquiringLedger;
|
||||
|
||||
void setMode(OperatingMode);
|
||||
|
||||
@@ -57,6 +60,11 @@ protected:
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::value_type subInfoMapValue;
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::iterator subInfoMapIterator;
|
||||
|
||||
// last ledger close
|
||||
int mLastCloseProposers, mLastCloseConvergeTime;
|
||||
uint256 mLastCloseHash;
|
||||
uint32 mLastCloseNetTime;
|
||||
|
||||
// XXX Split into more locks.
|
||||
boost::interprocess::interprocess_upgradable_mutex mMonitorLock;
|
||||
subInfoMapType mBootAccountInfo;
|
||||
@@ -77,7 +85,7 @@ public:
|
||||
NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster);
|
||||
|
||||
// network information
|
||||
uint64 getNetworkTimeNC();
|
||||
uint32 getNetworkTimeNC();
|
||||
boost::posix_time::ptime getNetworkTimePT();
|
||||
uint32 getCurrentLedgerID();
|
||||
OperatingMode getOperatingMode() { return mMode; }
|
||||
@@ -156,7 +164,7 @@ public:
|
||||
const std::vector<unsigned char>& myNode, std::list< std::vector<unsigned char> >& newNodes);
|
||||
|
||||
// ledger proposal/close functions
|
||||
bool recvPropose(uint32 proposeSeq, const uint256& proposeHash,
|
||||
bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime,
|
||||
const std::string& pubKey, const std::string& signature);
|
||||
bool gotTXData(boost::shared_ptr<Peer> peer, const uint256& hash,
|
||||
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
|
||||
@@ -171,7 +179,12 @@ public:
|
||||
bool checkLastClosedLedger(const std::vector<Peer::pointer>&, uint256& networkClosed);
|
||||
int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger);
|
||||
void endConsensus();
|
||||
void setStateTimer(int seconds);
|
||||
void setStateTimer();
|
||||
void newLCL(int proposers, int convergeTime, const uint256& ledgerHash);
|
||||
int getPreviousProposers() { return mLastCloseProposers; }
|
||||
int getPreviousSeconds() { return mLastCloseConvergeTime; }
|
||||
uint32 getLastCloseNetTime() { return mLastCloseNetTime; }
|
||||
void setLastCloseNetTime(uint32 t) { mLastCloseNetTime = t; }
|
||||
Json::Value getServerInfo();
|
||||
|
||||
// client information retrieval functions
|
||||
|
||||
17
src/Peer.cpp
17
src/Peer.cpp
@@ -571,14 +571,15 @@ void Peer::recvHello(newcoin::TMHello& packet)
|
||||
// Cancel verification timeout.
|
||||
(void) mVerifyTimer.cancel();
|
||||
|
||||
uint64 minTime = theApp->getOPs().getNetworkTimeNC() - 4;
|
||||
uint64 maxTime = minTime + 8;
|
||||
uint32 minTime = theApp->getOPs().getNetworkTimeNC() - 4;
|
||||
uint32 maxTime = minTime + 8;
|
||||
|
||||
if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime)))
|
||||
{
|
||||
Log(lsINFO) << "Recv(Hello): Disconnect: Clocks are too far off";
|
||||
Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off";
|
||||
}
|
||||
else if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR))
|
||||
|
||||
if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR))
|
||||
{
|
||||
Log(lsINFO) << "Recv(Hello): Server requires protocol version " <<
|
||||
GET_VERSION_MAJOR(packet.protoversion()) << "." << GET_VERSION_MINOR(packet.protoversion())
|
||||
@@ -716,7 +717,8 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet)
|
||||
uint256 currentTxHash;
|
||||
memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32);
|
||||
|
||||
if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.nodepubkey(), packet.signature()))
|
||||
if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.closetime(),
|
||||
packet.nodepubkey(), packet.signature()))
|
||||
{ // FIXME: Not all nodes will want proposals
|
||||
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, newcoin::mtPROPOSE_LEDGER);
|
||||
theApp->getConnectionPool().relayMessage(this, message);
|
||||
@@ -1111,6 +1113,11 @@ void Peer::recvLedger(newcoin::TMLedgerData& packet)
|
||||
punishPeer(PP_UNWANTED_DATA);
|
||||
}
|
||||
|
||||
bool Peer::hasLedger(const uint256& hash) const
|
||||
{
|
||||
return (hash == mClosedLedgerHash) || (hash == mPreviousLedgerHash);
|
||||
}
|
||||
|
||||
// Get session information we can sign to prevent man in the middle attack.
|
||||
// (both sides get the same information, neither side controls it)
|
||||
void Peer::getSessionCookie(std::string& strDst)
|
||||
|
||||
@@ -159,6 +159,7 @@ public:
|
||||
static PackedMessage::pointer createGetFullLedger(uint256& hash);
|
||||
|
||||
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
|
||||
bool hasLedger(const uint256& hash) const;
|
||||
NewcoinAddress getNodePublic() const { return mNodePublic; }
|
||||
void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); }
|
||||
};
|
||||
|
||||
@@ -46,6 +46,13 @@ SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(Modifying)
|
||||
mTNByID[*root] = root;
|
||||
}
|
||||
|
||||
SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(Synching)
|
||||
{ // FIXME: Need to acquire root node
|
||||
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
||||
root->makeInner();
|
||||
mTNByID[*root] = root;
|
||||
}
|
||||
|
||||
SHAMap::pointer SHAMap::snapShot(bool isMutable)
|
||||
{ // Return a new SHAMap that is an immutable snapshot of this one
|
||||
// Initially nodes are shared, but CoW is forced on both ledgers
|
||||
@@ -158,7 +165,7 @@ SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify)
|
||||
|
||||
SHAMapTreeNode* SHAMap::walkToPointer(const uint256& id)
|
||||
{
|
||||
SHAMapTreeNode* inNode = &*root;
|
||||
SHAMapTreeNode* inNode = root.get();
|
||||
while (!inNode->isLeaf())
|
||||
{
|
||||
int branch = inNode->selectBranch(id);
|
||||
@@ -201,12 +208,12 @@ SHAMapTreeNode* SHAMap::getNodePointer(const SHAMapNode& id, const uint256& hash
|
||||
{ // fast, but you do not hold a reference
|
||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = mTNByID.find(id);
|
||||
if (it != mTNByID.end())
|
||||
return &*it->second;
|
||||
return it->second.get();
|
||||
|
||||
SHAMapTreeNode::pointer node = fetchNodeExternal(id, hash);
|
||||
if (!mTNByID.insert(std::make_pair(id, node)).second)
|
||||
assert(false);
|
||||
return &*node;
|
||||
return node.get();
|
||||
}
|
||||
|
||||
void SHAMap::returnNode(SHAMapTreeNode::pointer& node, bool modify)
|
||||
@@ -338,13 +345,13 @@ void SHAMap::eraseChildren(SHAMapTreeNode::pointer node)
|
||||
SHAMapItem::pointer SHAMap::peekFirstItem()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
return firstBelow(&*root);
|
||||
return firstBelow(root.get());
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::peekLastItem()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
return lastBelow(&*root);
|
||||
return lastBelow(root.get());
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
|
||||
@@ -366,7 +373,7 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
|
||||
if(!node->isEmptyBranch(i))
|
||||
{
|
||||
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
|
||||
SHAMapItem::pointer item = firstBelow(&*node);
|
||||
SHAMapItem::pointer item = firstBelow(node.get());
|
||||
if (!item) throw std::runtime_error("missing node");
|
||||
return item;
|
||||
}
|
||||
@@ -394,7 +401,7 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id)
|
||||
if(!node->isEmptyBranch(i))
|
||||
{
|
||||
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
|
||||
SHAMapItem::pointer item = firstBelow(&*node);
|
||||
SHAMapItem::pointer item = firstBelow(node.get());
|
||||
if (!item) throw std::runtime_error("missing node");
|
||||
return item;
|
||||
}
|
||||
@@ -465,7 +472,7 @@ bool SHAMap::delItem(const uint256& id)
|
||||
}
|
||||
else if(bc==1)
|
||||
{ // pull up on the thread
|
||||
SHAMapItem::pointer item = onlyBelow(&*node);
|
||||
SHAMapItem::pointer item = onlyBelow(node.get());
|
||||
if(item)
|
||||
{
|
||||
eraseChildren(node);
|
||||
@@ -488,14 +495,15 @@ bool SHAMap::delItem(const uint256& id)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction)
|
||||
bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta)
|
||||
{ // add the specified item, does not update
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "aGI " << item->getTag().GetHex() << std::endl;
|
||||
#endif
|
||||
|
||||
uint256 tag = item->getTag();
|
||||
SHAMapTreeNode::TNType type = isTransaction ? SHAMapTreeNode::tnTRANSACTION : SHAMapTreeNode::tnACCOUNT_STATE;
|
||||
SHAMapTreeNode::TNType type = !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE :
|
||||
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM);
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
assert(mState != Immutable);
|
||||
@@ -580,12 +588,12 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction)
|
||||
bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction, bool hasMetaData)
|
||||
{
|
||||
return addGiveItem(boost::make_shared<SHAMapItem>(i), isTransaction);
|
||||
return addGiveItem(boost::make_shared<SHAMapItem>(i), isTransaction, hasMetaData);
|
||||
}
|
||||
|
||||
bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction)
|
||||
bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta)
|
||||
{ // can't change the tag but can change the hash
|
||||
uint256 tag = item->getTag();
|
||||
|
||||
@@ -605,7 +613,8 @@ bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction)
|
||||
}
|
||||
|
||||
returnNode(node, true);
|
||||
if (!node->setItem(item, isTransaction ? SHAMapTreeNode::tnTRANSACTION : SHAMapTreeNode::tnACCOUNT_STATE))
|
||||
if (!node->setItem(item, !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE :
|
||||
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM)))
|
||||
{
|
||||
Log(lsWARNING) << "SHAMap setItem, no change";
|
||||
return true;
|
||||
@@ -747,8 +756,8 @@ BOOST_AUTO_TEST_CASE( SHAMap_test )
|
||||
SHAMap sMap;
|
||||
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
|
||||
|
||||
if(!sMap.addItem(i2, true)) BOOST_FAIL("no add");
|
||||
if(!sMap.addItem(i1, true)) BOOST_FAIL("no add");
|
||||
if(!sMap.addItem(i2, true, false)) BOOST_FAIL("no add");
|
||||
if(!sMap.addItem(i1, true, false)) BOOST_FAIL("no add");
|
||||
|
||||
SHAMapItem::pointer i;
|
||||
|
||||
@@ -759,9 +768,9 @@ BOOST_AUTO_TEST_CASE( SHAMap_test )
|
||||
i = sMap.peekNextItem(i->getTag());
|
||||
if (i) BOOST_FAIL("bad traverse");
|
||||
|
||||
sMap.addItem(i4, true);
|
||||
sMap.addItem(i4, true, false);
|
||||
sMap.delItem(i2.getTag());
|
||||
sMap.addItem(i3, true);
|
||||
sMap.addItem(i3, true, false);
|
||||
|
||||
i = sMap.peekFirstItem();
|
||||
if (!i || (*i != i1)) BOOST_FAIL("bad traverse");
|
||||
|
||||
22
src/SHAMap.h
22
src/SHAMap.h
@@ -135,8 +135,9 @@ public:
|
||||
{
|
||||
tnERROR = 0,
|
||||
tnINNER = 1,
|
||||
tnTRANSACTION = 2,
|
||||
tnACCOUNT_STATE = 3
|
||||
tnTRANSACTION_NM = 2, // transaction, no metadata
|
||||
tnTRANSACTION_MD = 3, // transaction, with metadata
|
||||
tnACCOUNT_STATE = 4
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -173,11 +174,13 @@ public:
|
||||
TNType getType() const { return mType; }
|
||||
|
||||
// type functions
|
||||
bool isLeaf() const { return (mType == tnTRANSACTION) || (mType == tnACCOUNT_STATE); }
|
||||
bool isLeaf() const { return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD) ||
|
||||
(mType == tnACCOUNT_STATE); }
|
||||
bool isInner() const { return mType == tnINNER; }
|
||||
bool isValid() const { return mType != tnERROR; }
|
||||
bool isTransaction() const { return mType != tnTRANSACTION; }
|
||||
bool isAccountState() const { return mType != tnACCOUNT_STATE; }
|
||||
bool isTransaction() const { return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD); }
|
||||
bool hasMetaData() const { return mType == tnTRANSACTION_MD; }
|
||||
bool isAccountState() const { return mType == tnACCOUNT_STATE; }
|
||||
|
||||
// inner node functions
|
||||
bool isInnerNode() const { return !mItem; }
|
||||
@@ -287,6 +290,7 @@ public:
|
||||
|
||||
// build new map
|
||||
SHAMap(uint32 seq = 0);
|
||||
SHAMap(const uint256& hash);
|
||||
|
||||
// Returns a new map that's a snapshot of this one. Force CoW
|
||||
SHAMap::pointer snapShot(bool isMutable);
|
||||
@@ -299,15 +303,15 @@ public:
|
||||
// normal hash access functions
|
||||
bool hasItem(const uint256& id);
|
||||
bool delItem(const uint256& id);
|
||||
bool addItem(const SHAMapItem& i, bool isTransaction);
|
||||
bool updateItem(const SHAMapItem& i, bool isTransaction);
|
||||
bool addItem(const SHAMapItem& i, bool isTransaction, bool hasMeta);
|
||||
bool updateItem(const SHAMapItem& i, bool isTransaction, bool hasMeta);
|
||||
SHAMapItem getItem(const uint256& id);
|
||||
uint256 getHash() const { return root->getNodeHash(); }
|
||||
uint256 getHash() { return root->getNodeHash(); }
|
||||
|
||||
// save a copy if you have a temporary anyway
|
||||
bool updateGiveItem(SHAMapItem::pointer, bool isTransaction);
|
||||
bool addGiveItem(SHAMapItem::pointer, bool isTransaction);
|
||||
bool updateGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta);
|
||||
bool addGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta);
|
||||
|
||||
// save a copy if you only need a temporary
|
||||
SHAMapItem::pointer peekItem(const uint256& id);
|
||||
|
||||
@@ -197,7 +197,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
Serializer s(rawNode);
|
||||
int type = s.removeLastByte();
|
||||
int len = s.getLength();
|
||||
if ((type < 0) || (type > 3))
|
||||
if ((type < 0) || (type > 4))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Invalid wire format node" << std::endl;
|
||||
@@ -210,14 +210,14 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
if (type == 0)
|
||||
{ // transaction
|
||||
mItem = boost::make_shared<SHAMapItem>(s.getPrefixHash(sHP_TransactionID), s.peekData());
|
||||
mType = tnTRANSACTION;
|
||||
mType = tnTRANSACTION_NM;
|
||||
}
|
||||
else if (type == 1)
|
||||
{ // account state
|
||||
if (len < (256 / 8))
|
||||
throw std::runtime_error("short AS node");
|
||||
uint256 u;
|
||||
s.get256(u, len - 32);
|
||||
s.get256(u, len - (256 / 8));
|
||||
s.chop(256 / 8);
|
||||
if (u.isZero()) throw std::runtime_error("invalid AS node");
|
||||
mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
|
||||
@@ -242,6 +242,18 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
}
|
||||
mType = tnINNER;
|
||||
}
|
||||
else if (type == 4)
|
||||
{ // transaction with metadata
|
||||
if (len < (256 / 8))
|
||||
throw std::runtime_error("short TM node");
|
||||
uint256 u;
|
||||
s.get256(u, len - (256 / 8));
|
||||
s.chop(256 / 8);
|
||||
if (u.isZero())
|
||||
throw std::runtime_error("invalid TM node");
|
||||
mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
|
||||
mType = tnTRANSACTION_MD;
|
||||
}
|
||||
}
|
||||
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
@@ -258,8 +270,8 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
|
||||
if (prefix == sHP_TransactionID)
|
||||
{
|
||||
mItem = boost::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData());
|
||||
mType = tnTRANSACTION;
|
||||
mItem = boost::make_shared<SHAMapItem>(Serializer::getSHA512Half(rawNode), s.peekData());
|
||||
mType = tnTRANSACTION_NM;
|
||||
}
|
||||
else if (prefix == sHP_LeafNode)
|
||||
{
|
||||
@@ -282,6 +294,13 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
s.get256(mHashes[i] , i * 32);
|
||||
mType = tnINNER;
|
||||
}
|
||||
else if (prefix == sHP_TransactionNode)
|
||||
{
|
||||
uint256 txID; // WRITEME: Need code to extract transaction ID from TX+MD
|
||||
assert(false);
|
||||
mItem = boost::make_shared<SHAMapItem>(txID, s.peekData());
|
||||
mType = tnTRANSACTION_MD;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsINFO) << "Unknown node prefix " << std::hex << prefix << std::dec;
|
||||
@@ -310,16 +329,20 @@ bool SHAMapTreeNode::updateHash()
|
||||
}
|
||||
else if (mType == tnACCOUNT_STATE)
|
||||
{
|
||||
Serializer s;
|
||||
Serializer s((256 + 32) / 8 + mItem->peekData().size());
|
||||
s.add32(sHP_LeafNode);
|
||||
mItem->addRaw(s);
|
||||
s.add256(mItem->getTag());
|
||||
nh = s.getSHA512Half();
|
||||
}
|
||||
else if (mType == tnTRANSACTION)
|
||||
else if (mType == tnTRANSACTION_NM)
|
||||
{
|
||||
nh = Serializer::getPrefixHash(sHP_TransactionID, mItem->peekData());
|
||||
}
|
||||
else if (mType == tnTRANSACTION_MD)
|
||||
{
|
||||
nh = Serializer::getPrefixHash(sHP_TransactionNode, mItem->peekData());
|
||||
}
|
||||
else assert(false);
|
||||
|
||||
if (nh == mHash) return false;
|
||||
@@ -375,7 +398,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
|
||||
s.add8(1);
|
||||
}
|
||||
}
|
||||
else if (mType == tnTRANSACTION)
|
||||
else if (mType == tnTRANSACTION_NM)
|
||||
{
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
{
|
||||
@@ -388,7 +411,22 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
|
||||
s.add8(0);
|
||||
}
|
||||
}
|
||||
else assert(false);
|
||||
else if (mType == tnTRANSACTION_MD)
|
||||
{
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
{
|
||||
s.add32(sHP_TransactionNode);
|
||||
mItem->addRaw(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
mItem->addRaw(s);
|
||||
s.add256(mItem->getTag());
|
||||
s.add8(4);
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
|
||||
bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type)
|
||||
|
||||
@@ -362,7 +362,7 @@ static bool confuseMap(SHAMap &map, int count)
|
||||
{
|
||||
SHAMapItem::pointer item = makeRandomAS();
|
||||
items.push_back(item->getTag());
|
||||
if (!map.addItem(*item, false))
|
||||
if (!map.addItem(*item, false, false))
|
||||
{
|
||||
Log(lsFATAL) << "Unable to add item to map";
|
||||
return false;
|
||||
@@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test )
|
||||
Log(lsTRACE) << "Adding random data";
|
||||
int items = 10000;
|
||||
for (int i = 0; i < items; ++i)
|
||||
source.addItem(*makeRandomAS(), false);
|
||||
source.addItem(*makeRandomAS(), false, false);
|
||||
|
||||
Log(lsTRACE) << "Adding items, then removing them";
|
||||
if (!confuseMap(source, 500)) BOOST_FAIL("ConfuseMap");
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
SOElement SerializedValidation::sValidationFormat[] = {
|
||||
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
|
||||
{ sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 },
|
||||
{ sfCloseTime, "CloseTime", STI_UINT64, SOE_REQUIRED, 0 },
|
||||
{ sfCloseTime, "CloseTime", STI_UINT32, SOE_REQUIRED, 0 },
|
||||
{ sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 },
|
||||
{ sfVersion, "Version", STI_UINT32, SOE_IFFLAG, 1 },
|
||||
{ sfExtensions, "Extensions", STI_TL, SOE_IFFLAG, 0x01000000 },
|
||||
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 },
|
||||
};
|
||||
|
||||
@@ -21,12 +19,12 @@ SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSi
|
||||
if (checkSignature && !isValid()) throw std::runtime_error("Invalid validation");
|
||||
}
|
||||
|
||||
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint64 closeTime,
|
||||
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 closeTime,
|
||||
const NewcoinAddress& naSeed, bool isFull)
|
||||
: STObject(sValidationFormat), mSignature("Signature"), mTrusted(false)
|
||||
{
|
||||
setValueFieldH256(sfLedgerHash, ledgerHash);
|
||||
setValueFieldU64(sfCloseTime, closeTime);
|
||||
setValueFieldU32(sfCloseTime, closeTime);
|
||||
if (naSeed.isValid())
|
||||
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
|
||||
if (!isFull) setFlag(sFullFlag);
|
||||
@@ -52,9 +50,9 @@ uint256 SerializedValidation::getLedgerHash() const
|
||||
return getValueFieldH256(sfLedgerHash);
|
||||
}
|
||||
|
||||
uint64 SerializedValidation::getCloseTime() const
|
||||
uint32 SerializedValidation::getCloseTime() const
|
||||
{
|
||||
return getValueFieldU64(sfCloseTime);
|
||||
return getValueFieldU32(sfCloseTime);
|
||||
}
|
||||
|
||||
bool SerializedValidation::isValid() const
|
||||
|
||||
@@ -22,10 +22,10 @@ public:
|
||||
SerializedValidation(SerializerIterator& sit, bool checkSignature = true);
|
||||
SerializedValidation(const Serializer& s, bool checkSignature = true);
|
||||
|
||||
SerializedValidation(const uint256& ledgerHash, uint64 closeTime, const NewcoinAddress& naSeed, bool isFull);
|
||||
SerializedValidation(const uint256& ledgerHash, uint32 closeTime, const NewcoinAddress& naSeed, bool isFull);
|
||||
|
||||
uint256 getLedgerHash() const;
|
||||
uint64 getCloseTime() const;
|
||||
uint32 getCloseTime() const;
|
||||
NewcoinAddress getSignerPublic() const;
|
||||
bool isValid() const;
|
||||
bool isFull() const;
|
||||
|
||||
@@ -32,8 +32,8 @@ public:
|
||||
// assemble functions
|
||||
int add8(unsigned char byte);
|
||||
int add16(uint16);
|
||||
int add32(uint32); // ledger indexes, account sequence
|
||||
int add64(uint64); // timestamps, amounts
|
||||
int add32(uint32); // ledger indexes, account sequence, timestamps
|
||||
int add64(uint64); // native currency amounts
|
||||
int add128(const uint128&); // private key generators
|
||||
int add160(const uint160&); // account names, hankos
|
||||
int add256(const uint256&); // transaction and ledger hashes
|
||||
|
||||
@@ -476,18 +476,6 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac
|
||||
return terSUCCESS;
|
||||
}
|
||||
|
||||
Ledger::pointer TransactionEngine::getTransactionLedger(uint32 targetLedger)
|
||||
{
|
||||
Ledger::pointer ledger = mDefaultLedger;
|
||||
if (mAlternateLedger && (targetLedger != 0) &&
|
||||
(targetLedger != mLedger->getLedgerSeq()) && (targetLedger == mAlternateLedger->getLedgerSeq()))
|
||||
{
|
||||
Log(lsINFO) << "Transaction goes into wobble ledger";
|
||||
ledger = mAlternateLedger;
|
||||
}
|
||||
return ledger;
|
||||
}
|
||||
|
||||
bool TransactionEngine::entryExists(SLE::pointer sleEntry)
|
||||
{
|
||||
return mEntries.find(sleEntry) != mEntries.end();
|
||||
@@ -576,16 +564,10 @@ void TransactionEngine::entryUnfunded(SLE::pointer sleEntry)
|
||||
}
|
||||
|
||||
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
|
||||
TransactionEngineParams params, uint32 targetLedger)
|
||||
{
|
||||
return applyTransaction(txn, params, getTransactionLedger(targetLedger));
|
||||
}
|
||||
|
||||
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
|
||||
TransactionEngineParams params, Ledger::pointer ledger)
|
||||
TransactionEngineParams params)
|
||||
{
|
||||
Log(lsTRACE) << "applyTransaction>";
|
||||
mLedger = ledger;
|
||||
assert(mLedger);
|
||||
mLedgerParentCloseTime = mLedger->getParentCloseTimeNC();
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -724,12 +706,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
}
|
||||
|
||||
if (terSUCCESS != terResult)
|
||||
{
|
||||
// Avoid unnecessary locking.
|
||||
mLedger = Ledger::pointer();
|
||||
|
||||
return terResult;
|
||||
}
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
|
||||
|
||||
@@ -1072,7 +1049,6 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
mLedger->destroyCoins(saPaid.getNValue());
|
||||
}
|
||||
|
||||
mLedger = Ledger::pointer();
|
||||
mEntries.clear();
|
||||
|
||||
return terResult;
|
||||
|
||||
@@ -155,7 +155,6 @@ private:
|
||||
STAmount& saTakerGot);
|
||||
|
||||
protected:
|
||||
Ledger::pointer mDefaultLedger, mAlternateLedger;
|
||||
Ledger::pointer mLedger;
|
||||
uint64 mLedgerParentCloseTime;
|
||||
|
||||
@@ -189,20 +188,12 @@ protected:
|
||||
|
||||
public:
|
||||
TransactionEngine() { ; }
|
||||
TransactionEngine(Ledger::pointer ledger) : mDefaultLedger(ledger) { ; }
|
||||
TransactionEngine(Ledger::pointer ledger) : mLedger(ledger) { ; }
|
||||
|
||||
Ledger::pointer getDefaultLedger() { return mDefaultLedger; }
|
||||
void setDefaultLedger(Ledger::pointer ledger) { mDefaultLedger = ledger; }
|
||||
Ledger::pointer getAlternateLedger() { return mAlternateLedger; }
|
||||
void setAlternateLedger(Ledger::pointer ledger) { mAlternateLedger = ledger; }
|
||||
void setLedger(Ledger::pointer ledger) { mDefaultLedger = ledger;
|
||||
mAlternateLedger = Ledger::pointer(); }
|
||||
Ledger::pointer getLedger() { return mLedger; }
|
||||
void setLedger(Ledger::pointer ledger) { assert(ledger); mLedger = ledger; }
|
||||
|
||||
Ledger::pointer getTransactionLedger(uint32 targetLedger);
|
||||
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams,
|
||||
Ledger::pointer ledger);
|
||||
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams,
|
||||
uint32 targetLedger);
|
||||
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams);
|
||||
};
|
||||
|
||||
inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
|
||||
|
||||
@@ -11,9 +11,9 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val)
|
||||
if (theApp->getUNL().nodeInUNL(val->getSignerPublic()))
|
||||
{
|
||||
val->setTrusted();
|
||||
uint64 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint64 valClose = val->getCloseTime();
|
||||
if ((now > valClose) && (now < (valClose + LEDGER_INTERVAL)))
|
||||
uint32 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint32 valClose = val->getCloseTime();
|
||||
if ((now > valClose) && (now < (valClose + LEDGER_MAX_INTERVAL)))
|
||||
isCurrent = true;
|
||||
else
|
||||
Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose;
|
||||
@@ -55,19 +55,19 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren
|
||||
trusted = untrusted = 0;
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger);
|
||||
uint64 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint32 now = theApp->getOPs().getNetworkTimeNC();
|
||||
if (it != mValidations.end())
|
||||
{
|
||||
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
|
||||
{
|
||||
bool trusted = vit->second->isTrusted();
|
||||
if (trusted && currentOnly)
|
||||
bool isTrusted = vit->second->isTrusted();
|
||||
if (isTrusted && currentOnly)
|
||||
{
|
||||
uint64 closeTime = vit->second->getCloseTime();
|
||||
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_INTERVAL)))
|
||||
uint32 closeTime = vit->second->getCloseTime();
|
||||
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_MAX_INTERVAL)))
|
||||
trusted = false;
|
||||
}
|
||||
if (trusted)
|
||||
if (isTrusted)
|
||||
++trusted;
|
||||
else
|
||||
++untrusted;
|
||||
@@ -75,9 +75,38 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren
|
||||
}
|
||||
}
|
||||
|
||||
int ValidationCollection::getTrustedValidationCount(const uint256& ledger)
|
||||
{
|
||||
int trusted = 0;
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
for (boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger),
|
||||
end = mValidations.end(); it != end; ++it)
|
||||
{
|
||||
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
|
||||
{
|
||||
if (vit->second->isTrusted())
|
||||
++trusted;
|
||||
}
|
||||
}
|
||||
return trusted;
|
||||
}
|
||||
|
||||
int ValidationCollection::getCurrentValidationCount(uint32 afterTime)
|
||||
{
|
||||
int count = 0;
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
for (boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin(),
|
||||
end = mCurrentValidations.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second->isTrusted() && (it->second->getCloseTime() > afterTime))
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
|
||||
{
|
||||
uint64 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint32 now = theApp->getOPs().getNetworkTimeNC();
|
||||
boost::unordered_map<uint256, int> ret;
|
||||
|
||||
{
|
||||
@@ -85,14 +114,10 @@ boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
|
||||
while (it != mCurrentValidations.end())
|
||||
{
|
||||
if (now > (it->second->getCloseTime() + LEDGER_INTERVAL))
|
||||
{
|
||||
Log(lsTRACE) << "Erasing validation for " << it->second->getLedgerHash().GetHex();
|
||||
if (now > (it->second->getCloseTime() + LEDGER_MAX_INTERVAL))
|
||||
it = mCurrentValidations.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsTRACE) << "Counting validation for " << it->second->getLedgerHash().GetHex();
|
||||
++ret[it->second->getLedgerHash()];
|
||||
++it;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
bool addValidation(SerializedValidation::pointer);
|
||||
ValidationSet getValidations(const uint256& ledger);
|
||||
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted);
|
||||
int getTrustedValidationCount(const uint256& ledger);
|
||||
int getCurrentValidationCount(uint32 afterTime);
|
||||
boost::unordered_map<uint256, int> getCurrentValidations();
|
||||
};
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
// Versions
|
||||
//
|
||||
|
||||
// Version of this software:
|
||||
#define SERVER_VERSION_MAJOR 0
|
||||
#define SERVER_VERSION_MINOR 1
|
||||
#define SERVER_VERSION_MINOR 3
|
||||
#define SERVER_VERSION_SUB "-a"
|
||||
#define SERVER_NAME "NewCoin"
|
||||
|
||||
@@ -17,11 +16,11 @@
|
||||
|
||||
// Version we prefer to speak:
|
||||
#define PROTO_VERSION_MAJOR 0
|
||||
#define PROTO_VERSION_MINOR 2
|
||||
#define PROTO_VERSION_MINOR 3
|
||||
|
||||
// Version we wil speak to:
|
||||
#define MIN_PROTO_MAJOR 0
|
||||
#define MIN_PROTO_MINOR 2
|
||||
#define MIN_PROTO_MINOR 3
|
||||
|
||||
#define MAKE_VERSION_INT(maj,min) ((maj << 16) | min)
|
||||
#define GET_VERSION_MAJOR(ver) (ver >> 16)
|
||||
|
||||
@@ -91,6 +91,7 @@ int main(int argc, char* argv[])
|
||||
("rpc", "Perform rpc command (default).")
|
||||
("test,t", "Perform unit tests.")
|
||||
("parameters", po::value< vector<string> >(), "Specify comma separated parameters.")
|
||||
("verbose,v", "Increase log level")
|
||||
;
|
||||
|
||||
// Interpret positional arguments as --parameters.
|
||||
@@ -132,6 +133,11 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (vm.count("verbose"))
|
||||
{
|
||||
Log::setMinSeverity(lsTRACE);
|
||||
}
|
||||
|
||||
if (!iResult)
|
||||
{
|
||||
theConfig.setup(vm.count("conf") ? vm["conf"].as<std::string>() : "");
|
||||
|
||||
@@ -105,9 +105,10 @@ message TMProposeSet {
|
||||
required uint32 proposeSeq = 1;
|
||||
required bytes currentTxHash = 2; // the hash of the ledger we are proposing
|
||||
required bytes nodePubKey = 3;
|
||||
required bytes signature = 4; // signature of above fields
|
||||
repeated bytes addedTransactions = 5; // not required if number is large
|
||||
repeated bytes removedTransactions = 6; // not required if number is large
|
||||
required uint32 closeTime = 4;
|
||||
required bytes signature = 5; // signature of above fields
|
||||
repeated bytes addedTransactions = 6; // not required if number is large
|
||||
repeated bytes removedTransactions = 7; // not required if number is large
|
||||
}
|
||||
|
||||
enum TxSetStatus {
|
||||
|
||||
Reference in New Issue
Block a user