Merge branch 'master' of github.com:jedmccaleb/NewCoin

Conflicts:
	src/Peer.cpp
This commit is contained in:
Arthur Britto
2012-06-20 13:41:14 -07:00
19 changed files with 388 additions and 87 deletions

37
deploy/cointoss.nsi Normal file
View File

@@ -0,0 +1,37 @@
Name "CoinToss"
; The file to write
OutFile "toss install.exe"
; The default installation directory
InstallDir "$PROGRAMFILES\CoinToss"
; Request application privileges for Windows Vista
RequestExecutionLevel user
;--------------------------------
; Pages
Page directory
Page instfiles
;--------------------------------
; The stuff to install
Section "" ;No components page, name is not important
; Set output path to the installation directory.
SetOutPath $INSTDIR
; Put file there
File ..\Release\newcoin.exe
File ..\*.dll
File "start CoinToss.bat"
File newcoind.cfg
File validators.txt
File /r /x .git ..\..\nc-client\*.*
SectionEnd ; end the section

147
deploy/newcoind.cfg Normal file
View File

@@ -0,0 +1,147 @@
#
# Sample newcoind.cfg
#
# This file should be named newcoind.cfg. This file is UTF-8 with Dos, UNIX,
# or Mac style end of lines. Blank lines and lines beginning with '#' are
# ignored. Undefined sections are reserved. No escapes are currently defined.
#
# When you launch newcoind, it will attempt to find this file.
#
# --conf=<path>:
# You may specify the location of this file with --conf=<path>. The config
# directory is the directory containing this file. The data directory is a
# the subdirectory named "dbs".
#
# Windows and no --conf:
# The config directory is the same directory as the newcoind program. The
# data directory is a the subdirectory named "dbs".
#
# Other OSes and no --conf:
# This file will be looked for in these places in the following order:
# ./newcoind.cfg
# $XDG_CONFIG_HOME/newcoin/newcoind.cfg
#
# If newcoind.cfg, is found in the current working directory, the directory
# will be used as the config directory. The data directory is a the
# subdirectory named "dbs".
#
# Otherwise, the data directory data is:
# $XDG_DATA_HOME/newcoin/
#
# Note: $XDG_CONFIG_HOME defaults to $HOME/.config
# $XDG_DATA_HOME defaults to $HOME/.local/share
#
# [debug_logfile]
# Specifies were a debug logfile is kept. By default, no debug log is kept
#
# Example: debug.log
#
# [validators_site]:
# Specifies where to find validators.txt for UNL boostrapping and RPC command unl_network.
# During alpha testing, this defaults to: redstem.com
#
# Example: newcoin.org
#
# [unl_default]:
# XXX This should be called: [validators_file]
# Specifies how to bootstrap the UNL list. The UNL list is based on a
# validators.txt file and is maintained in the databases. When newcoind
# starts up, if the databases are missing or are obsolete due to an upgrade
# of newcoind, newcoind will reconstruct the UNL list as specified here.
#
# If this entry is not present or empty, newcoind will look for a validators.txt in the
# config directory. If not found there, it will attempt to retrieve the file
# from the newcoin foundation's web site.
#
# This entry is also used by the RPC command unl_load.
#
# Specify the file by specifying its full path.
#
# Examples:
# C:/home/johndoe/newcoin/validators.txt
# /home/johndoe/newcoin/validators.txt
#
# [validators]:
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [validators_url].
# List of nodes to accept as validators speficied by public key or domain.
#
# For domains, newcoind will probe for https web servers at the specied
# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN
#
# Examples:
# redstem.com
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
#
# [ips]:
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [ips_url].
# List of ips where the Newcoin protocol is avialable.
# One ipv4 or ipv6 address per line.
# A port may optionally be specified after adding a space to the address.
# By convention, if known, IPs are listed in from most to least trusted.
#
# Examples:
# 192.168.0.1
# 192.168.0.1 3939
# 2001:0db8:0100:f101:0210:a4ff:fee3:9566
#
# [peer_ip]:
# IP address or domain to bind to allow external connections from peers.
# Defaults to not allow external connections from peers.
#
# Examples: 0.0.0.0 - Bind on all interfaces.
#
# [peer_port]:
# Port to bind to allow external connections from peers.
#
# [rpc_ip]:
# IP address or domain to bind to allow insecure RPC connections.
# Defaults to not allow RPC connections.
#
# [rpc_port]:
# Port to bind to if allowing insecure RPC connections.
#
# [rpc_allow_remote]:
# 0 or 1. 0 only allows RPC connections from 127.0.0.1. [default 0]
#
# [websocket_ip]:
# IP address or domain to bind to allow client connections.
#
# Examples: 0.0.0.0 - Bind on all interfaces.
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
#
# [websocket_port]:
# Port to bind to allow client connections.
#
# [validation_seed]:
# To perform validation, this section should contain either a validation seed or key.
# The validation seed is used to generate the validation public/private key pair.
# To obtain a validation seed, use the validation_create command.
#
# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
# shfArahZT9Q9ckTf3s1psJ7C7qzVN
#
[peer_ip]
0.0.0.0
[peer_port]
51235
[rpc_ip]
127.0.0.1
[rpc_port]
5005
[rpc_allow_remote]
1
[debug_logfile]
debug.log
[validation_seed]
shh1D4oj5czH3PUEjYES8c7Bay3tE
[unl_default]
validators.txt

