Merge branch 'master' into ripple

Conflicts:
	src/LedgerEntrySet.cpp
This commit is contained in:
Arthur Britto
2012-08-10 13:14:58 -07:00
37 changed files with 946 additions and 298 deletions

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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; }

View File

@@ -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);

View File

@@ -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.

View File

@@ -37,7 +37,6 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
t.detach();
}
}
Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: deferred";
return true;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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(); }

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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; }

View File

@@ -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());
}
}

View File

@@ -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));

View File

@@ -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;

View File

@@ -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);

View File

@@ -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";

View File

@@ -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
View 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
View 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

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();
};

View File

@@ -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)