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

This commit is contained in:
jed
2012-10-10 09:34:10 -07:00
16 changed files with 207 additions and 84 deletions

View File

@@ -299,16 +299,30 @@ Remote.prototype.server_subscribe = function (onDone, onFailure) {
this.request(
{ 'command' : 'server_subscribe' },
function (r) {
self.ledger_current_index = r.ledger_current_index;
self.ledger_closed = r.ledger_closed;
self.stand_alone = r.stand_alone;
onDone();
function (r) {
self.ledger_current_index = r.ledger_current_index;
self.ledger_closed = r.ledger_closed;
self.stand_alone = r.stand_alone;
onDone();
},
onFailure
);
};
Remote.prototype.ledger_accept = function (onDone, onFailure) {
if (this.stand_alone)
{
this.request(
{ 'command' : 'ledger_accept' },
onDone,
onFailure
);
}
else {
onFailure({ 'error' : 'notStandAlone' });
}
};
// Refresh accounts[account].seq
// done(result);
Remote.prototype.account_seq = function (account, advance, onDone, onFailure) {

View File

@@ -194,24 +194,30 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency)
return sCurrency;
}
// Assumes trusted input.
bool STAmount::setValue(const std::string& sAmount)
{ // Note: mIsNative must be set already!
uint64 uValue;
int iOffset;
size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : ".");
bool bInteger = uDecimal == std::string::npos;
size_t uExp = uDecimal == std::string::npos ? sAmount.find_first_of("e") : std::string::npos;
bool bInteger = uDecimal == std::string::npos && uExp == std::string::npos;
mIsNegative = false;
if (bInteger)
{
// Integer input: does not necessarily mean native.
try
{
int64 a = sAmount.empty() ? 0 : lexical_cast_st<int64>(sAmount);
if (a >= 0)
uValue = static_cast<uint64>(a);
{
uValue = static_cast<uint64>(a);
}
else
{
uValue = static_cast<uint64>(-a);
uValue = static_cast<uint64>(-a);
mIsNegative = true;
}
@@ -224,36 +230,73 @@ bool STAmount::setValue(const std::string& sAmount)
}
iOffset = 0;
}
else if (uExp != std::string::npos)
{
// e input
try
{
int64 iInteger = uExp ? lexical_cast_st<uint64>(sAmount.substr(0, uExp)) : 0;
if (iInteger >= 0)
{
uValue = static_cast<uint64>(iInteger);
}
else
{
uValue = static_cast<uint64>(-iInteger);
mIsNegative = true;
}
iOffset = lexical_cast_st<uint64>(sAmount.substr(uExp+1));
}
catch (...)
{
Log(lsINFO) << "Bad e amount: " << sAmount;
return false;
}
}
else
{
// Float input: has a decimal
// Example size decimal size-decimal offset
// ^1 2 0 2 -1
// 123^ 4 3 1 0
// 1^23 4 1 3 -2
iOffset = -int(sAmount.size() - uDecimal - 1);
// Issolate integer and fraction.
uint64 uInteger;
int64 iInteger = uDecimal ? lexical_cast_st<uint64>(sAmount.substr(0, uDecimal)) : 0;
if (iInteger >= 0)
uInteger = static_cast<uint64>(iInteger);
else
try
{
uInteger = static_cast<uint64>(-iInteger);
mIsNegative = true;
iOffset = -int(sAmount.size() - uDecimal - 1);
// Issolate integer and fraction.
uint64 uInteger;
int64 iInteger = uDecimal ? lexical_cast_st<uint64>(sAmount.substr(0, uDecimal)) : 0;
if (iInteger >= 0)
{
uInteger = static_cast<uint64>(iInteger);
}
else
{
uInteger = static_cast<uint64>(-iInteger);
mIsNegative = true;
}
uint64 uFraction = iOffset ? lexical_cast_st<uint64>(sAmount.substr(uDecimal+1)) : 0;
// Scale the integer portion to the same offset as the fraction.
uValue = uInteger;
for (int i = -iOffset; i--;)
uValue *= 10;
// Add in the fraction.
uValue += uFraction;
}
catch (...)
{
Log(lsINFO) << "Bad float amount: " << sAmount;
uint64 uFraction = iOffset ? lexical_cast_st<uint64>(sAmount.substr(uDecimal+1)) : 0;
// Scale the integer portion to the same offset as the fraction.
uValue = uInteger;
for (int i = -iOffset; i--;)
uValue *= 10;
// Add in the fraction.
uValue += uFraction;
return false;
}
}
if (mIsNative)

View File