View File

@@ -0,0 +1,3 @@
start newcoin
sleep 4
start index.html

25
deploy/validators.txt Normal file
View File

@@ -0,0 +1,25 @@
#
# Default validators.txt
#
# A list of domains to bootstrap a nodes UNLs or for clients to indirectly
# locate IPs to contact the Newcoin network.
#
# This file is UTF-8 with Dos, UNIX, or Mac style end of lines.
# Blank lines and lines starting with a '#' are ignored.
# All other lines should be hankos or domain names.
#
# [validators]:
# List of nodes to accept as validators speficied by public key or domain.
#
# For domains, newcoind will probe for https web servers at the specied
# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN
#
# Examples: redstem.com
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
#
[validators]
n9LQC4xFSWXNv1SU1sKtjrW6TZpBZSwp1nRWej8saGs155x42YFZ first
n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V second
n9KXAZxiHkWuVGxDEE8boW7WmcycpZNmWei4vxVaywLZ391Nbuqx third

View File

@@ -72,7 +72,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>BOOST_TEST_ALTERNATIVE_INIT_API;BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\OpenSSL\include;..\boost_1_47_0;..\protobuf-2.4.1\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>

View File

@@ -100,7 +100,7 @@ bool STAmount::setValue(const std::string& sAmount, const std::string& sCurrency
if (bInteger)
{
uValue = sAmount.empty() ? 0 : boost::lexical_cast<unsigned int>(sAmount);
uValue = sAmount.empty() ? 0 : boost::lexical_cast<uint64>(sAmount);
iOffset = 0;
}
else

View File

@@ -1,6 +1,9 @@
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include "../database/SqliteDatabase.h"
#include "Application.h"
@@ -52,6 +55,11 @@ void Application::stop()
std::cerr << "Stopped: " << mIOService.stopped() << std::endl;
}
static void InitDB(DatabaseCon** dbCon, const char *fileName, const char *dbInit[], int dbCount)
{
*dbCon = new DatabaseCon(fileName, dbInit, dbCount);
}
void Application::run()
{
assert(mTxnDB == NULL);
@@ -61,11 +69,12 @@ void Application::run()
//
// Construct databases.
//
mTxnDB = new DatabaseCon("transaction.db", TxnDBInit, TxnDBCount);
mLedgerDB = new DatabaseCon("ledger.db", LedgerDBInit, LedgerDBCount);
mWalletDB = new DatabaseCon("wallet.db", WalletDBInit, WalletDBCount);
mHashNodeDB = new DatabaseCon("hashnode.db", HashNodeDBInit, HashNodeDBCount);
mNetNodeDB = new DatabaseCon("netnode.db", NetNodeDBInit, NetNodeDBCount);
boost::thread t1(boost::bind(&InitDB, &mTxnDB, "transaction.db", TxnDBInit, TxnDBCount));
boost::thread t2(boost::bind(&InitDB, &mLedgerDB, "ledger.db", LedgerDBInit, LedgerDBCount));
boost::thread t3(boost::bind(&InitDB, &mWalletDB, "wallet.db", WalletDBInit, WalletDBCount));
boost::thread t4(boost::bind(&InitDB, &mHashNodeDB, "hashnode.db", HashNodeDBInit, HashNodeDBCount));
boost::thread t5(boost::bind(&InitDB, &mNetNodeDB, "netnode.db", NetNodeDBInit, NetNodeDBCount));
t1.join(); t2.join(); t3.join(); t4.join(); t5.join();
//
// Begin validation and ip maintenance.

View File

@@ -2,6 +2,8 @@
// Transaction database holds transactions and public keys
const char *TxnDBInit[] = {
"BEGIN TRANSACTION;",
"CREATE TABLE Transactions ( \
TransID CHARACTER(64) PRIMARY KEY, \
TransType CHARACTER(24), \
@@ -21,13 +23,17 @@ const char *TxnDBInit[] = {
LedgerSeq BIGINT UNSIGNED \
);",
"CREATE INDEX AcctTxindex ON \
AccountTransactions(Account, LedgerSeq, TransID);"
AccountTransactions(Account, LedgerSeq, TransID);",
"END TRANSACTION;"
};
int TxnDBCount = sizeof(TxnDBInit) / sizeof(const char *);
// Ledger database holds ledgers and ledger confirmations
const char *LedgerDBInit[] = {
"BEGIN TRANSACTION;",
"CREATE TABLE Ledgers ( \
LedgerHash CHARACTER(64) PRIMARY KEY, \
LedgerSeq BIGINT UNSIGNED, \
@@ -46,8 +52,9 @@ const char *LedgerDBInit[] = {
Signature BLOB \
);",
"CREATE INDEX LedgerConfByHash ON \
LedgerConfirmations(LedgerHash)"
LedgerConfirmations(LedgerHash)",
#endif
"END TRANSACTION;"
};
int LedgerDBCount = sizeof(LedgerDBInit) / sizeof(const char *);
@@ -55,6 +62,8 @@ int LedgerDBCount = sizeof(LedgerDBInit) / sizeof(const char *);
// Wallet database holds local accounts and trusted nodes
const char *WalletDBInit[] = {
// Node identity must be persisted for CAS routing and responsibilities.
"BEGIN TRANSACTION;",
"CREATE TABLE NodeIdentity ( \
PublicKey CHARACTER(53), \
PrivateKey CHARACTER(52), \
@@ -221,13 +230,17 @@ const char *WalletDBInit[] = {
);",
"CREATE INDEX PeerScanIndex ON \
PeerIps(ScanNext);"
PeerIps(ScanNext);",
"END TRANSACTION;"
};
int WalletDBCount = sizeof(WalletDBInit) / sizeof(const char *);
// Hash node database holds nodes indexed by hash
const char *HashNodeDBInit[] = {
"BEGIN TRANSACTION;",
"CREATE TABLE CommittedObjects ( \
Hash CHARACTER(64) PRIMARY KEY, \
ObjType CHAR(1) NOT NULL, \
@@ -236,7 +249,9 @@ const char *HashNodeDBInit[] = {
);",
"CREATE INDEX ObjectLocate ON \
CommittedObjects(LedgerIndex, ObjType);"
CommittedObjects(LedgerIndex, ObjType);",
"END TRANSACTION;"
};
int HashNodeDBCount = sizeof(HashNodeDBInit) / sizeof(const char *);

