mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge branch 'master' into ripple
Conflicts: src/LedgerEntrySet.cpp
This commit is contained in:
@@ -146,6 +146,7 @@
|
||||
<ClCompile Include="src\SHAMapDiff.cpp" />
|
||||
<ClCompile Include="src\SHAMapNodes.cpp" />
|
||||
<ClCompile Include="src\SHAMapSync.cpp" />
|
||||
<ClCompile Include="src\SNTPClient.cpp" />
|
||||
<ClCompile Include="src\Suppression.cpp" />
|
||||
<ClCompile Include="src\Transaction.cpp" />
|
||||
<ClCompile Include="src\TransactionEngine.cpp" />
|
||||
@@ -248,17 +249,13 @@
|
||||
<None Include="html\newcoin.html">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="Issues" />
|
||||
<None Include="Makefile" />
|
||||
<None Include="newcoind.cfg" />
|
||||
<None Include="notes.txt" />
|
||||
<CustomBuild Include="src\newcoin.proto">
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\protoc-2.4.1-win32\protoc -I=..\newcoin\src --cpp_out=..\newcoin\obj\src ..\newcoin\src\newcoin.proto</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">obj\src\newcoin.pb.h</Outputs>
|
||||
</CustomBuild>
|
||||
<None Include="SConstruct" />
|
||||
<None Include="todo.txt" />
|
||||
<None Include="validators.txt" />
|
||||
<None Include="wallet.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -273,6 +273,9 @@
|
||||
<ClCompile Include="src\TransactionMeta.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\SNTPClient.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="KnownNodeList.h">
|
||||
@@ -506,16 +509,12 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="wallet.xml" />
|
||||
<None Include="notes.txt" />
|
||||
<None Include="html\newcoin.html">
|
||||
<Filter>html</Filter>
|
||||
</None>
|
||||
<None Include="todo.txt" />
|
||||
<None Include="Makefile" />
|
||||
<None Include="SConstruct" />
|
||||
<None Include="newcoind.cfg" />
|
||||
<None Include="validators.txt" />
|
||||
<None Include="Issues" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="src\newcoin.proto" />
|
||||
|
||||
10
newcoind.cfg
10
newcoind.cfg
@@ -85,6 +85,10 @@
|
||||
# 192.168.0.1 3939
|
||||
# 2001:0db8:0100:f101:0210:a4ff:fee3:9566
|
||||
#
|
||||
# [sntp_servers]
|
||||
# IP address or domain of servers to use for time synchronization.
|
||||
# The default time servers are suitable for servers located in the United States
|
||||
#
|
||||
# [peer_ip]:
|
||||
# IP address or domain to bind to allow external connections from peers.
|
||||
# Defaults to not allow external connections from peers.
|
||||
@@ -140,6 +144,12 @@
|
||||
[debug_logfile]
|
||||
debug.log
|
||||
|
||||
[sntp_servers]
|
||||
time.windows.com
|
||||
time.apple.com
|
||||
time.nist.gov
|
||||
pool.ntp.org
|
||||
|
||||
[validation_seed]
|
||||
shh1D4oj5czH3PUEjYES8c7Bay3tE
|
||||
|
||||
|
||||
@@ -446,7 +446,7 @@ bool STAmount::operator==(const STAmount& a) const
|
||||
|
||||
bool STAmount::operator!=(const STAmount& a) const
|
||||
{
|
||||
return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative!= a.mIsNegative) || !isComparable(a);
|
||||
return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative != a.mIsNegative) || !isComparable(a);
|
||||
}
|
||||
|
||||
bool STAmount::operator<(const STAmount& a) const
|
||||
@@ -762,6 +762,14 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn)
|
||||
return (ret << (64 - 8)) | r.getMantissa();
|
||||
}
|
||||
|
||||
STAmount STAmount::setRate(uint64 rate, const uint160& currencyOut)
|
||||
{
|
||||
uint64 mantissa = rate & ~(255ull << (64 - 8));
|
||||
int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
|
||||
|
||||
return STAmount(currencyOut, mantissa, exponent);
|
||||
}
|
||||
|
||||
// Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds.
|
||||
// --> saOfferFunds: Limit for saOfferPays
|
||||
// --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver
|
||||
@@ -1105,6 +1113,12 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test )
|
||||
if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20")
|
||||
BOOST_FAIL("STAmount divide fail");
|
||||
|
||||
STAmount a1(currency, 60), a2 (currency, 10, -1);
|
||||
if (STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency))
|
||||
BOOST_FAIL("STAmount setRate(getRate) fail");
|
||||
if (STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency))
|
||||
BOOST_FAIL("STAmount setRate(getRate) fail");
|
||||
|
||||
BOOST_TEST_MESSAGE("Amount CC Complete");
|
||||
}
|
||||
|
||||
@@ -1115,21 +1129,21 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests )
|
||||
|
||||
uint160 c(1);
|
||||
if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getrate fail");
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ DatabaseCon::~DatabaseCon()
|
||||
Application::Application() :
|
||||
mUNL(mIOService),
|
||||
mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300),
|
||||
mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
|
||||
mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
|
||||
mHashNodeDB(NULL), mNetNodeDB(NULL),
|
||||
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL)
|
||||
{
|
||||
RAND_bytes(mNonce256.begin(), mNonce256.size());
|
||||
@@ -50,6 +51,7 @@ extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount
|
||||
|
||||
void Application::stop()
|
||||
{
|
||||
mAuxService.stop();
|
||||
mIOService.stop();
|
||||
mHashedObjectStore.bulkWrite();
|
||||
mValidations.flush();
|
||||
@@ -68,6 +70,11 @@ void Application::run()
|
||||
if (!theConfig.DEBUG_LOGFILE.empty())
|
||||
Log::setLogFile(theConfig.DEBUG_LOGFILE);
|
||||
|
||||
mSNTPClient.init(theConfig.SNTP_SERVERS);
|
||||
|
||||
boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService));
|
||||
auxThread.detach();
|
||||
|
||||
//
|
||||
// Construct databases.
|
||||
//
|
||||
@@ -90,6 +97,7 @@ void Application::run()
|
||||
//
|
||||
getUNL().nodeBootstrap();
|
||||
|
||||
|
||||
//
|
||||
// Allow peer connections.
|
||||
//
|
||||
@@ -146,6 +154,7 @@ void Application::run()
|
||||
mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC());
|
||||
}
|
||||
|
||||
|
||||
mNetOps.setStateTimer();
|
||||
|
||||
mIOService.run(); // This blocks
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "TaggedCache.h"
|
||||
#include "ValidationCollection.h"
|
||||
#include "Suppression.h"
|
||||
#include "SNTPClient.h"
|
||||
#include "../database/database.h"
|
||||
|
||||
|
||||
@@ -38,7 +39,7 @@ public:
|
||||
|
||||
class Application
|
||||
{
|
||||
boost::asio::io_service mIOService;
|
||||
boost::asio::io_service mIOService, mAuxService;
|
||||
|
||||
Wallet mWallet;
|
||||
UniqueNodeList mUNL;
|
||||
@@ -50,6 +51,7 @@ class Application
|
||||
ValidationCollection mValidations;
|
||||
SuppressionTable mSuppressions;
|
||||
HashedObjectStore mHashedObjectStore;
|
||||
SNTPClient mSNTPClient;
|
||||
|
||||
DatabaseCon *mRpcDB, *mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB;
|
||||
|
||||
@@ -86,6 +88,7 @@ public:
|
||||
bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); }
|
||||
bool isNew(const uint160& s) { return mSuppressions.addSuppression(s); }
|
||||
bool running() { return mTxnDB != NULL; }
|
||||
bool getSystemTimeOffset(int& offset) { return mSNTPClient.getOffset(offset); }
|
||||
|
||||
DatabaseCon* getRpcDB() { return mRpcDB; }
|
||||
DatabaseCon* getTxnDB() { return mTxnDB; }
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define SECTION_RPC_ALLOW_REMOTE "rpc_allow_remote"
|
||||
#define SECTION_RPC_IP "rpc_ip"
|
||||
#define SECTION_RPC_PORT "rpc_port"
|
||||
#define SECTION_SNTP "sntp_servers"
|
||||
#define SECTION_UNL_DEFAULT "unl_default"
|
||||
#define SECTION_VALIDATION_QUORUM "validation_quorum"
|
||||
#define SECTION_VALIDATION_SEED "validation_seed"
|
||||
@@ -193,6 +194,12 @@ void Config::load()
|
||||
// sectionEntriesPrint(&IPS, SECTION_IPS);
|
||||
}
|
||||
|
||||
smtTmp = sectionEntries(secConfig, SECTION_SNTP);
|
||||
if (smtTmp)
|
||||
{
|
||||
SNTP_SERVERS = *smtTmp;
|
||||
}
|
||||
|
||||
(void) sectionSingleB(secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE);
|
||||
|
||||
(void) sectionSingleB(secConfig, SECTION_PEER_IP, PEER_IP);
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
std::string VALIDATORS_SITE; // Where to find validators.txt on the Internet.
|
||||
std::vector<std::string> VALIDATORS; // Validators from newcoind.cfg.
|
||||
std::vector<std::string> IPS; // Peer IPs from newcoind.cfg.
|
||||
std::vector<std::string> SNTP_SERVERS; // SNTP servers from newcoind.cfg.
|
||||
|
||||
// Network parameters
|
||||
int NETWORK_START_TIME; // The Unix time we start ledger 0.
|
||||
|
||||
@@ -37,7 +37,6 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
|
||||
t.detach();
|
||||
}
|
||||
}
|
||||
Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: deferred";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ Ledger::Ledger(bool dummy, Ledger& prevLedger) :
|
||||
prevLedger.getCloseAgree(), mLedgerSeq);
|
||||
if (prevLedger.mCloseTime == 0)
|
||||
{
|
||||
mCloseTime = theApp->getOPs().getNetworkTimeNC();
|
||||
mCloseTime = theApp->getOPs().getCloseTimeNC() - mCloseResolution;
|
||||
mCloseTime -= (mCloseTime % mCloseResolution);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "SHAMapSync.h"
|
||||
#include "HashPrefixes.h"
|
||||
|
||||
#define LA_DEBUG
|
||||
// #define LA_DEBUG
|
||||
#define LEDGER_ACQUIRE_TIMEOUT 2
|
||||
#define TRUST_NETWORK
|
||||
|
||||
@@ -88,13 +88,23 @@ void PeerSet::TimerEntry(boost::weak_ptr<PeerSet> wptr, const boost::system::err
|
||||
}
|
||||
|
||||
LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT),
|
||||
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false)
|
||||
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "Acquiring ledger " << mHash.GetHex();
|
||||
#endif
|
||||
}
|
||||
|
||||
void LedgerAcquire::onTimer()
|
||||
{
|
||||
if (getTimeouts() > 6)
|
||||
{
|
||||
setFailed();
|
||||
done();
|
||||
}
|
||||
else trigger(Peer::pointer(), true);
|
||||
}
|
||||
|
||||
boost::weak_ptr<PeerSet> LedgerAcquire::pmDowncast()
|
||||
{
|
||||
return boost::shared_polymorphic_downcast<PeerSet, LedgerAcquire>(shared_from_this());
|
||||
@@ -102,6 +112,9 @@ boost::weak_ptr<PeerSet> LedgerAcquire::pmDowncast()
|
||||
|
||||
void LedgerAcquire::done()
|
||||
{
|
||||
if (mSignaled)
|
||||
return;
|
||||
mSignaled = true;
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "Done acquiring ledger " << mHash.GetHex();
|
||||
#endif
|
||||
@@ -113,9 +126,10 @@ void LedgerAcquire::done()
|
||||
mOnComplete.empty();
|
||||
mLock.unlock();
|
||||
|
||||
theApp->getMasterLedger().storeLedger(mLedger);
|
||||
if (mLedger)
|
||||
theApp->getMasterLedger().storeLedger(mLedger);
|
||||
|
||||
for (int i = 0; i < triggers.size(); ++i)
|
||||
for (unsigned int i = 0; i < triggers.size(); ++i)
|
||||
triggers[i](shared_from_this());
|
||||
}
|
||||
|
||||
@@ -126,33 +140,25 @@ void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)>
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
void LedgerAcquire::trigger(Peer::pointer peer, bool timer)
|
||||
{
|
||||
if (mAborted)
|
||||
if (mAborted || mComplete || mFailed)
|
||||
return;
|
||||
#ifdef LA_DEBUG
|
||||
if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP();
|
||||
else Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex();
|
||||
Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
#endif
|
||||
if (mComplete || mFailed)
|
||||
return;
|
||||
Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
else
|
||||
Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
#endif
|
||||
if (!mHaveBase)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "need base";
|
||||
#endif
|
||||
newcoin::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(newcoin::liBASE);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
if (peer)
|
||||
{
|
||||
sendRequest(tmGL, peer);
|
||||
return;
|
||||
}
|
||||
else sendRequest(tmGL);
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
|
||||
if (mHaveBase && !mHaveTransactions)
|
||||
@@ -168,12 +174,7 @@ void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
tmGL.set_ledgerseq(mLedger->getLedgerSeq());
|
||||
tmGL.set_itype(newcoin::liTX_NODE);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
if (peer)
|
||||
{
|
||||
sendRequest(tmGL, peer);
|
||||
return;
|
||||
}
|
||||
sendRequest(tmGL);
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -187,7 +188,8 @@ void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
else
|
||||
{
|
||||
mHaveTransactions = true;
|
||||
if (mHaveState) mComplete = true;
|
||||
if (mHaveState)
|
||||
mComplete = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -198,12 +200,7 @@ void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
tmGL.set_itype(newcoin::liTX_NODE);
|
||||
for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
|
||||
*(tmGL.add_nodeids()) = it->getRawString();
|
||||
if (peer)
|
||||
{
|
||||
sendRequest(tmGL, peer);
|
||||
return;
|
||||
}
|
||||
sendRequest(tmGL);
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,12 +218,7 @@ void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
tmGL.set_ledgerseq(mLedger->getLedgerSeq());
|
||||
tmGL.set_itype(newcoin::liAS_NODE);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
if (peer)
|
||||
{
|
||||
sendRequest(tmGL, peer);
|
||||
return;
|
||||
}
|
||||
sendRequest(tmGL);
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -240,7 +232,8 @@ void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
else
|
||||
{
|
||||
mHaveState = true;
|
||||
if (mHaveTransactions) mComplete = true;
|
||||
if (mHaveTransactions)
|
||||
mComplete = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -251,25 +244,23 @@ void LedgerAcquire::trigger(Peer::pointer peer)
|
||||
tmGL.set_itype(newcoin::liAS_NODE);
|
||||
for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
|
||||
*(tmGL.add_nodeids()) = it->getRawString();
|
||||
if (peer)
|
||||
{
|
||||
sendRequest(tmGL, peer);
|
||||
return;
|
||||
}
|
||||
sendRequest(tmGL);
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mComplete || mFailed)
|
||||
done();
|
||||
else
|
||||
else if (timer)
|
||||
resetTimer();
|
||||
}
|
||||
|
||||
void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::pointer peer)
|
||||
{
|
||||
peer->sendPacket(boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER));
|
||||
if (!peer)
|
||||
sendRequest(tmGL);
|
||||
else
|
||||
peer->sendPacket(boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER));
|
||||
}
|
||||
|
||||
void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL)
|
||||
@@ -320,8 +311,10 @@ bool LedgerAcquire::takeBase(const std::string& data)
|
||||
theApp->getHashedObjectStore().store(LEDGER, mLedger->getLedgerSeq(), s.peekData(), mHash);
|
||||
|
||||
progress();
|
||||
if (!mLedger->getTransHash()) mHaveTransactions = true;
|
||||
if (!mLedger->getAccountHash()) mHaveState = true;
|
||||
if (!mLedger->getTransHash())
|
||||
mHaveTransactions = true;
|
||||
if (!mLedger->getAccountHash())
|
||||
mHaveState = true;
|
||||
mLedger->setAcquiring();
|
||||
return true;
|
||||
}
|
||||
@@ -337,7 +330,7 @@ bool LedgerAcquire::takeTxNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
{
|
||||
if (nodeIDit->isRoot())
|
||||
{
|
||||
if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, STN_ARF_WIRE))
|
||||
if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, snfWIRE))
|
||||
return false;
|
||||
}
|
||||
else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))
|
||||
@@ -372,7 +365,7 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
{
|
||||
if (nodeIDit->isRoot())
|
||||
{
|
||||
if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, STN_ARF_WIRE))
|
||||
if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, snfWIRE))
|
||||
return false;
|
||||
}
|
||||
else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))
|
||||
@@ -396,13 +389,13 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
bool LedgerAcquire::takeAsRootNode(const std::vector<unsigned char>& data)
|
||||
{
|
||||
if (!mHaveBase) return false;
|
||||
return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, STN_ARF_WIRE);
|
||||
return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE);
|
||||
}
|
||||
|
||||
bool LedgerAcquire::takeTxRootNode(const std::vector<unsigned char>& data)
|
||||
{
|
||||
if (!mHaveBase) return false;
|
||||
return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, STN_ARF_WIRE);
|
||||
return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE);
|
||||
}
|
||||
|
||||
LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
|
||||
@@ -468,23 +461,21 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi
|
||||
return false;
|
||||
if (packet.nodes_size() == 1)
|
||||
{
|
||||
ledger->trigger(peer);
|
||||
ledger->trigger(peer, false);
|
||||
return true;
|
||||
}
|
||||
Log(lsDEBUG) << "liBASE includes ASbase";
|
||||
if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata())))
|
||||
{
|
||||
Log(lsWARNING) << "Included ASbase invalid";
|
||||
}
|
||||
if (packet.nodes().size() == 2)
|
||||
{
|
||||
ledger->trigger(peer);
|
||||
ledger->trigger(peer, false);
|
||||
return true;
|
||||
}
|
||||
Log(lsDEBUG) << "liBASE includes TXbase";
|
||||
if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata())))
|
||||
Log(lsWARNING) << "Invcluded TXbase invalid";
|
||||
ledger->trigger(peer);
|
||||
ledger->trigger(peer, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -508,7 +499,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi
|
||||
else
|
||||
ret = ledger->takeAsNode(nodeIDs, nodeData);
|
||||
if (ret)
|
||||
ledger->trigger(peer);
|
||||
ledger->trigger(peer, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,14 +65,14 @@ public:
|
||||
|
||||
protected:
|
||||
Ledger::pointer mLedger;
|
||||
bool mHaveBase, mHaveState, mHaveTransactions, mAborted;
|
||||
bool mHaveBase, mHaveState, mHaveTransactions, mAborted, mSignaled;
|
||||
|
||||
std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete;
|
||||
|
||||
void done();
|
||||
void onTimer() { trigger(Peer::pointer()); }
|
||||
void onTimer();
|
||||
|
||||
void newPeer(Peer::pointer peer) { trigger(peer); }
|
||||
void newPeer(Peer::pointer peer) { trigger(peer, false); }
|
||||
|
||||
boost::weak_ptr<PeerSet> pmDowncast();
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
bool takeTxRootNode(const std::vector<unsigned char>& data);
|
||||
bool takeAsNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data);
|
||||
bool takeAsRootNode(const std::vector<unsigned char>& data);
|
||||
void trigger(Peer::pointer);
|
||||
void trigger(Peer::pointer, bool timer);
|
||||
};
|
||||
|
||||
class LedgerAcquireMaster
|
||||
|
||||
@@ -36,7 +36,7 @@ boost::weak_ptr<PeerSet> TransactionAcquire::pmDowncast()
|
||||
return boost::shared_polymorphic_downcast<PeerSet, TransactionAcquire>(shared_from_this());
|
||||
}
|
||||
|
||||
void TransactionAcquire::trigger(Peer::pointer peer)
|
||||
void TransactionAcquire::trigger(Peer::pointer peer, bool timer)
|
||||
{
|
||||
if (mComplete || mFailed)
|
||||
return;
|
||||
@@ -76,7 +76,7 @@ void TransactionAcquire::trigger(Peer::pointer peer)
|
||||
}
|
||||
if (mComplete || mFailed)
|
||||
done();
|
||||
else
|
||||
else if (timer)
|
||||
resetTimer();
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ bool TransactionAcquire::takeNodes(const std::list<SHAMapNode>& nodeIDs,
|
||||
Log(lsWARNING) << "Got root TXS node, already have it";
|
||||
return false;
|
||||
}
|
||||
if (!mMap->addRootNode(getHash(), *nodeDatait, STN_ARF_WIRE))
|
||||
if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE))
|
||||
return false;
|
||||
else mHaveRoot = true;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ bool TransactionAcquire::takeNodes(const std::list<SHAMapNode>& nodeIDs,
|
||||
++nodeIDit;
|
||||
++nodeDatait;
|
||||
}
|
||||
trigger(peer);
|
||||
trigger(peer, false);
|
||||
progress();
|
||||
return true;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes)
|
||||
++mYays;
|
||||
res.first->second = true;
|
||||
}
|
||||
else if(!votesYes && res.first->second)
|
||||
else if (!votesYes && res.first->second)
|
||||
{ // changes vote to no
|
||||
Log(lsTRACE) << "Peer " << peer.GetHex() << " now votes NO on " << mTransactionID.GetHex();
|
||||
++mNays;
|
||||
@@ -201,12 +201,14 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre
|
||||
assert(mPreviousMSeconds);
|
||||
|
||||
mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution(
|
||||
previousLedger->getCloseResolution(), previousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1);
|
||||
mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1);
|
||||
|
||||
mHaveCorrectLCL = previousLedger->getHash() == prevLCLHash;
|
||||
|
||||
if (!mHaveCorrectLCL)
|
||||
{
|
||||
Log(lsINFO) << "Entering consensus with: " << previousLedger->getHash().GetHex();
|
||||
Log(lsINFO) << "Correct LCL is: " << prevLCLHash.GetHex();
|
||||
mHaveCorrectLCL = mProposing = mValidating = false;
|
||||
mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash);
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
@@ -216,16 +218,50 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre
|
||||
}
|
||||
else if (mValSeed.isValid())
|
||||
{
|
||||
Log(lsINFO) << "Entering consensus process, validating";
|
||||
mHaveCorrectLCL = mValidating = true;
|
||||
mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsINFO) << "Entering consensus process, proposing";
|
||||
mHaveCorrectLCL = true;
|
||||
mProposing = mValidating = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerConsensus::checkLCL()
|
||||
{
|
||||
uint256 netLgr = mPrevLedgerHash;
|
||||
int netLgrCount = 0;
|
||||
{
|
||||
boost::unordered_map<uint256, int> vals = theApp->getValidations().getCurrentValidations();
|
||||
for (boost::unordered_map<uint256, int>::iterator it = vals.begin(), end = vals.end(); it != end; ++it)
|
||||
if ((it->second > netLgrCount) && !theApp->getValidations().isDeadLedger(it->first))
|
||||
{
|
||||
netLgr = it->first;
|
||||
netLgrCount = it->second;
|
||||
}
|
||||
}
|
||||
if (netLgr != mPrevLedgerHash)
|
||||
{ // LCL change
|
||||
Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ")";
|
||||
mPrevLedgerHash = netLgr;
|
||||
mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash);
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
bool found = false;
|
||||
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||
if ((*it)->hasLedger(mPrevLedgerHash))
|
||||
{
|
||||
found = true;
|
||||
mAcquiringLedger->peerHas(*it);
|
||||
}
|
||||
if (!found)
|
||||
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||
mAcquiringLedger->peerHas(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerConsensus::takeInitialPosition(Ledger& initialLedger)
|
||||
{
|
||||
SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false);
|
||||
@@ -234,7 +270,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger)
|
||||
|
||||
// if any peers have taken a contrary position, process disputes
|
||||
boost::unordered_set<uint256> found;
|
||||
for(boost::unordered_map<uint160, LedgerProposal::pointer>::iterator it = mPeerPositions.begin(),
|
||||
for (boost::unordered_map<uint160, LedgerProposal::pointer>::iterator it = mPeerPositions.begin(),
|
||||
end = mPeerPositions.end(); it != end; ++it)
|
||||
{
|
||||
uint256 set = it->second->getCurrentHash();
|
||||
@@ -260,14 +296,14 @@ void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2)
|
||||
{
|
||||
SHAMap::SHAMapDiff differences;
|
||||
m1->compare(m2, differences, 16384);
|
||||
for(SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos)
|
||||
for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos)
|
||||
{ // create disputed transactions (from the ledger that has them)
|
||||
if (pos->second.first)
|
||||
{
|
||||
assert(!pos->second.second);
|
||||
addDisputedTransaction(pos->first, pos->second.first->peekData());
|
||||
}
|
||||
else if(pos->second.second)
|
||||
else if (pos->second.second)
|
||||
{
|
||||
assert(!pos->second.first);
|
||||
addDisputedTransaction(pos->first, pos->second.second->peekData());
|
||||
@@ -335,7 +371,7 @@ void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vector<uint160
|
||||
it != end; ++it)
|
||||
{
|
||||
bool setHas = map->hasItem(it->second->getTransactionID());
|
||||
for(std::vector<uint160>::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit)
|
||||
for (std::vector<uint160>::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit)
|
||||
it->second->setVote(*pit, setHas);
|
||||
}
|
||||
}
|
||||
@@ -369,7 +405,7 @@ void LedgerConsensus::statePreClose()
|
||||
int proposersClosed = mPeerPositions.size();
|
||||
|
||||
// This ledger is open. This computes how long since the last ledger closed
|
||||
int sinceClose = 1000 * (theApp->getOPs().getNetworkTimeNC() - theApp->getOPs().getLastCloseNetTime());
|
||||
int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - theApp->getOPs().getLastCloseNetTime());
|
||||
|
||||
if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed,
|
||||
mPreviousMSeconds, sinceClose))
|
||||
@@ -377,7 +413,7 @@ void LedgerConsensus::statePreClose()
|
||||
Log(lsINFO) << "CLC: closing ledger";
|
||||
mState = lcsESTABLISH;
|
||||
mConsensusStartTime = boost::posix_time::second_clock::universal_time();
|
||||
mCloseTime = theApp->getOPs().getNetworkTimeNC();
|
||||
mCloseTime = theApp->getOPs().getCloseTimeNC();
|
||||
theApp->getOPs().setLastCloseNetTime(mCloseTime);
|
||||
statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger);
|
||||
takeInitialPosition(*theApp->getMasterLedger().closeLedger());
|
||||
@@ -391,9 +427,10 @@ void LedgerConsensus::stateEstablish()
|
||||
updateOurPositions();
|
||||
if (!mHaveCloseTimeConsensus)
|
||||
{
|
||||
Log(lsINFO) << "No close time consensus";
|
||||
if (haveConsensus())
|
||||
Log(lsINFO) << "We have TX consensus but not CT consensus";
|
||||
}
|
||||
else if (haveConsensus())
|
||||
if (haveConsensus())
|
||||
{
|
||||
Log(lsINFO) << "Converge cutoff";
|
||||
mState = lcsFINISHED;
|
||||
@@ -418,17 +455,21 @@ void LedgerConsensus::timerEntry()
|
||||
{
|
||||
if (!mHaveCorrectLCL)
|
||||
{
|
||||
Log(lsINFO) << "Checking for consensus ledger " << mPrevLedgerHash.GetHex();
|
||||
checkLCL();
|
||||
Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash);
|
||||
if (consensus)
|
||||
{
|
||||
Log(lsINFO) << "We have acquired the consensus ledger";
|
||||
Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex();
|
||||
if (theApp->getMasterLedger().getClosedLedger()->getHash() != mPrevLedgerHash)
|
||||
theApp->getOPs().switchLastClosedLedger(consensus);
|
||||
theApp->getOPs().switchLastClosedLedger(consensus, true);
|
||||
mPreviousLedger = consensus;
|
||||
mHaveCorrectLCL = true;
|
||||
mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution(
|
||||
mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(),
|
||||
mPreviousLedger->getLedgerSeq() + 1);
|
||||
}
|
||||
else Log(lsINFO) << "We still don't have it";
|
||||
else
|
||||
Log(lsINFO) << "Need consensus ledger " << mPrevLedgerHash.GetHex();
|
||||
}
|
||||
|
||||
mCurrentMSeconds = (mCloseTime == 0) ? 0 :
|
||||
@@ -437,9 +478,9 @@ void LedgerConsensus::timerEntry()
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case lcsPRE_CLOSE: statePreClose(); if (mState != lcsESTABLISH) return;
|
||||
case lcsESTABLISH: stateEstablish(); if (mState != lcsFINISHED) return;
|
||||
case lcsFINISHED: stateFinished(); if (mState != lcsACCEPTED) return;
|
||||
case lcsPRE_CLOSE: statePreClose(); if (mState != lcsESTABLISH) return; fallthru();
|
||||
case lcsESTABLISH: stateEstablish(); if (mState != lcsFINISHED) return; fallthru();
|
||||
case lcsFINISHED: stateFinished(); if (mState != lcsACCEPTED) return; fallthru();
|
||||
case lcsACCEPTED: stateAccepted(); return;
|
||||
}
|
||||
assert(false);
|
||||
@@ -447,12 +488,11 @@ void LedgerConsensus::timerEntry()
|
||||
|
||||
void LedgerConsensus::updateOurPositions()
|
||||
{
|
||||
Log(lsINFO) << "Updating our positions";
|
||||
bool changes = false;
|
||||
SHAMap::pointer ourPosition;
|
||||
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)
|
||||
{
|
||||
if (it->second->updatePosition(mClosePercent, mProposing))
|
||||
@@ -479,8 +519,6 @@ void LedgerConsensus::updateOurPositions()
|
||||
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)
|
||||
@@ -489,18 +527,38 @@ void LedgerConsensus::updateOurPositions()
|
||||
neededWeight = AV_MID_CONSENSUS_PCT;
|
||||
else neededWeight = AV_LATE_CONSENSUS_PCT;
|
||||
|
||||
int thresh = mPeerPositions.size() * neededWeight / 100;
|
||||
uint32 closeTime = 0;
|
||||
mHaveCloseTimeConsensus = false;
|
||||
|
||||
int thresh = mPeerPositions.size();
|
||||
if (thresh == 0)
|
||||
{ // no other times
|
||||
mHaveCloseTimeConsensus = true;
|
||||
closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution);
|
||||
}
|
||||
if (mProposing)
|
||||
{
|
||||
++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)];
|
||||
++thresh;
|
||||
}
|
||||
thresh = thresh * neededWeight / 100;
|
||||
|
||||
for (std::map<uint32, int>::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it)
|
||||
{
|
||||
Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh;
|
||||
if (it->second > thresh)
|
||||
{
|
||||
Log(lsINFO) << "Close time consensus reached: " << closeTime;
|
||||
mHaveCloseTimeConsensus = true;
|
||||
closeTime = it->first;
|
||||
}
|
||||
}
|
||||
|
||||
if (closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)))
|
||||
{
|
||||
ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (changes)
|
||||
{
|
||||
@@ -508,7 +566,7 @@ void LedgerConsensus::updateOurPositions()
|
||||
mOurPosition->changePosition(newHash, closeTime);
|
||||
if (mProposing) propose(addedTx, removedTx);
|
||||
mapComplete(newHash, ourPosition, false);
|
||||
Log(lsINFO) << "We change our position to " << newHash.GetHex();
|
||||
Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash.GetHex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,6 +710,7 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
|
||||
}
|
||||
else if (newPosition->getProposeSeq() == 0)
|
||||
{ // new initial close time estimate
|
||||
Log(lsTRACE) << "Peer reports close time as " << newPosition->getCloseTime();
|
||||
++mCloseTimes[newPosition->getCloseTime()];
|
||||
}
|
||||
Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/"
|
||||
@@ -818,13 +877,15 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
applyTransactions(set, newLCL, newLCL, failedTransactions, true);
|
||||
newLCL->setClosed();
|
||||
|
||||
uint32 closeTime = mOurPosition->getCloseTime();
|
||||
uint32 closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() & mCloseResolution);
|
||||
bool closeTimeCorrect = true;
|
||||
if (closeTime == 0)
|
||||
{ // we didn't agree
|
||||
{ // we agreed to disagree
|
||||
closeTimeCorrect = false;
|
||||
closeTime = mPreviousLedger->getCloseTimeNC() + 1;
|
||||
Log(lsINFO) << "Consensus close time (good) " << closeTime;
|
||||
}
|
||||
else Log(lsINFO) << "Consensus close time (bad) " << closeTime;
|
||||
|
||||
newLCL->setAccepted(closeTime, mCloseResolution, closeTimeCorrect);
|
||||
newLCL->updateHash();
|
||||
@@ -833,7 +894,6 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
statusChange(newcoin::neACCEPTED_LEDGER, *newLCL);
|
||||
if (mValidating)
|
||||
{
|
||||
assert (theApp->getOPs().getNetworkTimeNC() > newLCL->getCloseTimeNC());
|
||||
SerializedValidation::pointer v = boost::make_shared<SerializedValidation>
|
||||
(newLCLHash, newLCL->getCloseTimeNC(), mValSeed, mProposing);
|
||||
v->setTrusted();
|
||||
@@ -844,7 +904,6 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
theApp->getConnectionPool().relayMessage(NULL, boost::make_shared<PackedMessage>(val, newcoin::mtVALIDATION));
|
||||
Log(lsINFO) << "Validation sent " << newLCLHash.GetHex();
|
||||
}
|
||||
else Log(lsWARNING) << "Not validating";
|
||||
|
||||
Ledger::pointer newOL = boost::make_shared<Ledger>(true, boost::ref(*newLCL));
|
||||
ScopedLock sl = theApp->getMasterLedger().getLock();
|
||||
@@ -878,21 +937,72 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
mState = lcsACCEPTED;
|
||||
sl.unlock();
|
||||
|
||||
if (mValidating && mOurPosition->getCurrentHash().isNonZero())
|
||||
{ // see how close our close time is to other node's close time reports
|
||||
Log(lsINFO) << "We closed at " << boost::lexical_cast<std::string>(mCloseTime);
|
||||
uint64 closeTotal = mCloseTime;
|
||||
int closeCount = 1;
|
||||
for (std::map<uint32, int>::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it)
|
||||
{
|
||||
Log(lsINFO) << boost::lexical_cast<std::string>(it->second) << " time votes for "
|
||||
<< boost::lexical_cast<std::string>(it->first);
|
||||
closeCount += it->second;
|
||||
closeTotal += static_cast<uint64>(it->first) * static_cast<uint64>(it->second);
|
||||
}
|
||||
closeTotal += (closeCount / 2);
|
||||
closeTotal /= closeCount;
|
||||
int offset = static_cast<int>(closeTotal) - static_cast<int>(mCloseTime);
|
||||
Log(lsINFO) << "Our close offset is estimated at " << offset << " (" << closeCount << ")";
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
Json::StyledStreamWriter ssw;
|
||||
if (1)
|
||||
{
|
||||
Json::StyledStreamWriter ssw;
|
||||
Log(lsTRACE) << "newLCL";
|
||||
Json::Value p;
|
||||
newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
|
||||
ssw.write(Log(lsTRACE).ref(), p);
|
||||
}
|
||||
#endif
|
||||
// FIXME: If necessary, change state to TRACKING/FULL
|
||||
}
|
||||
|
||||
void LedgerConsensus::endConsensus()
|
||||
{
|
||||
theApp->getOPs().endConsensus();
|
||||
theApp->getOPs().endConsensus(mHaveCorrectLCL);
|
||||
}
|
||||
|
||||
Json::Value LedgerConsensus::getJson()
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
ret["proposing"] = mProposing ? "yes" : "no";
|
||||
ret["validating"] = mValidating ? "yes" : "no";
|
||||
ret["proposers"] = static_cast<int>(mPeerPositions.size());
|
||||
|
||||
if (mHaveCorrectLCL)
|
||||
{
|
||||
ret["synched"] = "yes";
|
||||
ret["ledger_seq"] = mPreviousLedger->getLedgerSeq() + 1;
|
||||
ret["close_granularity"] = mCloseResolution;
|
||||
}
|
||||
else
|
||||
ret["synched"] = "no";
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case lcsPRE_CLOSE: ret["state"] = "open"; break;
|
||||
case lcsESTABLISH: ret["state"] = "consensus"; break;
|
||||
case lcsFINISHED: ret["state"] = "finished"; break;
|
||||
case lcsACCEPTED: ret["state"] = "accepted"; break;
|
||||
}
|
||||
|
||||
int v = mDisputes.size();
|
||||
if (v != 0)
|
||||
ret["disputes"] = v;
|
||||
|
||||
if (mOurPosition)
|
||||
ret["our_position"] = mOurPosition->getJson();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/unordered/unordered_map.hpp>
|
||||
|
||||
#include "../json/value.h"
|
||||
|
||||
#include "key.h"
|
||||
#include "Transaction.h"
|
||||
#include "LedgerAcquire.h"
|
||||
@@ -25,11 +27,11 @@ protected:
|
||||
SHAMap::pointer mMap;
|
||||
bool mHaveRoot;
|
||||
|
||||
void onTimer() { trigger(Peer::pointer()); }
|
||||
void newPeer(Peer::pointer peer) { trigger(peer); }
|
||||
void onTimer() { trigger(Peer::pointer(), true); }
|
||||
void newPeer(Peer::pointer peer) { trigger(peer, false); }
|
||||
|
||||
void done();
|
||||
void trigger(Peer::pointer);
|
||||
void trigger(Peer::pointer, bool timer);
|
||||
boost::weak_ptr<PeerSet> pmDowncast();
|
||||
|
||||
public:
|
||||
@@ -142,6 +144,7 @@ public:
|
||||
LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime);
|
||||
|
||||
int startup();
|
||||
Json::Value getJson();
|
||||
|
||||
Ledger::pointer peekPreviousLedger() { return mPreviousLedger; }
|
||||
uint256 getLCL() { return mPrevLedgerHash; }
|
||||
@@ -149,6 +152,7 @@ public:
|
||||
SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire);
|
||||
TransactionAcquire::pointer getAcquiring(const uint256& hash);
|
||||
void mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired);
|
||||
void checkLCL();
|
||||
|
||||
void timerEntry();
|
||||
|
||||
|
||||
@@ -169,9 +169,11 @@ void LedgerEntrySet::entryDelete(SLE::pointer& sle, bool unfunded)
|
||||
if (unfunded)
|
||||
{
|
||||
assert(sle->getType() == ltOFFER); // only offers can be unfunded
|
||||
#if 0
|
||||
mSet.deleteUnfunded(sle->getIndex(),
|
||||
sle->getIValueFieldAmount(sfTakerPays),
|
||||
sle->getIValueFieldAmount(sfTakerGets));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -192,4 +194,64 @@ bool LedgerEntrySet::intersect(const LedgerEntrySet& lesLeft, const LedgerEntryS
|
||||
return true; // XXX Needs implementation
|
||||
}
|
||||
|
||||
Json::Value LedgerEntrySet::getJson(int) const
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
Json::Value nodes(Json::arrayValue);
|
||||
for (boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.begin(),
|
||||
end = mEntries.end(); it != end; ++it)
|
||||
{
|
||||
Json::Value entry(Json::objectValue);
|
||||
entry["node"] = it->first.GetHex();
|
||||
switch (it->second.mEntry->getType())
|
||||
{
|
||||
case ltINVALID: entry["type"] = "invalid"; break;
|
||||
case ltACCOUNT_ROOT: entry["type"] = "acccount_root"; break;
|
||||
case ltDIR_NODE: entry["type"] = "dir_node"; break;
|
||||
case ltGENERATOR_MAP: entry["type"] = "generator_map"; break;
|
||||
case ltRIPPLE_STATE: entry["type"] = "ripple_state"; break;
|
||||
case ltNICKNAME: entry["type"] = "nickname"; break;
|
||||
case ltOFFER: entry["type"] = "offer"; break;
|
||||
default: assert(false);
|
||||
}
|
||||
switch (it->second.mAction)
|
||||
{
|
||||
case taaCACHED: entry["action"] = "cache"; break;
|
||||
case taaMODIFY: entry["action"] = "modify"; break;
|
||||
case taaDELETE: entry["action"] = "delete"; break;
|
||||
case taaCREATE: entry["action"] = "create"; break;
|
||||
default: assert(false);
|
||||
}
|
||||
nodes.append(entry);
|
||||
}
|
||||
ret["nodes" ] = nodes;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LedgerEntrySet::addRawMeta(Serializer& s)
|
||||
{
|
||||
for (boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.begin(),
|
||||
end = mEntries.end(); it != end; ++it)
|
||||
{
|
||||
switch (it->second.mAction)
|
||||
{
|
||||
case taaMODIFY:
|
||||
// WRITEME
|
||||
break;
|
||||
case taaDELETE:
|
||||
// WRITEME
|
||||
break;
|
||||
case taaCREATE:
|
||||
// WRITEME
|
||||
break;
|
||||
default:
|
||||
// ignore these
|
||||
break;
|
||||
}
|
||||
}
|
||||
mSet.addRaw(s);
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -58,6 +58,9 @@ public:
|
||||
void entryDelete(SLE::pointer&, bool unfunded);
|
||||
void entryModify(SLE::pointer&); // This entry will be modified
|
||||
|
||||
Json::Value getJson(int) const;
|
||||
void addRawMeta(Serializer&);
|
||||
|
||||
// iterator functions
|
||||
bool isEmpty() const { return mEntries.empty(); }
|
||||
boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator begin() const { return mEntries.begin(); }
|
||||
|
||||
@@ -72,4 +72,18 @@ std::vector<unsigned char> LedgerProposal::sign(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value LedgerProposal::getJson() const
|
||||
{
|
||||
Json::Value ret = Json::objectValue;
|
||||
ret["previous_ledger"] = mPreviousLedger.GetHex();
|
||||
ret["transaction_hash"] = mCurrentHash.GetHex();
|
||||
ret["close_time"] = mCloseTime;
|
||||
ret["propose_seq"] = mProposeSeq;
|
||||
|
||||
if (mPublicKey.isValid())
|
||||
ret["peer_id"] = mPublicKey.humanNodePublic();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "../json/value.h"
|
||||
|
||||
#include "NewcoinAddress.h"
|
||||
#include "Serializer.h"
|
||||
|
||||
@@ -48,6 +50,7 @@ public:
|
||||
std::vector<unsigned char> sign();
|
||||
|
||||
void changePosition(const uint256& newPosition, uint32 newCloseTime);
|
||||
Json::Value getJson() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,13 +19,15 @@ int ContinuousLedgerTiming::shouldClose(
|
||||
int previousMSeconds, // seconds the previous ledger took to reach consensus
|
||||
int currentMSeconds) // seconds since the previous ledger closed
|
||||
{
|
||||
assert((previousMSeconds > 0) && (previousMSeconds < 600000));
|
||||
assert((currentMSeconds >= 0) && (currentMSeconds < 600000));
|
||||
|
||||
#if 0
|
||||
Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") %
|
||||
(anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds);
|
||||
#endif
|
||||
if ((previousMSeconds < -1000) || (previousMSeconds > 600000) ||
|
||||
(currentMSeconds < -1000) || (currentMSeconds > 600000))
|
||||
{
|
||||
Log(lsFATAL) <<
|
||||
boost::str(boost::format("CLC::shouldClose range error Trans=%s, Prop: %d/%d, Secs: %d (last:%d)")
|
||||
% (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed
|
||||
% currentMSeconds % previousMSeconds);
|
||||
return currentMSeconds;
|
||||
}
|
||||
|
||||
if (!anyTransactions)
|
||||
{ // no transactions so far this interval
|
||||
@@ -44,12 +46,6 @@ int ContinuousLedgerTiming::shouldClose(
|
||||
return LEDGER_IDLE_INTERVAL * 1000; // normal idle
|
||||
}
|
||||
|
||||
if (previousMSeconds == (1000 * LEDGER_IDLE_INTERVAL)) // coming out of idle, close now
|
||||
{
|
||||
Log(lsTRACE) << "leaving idle, close now";
|
||||
return currentMSeconds;
|
||||
}
|
||||
|
||||
Log(lsTRACE) << "close now";
|
||||
return currentMSeconds; // this ledger should close now
|
||||
}
|
||||
@@ -101,7 +97,6 @@ bool ContinuousLedgerTiming::haveConsensus(
|
||||
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;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# define LEDGER_IDLE_INTERVAL 15
|
||||
|
||||
// The number of seconds a validation remains current
|
||||
# define LEDGER_MAX_INTERVAL 60
|
||||
# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 4)
|
||||
|
||||
// The number of milliseconds we wait minimum to ensure participation
|
||||
# define LEDGER_MIN_CONSENSUS 2000
|
||||
|
||||
@@ -24,14 +24,16 @@
|
||||
// there's a functional network.
|
||||
|
||||
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
|
||||
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster),
|
||||
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0),
|
||||
mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL)
|
||||
{
|
||||
}
|
||||
|
||||
boost::posix_time::ptime NetworkOPs::getNetworkTimePT()
|
||||
{
|
||||
return boost::posix_time::second_clock::universal_time();
|
||||
int offset = 0;
|
||||
theApp->getSystemTimeOffset(offset);
|
||||
return boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(offset);
|
||||
}
|
||||
|
||||
uint32 NetworkOPs::getNetworkTimeNC()
|
||||
@@ -39,6 +41,11 @@ uint32 NetworkOPs::getNetworkTimeNC()
|
||||
return iToSeconds(getNetworkTimePT());
|
||||
}
|
||||
|
||||
uint32 NetworkOPs::getCloseTimeNC()
|
||||
{
|
||||
return iToSeconds(getNetworkTimePT() + boost::posix_time::seconds(mCloseTimeOffset));
|
||||
}
|
||||
|
||||
uint32 NetworkOPs::getCurrentLedgerID()
|
||||
{
|
||||
return mLedgerMaster->getCurrentLedger()->getLedgerSeq();
|
||||
@@ -415,6 +422,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
|
||||
Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger();
|
||||
uint256 closedLedger = ourClosed->getHash();
|
||||
uint256 prevClosedLedger = ourClosed->getParentHash();
|
||||
ValidationCount& ourVC = ledgers[closedLedger];
|
||||
|
||||
if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING))
|
||||
@@ -447,19 +455,26 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
|
||||
// 3) Is there a network ledger we'd like to switch to? If so, do we have it?
|
||||
bool switchLedgers = false;
|
||||
for(boost::unordered_map<uint256, ValidationCount>::iterator it = ledgers.begin(), end = ledgers.end();
|
||||
for (boost::unordered_map<uint256, ValidationCount>::iterator it = ledgers.begin(), end = ledgers.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
Log(lsTRACE) << "L: " << it->first.GetHex() <<
|
||||
" t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing;
|
||||
if (it->second > bestVC)
|
||||
if ((it->second > bestVC) && !theApp->getValidations().isDeadLedger(it->first))
|
||||
{
|
||||
bestVC = it->second;
|
||||
closedLedger = it->first;
|
||||
switchLedgers = true;
|
||||
}
|
||||
}
|
||||
networkClosed = closedLedger;
|
||||
|
||||
if (switchLedgers && (closedLedger == prevClosedLedger))
|
||||
{ // don't switch to our own previous ledger
|
||||
networkClosed = ourClosed->getHash();
|
||||
switchLedgers = false;
|
||||
}
|
||||
else
|
||||
networkClosed = closedLedger;
|
||||
|
||||
if (!switchLedgers)
|
||||
{
|
||||
@@ -518,15 +533,18 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
|
||||
// FIXME: If this rewinds the ledger sequence, or has the same sequence, we should update the status on
|
||||
// any stored transactions in the invalidated ledgers.
|
||||
switchLastClosedLedger(consensus);
|
||||
switchLastClosedLedger(consensus, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
|
||||
void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus)
|
||||
{ // set the newledger as our last closed ledger -- this is abnormal code
|
||||
|
||||
Log(lsERROR) << "ABNORMAL Switching last closed ledger to " << newLedger->getHash().GetHex();
|
||||
if (duringConsensus)
|
||||
Log(lsERROR) << "JUMPdc last closed ledger to " << newLedger->getHash().GetHex();
|
||||
else
|
||||
Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash().GetHex();
|
||||
|
||||
newLedger->setClosed();
|
||||
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*newLedger));
|
||||
@@ -586,12 +604,6 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint
|
||||
if (!theApp->isNew(s.getSHA512Half()))
|
||||
return false;
|
||||
|
||||
if ((mMode != omFULL) && (mMode != omTRACKING))
|
||||
{
|
||||
Log(lsINFO) << "Received proposal when not full/tracking: " << mMode;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mConsensus)
|
||||
{ // FIXME: CLC
|
||||
Log(lsWARNING) << "Received proposal when full but not during consensus window";
|
||||
@@ -643,10 +655,11 @@ void NetworkOPs::mapComplete(const uint256& hash, SHAMap::pointer map)
|
||||
mConsensus->mapComplete(hash, map, true);
|
||||
}
|
||||
|
||||
void NetworkOPs::endConsensus()
|
||||
void NetworkOPs::endConsensus(bool correctLCL)
|
||||
{
|
||||
uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash();
|
||||
Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead";
|
||||
theApp->getValidations().addDeadLedger(deadLedger);
|
||||
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 && ((*it)->getClosedLedgerHash() == deadLedger))
|
||||
@@ -735,6 +748,9 @@ Json::Value NetworkOPs::getServerInfo()
|
||||
if (!theConfig.VALIDATION_SEED.isValid()) info["serverState"] = "none";
|
||||
else info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic();
|
||||
|
||||
if (mConsensus)
|
||||
info["consensus"] = mConsensus->getJson();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> > subInfoMapType;
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::value_type subInfoMapValue;
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::iterator subInfoMapIterator;
|
||||
|
||||
OperatingMode mMode;
|
||||
boost::posix_time::ptime mConnectTime;
|
||||
boost::asio::deadline_timer mNetTimer;
|
||||
@@ -54,16 +58,12 @@ protected:
|
||||
LedgerMaster* mLedgerMaster;
|
||||
LedgerAcquire::pointer mAcquiringLedger;
|
||||
|
||||
void setMode(OperatingMode);
|
||||
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> > subInfoMapType;
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::value_type subInfoMapValue;
|
||||
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::iterator subInfoMapIterator;
|
||||
int mCloseTimeOffset;
|
||||
|
||||
// last ledger close
|
||||
int mLastCloseProposers, mLastCloseConvergeTime;
|
||||
uint256 mLastCloseHash;
|
||||
uint32 mLastCloseNetTime;
|
||||
int mLastCloseProposers, mLastCloseConvergeTime;
|
||||
uint256 mLastCloseHash;
|
||||
uint32 mLastCloseNetTime;
|
||||
|
||||
// XXX Split into more locks.
|
||||
boost::interprocess::interprocess_upgradable_mutex mMonitorLock;
|
||||
@@ -75,6 +75,8 @@ protected:
|
||||
boost::unordered_set<InfoSub*> mSubTransaction; // all transactions
|
||||
// subInfoMapType mSubTransactionAccounts;
|
||||
|
||||
void setMode(OperatingMode);
|
||||
|
||||
Json::Value transJson(const SerializedTransaction& stTxn, TransactionEngineResult terResult, const std::string& strStatus, int iSeq, const std::string& strType);
|
||||
void pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState);
|
||||
void pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState);
|
||||
@@ -86,6 +88,7 @@ public:
|
||||
|
||||
// network information
|
||||
uint32 getNetworkTimeNC();
|
||||
uint32 getCloseTimeNC();
|
||||
boost::posix_time::ptime getNetworkTimePT();
|
||||
uint32 getCurrentLedgerID();
|
||||
OperatingMode getOperatingMode() { return mMode; }
|
||||
@@ -181,10 +184,10 @@ public:
|
||||
|
||||
// network state machine
|
||||
void checkState(const boost::system::error_code& result);
|
||||
void switchLastClosedLedger(Ledger::pointer newLedger); // Used for the "jump" case
|
||||
void switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus); // Used for the "jump" case
|
||||
bool checkLastClosedLedger(const std::vector<Peer::pointer>&, uint256& networkClosed);
|
||||
int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger);
|
||||
void endConsensus();
|
||||
void endConsensus(bool correctLCL);
|
||||
void setStateTimer();
|
||||
void newLCL(int proposers, int convergeTime, const uint256& ledgerHash);
|
||||
int getPreviousProposers() { return mLastCloseProposers; }
|
||||
|
||||
25
src/Peer.cpp
25
src/Peer.cpp
@@ -571,15 +571,24 @@ void Peer::recvHello(newcoin::TMHello& packet)
|
||||
// Cancel verification timeout.
|
||||
(void) mVerifyTimer.cancel();
|
||||
|
||||
uint32 minTime = theApp->getOPs().getNetworkTimeNC() - 4;
|
||||
uint32 maxTime = minTime + 8;
|
||||
uint32 ourTime = theApp->getOPs().getNetworkTimeNC();
|
||||
uint32 minTime = ourTime - 10;
|
||||
uint32 maxTime = ourTime + 10;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (packet.has_nettime())
|
||||
{
|
||||
int64 to = ourTime;
|
||||
to -= packet.nettime();
|
||||
Log(lsDEBUG) << "Connect: time offset " << to;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime)))
|
||||
{
|
||||
Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off";
|
||||
}
|
||||
|
||||
if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR))
|
||||
else if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR))
|
||||
{
|
||||
Log(lsINFO) << "Recv(Hello): Server requires protocol version " <<
|
||||
GET_VERSION_MAJOR(packet.protoversion()) << "." << GET_VERSION_MINOR(packet.protoversion())
|
||||
@@ -998,13 +1007,13 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
|
||||
reply.add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
|
||||
|
||||
if (packet.nodeids().size() != 0)
|
||||
{
|
||||
{ // new-style root request
|
||||
Log(lsINFO) << "Ledger root w/map roots request";
|
||||
SHAMap::pointer map = ledger->peekAccountStateMap();
|
||||
if (map)
|
||||
{
|
||||
{ // return account state root node if possible
|
||||
Serializer rootNode(768);
|
||||
if (map->getRootNode(rootNode, STN_ARF_WIRE))
|
||||
if (map->getRootNode(rootNode, snfWIRE))
|
||||
{
|
||||
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
|
||||
if (ledger->getTransHash().isNonZero())
|
||||
@@ -1013,7 +1022,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
|
||||
if (map)
|
||||
{
|
||||
rootNode.resize(0);
|
||||
if (map->getRootNode(rootNode, STN_ARF_WIRE))
|
||||
if (map->getRootNode(rootNode, snfWIRE))
|
||||
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
CKey::pointer PubKeyCache::locate(const NewcoinAddress& id)
|
||||
{
|
||||
if(1)
|
||||
{ // is it in cache
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
std::map<NewcoinAddress, CKey::pointer>::iterator it(mCache.find(id));
|
||||
|
||||
@@ -262,7 +262,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
break;
|
||||
}
|
||||
if (!foundNode) return SHAMapItem::pointer();
|
||||
} while (1);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node)
|
||||
@@ -284,7 +284,7 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node)
|
||||
break;
|
||||
}
|
||||
if (!foundNode) return SHAMapItem::pointer();
|
||||
} while (1);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode* node)
|
||||
@@ -359,22 +359,23 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
|
||||
std::stack<SHAMapTreeNode::pointer> stack = getStack(id, true, false);
|
||||
while(!stack.empty())
|
||||
while (!stack.empty())
|
||||
{
|
||||
SHAMapTreeNode::pointer node = stack.top();
|
||||
stack.pop();
|
||||
|
||||
if(node->isLeaf())
|
||||
if (node->isLeaf())
|
||||
{
|
||||
if(node->peekItem()->getTag()>id)
|
||||
if (node->peekItem()->getTag() > id)
|
||||
return node->peekItem();
|
||||
}
|
||||
else for(int i = node->selectBranch(id) + 1; i < 16; ++i)
|
||||
if(!node->isEmptyBranch(i))
|
||||
else for (int i = node->selectBranch(id) + 1; i < 16; ++i)
|
||||
if (!node->isEmptyBranch(i))
|
||||
{
|
||||
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
|
||||
SHAMapItem::pointer item = firstBelow(node.get());
|
||||
if (!item) throw std::runtime_error("missing node");
|
||||
if (!item)
|
||||
throw std::runtime_error("missing node");
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -392,17 +393,18 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id)
|
||||
SHAMapTreeNode::pointer node = stack.top();
|
||||
stack.pop();
|
||||
|
||||
if(node->isLeaf())
|
||||
if (node->isLeaf())
|
||||
{
|
||||
if(node->peekItem()->getTag()<id)
|
||||
if (node->peekItem()->getTag() < id)
|
||||
return node->peekItem();
|
||||
}
|
||||
else for(int i = node->selectBranch(id) - 1; i >= 0; --i)
|
||||
if(!node->isEmptyBranch(i))
|
||||
else for (int i = node->selectBranch(id) - 1; i >= 0; --i)
|
||||
if (!node->isEmptyBranch(i))
|
||||
{
|
||||
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
|
||||
SHAMapItem::pointer item = firstBelow(node.get());
|
||||
if (!item) throw std::runtime_error("missing node");
|
||||
if (!item)
|
||||
throw std::runtime_error("missing node");
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -414,7 +416,8 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
SHAMapTreeNode* leaf = walkToPointer(id);
|
||||
if (!leaf) return SHAMapItem::pointer();
|
||||
if (!leaf)
|
||||
return SHAMapItem::pointer();
|
||||
return leaf->peekItem();
|
||||
}
|
||||
|
||||
@@ -432,7 +435,7 @@ bool SHAMap::delItem(const uint256& id)
|
||||
assert(mState != Immutable);
|
||||
|
||||
std::stack<SHAMapTreeNode::pointer> stack = getStack(id, true, false);
|
||||
if(stack.empty())
|
||||
if (stack.empty())
|
||||
throw std::runtime_error("missing node");
|
||||
|
||||
SHAMapTreeNode::pointer leaf=stack.top();
|
||||
@@ -442,7 +445,7 @@ bool SHAMap::delItem(const uint256& id)
|
||||
|
||||
SHAMapTreeNode::TNType type=leaf->getType();
|
||||
returnNode(leaf, true);
|
||||
if(mTNByID.erase(*leaf)==0)
|
||||
if (mTNByID.erase(*leaf) == 0)
|
||||
assert(false);
|
||||
|
||||
uint256 prevHash;
|
||||
@@ -460,8 +463,8 @@ bool SHAMap::delItem(const uint256& id)
|
||||
}
|
||||
if (!node->isRoot())
|
||||
{ // we may have made this a node with 1 or 0 children
|
||||
int bc=node->getBranchCount();
|
||||
if(bc==0)
|
||||
int bc = node->getBranchCount();
|
||||
if (bc == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "delItem makes empty node" << std::endl;
|
||||
@@ -470,10 +473,10 @@ bool SHAMap::delItem(const uint256& id)
|
||||
if (!mTNByID.erase(*node))
|
||||
assert(false);
|
||||
}
|
||||
else if(bc==1)
|
||||
else if (bc == 1)
|
||||
{ // pull up on the thread
|
||||
SHAMapItem::pointer item = onlyBelow(node.get());
|
||||
if(item)
|
||||
if (item)
|
||||
{
|
||||
eraseChildren(node);
|
||||
#ifdef ST_DEBUG
|
||||
@@ -521,7 +524,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
|
||||
uint256 prevHash;
|
||||
returnNode(node, true);
|
||||
|
||||
if(node->isInner())
|
||||
if (node->isInner())
|
||||
{ // easy case, we end on an inner node
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "aGI inner " << node->getString() << std::endl;
|
||||
@@ -530,7 +533,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
|
||||
assert(node->isEmptyBranch(branch));
|
||||
SHAMapTreeNode::pointer newNode =
|
||||
boost::make_shared<SHAMapTreeNode>(node->getChildNodeID(branch), item, type, mSeq);
|
||||
if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||
{
|
||||
std::cerr << "Node: " << node->getString() << std::endl;
|
||||
std::cerr << "NewNode: " << newNode->getString() << std::endl;
|
||||
@@ -562,7 +565,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
|
||||
SHAMapTreeNode::pointer newNode =
|
||||
boost::make_shared<SHAMapTreeNode>(mSeq, node->getChildNodeID(b1));
|
||||
newNode->makeInner();
|
||||
if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||
assert(false);
|
||||
stack.push(node);
|
||||
node = newNode;
|
||||
@@ -579,7 +582,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
|
||||
|
||||
newNode = boost::make_shared<SHAMapTreeNode>(node->getChildNodeID(b2), otherItem, type, mSeq);
|
||||
assert(newNode->isValid() && newNode->isLeaf());
|
||||
if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||
assert(false);
|
||||
node->setChildHash(b2, newNode->getNodeHash());
|
||||
}
|
||||
@@ -635,13 +638,13 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
|
||||
throw SHAMapMissingNode(id, hash);
|
||||
|
||||
HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash));
|
||||
if(!obj)
|
||||
if (!obj)
|
||||
throw SHAMapMissingNode(id, hash);
|
||||
assert(Serializer::getSHA512Half(obj->getData()) == hash);
|
||||
|
||||
try
|
||||
{
|
||||
SHAMapTreeNode::pointer ret = boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq, STN_ARF_PREFIXED);
|
||||
SHAMapTreeNode::pointer ret = boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq, snfPREFIX);
|
||||
#ifdef DEBUG
|
||||
assert((ret->getNodeHash() == hash) && (id == *ret));
|
||||
#endif
|
||||
@@ -665,14 +668,14 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq)
|
||||
int flushed = 0;
|
||||
Serializer s;
|
||||
|
||||
if(mDirtyNodes)
|
||||
if (mDirtyNodes)
|
||||
{
|
||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>& dirtyNodes = *mDirtyNodes;
|
||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = dirtyNodes.begin();
|
||||
while (it != dirtyNodes.end())
|
||||
{
|
||||
s.erase();
|
||||
it->second->addRaw(s, STN_ARF_PREFIXED);
|
||||
it->second->addRaw(s, snfPREFIX);
|
||||
theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half());
|
||||
if (flushed++ >= maxNodes)
|
||||
return flushed;
|
||||
@@ -714,10 +717,10 @@ void SHAMap::dump(bool hash)
|
||||
#if 0
|
||||
std::cerr << "SHAMap::dump" << std::endl;
|
||||
SHAMapItem::pointer i=peekFirstItem();
|
||||
while(i)
|
||||
while (i)
|
||||
{
|
||||
std::cerr << "Item: id=" << i->getTag().GetHex() << std::endl;
|
||||
i=peekNextItem(i->getTag());
|
||||
i = peekNextItem(i->getTag());
|
||||
}
|
||||
std::cerr << "SHAMap::dump done" << std::endl;
|
||||
#endif
|
||||
@@ -728,7 +731,8 @@ void SHAMap::dump(bool hash)
|
||||
it != mTNByID.end(); ++it)
|
||||
{
|
||||
std::cerr << it->second->getString() << std::endl;
|
||||
if(hash) std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl;
|
||||
if (hash)
|
||||
std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -756,8 +760,8 @@ BOOST_AUTO_TEST_CASE( SHAMap_test )
|
||||
SHAMap sMap;
|
||||
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
|
||||
|
||||
if(!sMap.addItem(i2, true, false)) BOOST_FAIL("no add");
|
||||
if(!sMap.addItem(i1, true, false)) BOOST_FAIL("no add");
|
||||
if (!sMap.addItem(i2, true, false)) BOOST_FAIL("no add");
|
||||
if (!sMap.addItem(i1, true, false)) BOOST_FAIL("no add");
|
||||
|
||||
SHAMapItem::pointer i;
|
||||
|
||||
|
||||
19
src/SHAMap.h
19
src/SHAMap.h
@@ -122,6 +122,12 @@ public:
|
||||
virtual void dump();
|
||||
};
|
||||
|
||||
enum SHANodeFormat
|
||||
{
|
||||
snfPREFIX = 1, // Form that hashes to its official hash
|
||||
snfWIRE = 2, // Compressed form used on the wire
|
||||
};
|
||||
|
||||
class SHAMapTreeNode : public SHAMapNode
|
||||
{
|
||||
friend class SHAMap;
|
||||
@@ -156,12 +162,9 @@ public:
|
||||
SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq); // copy node from older tree
|
||||
SHAMapTreeNode(const SHAMapNode& nodeID, SHAMapItem::pointer item, TNType type, uint32 seq);
|
||||
|
||||
#define STN_ARF_PREFIXED 1
|
||||
#define STN_ARF_WIRE 2
|
||||
|
||||
// raw node functions
|
||||
SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& contents, uint32 seq, int format);
|
||||
void addRaw(Serializer &, int format);
|
||||
SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& data, uint32 seq, SHANodeFormat format);
|
||||
void addRaw(Serializer &, SHANodeFormat format);
|
||||
|
||||
virtual bool isPopulated() const { return true; }
|
||||
|
||||
@@ -325,9 +328,9 @@ public:
|
||||
SHAMapSyncFilter* filter);
|
||||
bool getNodeFat(const SHAMapNode& node, std::vector<SHAMapNode>& nodeIDs,
|
||||
std::list<std::vector<unsigned char> >& rawNode, bool fatLeaves);
|
||||
bool getRootNode(Serializer& s, int format);
|
||||
bool addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, int format);
|
||||
bool addRootNode(const std::vector<unsigned char>& rootNode, int format);
|
||||
bool getRootNode(Serializer& s, SHANodeFormat format);
|
||||
bool addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, SHANodeFormat format);
|
||||
bool addRootNode(const std::vector<unsigned char>& rootNode, SHANodeFormat format);
|
||||
bool addKnownNode(const SHAMapNode& nodeID, const std::vector<unsigned char>& rawNode,
|
||||
SHAMapSyncFilter* filter);
|
||||
|
||||
|
||||
@@ -27,50 +27,50 @@ uint256 SHAMapNode::smMasks[65];
|
||||
|
||||
bool SHAMapNode::operator<(const SHAMapNode &s) const
|
||||
{
|
||||
if(s.mDepth<mDepth) return true;
|
||||
if(s.mDepth>mDepth) return false;
|
||||
return mNodeID<s.mNodeID;
|
||||
if (s.mDepth < mDepth) return true;
|
||||
if (s.mDepth > mDepth) return false;
|
||||
return mNodeID < s.mNodeID;
|
||||
}
|
||||
|
||||
bool SHAMapNode::operator>(const SHAMapNode &s) const
|
||||
{
|
||||
if(s.mDepth<mDepth) return false;
|
||||
if(s.mDepth>mDepth) return true;
|
||||
return mNodeID>s.mNodeID;
|
||||
if (s.mDepth < mDepth) return false;
|
||||
if (s.mDepth > mDepth) return true;
|
||||
return mNodeID > s.mNodeID;
|
||||
}
|
||||
|
||||
bool SHAMapNode::operator<=(const SHAMapNode &s) const
|
||||
{
|
||||
if(s.mDepth<mDepth) return true;
|
||||
if(s.mDepth>mDepth) return false;
|
||||
return mNodeID<=s.mNodeID;
|
||||
if (s.mDepth < mDepth) return true;
|
||||
if (s.mDepth > mDepth) return false;
|
||||
return mNodeID <= s.mNodeID;
|
||||
}
|
||||
|
||||
bool SHAMapNode::operator>=(const SHAMapNode &s) const
|
||||
{
|
||||
if(s.mDepth<mDepth) return false;
|
||||
if(s.mDepth>mDepth) return true;
|
||||
return mNodeID>=s.mNodeID;
|
||||
if (s.mDepth < mDepth) return false;
|
||||
if (s.mDepth > mDepth) return true;
|
||||
return mNodeID >= s.mNodeID;
|
||||
}
|
||||
|
||||
bool SHAMapNode::operator==(const SHAMapNode &s) const
|
||||
{
|
||||
return (s.mDepth==mDepth) && (s.mNodeID==mNodeID);
|
||||
return (s.mDepth == mDepth) && (s.mNodeID == mNodeID);
|
||||
}
|
||||
|
||||
bool SHAMapNode::operator!=(const SHAMapNode &s) const
|
||||
{
|
||||
return (s.mDepth!=mDepth) || (s.mNodeID!=mNodeID);
|
||||
return (s.mDepth != mDepth) || (s.mNodeID != mNodeID);
|
||||
}
|
||||
|
||||
bool SHAMapNode::operator==(const uint256 &s) const
|
||||
{
|
||||
return s==mNodeID;
|
||||
return s == mNodeID;
|
||||
}
|
||||
|
||||
bool SHAMapNode::operator!=(const uint256 &s) const
|
||||
{
|
||||
return s!=mNodeID;
|
||||
return s != mNodeID;
|
||||
}
|
||||
|
||||
static bool j = SHAMapNode::ClassInit();
|
||||
@@ -78,7 +78,7 @@ static bool j = SHAMapNode::ClassInit();
|
||||
bool SHAMapNode::ClassInit()
|
||||
{ // set up the depth masks
|
||||
uint256 selector;
|
||||
for(int i = 0; i < 64; i += 2)
|
||||
for (int i = 0; i < 64; i += 2)
|
||||
{
|
||||
smMasks[i] = selector;
|
||||
*(selector.begin() + (i / 2)) = 0xF0;
|
||||
@@ -189,10 +189,10 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::pointer item,
|
||||
updateHash();
|
||||
}
|
||||
|
||||
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& rawNode, uint32 seq, int format)
|
||||
: SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false)
|
||||
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& rawNode, uint32 seq,
|
||||
SHANodeFormat format) : SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false)
|
||||
{
|
||||
if (format == STN_ARF_WIRE)
|
||||
if (format == snfWIRE)
|
||||
{
|
||||
Serializer s(rawNode);
|
||||
int type = s.removeLastByte();
|
||||
@@ -256,7 +256,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
}
|
||||
}
|
||||
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
if (format == snfPREFIX)
|
||||
{
|
||||
if (rawNode.size() < 4)
|
||||
{
|
||||
@@ -350,14 +350,14 @@ bool SHAMapTreeNode::updateHash()
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHAMapTreeNode::addRaw(Serializer& s, int format)
|
||||
void SHAMapTreeNode::addRaw(Serializer& s, SHANodeFormat format)
|
||||
{
|
||||
assert((format == STN_ARF_PREFIXED) || (format == STN_ARF_WIRE));
|
||||
assert((format == snfPREFIX) || (format == snfWIRE));
|
||||
if (mType == tnERROR) throw std::runtime_error("invalid I node type");
|
||||
|
||||
if (mType == tnINNER)
|
||||
{
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
if (format == snfPREFIX)
|
||||
{
|
||||
s.add32(sHP_InnerNode);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
@@ -385,7 +385,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
|
||||
}
|
||||
else if (mType == tnACCOUNT_STATE)
|
||||
{
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
if (format == snfPREFIX)
|
||||
{
|
||||
s.add32(sHP_LeafNode);
|
||||
mItem->addRaw(s);
|
||||
@@ -400,7 +400,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
|
||||
}
|
||||
else if (mType == tnTRANSACTION_NM)
|
||||
{
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
if (format == snfPREFIX)
|
||||
{
|
||||
s.add32(sHP_TransactionID);
|
||||
mItem->addRaw(s);
|
||||
@@ -413,7 +413,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
|
||||
}
|
||||
else if (mType == tnTRANSACTION_MD)
|
||||
{
|
||||
if (format == STN_ARF_PREFIXED)
|
||||
if (format == snfPREFIX)
|
||||
{
|
||||
s.add32(sHP_TransactionNode);
|
||||
mItem->addRaw(s);
|
||||
@@ -476,7 +476,7 @@ std::string SHAMapTreeNode::getString() const
|
||||
ret += ")";
|
||||
if (isInner())
|
||||
{
|
||||
for(int i = 0; i < 16; ++i)
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (!isEmptyBranch(i))
|
||||
{
|
||||
ret += "\nb";
|
||||
|
||||
@@ -58,7 +58,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
|
||||
std::vector<unsigned char> nodeData;
|
||||
if (filter->haveNode(childID, childHash, nodeData))
|
||||
{
|
||||
d = boost::make_shared<SHAMapTreeNode>(childID, nodeData, mSeq, STN_ARF_PREFIXED);
|
||||
d = boost::make_shared<SHAMapTreeNode>(childID, nodeData, mSeq, snfPREFIX);
|
||||
if (childHash != d->getNodeHash())
|
||||
{
|
||||
Log(lsERROR) << "Wrong hash from cached object";
|
||||
@@ -99,7 +99,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector<SHAMapNode>& nodeI
|
||||
|
||||
nodeIDs.push_back(*node);
|
||||
Serializer s;
|
||||
node->addRaw(s, STN_ARF_WIRE);
|
||||
node->addRaw(s, snfWIRE);
|
||||
rawNodes.push_back(s.peekData());
|
||||
|
||||
if (node->isRoot() || node->isLeaf()) // don't get a fat root, can't get a fat leaf
|
||||
@@ -114,7 +114,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector<SHAMapNode>& nodeI
|
||||
{
|
||||
nodeIDs.push_back(*nextNode);
|
||||
Serializer s;
|
||||
nextNode->addRaw(s, STN_ARF_WIRE);
|
||||
nextNode->addRaw(s, snfWIRE);
|
||||
rawNodes.push_back(s.peekData());
|
||||
}
|
||||
}
|
||||
@@ -122,14 +122,14 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector<SHAMapNode>& nodeI
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHAMap::getRootNode(Serializer& s, int format)
|
||||
bool SHAMap::getRootNode(Serializer& s, SHANodeFormat format)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
root->addRaw(s, format);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, int format)
|
||||
bool SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, SHANodeFormat format)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
|
||||
@@ -160,7 +160,7 @@ bool SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, int format)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHAMap::addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, int format)
|
||||
bool SHAMap::addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, SHANodeFormat format)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
|
||||
@@ -236,14 +236,14 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
|
||||
uint256 hash = iNode->getChildHash(branch);
|
||||
if (!hash) return false;
|
||||
|
||||
SHAMapTreeNode::pointer newNode = boost::make_shared<SHAMapTreeNode>(node, rawNode, mSeq, STN_ARF_WIRE);
|
||||
SHAMapTreeNode::pointer newNode = boost::make_shared<SHAMapTreeNode>(node, rawNode, mSeq, snfWIRE);
|
||||
if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for
|
||||
return false;
|
||||
|
||||
if (filter)
|
||||
{
|
||||
Serializer s;
|
||||
newNode->addRaw(s, STN_ARF_PREFIXED);
|
||||
newNode->addRaw(s, snfPREFIX);
|
||||
filter->gotNode(node, hash, s.peekData(), newNode->isLeaf());
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ std::list<std::vector<unsigned char> > SHAMap::getTrustedPath(const uint256& ind
|
||||
Serializer s;
|
||||
while (!stack.empty())
|
||||
{
|
||||
stack.top()->addRaw(s, STN_ARF_WIRE);
|
||||
stack.top()->addRaw(s, snfWIRE);
|
||||
path.push_back(s.getData());
|
||||
s.erase();
|
||||
stack.pop();
|
||||
@@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test )
|
||||
Log(lsFATAL) << "Didn't get root node " << gotNodes.size();
|
||||
BOOST_FAIL("NodeSize");
|
||||
}
|
||||
if (!destination.addRootNode(*gotNodes.begin(), STN_ARF_WIRE))
|
||||
if (!destination.addRootNode(*gotNodes.begin(), snfWIRE))
|
||||
{
|
||||
Log(lsFATAL) << "AddRootNode fails";
|
||||
BOOST_FAIL("AddRootNode");
|
||||
|
||||
249
src/SNTPClient.cpp
Normal file
249
src/SNTPClient.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
#include "SNTPClient.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
// #define SNTP_DEBUG
|
||||
|
||||
static uint8_t SNTPQueryData[48] =
|
||||
{ 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
||||
|
||||
// NTP query frequency - 5 minutes
|
||||
#define NTP_QUERY_FREQUENCY (5 * 60)
|
||||
|
||||
// NTP minimum interval to query same servers - 3 minutes
|
||||
#define NTP_MIN_QUERY (3 * 60)
|
||||
|
||||
// NTP sample window (should be odd)
|
||||
#define NTP_SAMPLE_WINDOW 9
|
||||
|
||||
// NTP timestamp constant
|
||||
#define NTP_UNIX_OFFSET 0x83AA7E80
|
||||
|
||||
// SNTP packet offsets
|
||||
#define NTP_OFF_INFO 0
|
||||
#define NTP_OFF_ROOTDELAY 1
|
||||
#define NTP_OFF_ROOTDISP 2
|
||||
#define NTP_OFF_REFERENCEID 3
|
||||
#define NTP_OFF_REFTS_INT 4
|
||||
#define NTP_OFF_REFTS_FRAC 5
|
||||
#define NTP_OFF_ORGTS_INT 6
|
||||
#define NTP_OFF_ORGTS_FRAC 7
|
||||
#define NTP_OFF_RECVTS_INT 8
|
||||
#define NTP_OFF_RECVTS_FRAC 9
|
||||
#define NTP_OFF_XMITTS_INT 10
|
||||
#define NTP_OFF_XMITTS_FRAC 11
|
||||
|
||||
|
||||
SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service),
|
||||
mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256)
|
||||
{
|
||||
mSocket.open(boost::asio::ip::udp::v4());
|
||||
mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint,
|
||||
boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
|
||||
mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY));
|
||||
mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
boost::asio::ip::udp::resolver::iterator sel = it;
|
||||
int i = 1;
|
||||
while (++it != boost::asio::ip::udp::resolver::iterator())
|
||||
if ((rand() % ++i) == 0)
|
||||
sel = it;
|
||||
if (sel != boost::asio::ip::udp::resolver::iterator())
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
SNTPQuery& query = mQueries[*sel];
|
||||
time_t now = time(NULL);
|
||||
if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now))
|
||||
{ // This can happen if the same IP address is reached through multiple names
|
||||
Log(lsTRACE) << "SNTP: Redundant query suppressed";
|
||||
return;
|
||||
}
|
||||
query.mReceivedReply = false;
|
||||
query.mLocalTimeSent = now;
|
||||
RAND_bytes(reinterpret_cast<unsigned char *>(&query.mQueryNonce), sizeof(query.mQueryNonce));
|
||||
reinterpret_cast<uint32*>(SNTPQueryData)[NTP_OFF_XMITTS_INT] = time(NULL) + NTP_UNIX_OFFSET;
|
||||
reinterpret_cast<uint32*>(SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.mQueryNonce;
|
||||
mSocket.async_send_to(boost::asio::buffer(SNTPQueryData, 48), *sel,
|
||||
boost::bind(&SNTPClient::sendComplete, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SNTPClient::receivePacket(const boost::system::error_code& error, std::size_t bytes_xferd)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
#ifdef SNTP_DEBUG
|
||||
Log(lsTRACE) << "SNTP: Packet from " << mReceiveEndpoint;
|
||||
#endif
|
||||
std::map<boost::asio::ip::udp::endpoint, SNTPQuery>::iterator query = mQueries.find(mReceiveEndpoint);
|
||||
if (query == mQueries.end())
|
||||
Log(lsDEBUG) << "SNTP: Reply from " << mReceiveEndpoint << " found without matching query";
|
||||
else if (query->second.mReceivedReply)
|
||||
Log(lsDEBUG) << "SNTP: Duplicate response from " << mReceiveEndpoint;
|
||||
else
|
||||
{
|
||||
query->second.mReceivedReply = true;
|
||||
if (time(NULL) > (query->second.mLocalTimeSent + 1))
|
||||
Log(lsWARNING) << "SNTP: Late response from " << mReceiveEndpoint;
|
||||
else if (bytes_xferd < 48)
|
||||
Log(lsWARNING) << "SNTP: Short reply from " << mReceiveEndpoint
|
||||
<< " (" << bytes_xferd << ") " << mReceiveBuffer.size();
|
||||
else if (reinterpret_cast<uint32*>(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryNonce)
|
||||
Log(lsWARNING) << "SNTP: Reply from " << mReceiveEndpoint << "had wrong nonce";
|
||||
else
|
||||
processReply();
|
||||
}
|
||||
}
|
||||
|
||||
mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint,
|
||||
boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void SNTPClient::sendComplete(const boost::system::error_code& error, std::size_t)
|
||||
{
|
||||
if (error)
|
||||
Log(lsWARNING) << "SNTP: Send error";
|
||||
}
|
||||
|
||||
void SNTPClient::processReply()
|
||||
{
|
||||
assert(mReceiveBuffer.size() >= 48);
|
||||
uint32 *recvBuffer = reinterpret_cast<uint32*>(&mReceiveBuffer.front());
|
||||
|
||||
unsigned info = ntohl(recvBuffer[NTP_OFF_INFO]);
|
||||
int64_t timev = ntohl(recvBuffer[NTP_OFF_RECVTS_INT]);
|
||||
unsigned stratum = (info >> 16) & 0xff;
|
||||
|
||||
if ((info >> 30) == 3)
|
||||
{
|
||||
Log(lsINFO) << "SNTP: Alarm condition " << mReceiveEndpoint;
|
||||
return;
|
||||
}
|
||||
if ((stratum == 0) || (stratum > 14))
|
||||
{
|
||||
Log(lsINFO) << "SNTP: Unreasonable stratum (" << stratum << ") from " << mReceiveEndpoint;
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now = time(NULL);
|
||||
timev -= now;
|
||||
timev -= NTP_UNIX_OFFSET;
|
||||
|
||||
// add offset to list, replacing oldest one if appropriate
|
||||
mOffsetList.push_back(timev);
|
||||
if (mOffsetList.size() >= NTP_SAMPLE_WINDOW)
|
||||
mOffsetList.pop_front();
|
||||
mLastOffsetUpdate = now;
|
||||
|
||||
// select median time
|
||||
std::list<int> offsetList = mOffsetList;
|
||||
offsetList.sort();
|
||||
int j = offsetList.size();
|
||||
std::list<int>::iterator it = offsetList.begin();
|
||||
for (int i = 0; i < (j / 2); ++i)
|
||||
++it;
|
||||
mOffset = *it;
|
||||
if ((j % 2) == 0)
|
||||
mOffset = (mOffset + (*--it)) / 2;
|
||||
|
||||
if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good
|
||||
mOffset = 0;
|
||||
|
||||
#ifndef SNTP_DEBUG
|
||||
if (timev || mOffset)
|
||||
#endif
|
||||
Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset;
|
||||
}
|
||||
|
||||
void SNTPClient::timerEntry(const boost::system::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
doQuery();
|
||||
mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY));
|
||||
mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
void SNTPClient::addServer(const std::string& server)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
mServers.push_back(std::make_pair(server, (time_t) -1));
|
||||
}
|
||||
|
||||
void SNTPClient::init(const std::vector<std::string>& servers)
|
||||
{
|
||||
std::vector<std::string>::const_iterator it = servers.begin();
|
||||
if (it == servers.end())
|
||||
{
|
||||
Log(lsINFO) << "SNTP: no server specified";
|
||||
return;
|
||||
}
|
||||
do
|
||||
addServer(*it++);
|
||||
while (it != servers.end());
|
||||
queryAll();
|
||||
}
|
||||
|
||||
void SNTPClient::queryAll()
|
||||
{
|
||||
while (doQuery())
|
||||
nothing();
|
||||
}
|
||||
|
||||
bool SNTPClient::getOffset(int& offset)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
if ((mLastOffsetUpdate == (time_t) -1) || ((mLastOffsetUpdate + 90) < time(NULL)))
|
||||
return false;
|
||||
offset = mOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SNTPClient::doQuery()
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
std::vector< std::pair<std::string, time_t> >::iterator best = mServers.end();
|
||||
for (std::vector< std::pair<std::string, time_t> >::iterator it = mServers.begin(), end = best;
|
||||
it != end; ++it)
|
||||
if ((best == end) || (it->second == (time_t) -1) || (it->second < best->second))
|
||||
best = it;
|
||||
if (best == mServers.end())
|
||||
{
|
||||
Log(lsINFO) << "SNTP: No server to query";
|
||||
return false;
|
||||
}
|
||||
time_t now = time(NULL);
|
||||
if ((best->second != (time_t) -1) && ((best->second + NTP_MIN_QUERY) >= now))
|
||||
{
|
||||
Log(lsTRACE) << "SNTP: All servers recently queried";
|
||||
return false;
|
||||
}
|
||||
best->second = now;
|
||||
|
||||
boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), best->first, "ntp");
|
||||
mResolver.async_resolve(query,
|
||||
boost::bind(&SNTPClient::resolveComplete, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::iterator));
|
||||
#ifdef SNTP_DEBUG
|
||||
Log(lsTRACE) << "SNTP: Resolve pending for " << best->first;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
58
src/SNTPClient.h
Normal file
58
src/SNTPClient.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef __SNTPCLIENT__
|
||||
#define __SNTPCLIENT__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
class SNTPQuery
|
||||
{
|
||||
public:
|
||||
bool mReceivedReply;
|
||||
time_t mLocalTimeSent;
|
||||
int mQueryNonce;
|
||||
|
||||
SNTPQuery(time_t j = (time_t) -1) : mReceivedReply(false), mLocalTimeSent(j) { ; }
|
||||
};
|
||||
|
||||
class SNTPClient
|
||||
{
|
||||
protected:
|
||||
std::map<boost::asio::ip::udp::endpoint, SNTPQuery> mQueries;
|
||||
boost::mutex mLock;
|
||||
|
||||
boost::asio::ip::udp::socket mSocket;
|
||||
boost::asio::deadline_timer mTimer;
|
||||
boost::asio::ip::udp::resolver mResolver;
|
||||
|
||||
std::vector< std::pair<std::string, time_t> > mServers;
|
||||
|
||||
int mOffset;
|
||||
time_t mLastOffsetUpdate;
|
||||
std::list<int> mOffsetList;
|
||||
|
||||
std::vector<uint8_t> mReceiveBuffer;
|
||||
boost::asio::ip::udp::endpoint mReceiveEndpoint;
|
||||
|
||||
void receivePacket(const boost::system::error_code& error, std::size_t bytes);
|
||||
void resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator iterator);
|
||||
void sentPacket(boost::shared_ptr<std::string>, const boost::system::error_code&, std::size_t);
|
||||
void timerEntry(const boost::system::error_code&);
|
||||
void sendComplete(const boost::system::error_code& error, std::size_t bytesTransferred);
|
||||
void processReply();
|
||||
|
||||
public:
|
||||
SNTPClient(boost::asio::io_service& service);
|
||||
void init(const std::vector<std::string>& servers);
|
||||
void addServer(const std::string& mServer);
|
||||
|
||||
void queryAll();
|
||||
bool doQuery();
|
||||
bool getOffset(int& offset);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
virtual void add(Serializer& s) const { return; }
|
||||
|
||||
virtual bool isEquivalent(const SerializedType& t) const
|
||||
{ std::cerr << getSType() << std::endl; assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; }
|
||||
{ assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; }
|
||||
|
||||
bool operator==(const SerializedType& t) const
|
||||
{ return (getSType() == t.getSType()) && isEquivalent(t); }
|
||||
@@ -290,6 +290,7 @@ public:
|
||||
|
||||
bool isNative() const { return mIsNative; }
|
||||
bool isZero() const { return mValue == 0; }
|
||||
bool isNonZero() const { return mValue != 0; }
|
||||
bool isNegative() const { return mIsNegative && !isZero(); }
|
||||
bool isPositive() const { return !mIsNegative && !isZero(); }
|
||||
bool isGEZero() const { return !mIsNegative; }
|
||||
@@ -342,6 +343,7 @@ public:
|
||||
|
||||
// Someone is offering X for Y, what is the rate?
|
||||
static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn);
|
||||
static STAmount setRate(uint64 rate, const uint160& currencyOut);
|
||||
|
||||
// Someone is offering X for Y, I try to pay Z, how much do I get?
|
||||
// And what's left of the offer? And how much do I actually pay?
|
||||
@@ -706,7 +708,7 @@ public:
|
||||
int getLength() const;
|
||||
SerializedTypeID getSType() const { return STI_TL; }
|
||||
std::string getText() const;
|
||||
void add(Serializer& s) const { if(s.addTaggedList(value)<0) throw(0); }
|
||||
void add(Serializer& s) const { if (s.addTaggedList(value) < 0) throw(0); }
|
||||
|
||||
const std::vector<TaggedListItem>& peekValue() const { return value; }
|
||||
std::vector<TaggedListItem>& peekValue() { return value; }
|
||||
|
||||
@@ -1944,7 +1944,7 @@ bool TransactionEngine::calcNodeOfferRev(
|
||||
// Do a directory.
|
||||
// - Drive on computing saCurDlvAct to derive saPrvDlvAct.
|
||||
SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip);
|
||||
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio
|
||||
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio
|
||||
unsigned int uEntry = 0;
|
||||
uint256 uCurIndex;
|
||||
|
||||
@@ -2027,7 +2027,7 @@ bool TransactionEngine::calcNodeOfferRev(
|
||||
// Do a directory.
|
||||
// - Drive on computing saCurDlvAct to derive saPrvDlvAct.
|
||||
SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip);
|
||||
// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio
|
||||
// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip), uCurCurrencyID); // For correct ratio
|
||||
unsigned int uEntry = 0;
|
||||
uint256 uNxtIndex;
|
||||
|
||||
@@ -2136,7 +2136,7 @@ bool TransactionEngine::calcNodeOfferFwd(
|
||||
// Do a directory.
|
||||
// - Drive on computing saPrvDlvAct to derive saCurDlvAct.
|
||||
SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip);
|
||||
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio
|
||||
STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio
|
||||
unsigned int uEntry = 0;
|
||||
uint256 uCurIndex;
|
||||
|
||||
|
||||
@@ -152,6 +152,17 @@ TransactionMetaNodeEntry* TransactionMetaNode::findEntry(int nodeType)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TMNEBalance* TransactionMetaNode::findBalance()
|
||||
{
|
||||
for (boost::ptr_vector<TransactionMetaNodeEntry>::iterator it = mEntries.begin(), end = mEntries.end();
|
||||
it != end; ++it)
|
||||
if (it->getType() == TransactionMetaNodeEntry::TMNChangedBalance)
|
||||
return dynamic_cast<TMNEBalance *>(&*it);
|
||||
TMNEBalance* node = new TMNEBalance();
|
||||
mEntries.push_back(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
void TransactionMetaNode::addNode(TransactionMetaNodeEntry* node)
|
||||
{
|
||||
mEntries.push_back(node);
|
||||
@@ -194,7 +205,7 @@ TransactionMetaSet::TransactionMetaSet(uint32 ledger, const std::vector<unsigned
|
||||
if (node.isZero())
|
||||
break;
|
||||
mNodes.insert(std::make_pair(node, TransactionMetaNode(node, sit)));
|
||||
} while(1);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void TransactionMetaSet::addRaw(Serializer& s)
|
||||
@@ -256,12 +267,13 @@ TransactionMetaNode& TransactionMetaSet::modifyNode(const uint256& node)
|
||||
return mNodes.insert(std::make_pair(node, TransactionMetaNode(node))).first->second;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void TransactionMetaSet::threadNode(const uint256& node, const uint256& prevTx, uint32 prevLgr)
|
||||
{
|
||||
modifyNode(node).thread(prevTx, prevLgr);
|
||||
}
|
||||
|
||||
bool TransactionMetaSet::deleteUnfunded(const uint256& nodeID,
|
||||
void TransactionMetaSet::deleteUnfunded(const uint256& nodeID,
|
||||
const STAmount& firstBalance, const STAmount &secondBalance)
|
||||
{
|
||||
TransactionMetaNode& node = modifyNode(nodeID);
|
||||
@@ -270,5 +282,5 @@ bool TransactionMetaSet::deleteUnfunded(const uint256& nodeID,
|
||||
entry->setBalances(firstBalance, secondBalance);
|
||||
else
|
||||
node.addNode(new TMNEUnfunded(firstBalance, secondBalance));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -36,11 +36,11 @@ public:
|
||||
bool operator>(const TransactionMetaNodeEntry&) const;
|
||||
bool operator>=(const TransactionMetaNodeEntry&) const;
|
||||
|
||||
std::auto_ptr<TransactionMetaNodeEntry> clone() const
|
||||
{ return std::auto_ptr<TransactionMetaNodeEntry>(clone()); }
|
||||
virtual std::auto_ptr<TransactionMetaNodeEntry> clone() const
|
||||
{ return std::auto_ptr<TransactionMetaNodeEntry>(duplicate()); }
|
||||
|
||||
protected:
|
||||
virtual TransactionMetaNodeEntry* clone(void) = 0;
|
||||
virtual TransactionMetaNodeEntry* duplicate(void) const = 0;
|
||||
};
|
||||
|
||||
class TMNEBalance : public TransactionMetaNodeEntry
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
|
||||
virtual Json::Value getJson(int) const;
|
||||
virtual int compare(const TransactionMetaNodeEntry&) const;
|
||||
virtual TransactionMetaNodeEntry* clone(void) { return new TMNEBalance(*this); }
|
||||
virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEBalance(*this); }
|
||||
};
|
||||
|
||||
class TMNEUnfunded : public TransactionMetaNodeEntry
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
virtual void addRaw(Serializer&) const;
|
||||
virtual Json::Value getJson(int) const;
|
||||
virtual int compare(const TransactionMetaNodeEntry&) const;
|
||||
virtual TransactionMetaNodeEntry* clone(void) { return new TMNEUnfunded(*this); }
|
||||
virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEUnfunded(*this); }
|
||||
};
|
||||
|
||||
inline TransactionMetaNodeEntry* new_clone(const TransactionMetaNodeEntry& s) { return s.clone().release(); }
|
||||
@@ -114,6 +114,7 @@ public:
|
||||
const boost::ptr_vector<TransactionMetaNodeEntry>& peekEntries() const { return mEntries; }
|
||||
|
||||
TransactionMetaNodeEntry* findEntry(int nodeType);
|
||||
TMNEBalance* findBalance();
|
||||
void addNode(TransactionMetaNodeEntry*);
|
||||
|
||||
bool operator<(const TransactionMetaNode& n) const { return mNode < n.mNode; }
|
||||
@@ -126,6 +127,11 @@ public:
|
||||
TransactionMetaNode(const uint256&node, SerializerIterator&);
|
||||
void addRaw(Serializer&);
|
||||
Json::Value getJson(int) const;
|
||||
|
||||
void threadNode(const uint256& previousTransaction, uint32 previousLedger);
|
||||
void deleteUnfunded(const STAmount& firstBalance, const STAmount& secondBalance);
|
||||
void adjustBalance(unsigned flags, const STAmount &amount, bool signedBy);
|
||||
void adjustBalances(unsigned flags, const STAmount &firstAmt, const STAmount &secondAmt);
|
||||
};
|
||||
|
||||
|
||||
@@ -148,16 +154,11 @@ public:
|
||||
void swap(TransactionMetaSet&);
|
||||
|
||||
bool isNodeAffected(const uint256&) const;
|
||||
TransactionMetaNode& getAffectedNode(const uint256&);
|
||||
const TransactionMetaNode& peekAffectedNode(const uint256&) const;
|
||||
|
||||
Json::Value getJson(int) const;
|
||||
void addRaw(Serializer&);
|
||||
|
||||
void threadNode(const uint256& node, const uint256& previousTransaction, uint32 previousLedger);
|
||||
bool signedBy(const uint256& node, const STAmount& fee);
|
||||
bool deleteUnfunded(const uint256& node, const STAmount& firstBalance, const STAmount& secondBalance);
|
||||
bool adjustBalance(const uint256& node, unsigned flags, const STAmount &amount);
|
||||
bool adjustBalances(const uint256& node, unsigned flags, const STAmount &firstAmt, const STAmount &secondAmt);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,20 +7,22 @@
|
||||
|
||||
bool ValidationCollection::addValidation(SerializedValidation::pointer val)
|
||||
{
|
||||
NewcoinAddress signer = val->getSignerPublic();
|
||||
bool isCurrent = false;
|
||||
if (theApp->getUNL().nodeInUNL(val->getSignerPublic()))
|
||||
if (theApp->getUNL().nodeInUNL(signer))
|
||||
{
|
||||
val->setTrusted();
|
||||
uint32 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint32 now = theApp->getOPs().getCloseTimeNC();
|
||||
uint32 valClose = val->getCloseTime();
|
||||
if ((now > valClose) && (now < (valClose + LEDGER_MAX_INTERVAL)))
|
||||
if ((now > (valClose - 4)) && (now < (valClose + LEDGER_MAX_INTERVAL)))
|
||||
isCurrent = true;
|
||||
else
|
||||
Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose;
|
||||
}
|
||||
else Log(lsINFO) << "Node " << signer.humanNodePublic() << " not in UNL";
|
||||
|
||||
uint256 hash = val->getLedgerHash();
|
||||
uint160 node = val->getSignerPublic().getNodeID();
|
||||
uint160 node = signer.getNodeID();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
@@ -28,18 +30,27 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val)
|
||||
return false;
|
||||
if (isCurrent)
|
||||
{
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.find(node);
|
||||
if ((it == mCurrentValidations.end()) || (val->getCloseTime() >= it->second->getCloseTime()))
|
||||
boost::unordered_map<uint160, ValidationPair>::iterator it = mCurrentValidations.find(node);
|
||||
if ((it == mCurrentValidations.end()) || (!it->second.newest) ||
|
||||
(val->getCloseTime() > it->second.newest->getCloseTime()))
|
||||
{
|
||||
if (it != mCurrentValidations.end())
|
||||
mStaleValidations.push_back(it->second);
|
||||
mCurrentValidations[node] = val;
|
||||
condWrite();
|
||||
{
|
||||
if (it->second.oldest)
|
||||
{
|
||||
mStaleValidations.push_back(it->second.oldest);
|
||||
condWrite();
|
||||
}
|
||||
it->second.oldest = it->second.newest;
|
||||
it->second.newest = val;
|
||||
}
|
||||
else
|
||||
mCurrentValidations.insert(std::make_pair(node, ValidationPair(val)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log(lsINFO) << "Val for " << hash.GetHex() << " from " << val->getSignerPublic().humanNodePublic()
|
||||
Log(lsINFO) << "Val for " << hash.GetHex() << " from " << signer.humanNodePublic()
|
||||
<< " added " << (val->isTrusted() ? "trusted" : "UNtrusted");
|
||||
return isCurrent;
|
||||
}
|
||||
@@ -50,7 +61,8 @@ ValidationSet ValidationCollection::getValidations(const uint256& ledger)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger);
|
||||
if (it != mValidations.end()) ret = it->second;
|
||||
if (it != mValidations.end())
|
||||
ret = it->second;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -60,7 +72,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren
|
||||
trusted = untrusted = 0;
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger);
|
||||
uint32 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint32 now = theApp->getOPs().getCloseTimeNC();
|
||||
if (it != mValidations.end())
|
||||
{
|
||||
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
|
||||
@@ -70,7 +82,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren
|
||||
{
|
||||
uint32 closeTime = vit->second->getCloseTime();
|
||||
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_MAX_INTERVAL)))
|
||||
trusted = false;
|
||||
isTrusted = false;
|
||||
}
|
||||
if (isTrusted)
|
||||
++trusted;
|
||||
@@ -100,10 +112,10 @@ 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(),
|
||||
for (boost::unordered_map<uint160, ValidationPair>::iterator it = mCurrentValidations.begin(),
|
||||
end = mCurrentValidations.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second->isTrusted() && (it->second->getCloseTime() > afterTime))
|
||||
if (it->second.newest->isTrusted() && (it->second.newest->getCloseTime() > afterTime))
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
@@ -111,24 +123,45 @@ int ValidationCollection::getCurrentValidationCount(uint32 afterTime)
|
||||
|
||||
boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
|
||||
{
|
||||
uint32 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint32 now = theApp->getOPs().getCloseTimeNC();
|
||||
boost::unordered_map<uint256, int> ret;
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
|
||||
boost::unordered_map<uint160, ValidationPair>::iterator it = mCurrentValidations.begin();
|
||||
bool anyNew = false;
|
||||
while (it != mCurrentValidations.end())
|
||||
{
|
||||
if (now > (it->second->getCloseTime() + LEDGER_MAX_INTERVAL))
|
||||
ValidationPair& pair = it->second;
|
||||
|
||||
if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_MAX_INTERVAL)))
|
||||
{
|
||||
mStaleValidations.push_back(it->second);
|
||||
it = mCurrentValidations.erase(it);
|
||||
mStaleValidations.push_back(pair.oldest);
|
||||
pair.oldest = SerializedValidation::pointer();
|
||||
anyNew = true;
|
||||
}
|
||||
if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_MAX_INTERVAL)))
|
||||
{
|
||||
mStaleValidations.push_back(pair.newest);
|
||||
pair.newest = SerializedValidation::pointer();
|
||||
anyNew = true;
|
||||
}
|
||||
if (!pair.newest && !pair.oldest)
|
||||
it = mCurrentValidations.erase(it);
|
||||
else
|
||||
{
|
||||
++ret[it->second->getLedgerHash()];
|
||||
if (pair.oldest)
|
||||
{
|
||||
Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " <<
|
||||
boost::lexical_cast<std::string>(pair.oldest->getCloseTime());
|
||||
++ret[pair.oldest->getLedgerHash()];
|
||||
}
|
||||
if (pair.newest)
|
||||
{
|
||||
Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " <<
|
||||
boost::lexical_cast<std::string>(pair.newest->getCloseTime());
|
||||
++ret[pair.newest->getLedgerHash()];
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -139,14 +172,35 @@ boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ValidationCollection::isDeadLedger(const uint256& ledger)
|
||||
{
|
||||
for (std::list<uint256>::iterator it = mDeadLedgers.begin(), end = mDeadLedgers.end(); it != end; ++it)
|
||||
if (*it == ledger)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ValidationCollection::addDeadLedger(const uint256& ledger)
|
||||
{
|
||||
if (isDeadLedger(ledger))
|
||||
return;
|
||||
|
||||
mDeadLedgers.push_back(ledger);
|
||||
if (mDeadLedgers.size() >= 128)
|
||||
mDeadLedgers.pop_front();
|
||||
}
|
||||
|
||||
void ValidationCollection::flush()
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
|
||||
boost::unordered_map<uint160, ValidationPair>::iterator it = mCurrentValidations.begin();
|
||||
bool anyNew = false;
|
||||
while (it != mCurrentValidations.end())
|
||||
{
|
||||
mStaleValidations.push_back(it->second);
|
||||
if (it->second.oldest)
|
||||
mStaleValidations.push_back(it->second.oldest);
|
||||
if (it->second.newest)
|
||||
mStaleValidations.push_back(it->second.newest);
|
||||
++it;
|
||||
anyNew = true;
|
||||
}
|
||||
|
||||
@@ -12,14 +12,24 @@
|
||||
|
||||
typedef boost::unordered_map<uint160, SerializedValidation::pointer> ValidationSet;
|
||||
|
||||
class ValidationPair
|
||||
{
|
||||
public:
|
||||
SerializedValidation::pointer oldest, newest;
|
||||
|
||||
ValidationPair(SerializedValidation::pointer v) : newest(v) { ; }
|
||||
};
|
||||
|
||||
class ValidationCollection
|
||||
{
|
||||
protected:
|
||||
|
||||
boost::mutex mValidationLock;
|
||||
boost::unordered_map<uint256, ValidationSet> mValidations;
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer> mCurrentValidations;
|
||||
std::vector<SerializedValidation::pointer> mStaleValidations;
|
||||
boost::unordered_map<uint256, ValidationSet> mValidations;
|
||||
boost::unordered_map<uint160, ValidationPair> mCurrentValidations;
|
||||
std::vector<SerializedValidation::pointer> mStaleValidations;
|
||||
std::list<uint256> mDeadLedgers;
|
||||
|
||||
bool mWriting;
|
||||
|
||||
void doWrite();
|
||||
@@ -31,9 +41,16 @@ public:
|
||||
bool addValidation(SerializedValidation::pointer);
|
||||
ValidationSet getValidations(const uint256& ledger);
|
||||
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted);
|
||||
|
||||
int getTrustedValidationCount(const uint256& ledger);
|
||||
int getCurrentValidationCount(uint32 afterTime);
|
||||
|
||||
boost::unordered_map<uint256, int> getCurrentValidations();
|
||||
|
||||
void addDeadLedger(const uint256&);
|
||||
bool isDeadLedger(const uint256&);
|
||||
std::list<uint256> getDeadLedgers() { return mDeadLedgers; }
|
||||
|
||||
void flush();
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//
|
||||
|
||||
#define SERVER_VERSION_MAJOR 0
|
||||
#define SERVER_VERSION_MINOR 3
|
||||
#define SERVER_VERSION_MINOR 4
|
||||
#define SERVER_VERSION_SUB "-a"
|
||||
#define SERVER_NAME "NewCoin"
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
// Version we prefer to speak:
|
||||
#define PROTO_VERSION_MAJOR 0
|
||||
#define PROTO_VERSION_MINOR 3
|
||||
#define PROTO_VERSION_MINOR 4
|
||||
|
||||
// Version we wil speak to:
|
||||
#define MIN_PROTO_MAJOR 0
|
||||
#define MIN_PROTO_MINOR 3
|
||||
#define MIN_PROTO_MINOR 4
|
||||
|
||||
#define MAKE_VERSION_INT(maj,min) ((maj << 16) | min)
|
||||
#define GET_VERSION_MAJOR(ver) (ver >> 16)
|
||||
|
||||
Reference in New Issue
Block a user