@@ -88,20 +88,24 @@ void Application::run()
boost::thread t6(boost::bind(&InitDB, &mNetNodeDB, "netnode.db", NetNodeDBInit, NetNodeDBCount));
t1.join(); t2.join(); t3.join(); t4.join(); t5.join(); t6.join();
if(theConfig.START_UP==Config::FRESH)
if (theConfig.START_UP == Config::FRESH)
{
Log(lsINFO) << "Starting new Ledger";
startNewLedger();
}else if(theConfig.START_UP==Config::LOAD)
}
else if (theConfig.START_UP == Config::LOAD)
{
Log(lsINFO) << "Loading Old Ledger";
loadOldLedger();
}else
{ // TODO: This should really not validate a ledger until it gets the current one from our peers
// but I'll let david make this change since a lot of code assumes we have a ledger
// for now just do what we always were doing
}
else if (theConfig.START_UP == Config::NETWORK)
{ // This should probably become the default once we have a stable network
if (!theConfig.RUN_STANDALONE)
mNetOps.needNetworkLedger();
startNewLedger();
}
else
startNewLedger();
//
// Begin validation and ip maintenance.
@@ -173,6 +177,7 @@ Application::~Application()
delete mHashNodeDB;
delete mNetNodeDB;
}
void Application::startNewLedger()
{
// New stuff.
@@ -203,14 +208,17 @@ void Application::startNewLedger()
void Application::loadOldLedger()
{
Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;",true);
Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;");
if(!lastLedger)
if (!lastLedger)
{
std::cout << "No Ledger found?" << std::endl;
exit(-1);
}
mMasterLedger.pushLedger(lastLedger);
lastLedger->setClosed();
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*lastLedger));
mMasterLedger.switchLedgers(lastLedger, openLedger);
mNetOps.setLastCloseTime(lastLedger->getCloseTimeNC());
}
// vim:ts=4

View File

@@ -56,7 +56,7 @@ public:
std::vector<std::string> IPS; // Peer IPs from newcoind.cfg.
std::vector<std::string> SNTP_SERVERS; // SNTP servers from newcoind.cfg.
enum StartUpType {FRESH,NORMAL,LOAD};
enum StartUpType { FRESH, NORMAL, LOAD, NETWORK };
StartUpType START_UP;
// Network parameters

View File

@@ -391,7 +391,7 @@ void Ledger::saveAcceptedLedger(Ledger::ref ledger)
theApp->getOPs().pubLedger(ledger);
}
Ledger::pointer Ledger::getSQL(const std::string& sql,bool isMutable)
Ledger::pointer Ledger::getSQL(const std::string& sql)
{
uint256 ledgerHash, prevHash, accountHash, transHash;
uint64 totCoins;
@@ -424,8 +424,8 @@ Ledger::pointer Ledger::getSQL(const std::string& sql,bool isMutable)
db->endIterRows();
}
Ledger::pointer ret =Ledger::pointer(new Ledger(prevHash, transHash, accountHash, totCoins, closingTime, prevClosingTime,
closeFlags, closeResolution, ledgerSeq,isMutable));
Ledger::pointer ret = Ledger::pointer(new Ledger(prevHash, transHash, accountHash, totCoins,
closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq, true));
if (ret->getHash() != ledgerHash)
{
if (sLog(lsERROR))

View File

@@ -93,7 +93,7 @@ public:
Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution,
uint32 ledgerSeq,bool immutable); // used for database ledgers
uint32 ledgerSeq, bool immutable); // used for database ledgers
Ledger(const std::vector<unsigned char>& rawLedger);
@@ -103,7 +103,7 @@ public:
Ledger(Ledger& target, bool isMutable); // snapshot
static Ledger::pointer getSQL(const std::string& sqlStatement,bool immutable=false);
static Ledger::pointer getSQL(const std::string& sqlStatement);
void updateHash();
void setClosed() { mClosed = true; }
@@ -116,10 +116,6 @@ public:
void armDirty() { mTransactionMap->armDirty(); mAccountStateMap->armDirty(); }
void disarmDirty() { mTransactionMap->disarmDirty(); mAccountStateMap->disarmDirty(); }
// This ledger has closed, will never be accepted, and is accepting
// new transactions to be re-reprocessed when do accept a new last-closed ledger
void bumpSeq() { mClosed = true; mLedgerSeq++; }
// ledger signature operations
void addRaw(Serializer &s) const;
void setRaw(const Serializer& s);

View File