View File

@@ -16,6 +16,8 @@
// #define LC_DEBUG
// TODO: If we don't have the previousLCL, check if we got it. If so, change modes
TransactionAcquire::TransactionAcquire(const uint256& hash)
: PeerSet(hash, 1), mFilter(&theApp->getNodeCache()), mHaveRoot(false)
{
@@ -188,12 +190,15 @@ int LCTransaction::getAgreeLevel()
return (mNays * 100 + 100) / (mYays + mNays + 1);
}
LedgerConsensus::LedgerConsensus(Ledger::pointer previousLedger, uint32 closeTime)
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPreviousLedger(previousLedger)
LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime)
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger)
{
mValSeed = theConfig.VALIDATION_SEED;
Log(lsDEBUG) << "Creating consensus object";
Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime;
if (theConfig.VALIDATION_SEED.isValid())
if (previousLedger->getHash() != prevLCLHash)
mHaveCorrectLCL = mProposing = mValidating = false;
else if (mValSeed.isValid())
{
mValidating = true;
mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL;
@@ -205,7 +210,7 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
{
SHAMap::pointer initialSet = initialLedger->peekTransactionMap()->snapShot(false);
uint256 txSet = initialSet->getHash();
assert (initialLedger->getParentHash() == mPreviousLedger->getHash());
assert (!mHaveCorrectLCL || (initialLedger->getParentHash() == mPreviousLedger->getHash()));
// if any peers have taken a contrary position, process disputes
boost::unordered_set<uint256> found;
@@ -221,9 +226,9 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
}
}
if (mProposing)
if (mValidating)
mOurPosition = boost::make_shared<LedgerProposal>
(theConfig.VALIDATION_SEED, initialLedger->getParentHash(), txSet);
(mValSeed, initialLedger->getParentHash(), txSet);
else
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet);
mapComplete(txSet, initialSet, false);
@@ -317,13 +322,21 @@ void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vector<uint160
void LedgerConsensus::statusChange(newcoin::NodeEvent event, Ledger::pointer ledger)
{ // Send a node status change message to our peers
newcoin::TMStatusChange s;
s.set_newevent(event);
s.set_ledgerseq(ledger->getLedgerSeq());
s.set_networktime(theApp->getOPs().getNetworkTimeNC());
uint256 plhash = ledger->getParentHash();
s.set_previousledgerhash(plhash.begin(), plhash.size());
if (!mHaveCorrectLCL)
s.set_newevent(newcoin::neLOST_SYNC);
else
{
s.set_newevent(event);
s.set_ledgerseq(ledger->getLedgerSeq());
s.set_networktime(theApp->getOPs().getNetworkTimeNC());
uint256 hash = ledger->getParentHash();
s.set_previousledgerhash(hash.begin(), hash.size());
hash = ledger->getHash();
s.set_ledgerhash(hash.begin(), hash.size());
}
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(s, newcoin::mtSTATUS_CHANGE);
theApp->getConnectionPool().relayMessage(NULL, packet);
Log(lsINFO) << "send status change to peer";
}
void LedgerConsensus::abort()
@@ -724,7 +737,7 @@ void LedgerConsensus::accept(SHAMap::pointer set)
assert(set->getHash() == mOurPosition->getCurrentHash());
Log(lsINFO) << "Computing new LCL based on network consensus";
Log(lsDEBUG) << "Consensus " << mOurPosition->getCurrentHash().GetHex();
Log(lsDEBUG) << "Previous LCL " << mPreviousLedger->getHash().GetHex();
Log(lsDEBUG) << "Previous LCL " << mPrevLedgerHash.GetHex();
Ledger::pointer newLCL = boost::make_shared<Ledger>(false, boost::ref(*mPreviousLedger));
@@ -747,15 +760,6 @@ void LedgerConsensus::accept(SHAMap::pointer set)
uint256 newLCLHash = newLCL->getHash();
Log(lsTRACE) << "newLCL " << newLCLHash.GetHex();
#ifdef DEBUG
if (1)
{
Log(lsTRACE) << "newLCL after transactions";
Json::Value p;
newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
ssw.write(Log(lsTRACE).ref(), p);
}
#endif
Ledger::pointer newOL = boost::make_shared<Ledger>(true, boost::ref(*newLCL));
@@ -811,13 +815,17 @@ void LedgerConsensus::accept(SHAMap::pointer set)
Json::Value p;
newOL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
ssw.write(Log(lsTRACE).ref(), p);
Log(lsINFO) << "newLCL after transactions";
Json::Value p2;
newLCL->addJson(p2, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
ssw.write(Log(lsTRACE).ref(), p2);
}
#endif
if (mValidating)
{
SerializedValidation::pointer v = boost::make_shared<SerializedValidation>
(newLCLHash, mOurPosition->peekSeed(), true);
(newLCLHash, newLCL->getCloseTimeNC(), mOurPosition->peekSeed(), true);
v->setTrusted();
// FIXME: If not proposing, set not full
theApp->getValidations().addValidation(v);
@@ -825,9 +833,10 @@ void LedgerConsensus::accept(SHAMap::pointer set)
newcoin::TMValidation val;
val.set_validation(&validation[0], validation.size());
theApp->getConnectionPool().relayMessage(NULL, boost::make_shared<PackedMessage>(val, newcoin::mtVALIDATION));
Log(lsINFO) << "Validation sent " << newLCL->getHash().GetHex();
Log(lsINFO) << "Validation sent " << newLCLHash.GetHex();
}
statusChange(newcoin::neACCEPTED_LEDGER, newOL);
else Log(lsWARNING) << "Not validating";
statusChange(newcoin::neACCEPTED_LEDGER, newLCL);
}
void LedgerConsensus::endConsensus()

