From 0d7710dbe085a3dbfcf3a680feb37e4ec4d80039 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 8 Oct 2012 15:55:47 -0700 Subject: [PATCH 1/8] Document the log levels. We need to move things from INFO to DEBUG. --- src/Log.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Log.h b/src/Log.h index a71d07ee9c..10c18fd0eb 100644 --- a/src/Log.h +++ b/src/Log.h @@ -28,12 +28,12 @@ enum LogSeverity { - lsTRACE = 0, - lsDEBUG = 1, - lsINFO = 2, - lsWARNING = 3, - lsERROR = 4, - lsFATAL = 5 + lsTRACE = 0, // Very low-level progress information, details inside an operation + lsDEBUG = 1, // Function-level progress information, operations + lsINFO = 2, // Server-level progress information, major operations + lsWARNING = 3, // Conditions that warrant human attention, may indicate a problem + lsERROR = 4, // A condition that indicates a problem + lsFATAL = 5 // A severe condition that indicates a server problem }; class LogPartition From 9ea500a2ab82fb2c905cee796f5aa003e1c8282c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 8 Oct 2012 16:15:25 -0700 Subject: [PATCH 2/8] JS: Initial check in of Amount. --- js/amount.js | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++ js/utils.js | 23 +++++- 2 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 js/amount.js diff --git a/js/amount.js b/js/amount.js new file mode 100644 index 0000000000..87bfdce74a --- /dev/null +++ b/js/amount.js @@ -0,0 +1,211 @@ +// Represent Newcoin amounts and currencies. + + +var utils = require("./utils.js"); + +var UInt160 = function () { + // Internal form: + // 0, 1, 'iXXXXX', 20 byte string, or NaN. + // XXX Should standardize on 'i' format or 20 format. +}; + +// Returns NaN on error. +UInt160.method('parse_json', function (j) { + // Canonicalize and validate + + switch (j) { + case undefined: + case "0": + case exports.consts.address_xns: + case exports.consts.uint160_xns: + case exports.consts.hex_xns: + this.value = 0; + break; + + case "1": + case exports.consts.address_one: + case exports.consts.uint160_one: + case exports.consts.hex_one: + this.value = 1; + break; + + default: + if ('string' !== typeof j) { + this.value = NaN; + } + else if (20 === j.length) { + this.value = j; + } + else if (40 === j.length) { + this.value = utils.hexToString(j); + } + else if (j[0] === "i") { + // XXX Do more checking convert to string. + + this.value = j; + } + else { + this.value = NaN; + } + } + + return this.value; +}); + +// Convert from internal form. +// XXX Json form should allow 0 and 1, C++ doesn't currently allow it. +UInt160.method('to_json', function () { + if ("0" === this.value) { + return exports.consts.hex_xns; + } + else if ("1" === this.value) + { + return exports.consts.hex_one; + } + else if (20 === this.value.length) { + return utils.stringToHex(this.value); + } + else + { + return this.value; + } +}); + +var Currency = function () { + // Internal form: 0 = XNS. 3 letter-code. + // XXX Internal should be 0 or hex. + + // Json form: + // '', 'XNS', '0': 0 + // 3-letter code: ... + // XXX Should support hex, C++ doesn't currently allow it. +} + +// Returns NaN on error. +Currency.method('parse_json', function (j) { + if ("" === j || "0" === j || "XNS" === j) { + this.value = 0; + } + else if ('string' != typeof j || 3 !== j.length) { + this.value = NaN; + } + else { + this.value = j; + } + + return this.value; +}); + +Currency.method('to_json', function () { + return this.value ? this.value : 'XNS'; +}); + +Currency.method('to_human', function() { + return this.value ? this.value : 'XNS'; +}); + +var Amount = function () { + // Json format: + // integer : XNS + // { 'value' : ..., 'currency' : ..., 'issuer' : ...} + + this.value = 0; + this.offset = 0; + this.is_native = false; + this.is_negative = false; + + this.currency = new Currency(); + this.issuer = new UInt160(); + +} + +// Convert only value to JSON text. +Amount.method('to_text', function() { + // XXX Needs to work for native and non-native. + return this.is_negative ? -this.value : this.value; // XXX Use biginteger. +}); + +Amount.method('to_json', function() { + if (this.is_native) { + return this.to_text(); + } + else + { + return { + 'value' : this.to_text(), + 'currency' : this.currency.to_json(), + 'issuer' : this.issuer.to_json(), + }; + } +}); + +// Parse a native value. +Amount.method('parse_native', function() { + if ('integer' === typeof j) { + // XNS + this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.offset = 0; + this.is_native = true; + this.is_negative = x < 0; + } + else if ('string' === typeof j) { + this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.offset = 0; + this.is_native = true; + this.is_negative = x < 0; + } + else { + this.value = NaN; + } +}); + +// Parse a non-native value. +Amount.method('parse_value', function() { + if ('integer' === typeof j) { + this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.offset = 0; + this.is_native = false; + this.is_negative = x < 0; + } + else if ('string' === typeof j) { + this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.offset = 0; + this.is_native = false; + this.is_negative = x < 0; + } + else { + this.value = NaN; + } +}); + +// <-> j +Amount.method('parse_json', function(j) { + if ('object' === typeof j && j.currency) { + + this.parse_value(j); + this.currency.parse_json(j.currency); + this.issuer.parse_json(j.issuer); + } + else { + this.parse_native(j); + this.currency = 0; + this.issuer = 0; + } +}); + +exports.UInt160 = UInt160; +exports.Currency = Currency; +exports.Amount = Amount; + +exports.consts = { + 'address_xns' : "iiiiiiiiiiiiiiiiiiiiihoLvTp", + 'address_one' : "iiiiiiiiiiiiiiiiiiiiBZbvjr", + 'currency_xns' : 0, + 'currency_one' : 1, + 'uint160_xns' : hexToString("0000000000000000000000000000000000000000"), + 'uint160_one' : hexToString("0000000000000000000000000000000000000001"), + 'hex_xns' : "0000000000000000000000000000000000000000", + 'hex_one' : "0000000000000000000000000000000000000001", +}; + +// vim:sw=2:sts=2:ts=8 diff --git a/js/utils.js b/js/utils.js index 6bb4ae7a2d..511dacc436 100644 --- a/js/utils.js +++ b/js/utils.js @@ -127,11 +127,32 @@ var trace = function(comment, func) { }; }; +var hexToString = function (h) { + var c = h.length % 1 ? "0" + h : h; + var a = []; + + for (i=0; i != c.length; i += 2) { + a.push(String.fromCharCode(parseInt(c.substring(i, i+2), 16))); + } + + return a.join(""); +}; + +var stringToHex = function (s) { + return Array.prototype.map.call(s, function (c) { + var b = c.charCodeAt(0); + + return b < 16 ? "0" + b.toString(16) : b.toString(16); + }).join(""); +}; + exports.emptyPath = emptyPath; exports.mapOr = mapOr; exports.mkPath = mkPath; exports.resetPath = resetPath; exports.rmPath = rmPath; exports.trace = trace; +exports.hexToString = hexToString; +exports.stringToHex = stringToHex; -// vim:ts=4 +// vim:sw=2:sts=2:ts=8 From 2cc4bd5fed3b7639929a1ba14bd5807ef903ca4b Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 8 Oct 2012 16:58:47 -0700 Subject: [PATCH 3/8] JS: improve hexToString and add unit tests. --- js/utils.js | 11 ++++++++--- test/standalone-test.js | 26 ++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/js/utils.js b/js/utils.js index 511dacc436..a589ac391c 100644 --- a/js/utils.js +++ b/js/utils.js @@ -128,11 +128,16 @@ var trace = function(comment, func) { }; var hexToString = function (h) { - var c = h.length % 1 ? "0" + h : h; var a = []; + var i = 0; - for (i=0; i != c.length; i += 2) { - a.push(String.fromCharCode(parseInt(c.substring(i, i+2), 16))); + if (h.length % 2) { + a.push(String.fromCharCode(parseInt(h.substring(0, 1), 16))); + i = 1; + } + + for (; i != h.length; i += 2) { + a.push(String.fromCharCode(parseInt(h.substring(i, i+2), 16))); } return a.join(""); diff --git a/test/standalone-test.js b/test/standalone-test.js index 8dfe15e336..572b0d0b51 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -1,17 +1,35 @@ var fs = require("fs"); var buster = require("buster"); -var server = require("./server.js"); -var remote = require("../js/remote.js"); -var config = require("./config.js"); +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. 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 and stop" : function (done) { server.start("alpha", function (e) { buster.refute(e); From b7c2eb65f2f693bba55ae1740edfad7a0c0daaba Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 8 Oct 2012 17:27:00 -0700 Subject: [PATCH 4/8] Cosmetic. --- js/amount.js | 65 ++++++++++---------- js/remote.js | 60 +++++++++--------- js/utils.js | 170 +++++++++++++++++++++++++-------------------------- 3 files changed, 149 insertions(+), 146 deletions(-) diff --git a/js/amount.js b/js/amount.js index 87bfdce74a..ead5aa74db 100644 --- a/js/amount.js +++ b/js/amount.js @@ -10,7 +10,7 @@ var UInt160 = function () { }; // Returns NaN on error. -UInt160.method('parse_json', function (j) { +UInt160.prototype.parse_json = function (j) { // Canonicalize and validate switch (j) { @@ -50,11 +50,11 @@ UInt160.method('parse_json', function (j) { } return this.value; -}); +}; // Convert from internal form. // XXX Json form should allow 0 and 1, C++ doesn't currently allow it. -UInt160.method('to_json', function () { +UInt160.prototype.to_json = function () { if ("0" === this.value) { return exports.consts.hex_xns; } @@ -69,7 +69,7 @@ UInt160.method('to_json', function () { { return this.value; } -}); +}; var Currency = function () { // Internal form: 0 = XNS. 3 letter-code. @@ -82,7 +82,7 @@ var Currency = function () { } // Returns NaN on error. -Currency.method('parse_json', function (j) { +Currency.prototype.parse_json = function (j) { if ("" === j || "0" === j || "XNS" === j) { this.value = 0; } @@ -94,15 +94,15 @@ Currency.method('parse_json', function (j) { } return this.value; -}); +}; -Currency.method('to_json', function () { +Currency.prototype.to_json = function () { return this.value ? this.value : 'XNS'; -}); +}; -Currency.method('to_human', function() { +Currency.prototype.to_human = function() { return this.value ? this.value : 'XNS'; -}); +}; var Amount = function () { // Json format: @@ -116,16 +116,15 @@ var Amount = function () { this.currency = new Currency(); this.issuer = new UInt160(); - -} +}; // Convert only value to JSON text. -Amount.method('to_text', function() { +Amount.prototype.to_text = function() { // XXX Needs to work for native and non-native. return this.is_negative ? -this.value : this.value; // XXX Use biginteger. -}); +}; -Amount.method('to_json', function() { +Amount.prototype.to_json = function() { if (this.is_native) { return this.to_text(); } @@ -137,49 +136,49 @@ Amount.method('to_json', function() { 'issuer' : this.issuer.to_json(), }; } -}); +}; // Parse a native value. -Amount.method('parse_native', function() { +Amount.prototype.parse_native = function(j) { if ('integer' === typeof j) { // XNS - this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.value = j >= 0 ? j : -j; // XXX Use biginteger. this.offset = 0; this.is_native = true; - this.is_negative = x < 0; + this.is_negative = j < 0; } else if ('string' === typeof j) { - this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.value = j >= 0 ? j : -j; // XXX Use biginteger. this.offset = 0; this.is_native = true; - this.is_negative = x < 0; + this.is_negative = j < 0; } else { this.value = NaN; } -}); +}; // Parse a non-native value. -Amount.method('parse_value', function() { +Amount.prototype.parse_value = function(j) { if ('integer' === typeof j) { - this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.value = j >= 0 ? j : -j; // XXX Use biginteger. this.offset = 0; this.is_native = false; - this.is_negative = x < 0; + this.is_negative = j < 0; } else if ('string' === typeof j) { - this.value = x >= 0 ? j : -j; // XXX Use biginteger. + this.value = j >= 0 ? j : -j; // XXX Use biginteger. this.offset = 0; this.is_native = false; - this.is_negative = x < 0; + this.is_negative = j < 0; } else { this.value = NaN; } -}); +}; // <-> j -Amount.method('parse_json', function(j) { +Amount.prototype.parse_json = function(j) { if ('object' === typeof j && j.currency) { this.parse_value(j); @@ -191,13 +190,13 @@ Amount.method('parse_json', function(j) { this.currency = 0; this.issuer = 0; } -}); +}; -exports.UInt160 = UInt160; +exports.Amount = Amount; exports.Currency = Currency; -exports.Amount = Amount; +exports.UInt160 = UInt160; -exports.consts = { +exports.consts = { 'address_xns' : "iiiiiiiiiiiiiiiiiiiiihoLvTp", 'address_one' : "iiiiiiiiiiiiiiiiiiiiBZbvjr", 'currency_xns' : 0, diff --git a/js/remote.js b/js/remote.js index 069b1c0753..8919d6308a 100644 --- a/js/remote.js +++ b/js/remote.js @@ -63,7 +63,7 @@ var fees = { 'offer' : 100, }; -Remote.method('connect_helper', function () { +Remote.prototype.connect_helper = function () { var self = this; if (this.trace) console.log("remote: connect: %s", this.url); @@ -88,11 +88,13 @@ Remote.method('connect_helper', function () { 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. } @@ -101,6 +103,7 @@ Remote.method('connect_helper', function () { // Covers failure to open. ws.onclose = function () { if (this.trace) console.log("remote: onclose: %s", ws.readyState); + ws.onerror = undefined; self.done(ws.readyState); }; @@ -112,6 +115,7 @@ Remote.method('connect_helper', function () { if (message.type !== 'response') { console.log("unexpected message: %s", json); + } else { var done = ws.response[message.id]; if (done) { @@ -121,12 +125,12 @@ Remote.method('connect_helper', function () { } } }); -}); +}; // Target state is connectted. // done(readyState): // --> readyState: OPEN, CLOSED -Remote.method('connect', function (done, timeout) { +Remote.prototype.connect = function (done, timeout) { var self = this; this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); @@ -147,10 +151,10 @@ Remote.method('connect', function (done, timeout) { } this.connect_helper(); -}); +}; // Target stated is disconnected. -Remote.method('disconnect', function (done) { +Remote.prototype.disconnect = function (done) { var self = this; var ws = this.ws; @@ -160,11 +164,11 @@ Remote.method('disconnect', function (done) { }; ws.close(); -}); +}; // Send a request. The request should lack the id. // <-> request: what to send, consumed. -Remote.method('request', function (request, onDone, onFailure) { +Remote.prototype.request = function (request, onDone, onFailure) { var self = this; this.id += 1; // Advance id. @@ -187,24 +191,24 @@ Remote.method('request', function (request, onDone, onFailure) { if (this.trace) console.log("remote: request: %s", JSON.stringify(request)); this.ws.send(JSON.stringify(request)); -}); +}; -Remote.method('request_ledger_closed', function (onDone, onFailure) { +Remote.prototype.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('request_ledger_current', function (onDone, onFailure) { +Remote.prototype.request_ledger_current = function (onDone, onFailure) { this.request({ 'command' : 'ledger_current' }, onDone, onFailure); -}); +}; // <-> request: // --> ledger : optional // --> ledger_index : optional // --> type -Remote.method('request_ledger_entry', function (req, onDone, onFailure) { +Remote.prototype.request_ledger_entry = function (req, onDone, onFailure) { var self = this; assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. @@ -264,12 +268,12 @@ Remote.method('request_ledger_entry', function (req, onDone, onFailure) { }, onFailure); } } -}); +}; // Submit a json transaction. // done(value) // XXX <-> value: { 'status', status, 'result' : result, ... } -Remote.method('submit', function (req, onDone, onFailure) { +Remote.prototype.submit = function (req, onDone, onFailure) { if (this.trace) console.log("remote: submit: %s", JSON.stringify(req)); req.command = 'submit'; @@ -282,7 +286,7 @@ Remote.method('submit', function (req, onDone, onFailure) { { this.request(req, onDone, onFailure); } -}); +}; // // Higher level functions. @@ -290,7 +294,7 @@ Remote.method('submit', function (req, onDone, onFailure) { // 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) { +Remote.prototype.server_subscribe = function (onDone, onFailure) { var self = this; this.request( @@ -303,11 +307,11 @@ Remote.method('server_subscribe', function (onDone, onFailure) { }, onFailure ); -}); +}; // Refresh accounts[account].seq // done(result); -Remote.method('account_seq', function (account, advance, onDone, onFailure) { +Remote.prototype.account_seq = function (account, advance, onDone, onFailure) { var self = this; var account_root_entry = this.accounts[account]; @@ -341,10 +345,10 @@ Remote.method('account_seq', function (account, advance, onDone, onFailure) { onFailure ); } -}); +}; // A submit that fills in the sequence number. -Remote.method('submit_seq', function (trans, onDirty, onDone, onFailure) { +Remote.prototype.submit_seq = function (trans, onDirty, onDone, onFailure) { var self = this; // Get the next sequence number for the account. @@ -354,18 +358,18 @@ Remote.method('submit_seq', function (trans, onDirty, onDone, onFailure) { self.submit(trans, onDone, onFailure); }, onFailure); -}); +}; // Mark an account's root node as dirty. -Remote.method('dirty_account_root', function (account) { +Remote.prototype.dirty_account_root = function (account) { delete this.ledgers.current.account_root.account; -}); +}; // // Transactions // -Remote.method('ripple_line_set', function (secret, src, dst, amount, onDone) { +Remote.prototype.ripple_line_set = function (secret, src, dst, amount, onDone) { var secret = this.config.accounts[src] ? this.config.accounts[src].secret : secret; var src_account = this.config.accounts[src] ? this.config.accounts[src].account : src; var dst_account = this.config.accounts[dst] ? this.config.accounts[dst].account : dst; @@ -382,9 +386,9 @@ Remote.method('ripple_line_set', function (secret, src, dst, amount, onDone) { 'secret' : secret, }, function () { }, onDone); -}); +}; -Remote.method('send_xns', function (secret, src, dst, amount, create, onDone) { +Remote.prototype.send_xns = function (secret, src, dst, amount, create, onDone) { var secret = this.config.accounts[src] ? this.config.accounts[src].secret : secret; var src_account = this.config.accounts[src] ? this.config.accounts[src].account : src; var dst_account = this.config.accounts[dst] ? this.config.accounts[dst].account : dst; @@ -402,7 +406,7 @@ Remote.method('send_xns', function (secret, src, dst, amount, create, onDone) { 'secret' : secret, }, function () { }, onDone); -}); +}; exports.Remote = Remote; exports.remoteConfig = remoteConfig; diff --git a/js/utils.js b/js/utils.js index a589ac391c..950da3e416 100644 --- a/js/utils.js +++ b/js/utils.js @@ -4,127 +4,127 @@ var fs = require("fs"); var path = require("path"); Function.prototype.method = function(name,func) { - this.prototype[name] = func; + this.prototype[name] = func; - return this; + return this; }; var filterErr = function(code, done) { - return function(e) { - done(e.code !== code ? e : undefined); - }; + return function(e) { + done(e.code !== code ? e : undefined); + }; }; var throwErr = function(done) { - return function(e) { - if (e) - throw e; - - done(); - }; + return function(e) { + if (e) + throw e; + + done(); + }; }; // apply function to elements of array. Return first true value to done or undefined. var mapOr = function(func, array, done) { - if (array.length) { - func(array[array.length-1], function(v) { - if (v) { - done(v); - } - else { - array.length -= 1; - mapOr(func, array, done); - } - }); - } - else { - done(); - } + if (array.length) { + func(array[array.length-1], function(v) { + if (v) { + done(v); + } + else { + array.length -= 1; + mapOr(func, array, done); + } + }); + } + else { + done(); + } }; // Make a directory and sub-directories. var mkPath = function(dirPath, mode, done) { - fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function(e) { - if (!e || e.code === "EEXIST") { - // Created or already exists, done. - done(); - } - else if (e.code === "ENOENT") { - // Missing sub dir. + fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function(e) { + if (!e || e.code === "EEXIST") { + // Created or already exists, done. + done(); + } + else if (e.code === "ENOENT") { + // Missing sub dir. - mkPath(path.dirname(dirPath), mode, function(e) { - if (e) { - throw e; - } - else { - mkPath(dirPath, mode, done); - } - }); + mkPath(path.dirname(dirPath), mode, function(e) { + if (e) { + throw e; } else { - throw e; + mkPath(dirPath, mode, done); } - }); + }); + } + else { + throw e; + } + }); }; // Empty a directory. var emptyPath = function(dirPath, done) { - fs.readdir(dirPath, function(err, files) { - if (err) { - done(err); - } - else { - mapOr(rmPath, files.map(function(f) { return path.join(dirPath, f); }), done); - } - }); + fs.readdir(dirPath, function(err, files) { + if (err) { + done(err); + } + else { + mapOr(rmPath, files.map(function(f) { return path.join(dirPath, f); }), done); + } + }); }; // Remove path recursively. var rmPath = function(dirPath, done) { // console.log("rmPath: %s", dirPath); - fs.lstat(dirPath, function(err, stats) { - if (err && err.code == "ENOENT") { - done(); - } - if (err) { - done(err); - } - else if (stats.isDirectory()) { - emptyPath(dirPath, function(e) { - if (e) { - done(e); - } - else { -// console.log("rmdir: %s", dirPath); done(); - fs.rmdir(dirPath, done); - } - }); - } - else { -// console.log("unlink: %s", dirPath); done(); - fs.unlink(dirPath, done); - } - }); + fs.lstat(dirPath, function(err, stats) { + if (err && err.code == "ENOENT") { + done(); + } + if (err) { + done(err); + } + else if (stats.isDirectory()) { + emptyPath(dirPath, function(e) { + if (e) { + done(e); + } + else { +// console.log("rmdir: %s", dirPath); done(); + fs.rmdir(dirPath, done); + } + }); + } + else { +// console.log("unlink: %s", dirPath); done(); + fs.unlink(dirPath, done); + } + }); }; // Create directory if needed and empty if needed. var resetPath = function(dirPath, mode, done) { - mkPath(dirPath, mode, function(e) { - if (e) { - done(e); - } - else { - emptyPath(dirPath, done); - } - }); + mkPath(dirPath, mode, function(e) { + if (e) { + done(e); + } + else { + emptyPath(dirPath, done); + } + }); }; var trace = function(comment, func) { - return function() { - console.log("%s: %s", trace, arguments.toString); - func(arguments); - }; + return function() { + console.log("%s: %s", trace, arguments.toString); + func(arguments); + }; }; var hexToString = function (h) { From 108d69d29b6aaf94a97c99b83d8399baba6c8671 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 8 Oct 2012 18:16:48 -0700 Subject: [PATCH 5/8] Remove dead fields. --- src/SerializeProto.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/SerializeProto.h b/src/SerializeProto.h index 23a2260bb7..736a83a3e8 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -30,7 +30,6 @@ FIELD(TransactionType, UINT16, 2) // 32-bit integers (common) - FIELD(ObjectType, UINT32, 1) FIELD(Flags, UINT32, 2) FIELD(SourceTag, UINT32, 3) FIELD(Sequence, UINT32, 4) @@ -91,7 +90,7 @@ FIELD(Fee, AMOUNT, 8) FIELD(SendMax, AMOUNT, 9) - // current amount (uncommon) + // currency amount (uncommon) FIELD(MinimumOffer, AMOUNT, 16) FIELD(RippleEscrow, AMOUNT, 17) @@ -113,8 +112,6 @@ FIELD(Owner, ACCOUNT, 2) FIELD(Destination, ACCOUNT, 3) FIELD(Issuer, ACCOUNT, 4) - FIELD(HighID, ACCOUNT, 5) - FIELD(LowID, ACCOUNT, 6) FIELD(Target, ACCOUNT, 7) FIELD(AuthorizedKey, ACCOUNT, 8) From 6f2e4b81726065f7950c42de6f0d3207801823d3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 8 Oct 2012 20:02:52 -0700 Subject: [PATCH 6/8] Add RPC "accept_ledger" function which processes all pending transactions (in standalone mode only) and closes the ledger, opening a new one. The sequence number of the new open ledger is returned. --- src/Application.cpp | 1 - src/LedgerConsensus.cpp | 32 ++++++++++++++++++++++++-------- src/LedgerConsensus.h | 5 ++++- src/LedgerMaster.h | 2 -- src/NetworkOPs.cpp | 16 +++++++++++----- src/NetworkOPs.h | 1 + src/RPCServer.cpp | 12 ++++++++++++ src/RPCServer.h | 2 ++ 8 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 2011ca8e78..b9483a37b8 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -162,7 +162,6 @@ void Application::run() { Log(lsWARNING) << "Running in standalone mode"; mNetOps.setStandAlone(); - mMasterLedger.runStandAlone(); } else mNetOps.setStateTimer(); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index bccbd76d14..a07965ae6b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -527,15 +527,20 @@ void LedgerConsensus::statePreClose() } if (ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, - mPreviousMSeconds, sinceClose, idleInterval)) - { // it is time to close the ledger + mPreviousMSeconds, sinceClose, idleInterval)) + { + closeLedger(); + } +} + +void LedgerConsensus::closeLedger() +{ mState = lcsESTABLISH; mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); mCloseTime = theApp->getOPs().getCloseTimeNC(); theApp->getOPs().setLastCloseTime(mCloseTime); statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); takeInitialPosition(*theApp->getMasterLedger().closeLedger()); - } } void LedgerConsensus::stateEstablish() @@ -551,7 +556,7 @@ void LedgerConsensus::stateEstablish() { cLog(lsINFO) << "Converge cutoff (" << mPeerPositions.size() << " participants)"; mState = lcsFINISHED; - beginAccept(); + beginAccept(false); } } @@ -929,7 +934,7 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, return set->takeNodes(nodeIDs, nodeData, peer); } -void LedgerConsensus::beginAccept() +void LedgerConsensus::beginAccept(bool synchronous) { SHAMap::pointer consensusSet = mAcquired[mOurPosition->getCurrentHash()]; if (!consensusSet) @@ -940,7 +945,10 @@ void LedgerConsensus::beginAccept() } theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); - theApp->getIOService().post(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet)); + if (synchronous) + accept(consensusSet); + else + theApp->getIOService().post(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet)); } void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::pointer txSet) @@ -1173,7 +1181,6 @@ void LedgerConsensus::accept(SHAMap::ref set) theApp->getOPs().closeTimeOffset(offset); } -#ifdef DEBUG if (sLog(lsTRACE)) { Log(lsTRACE) << "newLCL"; @@ -1181,7 +1188,6 @@ void LedgerConsensus::accept(SHAMap::ref set) newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); Log(lsTRACE) << p; } -#endif } void LedgerConsensus::endConsensus() @@ -1189,6 +1195,16 @@ void LedgerConsensus::endConsensus() theApp->getOPs().endConsensus(mHaveCorrectLCL); } +void LedgerConsensus::simulate() +{ + cLog(lsINFO) << "Simulating consensus"; + closeLedger(); + mCurrentMSeconds = 100; + beginAccept(true); + endConsensus(); + cLog(lsINFO) << "Simulation complete"; +} + Json::Value LedgerConsensus::getJson() { Json::Value ret(Json::objectValue); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 44b4db409f..6e5d81a552 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -148,8 +148,9 @@ protected: void updateOurPositions(); void playbackProposals(); int getThreshold(); + void closeLedger(); - void beginAccept(); + void beginAccept(bool synchronous); void endConsensus(); public: @@ -189,6 +190,8 @@ public: void swapDefer(boost::unordered_map< uint160, std::list > &n) { mDeferredProposals.swap(n); } + // test/debug + void simulate(); }; diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 76e6327381..2f198b8847 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -43,8 +43,6 @@ public: // The finalized ledger is the last closed/accepted ledger Ledger::pointer getClosedLedger() { return mFinalizedLedger; } - void runStandAlone() { mFinalizedLedger = mCurrentLedger; } - TER doTransaction(const SerializedTransaction& txn, TransactionEngineParams params); void pushLedger(Ledger::ref newLedger); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index b2b128cd15..32b9651d23 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -443,7 +443,7 @@ 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 (theApp->getOPs().getNetworkTimeNC() < theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC()) + if (theApp->getOPs().getNetworkTimeNC() < mLedgerMaster->getCurrentLedger()->getCloseTimeNC()) setMode(omFULL); } @@ -454,7 +454,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result) } if ((!mConsensus) && (mMode != omDISCONNECTED)) - beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger()); + beginConsensus(networkClosed, mLedgerMaster->getCurrentLedger()); if (mConsensus) mConsensus->timerEntry(); } @@ -650,7 +650,7 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo assert(!mConsensus); prevLedger->setImmutable(); mConsensus = boost::make_shared( - networkClosed, prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC()); + networkClosed, prevLedger, mLedgerMaster->getCurrentLedger()->getCloseTimeNC()); mConsensus->swapDefer(mDeferredProposals); cLog(lsDEBUG) << "Initiating consensus engine"; @@ -670,7 +670,7 @@ bool NetworkOPs::haveConsensusObject() if (!ledgerChange) { cLog(lsWARNING) << "Beginning consensus due to peer action"; - beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger()); + beginConsensus(networkClosed, mLedgerMaster->getCurrentLedger()); } return mConsensus; } @@ -770,7 +770,7 @@ void NetworkOPs::mapComplete(const uint256& hash, SHAMap::ref map) void NetworkOPs::endConsensus(bool correctLCL) { - uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash(); + uint256 deadLedger = mLedgerMaster->getClosedLedger()->getParentHash(); std::vector peerList = theApp->getConnectionPool().getPeerVector(); BOOST_FOREACH(Peer::ref it, peerList) if (it && (it->getClosedLedgerHash() == deadLedger)) @@ -1222,6 +1222,12 @@ void NetworkOPs::newLCL(int proposers, int convergeTime, const uint256& ledgerHa mLastCloseHash = ledgerHash; } +uint32 NetworkOPs::acceptLedger() +{ // accept the current transaction tree, return the new ledger's sequence + beginConsensus(mLedgerMaster->getClosedLedger()->getHash(), mLedgerMaster->getCurrentLedger()); + mConsensus->simulate(); + return mLedgerMaster->getCurrentLedger()->getLedgerSeq(); +} #if 0 void NetworkOPs::subAccountChanges(InfoSub* ispListener, const uint256 uLedgerHash) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 4c64374f17..8f4d3557d1 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -190,6 +190,7 @@ public: uint32 getLastCloseTime() { return mLastCloseTime; } void setLastCloseTime(uint32 t) { mLastCloseTime = t; } Json::Value getServerInfo(); + uint32 acceptLedger(); // client information retrieval functions std::vector< std::pair > diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 9aa51033c6..6d669e03f1 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -70,6 +70,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." }, { rpcNO_NETWORK, "noNetwork", "Network not available." }, { rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." }, + { rpcNOT_STANDALONE, "notStandAlone", "Operation valid in debug mode only." }, { rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." }, { rpcPAYS_ACT_MALFORMED, "paysActMalformed", "Pays account malformed." }, { rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed." }, @@ -419,6 +420,16 @@ Json::Value RPCServer::accountFromString(const uint256& uLedger, NewcoinAddress& return Json::Value(Json::objectValue); } +Json::Value RPCServer::doAcceptLedger(const Json::Value ¶ms) +{ + if (!theConfig.RUN_STANDALONE) + return RPCError(rpcNOT_STANDALONE); + + Json::Value obj(Json::objectValue); + obj["newLedger"] = theApp->getOPs().acceptLedger(); + return obj; +} + // account_domain_set [] Json::Value RPCServer::doAccountDomainSet(const Json::Value ¶ms) { @@ -2641,6 +2652,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params bool mAdminRequired; unsigned int iOptions; } commandsA[] = { + { "accept_ledger", &RPCServer::doAcceptLedger, 0, 0, true }, { "account_domain_set", &RPCServer::doAccountDomainSet, 2, 3, false, optCurrent }, { "account_email_set", &RPCServer::doAccountEmailSet, 2, 3, false, optCurrent }, { "account_info", &RPCServer::doAccountInfo, 1, 2, false, optCurrent }, diff --git a/src/RPCServer.h b/src/RPCServer.h index d203cbc3ca..ce859c8431 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -23,6 +23,7 @@ public: // Misc failure rpcLOAD_FAILED, rpcNO_PERMISSION, + rpcNOT_STANDALONE, // Networking rpcNO_CLOSED, @@ -128,6 +129,7 @@ private: Json::Value accountFromString(const uint256& uLedger, NewcoinAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex); + Json::Value doAcceptLedger(const Json::Value ¶ms); Json::Value doAccountDomainSet(const Json::Value ¶ms); Json::Value doAccountEmailSet(const Json::Value ¶ms); Json::Value doAccountInfo(const Json::Value& params); From 573865cb23f42b3be576e255aeb39ceeeb3e5799 Mon Sep 17 00:00:00 2001 From: jed Date: Tue, 9 Oct 2012 03:01:32 -0700 Subject: [PATCH 7/8] allow you to load old ledger --- newcoind.cfg | 6 ++++ src/Application.cpp | 84 ++++++++++++++++++++++++++++++-------------- src/Application.h | 3 ++ src/Config.cpp | 1 + src/Config.h | 3 ++ src/Ledger.cpp | 11 +++--- src/Ledger.h | 6 ++-- src/LedgerMaster.cpp | 4 ++- src/NetworkOPs.cpp | 6 ++-- src/main.cpp | 5 +++ 10 files changed, 92 insertions(+), 37 deletions(-) diff --git a/newcoind.cfg b/newcoind.cfg index 689b276923..6a3e97437f 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -118,6 +118,12 @@ [rpc_allow_remote] 1 +[websocket_ip] +0.0.0.0 + +[websocket_port] +5006 + [debug_logfile] log/debug.log diff --git a/src/Application.cpp b/src/Application.cpp index 2011ca8e78..49bd4836dc 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -73,6 +73,7 @@ void Application::run() boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); auxThread.detach(); + if (!theConfig.RUN_STANDALONE) mSNTPClient.init(theConfig.SNTP_SERVERS); @@ -87,9 +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) + { + Log(lsINFO) << "Starting new Ledger"; + startNewLedger(); + }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 + startNewLedger(); + } + // // Begin validation and ip maintenance. - // - Wallet maintains local information: including identity and network connection persistency information. + // - Wallet maintains local information: including identity and network connection persistence information. // mWallet.start(); @@ -132,32 +148,8 @@ void Application::run() if (!theConfig.RUN_STANDALONE) mConnectionPool.start(); - // New stuff. - NewcoinAddress rootSeedMaster = NewcoinAddress::createSeedGeneric("masterpassphrase"); - NewcoinAddress rootGeneratorMaster = NewcoinAddress::createGeneratorPublic(rootSeedMaster); - NewcoinAddress rootAddress = NewcoinAddress::createAccountPublic(rootGeneratorMaster, 0); - - // Print enough information to be able to claim root account. - Log(lsINFO) << "Root master seed: " << rootSeedMaster.humanSeed(); - Log(lsINFO) << "Root account: " << rootAddress.humanAccountID(); - - { - Ledger::pointer firstLedger = boost::make_shared(rootAddress, SYSTEM_CURRENCY_START); - assert(!!firstLedger->getAccountState(rootAddress)); - firstLedger->updateHash(); - firstLedger->setClosed(); - firstLedger->setAccepted(); - mMasterLedger.pushLedger(firstLedger); - - Ledger::pointer secondLedger = boost::make_shared(true, boost::ref(*firstLedger)); - secondLedger->setClosed(); - secondLedger->setAccepted(); - mMasterLedger.pushLedger(secondLedger, boost::make_shared(true, boost::ref(*secondLedger))); - assert(!!secondLedger->getAccountState(rootAddress)); - mNetOps.setLastCloseTime(secondLedger->getCloseTimeNC()); - } - + if (theConfig.RUN_STANDALONE) { Log(lsWARNING) << "Running in standalone mode"; @@ -182,4 +174,44 @@ Application::~Application() delete mHashNodeDB; delete mNetNodeDB; } +void Application::startNewLedger() +{ + // New stuff. + NewcoinAddress rootSeedMaster = NewcoinAddress::createSeedGeneric("masterpassphrase"); + NewcoinAddress rootGeneratorMaster = NewcoinAddress::createGeneratorPublic(rootSeedMaster); + NewcoinAddress rootAddress = NewcoinAddress::createAccountPublic(rootGeneratorMaster, 0); + + // Print enough information to be able to claim root account. + Log(lsINFO) << "Root master seed: " << rootSeedMaster.humanSeed(); + Log(lsINFO) << "Root account: " << rootAddress.humanAccountID(); + + { + Ledger::pointer firstLedger = boost::make_shared(rootAddress, SYSTEM_CURRENCY_START); + assert(!!firstLedger->getAccountState(rootAddress)); + firstLedger->updateHash(); + firstLedger->setClosed(); + firstLedger->setAccepted(); + mMasterLedger.pushLedger(firstLedger); + + Ledger::pointer secondLedger = boost::make_shared(true, boost::ref(*firstLedger)); + secondLedger->setClosed(); + secondLedger->setAccepted(); + mMasterLedger.pushLedger(secondLedger, boost::make_shared(true, boost::ref(*secondLedger))); + assert(!!secondLedger->getAccountState(rootAddress)); + mNetOps.setLastCloseTime(secondLedger->getCloseTimeNC()); + } +} + +void Application::loadOldLedger() +{ + Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;",true); + + if(!lastLedger) + { + std::cout << "No Ledger found?" << std::endl; + exit(-1); + } + mMasterLedger.pushLedger(lastLedger); + mNetOps.setLastCloseTime(lastLedger->getCloseTimeNC()); +} // vim:ts=4 diff --git a/src/Application.h b/src/Application.h index 8ab7f83ed2..9a37333fb2 100644 --- a/src/Application.h +++ b/src/Application.h @@ -67,6 +67,9 @@ class Application std::map mPeerMap; boost::recursive_mutex mPeerMapLock; + void startNewLedger(); + void loadOldLedger(); + public: Application(); ~Application(); diff --git a/src/Config.cpp b/src/Config.cpp index 4e4cb8e910..e4fb3f79ae 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -155,6 +155,7 @@ void Config::setup(const std::string& strConf) VALIDATORS_SITE = DEFAULT_VALIDATORS_SITE; RUN_STANDALONE = false; + START_UP = NORMAL; load(); } diff --git a/src/Config.h b/src/Config.h index 6fc42dca35..cc2b85ed4b 100644 --- a/src/Config.h +++ b/src/Config.h @@ -56,6 +56,9 @@ public: std::vector IPS; // Peer IPs from newcoind.cfg. std::vector SNTP_SERVERS; // SNTP servers from newcoind.cfg. + enum StartUpType {FRESH,NORMAL,LOAD}; + StartUpType START_UP; + // Network parameters int NETWORK_START_TIME; // The Unix time we start ledger 0. int TRANSACTION_FEE_BASE; diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 2f3c8cfdf1..015a51c303 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -37,11 +37,11 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s } Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, - uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq) + uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq,bool isMutable) : mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), mTotCoins(totCoins), mLedgerSeq(ledgerSeq), mCloseTime(closeTime), mParentCloseTime(parentCloseTime), mCloseResolution(closeResolution), mCloseFlags(closeFlags), - mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false) + mClosed(false), mValidHash(false), mAccepted(false), mImmutable(isMutable) { updateHash(); } @@ -390,7 +390,7 @@ void Ledger::saveAcceptedLedger(Ledger::ref ledger) theApp->getOPs().pubLedger(ledger); } -Ledger::pointer Ledger::getSQL(const std::string& sql) +Ledger::pointer Ledger::getSQL(const std::string& sql,bool isMutable) { uint256 ledgerHash, prevHash, accountHash, transHash; uint64 totCoins; @@ -423,9 +423,8 @@ Ledger::pointer Ledger::getSQL(const std::string& sql) db->endIterRows(); } - Ledger::pointer ret = - boost::make_shared(prevHash, transHash, accountHash, totCoins, closingTime, prevClosingTime, - closeFlags, closeResolution, ledgerSeq); + Ledger::pointer ret =Ledger::pointer(new Ledger(prevHash, transHash, accountHash, totCoins, closingTime, prevClosingTime, + closeFlags, closeResolution, ledgerSeq,isMutable)); if (ret->getHash() != ledgerHash) { Json::StyledStreamWriter ssw; diff --git a/src/Ledger.h b/src/Ledger.h index d059f01581..e7a546649f 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -84,7 +84,7 @@ private: protected: - static Ledger::pointer getSQL(const std::string& sqlStatement); + SLE::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID, LedgerEntryType let); @@ -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); // used for database ledgers + uint32 ledgerSeq,bool immutable); // used for database ledgers Ledger(const std::vector& rawLedger); @@ -103,6 +103,8 @@ public: Ledger(Ledger& target, bool isMutable); // snapshot + static Ledger::pointer getSQL(const std::string& sqlStatement,bool immutable=false); + void updateHash(); void setClosed() { mClosed = true; } void setAccepted(uint32 closeTime, int closeResolution, bool correctCloseTime); diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index e0adb16ade..dd0f6eccad 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -21,7 +21,7 @@ bool LedgerMaster::addHeldTransaction(const Transaction::pointer& transaction) void LedgerMaster::pushLedger(Ledger::ref newLedger) { // Caller should already have properly assembled this ledger into "ready-to-close" form -- - // all candidate transactions must already be appled + // all candidate transactions must already be applied Log(lsINFO) << "PushLedger: " << newLedger->getHash(); ScopedLock sl(mLock); if (!!mFinalizedLedger) @@ -70,6 +70,8 @@ void LedgerMaster::storeLedger(Ledger::ref ledger) mLedgerHistory.addLedger(ledger); } + + Ledger::pointer LedgerMaster::closeLedger() { boost::recursive_mutex::scoped_lock sl(mLock); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 27e28d413c..dcaca38004 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -424,7 +424,7 @@ 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); - assert(networkClosed.isNonZero()); + 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, @@ -438,7 +438,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result) setMode(omTRACKING); } - if ((mMode == omTRACKING) && !ledgerChange) + if ((mMode == omTRACKING) && !ledgerChange ) { // 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 @@ -470,6 +470,8 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis Log(lsTRACE) << "NetworkOPs::checkLastClosedLedger"; Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger(); + if(!ourClosed) return(false); + uint256 closedLedger = ourClosed->getHash(); uint256 prevClosedLedger = ourClosed->getParentHash(); diff --git a/src/main.cpp b/src/main.cpp index 4a69f9f2da..63a7812136 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -98,6 +98,8 @@ int main(int argc, char* argv[]) ("test,t", "Perform unit tests.") ("parameters", po::value< vector >(), "Specify comma separated parameters.") ("verbose,v", "Increase log level.") + ("load","Load the current ledger from the local DB.") + ("start","Start from a fresh Ledger.") ; // Interpret positional arguments as --parameters. @@ -154,6 +156,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 (iResult) { nothing(); From daedc85cdd69ac70c99c451a61dbe4dccc310189 Mon Sep 17 00:00:00 2001 From: jed Date: Tue, 9 Oct 2012 05:01:03 -0700 Subject: [PATCH 8/8] . --- src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Application.cpp b/src/Application.cpp index 49bd4836dc..1a67e0b74d 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -154,7 +154,6 @@ void Application::run() { Log(lsWARNING) << "Running in standalone mode"; mNetOps.setStandAlone(); - mMasterLedger.runStandAlone(); } else mNetOps.setStateTimer();