@@ -26,8 +26,9 @@
SETUP_LOG();
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0),
mLastCloseProposers(0), mLastCloseConvergeTime(1000 * LEDGER_IDLE_INTERVAL), mLastValidationTime(0)
mMode(omDISCONNECTED), mNeedNetworkLedger(false), mNetTimer(io_service), mLedgerMaster(pLedgerMaster),
mCloseTimeOffset(0), mLastCloseProposers(0), mLastCloseConvergeTime(1000 * LEDGER_IDLE_INTERVAL),
mLastValidationTime(0)
{
}
@@ -424,7 +425,8 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
// If full or tracking, check only at wobble time!
uint256 networkClosed;
bool ledgerChange = checkLastClosedLedger(peerList, networkClosed);
if(networkClosed.isZero())return;
if(networkClosed.isZero())
return;
// WRITEME: Unless we are in omFULL and in the process of doing a consensus,
// we must count how many nodes share our LCL, how many nodes disagree with our LCL,
@@ -435,7 +437,8 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
if ((mMode == omCONNECTED) && !ledgerChange)
{ // count number of peers that agree with us and UNL nodes whose validations we have for LCL
// if the ledger is good enough, go to omTRACKING - TODO
setMode(omTRACKING);
if (!mNeedNetworkLedger)
setMode(omTRACKING);
}
if ((mMode == omTRACKING) && !ledgerChange )
@@ -617,6 +620,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringCo
else
cLog(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash();
mNeedNetworkLedger = false;
newLedger->setClosed();
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*newLedger));
mLedgerMaster->switchLedgers(newLedger, openLedger);
@@ -931,10 +935,10 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
{
Json::Value jvObj(Json::objectValue);
jvObj["type"] = "ledgerAccepted";
jvObj["seq"] = lpAccepted->getLedgerSeq();
jvObj["hash"] = lpAccepted->getHash().ToString();
jvObj["time"] = Json::Value::UInt(lpAccepted->getCloseTimeNC());
jvObj["type"] = "ledgerAccepted";
jvObj["ledger_closed_index"] = lpAccepted->getLedgerSeq();
jvObj["ledger_closed"] = lpAccepted->getHash().ToString();
jvObj["time"] = Json::Value::UInt(lpAccepted->getCloseTimeNC());
BOOST_FOREACH(InfoSub* ispListener, mSubLedger)
{

View File

@@ -52,6 +52,7 @@ protected:
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::iterator subInfoMapIterator;
OperatingMode mMode;
bool mNeedNetworkLedger;
boost::posix_time::ptime mConnectTime;
boost::asio::deadline_timer mNetTimer;
boost::shared_ptr<LedgerConsensus> mConsensus;
@@ -184,6 +185,7 @@ public:
void setStandAlone() { setMode(omFULL); }
void setStateTimer();
void newLCL(int proposers, int convergeTime, const uint256& ledgerHash);
void needNetworkLedger() { mNeedNetworkLedger = true; }
void consensusViewChange();
int getPreviousProposers() { return mLastCloseProposers; }
int getPreviousConvergeTime() { return mLastCloseConvergeTime; }

View File

@@ -104,6 +104,9 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet
if (ele.mAccountID == mDstAccountID) {
path.mPath.erase(path.mPath.begin());
path.mPath.erase(path.mPath.begin() + path.mPath.size()-1);
if (path.mPath.size() == 0) {
continue;
}
retPathSet.addPath(path);
return true;
}
@@ -118,7 +121,11 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet
STPath new_path(path);
STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut());
new_path.mPath.push_back(new_ele);
new_path.mCurrencyID = book->getCurrencyOut();
new_path.mCurrentAccount = book->getCurrencyOut();
pqueue.push(new_path);
}
}
@@ -136,8 +143,26 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet
new_path.mPath.push_back(new_ele);
pqueue.push(new_path);
}
} // BOOST_FOREACHE
// every offer that wants the source currency
std::vector<OrderBook::pointer> books;
mOrderBook.getBooks(path.mCurrentAccount, path.mCurrencyID, books);
BOOST_FOREACH(OrderBook::pointer book,books)
{
STPath new_path(path);
STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut());
new_path.mPath.push_back(new_ele);
new_path.mCurrentAccount=book->getIssuerOut();
new_path.mCurrencyID=book->getCurrencyOut();
pqueue.push(new_path);
}
}
} // else
// enumerate all adjacent nodes, construct a new path and push it into the queue
} // While
} // if there is a ledger

View File

@@ -1828,9 +1828,6 @@ Json::Value RPCServer::doSend(const Json::Value& params)
if (params.size() >= 9)
sSrcIssuer = params[8u].asString();
if (params.size() >= 9)
sSrcIssuer = params[8u].asString();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
return RPCError(rpcBAD_SEED);

View File

@@ -24,6 +24,7 @@
// 8-bit integers
FIELD(CloseResolution, UINT8, 1)
FIELD(TemplateEntryType, UINT8, 2)
// 16-bit integers
FIELD(LedgerEntryType, UINT16, 1)
@@ -123,9 +124,13 @@
// inner object
// OBJECT/1 is reserved for end of object
FIELD(TemplateEntry, OBJECT, 1)
// array of objects
// ARRAY/1 is reserved for end of array
FIELD(SigningAccounts, ARRAY, 2)
FIELD(TxnSignatures, ARRAY, 3)
FIELD(Signatures, ARRAY, 4)
FIELD(Template, ARRAY, 5)
FIELD(Necessary, ARRAY, 6)
FIELD(Sufficient, ARRAY, 7)