View File

@@ -83,9 +83,11 @@ class LedgerConsensus : public boost::enable_shared_from_this<LedgerConsensus>
protected:
LCState mState;
uint32 mCloseTime;
uint256 mPrevLedgerHash;
Ledger::pointer mPreviousLedger;
LedgerProposal::pointer mOurPosition;
bool mProposing, mValidating;
NewcoinAddress mValSeed;
bool mProposing, mValidating, mHaveCorrectLCL;
// Convergence tracking, trusted peers indexed by hash of public key
boost::unordered_map<uint160, LedgerProposal::pointer> mPeerPositions;
@@ -130,7 +132,7 @@ protected:
void endConsensus();
public:
LedgerConsensus(Ledger::pointer previousLedger, uint32 closeTime);
LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime);
int startup();

View File

@@ -251,7 +251,7 @@ void NetworkOPs::setStateTimer(int sec)
uint64 consensusTime = mLedgerMaster->getCurrentLedger()->getCloseTimeNC() - LEDGER_WOBBLE_TIME;
uint64 now = getNetworkTimeNC();
if (now >= consensusTime) sec = 0;
if (now >= consensusTime) sec = 1;
else if (sec > (consensusTime - now)) sec = (consensusTime - now);
}
mNetTimer.expires_from_now(boost::posix_time::seconds(sec));
@@ -269,8 +269,6 @@ public:
{
if (trustedValidations > v.trustedValidations) return true;
if (trustedValidations < v.trustedValidations) return false;
if (untrustedValidations > v.untrustedValidations) return true;
if (untrustedValidations < v.untrustedValidations) return false;
if (nodesUsing > v.nodesUsing) return true;
if (nodesUsing < v.nodesUsing) return false;
return highNode > v.highNode;
@@ -308,7 +306,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
return;
}
// FIXME: Don't check unless last closed ledger is at least some seconds old
// If full or tracking, check only at wobble time!
if (checkLastClosedLedger(peerList))
@@ -334,14 +331,11 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
// check if the ledger is good enough to go to omFULL
// Note: Do not go to omFULL if we don't have the previous ledger
// check if the ledger is bad enough to go to omCONNECTED -- TODO
if (theConfig.VALIDATION_SEED.isValid())
{
if (theApp->getOPs().getNetworkTimeNC() <
(theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4))
setMode(omFULL);
else
Log(lsWARNING) << "Too late to go to full, try next ledger";
}
if (theApp->getOPs().getNetworkTimeNC() <
(theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4))
setMode(omFULL);
else
Log(lsWARNING) << "Too late to go to full, will try in consensus window";
}
if (mMode == omFULL)
@@ -363,8 +357,11 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
// Do we have sufficient validations for our last closed ledger? Or do sufficient nodes
// agree? And do we have no better ledger available?
// If so, we are either tracking or full.
boost::unordered_map<uint256, ValidationCount> ledgers;
// FIXME: We may have a ledger with many recent validations but that no directly-connected
// node is using. THis is kind of fundamental.
boost::unordered_map<uint256, ValidationCount> ledgers;
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
{
if (!*it)
@@ -377,11 +374,10 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
if (!!peerLedger)
{
// FIXME: If we have this ledger, don't count it if it's too far past its close time
bool isNew = ledgers.find(peerLedger) == ledgers.end();
ValidationCount& vc = ledgers[peerLedger];
if (isNew)
if (vc.nodesUsing == 0)
{
theApp->getValidations().getValidationCount(peerLedger,
theApp->getValidations().getValidationCount(peerLedger, true,
vc.trustedValidations, vc.untrustedValidations);
Log(lsTRACE) << peerLedger.GetHex() << " has " << vc.trustedValidations <<
" trusted validations and " << vc.untrustedValidations << " untrusted";
@@ -395,19 +391,27 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
Ledger::pointer currentClosed = mLedgerMaster->getClosedLedger();
uint256 closedLedger = currentClosed->getHash();
ValidationCount& vc = ledgers[closedLedger];
if ((vc.nodesUsing == 0) || (theApp->getWallet().getNodePublic() > vc.highNode))
vc.highNode = theApp->getWallet().getNodePublic();
++ledgers[closedLedger].nodesUsing;
ValidationCount& ourVC = ledgers[closedLedger];
if (ourVC.nodesUsing == 0)
{
ourVC.highNode = theApp->getWallet().getNodePublic();
theApp->getValidations().getValidationCount(closedLedger, true,
ourVC.trustedValidations, ourVC.untrustedValidations);
}
++ourVC.nodesUsing;
ValidationCount bestVC = ourVC;
// 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();
it != end; ++it)
{
if (it->second > vc)
Log(lsTRACE) << "L: " << it->first.GetHex() <<
" t=" << it->second.trustedValidations << ", u=" << it->second.untrustedValidations <<
", n=" << it->second.nodesUsing;
if (it->second > bestVC)
{
vc = it->second;
bestVC = it->second;
closedLedger = it->first;
switchLedgers = true;
}
@@ -467,8 +471,10 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
s.set_newevent(newcoin::neSWITCHED_LEDGER);
s.set_ledgerseq(newLedger->getLedgerSeq());
s.set_networktime(theApp->getOPs().getNetworkTimeNC());
uint256 plhash = newLedger->getParentHash();
s.set_previousledgerhash(plhash.begin(), plhash.size());
uint256 hash = newLedger->getParentHash();
s.set_previousledgerhash(hash.begin(), hash.size());
hash = newLedger->getHash();
s.set_ledgerhash(hash.begin(), hash.size());
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(s, newcoin::mtSTATUS_CHANGE);
theApp->getConnectionPool().relayMessage(NULL, packet);
}
@@ -491,8 +497,9 @@ int NetworkOPs::beginConsensus(Ledger::pointer closingLedger)
// Create a consensus object to get consensus on this ledger
if (!!mConsensus) mConsensus->abort();
prevLedger->setImmutable();
mConsensus = boost::make_shared<LedgerConsensus>
(prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
mConsensus = boost::make_shared<LedgerConsensus>(
prevLedger->getHash(), // FIXME: Only do this if the previous ledger is the consensus previous ledger
prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
Log(lsDEBUG) << "Pre-close time, initiating consensus engine";
return mConsensus->startup();
@@ -568,6 +575,12 @@ void NetworkOPs::mapComplete(const uint256& hash, SHAMap::pointer map)
void NetworkOPs::endConsensus()
{
uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash();
Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead";
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))
(*it)->cycleStatus();
mConsensus = boost::shared_ptr<LedgerConsensus>();
}

View File

@@ -823,21 +823,23 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet)
packet.set_networktime(theApp->getOPs().getNetworkTimeNC());
mLastStatus = packet;
if (packet.newevent() == newcoin::neLOST_SYNC)
{
mPreviousLedgerHash.zero();
mClosedLedgerHash.zero();
}
if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8)))
{ // a peer has changed ledgers
if (packet.has_previousledgerhash() && (packet.previousledgerhash().size() == (256 / 8)))
memcpy(mPreviousLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8);
else
mPreviousLedgerHash = mClosedLedgerHash;
memcpy(mClosedLedgerHash.begin(), packet.ledgerhash().data(), 256 / 8);
mClosedLedgerTime = ptFromSeconds(packet.networktime());
Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash.GetHex();
}
else if(packet.has_previousledgerhash() && packet.previousledgerhash().size() == (256 / 8))
else mClosedLedgerHash.zero();
if (packet.has_previousledgerhash() && packet.previousledgerhash().size() == (256 / 8))
{
memcpy(mClosedLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8);
mClosedLedgerTime = ptFromSeconds(packet.networktime());
memcpy(mPreviousLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8);
}
else mPreviousLedgerHash.zero();
}
void Peer::recvGetLedger(newcoin::TMGetLedger& packet)

