diff --git a/.gitignore b/.gitignore
index 2530f7eb82..92eb7bb785 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,10 @@
*.o
obj/*
bin/newcoind
-
newcoind
+# Ignore locally installed node_modules
+node_modules
+
+# Ignore tmp directory.
+tmp
diff --git a/Debug/newcoin.exe.embed.manifest.res b/Debug/newcoin.exe.embed.manifest.res
deleted file mode 100644
index 9c8df0e3c8..0000000000
Binary files a/Debug/newcoin.exe.embed.manifest.res and /dev/null differ
diff --git a/Debug/newcoin_manifest.rc b/Debug/newcoin_manifest.rc
deleted file mode 100644
index 20da22ef1c..0000000000
Binary files a/Debug/newcoin_manifest.rc and /dev/null differ
diff --git a/js/remote.js b/js/remote.js
new file mode 100644
index 0000000000..ffab43eaad
--- /dev/null
+++ b/js/remote.js
@@ -0,0 +1,205 @@
+// Remote access to a server.
+// - We never send binary data.
+// - We use the W3C interface for node and browser compatibility:
+// http://www.w3.org/TR/websockets/#the-websocket-interface
+//
+// YYY Will later provide a network access which use multiple instances of this.
+// YYY A better model might be to allow requesting a target state: keep connected or not.
+//
+
+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 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;
+
+ if (this.trace)
+ console.log("remote: connect: %s", this.url);
+
+ 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);
+ }
+ }
+ });
+});
+
+// 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();
+
+});
+
+// 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();
+});
+
+// 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('ledger_closed', function(done) {
+ assert(this.trusted); // If not trusted, need to check proof.
+
+ this.request({ 'command' : 'ledger_closed' }, done);
+});
+
+// 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);
+});
+
+// <-> 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);
+});
+
+// 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() {
+// });
+});
+
+exports.Remote = Remote;
+exports.remoteConfig = remoteConfig;
+
+// vim:ts=4
diff --git a/js/serializer.js b/js/serializer.js
new file mode 100644
index 0000000000..00f9e070b5
--- /dev/null
+++ b/js/serializer.js
@@ -0,0 +1,44 @@
+//
+
+var serializer = {};
+
+serializer.addUInt16 = function(value) {
+ switch (typeof value) {
+ case 'string':
+ addUInt16(value.charCodeAt(0));
+ break;
+
+ case 'integer':
+ for (i = 16/8; i; i -=1) {
+ raw.push(value & 255);
+ value >>= 8;
+ }
+ break;
+
+ default:
+ throw 'UNEXPECTED_TYPE';
+ }
+};
+
+serializer.addUInt160 = function(value) {
+ switch (typeof value) {
+ case 'array':
+ raw.concat(value);
+ break;
+
+ case 'integer':
+ for (i = 160/8; i; i -=1) {
+ raw.push(value & 255);
+ value >>= 8;
+ }
+ break;
+
+ default:
+ throw 'UNEXPECTED_TYPE';
+ }
+};
+
+serializer.getSHA512Half = function() {
+};
+
+// vim:ts=4
diff --git a/js/utils.js b/js/utils.js
new file mode 100644
index 0000000000..6bb4ae7a2d
--- /dev/null
+++ b/js/utils.js
@@ -0,0 +1,137 @@
+// YYY Should probably have two versions: node vs browser
+
+var fs = require("fs");
+var path = require("path");
+
+Function.prototype.method = function(name,func) {
+ this.prototype[name] = func;
+
+ return this;
+};
+
+var filterErr = function(code, done) {
+ return function(e) {
+ done(e.code !== code ? e : undefined);
+ };
+};
+
+var throwErr = function(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();
+ }
+};
+
+// 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.
+
+ mkPath(path.dirname(dirPath), mode, function(e) {
+ if (e) {
+ throw e;
+ }
+ else {
+ 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);
+ }
+ });
+};
+
+// 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);
+ }
+ });
+};
+
+// 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);
+ }
+ });
+};
+
+var trace = function(comment, func) {
+ return function() {
+ console.log("%s: %s", trace, arguments.toString);
+ func(arguments);
+ };
+};
+
+exports.emptyPath = emptyPath;
+exports.mapOr = mapOr;
+exports.mkPath = mkPath;
+exports.resetPath = resetPath;
+exports.rmPath = rmPath;
+exports.trace = trace;
+
+// vim:ts=4
diff --git a/newcoin.vcxproj b/newcoin.vcxproj
index aafa214ad2..4a7bdee1dd 100644
--- a/newcoin.vcxproj
+++ b/newcoin.vcxproj
@@ -50,6 +50,7 @@
Disabled
BOOST_TEST_ALTERNATIVE_INIT_API;BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
..\OpenSSL\include;..\boost_1_47_0;..\protobuf-2.4.1\src\
+ ProgramDatabase
Console
@@ -101,21 +102,21 @@
+
+
-
-
@@ -123,19 +124,25 @@
+
+
+
+
+
+
@@ -146,6 +153,7 @@
+
@@ -188,11 +196,13 @@
+
+
@@ -207,19 +217,25 @@
+
+
+
+
+
+
@@ -259,6 +275,13 @@
+
+
+
+
+
+
+
diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters
index 9a6fa8ac81..f569d1ac42 100644
--- a/newcoin.vcxproj.filters
+++ b/newcoin.vcxproj.filters
@@ -93,15 +93,9 @@
Source Files
-
- Source Files
-
Source Files
-
- Source Files
-
Source Files
@@ -273,6 +267,33 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -503,6 +524,30 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
@@ -512,7 +557,6 @@
-
diff --git a/newcoind.cfg b/newcoind.cfg
index 774a32129d..689b276923 100644
--- a/newcoind.cfg
+++ b/newcoind.cfg
@@ -5,31 +5,8 @@
# or Mac style end of lines. Blank lines and lines beginning with '#' are
# ignored. Undefined sections are reserved. No escapes are currently defined.
#
-# When you launch newcoind, it will attempt to find this file.
-#
-# --conf=:
-# You may specify the location of this file with --conf=. The config
-# directory is the directory containing this file. The data directory is a
-# the subdirectory named "dbs".
-#
-# Windows and no --conf:
-# The config directory is the same directory as the newcoind program. The
-# data directory is a the subdirectory named "dbs".
-#
-# Other OSes and no --conf:
-# This file will be looked for in these places in the following order:
-# ./newcoind.cfg
-# $XDG_CONFIG_HOME/newcoin/newcoind.cfg
-#
-# If newcoind.cfg, is found in the current working directory, the directory
-# will be used as the config directory. The data directory is a the
-# subdirectory named "dbs".
-#
-# Otherwise, the data directory data is:
-# $XDG_DATA_HOME/newcoin/
-#
-# Note: $XDG_CONFIG_HOME defaults to $HOME/.config
-# $XDG_DATA_HOME defaults to $HOME/.local/share
+# When you launch newcoind, it will attempt to find this file. For details,
+# refer to the manual page for --conf command line option.
#
# [debug_logfile]
# Specifies were a debug logfile is kept. By default, no debug log is kept
@@ -142,7 +119,7 @@
1
[debug_logfile]
-debug.log
+log/debug.log
[sntp_servers]
time.windows.com
diff --git a/src/AccountState.cpp b/src/AccountState.cpp
index 5e56bd9965..9aee8f8694 100644
--- a/src/AccountState.cpp
+++ b/src/AccountState.cpp
@@ -9,23 +9,28 @@
#include "Ledger.h"
#include "Serializer.h"
+#include "Log.h"
-AccountState::AccountState(const NewcoinAddress& id) : mAccountID(id), mValid(false)
+AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAccountID), mValid(false)
{
- if (!id.isValid()) return;
+ if (!naAccountID.isValid()) return;
+
mLedgerEntry = boost::make_shared(ltACCOUNT_ROOT);
- mLedgerEntry->setIndex(Ledger::getAccountRootIndex(id));
- mLedgerEntry->setIFieldAccount(sfAccount, id);
+ mLedgerEntry->setIndex(Ledger::getAccountRootIndex(naAccountID));
+ mLedgerEntry->setFieldAccount(sfAccount, naAccountID.getAccountID());
+
mValid = true;
}
-AccountState::AccountState(SerializedLedgerEntry::pointer ledgerEntry) : mLedgerEntry(ledgerEntry), mValid(false)
+AccountState::AccountState(SLE::ref ledgerEntry, const NewcoinAddress& naAccountID) :
+ mAccountID(naAccountID), mLedgerEntry(ledgerEntry), mValid(false)
{
- if (!mLedgerEntry) return;
- if (mLedgerEntry->getType() != ltACCOUNT_ROOT) return;
- mAccountID = mLedgerEntry->getIValueFieldAccount(sfAccount);
- if (mAccountID.isValid())
- mValid = true;
+ if (!mLedgerEntry)
+ return;
+ if (mLedgerEntry->getType() != ltACCOUNT_ROOT)
+ return;
+
+ mValid = true;
}
std::string AccountState::createGravatarUrl(uint128 uEmailHash)
@@ -41,20 +46,22 @@ void AccountState::addJson(Json::Value& val)
{
val = mLedgerEntry->getJson(0);
- if (!mValid) val["Invalid"] = true;
-
- if (mLedgerEntry->getIFieldPresent(sfEmailHash))
- val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getIFieldH128(sfEmailHash));
+ if (mValid)
+ {
+ if (mLedgerEntry->isFieldPresent(sfEmailHash))
+ val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getFieldH128(sfEmailHash));
+ }
+ else
+ {
+ val["Invalid"] = true;
+ }
}
void AccountState::dump()
{
Json::Value j(Json::objectValue);
-
addJson(j);
-
- Json::StyledStreamWriter ssw;
- ssw.write(std::cerr, j);
+ Log(lsINFO) << j;
}
// vim:ts=4
diff --git a/src/AccountState.h b/src/AccountState.h
index d51898e5dd..728d5ae96a 100644
--- a/src/AccountState.h
+++ b/src/AccountState.h
@@ -28,22 +28,21 @@ private:
bool mValid;
public:
- AccountState(const NewcoinAddress& AccountID); // For new accounts
- AccountState(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
+ AccountState(const NewcoinAddress& naAccountID); // For new accounts
+ AccountState(SLE::ref ledgerEntry,const NewcoinAddress& naAccountI); // For accounts in a ledger
bool bHaveAuthorizedKey()
{
- return mLedgerEntry->getIFieldPresent(sfAuthorizedKey);
+ return mLedgerEntry->isFieldPresent(sfAuthorizedKey);
}
NewcoinAddress getAuthorizedKey()
{
- return mLedgerEntry->getIValueFieldAccount(sfAuthorizedKey);
+ return mLedgerEntry->getFieldAccount(sfAuthorizedKey);
}
- const NewcoinAddress& getAccountID() const { return mAccountID; }
- STAmount getBalance() const { return mLedgerEntry->getIValueFieldAmount(sfBalance); }
- uint32 getSeq() const { return mLedgerEntry->getIFieldU32(sfSequence); }
+ STAmount getBalance() const { return mLedgerEntry->getFieldAmount(sfBalance); }
+ uint32 getSeq() const { return mLedgerEntry->getFieldU32(sfSequence); }
SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; }
const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; }
diff --git a/src/Amount.cpp b/src/Amount.cpp
index 7d95eeffca..9c5d0df513 100644
--- a/src/Amount.cpp
+++ b/src/Amount.cpp
@@ -3,6 +3,8 @@
#include
#include
+#include
+#include
#include
#include "Config.h"
@@ -10,6 +12,9 @@
#include "SerializedTypes.h"
#include "utils.h"
+uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1));
+
+// --> sCurrency: "", "XNS", or three letter ISO code.
bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency)
{
bool bSuccess = true;
@@ -51,6 +56,98 @@ std::string STAmount::getHumanCurrency() const
return createHumanCurrency(mCurrency);
}
+STAmount::STAmount(SField::ref n, const Json::Value& v)
+ : SerializedType(n), mValue(0), mOffset(0), mIsNegative(false)
+{
+ Json::Value value, currency, issuer;
+
+ if (v.isObject())
+ {
+ value = v["value"];
+ currency = v["currency"];
+ issuer = v["issuer"];
+ }
+ else if (v.isArray())
+ {
+ value = v.get(Json::UInt(0), 0);
+ currency = v.get(Json::UInt(1), Json::nullValue);
+ issuer = v.get(Json::UInt(2), Json::nullValue);
+ }
+ else if (v.isString())
+ {
+ std::string val = v.asString();
+ std::vector elements;
+ boost::split(elements, val, boost::is_any_of("\t\n\r ,/"));
+
+ if ((elements.size() < 0) || (elements.size() > 3))
+ throw std::runtime_error("invalid amount string");
+
+ value = elements[0];
+ if (elements.size() > 0)
+ currency = elements[1];
+ if (elements.size() > 1)
+ issuer = elements[2];
+ }
+ else
+ value = v;
+
+ mIsNative = !currency.isString() || currency.asString().empty() || (currency.asString() == SYSTEM_CURRENCY_CODE);
+
+ if (value.isInt())
+ {
+ if (value.asInt() >= 0)
+ mValue = value.asInt();
+ else
+ {
+ mValue = -value.asInt();
+ mIsNegative = true;
+ }
+ }
+ else if (value.isUInt())
+ mValue = v.asUInt();
+ else if (value.isString())
+ {
+ if (mIsNative)
+ {
+ int64 val = lexical_cast_st(value.asString());
+ if (val >= 0)
+ mValue = val;
+ else
+ {
+ mValue = -val;
+ mIsNegative = true;
+ }
+ }
+ else
+ setValue(value.asString());
+ }
+ else
+ throw std::runtime_error("invalid amount type");
+
+ if (mIsNative)
+ return;
+
+ if (!currencyFromString(mCurrency, currency.asString()))
+ throw std::runtime_error("invalid currency");
+
+ if (!issuer.isString())
+ throw std::runtime_error("invalid issuer");
+
+ if (issuer.size() == (160/4))
+ mIssuer.SetHex(issuer.asString());
+ else
+ {
+ NewcoinAddress is;
+ if(!is.setAccountID(issuer.asString()))
+ throw std::runtime_error("invalid issuer");
+ mIssuer = is.getAccountID();
+ }
+ if (mIssuer.isZero())
+ throw std::runtime_error("invalid issuer");
+
+ canonicalize();
+}
+
std::string STAmount::createHumanCurrency(const uint160& uCurrency)
{
std::string sCurrency;
@@ -59,6 +156,10 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency)
{
return SYSTEM_CURRENCY_CODE;
}
+ else if (uCurrency == CURRENCY_ONE)
+ {
+ return "1";
+ }
else
{
Serializer s(160/8);
@@ -74,15 +175,15 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency)
if (!::isZero(vucZeros.begin(), vucZeros.size()))
{
- throw std::runtime_error("bad currency: zeros");
+ throw std::runtime_error(boost::str(boost::format("bad currency: zeros: %s") % uCurrency));
}
else if (!::isZero(vucVersion.begin(), vucVersion.size()))
{
- throw std::runtime_error("bad currency: version");
+ throw std::runtime_error(boost::str(boost::format("bad currency: version: %s") % uCurrency));
}
else if (!::isZero(vucReserved.begin(), vucReserved.size()))
{
- throw std::runtime_error("bad currency: reserved");
+ throw std::runtime_error(boost::str(boost::format("bad currency: reserved: %s") % uCurrency));
}
else
{
@@ -93,50 +194,32 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency)
return sCurrency;
}
-// Not meant to be the ultimate parser. For use by RPC which is supposed to be sane and trusted.
-// Native has special handling:
-// - Integer values are in base units.
-// - Float values are in float units.
-// - To avoid a mistake float value for native are specified with a "^" in place of a "."
-// <-- bValid: true = valid
-bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurrency, const std::string& sIssuer)
-{
- //
- // Figure out the currency.
- //
- if (!currencyFromString(mCurrency, sCurrency))
- return false;
-
- mIsNative = !mCurrency;
-
- //
- // Figure out the issuer.
- //
- NewcoinAddress naIssuerID;
-
- // Issuer must be "" or a valid account string.
- if (!naIssuerID.setAccountID(sIssuer))
- return false;
-
- mIssuer = naIssuerID.getAccountID();
-
- // Stamps not must have an issuer.
- if (mIsNative && !mIssuer.isZero())
- return false;
-
+bool STAmount::setValue(const std::string& sAmount)
+{ // Note: mIsNative must be set already!
uint64 uValue;
int iOffset;
size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : ".");
bool bInteger = uDecimal == std::string::npos;
+ mIsNegative = false;
if (bInteger)
{
try
{
- uValue = sAmount.empty() ? 0 : boost::lexical_cast(sAmount);
+ int64 a = sAmount.empty() ? 0 : lexical_cast_st(sAmount);
+ if (a >= 0)
+ uValue = static_cast(a);
+ else
+ {
+ uValue = static_cast(-a);
+ mIsNegative = true;
+ }
+
}
catch (...)
{
+ Log(lsINFO) << "Bad integer amount: " << sAmount;
+
return false;
}
iOffset = 0;
@@ -147,16 +230,26 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr
// ^1 2 0 2 -1
// 123^ 4 3 1 0
// 1^23 4 1 3 -2
- iOffset = -int(sAmount.size()-uDecimal-1);
+ iOffset = -int(sAmount.size() - uDecimal - 1);
// Issolate integer and fraction.
- uint64 uInteger = uDecimal ? boost::lexical_cast(sAmount.substr(0, uDecimal)) : 0;
- uint64 uFraction = iOffset ? boost::lexical_cast(sAmount.substr(uDecimal+1)) : 0;
+ uint64 uInteger;
+ int64 iInteger = uDecimal ? lexical_cast_st(sAmount.substr(0, uDecimal)) : 0;
+ if (iInteger >= 0)
+ uInteger = static_cast(iInteger);
+ else
+ {
+ uInteger = static_cast(-iInteger);
+ mIsNegative = true;
+ }
+
+
+ uint64 uFraction = iOffset ? lexical_cast_st(sAmount.substr(uDecimal+1)) : 0;
// Scale the integer portion to the same offset as the fraction.
uValue = uInteger;
- for (int i=-iOffset; i--;)
+ for (int i = -iOffset; i--;)
uValue *= 10;
// Add in the fraction.
@@ -186,10 +279,55 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr
mOffset = iOffset;
canonicalize();
}
-
return true;
}
+// Not meant to be the ultimate parser. For use by RPC which is supposed to be sane and trusted.
+// Native has special handling:
+// - Integer values are in base units.
+// - Float values are in float units.
+// - To avoid a mistake float value for native are specified with a "^" in place of a "."
+// <-- bValid: true = valid
+bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurrency, const std::string& sIssuer)
+{
+ //
+ // Figure out the currency.
+ //
+ if (!currencyFromString(mCurrency, sCurrency))
+ {
+ Log(lsINFO) << "Currency malformed: " << sCurrency;
+
+ return false;
+ }
+
+ mIsNative = !mCurrency;
+
+ //
+ // Figure out the issuer.
+ //
+ NewcoinAddress naIssuerID;
+
+ // Issuer must be "" or a valid account string.
+ if (!naIssuerID.setAccountID(sIssuer))
+ {
+ Log(lsINFO) << "Issuer malformed: " << sIssuer;
+
+ return false;
+ }
+
+ mIssuer = naIssuerID.getAccountID();
+
+ // Stamps not must have an issuer.
+ if (mIsNative && !mIssuer.isZero())
+ {
+ Log(lsINFO) << "Issuer specified for stamps: " << sIssuer;
+
+ return false;
+ }
+
+ return setValue(sAmount);
+}
+
// amount = value * [10 ^ offset]
// representation range is 10^80 - 10^(-80)
// on the wire, high 8 bits are (offset+142), low 56 bits are value
@@ -274,21 +412,15 @@ void STAmount::add(Serializer& s) const
s.add64(mValue | (static_cast(mOffset + 512 + 256 + 97) << (64 - 10)));
s.add160(mCurrency);
+ s.add160(mIssuer);
}
}
-STAmount::STAmount(const char* name, int64 value) : SerializedType(name), mOffset(0), mIsNative(true)
+STAmount STAmount::createFromInt64(SField::ref name, int64 value)
{
- if (value >= 0)
- {
- mIsNegative = false;
- mValue = static_cast(value);
- }
- else
- {
- mIsNegative = true;
- mValue = static_cast(-value);
- }
+ return value >= 0
+ ? STAmount(name, static_cast(value), false)
+ : STAmount(name, static_cast(-value), true);
}
void STAmount::setValue(const STAmount &a)
@@ -303,13 +435,14 @@ void STAmount::setValue(const STAmount &a)
uint64 STAmount::toUInt64() const
{ // makes them sort easily
- if (mValue == 0) return 0x4000000000000000ull;
+ if (mValue == 0)
+ return 0x4000000000000000ull;
if (mIsNegative)
return mValue | (static_cast(mOffset + 97) << (64 - 10));
return mValue | (static_cast(mOffset + 256 + 97) << (64 - 10));
}
-STAmount* STAmount::construct(SerializerIterator& sit, const char *name)
+STAmount* STAmount::construct(SerializerIterator& sit, SField::ref name)
{
uint64 value = sit.get64();
@@ -320,25 +453,28 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name)
return new STAmount(name, value, true); // negative
}
- uint160 currency = sit.get160();
- if (!currency)
+ uint160 uCurrencyID = sit.get160();
+ if (!uCurrencyID)
throw std::runtime_error("invalid native currency");
+ uint160 uIssuerID = sit.get160();
+
int offset = static_cast(value >> (64 - 10)); // 10 bits for the offset, sign and "not native" flag
value &= ~(1023ull << (64-10));
- if (value == 0)
+ if (value)
{
- if (offset != 512)
+ bool isNegative = (offset & 256) == 0;
+ offset = (offset & 255) - 97; // center the range
+ if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset))
throw std::runtime_error("invalid currency value");
- return new STAmount(name, currency);
+
+ return new STAmount(name, uCurrencyID, uIssuerID, value, offset, isNegative);
}
- bool isNegative = (offset & 256) == 0;
- offset = (offset & 255) - 97; // center the range
- if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset))
+ if (offset != 512)
throw std::runtime_error("invalid currency value");
- return new STAmount(name, currency, value, offset, isNegative);
+ return new STAmount(name, uCurrencyID, uIssuerID);
}
int64 STAmount::getSNValue() const
@@ -368,14 +504,14 @@ std::string STAmount::getRaw() const
if (mValue == 0) return "0";
if (mIsNative)
{
- if (mIsNegative) return std::string("-") + boost::lexical_cast(mValue);
- else return boost::lexical_cast(mValue);
+ if (mIsNegative) return std::string("-") + lexical_cast_i(mValue);
+ else return lexical_cast_i(mValue);
}
if (mIsNegative)
return mCurrency.GetHex() + ": -" +
- boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset);
+ lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset);
else return mCurrency.GetHex() + ": " +
- boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset);
+ lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset);
}
std::string STAmount::getText() const
@@ -384,20 +520,20 @@ std::string STAmount::getText() const
if (mIsNative)
{
if (mIsNegative)
- return std::string("-") + boost::lexical_cast(mValue);
- else return boost::lexical_cast(mValue);
+ return std::string("-") + lexical_cast_i(mValue);
+ else return lexical_cast_i(mValue);
}
if ((mOffset < -25) || (mOffset > -5))
{
if (mIsNegative)
- return std::string("-") + boost::lexical_cast(mValue) +
- "e" + boost::lexical_cast(mOffset);
+ return std::string("-") + lexical_cast_i(mValue) +
+ "e" + lexical_cast_i(mOffset);
else
- return boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset);
+ return lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset);
}
std::string val = "000000000000000000000000000";
- val += boost::lexical_cast(mValue);
+ val += lexical_cast_i(mValue);
val += "00000000000000000000000";
std::string pre = val.substr(0, mOffset + 43);
@@ -446,7 +582,7 @@ bool STAmount::operator==(const STAmount& a) const
bool STAmount::operator!=(const STAmount& a) const
{
- return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative!= a.mIsNegative) || !isComparable(a);
+ return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative != a.mIsNegative) || !isComparable(a);
}
bool STAmount::operator<(const STAmount& a) const
@@ -488,19 +624,7 @@ STAmount& STAmount::operator-=(const STAmount& a)
STAmount STAmount::operator-(void) const
{
if (mValue == 0) return *this;
- return STAmount(name, mCurrency, mValue, mOffset, mIsNative, !mIsNegative);
-}
-
-STAmount& STAmount::operator=(const STAmount& a)
-{
- mValue = a.mValue;
- mOffset = a.mOffset;
- mIssuer = a.mIssuer;
- mCurrency = a.mCurrency;
- mIsNative = a.mIsNative;
- mIsNegative = a.mIsNegative;
-
- return *this;
+ return STAmount(getFName(), mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative);
}
STAmount& STAmount::operator=(uint64 v)
@@ -553,12 +677,12 @@ bool STAmount::operator>=(uint64 v) const
STAmount STAmount::operator+(uint64 v) const
{
- return STAmount(name, getSNValue() + static_cast(v));
+ return STAmount(getFName(), getSNValue() + static_cast(v));
}
STAmount STAmount::operator-(uint64 v) const
{
- return STAmount(name, getSNValue() - static_cast(v));
+ return STAmount(getFName(), getSNValue() - static_cast(v));
}
STAmount::operator double() const
@@ -576,7 +700,7 @@ STAmount operator+(const STAmount& v1, const STAmount& v2)
v1.throwComparable(v2);
if (v1.mIsNative)
- return STAmount(v1.name, v1.getSNValue() + v2.getSNValue());
+ return STAmount(v1.getFName(), v1.getSNValue() + v2.getSNValue());
int ov1 = v1.mOffset, ov2 = v2.mOffset;
@@ -598,9 +722,9 @@ STAmount operator+(const STAmount& v1, const STAmount& v2)
int64 fv = vv1 + vv2;
if (fv >= 0)
- return STAmount(v1.name, v1.mCurrency, fv, ov1, false);
+ return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, fv, ov1, false);
else
- return STAmount(v1.name, v1.mCurrency, -fv, ov1, true);
+ return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, -fv, ov1, true);
}
STAmount operator-(const STAmount& v1, const STAmount& v2)
@@ -609,7 +733,10 @@ STAmount operator-(const STAmount& v1, const STAmount& v2)
v1.throwComparable(v2);
if (v2.mIsNative)
- return STAmount(v1.name, v1.getSNValue() - v2.getSNValue());
+ {
+ // XXX This could be better, check for overflow and that maximum range is covered.
+ return STAmount::createFromInt64(v1.getFName(), v1.getSNValue() - v2.getSNValue());
+ }
int ov1 = v1.mOffset, ov2 = v2.mOffset;
int64 vv1 = static_cast(v1.mValue), vv2 = static_cast(v2.mValue);
@@ -630,15 +757,15 @@ STAmount operator-(const STAmount& v1, const STAmount& v2)
int64 fv = vv1 - vv2;
if (fv >= 0)
- return STAmount(v1.name, v1.mCurrency, fv, ov1, false);
+ return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, fv, ov1, false);
else
- return STAmount(v1.name, v1.mCurrency, -fv, ov1, true);
+ return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, -fv, ov1, true);
}
-STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& currencyOut)
+STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (den.isZero()) throw std::runtime_error("division by zero");
- if (num.isZero()) return STAmount(currencyOut);
+ if (num.isZero()) return STAmount(uCurrencyID, uIssuerID);
uint64 numVal = num.mValue, denVal = den.mValue;
int numOffset = num.mOffset, denOffset = den.mOffset;
@@ -674,17 +801,17 @@ STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint16
assert(BN_num_bytes(&v) <= 64);
if (num.mIsNegative != den.mIsNegative)
- return -STAmount(currencyOut, v.getulong(), finOffset);
- else return STAmount(currencyOut, v.getulong(), finOffset);
+ return -STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset);
+ else return STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset);
}
-STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut)
+STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (v1.isZero() || v2.isZero())
- return STAmount(currencyOut);
+ return STAmount(uCurrencyID, uIssuerID);
if (v1.mIsNative && v2.mIsNative) // FIXME: overflow
- return STAmount(v1.name, v1.getSNValue() * v2.getSNValue());
+ return STAmount(v1.getFName(), v1.getSNValue() * v2.getSNValue());
uint64 value1 = v1.mValue, value2 = v2.mValue;
int offset1 = v1.mOffset, offset2 = v2.mOffset;
@@ -737,8 +864,8 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16
assert(BN_num_bytes(&v) <= 64);
if (v1.mIsNegative != v2.mIsNegative)
- return -STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14);
- else return STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14);
+ return -STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14);
+ else return STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14);
}
// Convert an offer into an index amount so they sort by rate.
@@ -753,7 +880,7 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn)
{
if (offerOut.isZero()) throw std::runtime_error("Worthless offer");
- STAmount r = divide(offerIn, offerOut, uint160(1));
+ STAmount r = divide(offerIn, offerOut, CURRENCY_ONE, ACCOUNT_ONE);
assert((r.getExponent() >= -100) && (r.getExponent() <= 155));
@@ -762,41 +889,65 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn)
return (ret << (64 - 8)) | r.getMantissa();
}
+STAmount STAmount::setRate(uint64 rate)
+{
+ uint64 mantissa = rate & ~(255ull << (64 - 8));
+ int exponent = static_cast(rate >> (64 - 8)) - 100;
+
+ return STAmount(CURRENCY_ONE, ACCOUNT_ONE, mantissa, exponent);
+}
+
// Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds.
-// --> saOfferFunds: Limit for saOfferPays
-// --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver
-// --> saOfferPays: Request : this should be reduced as the offer is fullfilled.
-// --> saOfferGets: Request : this should be reduced as the offer is fullfilled.
-// --> saTakerPays: Total : Used to know the approximate ratio of the exchange.
-// --> saTakerGets: Total : Used to know the approximate ratio of the exchange.
-// <-- saTakerPaid: Actual
-// <-- saTakerGot: Actual
-// <-- bRemove: remove offer it is either fullfilled or unfunded
+// --> uTakerPaysRate: >= QUALITY_ONE
+// --> uOfferPaysRate: >= QUALITY_ONE
+// --> saOfferFunds: Limit for saOfferPays
+// --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver
+// --> saOfferPays: Request : this should be reduced as the offer is fullfilled.
+// --> saOfferGets: Request : this should be reduced as the offer is fullfilled.
+// --> saTakerPays: Total : Used to know the approximate ratio of the exchange.
+// --> saTakerGets: Total : Used to know the approximate ratio of the exchange.
+// <-- saTakerPaid: Actual
+// <-- saTakerGot: Actual
+// <-- saTakerIssuerFee: Actual
+// <-- saOfferIssuerFee: Actual
+// <-- bRemove: remove offer it is either fullfilled or unfunded
bool STAmount::applyOffer(
+ const uint32 uTakerPaysRate, const uint32 uOfferPaysRate,
const STAmount& saOfferFunds, const STAmount& saTakerFunds,
const STAmount& saOfferPays, const STAmount& saOfferGets,
const STAmount& saTakerPays, const STAmount& saTakerGets,
- STAmount& saTakerPaid, STAmount& saTakerGot)
+ STAmount& saTakerPaid, STAmount& saTakerGot,
+ STAmount& saTakerIssuerFee, STAmount& saOfferIssuerFee)
{
saOfferGets.throwComparable(saTakerPays);
assert(!saOfferFunds.isZero() && !saTakerFunds.isZero()); // Must have funds.
assert(!saOfferGets.isZero() && !saOfferPays.isZero()); // Must not be a null offer.
+ // Amount offer can pay out, limited by funds and fees.
+ STAmount saOfferFundsAvailable = QUALITY_ONE == uOfferPaysRate
+ ? saOfferFunds
+ : STAmount::divide(saOfferFunds, STAmount(CURRENCY_ONE, uOfferPaysRate, -9));
+
// Amount offer can pay out, limited by offer and funds.
- STAmount saOfferPaysAvailable = saOfferFunds < saOfferPays ? saOfferFunds : saOfferPays;
+ STAmount saOfferPaysAvailable = std::min(saOfferFundsAvailable, saOfferPays);
// Amount offer can get in proportion, limited by offer funds.
STAmount saOfferGetsAvailable =
- saOfferFunds == saOfferPays
+ saOfferFundsAvailable == saOfferPays
? saOfferGets // Offer was fully funded, avoid shenanigans.
- : divide(multiply(saTakerPays, saOfferPaysAvailable, uint160(1)), saTakerGets, saOfferGets.getCurrency());
+ : divide(multiply(saTakerPays, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saTakerGets, saOfferGets.getCurrency(), saOfferGets.getIssuer());
- if (saOfferGets == saOfferGetsAvailable && saTakerFunds >= saOfferGets)
+ // Amount taker can spend, limited by funds and fees.
+ STAmount saTakerFundsAvailable = QUALITY_ONE == uTakerPaysRate
+ ? saTakerFunds
+ : STAmount::divide(saTakerFunds, STAmount(CURRENCY_ONE, uTakerPaysRate, -9));
+
+ if (saOfferGets == saOfferGetsAvailable && saTakerFundsAvailable >= saOfferGets)
{
// Taker gets all of offer available.
- saTakerPaid = saOfferGets; // Taker paid what offer could get.
- saTakerGot = saOfferPays; // Taker got what offer could pay.
+ saTakerPaid = saOfferGets; // Taker paid what offer could get.
+ saTakerGot = saOfferPays; // Taker got what offer could pay.
Log(lsINFO) << "applyOffer: took all outright";
}
@@ -812,19 +963,43 @@ bool STAmount::applyOffer(
{
// Taker only get's a portion of offer.
saTakerPaid = saTakerFunds; // Taker paid all he had.
- saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, uint160(1)), saOfferGetsAvailable, saOfferPays.getCurrency());
+ saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer());
Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText();
Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText();
}
+ if (uTakerPaysRate == QUALITY_ONE)
+ {
+ saTakerIssuerFee = STAmount(saTakerPaid.getCurrency(), saTakerPaid.getIssuer());
+ }
+ else
+ {
+ // Compute fees in a rounding safe way.
+ STAmount saTotal = STAmount::multiply(saTakerPaid, STAmount(CURRENCY_ONE, uTakerPaysRate, -9));
+
+ saTakerIssuerFee = (saTotal > saTakerFunds) ? saTakerFunds-saTakerPaid : saTotal - saTakerPaid;
+ }
+
+ if (uOfferPaysRate == QUALITY_ONE)
+ {
+ saOfferIssuerFee = STAmount(saTakerGot.getCurrency(), saTakerGot.getIssuer());
+ }
+ else
+ {
+ // Compute fees in a rounding safe way.
+ STAmount saTotal = STAmount::multiply(saTakerPaid, STAmount(CURRENCY_ONE, uTakerPaysRate, -9));
+
+ saOfferIssuerFee = (saTotal > saOfferFunds) ? saOfferFunds-saTakerGot : saTotal - saTakerGot;
+ }
+
return saTakerGot >= saOfferPays;
}
STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed)
{ // Someone wants to get (needed) out of the offer, how much should they pay in?
if (offerOut.isZero())
- return STAmount(offerIn.getCurrency());
+ return STAmount(offerIn.getCurrency(), offerIn.getIssuer());
if (needed >= offerOut)
{
@@ -832,7 +1007,7 @@ STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, con
return needed;
}
- STAmount ret = divide(multiply(needed, offerIn, uint160(1)), offerOut, offerIn.getCurrency());
+ STAmount ret = divide(multiply(needed, offerIn, CURRENCY_ONE, ACCOUNT_ONE), offerOut, offerIn.getCurrency(), offerIn.getIssuer());
return (ret > offerIn) ? offerIn : ret;
}
@@ -855,23 +1030,43 @@ uint64 STAmount::convertToDisplayAmount(const STAmount& internalAmount, uint64 t
return muldiv(internalAmount.getNValue(), totalInit, totalNow);
}
-STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit,
- const char *name)
+STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit, SField::ref name)
{ // Convert a display/request currency amount to an internal amount
return STAmount(name, muldiv(displayAmount, totalNow, totalInit));
}
STAmount STAmount::deserialize(SerializerIterator& it)
{
- STAmount *s = construct(it);
+ std::auto_ptr s(dynamic_cast(construct(it, sfGeneric)));
STAmount ret(*s);
-
- delete s;
-
return ret;
}
std::string STAmount::getFullText() const
+{
+ if (mIsNative)
+ {
+ return str(boost::format("%s/" SYSTEM_CURRENCY_CODE) % getText());
+ }
+ else if (!mIssuer)
+ {
+ return str(boost::format("%s/%s/0") % getText() % getHumanCurrency());
+ }
+ else if (mIssuer == ACCOUNT_ONE)
+ {
+ return str(boost::format("%s/%s/1") % getText() % getHumanCurrency());
+ }
+ else
+ {
+ return str(boost::format("%s/%s/%s")
+ % getText()
+ % getHumanCurrency()
+ % NewcoinAddress::createHumanAccountID(mIssuer));
+ }
+}
+
+#if 0
+std::string STAmount::getExtendedText() const
{
if (mIsNative)
{
@@ -879,7 +1074,7 @@ std::string STAmount::getFullText() const
}
else
{
- return str(boost::format("%s %s/%s %dE%d" )
+ return str(boost::format("%s/%s/%s %dE%d" )
% getText()
% getHumanCurrency()
% NewcoinAddress::createHumanAccountID(mIssuer)
@@ -887,6 +1082,7 @@ std::string STAmount::getFullText() const
% getExponent());
}
}
+#endif
Json::Value STAmount::getJson(int) const
{
@@ -1014,8 +1210,7 @@ BOOST_AUTO_TEST_CASE( NativeCurrency_test )
BOOST_AUTO_TEST_CASE( CustomCurrency_test )
{
- uint160 currency(1);
- STAmount zero(currency), one(currency, 1), hundred(currency, 100);
+ STAmount zero(CURRENCY_ONE, ACCOUNT_ONE), one(CURRENCY_ONE, ACCOUNT_ONE, 1), hundred(CURRENCY_ONE, ACCOUNT_ONE, 100);
serdes(one).getRaw();
@@ -1082,29 +1277,35 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test )
if (!(hundred != zero)) BOOST_FAIL("STAmount fail");
if (!(hundred != one)) BOOST_FAIL("STAmount fail");
if ((hundred != hundred)) BOOST_FAIL("STAmount fail");
- if (STAmount(currency).getText() != "0") BOOST_FAIL("STAmount fail");
- if (STAmount(currency,31).getText() != "31") BOOST_FAIL("STAmount fail");
- if (STAmount(currency,31,1).getText() != "310") BOOST_FAIL("STAmount fail");
- if (STAmount(currency,31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail");
- if (STAmount(currency,31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail");
+ if (STAmount(CURRENCY_ONE, ACCOUNT_ONE).getText() != "0") BOOST_FAIL("STAmount fail");
+ if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31).getText() != "31") BOOST_FAIL("STAmount fail");
+ if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,1).getText() != "310") BOOST_FAIL("STAmount fail");
+ if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail");
+ if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail");
- if (STAmount::multiply(STAmount(currency, 20), STAmount(3), currency).getText() != "60")
+ if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
- if (STAmount::multiply(STAmount(currency, 20), STAmount(3), uint160()).getText() != "60")
+ if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
- if (STAmount::multiply(STAmount(20), STAmount(3), currency).getText() != "60")
+ if (STAmount::multiply(STAmount(20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
- if (STAmount::multiply(STAmount(20), STAmount(3), uint160()).getText() != "60")
+ if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
- if (STAmount::divide(STAmount(currency, 60) , STAmount(3), currency).getText() != "20")
+ if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
- if (STAmount::divide(STAmount(currency, 60) , STAmount(3), uint160()).getText() != "20")
+ if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "20")
BOOST_FAIL("STAmount divide fail");
- if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), currency).getText() != "20")
+ if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
- if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20")
+ if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), uint160(), ACCOUNT_XNS).getText() != "20")
BOOST_FAIL("STAmount divide fail");
+ STAmount a1(CURRENCY_ONE, ACCOUNT_ONE, 60), a2 (CURRENCY_ONE, ACCOUNT_ONE, 10, -1);
+ if (STAmount::divide(a2, a1, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a1, a2)))
+ BOOST_FAIL("STAmount setRate(getRate) fail");
+ if (STAmount::divide(a1, a2, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a2, a1)))
+ BOOST_FAIL("STAmount setRate(getRate) fail");
+
BOOST_TEST_MESSAGE("Amount CC Complete");
}
@@ -1113,23 +1314,22 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests )
// Test currency multiplication and division operations such as
// convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded
- uint160 c(1);
if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
+ BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
- if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
- if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
- if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
- if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
- if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
- if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
- BOOST_FAIL("STAmount getrate fail");
+ BOOST_FAIL("STAmount getRate fail");
+ if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
+ BOOST_FAIL("STAmount getRate fail");
+ if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
+ BOOST_FAIL("STAmount getRate fail");
+ if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
+ BOOST_FAIL("STAmount getRate fail");
+ if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
+ BOOST_FAIL("STAmount getRate fail");
+ if (STAmount::getRate(STAmount(1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
+ BOOST_FAIL("STAmount getRate fail");
+ if (STAmount::getRate(STAmount(10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
+ BOOST_FAIL("STAmount getRate fail");
}
diff --git a/src/Application.cpp b/src/Application.cpp
index 89fe9d2ddc..2011ca8e78 100644
--- a/src/Application.cpp
+++ b/src/Application.cpp
@@ -36,9 +36,9 @@ DatabaseCon::~DatabaseCon()
}
Application::Application() :
- mUNL(mIOService),
+ mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService),
mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300),
- mSNTPClient(mIOService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
+ mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
mHashNodeDB(NULL), mNetNodeDB(NULL),
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL)
{
@@ -54,6 +54,7 @@ void Application::stop()
mIOService.stop();
mHashedObjectStore.bulkWrite();
mValidations.flush();
+ mAuxService.stop();
Log(lsINFO) << "Stopped: " << mIOService.stopped();
}
@@ -69,6 +70,12 @@ void Application::run()
if (!theConfig.DEBUG_LOGFILE.empty())
Log::setLogFile(theConfig.DEBUG_LOGFILE);
+ boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService));
+ auxThread.detach();
+
+ if (!theConfig.RUN_STANDALONE)
+ mSNTPClient.init(theConfig.SNTP_SERVERS);
+
//
// Construct databases.
//
@@ -89,12 +96,14 @@ void Application::run()
//
// Set up UNL.
//
- getUNL().nodeBootstrap();
+ if (!theConfig.RUN_STANDALONE)
+ getUNL().nodeBootstrap();
+
//
// Allow peer connections.
//
- if (!theConfig.PEER_IP.empty() && theConfig.PEER_PORT)
+ if (!theConfig.RUN_STANDALONE && !theConfig.PEER_IP.empty() && theConfig.PEER_PORT)
{
mPeerDoor = new PeerDoor(mIOService);
}
@@ -120,7 +129,8 @@ void Application::run()
//
// Begin connecting to network.
//
- mConnectionPool.start();
+ if (!theConfig.RUN_STANDALONE)
+ mConnectionPool.start();
// New stuff.
NewcoinAddress rootSeedMaster = NewcoinAddress::createSeedGeneric("masterpassphrase");
@@ -144,12 +154,18 @@ void Application::run()
secondLedger->setAccepted();
mMasterLedger.pushLedger(secondLedger, boost::make_shared(true, boost::ref(*secondLedger)));
assert(!!secondLedger->getAccountState(rootAddress));
- mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC());
+ mNetOps.setLastCloseTime(secondLedger->getCloseTimeNC());
}
- mSNTPClient.init(theConfig.SNTP_SERVERS);
- mNetOps.setStateTimer();
+ if (theConfig.RUN_STANDALONE)
+ {
+ Log(lsWARNING) << "Running in standalone mode";
+ mNetOps.setStandAlone();
+ mMasterLedger.runStandAlone();
+ }
+ else
+ mNetOps.setStateTimer();
mIOService.run(); // This blocks
diff --git a/src/Application.h b/src/Application.h
index 9efbc89fc1..8ab7f83ed2 100644
--- a/src/Application.h
+++ b/src/Application.h
@@ -39,7 +39,8 @@ public:
class Application
{
- boost::asio::io_service mIOService;
+ boost::asio::io_service mIOService, mAuxService;
+ boost::asio::io_service::work mIOWork, mAuxWork;
Wallet mWallet;
UniqueNodeList mUNL;
@@ -78,6 +79,7 @@ public:
NetworkOPs& getOPs() { return mNetOps; }
boost::asio::io_service& getIOService() { return mIOService; }
+ boost::asio::io_service& getAuxService() { return mAuxService; }
LedgerMaster& getMasterLedger() { return mMasterLedger; }
LedgerAcquireMaster& getMasterLedgerAcquire() { return mMasterLedgerAcquire; }
diff --git a/src/CallRPC.cpp b/src/CallRPC.cpp
index 38f697a1e7..50896b858c 100644
--- a/src/CallRPC.cpp
+++ b/src/CallRPC.cpp
@@ -112,7 +112,8 @@ Json::Value callRPC(const std::string& strMethod, const Json::Value& params)
"If the file does not exist, create it with owner-readable-only file permissions.");
// Connect to localhost
- std::cout << "Connecting to port:" << theConfig.RPC_PORT << std::endl;
+ std::cout << "Connecting to: " << theConfig.RPC_IP << ":" << theConfig.RPC_PORT << std::endl;
+
boost::asio::ip::tcp::endpoint
endpoint(boost::asio::ip::address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT);
boost::asio::ip::tcp::iostream stream;
diff --git a/src/CanonicalTXSet.cpp b/src/CanonicalTXSet.cpp
index c46c089374..e3af1e4870 100644
--- a/src/CanonicalTXSet.cpp
+++ b/src/CanonicalTXSet.cpp
@@ -37,7 +37,7 @@ bool CanonicalTXKey::operator>=(const CanonicalTXKey& key)const
return mTXid >= key.mTXid;
}
-void CanonicalTXSet::push_back(SerializedTransaction::pointer txn)
+void CanonicalTXSet::push_back(const SerializedTransaction::pointer& txn)
{
uint256 effectiveAccount = mSetHash;
effectiveAccount ^= txn->getSourceAccount().getAccountID().to256();
diff --git a/src/CanonicalTXSet.h b/src/CanonicalTXSet.h
index 6978859af7..3315625a3e 100644
--- a/src/CanonicalTXSet.h
+++ b/src/CanonicalTXSet.h
@@ -38,7 +38,7 @@ protected:
public:
CanonicalTXSet(const uint256& lclHash) : mSetHash(lclHash) { ; }
- void push_back(SerializedTransaction::pointer txn);
+ void push_back(const SerializedTransaction::pointer& txn);
iterator erase(const iterator& it);
iterator begin() { return mMap.begin(); }
diff --git a/src/Config.cpp b/src/Config.cpp
index cf9c135bfe..4e4cb8e910 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#define SECTION_ACCOUNT_PROBE_MAX "account_probe_max"
#define SECTION_DEBUG_LOGFILE "debug_logfile"
@@ -12,6 +13,7 @@
#define SECTION_FEE_DEFAULT "fee_default"
#define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create"
#define SECTION_FEE_OFFER "fee_offer"
+#define SECTION_FEE_OPERATION "fee_operation"
#define SECTION_IPS "ips"
#define SECTION_NETWORK_QUORUM "network_quorum"
#define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water"
@@ -37,6 +39,7 @@
#define DEFAULT_FEE_ACCOUNT_CREATE 1000
#define DEFAULT_FEE_NICKNAME_CREATE 1000
#define DEFAULT_FEE_OFFER DEFAULT_FEE_DEFAULT
+#define DEFAULT_FEE_OPERATION 1
Config theConfig;
@@ -145,11 +148,14 @@ void Config::setup(const std::string& strConf)
FEE_NICKNAME_CREATE = DEFAULT_FEE_NICKNAME_CREATE;
FEE_OFFER = DEFAULT_FEE_OFFER;
FEE_DEFAULT = DEFAULT_FEE_DEFAULT;
+ FEE_CONTRACT_OPERATION = DEFAULT_FEE_OPERATION;
ACCOUNT_PROBE_MAX = 10;
VALIDATORS_SITE = DEFAULT_VALIDATORS_SITE;
+ RUN_STANDALONE = false;
+
load();
}
@@ -230,19 +236,19 @@ void Config::load()
if (sectionSingleB(secConfig, SECTION_PEER_SCAN_INTERVAL_MIN, strTemp))
// Minimum for min is 60 seconds.
- PEER_SCAN_INTERVAL_MIN = MAX(60, boost::lexical_cast(strTemp));
+ PEER_SCAN_INTERVAL_MIN = std::max(60, boost::lexical_cast(strTemp));
if (sectionSingleB(secConfig, SECTION_PEER_START_MAX, strTemp))
- PEER_START_MAX = MAX(1, boost::lexical_cast(strTemp));
+ PEER_START_MAX = std::max(1, boost::lexical_cast(strTemp));
if (sectionSingleB(secConfig, SECTION_PEER_CONNECT_LOW_WATER, strTemp))
- PEER_CONNECT_LOW_WATER = MAX(1, boost::lexical_cast(strTemp));
+ PEER_CONNECT_LOW_WATER = std::max(1, boost::lexical_cast(strTemp));
if (sectionSingleB(secConfig, SECTION_NETWORK_QUORUM, strTemp))
- NETWORK_QUORUM = MAX(0, boost::lexical_cast(strTemp));
+ NETWORK_QUORUM = std::max(0, boost::lexical_cast(strTemp));
if (sectionSingleB(secConfig, SECTION_VALIDATION_QUORUM, strTemp))
- VALIDATION_QUORUM = MAX(0, boost::lexical_cast(strTemp));
+ VALIDATION_QUORUM = std::max(0, boost::lexical_cast(strTemp));
if (sectionSingleB(secConfig, SECTION_FEE_ACCOUNT_CREATE, strTemp))
FEE_ACCOUNT_CREATE = boost::lexical_cast(strTemp);
@@ -256,6 +262,9 @@ void Config::load()
if (sectionSingleB(secConfig, SECTION_FEE_DEFAULT, strTemp))
FEE_DEFAULT = boost::lexical_cast(strTemp);
+ if (sectionSingleB(secConfig, SECTION_FEE_OPERATION, strTemp))
+ FEE_CONTRACT_OPERATION = boost::lexical_cast(strTemp);
+
if (sectionSingleB(secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp))
ACCOUNT_PROBE_MAX = boost::lexical_cast(strTemp);
diff --git a/src/Config.h b/src/Config.h
index 585980b92b..6fc42dca35 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -63,6 +63,7 @@ public:
int LEDGER_PROPOSAL_DELAY_SECONDS;
int LEDGER_AVALANCHE_SECONDS;
bool LEDGER_CREATOR; // should be false unless we are starting a new ledger
+ bool RUN_STANDALONE;
// Note: The following parameters do not relate to the UNL or trust at all
unsigned int NETWORK_QUORUM; // Minimum number of nodes to consider the network present
@@ -96,6 +97,7 @@ public:
uint64 FEE_ACCOUNT_CREATE; // Fee to create an account.
uint64 FEE_NICKNAME_CREATE; // Fee to create a nickname.
uint64 FEE_OFFER; // Rate per day.
+ int FEE_CONTRACT_OPERATION; // fee for each contract operation
// Client behavior
int ACCOUNT_PROBE_MAX; // How far to scan for accounts.
diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp
index 2a7f38bb7e..6285d45551 100644
--- a/src/ConnectionPool.cpp
+++ b/src/ConnectionPool.cpp
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include "Config.h"
#include "Peer.h"
@@ -42,6 +43,9 @@ ConnectionPool::ConnectionPool(boost::asio::io_service& io_service) :
void ConnectionPool::start()
{
+ if (theConfig.RUN_STANDALONE)
+ return;
+
// Start running policy.
policyEnforce();
@@ -223,8 +227,9 @@ void ConnectionPool::policyHandler(const boost::system::error_code& ecResult)
// YYY: Should probably do this in the background.
// YYY: Might end up sending to disconnected peer?
-void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg)
+int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg)
{
+ int sentTo = 0;
boost::mutex::scoped_lock sl(mPeerLock);
BOOST_FOREACH(naPeer pair, mConnectedMap)
@@ -233,8 +238,13 @@ void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg)
if (!peer)
std::cerr << "CP::RM null peer in list" << std::endl;
else if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected())
+ {
+ ++sentTo;
peer->sendPacket(msg);
+ }
}
+
+ return sentTo;
}
// Schedule a connection via scanning.
@@ -243,6 +253,8 @@ void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg)
// Requires sane IP and port.
void ConnectionPool::connectTo(const std::string& strIp, int iPort)
{
+ if (theConfig.RUN_STANDALONE)
+ return;
{
Database* db = theApp->getWalletDB()->getDB();
ScopedLock sl(theApp->getWalletDB()->getDBLock());
@@ -334,7 +346,8 @@ std::vector ConnectionPool::getPeerVector()
// Now know peer's node public key. Determine if we want to stay connected.
// <-- bNew: false = redundant
-bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort)
+bool ConnectionPool::peerConnected(Peer::ref peer, const NewcoinAddress& naPeer,
+ const std::string& strIP, int iPort)
{
bool bNew = false;
@@ -392,7 +405,7 @@ bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& naP
}
// We maintain a map of public key to peer for connected and verified peers. Maintain it.
-void ConnectionPool::peerDisconnected(Peer::pointer peer, const NewcoinAddress& naPeer)
+void ConnectionPool::peerDisconnected(Peer::ref peer, const NewcoinAddress& naPeer)
{
if (naPeer.isValid())
{
@@ -479,7 +492,7 @@ bool ConnectionPool::peerScanSet(const std::string& strIp, int iPort)
}
// --> strIp: not empty
-void ConnectionPool::peerClosed(Peer::pointer peer, const std::string& strIp, int iPort)
+void ConnectionPool::peerClosed(Peer::ref peer, const std::string& strIp, int iPort)
{
ipPort ipPeer = make_pair(strIp, iPort);
bool bScanRefresh = false;
@@ -534,7 +547,7 @@ void ConnectionPool::peerClosed(Peer::pointer peer, const std::string& strIp, in
scanRefresh();
}
-void ConnectionPool::peerVerified(Peer::pointer peer)
+void ConnectionPool::peerVerified(Peer::ref peer)
{
if (mScanning && mScanning == peer)
{
@@ -639,7 +652,7 @@ void ConnectionPool::scanRefresh()
(void) mScanTimer.cancel();
- iInterval = MAX(iInterval, theConfig.PEER_SCAN_INTERVAL_MIN);
+ iInterval = std::max(iInterval, theConfig.PEER_SCAN_INTERVAL_MIN);
tpNext = tpNow + boost::posix_time::seconds(iInterval);
diff --git a/src/ConnectionPool.h b/src/ConnectionPool.h
index c71c59fef6..4db0239853 100644
--- a/src/ConnectionPool.h
+++ b/src/ConnectionPool.h
@@ -58,7 +58,7 @@ public:
void start();
// Send message to network.
- void relayMessage(Peer* fromPeer, PackedMessage::pointer msg);
+ int relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg);
// Manual connection request.
// Queue for immediate scanning.
@@ -72,16 +72,16 @@ public:
// We know peers node public key.
// <-- bool: false=reject
- bool peerConnected(Peer::pointer peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort);
+ bool peerConnected(Peer::ref peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort);
// No longer connected.
- void peerDisconnected(Peer::pointer peer, const NewcoinAddress& naPeer);
+ void peerDisconnected(Peer::ref peer, const NewcoinAddress& naPeer);
// As client accepted.
- void peerVerified(Peer::pointer peer);
+ void peerVerified(Peer::ref peer);
// As client failed connect and be accepted.
- void peerClosed(Peer::pointer peer, const std::string& strIp, int iPort);
+ void peerClosed(Peer::ref peer, const std::string& strIp, int iPort);
Json::Value getPeersJson();
std::vector getPeerVector();
@@ -98,11 +98,6 @@ public:
void policyLowWater();
void policyEnforce();
-#if 0
- //std::vector > mBroadcastMessages;
-
- bool isMessageKnown(PackedMessage::pointer msg);
-#endif
};
extern void splitIpPort(const std::string& strIpPort, std::string& strIp, int& iPort);
diff --git a/src/Contract.cpp b/src/Contract.cpp
new file mode 100644
index 0000000000..09c3a4ecfc
--- /dev/null
+++ b/src/Contract.cpp
@@ -0,0 +1,35 @@
+#include "Contract.h"
+#include "Interpreter.h"
+
+using namespace Script;
+/*
+JED: V III
+*/
+
+Contract::Contract()
+{
+
+}
+
+
+void Contract::executeCreate()
+{
+
+}
+void Contract::executeRemove()
+{
+
+}
+void Contract::executeFund()
+{
+
+}
+void Contract::executeAccept()
+{
+ //std::vector code;
+
+ //Interpreter interpreter;
+ //interpreter.interpret(this,code);
+}
+
+
diff --git a/src/Contract.h b/src/Contract.h
new file mode 100644
index 0000000000..76d30dc54a
--- /dev/null
+++ b/src/Contract.h
@@ -0,0 +1,30 @@
+#ifndef __CONTRACT__
+#define __CONTRACT__
+
+#include "SerializedLedger.h"
+#include
+#include "ScriptData.h"
+/*
+ Encapsulates the SLE for a Contract
+*/
+
+class Contract
+{
+public:
+ Contract();
+
+ uint160& getIssuer();
+ uint160& getOwner();
+ STAmount& getRippleEscrow();
+ uint32 getEscrow();
+ uint32 getBond();
+
+ Script::Data getData(int index);
+
+ void executeCreate();
+ void executeRemove();
+ void executeFund();
+ void executeAccept();
+};
+
+#endif
\ No newline at end of file
diff --git a/src/Conversion.cpp b/src/Conversion.cpp
deleted file mode 100644
index 7f9de9029b..0000000000
--- a/src/Conversion.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "Conversion.h"
-#include "base58.h"
-using namespace std;
-
-#if 0
-
-uint160 protobufTo160(const std::string& buf)
-{
- uint160 ret;
- // TODO:
- return(ret);
-}
-
-uint256 protobufTo256(const std::string& hash)
-{
- uint256 ret;
- // TODO:
- return(ret);
-}
-
-uint160 humanTo160(const std::string& buf)
-{
- vector retVec;
- DecodeBase58(buf,retVec);
- uint160 ret;
- memcpy(ret.begin(), &retVec[0], ret.GetSerializeSize());
-
-
- return(ret);
-}
-
-bool humanToPK(const std::string& buf,std::vector& retVec)
-{
- return(DecodeBase58(buf,retVec));
-}
-
-bool u160ToHuman(uint160& buf, std::string& retStr)
-{
- retStr=EncodeBase58(buf.begin(),buf.end());
- return(true);
-}
-
-#endif
-
-base_uint256 uint160::to256() const
-{
- uint256 m;
- memcpy(m.begin(), begin(), size());
- return m;
-}
diff --git a/src/Conversion.h b/src/Conversion.h
deleted file mode 100644
index c2ceb5339a..0000000000
--- a/src/Conversion.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "uint256.h"
-#include
-
-extern uint160 protobufTo160(const std::string& buf);
-extern uint256 protobufTo256(const std::string& hash);
-extern uint160 humanTo160(const std::string& buf);
-extern bool humanToPK(const std::string& buf,std::vector& retVec);
-
-
-extern bool u160ToHuman(uint160& buf, std::string& retStr);
-
diff --git a/src/DBInit.cpp b/src/DBInit.cpp
index 245b2c5f78..c0f7086b78 100644
--- a/src/DBInit.cpp
+++ b/src/DBInit.cpp
@@ -14,6 +14,7 @@ const char *TxnDBInit[] = {
LedgerSeq BIGINT UNSIGNED, \
Status CHARACTER(1), \
RawTxn BLOB \
+ TxnMeta BLOB \
);",
"CREATE TABLE PubKeys ( \
ID CHARACTER(35) PRIMARY KEY, \
@@ -56,7 +57,7 @@ const char *LedgerDBInit[] = {
LedgerHash CHARACTER(64), \
NodePubKey CHARACTER(56), \
Flags BIGINT UNSIGNED, \
- CloseTime BIGINT UNSIGNED, \
+ SignTime BIGINT UNSIGNED, \
Signature BLOB \
);",
"CREATE INDEX ValidationByHash ON \
diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp
new file mode 100644
index 0000000000..612d250c97
--- /dev/null
+++ b/src/FieldNames.cpp
@@ -0,0 +1,97 @@
+
+#include "FieldNames.h"
+
+#include