View File

@@ -595,6 +595,9 @@ public:
// std::string getText() const;
Json::Value getJson(int) const;
uint160 mCurrencyID;
uint160 mCurrentAccount; // what account is at the end of the path
std::vector<STPathElement>::iterator begin() { return mPath.begin(); }
std::vector<STPathElement>::iterator end() { return mPath.end(); }
std::vector<STPathElement>::const_iterator begin() const { return mPath.begin(); }

View File

@@ -79,6 +79,7 @@ public:
boost::unordered_set<NewcoinAddress> parseAccountIds(const Json::Value& jvArray);
// Request-Response Commands
void doLedgerAccept(Json::Value& jvResult, const Json::Value& jvRequest);
void doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest);
void doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest);
void doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest);
@@ -303,6 +304,7 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest)
doFuncPtr dfpFunc;
} commandsA[] = {
// Request-Response Commands:
{ "ledger_accept", &WSConnection::doLedgerAccept },
{ "ledger_closed", &WSConnection::doLedgerClosed },
{ "ledger_current", &WSConnection::doLedgerCurrent },
{ "ledger_entry", &WSConnection::doLedgerEntry },
@@ -541,6 +543,20 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json
}
}
void WSConnection::doLedgerAccept(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theConfig.RUN_STANDALONE)
{
jvResult["error"] = "notStandAlone";
}
else
{
mNetwork.acceptLedger();
jvResult["ledger_current_index"] = mNetwork.getCurrentLedgerID();
}
}
void WSConnection::doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest)
{
uint256 uLedger = mNetwork.getClosedLedger();

View File

@@ -98,8 +98,9 @@ int main(int argc, char* argv[])
("test,t", "Perform unit tests.")
("parameters", po::value< vector<string> >(), "Specify comma separated parameters.")
("verbose,v", "Increase log level.")
("load","Load the current ledger from the local DB.")
("start","Start from a fresh Ledger.")
("load", "Load the current ledger from the local DB.")
("start", "Start from a fresh Ledger.")
("net", "Get the initial ledger from the network.")
;
// Interpret positional arguments as --parameters.
@@ -156,8 +157,9 @@ int main(int argc, char* argv[])
}
}
if(vm.count("start")) theConfig.START_UP=Config::FRESH;
else if(vm.count("load")) theConfig.START_UP=Config::LOAD;
if (vm.count("start")) theConfig.START_UP = Config::FRESH;
else if (vm.count("load")) theConfig.START_UP = Config::LOAD;
else if (vm.count("net")) theConfig.START_UP = Config::NETWORK;
if (iResult)
{

View File

@@ -1,9 +1,8 @@
var fs = require("fs");
var buster = require("buster");
var fs = require("fs");
var buster = require("buster");
var server = require("./server.js");
var remote = require("../js/remote.js");
var utils = require("../js/utils.js");
var config = require("./config.js");
// How long to wait for server to start.
@@ -11,23 +10,6 @@ var serverDelay = 1500;
buster.testRunner.timeout = 5000;
buster.testCase("Utils", {
"hexToString and stringToHex" : {
"Even: 123456" : function () {
buster.assert.equals("123456", utils.stringToHex(utils.hexToString("123456")));
},
"Odd: 12345" : function () {
buster.assert.equals("012345", utils.stringToHex(utils.hexToString("12345")));
},
"Under 10: 0" : function () {
buster.assert.equals("00", utils.stringToHex(utils.hexToString("0")));
},
"Under 10: 1" : function () {
buster.assert.equals("01", utils.stringToHex(utils.hexToString("1")));
}
}
});
buster.testCase("Standalone server startup", {
"server start and stop" : function (done) {
server.start("alpha",

26
test/utils-test.js Normal file
View File

@@ -0,0 +1,26 @@
var fs = require("fs");
var buster = require("buster");
var utils = require("../js/utils.js");
buster.testCase("Utils", {
"hexToString and stringToHex" : {
"Even: 123456" : function () {
buster.assert.equals("123456", utils.stringToHex(utils.hexToString("123456")));
},
"Odd: 12345" : function () {
buster.assert.equals("012345", utils.stringToHex(utils.hexToString("12345")));
},
"Under 10: 0" : function () {
buster.assert.equals("00", utils.stringToHex(utils.hexToString("0")));
},
"Under 10: 1" : function () {
buster.assert.equals("01", utils.stringToHex(utils.hexToString("1")));
},
"Empty" : function () {
buster.assert.equals("", utils.stringToHex(utils.hexToString("")));
}
}
});
// vim:sw=2:sts=2:ts=8