View File

@@ -136,6 +136,7 @@ public:
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
NewcoinAddress getNodePublic() const { return mNodePublic; }
void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); }
};
#endif

View File

@@ -38,6 +38,7 @@ enum SOE_Field
sfBorrowRate,
sfBorrowStart,
sfBorrower,
sfCloseTime,
sfCurrency,
sfCurrencyIn,
sfCurrencyOut,

View File

@@ -4,6 +4,7 @@
SOElement SerializedValidation::sValidationFormat[] = {
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
{ sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 },
{ sfCloseTime, "CloseTime", STI_UINT64, SOE_REQUIRED, 0 },
{ sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 },
{ sfExtensions, "Extensions", STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 },
@@ -18,11 +19,14 @@ SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSi
if (!isValid()) throw std::runtime_error("Invalid validation");
}
SerializedValidation::SerializedValidation(const uint256& ledgerHash, const NewcoinAddress& naSeed, bool isFull)
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint64 closeTime,
const NewcoinAddress& naSeed, bool isFull)
: STObject(sValidationFormat), mSignature("Signature"), mTrusted(false)
{
setValueFieldH256(sfLedgerHash, ledgerHash);
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
setValueFieldU64(sfCloseTime, closeTime);
if (naSeed.isValid())
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
if (!isFull) setFlag(sFullFlag);
NewcoinAddress::createNodePrivate(naSeed).signNodePrivate(getSigningHash(), mSignature.peekValue());
@@ -46,6 +50,11 @@ uint256 SerializedValidation::getLedgerHash() const
return getValueFieldH256(sfLedgerHash);
}
uint64 SerializedValidation::getCloseTime() const
{
return getValueFieldU64(sfCloseTime);
}
bool SerializedValidation::isValid() const
{
try

View File

@@ -23,9 +23,10 @@ public:
SerializedValidation(SerializerIterator& sit, bool checkSignature = true);
SerializedValidation(const Serializer& s, bool checkSignature = true);
SerializedValidation(const uint256& ledgerHash, const NewcoinAddress& naSeed, bool isFull);
SerializedValidation(const uint256& ledgerHash, uint64 closeTime, const NewcoinAddress& naSeed, bool isFull);
uint256 getLedgerHash() const;
uint64 getCloseTime() const;
NewcoinAddress getSignerPublic() const;
bool isValid() const;
bool isFull() const;
@@ -33,7 +34,7 @@ public:
CKey::pointer getSigningKey() const;
uint256 getSigningHash() const;
void setTrusted() { mTrusted = true; }
void setTrusted() { mTrusted = true; }
void addSigned(Serializer&) const;
void addSignature(Serializer&) const;
std::vector<unsigned char> getSigned() const;

View File

@@ -2,22 +2,40 @@
#include "ValidationCollection.h"
#include "Application.h"
#include "LedgerTiming.h"
#include "Log.h"
bool ValidationCollection::addValidation(SerializedValidation::pointer val)
{
if(theApp->getUNL().nodeInUNL(val->getSignerPublic()))
val->setTrusted();
bool isTrusted = false;
if (theApp->getUNL().nodeInUNL(val->getSignerPublic()))
{
uint64 now = theApp->getOPs().getNetworkTimeNC();
uint64 valClose = val->getCloseTime();
if ((now > valClose) && (now < (valClose + 2 * LEDGER_INTERVAL)))
isTrusted = true;
else
Log(lsWARNING) << "Received stale validation";
}
uint256 hash = val->getLedgerHash();
uint160 node = val->getSignerPublic().getNodeID();
boost::mutex::scoped_lock sl(mValidationLock);
bool ret = mValidations[hash].insert(std::make_pair(node, val)).second;
if (ret)
Log(lsINFO) << "Val for " << hash.GetHex() << " from " << node.GetHex() << " added " <<
(val->isTrusted() ? "trusted" : "UNtrusted");
return ret;
{
boost::mutex::scoped_lock sl(mValidationLock);
if (!mValidations[hash].insert(std::make_pair(node, val)).second)
return false;
if (isTrusted)
{
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.find(node);
if ((it == mCurrentValidations.end()) || (val->getCloseTime() >= it->second->getCloseTime()))
mCurrentValidations[node] = val;
}
}
Log(lsINFO) << "Val for " << hash.GetHex() << " from " << node.GetHex() << " added " <<
(val->isTrusted() ? "trusted" : "UNtrusted");
return true;
}
ValidationSet ValidationCollection::getValidations(const uint256& ledger)
@@ -31,17 +49,24 @@ ValidationSet ValidationCollection::getValidations(const uint256& ledger)
return ret;
}
void ValidationCollection::getValidationCount(const uint256& ledger, int& trusted, int &untrusted)
void ValidationCollection::getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int &untrusted)
{
trusted = untrusted = 0;
boost::mutex::scoped_lock sl(mValidationLock);
boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger);
uint64 now = theApp->getOPs().getNetworkTimeNC();
if (it != mValidations.end())
{
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end();
vit != end; ++vit)
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
{
if(vit->second->isTrusted())
bool trusted = vit->second->isTrusted();
if (trusted && currentOnly)
{
uint64 closeTime = vit->second->getCloseTime();
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_INTERVAL)))
trusted = false;
}
if (trusted)
++trusted;
else
++untrusted;

View File

@@ -16,13 +16,14 @@ class ValidationCollection
boost::mutex mValidationLock;
boost::unordered_map<uint256, ValidationSet> mValidations;
boost::unordered_map<uint160, SerializedValidation::pointer> mCurrentValidations;
public:
ValidationCollection() { ; }
bool addValidation(SerializedValidation::pointer);
ValidationSet getValidations(const uint256& ledger);
void getValidationCount(const uint256& ledger, int& trusted, int& untrusted);
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted);
};
#endif

View File

@@ -88,6 +88,7 @@ enum NodeEvent {
neCLOSING_LEDGER = 1; // closing a ledger because its close time has come
neACCEPTED_LEDGER = 2; // accepting a closed ledger, we have finished computing it
neSWITCHED_LEDGER = 3; // changing due to network consensus
neLOST_SYNC = 4;
}
message TMStatusChange {