diff --git a/js/remote.js b/js/remote.js index ffab43eaad..de94590e37 100644 --- a/js/remote.js +++ b/js/remote.js @@ -12,194 +12,318 @@ var util = require('util'); var WebSocket = require('ws'); // --> trusted: truthy, if remote is trusted -var Remote = function(trusted, websocket_ip, websocket_port, trace) { - this.trusted = trusted; - this.websocket_ip = websocket_ip; - this.websocket_port = websocket_port; - this.id = 0; - this.trace = trace; +var Remote = function (trusted, websocket_ip, websocket_port, trace) { + this.trusted = trusted; + this.websocket_ip = websocket_ip; + this.websocket_port = websocket_port; + this.id = 0; + this.trace = trace; + this.ledger_closed = undefined; + this.ledger_current_index = undefined; + this.stand_alone = undefined; + + // Cache information for accounts. + this.account = {}; + + // Cache for various ledgers. + // XXX Clear when ledger advances. + this.ledgers = { + 'current' : {} + }; }; -var remoteConfig = function(config, server, trace) { - var serverConfig = config.servers[server]; - - return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, trace); +var remoteConfig = function (config, server, trace) { + var serverConfig = config.servers[server]; + return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, trace); }; -Remote.method('connect_helper', function() { - var self = this; +// XXX This needs to be determined from the network. +var fees = { + 'default' : 100, + 'account_create' : 1000, + 'nickname_create' : 1000, + 'offer' : 100, +}; - if (this.trace) - console.log("remote: connect: %s", this.url); +// For accounts we cache things like sequence numbers. +var accounts = { + // Consider sequence numbers stable if you know you're not generating bad transactions. + // Otherwise, clear it to have it automatically refreshed from the network. + + // acount : { seq : __ } +}; - this.ws = new WebSocket(this.url); - - var ws = this.ws; - - ws.response = {}; - - ws.onopen = function() { - if (this.trace) - console.log("remote: onopen: %s", ws.readyState); - - ws.onclose = undefined; - ws.onerror = undefined; - - self.done(ws.readyState); - }; - - ws.onerror = function() { - if (this.trace) - console.log("remote: onerror: %s", ws.readyState); - - ws.onclose = undefined; - - if (self.expire) { - if (this.trace) - console.log("remote: was expired"); - - self.done(ws.readyState); - } - else - { - // Delay and retry. - setTimeout(function() { - if (this.trace) - console.log("remote: retry"); - - self.connect_helper(); - }, 50); // Retry rate 50ms. - } - }; - - // Covers failure to open. - ws.onclose = function() { - if (this.trace) - console.log("remote: onclose: %s", ws.readyState); - - ws.onerror = undefined; - - self.done(ws.readyState); - }; - - // Node's ws module doesn't pass arguments to onmessage. - ws.on('message', function(json, flags) { - var message = JSON.parse(json); - // console.log("message: %s", json); - - if (message.type !== 'response') { - console.log("unexpected message: %s", json); - - } else { - var done = ws.response[message.id]; - - if (done) { - done(message); - - } else { - console.log("unexpected message id: %s", json); - } - } - }); +Remote.method('connect_helper', function () { + var self = this; + + if (this.trace) console.log("remote: connect: %s", this.url); + + var ws = this.ws = new WebSocket(this.url);; + + ws.response = {}; + + ws.onopen = function () { + if (this.trace) console.log("remote: onopen: %s", ws.readyState); + + ws.onclose = undefined; + ws.onerror = undefined; + + self.done(ws.readyState); + }; + + ws.onerror = function () { + if (this.trace) console.log("remote: onerror: %s", ws.readyState); + + ws.onclose = undefined; + + if (self.expire) { + if (this.trace) console.log("remote: was expired"); + self.done(ws.readyState); + } else { + // Delay and retry. + setTimeout(function () { + if (this.trace) console.log("remote: retry"); + self.connect_helper(); + }, 50); // Retry rate 50ms. + } + }; + + // Covers failure to open. + ws.onclose = function () { + if (this.trace) console.log("remote: onclose: %s", ws.readyState); + ws.onerror = undefined; + self.done(ws.readyState); + }; + + // Node's ws module doesn't pass arguments to onmessage. + ws.on('message', function (json, flags) { + var message = JSON.parse(json); + // console.log("message: %s", json); + + if (message.type !== 'response') { + console.log("unexpected message: %s", json); + } else { + var done = ws.response[message.id]; + if (done) { + done(message); + } else { + console.log("unexpected message id: %s", json); + } + } + }); }); // Target state is connectted. // done(readyState): // --> readyState: OPEN, CLOSED -Remote.method('connect', function(done, timeout) { - var self = this; - - this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); - this.done = done; - - if (timeout) { - if (this.trace) - console.log("remote: expire: false"); - - this.expire = false; - - setTimeout(function () { - if (this.trace) - console.log("remote: expire: timeout"); - - self.expire = true; - }, timeout); - } - else { - if (this.trace) - console.log("remote: expire: false"); - - this.expire = true; - } - - this.connect_helper(); - +Remote.method('connect', function (done, timeout) { + var self = this; + + this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); + this.done = done; + + if (timeout) { + if (this.trace) console.log("remote: expire: false"); + + this.expire = false; + + setTimeout(function () { + if (this.trace) console.log("remote: expire: timeout"); + self.expire = true; + }, timeout); + } else { + if (this.trace) console.log("remote: expire: false"); + this.expire = true; + } + + this.connect_helper(); }); // Target stated is disconnected. -Remote.method('disconnect', function(done) { - var ws = this.ws; - - ws.onclose = function() { - if (this.trace) - console.log("remote: onclose: %s", ws.readyState); - - done(ws.readyState); - }; - - ws.close(); +Remote.method('disconnect', function (done) { + var ws = this.ws; + + ws.onclose = function () { + if (this.trace) console.log("remote: onclose: %s", ws.readyState); + done(ws.readyState); + }; + + ws.close(); }); // Send a command. The comman should lack the id. // <-> command: what to send, consumed. -Remote.method('request', function(command, done) { - this.id += 1; // Advance id. - - var ws = this.ws; - - command.id = this.id; - - ws.response[command.id] = done; - - if (this.trace) - console.log("remote: send: %s", JSON.stringify(command)); - - ws.send(JSON.stringify(command)); +Remote.method('request', function (request, onDone, onFailure) { + this.id += 1; // Advance id. + + var ws = this.ws; + + request.id = this.id; + + ws.response[request.id] = function (response) { + if (this.trace) console.log("remote: response: %s", JSON.stringify(response)); + + if (onFailure && response.error) + { + onFailure(response); + } + else + { + onDone(response); + } + }; + + if (this.trace) console.log("remote: request: %s", JSON.stringify(request)); + + ws.send(JSON.stringify(request)); }); -Remote.method('ledger_closed', function(done) { - assert(this.trusted); // If not trusted, need to check proof. - - this.request({ 'command' : 'ledger_closed' }, done); +Remote.method('request_ledger_closed', function (onDone, onFailure) { + assert(this.trusted); // If not trusted, need to check proof. + this.request({ 'command' : 'ledger_closed' }, onDone, onFailure); }); // Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning). // Only for use by unit tests. -Remote.method('ledger_current', function(done) { - this.request({ 'command' : 'ledger_current' }, done); +Remote.method('request_ledger_current', function (onDone, onFailure) { + this.request({ 'command' : 'ledger_current' }, onDone, onFailure); }); -// <-> params: -// --> ledger : optional -// --> ledger_index : optional -Remote.method('ledger_entry', function(params, done) { - assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. - - params.command = 'ledger_entry'; - - this.request(params, done); +// <-> request: +// --> ledger : optional +// --> ledger_index : optional +// --> type +Remote.method('request_ledger_entry', function (req, onDone, onFailure) { + assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. + + req.command = 'ledger_entry'; + + if (req.ledger_closed) + { + // XXX Initial implementation no caching. + this.request(req, onDone, onFailure); + } + else if (req.ledger_index) + { + // Current + // XXX Only allow with standalone mode. Must sync response with advance. + var entry; + + switch (req.type) { + case 'account_root': + var cache = this.ledgers.current.account_root; + + if (!cache) + { + cache = this.ledgers.current.account_root = {}; + } + + var entry = this.ledgers.current.account_root[req.account]; + break; + + default: + // This type not cached. + } + + if (entry) + { + onDone(entry); + } + else + { + // Not cached. + + // Submit request + this.request(req, function (r) { + // Got result. + switch (req.type) { + case 'account_root': + this.ledgers.current.account_root.account = r; + break; + + default: + // This type not cached. + } + onDone(r); + }, onFailure); + } + } }); // Submit a json transaction. // done(value) // <-> value: { 'status', status, 'result' : result, ... } // done may be called up to 3 times. -Remote.method('submit', function(json, done) { -// this.request(..., function() { -// }); +Remote.method('submit', function (json, private_key, onDone, onFailure) { + var req = {}; + + req.command = 'submit'; + req.json = json; + + if (private_key && !this.trusted) + { + onFailure({ 'error' : 'untrustedSever', 'request' : req }); + } + else + { + this.request(req, onDone, onFailure); + } }); -exports.Remote = Remote; -exports.remoteConfig = remoteConfig; +// +// Higher level functions. +// -// vim:ts=4 +// Subscribe to a server to get the current and closed ledger. +// XXX Set up routine to update on notification. +Remote.method('server_subscribe', function (onDone, onFailure) { + this.request( + { 'command' : 'server_subscribe' }, + function (r) { + this.ledger_current_index = r.ledger_current_index; + this.ledger_closed = r.ledger_closed; + this.stand_alone = r.stand_alone; + onDone(); + }, + onFailure + ); +}); + +// Refresh accounts[account].seq +// done(result); +Remote.method('account_seq', function (account, onDone, onFailure) { + var account_root_entry = this.accounts[account]; + + if (account_root_entry && account_root_entry.seq) + { + onDone(account_root_entry.seq); + } + else + { + // Need to get the ledger entry. + this.request_ledger_entry( + { + 'ledger' : this.ledger_closed, + 'account_root' : account + }, + function (r) { + // Extract the seqence number from the account root entry. + this.accounts[account].seq = r.seq; + onDone(r.seq); + }, + onFailure + ); + } +}); + +// A submit that fills in the sequence number. +Remote.method('submit_seq', function (onDone, onFailure) { + +}); + +exports.Remote = Remote; +exports.remoteConfig = remoteConfig; +exports.fees = fees; +exports.accounts = accounts; + +// vim:sw=2:sts=2:ts=8 diff --git a/src/Pathfinder.cpp b/src/Pathfinder.cpp index 4f0276a451..9290f921ae 100644 --- a/src/Pathfinder.cpp +++ b/src/Pathfinder.cpp @@ -84,24 +84,65 @@ Pathfinder::Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountI bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet) { - if(mLedger) - { - PathOption::pointer head(new PathOption(mSrcAccountID,mSrcCurrencyID,mDstAmount.getCurrency())); - addOptions(head); + if(mLedger) { + std::queue pqueue; + STPathElement ele(mSrcAccountID, + mSrcCurrencyID, + uint160()); + STPath path; + path.addElement(ele); + pqueue.push(path); + while(pqueue.size()) { - for(int n=0; n tempPaths=mBuildingPaths; - mBuildingPaths.clear(); - BOOST_FOREACH(PathOption::pointer path,tempPaths) - { - addOptions(path); - } - if(checkComplete(retPathSet)) return(true); - } - } + STPath path = pqueue.front(); + pqueue.pop(); + // get the first path from the queue - return(false); + ele = path.mPath.back(); + // get the last node from the path + + if (ele.mAccountID == mDstAccountID) { + path.mPath.erase(path.mPath.begin()); + path.mPath.erase(path.mPath.begin() + path.mPath.size()-1); + retPathSet.addPath(path); + return true; + } + // found the destination + + if (!ele.mCurrencyID) { + BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXNSInBooks()) + { + //if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) + { + + STPath new_path(path); + STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); + new_path.mPath.push_back(new_ele); + pqueue.push(new_path); + } + } + + } else { + RippleLines rippleLines(ele.mAccountID); + BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) + { + if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) + { + STPath new_path(path); + STPathElement new_ele(line->getAccountIDPeer().getAccountID(), + ele.mCurrencyID, + uint160()); + + new_path.mPath.push_back(new_ele); + pqueue.push(new_path); + } + } + } + // enumerate all adjacent nodes, construct a new path and push it into the queue + } // While + } // if there is a ledger + + return false; } bool Pathfinder::checkComplete(STPathSet& retPathSet) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 3790691058..4b5de9ef8d 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1890,20 +1890,16 @@ Json::Value RPCServer::doSend(const Json::Value& params) // XXX Don't allow send to self of same currency. Transaction::pointer trans; - if (asDst) { // Destination exists, ordinary send. - STPathSet spsPaths; - uint160 srcCurrencyID; -// bool ret_b; -// ret_b = false; + STPathSet spsPaths; + uint160 srcCurrencyID; if (!saSrcAmountMax.isNative() || !saDstAmount.isNative()) { STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); -// ret_b = pf.findPaths(5, 1, spsPaths); pf.findPaths(5, 1, spsPaths); } diff --git a/src/RippleLines.cpp b/src/RippleLines.cpp index bae60414b1..e9a8ad25fa 100644 --- a/src/RippleLines.cpp +++ b/src/RippleLines.cpp @@ -8,6 +8,13 @@ RippleLines::RippleLines(const uint160& accountID, Ledger::pointer ledger) fillLines(accountID,ledger); } +void RippleLines::printRippleLines() { + for (int i =0; i < mLines.size(); i++) { + std::cout << i << ": " << mLines[i]->getAccountID().humanAccountID() << std::endl; + } + std::cout << std::endl; +} + RippleLines::RippleLines(const uint160& accountID ) { fillLines(accountID,theApp->getMasterLedger().getCurrentLedger()); diff --git a/src/RippleLines.h b/src/RippleLines.h index 13ea7f5dc4..00373838dd 100644 --- a/src/RippleLines.h +++ b/src/RippleLines.h @@ -16,4 +16,5 @@ public: RippleLines(const uint160& accountID ); // looks in the current ledger std::vector& getLines(){ return(mLines); } -}; \ No newline at end of file + void printRippleLines(); +}; diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 92316d8b96..32fab92f21 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -10,10 +10,35 @@ #include "Log.h" #include "NewcoinAddress.h" #include "utils.h" +#include "NewcoinAddress.h" STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0); STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1); +void STPathSet::printDebug() { + for (int i = 0; i < value.size(); i++) { + std::cout << i << ": "; + for (int j = 0; j < value[i].mPath.size(); j++) { + //STPathElement pe = value[i].mPath[j]; + NewcoinAddress nad; + nad.setAccountID(value[i].mPath[j].mAccountID); + std::cout << " " << nad.humanAccountID(); + //std::cout << " " << pe.mAccountID.GetHex(); + } + std::cout << std::endl; + } + +} + +void STPath::printDebug() { + std::cout << "STPath:" << std::endl; + for(int i =0; i < mPath.size(); i++) { + NewcoinAddress nad; + nad.setAccountID(mPath[i].mAccountID); + std::cout << " " << i << ": " << nad.humanAccountID() << std::endl; + } +} + std::string SerializedType::getFullText() const { std::string ret; @@ -331,6 +356,16 @@ bool STPathSet::isEquivalent(const SerializedType& t) const return v && (value == v->value); } +bool STPath::hasSeen(const uint160 &acct) { + + for (int i = 0; i < mPath.size();i++) { + STPathElement ele = getElement(i); + if (ele.getAccountID() == acct) + return true; + } + + return false; +} int STPath::getSerializeSize() const { int iBytes = 0; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 0c1cd3bac2..cee687a7fd 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -518,6 +518,9 @@ public: class STPathElement { + friend class STPathSet; + friend class STPath; + friend class Pathfinder; public: enum { typeEnd = 0x00, @@ -567,6 +570,8 @@ public: class STPath { + friend class STPathSet; + friend class Pathfinder; protected: std::vector mPath; @@ -574,12 +579,14 @@ public: STPath() { ; } STPath(const std::vector& p) : mPath(p) { ; } + void printDebug(); int getElementCount() const { return mPath.size(); } bool isEmpty() const { return mPath.empty(); } const STPathElement& getElement(int offset) const { return mPath[offset]; } const STPathElement& getElemet(int offset) { return mPath[offset]; } - void addElement(const STPathElement& e) { mPath.push_back(e); } + void addElement(const STPathElement &e) { mPath.push_back(e); } void clear() { mPath.clear(); } + bool hasSeen(const uint160 &acct); int getSerializeSize() const; // std::string getText() const; Json::Value getJson(int) const; @@ -636,7 +643,6 @@ protected: static STPathSet* construct(SerializerIterator&, SField::ref); public: - STPathSet() { ; } STPathSet(SField::ref n) : SerializedType(n) { ; } STPathSet(const std::vector& v) : value(v) { ; } @@ -658,6 +664,8 @@ public: virtual bool isEquivalent(const SerializedType& t) const; + void printDebug(); + std::vector::iterator begin() { return value.begin(); } std::vector::iterator end() { return value.end(); } std::vector::const_iterator begin() const { return value.begin(); } diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 208c5c71c3..f45299ec32 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -89,8 +89,8 @@ public: void doAccountTransactionSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); void doAccountTransactionUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest); - void doLedgerSubcribe(Json::Value& jvResult, const Json::Value& jvRequest); - void doLedgerUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest); + void doServerSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); + void doServerUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest); void doLedgerAccountsSubcribe(Json::Value& jvResult, const Json::Value& jvRequest); void doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest); void doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest); @@ -311,10 +311,10 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest) { "account_info_unsubscribe", &WSConnection::doAccountInfoUnsubscribe }, { "account_transaction_subscribe", &WSConnection::doAccountTransactionSubscribe }, { "account_transaction_unsubscribe", &WSConnection::doAccountTransactionUnsubscribe }, - { "ledger_subscribe", &WSConnection::doLedgerSubcribe }, - { "ledger_unsubscribe", &WSConnection::doLedgerUnsubscribe }, { "ledger_accounts_subscribe", &WSConnection::doLedgerAccountsSubcribe }, { "ledger_accounts_unsubscribe", &WSConnection::doLedgerAccountsUnsubscribe }, + { "server_subscribe", &WSConnection::doServerSubscribe }, + { "server_unsubscribe", &WSConnection::doServerUnsubscribe }, { "transaction_subscribe", &WSConnection::doTransactionSubcribe }, { "transaction_unsubscribe", &WSConnection::doTransactionUnsubscribe }, }; @@ -523,22 +523,6 @@ void WSConnection::doAccountTransactionUnsubscribe(Json::Value& jvResult, const } } -void WSConnection::doLedgerSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) -{ - if (!theApp->getOPs().subLedger(this)) - { - jvResult["error"] = "ledgerSubscribed"; - } -} - -void WSConnection::doLedgerUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest) -{ - if (!theApp->getOPs().unsubLedger(this)) - { - jvResult["error"] = "ledgerNotSubscribed"; - } -} - void WSConnection::doLedgerAccountsSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) { if (!theApp->getOPs().subLedgerAccounts(this)) @@ -559,13 +543,13 @@ void WSConnection::doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRe { uint256 uLedger = theApp->getOPs().getClosedLedger(); - jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); - jvResult["ledger"] = uLedger.ToString(); + jvResult["ledger_closed_index"] = theApp->getOPs().getLedgerID(uLedger); + jvResult["ledger_closed"] = uLedger.ToString(); } void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest) { - jvResult["ledger_index"] = theApp->getOPs().getCurrentLedgerID(); + jvResult["ledger_current_index"] = theApp->getOPs().getCurrentLedgerID(); } void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest) @@ -606,10 +590,17 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index. } - if (!!uLedger) - jvResult["ledger"] = uLedger.ToString(); + if (lpLedger->isClosed()) + { + if (!!uLedger) + jvResult["ledger_closed"] = uLedger.ToString(); - jvResult["ledger_index"] = uLedgerIndex; + jvResult["ledger_closed_index"] = uLedgerIndex; + } + else + { + jvResult["ledger_current_index"] = uLedgerIndex; + } uint256 uNodeIndex; bool bNodeBinary = false; @@ -788,6 +779,32 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } } +void WSConnection::doServerSubscribe(Json::Value& jvResult, const Json::Value& jvRequest) +{ + if (!theApp->getOPs().subLedger(this)) + { + jvResult["error"] = "serverSubscribed"; + } + else + { + if (theConfig.RUN_STANDALONE) + jvResult["stand_alone"] = 1; + + // XXX Make sure these values are available before returning them. + // XXX return connected status. + jvResult["ledger_closed"] = theApp->getOPs().getClosedLedger().ToString(); + jvResult["ledger_current_index"] = theApp->getOPs().getCurrentLedgerID(); + } +} + +void WSConnection::doServerUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest) +{ + if (!theApp->getOPs().unsubLedger(this)) + { + jvResult["error"] = "serverNotSubscribed"; + } +} + void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) { if (!theApp->getOPs().subTransaction(this)) diff --git a/test/config.js b/test/config.js index 0610373db9..10d084a532 100644 --- a/test/config.js +++ b/test/config.js @@ -9,17 +9,57 @@ exports.newcoind = path.join(process.cwd(), "newcoind"); // Configuration for servers. exports.servers = { - // A local test server. - alpha : { - 'trusted' : true, - // "peer_ip" : "0.0.0.0", - // "peer_port" : 51235, - 'rpc_ip' : "0.0.0.0", - 'rpc_port' : 5005, - 'websocket_ip' : "127.0.0.1", - 'websocket_port' : 6005, - 'validation_seed' : "shhDFVsmS2GSu5vUyZSPXYfj1r79h", - 'validators' : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta" - } + // A local test server. + 'alpha' : { + 'trusted' : true, + // "peer_ip" : "0.0.0.0", + // "peer_port" : 51235, + 'rpc_ip' : "0.0.0.0", + 'rpc_port' : 5005, + 'websocket_ip' : "127.0.0.1", + 'websocket_port' : 6005, + 'validation_seed' : "shhDFVsmS2GSu5vUyZSPXYfj1r79h", + 'validators' : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta" + } }; -// vim:ts=4 + +// Configuration for test accounts. +exports.accounts = { + // Users + 'alice' : { + 'account' : 'iG1QQv2nh2gi7RCZ1P8YYcBUKCCN633jCn', + 'passphrase' : 'alice', + }, + 'bob' : { + 'account' : 'iPMh7Pr9ct699rZUTWaytJUoHcJ7cgyzrK', + 'passphrase' : 'bob', + }, + 'carol' : { + 'account' : 'iH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW', + 'passphrase' : 'carol', + }, + + // Nexuses + 'bitstamp' : { + 'account' : 'i4jKmc2nQb5yEU6eycefrNKGHTU5NQJASx', + 'passphrase' : 'bitstamp', + }, + 'mtgox' : { + 'account' : 'iGrhwhaqU8g7ahwAvTq6rX5ivsfcbgZw6v', + 'passphrase' : 'mtgox', + }, + + // Merchants + 'amazon' : { + 'account' : 'ihheXqX7bDnXePJeMHhubDDvw2uUTtenPd', + 'passphrase' : 'amazon', + }, + + // Master account + 'root' : { + 'account' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh', + 'passphrase' : 'masterpassphrase', + }, +}; + +// vim:sw=2:sts=2:ts=8 diff --git a/test/standalone-test.js b/test/standalone-test.js index 6a18592a42..600e0a9df6 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -11,178 +11,179 @@ var serverDelay = 1500; buster.testRunner.timeout = 5000; buster.testCase("Standalone server startup", { - "server start and stop": function(done) { - server.start("alpha", - function(e) { - buster.refute(e); - server.stop("alpha", function(e) { - buster.refute(e); - done(); - }); - }); - } + "server start and stop": function (done) { + server.start("alpha", + function (e) { + buster.refute(e); + server.stop("alpha", function (e) { + buster.refute(e); + done(); + }); + }); + } }); buster.testCase("WebSocket connection", { - 'setUp' : - function(done) { - server.start("alpha", - function(e) { - buster.refute(e); - done(); - } - ); - }, + 'setUp' : + function (done) { + server.start("alpha", + function (e) { + buster.refute(e); + done(); + } + ); + }, - 'tearDown' : - function(done) { - server.stop("alpha", function(e) { - buster.refute(e); - done(); - }); - }, + 'tearDown' : + function (done) { + server.stop("alpha", function (e) { + buster.refute(e); + done(); + }); + }, - "websocket connect and disconnect" : - function(done) { - var alpha = remote.remoteConfig(config, "alpha"); + "websocket connect and disconnect" : + function (done) { + var alpha = remote.remoteConfig(config, "alpha"); - alpha.connect(function(stat) { - buster.assert(1 == stat); // OPEN + alpha.connect(function (stat) { + buster.assert(1 == stat); // OPEN - alpha.disconnect(function(stat) { - buster.assert(3 == stat); // CLOSED - done(); - }); - }, serverDelay); - }, + alpha.disconnect(function (stat) { + buster.assert(3 == stat); // CLOSED + done(); + }); + }, serverDelay); + }, }); buster.testCase("Websocket commands", { - 'setUp' : - function(done) { - server.start("alpha", - function(e) { - buster.refute(e); + 'setUp' : + function (done) { + server.start("alpha", + function (e) { + buster.refute(e); - alpha = remote.remoteConfig(config, "alpha"); + alpha = remote.remoteConfig(config, "alpha"); - alpha.connect(function(stat) { - buster.assert(1 == stat); // OPEN + alpha.connect(function (stat) { + buster.assert(1 == stat); // OPEN + done(); + }, serverDelay); + }); + }, - done(); - }, serverDelay); - }); - }, + 'tearDown' : + function (done) { + alpha.disconnect(function (stat) { + buster.assert(3 == stat); // CLOSED - 'tearDown' : - function(done) { - alpha.disconnect(function(stat) { - buster.assert(3 == stat); // CLOSED + server.stop("alpha", function (e) { + buster.refute(e); + done(); + }); + }); + }, - server.stop("alpha", function(e) { - buster.refute(e); + 'ledger_current' : + function (done) { + alpha.request_ledger_current(function (r) { + console.log(r); - done(); - }); - }); - }, + buster.assert.equals(r.ledger_current_index, 3); + done(); + }); + }, - 'ledger_current' : - function(done) { - alpha.ledger_current(function (r) { - console.log(r); + '// ledger_closed' : + function (done) { + alpha.request_ledger_closed(function (r) { + console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 3); - done(); - }); - }, + buster.assert.equals(r.ledger_closed_index, 2); + done(); + }); + }, - '// ledger_closed' : - function(done) { - alpha.ledger_closed(function (r) { - console.log("result: %s", JSON.stringify(r)); + 'account_root success' : + function (done) { + alpha.request_ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 2); - done(); - }); - }, + buster.refute(r.error); - 'account_root success' : - function(done) { - alpha.ledger_closed(function (r) { - // console.log("result: %s", JSON.stringify(r)); + alpha.request_ledger_entry({ + 'ledger_closed' : r.ledger_closed, + 'type' : 'account_root', + 'account_root' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); - buster.refute('error' in r); + buster.assert('node' in r); + done(); + }); + }); + }, - alpha.ledger_entry({ - 'ledger_index' : r.ledger_index, - 'account_root' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh' - } , function (r) { - // console.log("account_root: %s", JSON.stringify(r)); + 'account_root malformedAddress' : + function (done) { + alpha.request_ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); - buster.assert('node' in r); - done(); - }); - }); - }, + buster.refute(r.error); - 'account_root malformedAddress' : - function(done) { - alpha.ledger_closed(function (r) { - // console.log("result: %s", JSON.stringify(r)); + alpha.request_ledger_entry({ + 'ledger_closed' : r.ledger_closed, + 'type' : 'account_root', + 'account_root' : 'foobar' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); - buster.refute('error' in r); + buster.assert.equals(r.error, 'malformedAddress'); + done(); + }); + }); + }, - alpha.ledger_entry({ - 'ledger_index' : r.ledger_index, - 'account_root' : 'foobar' - } , function (r) { - // console.log("account_root: %s", JSON.stringify(r)); + 'account_root entryNotFound' : + function (done) { + alpha.request_ledger_closed(function (r) { + console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.error, 'malformedAddress'); - done(); - }); - }); - }, + buster.refute(r.error); - 'account_root entryNotFound' : - function(done) { - alpha.ledger_closed(function (r) { - // console.log("result: %s", JSON.stringify(r)); + alpha.request_ledger_entry({ + 'ledger_closed' : r.ledger_closed, + 'type' : 'account_root', + 'account_root' : 'iG1QQv2nh2gi7RCZ1P8YYcBUKCCN633jCn' + }, function (r) { + console.log("account_root: %s", JSON.stringify(r)); - buster.refute('error' in r); + buster.assert.equals(r.error, 'entryNotFound'); + done(); + }); + }); + }, - alpha.ledger_entry({ - 'ledger_index' : r.ledger_index, - 'account_root' : 'iG1QQv2nh2gi7RCZ1P8YYcBUKCCN633jCn' - } , function (r) { - // console.log("account_root: %s", JSON.stringify(r)); + 'ledger_entry index' : + function (done) { + alpha.request_ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.error, 'entryNotFound'); - done(); - }); - }); - }, + buster.refute(r.error); - 'ledger_entry index' : - function(done) { - alpha.ledger_closed(function (r) { - // console.log("result: %s", JSON.stringify(r)); - - buster.refute('error' in r); - - alpha.ledger_entry({ - 'ledger_index' : r.ledger_index, - 'index' : "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8", - } , function (r) { - console.log("node: %s", JSON.stringify(r)); - - buster.assert('node_binary' in r); - done(); - }); - }); - }, + alpha.request_ledger_entry({ + 'ledger_closed' : r.ledger_closed, + 'type' : 'account_root', + 'index' : "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8", + } , function (r) { + console.log("node: %s", JSON.stringify(r)); + buster.assert('node_binary' in r); + done(); + }); + }); + }, }); -// vim:ts=4 +// vim:sw=2:sts=2:ts=8