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