mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
210
js/amount.js
Normal file
210
js/amount.js
Normal file
@@ -0,0 +1,210 @@
|
||||
// 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.prototype.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.prototype.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.prototype.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.prototype.to_json = function () {
|
||||
return this.value ? this.value : 'XNS';
|
||||
};
|
||||
|
||||
Currency.prototype.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.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.prototype.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.prototype.parse_native = function(j) {
|
||||
if ('integer' === typeof j) {
|
||||
// XNS
|
||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
||||
this.offset = 0;
|
||||
this.is_native = true;
|
||||
this.is_negative = j < 0;
|
||||
}
|
||||
else if ('string' === typeof j) {
|
||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
||||
this.offset = 0;
|
||||
this.is_native = true;
|
||||
this.is_negative = j < 0;
|
||||
}
|
||||
else {
|
||||
this.value = NaN;
|
||||
}
|
||||
};
|
||||
|
||||
// Parse a non-native value.
|
||||
Amount.prototype.parse_value = function(j) {
|
||||
if ('integer' === typeof j) {
|
||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
||||
this.offset = 0;
|
||||
this.is_native = false;
|
||||
this.is_negative = j < 0;
|
||||
}
|
||||
else if ('string' === typeof j) {
|
||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
||||
this.offset = 0;
|
||||
this.is_native = false;
|
||||
this.is_negative = j < 0;
|
||||
}
|
||||
else {
|
||||
this.value = NaN;
|
||||
}
|
||||
};
|
||||
|
||||
// <-> j
|
||||
Amount.prototype.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.Amount = Amount;
|
||||
exports.Currency = Currency;
|
||||
exports.UInt160 = UInt160;
|
||||
|
||||
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
|
||||
60
js/remote.js
60
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;
|
||||
|
||||
198
js/utils.js
198
js/utils.js
@@ -4,127 +4,151 @@ 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) {
|
||||
var a = [];
|
||||
var i = 0;
|
||||
|
||||
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("");
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -133,5 +157,7 @@ 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
|
||||
|
||||
@@ -118,6 +118,12 @@
|
||||
[rpc_allow_remote]
|
||||
1
|
||||
|
||||
[websocket_ip]
|
||||
0.0.0.0
|
||||
|
||||
[websocket_port]
|
||||
5006
|
||||
|
||||
[debug_logfile]
|
||||
log/debug.log
|
||||
|
||||
|
||||
@@ -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,6 +148,33 @@ void Application::run()
|
||||
if (!theConfig.RUN_STANDALONE)
|
||||
mConnectionPool.start();
|
||||
|
||||
|
||||
|
||||
if (theConfig.RUN_STANDALONE)
|
||||
{
|
||||
Log(lsWARNING) << "Running in standalone mode";
|
||||
mNetOps.setStandAlone();
|
||||
}
|
||||
else
|
||||
mNetOps.setStateTimer();
|
||||
|
||||
mIOService.run(); // This blocks
|
||||
|
||||
mWSDoor->stop();
|
||||
|
||||
std::cout << "Done." << std::endl;
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
delete mTxnDB;
|
||||
delete mLedgerDB;
|
||||
delete mWalletDB;
|
||||
delete mHashNodeDB;
|
||||
delete mNetNodeDB;
|
||||
}
|
||||
void Application::startNewLedger()
|
||||
{
|
||||
// New stuff.
|
||||
NewcoinAddress rootSeedMaster = NewcoinAddress::createSeedGeneric("masterpassphrase");
|
||||
NewcoinAddress rootGeneratorMaster = NewcoinAddress::createGeneratorPublic(rootSeedMaster);
|
||||
@@ -156,30 +199,18 @@ void Application::run()
|
||||
assert(!!secondLedger->getAccountState(rootAddress));
|
||||
mNetOps.setLastCloseTime(secondLedger->getCloseTimeNC());
|
||||
}
|
||||
|
||||
|
||||
if (theConfig.RUN_STANDALONE)
|
||||
{
|
||||
Log(lsWARNING) << "Running in standalone mode";
|
||||
mNetOps.setStandAlone();
|
||||
mMasterLedger.runStandAlone();
|
||||
}
|
||||
else
|
||||
mNetOps.setStateTimer();
|
||||
|
||||
mIOService.run(); // This blocks
|
||||
|
||||
mWSDoor->stop();
|
||||
|
||||
std::cout << "Done." << std::endl;
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
void Application::loadOldLedger()
|
||||
{
|
||||
delete mTxnDB;
|
||||
delete mLedgerDB;
|
||||
delete mWalletDB;
|
||||
delete mHashNodeDB;
|
||||
delete mNetNodeDB;
|
||||
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
|
||||
|
||||
@@ -67,6 +67,9 @@ class Application
|
||||
std::map<std::string, Peer::pointer> mPeerMap;
|
||||
boost::recursive_mutex mPeerMapLock;
|
||||
|
||||
void startNewLedger();
|
||||
void loadOldLedger();
|
||||
|
||||
public:
|
||||
Application();
|
||||
~Application();
|
||||
|
||||
@@ -155,6 +155,7 @@ void Config::setup(const std::string& strConf)
|
||||
VALIDATORS_SITE = DEFAULT_VALIDATORS_SITE;
|
||||
|
||||
RUN_STANDALONE = false;
|
||||
START_UP = NORMAL;
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
@@ -56,6 +56,9 @@ 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};
|
||||
StartUpType START_UP;
|
||||
|
||||
// Network parameters
|
||||
int NETWORK_START_TIME; // The Unix time we start ledger 0.
|
||||
int TRANSACTION_FEE_BASE;
|
||||
|
||||
@@ -38,11 +38,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();
|
||||
}
|
||||
@@ -391,7 +391,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;
|
||||
@@ -424,9 +424,8 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
db->endIterRows();
|
||||
}
|
||||
|
||||
Ledger::pointer ret =
|
||||
boost::make_shared<Ledger>(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)
|
||||
{
|
||||
if (sLog(lsERROR))
|
||||
|
||||
@@ -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<unsigned char>& 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);
|
||||
|
||||
@@ -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<LedgerConsensus> 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);
|
||||
|
||||
@@ -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<LedgerProposal::pointer> > &n)
|
||||
{ mDeferredProposals.swap(n); }
|
||||
|
||||
// test/debug
|
||||
void simulate();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
12
src/Log.h
12
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
|
||||
|
||||
@@ -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,12 +438,12 @@ 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
|
||||
// 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();
|
||||
}
|
||||
@@ -470,6 +470,8 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
cLog(lsTRACE) << "NetworkOPs::checkLastClosedLedger";
|
||||
|
||||
Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger();
|
||||
if(!ourClosed) return(false);
|
||||
|
||||
uint256 closedLedger = ourClosed->getHash();
|
||||
uint256 prevClosedLedger = ourClosed->getParentHash();
|
||||
|
||||
@@ -650,7 +652,7 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo
|
||||
assert(!mConsensus);
|
||||
prevLedger->setImmutable();
|
||||
mConsensus = boost::make_shared<LedgerConsensus>(
|
||||
networkClosed, prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
|
||||
networkClosed, prevLedger, mLedgerMaster->getCurrentLedger()->getCloseTimeNC());
|
||||
mConsensus->swapDefer(mDeferredProposals);
|
||||
|
||||
cLog(lsDEBUG) << "Initiating consensus engine";
|
||||
@@ -670,7 +672,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 +772,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<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
BOOST_FOREACH(Peer::ref it, peerList)
|
||||
if (it && (it->getClosedLedgerHash() == deadLedger))
|
||||
@@ -1222,6 +1224,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)
|
||||
|
||||
@@ -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<uint32, uint256> >
|
||||
|
||||
@@ -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 <seed> <paying_account> [<domain>]
|
||||
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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -98,6 +98,8 @@ 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.")
|
||||
;
|
||||
|
||||
// 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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user