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

Conflicts:
	newcoin.vcxproj.filters
This commit is contained in:
jed
2012-10-04 02:32:31 -07:00
141 changed files with 13106 additions and 6483 deletions

6
.gitignore vendored
View File

@@ -16,6 +16,10 @@
*.o
obj/*
bin/newcoind
newcoind
# Ignore locally installed node_modules
node_modules
# Ignore tmp directory.
tmp

Binary file not shown.

Binary file not shown.

205
js/remote.js Normal file
View File

@@ -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

44
js/serializer.js Normal file
View File

@@ -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

137
js/utils.js Normal file
View File

@@ -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

View File

@@ -50,6 +50,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>BOOST_TEST_ALTERNATIVE_INIT_API;BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\OpenSSL\include;..\boost_1_47_0;..\protobuf-2.4.1\src\</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -101,21 +102,21 @@
<ClCompile Include="src\CanonicalTXSet.cpp" />
<ClCompile Include="src\Config.cpp" />
<ClCompile Include="src\ConnectionPool.cpp" />
<ClCompile Include="src\Contract.cpp" />
<ClCompile Include="src\Conversion.cpp" />
<ClCompile Include="src\DBInit.cpp" />
<ClCompile Include="src\DeterministicKeys.cpp" />
<ClCompile Include="src\ECIES.cpp" />
<ClCompile Include="src\HashedObject.cpp" />
<ClCompile Include="src\HttpsClient.cpp" />
<ClCompile Include="src\Interpreter.cpp" />
<ClCompile Include="src\Ledger.cpp" />
<ClCompile Include="src\LedgerAcquire.cpp" />
<ClCompile Include="src\LedgerConsensus.cpp" />
<ClCompile Include="src\LedgerEntrySet.cpp" />
<ClCompile Include="src\LedgerFormats.cpp" />
<ClCompile Include="src\LedgerHistory.cpp" />
<ClCompile Include="src\LedgerIndex.cpp" />
<ClCompile Include="src\LedgerMaster.cpp" />
<ClCompile Include="src\LedgerNode.cpp" />
<ClCompile Include="src\LedgerProposal.cpp" />
<ClCompile Include="src\LedgerTiming.cpp" />
<ClCompile Include="src\Log.cpp" />
@@ -123,19 +124,25 @@
<ClCompile Include="src\NetworkOPs.cpp" />
<ClCompile Include="src\NewcoinAddress.cpp" />
<ClCompile Include="src\NicknameState.cpp" />
<ClCompile Include="src\Operation.cpp" />
<ClCompile Include="src\OrderBook.cpp" />
<ClCompile Include="src\OrderBookDB.cpp" />
<ClCompile Include="src\PackedMessage.cpp" />
<ClCompile Include="src\ParseSection.cpp" />
<ClCompile Include="src\Pathfinder.cpp" />
<ClCompile Include="src\Peer.cpp" />
<ClCompile Include="src\PeerDoor.cpp" />
<ClCompile Include="src\PlatRand.cpp" />
<ClCompile Include="src\PubKeyCache.cpp" />
<ClCompile Include="src\RequestParser.cpp" />
<ClCompile Include="src\rfc1751.cpp" />
<ClCompile Include="src\RippleLines.cpp" />
<ClCompile Include="src\RippleState.cpp" />
<ClCompile Include="src\rpc.cpp" />
<ClCompile Include="src\RPCCommands.cpp" />
<ClCompile Include="src\RPCDoor.cpp" />
<ClCompile Include="src\RPCServer.cpp" />
<ClCompile Include="src\ScriptData.cpp" />
<ClCompile Include="src\SerializedLedger.cpp" />
<ClCompile Include="src\SerializedObject.cpp" />
<ClCompile Include="src\SerializedTransaction.cpp" />
@@ -146,6 +153,7 @@
<ClCompile Include="src\SHAMapDiff.cpp" />
<ClCompile Include="src\SHAMapNodes.cpp" />
<ClCompile Include="src\SHAMapSync.cpp" />
<ClCompile Include="src\SNTPClient.cpp" />
<ClCompile Include="src\Suppression.cpp" />
<ClCompile Include="src\Transaction.cpp" />
<ClCompile Include="src\TransactionEngine.cpp" />
@@ -188,11 +196,13 @@
<ClInclude Include="src\CanonicalTXSet.h" />
<ClInclude Include="src\Config.h" />
<ClInclude Include="src\ConnectionPool.h" />
<ClInclude Include="src\Contract.h" />
<ClInclude Include="src\Conversion.h" />
<ClInclude Include="src\HashedObject.h" />
<ClInclude Include="src\HttpReply.h" />
<ClInclude Include="src\HttpRequest.h" />
<ClInclude Include="src\HttpsClient.h" />
<ClInclude Include="src\Interpreter.h" />
<ClInclude Include="src\key.h" />
<ClInclude Include="src\Ledger.h" />
<ClInclude Include="src\LedgerAcquire.h" />
@@ -207,19 +217,25 @@
<ClInclude Include="src\NetworkStatus.h" />
<ClInclude Include="src\NewcoinAddress.h" />
<ClInclude Include="src\NicknameState.h" />
<ClInclude Include="src\Operation.h" />
<ClInclude Include="src\OrderBook.h" />
<ClInclude Include="src\OrderBookDB.h" />
<ClInclude Include="src\PackedMessage.h" />
<ClInclude Include="src\ParseSection.h" />
<ClInclude Include="src\Pathfinder.h" />
<ClInclude Include="src\Peer.h" />
<ClInclude Include="src\PeerDoor.h" />
<ClInclude Include="src\PubKeyCache.h" />
<ClInclude Include="src\RequestParser.h" />
<ClInclude Include="src\rfc1751.h" />
<ClInclude Include="src\RippleLines.h" />
<ClInclude Include="src\RippleState.h" />
<ClInclude Include="src\RPC.h" />
<ClInclude Include="src\RPCCommands.h" />
<ClInclude Include="src\RPCDoor.h" />
<ClInclude Include="src\RPCServer.h" />
<ClInclude Include="src\ScopedLock.h" />
<ClInclude Include="src\ScriptData.h" />
<ClInclude Include="src\SecureAllocator.h" />
<ClInclude Include="src\SerializedLedger.h" />
<ClInclude Include="src\SerializedObject.h" />
@@ -259,6 +275,13 @@
<None Include="validators.txt" />
<None Include="wallet.xml" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@@ -93,15 +93,9 @@
<ClCompile Include="src\LedgerHistory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\LedgerIndex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\LedgerMaster.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\LedgerNode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -273,6 +267,33 @@
<ClCompile Include="src\TransactionMeta.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SNTPClient.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Pathfinder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\RippleLines.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\OrderBookDB.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\OrderBook.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Contract.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Interpreter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ScriptData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Operation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="KnownNodeList.h">
@@ -503,6 +524,30 @@
<ClInclude Include="src\Wallet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Pathfinder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\RippleLines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\OrderBookDB.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\OrderBook.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Contract.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ScriptData.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Interpreter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Operation.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="wallet.xml" />
@@ -512,7 +557,6 @@
<None Include="SConstruct" />
<None Include="newcoind.cfg" />
<None Include="validators.txt" />
<None Include="README" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\newcoin.proto" />

View File

@@ -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=<path>:
# You may specify the location of this file with --conf=<path>. 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

View File

@@ -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<SerializedLedgerEntry>(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

View File

@@ -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; }

View File

@@ -3,6 +3,8 @@
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/test/unit_test.hpp>
#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<std::string> 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<int64>(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<uint64>(sAmount);
int64 a = sAmount.empty() ? 0 : lexical_cast_st<int64>(sAmount);
if (a >= 0)
uValue = static_cast<uint64>(a);
else
{
uValue = static_cast<uint64>(-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<uint64>(sAmount.substr(0, uDecimal)) : 0;
uint64 uFraction = iOffset ? boost::lexical_cast<uint64>(sAmount.substr(uDecimal+1)) : 0;
uint64 uInteger;
int64 iInteger = uDecimal ? lexical_cast_st<uint64>(sAmount.substr(0, uDecimal)) : 0;
if (iInteger >= 0)
uInteger = static_cast<uint64>(iInteger);
else
{
uInteger = static_cast<uint64>(-iInteger);
mIsNegative = true;
}
uint64 uFraction = iOffset ? lexical_cast_st<uint64>(sAmount.substr(uDecimal+1)) : 0;
// Scale the integer portion to the same offset as the fraction.
uValue = uInteger;
for (int i=-iOffset; i--;)
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<uint64>(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<uint64>(value);
}
else
{
mIsNegative = true;
mValue = static_cast<uint64>(-value);
}
return value >= 0
? STAmount(name, static_cast<uint64>(value), false)
: STAmount(name, static_cast<uint64>(-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<uint64>(mOffset + 97) << (64 - 10));
return mValue | (static_cast<uint64>(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<int>(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<std::string>(mValue);
else return boost::lexical_cast<std::string>(mValue);
if (mIsNegative) return std::string("-") + lexical_cast_i(mValue);
else return lexical_cast_i(mValue);
}
if (mIsNegative)
return mCurrency.GetHex() + ": -" +
boost::lexical_cast<std::string>(mValue) + "e" + boost::lexical_cast<std::string>(mOffset);
lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset);
else return mCurrency.GetHex() + ": " +
boost::lexical_cast<std::string>(mValue) + "e" + boost::lexical_cast<std::string>(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<std::string>(mValue);
else return boost::lexical_cast<std::string>(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<std::string>(mValue) +
"e" + boost::lexical_cast<std::string>(mOffset);
return std::string("-") + lexical_cast_i(mValue) +
"e" + lexical_cast_i(mOffset);
else
return boost::lexical_cast<std::string>(mValue) + "e" + boost::lexical_cast<std::string>(mOffset);
return lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset);
}
std::string val = "000000000000000000000000000";
val += boost::lexical_cast<std::string>(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<int64>(v));
return STAmount(getFName(), getSNValue() + static_cast<int64>(v));
}
STAmount STAmount::operator-(uint64 v) const
{
return STAmount(name, getSNValue() - static_cast<int64>(v));
return STAmount(getFName(), getSNValue() - static_cast<int64>(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<int64>(v1.mValue), vv2 = static_cast<int64>(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<int>(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<STAmount> s(dynamic_cast<STAmount*>(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");
}

View File

@@ -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<Ledger>(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

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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();

View File

@@ -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(); }

View File

@@ -5,6 +5,7 @@
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <iostream>
#include <algorithm>
#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<int>(strTemp));
PEER_SCAN_INTERVAL_MIN = std::max(60, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_PEER_START_MAX, strTemp))
PEER_START_MAX = MAX(1, boost::lexical_cast<int>(strTemp));
PEER_START_MAX = std::max(1, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_PEER_CONNECT_LOW_WATER, strTemp))
PEER_CONNECT_LOW_WATER = MAX(1, boost::lexical_cast<int>(strTemp));
PEER_CONNECT_LOW_WATER = std::max(1, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_NETWORK_QUORUM, strTemp))
NETWORK_QUORUM = MAX(0, boost::lexical_cast<int>(strTemp));
NETWORK_QUORUM = std::max(0, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_VALIDATION_QUORUM, strTemp))
VALIDATION_QUORUM = MAX(0, boost::lexical_cast<int>(strTemp));
VALIDATION_QUORUM = std::max(0, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_FEE_ACCOUNT_CREATE, strTemp))
FEE_ACCOUNT_CREATE = boost::lexical_cast<int>(strTemp);
@@ -256,6 +262,9 @@ void Config::load()
if (sectionSingleB(secConfig, SECTION_FEE_DEFAULT, strTemp))
FEE_DEFAULT = boost::lexical_cast<int>(strTemp);
if (sectionSingleB(secConfig, SECTION_FEE_OPERATION, strTemp))
FEE_CONTRACT_OPERATION = boost::lexical_cast<int>(strTemp);
if (sectionSingleB(secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp))
ACCOUNT_PROBE_MAX = boost::lexical_cast<int>(strTemp);

View File

@@ -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.

View File

@@ -6,6 +6,7 @@
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <algorithm>
#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<Peer::pointer> 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);

View File

@@ -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<Peer::pointer> getPeerVector();
@@ -98,11 +98,6 @@ public:
void policyLowWater();
void policyEnforce();
#if 0
//std::vector<std::pair<PackedMessage::pointer,int> > mBroadcastMessages;
bool isMessageKnown(PackedMessage::pointer msg);
#endif
};
extern void splitIpPort(const std::string& strIpPort, std::string& strIp, int& iPort);

35
src/Contract.cpp Normal file
View File

@@ -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<char> code;
//Interpreter interpreter;
//interpreter.interpret(this,code);
}

30
src/Contract.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef __CONTRACT__
#define __CONTRACT__
#include "SerializedLedger.h"
#include <boost/shared_ptr.hpp>
#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

View File

@@ -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<unsigned char> retVec;
DecodeBase58(buf,retVec);
uint160 ret;
memcpy(ret.begin(), &retVec[0], ret.GetSerializeSize());
return(ret);
}
bool humanToPK(const std::string& buf,std::vector<unsigned char>& 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;
}

View File

@@ -1,11 +0,0 @@
#include "uint256.h"
#include <string>
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<unsigned char>& retVec);
extern bool u160ToHuman(uint160& buf, std::string& retStr);

View File

@@ -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 \

97
src/FieldNames.cpp Normal file
View File

@@ -0,0 +1,97 @@
#include "FieldNames.h"
#include <map>
#include <boost/thread/mutex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
// These must stay at the top of this file
std::map<int, SField::ptr> SField::codeToField;
boost::mutex SField::mapMutex;
SField sfInvalid(-1), sfGeneric(0);
SField sfLedgerEntry(FIELD_CODE(STI_LEDGERENTRY, 1), STI_LEDGERENTRY, 1, "LedgerEntry");
SField sfTransaction(FIELD_CODE(STI_TRANSACTION, 1), STI_TRANSACTION, 1, "Transaction");
SField sfValidation(FIELD_CODE(STI_VALIDATION, 1), STI_VALIDATION, 1, "Validation");
#define FIELD(name, type, index) SField sf##name(FIELD_CODE(STI_##type, index), STI_##type, index, #name);
#define TYPE(name, type, index)
#include "SerializeProto.h"
#undef FIELD
#undef TYPE
SField::ref SField::getField(int code)
{
int type = code >> 16;
int field = code % 0xffff;
if ((type <= 0) || (type >= 256) || (field <= 0) || (field >= 256))
return sfInvalid;
boost::mutex::scoped_lock sl(mapMutex);
std::map<int, SField::ptr>::iterator it = codeToField.find(code);
if (it != codeToField.end())
return *(it->second);
switch (type)
{ // types we are willing to dynamically extend
#define FIELD(name, type, index)
#define TYPE(name, type, index) case STI_##type:
#include "SerializeProto.h"
#undef FIELD
#undef TYPE
break;
default:
return sfInvalid;
}
return *(new SField(code, static_cast<SerializedTypeID>(type), field, NULL));
}
int SField::compare(SField::ref f1, SField::ref f2)
{ // -1 = f1 comes before f2, 0 = illegal combination, 1 = f1 comes after f2
if ((f1.fieldCode <= 0) || (f2.fieldCode <= 0))
return 0;
if (f1.fieldCode < f2.fieldCode)
return -1;
if (f2.fieldCode < f1.fieldCode)
return 1;
return 0;
}
SField::ref SField::getField(int type, int value)
{
return getField(FIELD_CODE(type, value));
}
std::string SField::getName() const
{
if (!fieldName.empty())
return fieldName;
if (fieldValue == 0)
return "";
return boost::lexical_cast<std::string>(static_cast<int>(fieldType)) + "/" +
boost::lexical_cast<std::string>(fieldValue);
}
SField::ref SField::getField(const std::string& fieldName)
{ // OPTIMIZEME me with a map. CHECKME this is case sensitive
boost::mutex::scoped_lock sl(mapMutex);
typedef std::pair<const int, SField::ptr> int_sfref_pair;
BOOST_FOREACH(const int_sfref_pair& fieldPair, codeToField)
{
if (fieldPair.second->fieldName == fieldName)
return *(fieldPair.second);
}
return sfInvalid;
}

85
src/FieldNames.h Normal file
View File

@@ -0,0 +1,85 @@
#ifndef __FIELDNAMES__
#define __FIELDNAMES__
#include <string>
#include <boost/thread/mutex.hpp>
#define FIELD_CODE(type, index) ((static_cast<int>(type) << 16) | index)
enum SerializedTypeID
{
// special types
STI_UNKNOWN = -2,
STI_DONE = -1,
STI_NOTPRESENT = 0,
#define TYPE(name, field, value) STI_##field = value,
#define FIELD(name, field, value)
#include "SerializeProto.h"
#undef TYPE
#undef FIELD
// high level types
STI_TRANSACTION = 10001,
STI_LEDGERENTRY = 10002,
STI_VALIDATION = 10003,
};
enum SOE_Flags
{
SOE_INVALID = -1,
SOE_REQUIRED = 0, // required
SOE_OPTIONAL = 1, // optional
};
class SField
{
public:
typedef const SField& ref;
typedef SField const * ptr;
protected:
static std::map<int, ptr> codeToField;
static boost::mutex mapMutex;
public:
const int fieldCode; // (type<<16)|index
const SerializedTypeID fieldType; // STI_*
const int fieldValue; // Code number for protocol
std::string fieldName;
SField(int fc, SerializedTypeID tid, int fv, const char* fn) :
fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn)
{ codeToField[fc] = this; }
SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0) { ; }
static SField::ref getField(int fieldCode);
static SField::ref getField(int fieldType, int fieldValue);
static SField::ref getField(const std::string& fieldName);
static SField::ref getField(SerializedTypeID type, int value) { return getField(FIELD_CODE(type, value)); }
std::string getName() const;
bool hasName() const { return !fieldName.empty(); }
bool isGeneric() const { return fieldCode == 0; }
bool isInvalid() const { return fieldCode == -1; }
bool isKnown() const { return fieldType != STI_UNKNOWN; }
bool operator==(const SField& f) const { return fieldCode == f.fieldCode; }
bool operator!=(const SField& f) const { return fieldCode != f.fieldCode; }
static int compare(SField::ref f1, SField::ref f2);
};
extern SField sfInvalid, sfGeneric, sfLedgerEntry, sfTransaction, sfValidation;
#define FIELD(name, type, index) extern SField sf##name;
#define TYPE(name, type, index)
#include "SerializeProto.h"
#undef FIELD
#undef TYPE
#endif

View File

@@ -2,6 +2,7 @@
#include "HashedObject.h"
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
#include "Serializer.h"
#include "Application.h"
@@ -21,7 +22,9 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
if (!theApp->getHashNodeDB()) return true;
if (mCache.touch(hash))
{
Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: incache";
#ifdef HS_DEBUG
Log(lsTRACE) << "HOS: " << hash << " store: incache";
#endif
return false;
}
@@ -37,7 +40,6 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
t.detach();
}
}
Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: deferred";
return true;
}
@@ -62,23 +64,22 @@ void HashedObjectStore::bulkWrite()
db->executeSQL("BEGIN TRANSACTION;");
for (std::vector< boost::shared_ptr<HashedObject> >::iterator it = set.begin(), end = set.end(); it != end; ++it)
BOOST_FOREACH(const boost::shared_ptr<HashedObject>& it, set)
{
HashedObject& obj = **it;
if (!SQL_EXISTS(db, boost::str(fExists % obj.getHash().GetHex())))
if (!SQL_EXISTS(db, boost::str(fExists % it->getHash().GetHex())))
{
char type;
switch(obj.getType())
switch(it->getType())
{
case LEDGER: type = 'L'; break;
case TRANSACTION: type = 'T'; break;
case ACCOUNT_NODE: type = 'A'; break;
case TRANSACTION_NODE: type = 'N'; break;
default: type = 'U';
case hotLEDGER: type= 'L'; break;
case hotTRANSACTION: type = 'T'; break;
case hotACCOUNT_NODE: type = 'A'; break;
case hotTRANSACTION_NODE: type = 'N'; break;
default: type = 'U';
}
std::string rawData;
db->escape(&(obj.getData().front()), obj.getData().size(), rawData);
db->executeSQL(boost::str(fAdd % obj.getHash().GetHex() % type % obj.getIndex() % rawData ));
db->escape(&(it->getData().front()), it->getData().size(), rawData);
db->executeSQL(boost::str(fAdd % it->getHash().GetHex() % type % it->getIndex() % rawData ));
}
}
@@ -93,7 +94,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
obj = mCache.fetch(hash);
if (obj)
{
Log(lsTRACE) << "HOS: " << hash.GetHex() << " fetch: incache";
Log(lsTRACE) << "HOS: " << hash << " fetch: incache";
return obj;
}
}
@@ -103,8 +104,6 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
sql.append(hash.GetHex());
sql.append("';");
std::string type;
uint32 index;
std::vector<unsigned char> data;
{
ScopedLock sl(theApp->getHashNodeDB()->getDBLock());
@@ -112,7 +111,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
if (!db->executeSQL(sql) || !db->startIterRows())
{
Log(lsTRACE) << "HOS: " << hash.GetHex() << " fetch: not in db";
Log(lsTRACE) << "HOS: " << hash << " fetch: not in db";
return HashedObject::pointer();
}
@@ -120,7 +119,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
db->getStr("ObjType", type);
if (type.size() == 0) return HashedObject::pointer();
index = db->getBigInt("LedgerIndex");
uint32 index = db->getBigInt("LedgerIndex");
int size = db->getBinary("Object", NULL, 0);
data.resize(size);
@@ -129,13 +128,13 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
assert(Serializer::getSHA512Half(data) == hash);
HashedObjectType htype = UNKNOWN;
switch(type[0])
HashedObjectType htype = hotUNKNOWN;
switch (type[0])
{
case 'L': htype = LEDGER; break;
case 'T': htype = TRANSACTION; break;
case 'A': htype = ACCOUNT_NODE; break;
case 'N': htype = TRANSACTION_NODE; break;
case 'L': htype = hotLEDGER; break;
case 'T': htype = hotTRANSACTION; break;
case 'A': htype = hotACCOUNT_NODE; break;
case 'N': htype = hotTRANSACTION_NODE; break;
default:
Log(lsERROR) << "Invalid hashed object";
return HashedObject::pointer();
@@ -144,7 +143,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
obj = boost::make_shared<HashedObject>(htype, index, data, hash);
mCache.canonicalize(hash, obj);
}
Log(lsTRACE) << "HOS: " << hash.GetHex() << " fetch: in db";
Log(lsTRACE) << "HOS: " << hash << " fetch: in db";
return obj;
}

View File

@@ -10,11 +10,11 @@
enum HashedObjectType
{
UNKNOWN = 0,
LEDGER = 1,
TRANSACTION = 2,
ACCOUNT_NODE = 3,
TRANSACTION_NODE = 4
hotUNKNOWN = 0,
hotLEDGER = 1,
hotTRANSACTION = 2,
hotACCOUNT_NODE = 3,
hotTRANSACTION_NODE = 4
};
class HashedObject

200
src/Interpreter.cpp Normal file
View File

@@ -0,0 +1,200 @@
#include "Interpreter.h"
#include "Operation.h"
#include "Config.h"
/*
We also need to charge for each op
*/
namespace Script {
Interpreter::Interpreter()
{
mContract=NULL;
mCode=NULL;
mInstructionPointer=0;
mTotalFee=0;
mInBlock=false;
mBlockSuccess=true;
mBlockJump=0;
mFunctionTable.resize(NUM_OF_OPS);
/*
mFunctionTable[INT_OP]=new IntOp();
mFunctionTable[FLOAT_OP]=new FloatOp();
mFunctionTable[UINT160_OP]=new Uint160Op();
mFunctionTable[BOOL_OP]=new Uint160Op();
mFunctionTable[PATH_OP]=new Uint160Op();
mFunctionTable[ADD_OP]=new AddOp();
mFunctionTable[SUB_OP]=new SubOp();
mFunctionTable[MUL_OP]=new MulOp();
mFunctionTable[DIV_OP]=new DivOp();
mFunctionTable[MOD_OP]=new ModOp();
mFunctionTable[GTR_OP]=new GtrOp();
mFunctionTable[LESS_OP]=new LessOp();
mFunctionTable[EQUAL_OP]=new SubOp();
mFunctionTable[NOT_EQUAL_OP]=new SubOp();
mFunctionTable[AND_OP]=new SubOp();
mFunctionTable[OR_OP]=new SubOp();
mFunctionTable[NOT_OP]=new SubOp();
mFunctionTable[JUMP_OP]=new SubOp();
mFunctionTable[JUMPIF_OP]=new SubOp();
mFunctionTable[STOP_OP]=new SubOp();
mFunctionTable[CANCEL_OP]=new SubOp();
mFunctionTable[BLOCK_OP]=new SubOp();
mFunctionTable[BLOCK_END_OP]=new SubOp();
mFunctionTable[SEND_XNS_OP]=new SendXNSOp();
mFunctionTable[SEND_OP]=new SendOp();
mFunctionTable[REMOVE_CONTRACT_OP]=new SubOp();
mFunctionTable[FEE_OP]=new SubOp();
mFunctionTable[CHANGE_CONTRACT_OWNER_OP]=new SubOp();
mFunctionTable[STOP_REMOVE_OP]=new SubOp();
mFunctionTable[SET_DATA_OP]=new SubOp();
mFunctionTable[GET_DATA_OP]=new SubOp();
mFunctionTable[GET_NUM_DATA_OP]=new SubOp();
mFunctionTable[SET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_ISSUER_ID_OP]=new SubOp();
mFunctionTable[GET_OWNER_ID_OP]=new SubOp();
mFunctionTable[GET_LEDGER_TIME_OP]=new SubOp();
mFunctionTable[GET_LEDGER_NUM_OP]=new SubOp();
mFunctionTable[GET_RAND_FLOAT_OP]=new SubOp();
mFunctionTable[GET_XNS_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_CURRENCY_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_ISSUER]=new GetRippleEscrowedIssuerOp();
mFunctionTable[GET_ACCEPT_DATA_OP]=new AcceptDataOp();
mFunctionTable[GET_ACCEPTOR_ID_OP]=new GetAcceptorIDOp();
mFunctionTable[GET_CONTRACT_ID_OP]=new GetContractIDOp();
*/
}
Data::pointer Interpreter::popStack()
{
if(mStack.size())
{
Data::pointer item=mStack[mStack.size()-1];
mStack.pop_back();
return(item);
}else
{
return(Data::pointer(new ErrorData()));
}
}
void Interpreter::pushStack(Data::pointer data)
{
mStack.push_back(data);
}
// offset is where to jump to if the block fails
bool Interpreter::startBlock(int offset)
{
if(mInBlock) return(false); // can't nest blocks
mBlockSuccess=true;
mInBlock=true;
mBlockJump=offset+mInstructionPointer;
return(true);
}
bool Interpreter::endBlock()
{
if(!mInBlock) return(false);
mInBlock=false;
mBlockJump=0;
pushStack(Data::pointer(new BoolData(mBlockSuccess)));
return(true);
}
TER Interpreter::interpret(Contract* contract,const SerializedTransaction& txn,std::vector<unsigned char>& code)
{
mContract=contract;
mCode=&code;
mTotalFee=0;
mInstructionPointer=0;
while(mInstructionPointer<code.size())
{
unsigned int fun=(*mCode)[mInstructionPointer];
mInstructionPointer++;
if(fun>=mFunctionTable.size())
{
// TODO: log
return(temMALFORMED); // TODO: is this actually what we want to do?
}
mTotalFee += mFunctionTable[ fun ]->getFee();
if(mTotalFee>txn.getTransactionFee().getNValue())
{
// TODO: log
return(telINSUF_FEE_P);
}else
{
if(!mFunctionTable[ fun ]->work(this))
{
// TODO: log
return(temMALFORMED); // TODO: is this actually what we want to do?
}
}
}
return(tesSUCCESS);
}
Data::pointer Interpreter::getIntData()
{
int value=0; // TODO
mInstructionPointer += 4;
return(Data::pointer(new IntData(value)));
}
Data::pointer Interpreter::getFloatData()
{
float value=0; // TODO
mInstructionPointer += 4;
return(Data::pointer(new FloatData(value)));
}
Data::pointer Interpreter::getUint160Data()
{
uint160 value; // TODO
mInstructionPointer += 20;
return(Data::pointer(new Uint160Data(value)));
}
bool Interpreter::jumpTo(int offset)
{
mInstructionPointer += offset;
if( (mInstructionPointer<0) || (mInstructionPointer>mCode->size()) )
{
mInstructionPointer -= offset;
return(false);
}
return(true);
}
void Interpreter::stop()
{
mInstructionPointer=mCode->size();
}
Data::pointer Interpreter::getContractData(int index)
{
return(Data::pointer(new ErrorData()));
}
bool Interpreter::canSign(const uint160& signer)
{
return(true);
}
} // end namespace

82
src/Interpreter.h Normal file
View File

@@ -0,0 +1,82 @@
#ifndef __INTERPRETER__
#define __INTERPRETER__
#include "uint256.h"
#include "Contract.h"
#include <boost/shared_ptr.hpp>
#include <vector>
#include "ScriptData.h"
#include "TransactionEngine.h"
namespace Script {
class Operation;
// Contracts are non typed have variable data types
class Interpreter
{
std::vector<Operation*> mFunctionTable;
std::vector<Data::pointer> mStack;
Contract* mContract;
std::vector<unsigned char>* mCode;
unsigned int mInstructionPointer;
int mTotalFee;
bool mInBlock;
int mBlockJump;
bool mBlockSuccess;
public:
enum { INT_OP=1,FLOAT_OP,UINT160_OP,BOOL_OP,PATH_OP,
ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP,
GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP,
AND_OP,OR_OP,NOT_OP,
JUMP_OP, JUMPIF_OP,
STOP_OP, CANCEL_OP,
BLOCK_OP, BLOCK_END_OP,
SEND_XNS_OP,SEND_OP,REMOVE_CONTRACT_OP,FEE_OP,CHANGE_CONTRACT_OWNER_OP,
STOP_REMOVE_OP,
SET_DATA_OP,GET_DATA_OP, GET_NUM_DATA_OP,
SET_REGISTER_OP,GET_REGISTER_OP,
GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP,
GET_XNS_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER,
GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP,
NUM_OF_OPS };
Interpreter();
// returns a TransactionEngineResult
TER interpret(Contract* contract,const SerializedTransaction& txn,std::vector<unsigned char>& code);
void stop();
bool canSign(const uint160& signer);
int getInstructionPointer(){ return(mInstructionPointer); }
void setInstructionPointer(int n){ mInstructionPointer=n;}
Data::pointer popStack();
void pushStack(Data::pointer data);
bool jumpTo(int offset);
bool startBlock(int offset);
bool endBlock();
Data::pointer getIntData();
Data::pointer getFloatData();
Data::pointer getUint160Data();
Data::pointer getAcceptData(int index);
Data::pointer getContractData(int index);
};
} // end namespace
#endif

View File

@@ -13,22 +13,22 @@
#include "../obj/src/newcoin.pb.h"
#include "PackedMessage.h"
#include "Config.h"
#include "Conversion.h"
#include "BitcoinUtil.h"
#include "Wallet.h"
#include "LedgerTiming.h"
#include "HashPrefixes.h"
#include "Log.h"
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(0),
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1),
mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap())
{
// special case: put coins in root account
AccountState::pointer startAccount = boost::make_shared<AccountState>(masterID);
startAccount->peekSLE().setIFieldAmount(sfBalance, startAmount);
startAccount->peekSLE().setIFieldU32(sfSequence, 1);
startAccount->peekSLE().setFieldAmount(sfBalance, startAmount);
startAccount->peekSLE().setFieldU32(sfSequence, 1);
writeBack(lepCREATE, startAccount->getSLE());
#if 0
std::cerr << "Root account:";
@@ -57,7 +57,7 @@ Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mL
}
Ledger::Ledger(bool dummy, Ledger& prevLedger) :
Ledger::Ledger(bool /* dummy */, Ledger& prevLedger) :
mTotCoins(prevLedger.mTotCoins), mLedgerSeq(prevLedger.mLedgerSeq + 1),
mParentCloseTime(prevLedger.mCloseTime), mCloseResolution(prevLedger.mCloseResolution),
mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
@@ -71,7 +71,7 @@ Ledger::Ledger(bool dummy, Ledger& prevLedger) :
prevLedger.getCloseAgree(), mLedgerSeq);
if (prevLedger.mCloseTime == 0)
{
mCloseTime = theApp->getOPs().getCloseTimeNC();
mCloseTime = theApp->getOPs().getCloseTimeNC() - mCloseResolution;
mCloseTime -= (mCloseTime % mCloseResolution);
}
else
@@ -153,7 +153,7 @@ void Ledger::setAccepted(uint32 closeTime, int closeResolution, bool correctClos
void Ledger::setAccepted()
{ // used when we acquired the ledger
assert(mClosed && (mCloseResolution != 0) && (mCloseResolution != 0));
// FIXME assert(mClosed && (mCloseTime != 0) && (mCloseResolution != 0));
mCloseTime -= mCloseTime % mCloseResolution;
updateHash();
mAccepted = true;
@@ -177,7 +177,7 @@ AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
SerializedLedgerEntry::pointer sle =
boost::make_shared<SerializedLedgerEntry>(item->peekSerializer(), item->getTag());
if (sle->getType() != ltACCOUNT_ROOT) return AccountState::pointer();
return boost::make_shared<AccountState>(sle);
return boost::make_shared<AccountState>(sle,accountID);
}
NicknameState::pointer Ledger::getNicknameState(const uint256& uNickname)
@@ -210,35 +210,51 @@ RippleState::pointer Ledger::accessRippleState(const uint256& uNode)
return boost::make_shared<RippleState>(sle);
}
bool Ledger::addTransaction(Transaction::pointer trans)
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn)
{ // low-level - just add to table
assert(!mAccepted);
assert(trans->getID().isNonZero());
Serializer s;
trans->getSTransaction()->add(s);
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(trans->getID(), s.peekData());
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, txn.peekData());
if (!mTransactionMap->addGiveItem(item, true, false))
return false;
return true;
}
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn)
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn, const Serializer& md)
{ // low-level - just add to table
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, txn.peekData());
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
Serializer s(txn.getDataLength() + md.getDataLength() + 64);
s.addVL(txn.peekData());
s.addVL(md.peekData());
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, s.peekData());
if (!mTransactionMap->addGiveItem(item, true, true))
return false;
return true;
}
Transaction::pointer Ledger::getTransaction(const uint256& transID) const
{
SHAMapItem::pointer item = mTransactionMap->peekItem(transID);
SHAMapTreeNode::TNType type;
SHAMapItem::pointer item = mTransactionMap->peekItem(transID, type);
if (!item) return Transaction::pointer();
Transaction::pointer txn = theApp->getMasterTransaction().fetch(transID, false);
if (txn) return txn;
if (txn)
return txn;
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
txn = Transaction::sharedTransaction(item->getData(), true);
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
{
std::vector<unsigned char> txnData;
int txnLength;
if (!item->peekSerializer().getVL(txnData, 0, txnLength))
return Transaction::pointer();
txn = Transaction::sharedTransaction(txnData, false);
}
else
{
assert(false);
return Transaction::pointer();
}
txn = Transaction::sharedTransaction(item->getData(), true);
if (txn->getStatus() == NEW)
txn->setStatus(mClosed ? COMMITTED : INCLUDED, mLedgerSeq);
@@ -246,6 +262,39 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) const
return txn;
}
bool Ledger::getTransaction(const uint256& txID, Transaction::pointer& txn, TransactionMetaSet::pointer& meta)
{
SHAMapTreeNode::TNType type;
SHAMapItem::pointer item = mTransactionMap->peekItem(txID, type);
if (!item)
return false;
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
{ // in tree with no metadata
txn = theApp->getMasterTransaction().fetch(txID, false);
meta = TransactionMetaSet::pointer();
if (!txn)
txn = Transaction::sharedTransaction(item->getData(), true);
}
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
{ // in tree with metadata
SerializerIterator it(item->getData());
txn = theApp->getMasterTransaction().fetch(txID, false);
if (!txn)
txn = Transaction::sharedTransaction(it.getVL(), true);
else
it.getVL(); // skip transaction
meta = boost::make_shared<TransactionMetaSet>(mLedgerSeq, it.getVL());
}
else
return false;
if (txn->getStatus() == NEW)
txn->setStatus(mClosed ? COMMITTED : INCLUDED, mLedgerSeq);
theApp->getMasterTransaction().canonicalize(txn, false);
return true;
}
bool Ledger::unitTest()
{
return true;
@@ -257,7 +306,7 @@ uint256 Ledger::getHash()
return(mHash);
}
void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
void Ledger::saveAcceptedLedger(Ledger::ref ledger)
{
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;");
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;");
@@ -278,9 +327,9 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
ledger->mAccountHash.GetHex() % ledger->mTransHash.GetHex()));
// write out dirty nodes
while(ledger->mTransactionMap->flushDirty(256, TRANSACTION_NODE, ledger->mLedgerSeq))
while(ledger->mTransactionMap->flushDirty(256, hotTRANSACTION_NODE, ledger->mLedgerSeq))
{ ; }
while(ledger->mAccountStateMap->flushDirty(256, ACCOUNT_NODE, ledger->mLedgerSeq))
while(ledger->mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, ledger->mLedgerSeq))
{ ; }
ledger->disarmDirty();
@@ -416,34 +465,60 @@ void Ledger::addJson(Json::Value& ret, int options)
bool full = (options & LEDGER_JSON_FULL) != 0;
if(mClosed || full)
{
if (mClosed)
ledger["closed"] = true;
ledger["hash"] = mHash.GetHex();
ledger["transactionHash"] = mTransHash.GetHex();
ledger["accountHash"] = mAccountHash.GetHex();
if (mClosed) ledger["closed"] = true;
ledger["accepted"] = mAccepted;
ledger["totalCoins"] = boost::lexical_cast<std::string>(mTotCoins);
if ((mCloseFlags & sLCF_NoConsensusTime) != 0)
ledger["closeTimeEstimate"] = mCloseTime;
else
if (mCloseTime != 0)
{
ledger["closeTime"] = mCloseTime;
ledger["closeTimeResolution"] = mCloseResolution;
if ((mCloseFlags & sLCF_NoConsensusTime) != 0)
ledger["closeTimeEstimate"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime));
else
{
ledger["closeTime"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime));
ledger["closeTimeResolution"] = mCloseResolution;
}
}
}
else ledger["closed"] = false;
if (mCloseTime != 0)
ledger["closeTime"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime));
else
ledger["closed"] = false;
if (mTransactionMap && (full || ((options & LEDGER_JSON_DUMP_TXNS) != 0)))
{
Json::Value txns(Json::arrayValue);
for (SHAMapItem::pointer item = mTransactionMap->peekFirstItem(); !!item;
item = mTransactionMap->peekNextItem(item->getTag()))
SHAMapTreeNode::TNType type;
for (SHAMapItem::pointer item = mTransactionMap->peekFirstItem(type); !!item;
item = mTransactionMap->peekNextItem(item->getTag(), type))
{
if (full)
{
SerializerIterator sit(item->peekSerializer());
SerializedTransaction txn(sit);
txns.append(txn.getJson(0));
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
{
SerializerIterator sit(item->peekSerializer());
SerializedTransaction txn(sit);
txns.append(txn.getJson(0));
}
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
{
SerializerIterator sit(item->peekSerializer());
Serializer sTxn(sit.getVL());
SerializerIterator tsit(sTxn);
SerializedTransaction txn(tsit);
TransactionMetaSet meta(mLedgerSeq, sit.getVL());
Json::Value txJson = txn.getJson(0);
txJson["metaData"] = meta.getJson(0);
txns.append(txJson);
}
else
{
Json::Value error = Json::objectValue;
error[item->getTag().GetHex()] = type;
txns.append(error);
}
}
else txns.append(item->getTag().GetHex());
}
@@ -503,4 +578,345 @@ void Ledger::setCloseTime(boost::posix_time::ptime ptm)
mCloseTime = iToSeconds(ptm);
}
// XXX Use shared locks where possible?
LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::ref entry)
{
ScopedLock l(mAccountStateMap->Lock());
bool create = false;
if (!mAccountStateMap->hasItem(entry->getIndex()))
{
if ((parms & lepCREATE) == 0)
{
Log(lsERROR) << "WriteBack non-existent node without create";
return lepMISSING;
}
create = true;
}
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(entry->getIndex());
entry->add(item->peekSerializer());
if (create)
{
assert(!mAccountStateMap->hasItem(entry->getIndex()));
if(!mAccountStateMap->addGiveItem(item, false, false)) // FIXME: TX metadata
{
assert(false);
return lepERROR;
}
return lepCREATED;
}
if (!mAccountStateMap->updateGiveItem(item, false, false)) // FIXME: TX metadata
{
assert(false);
return lepERROR;
}
return lepOKAY;
}
SLE::pointer Ledger::getSLE(const uint256& uHash)
{
SHAMapItem::pointer node = mAccountStateMap->peekItem(uHash);
if (!node)
return SLE::pointer();
return boost::make_shared<SLE>(node->peekSerializer(), node->getTag());
}
uint256 Ledger::getFirstLedgerIndex()
{
SHAMapItem::pointer node = mAccountStateMap->peekFirstItem();
return node ? node->getTag() : uint256();
}
uint256 Ledger::getLastLedgerIndex()
{
SHAMapItem::pointer node = mAccountStateMap->peekLastItem();
return node ? node->getTag() : uint256();
}
uint256 Ledger::getNextLedgerIndex(const uint256& uHash)
{
SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash);
return node ? node->getTag() : uint256();
}
uint256 Ledger::getNextLedgerIndex(const uint256& uHash, const uint256& uEnd)
{
SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash);
if ((!node) || (node->getTag() > uEnd))
return uint256();
return node->getTag();
}
uint256 Ledger::getPrevLedgerIndex(const uint256& uHash)
{
SHAMapItem::pointer node = mAccountStateMap->peekPrevItem(uHash);
return node ? node->getTag() : uint256();
}
uint256 Ledger::getPrevLedgerIndex(const uint256& uHash, const uint256& uBegin)
{
SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash);
if ((!node) || (node->getTag() < uBegin))
return uint256();
return node->getTag();
}
SLE::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID,
LedgerEntryType let )
{
SHAMapItem::pointer account = mAccountStateMap->peekItem(nodeID);
if (!account)
{
if ( (parms & lepCREATE) == 0 )
{
parms = lepMISSING;
return SLE::pointer();
}
parms = parms | lepCREATED | lepOKAY;
SLE::pointer sle=boost::make_shared<SLE>(let);
sle->setIndex(nodeID);
return sle;
}
SLE::pointer sle =
boost::make_shared<SLE>(account->peekSerializer(), nodeID);
if (sle->getType() != let)
{ // maybe it's a currency or something
parms = parms | lepWRONGTYPE;
return SLE::pointer();
}
parms = parms | lepOKAY;
return sle;
}
SLE::pointer Ledger::getAccountRoot(const uint160& accountID)
{
LedgerStateParms qry = lepNONE;
return getASNode(qry, getAccountRootIndex(accountID), ltACCOUNT_ROOT);
}
SLE::pointer Ledger::getAccountRoot(const NewcoinAddress& naAccountID)
{
LedgerStateParms qry = lepNONE;
return getASNode(qry, getAccountRootIndex(naAccountID.getAccountID()), ltACCOUNT_ROOT);
}
//
// Directory
//
SLE::pointer Ledger::getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uNodeIndex, ltDIR_NODE);
}
//
// Generator Map
//
SLE::pointer Ledger::getGenerator(LedgerStateParms& parms, const uint160& uGeneratorID)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, getGeneratorIndex(uGeneratorID), ltGENERATOR_MAP);
}
//
// Nickname
//
SLE::pointer Ledger::getNickname(LedgerStateParms& parms, const uint256& uNickname)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uNickname, ltNICKNAME);
}
//
// Offer
//
SLE::pointer Ledger::getOffer(LedgerStateParms& parms, const uint256& uIndex)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uIndex, ltOFFER);
}
//
// Ripple State
//
SLE::pointer Ledger::getRippleState(LedgerStateParms& parms, const uint256& uNode)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uNode, ltRIPPLE_STATE);
}
// For an entry put in the 64 bit index or quality.
uint256 Ledger::getQualityIndex(const uint256& uBase, const uint64 uNodeDir)
{
// Indexes are stored in big endian format: they print as hex as stored.
// Most significant bytes are first. Least significant bytes represent adjacent entries.
// We place uNodeDir in the 8 right most bytes to be adjacent.
// Want uNodeDir in big endian format so ++ goes to the next entry for indexes.
uint256 uNode(uBase);
((uint64*) uNode.end())[-1] = htobe64(uNodeDir);
return uNode;
}
// Return the last 64 bits.
uint64 Ledger::getQuality(const uint256& uBase)
{
return be64toh(((uint64*) uBase.end())[-1]);
}
uint256 Ledger::getQualityNext(const uint256& uBase)
{
static uint256 uNext("10000000000000000");
uint256 uResult = uBase;
uResult += uNext;
return uResult;
}
uint256 Ledger::getAccountRootIndex(const uint160& uAccountID)
{
Serializer s(22);
s.add16(spaceAccount); // 2
s.add160(uAccountID); // 20
return s.getSHA512Half();
}
uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID)
{
bool bInNative = uTakerPaysCurrency.isZero();
bool bOutNative = uTakerGetsCurrency.isZero();
assert(!bInNative || !bOutNative); // Stamps to stamps not allowed.
assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed.
assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed.
assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ.
Serializer s(82);
s.add16(spaceBookDir); // 2
s.add160(uTakerPaysCurrency); // 20
s.add160(uTakerGetsCurrency); // 20
s.add160(uTakerPaysIssuerID); // 20
s.add160(uTakerGetsIssuerID); // 20
uint256 uBaseIndex = getQualityIndex(s.getSHA512Half()); // Return with quality 0.
Log(lsINFO) << str(boost::format("getBookBase(%s,%s,%s,%s) = %s")
% STAmount::createHumanCurrency(uTakerPaysCurrency)
% NewcoinAddress::createHumanAccountID(uTakerPaysIssuerID)
% STAmount::createHumanCurrency(uTakerGetsCurrency)
% NewcoinAddress::createHumanAccountID(uTakerGetsIssuerID)
% uBaseIndex.ToString());
return uBaseIndex;
}
uint256 Ledger::getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex)
{
if (uNodeIndex)
{
Serializer s(42);
s.add16(spaceDirNode); // 2
s.add256(uDirRoot); // 32
s.add64(uNodeIndex); // 8
return s.getSHA512Half();
}
else
{
return uDirRoot;
}
}
uint256 Ledger::getGeneratorIndex(const uint160& uGeneratorID)
{
Serializer s(22);
s.add16(spaceGenerator); // 2
s.add160(uGeneratorID); // 20
return s.getSHA512Half();
}
// What is important:
// --> uNickname: is a Sha256
// <-- SHA512/2: for consistency and speed in generating indexes.
uint256 Ledger::getNicknameIndex(const uint256& uNickname)
{
Serializer s(34);
s.add16(spaceNickname); // 2
s.add256(uNickname); // 32
return s.getSHA512Half();
}
uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence)
{
Serializer s(26);
s.add16(spaceOffer); // 2
s.add160(uAccountID); // 20
s.add32(uSequence); // 4
return s.getSHA512Half();
}
uint256 Ledger::getOwnerDirIndex(const uint160& uAccountID)
{
Serializer s(22);
s.add16(spaceOwnerDir); // 2
s.add160(uAccountID); // 20
return s.getSHA512Half();
}
uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency)
{
uint160 uAID = naA.getAccountID();
uint160 uBID = naB.getAccountID();
bool bAltB = uAID < uBID;
Serializer s(62);
s.add16(spaceRipple); // 2
s.add160(bAltB ? uAID : uBID); // 20
s.add160(bAltB ? uBID : uAID); // 20
s.add160(uCurrency); // 20
return s.getSHA512Half();
}
// vim:ts=4

View File

@@ -11,6 +11,7 @@
#include "../json/value.h"
#include "Transaction.h"
#include "TransactionMeta.h"
#include "AccountState.h"
#include "RippleState.h"
#include "NicknameState.h"
@@ -41,7 +42,8 @@ class Ledger : public boost::enable_shared_from_this<Ledger>
{ // The basic Ledger structure, can be opened, closed, or synching
friend class TransactionEngine;
public:
typedef boost::shared_ptr<Ledger> pointer;
typedef boost::shared_ptr<Ledger> pointer;
typedef const boost::shared_ptr<Ledger>& ref;
enum TransResult
{
@@ -55,7 +57,7 @@ public:
TR_PASTASEQ = 6, // account is past this transaction
TR_PREASEQ = 7, // account is missing transactions before this
TR_BADLSEQ = 8, // ledger too early
TR_TOOSMALL = 9, // amount is less than Tx fee
TR_TOOSMALL = 9, // amount is less than Tx fee
};
// ledger close flags
@@ -81,8 +83,6 @@ private:
protected:
bool addTransaction(Transaction::pointer);
bool addTransaction(const uint256& id, const Serializer& txn);
static Ledger::pointer getSQL(const std::string& sqlStatement);
@@ -115,7 +115,7 @@ public:
void disarmDirty() { mTransactionMap->disarmDirty(); mAccountStateMap->disarmDirty(); }
// This ledger has closed, will never be accepted, and is accepting
// new transactions to be re-repocessed when do accept a new last-closed ledger
// new transactions to be re-reprocessed when do accept a new last-closed ledger
void bumpSeq() { mClosed = true; mLedgerSeq++; }
// ledger signature operations
@@ -151,17 +151,20 @@ public:
bool isAcquiringAS(void);
// Transaction Functions
bool addTransaction(const uint256& id, const Serializer& txn);
bool addTransaction(const uint256& id, const Serializer& txn, const Serializer& metaData);
bool hasTransaction(const uint256& TransID) const { return mTransactionMap->hasItem(TransID); }
Transaction::pointer getTransaction(const uint256& transID) const;
bool getTransaction(const uint256& transID, Transaction::pointer& txn, TransactionMetaSet::pointer& txMeta);
// high-level functions
AccountState::pointer getAccountState(const NewcoinAddress& acctID);
LedgerStateParms writeBack(LedgerStateParms parms, SLE::pointer);
LedgerStateParms writeBack(LedgerStateParms parms, SLE::ref);
SLE::pointer getAccountRoot(const uint160& accountID);
SLE::pointer getAccountRoot(const NewcoinAddress& naAccountID);
// database functions
static void saveAcceptedLedger(Ledger::pointer);
static void saveAcceptedLedger(Ledger::ref);
static Ledger::pointer loadByIndex(uint32 ledgerIndex);
static Ledger::pointer loadByHash(const uint256& ledgerHash);
@@ -260,14 +263,11 @@ public:
// Ripple functions : credit lines
//
// Index of node which is the ripple state between to accounts for a currency.
// Index of node which is the ripple state between two accounts for a currency.
static uint256 getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency);
static uint256 getRippleStateIndex(const uint160& uiA, const uint160& uiB, const uint160& uCurrency)
{ return getRippleStateIndex(NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency); }
// Directory of lines indexed by an account (not all lines are indexed)
static uint256 getRippleDirIndex(const uint160& uAccountID);
RippleState::pointer accessRippleState(const uint256& uNode);
SLE::pointer getRippleState(LedgerStateParms& parms, const uint256& uNode);
@@ -284,12 +284,6 @@ public:
SLE::pointer getRippleState(const uint160& uiA, const uint160& uiB, const uint160& uCurrency)
{ return getRippleState(getRippleStateIndex(NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency)); }
//
// Misc
//
bool isCompatible(boost::shared_ptr<Ledger> other);
// bool signLedger(std::vector<unsigned char> &signature, const LocalHanko &hanko);
void addJson(Json::Value&, int options);
static bool unitTest();

View File

@@ -11,14 +11,16 @@
#include "HashPrefixes.h"
// #define LA_DEBUG
#define LEDGER_ACQUIRE_TIMEOUT 2
#define LEDGER_ACQUIRE_TIMEOUT 750
#define TRUST_NETWORK
PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0),
mComplete(false), mFailed(false), mProgress(true), mTimer(theApp->getIOService())
{ ; }
{
assert((mTimerInterval > 10) && (mTimerInterval < 30000));
}
void PeerSet::peerHas(Peer::pointer ptr)
void PeerSet::peerHas(Peer::ref ptr)
{
boost::recursive_mutex::scoped_lock sl(mLock);
std::vector< boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
@@ -38,7 +40,7 @@ void PeerSet::peerHas(Peer::pointer ptr)
newPeer(ptr);
}
void PeerSet::badPeer(Peer::pointer ptr)
void PeerSet::badPeer(Peer::ref ptr)
{
boost::recursive_mutex::scoped_lock sl(mLock);
std::vector< boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
@@ -61,7 +63,7 @@ void PeerSet::badPeer(Peer::pointer ptr)
void PeerSet::resetTimer()
{
mTimer.expires_from_now(boost::posix_time::seconds(mTimerInterval));
mTimer.expires_from_now(boost::posix_time::milliseconds(mTimerInterval));
mTimer.async_wait(boost::bind(&PeerSet::TimerEntry, pmDowncast(), boost::asio::placeholders::error));
}
@@ -70,7 +72,7 @@ void PeerSet::invokeOnTimer()
if (!mProgress)
{
++mTimeouts;
Log(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash.GetHex();
Log(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash;
}
else
mProgress = false;
@@ -82,16 +84,15 @@ void PeerSet::TimerEntry(boost::weak_ptr<PeerSet> wptr, const boost::system::err
if (result == boost::asio::error::operation_aborted)
return;
boost::shared_ptr<PeerSet> ptr = wptr.lock();
if (!ptr)
return;
ptr->invokeOnTimer();
if (ptr)
ptr->invokeOnTimer();
}
LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT),
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false)
{
#ifdef LA_DEBUG
Log(lsTRACE) << "Acquiring ledger " << mHash.GetHex();
Log(lsTRACE) << "Acquiring ledger " << mHash;
#endif
}
@@ -102,12 +103,12 @@ void LedgerAcquire::onTimer()
setFailed();
done();
}
else trigger(Peer::pointer());
else trigger(Peer::pointer(), true);
}
boost::weak_ptr<PeerSet> LedgerAcquire::pmDowncast()
{
return boost::shared_polymorphic_downcast<PeerSet, LedgerAcquire>(shared_from_this());
return boost::shared_polymorphic_downcast<PeerSet>(shared_from_this());
}
void LedgerAcquire::done()
@@ -116,7 +117,7 @@ void LedgerAcquire::done()
return;
mSignaled = true;
#ifdef LA_DEBUG
Log(lsTRACE) << "Done acquiring ledger " << mHash.GetHex();
Log(lsTRACE) << "Done acquiring ledger " << mHash;
#endif
std::vector< boost::function<void (LedgerAcquire::pointer)> > triggers;
@@ -129,7 +130,7 @@ void LedgerAcquire::done()
if (mLedger)
theApp->getMasterLedger().storeLedger(mLedger);
for (int i = 0; i < triggers.size(); ++i)
for (unsigned int i = 0; i < triggers.size(); ++i)
triggers[i](shared_from_this());
}
@@ -140,31 +141,25 @@ void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)>
mLock.unlock();
}
void LedgerAcquire::trigger(Peer::pointer peer)
void LedgerAcquire::trigger(Peer::ref peer, bool timer)
{
if (mAborted || mComplete || mFailed)
return;
#ifdef LA_DEBUG
if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP();
else Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex();
Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP();
else Log(lsTRACE) << "Trigger acquiring ledger " << mHash;
if (mComplete || mFailed)
Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
else
Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
#endif
if (!mHaveBase)
{
#ifdef LA_DEBUG
Log(lsTRACE) << "need base";
#endif
newcoin::TMGetLedger tmGL;
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
tmGL.set_itype(newcoin::liBASE);
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
else sendRequest(tmGL);
sendRequest(tmGL, peer);
}
if (mHaveBase && !mHaveTransactions)
@@ -180,12 +175,7 @@ void LedgerAcquire::trigger(Peer::pointer peer)
tmGL.set_ledgerseq(mLedger->getLedgerSeq());
tmGL.set_itype(newcoin::liTX_NODE);
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
sendRequest(tmGL, peer);
}
else
{
@@ -199,7 +189,8 @@ void LedgerAcquire::trigger(Peer::pointer peer)
else
{
mHaveTransactions = true;
if (mHaveState) mComplete = true;
if (mHaveState)
mComplete = true;
}
}
else
@@ -210,12 +201,7 @@ void LedgerAcquire::trigger(Peer::pointer peer)
tmGL.set_itype(newcoin::liTX_NODE);
for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL.add_nodeids()) = it->getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
sendRequest(tmGL, peer);
}
}
}
@@ -233,12 +219,7 @@ void LedgerAcquire::trigger(Peer::pointer peer)
tmGL.set_ledgerseq(mLedger->getLedgerSeq());
tmGL.set_itype(newcoin::liAS_NODE);
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
sendRequest(tmGL, peer);
}
else
{
@@ -252,7 +233,8 @@ void LedgerAcquire::trigger(Peer::pointer peer)
else
{
mHaveState = true;
if (mHaveTransactions) mComplete = true;
if (mHaveTransactions)
mComplete = true;
}
}
else
@@ -263,31 +245,30 @@ void LedgerAcquire::trigger(Peer::pointer peer)
tmGL.set_itype(newcoin::liAS_NODE);
for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL.add_nodeids()) = it->getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
sendRequest(tmGL, peer);
}
}
}
if (mComplete || mFailed)
done();
else
else if (timer)
resetTimer();
}
void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::pointer peer)
void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::ref peer)
{
peer->sendPacket(boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER));
if (!peer)
sendRequest(tmGL);
else
peer->sendPacket(boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER));
}
void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL)
{
boost::recursive_mutex::scoped_lock sl(mLock);
if (mPeers.empty()) return;
if (mPeers.empty())
return;
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER);
@@ -309,7 +290,7 @@ void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL)
bool LedgerAcquire::takeBase(const std::string& data)
{ // Return value: true=normal, false=bad data
#ifdef LA_DEBUG
Log(lsTRACE) << "got base acquiring ledger " << mHash.GetHex();
Log(lsTRACE) << "got base acquiring ledger " << mHash;
#endif
boost::recursive_mutex::scoped_lock sl(mLock);
if (mHaveBase) return true;
@@ -317,7 +298,7 @@ bool LedgerAcquire::takeBase(const std::string& data)
if (mLedger->getHash() != mHash)
{
Log(lsWARNING) << "Acquire hash mismatch";
Log(lsWARNING) << mLedger->getHash().GetHex() << "!=" << mHash.GetHex();
Log(lsWARNING) << mLedger->getHash() << "!=" << mHash;
mLedger = Ledger::pointer();
#ifdef TRUST_NETWORK
assert(false);
@@ -329,11 +310,13 @@ bool LedgerAcquire::takeBase(const std::string& data)
Serializer s(data.size() + 4);
s.add32(sHP_Ledger);
s.addRaw(data);
theApp->getHashedObjectStore().store(LEDGER, mLedger->getLedgerSeq(), s.peekData(), mHash);
theApp->getHashedObjectStore().store(hotLEDGER, mLedger->getLedgerSeq(), s.peekData(), mHash);
progress();
if (!mLedger->getTransHash()) mHaveTransactions = true;
if (!mLedger->getAccountHash()) mHaveState = true;
if (!mLedger->getTransHash())
mHaveTransactions = true;
if (!mLedger->getAccountHash())
mHaveState = true;
mLedger->setAcquiring();
return true;
}
@@ -349,7 +332,7 @@ bool LedgerAcquire::takeTxNode(const std::list<SHAMapNode>& nodeIDs,
{
if (nodeIDit->isRoot())
{
if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, STN_ARF_WIRE))
if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, snfWIRE))
return false;
}
else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))
@@ -374,7 +357,7 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
const std::list< std::vector<unsigned char> >& data)
{
#ifdef LA_DEBUG
Log(lsTRACE) << "got ASdata acquiring ledger " << mHash.GetHex();
Log(lsTRACE) << "got ASdata acquiring ledger " << mHash;
#endif
if (!mHaveBase) return false;
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
@@ -384,7 +367,7 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
{
if (nodeIDit->isRoot())
{
if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, STN_ARF_WIRE))
if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, snfWIRE))
return false;
}
else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))
@@ -408,13 +391,13 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
bool LedgerAcquire::takeAsRootNode(const std::vector<unsigned char>& data)
{
if (!mHaveBase) return false;
return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, STN_ARF_WIRE);
return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE);
}
bool LedgerAcquire::takeTxRootNode(const std::vector<unsigned char>& data)
{
if (!mHaveBase) return false;
return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, STN_ARF_WIRE);
return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE);
}
LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
@@ -422,7 +405,8 @@ LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
assert(hash.isNonZero());
boost::mutex::scoped_lock sl(mLock);
LedgerAcquire::pointer& ptr = mLedgers[hash];
if (ptr) return ptr;
if (ptr)
return ptr;
ptr = boost::make_shared<LedgerAcquire>(hash);
assert(mLedgers[hash] == ptr);
ptr->resetTimer(); // Cannot call in constructor
@@ -434,7 +418,8 @@ LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash)
assert(hash.isNonZero());
boost::mutex::scoped_lock sl(mLock);
std::map<uint256, LedgerAcquire::pointer>::iterator it = mLedgers.find(hash);
if (it != mLedgers.end()) return it->second;
if (it != mLedgers.end())
return it->second;
return LedgerAcquire::pointer();
}
@@ -448,11 +433,11 @@ bool LedgerAcquireMaster::hasLedger(const uint256& hash)
void LedgerAcquireMaster::dropLedger(const uint256& hash)
{
assert(hash.isNonZero());
boost::mutex::scoped_lock sl(mLock);
boost::mutex::scoped_lock sl(mLock);
mLedgers.erase(hash);
}
bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer peer)
bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::ref peer)
{
#ifdef LA_DEBUG
Log(lsTRACE) << "got data for acquiring ledger ";
@@ -465,7 +450,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi
}
memcpy(hash.begin(), packet.ledgerhash().data(), 32);
#ifdef LA_DEBUG
Log(lsTRACE) << hash.GetHex();
Log(lsTRACE) << hash;
#endif
LedgerAcquire::pointer ledger = find(hash);
@@ -480,7 +465,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi
return false;
if (packet.nodes_size() == 1)
{
ledger->trigger(peer);
ledger->trigger(peer, false);
return true;
}
if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata())))
@@ -489,12 +474,12 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi
}
if (packet.nodes().size() == 2)
{
ledger->trigger(peer);
ledger->trigger(peer, false);
return true;
}
if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata())))
Log(lsWARNING) << "Invcluded TXbase invalid";
ledger->trigger(peer);
ledger->trigger(peer, false);
return true;
}
@@ -518,7 +503,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi
else
ret = ledger->takeAsNode(nodeIDs, nodeData);
if (ret)
ledger->trigger(peer);
ledger->trigger(peer, false);
return ret;
}

View File

@@ -31,7 +31,7 @@ protected:
virtual ~PeerSet() { ; }
void sendRequest(const newcoin::TMGetLedger& message);
void sendRequest(const newcoin::TMGetLedger& message, Peer::pointer peer);
void sendRequest(const newcoin::TMGetLedger& message, Peer::ref peer);
public:
const uint256& getHash() const { return mHash; }
@@ -41,12 +41,12 @@ public:
void progress() { mProgress = true; }
void peerHas(Peer::pointer);
void badPeer(Peer::pointer);
void peerHas(Peer::ref);
void badPeer(Peer::ref);
void resetTimer();
protected:
virtual void newPeer(Peer::pointer) = 0;
virtual void newPeer(Peer::ref) = 0;
virtual void onTimer(void) = 0;
virtual boost::weak_ptr<PeerSet> pmDowncast() = 0;
@@ -72,12 +72,13 @@ protected:
void done();
void onTimer();
void newPeer(Peer::pointer peer) { trigger(peer); }
void newPeer(Peer::ref peer) { trigger(peer, false); }
boost::weak_ptr<PeerSet> pmDowncast();
public:
LedgerAcquire(const uint256& hash);
virtual ~LedgerAcquire() { ; }
bool isBase() const { return mHaveBase; }
bool isAcctStComplete() const { return mHaveState; }
@@ -92,7 +93,7 @@ public:
bool takeTxRootNode(const std::vector<unsigned char>& data);
bool takeAsNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data);
bool takeAsRootNode(const std::vector<unsigned char>& data);
void trigger(Peer::pointer);
void trigger(Peer::ref, bool timer);
};
class LedgerAcquireMaster
@@ -108,7 +109,7 @@ public:
LedgerAcquire::pointer find(const uint256& hash);
bool hasLedger(const uint256& ledgerHash);
void dropLedger(const uint256& ledgerHash);
bool gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer);
bool gotLedgerData(newcoin::TMLedgerData& packet, Peer::ref);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -27,21 +27,21 @@ protected:
SHAMap::pointer mMap;
bool mHaveRoot;
void onTimer() { trigger(Peer::pointer()); }
void newPeer(Peer::pointer peer) { trigger(peer); }
void onTimer() { trigger(Peer::pointer(), true); }
void newPeer(Peer::ref peer) { trigger(peer, false); }
void done();
void trigger(Peer::pointer);
void trigger(Peer::ref, bool timer);
boost::weak_ptr<PeerSet> pmDowncast();
public:
TransactionAcquire(const uint256& hash);
virtual ~TransactionAcquire() { ; }
SHAMap::pointer getMap() { return mMap; }
bool takeNodes(const std::list<SHAMapNode>& IDs, const std::list< std::vector<unsigned char> >& data,
Peer::pointer);
bool takeNodes(const std::list<SHAMapNode>& IDs, const std::list< std::vector<unsigned char> >& data, Peer::ref);
};
class LCTransaction
@@ -49,23 +49,25 @@ class LCTransaction
protected:
uint256 mTransactionID;
int mYays, mNays;
bool mOurPosition;
bool mOurVote;
Serializer transaction;
boost::unordered_map<uint160, bool> mVotes;
public:
typedef boost::shared_ptr<LCTransaction> pointer;
LCTransaction(const uint256 &txID, const std::vector<unsigned char>& tx, bool ourPosition) :
mTransactionID(txID), mYays(0), mNays(0), mOurPosition(ourPosition), transaction(tx) { ; }
LCTransaction(const uint256 &txID, const std::vector<unsigned char>& tx, bool ourVote) :
mTransactionID(txID), mYays(0), mNays(0), mOurVote(ourVote), transaction(tx) { ; }
const uint256& getTransactionID() const { return mTransactionID; }
bool getOurPosition() const { return mOurPosition; }
bool getOurVote() const { return mOurVote; }
Serializer& peekTransaction() { return transaction; }
void setOurVote(bool o) { mOurVote = o; }
void setVote(const uint160& peer, bool votesYes);
void unVote(const uint160& peer);
bool updatePosition(int percentTime, bool proposing);
bool updateVote(int percentTime, bool proposing);
};
enum LCState
@@ -99,7 +101,7 @@ protected:
boost::unordered_map<uint160, LedgerProposal::pointer> mPeerPositions;
// Transaction Sets, indexed by hash of transaction tree
boost::unordered_map<uint256, SHAMap::pointer> mComplete;
boost::unordered_map<uint256, SHAMap::pointer> mAcquired;
boost::unordered_map<uint256, TransactionAcquire::pointer> mAcquiring;
// Peer sets
@@ -111,37 +113,47 @@ protected:
// Close time estimates
std::map<uint32, int> mCloseTimes;
// deferred proposals (node ID -> proposals from that peer)
boost::unordered_map< uint160, std::list<LedgerProposal::pointer> > mDeferredProposals;
// nodes that have bowed out of this consensus process
boost::unordered_set<uint160> mDeadNodes;
// final accept logic
static void Saccept(boost::shared_ptr<LedgerConsensus> This, SHAMap::pointer txSet);
void accept(SHAMap::pointer txSet);
void accept(SHAMap::ref txSet);
void weHave(const uint256& id, Peer::pointer avoidPeer);
void startAcquiring(TransactionAcquire::pointer);
void weHave(const uint256& id, Peer::ref avoidPeer);
void startAcquiring(const TransactionAcquire::pointer&);
SHAMap::pointer find(const uint256& hash);
void createDisputes(SHAMap::pointer, SHAMap::pointer);
void createDisputes(SHAMap::ref, SHAMap::ref);
void addDisputedTransaction(const uint256&, const std::vector<unsigned char>& transaction);
void adjustCount(SHAMap::pointer map, const std::vector<uint160>& peers);
void propose(const std::vector<uint256>& addedTx, const std::vector<uint256>& removedTx);
void adjustCount(SHAMap::ref map, const std::vector<uint160>& peers);
void propose();
void addPosition(LedgerProposal&, bool ours);
void removePosition(LedgerProposal&, bool ours);
void sendHaveTxSet(const uint256& set, bool direct);
void applyTransactions(SHAMap::pointer transactionSet, Ledger::pointer targetLedger, Ledger::pointer checkLedger,
CanonicalTXSet& failedTransactions, bool final);
void applyTransaction(TransactionEngine& engine, SerializedTransaction::pointer txn, Ledger::pointer targetLedger,
CanonicalTXSet& failedTransactions, bool final);
void applyTransactions(SHAMap::ref transactionSet, Ledger::ref targetLedger,
Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr);
void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn,
Ledger::ref targetLedger, CanonicalTXSet& failedTransactions, bool openLgr);
uint32 roundCloseTime(uint32 closeTime);
// manipulating our own position
void statusChange(newcoin::NodeEvent, Ledger& ledger);
void takeInitialPosition(Ledger& initialLedger);
void updateOurPositions();
void playbackProposals();
int getThreshold();
void beginAccept();
void endConsensus();
public:
LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime);
LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previousLedger, uint32 closeTime);
int startup();
Json::Value getJson();
@@ -151,8 +163,9 @@ public:
SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire);
TransactionAcquire::pointer getAcquiring(const uint256& hash);
void mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired);
void mapComplete(const uint256& hash, SHAMap::ref map, bool acquired);
void checkLCL();
void handleLCL(const uint256& lclHash);
void timerEntry();
@@ -165,12 +178,17 @@ public:
bool haveConsensus();
bool peerPosition(LedgerProposal::pointer);
bool peerPosition(const LedgerProposal::pointer&);
void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic);
bool peerHasSet(Peer::pointer peer, const uint256& set, newcoin::TxSetStatus status);
bool peerHasSet(Peer::ref peer, const uint256& set, newcoin::TxSetStatus status);
bool peerGaveNodes(Peer::pointer peer, const uint256& setHash,
bool peerGaveNodes(Peer::ref peer, const uint256& setHash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
void swapDefer(boost::unordered_map< uint160, std::list<LedgerProposal::pointer> > &n)
{ mDeferredProposals.swap(n); }
};

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,8 @@
#include "SerializedLedger.h"
#include "TransactionMeta.h"
#include "Ledger.h"
#include "TransactionErr.h"
enum LedgerEntryAction
{
@@ -15,7 +17,6 @@ enum LedgerEntryAction
taaCREATE, // Newly created.
};
class LedgerEntrySetEntry
{
public:
@@ -23,47 +24,112 @@ public:
LedgerEntryAction mAction;
int mSeq;
LedgerEntrySetEntry(SLE::pointer e, LedgerEntryAction a, int s) : mEntry(e), mAction(a), mSeq(s) { ; }
LedgerEntrySetEntry(SLE::ref e, LedgerEntryAction a, int s) : mEntry(e), mAction(a), mSeq(s) { ; }
};
class LedgerEntrySet
{
protected:
Ledger::pointer mLedger;
boost::unordered_map<uint256, LedgerEntrySetEntry> mEntries;
TransactionMetaSet mSet;
int mSeq;
LedgerEntrySet(const boost::unordered_map<uint256, LedgerEntrySetEntry> &e, TransactionMetaSet& s, int m) :
mEntries(e), mSet(s), mSeq(m) { ; }
LedgerEntrySet(Ledger::ref ledger, const boost::unordered_map<uint256, LedgerEntrySetEntry> &e,
const TransactionMetaSet& s, int m) : mLedger(ledger), mEntries(e), mSet(s), mSeq(m) { ; }
SLE::pointer getForMod(const uint256& node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
public:
LedgerEntrySet(Ledger::ref ledger) : mLedger(ledger), mSeq(0) { ; }
LedgerEntrySet() : mSeq(0) { ; }
// set functions
LedgerEntrySet duplicate(); // Make a duplicate of this set
void setTo(LedgerEntrySet&); // Set this set to have the same contents as another
LedgerEntrySet duplicate() const; // Make a duplicate of this set
void setTo(const LedgerEntrySet&); // Set this set to have the same contents as another
void swapWith(LedgerEntrySet&); // Swap the contents of two sets
int getSeq() const { return mSeq; }
void bumpSeq() { ++mSeq; }
void init(const uint256& transactionID, uint32 ledgerID);
void init(Ledger::ref ledger, const uint256& transactionID, uint32 ledgerID);
void clear();
Ledger::pointer& getLedger() { return mLedger; }
const Ledger::pointer& getLedgerRef() const { return mLedger; }
// basic entry functions
SLE::pointer getEntry(const uint256& index, LedgerEntryAction&);
LedgerEntryAction hasEntry(const uint256& index) const;
void entryCache(SLE::pointer&); // Add this entry to the cache
void entryCreate(SLE::pointer&); // This entry will be created
void entryDelete(SLE::pointer&, bool unfunded);
void entryModify(SLE::pointer&); // This entry will be modified
void entryCache(SLE::ref); // Add this entry to the cache
void entryCreate(SLE::ref); // This entry will be created
void entryDelete(SLE::ref); // This entry will be deleted
void entryModify(SLE::ref); // This entry will be modified
// higher-level ledger functions
SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex);
SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex);
// Directory functions.
TER dirAdd(
uint64& uNodeDir, // Node of entry.
const uint256& uRootIndex,
const uint256& uLedgerIndex);
TER dirDelete(
const bool bKeepRoot,
const uint64& uNodeDir, // Node item is mentioned in.
const uint256& uRootIndex,
const uint256& uLedgerIndex, // Item being deleted
const bool bStable);
bool dirFirst(const uint256& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
bool dirNext(const uint256& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
// Offer functions.
TER offerDelete(const uint256& uOfferIndex);
TER offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID);
// Balance functions.
uint32 rippleTransferRate(const uint160& uIssuerID);
uint32 rippleTransferRate(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID);
STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID,
SField::ref sfLow = sfLowQualityIn, SField::ref sfHigh = sfHighQualityIn);
uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
{ return rippleQualityIn(uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut); }
STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
STAmount rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount);
void rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer=true);
STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount);
STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
void accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount);
STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault);
Json::Value getJson(int) const;
void calcRawMeta(Serializer&);
// iterator functions
bool isEmpty() const { return mEntries.empty(); }
bool isEmpty() const { return mEntries.empty(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator begin() const { return mEntries.begin(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator end() const { return mEntries.end(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator begin() { return mEntries.begin(); }
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator end() { return mEntries.end(); }
static bool intersect(const LedgerEntrySet& lesLeft, const LedgerEntrySet& lesRight);
};
#endif

View File

@@ -1,89 +1,118 @@
#include "LedgerFormats.h"
#define S_FIELD(x) sf##x, #x
std::map<int, LedgerEntryFormat*> LedgerEntryFormat::byType;
std::map<std::string, LedgerEntryFormat*> LedgerEntryFormat::byName;
LedgerEntryFormat LedgerFormats[]=
{
{ "AccountRoot", ltACCOUNT_ROOT, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(LastTxn), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_IFFLAG, 1 },
{ S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 },
{ S_FIELD(WalletLocator), STI_HASH256, SOE_IFFLAG, 4 },
{ S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 8 },
{ S_FIELD(TransferRate), STI_UINT32, SOE_IFFLAG, 16 },
{ S_FIELD(Domain), STI_VL, SOE_IFFLAG, 32 },
{ S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 },
{ S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "DirectoryNode", ltDIR_NODE, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Indexes), STI_VECTOR256, SOE_REQUIRED, 0 },
{ S_FIELD(IndexNext), STI_UINT64, SOE_IFFLAG, 1 },
{ S_FIELD(IndexPrevious), STI_UINT64, SOE_IFFLAG, 2 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "GeneratorMap", ltGENERATOR_MAP, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Nickname", ltNICKNAME, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Offer", ltOFFER, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(BookDirectory), STI_HASH256, SOE_REQUIRED, 0 },
{ S_FIELD(BookNode), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(PaysIssuer), STI_ACCOUNT, SOE_IFFLAG, 1 },
{ S_FIELD(GetsIssuer), STI_ACCOUNT, SOE_IFFLAG, 2 },
{ S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "RippleState", ltRIPPLE_STATE, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(LowID), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(LowLimit), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(HighID), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(HighLimit), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(LowQualityIn), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(LowQualityOut), STI_UINT32, SOE_IFFLAG, 2 },
{ S_FIELD(HighQualityIn), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(HighQualityOut), STI_UINT32, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ NULL, ltINVALID }
};
#define LEF_BASE \
<< SOElement(sfLedgerIndex, SOE_OPTIONAL) \
<< SOElement(sfLedgerEntryType, SOE_REQUIRED) \
<< SOElement(sfFlags, SOE_REQUIRED)
LedgerEntryFormat* getLgrFormat(LedgerEntryType t)
#define DECLARE_LEF(name, type) lef = new LedgerEntryFormat(#name, type); (*lef) LEF_BASE
static bool LEFInit()
{
LedgerEntryFormat* f = LedgerFormats;
while (f->t_name != NULL)
{
if (f->t_type == t) return f;
++f;
}
return NULL;
LedgerEntryFormat* lef;
DECLARE_LEF(AccountRoot, ltACCOUNT_ROOT)
<< SOElement(sfAccount, SOE_REQUIRED)
<< SOElement(sfSequence, SOE_REQUIRED)
<< SOElement(sfBalance, SOE_REQUIRED)
<< SOElement(sfLastTxnID, SOE_REQUIRED)
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
<< SOElement(sfAuthorizedKey, SOE_OPTIONAL)
<< SOElement(sfEmailHash, SOE_OPTIONAL)
<< SOElement(sfWalletLocator, SOE_OPTIONAL)
<< SOElement(sfMessageKey, SOE_OPTIONAL)
<< SOElement(sfTransferRate, SOE_OPTIONAL)
<< SOElement(sfDomain, SOE_OPTIONAL)
<< SOElement(sfPublishHash, SOE_OPTIONAL)
<< SOElement(sfPublishSize, SOE_OPTIONAL)
;
DECLARE_LEF(Contract, ltCONTRACT)
<< SOElement(sfAccount, SOE_REQUIRED)
<< SOElement(sfBalance, SOE_REQUIRED)
<< SOElement(sfLastTxnID, SOE_REQUIRED)
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
<< SOElement(sfIssuer, SOE_REQUIRED)
<< SOElement(sfOwner, SOE_REQUIRED)
<< SOElement(sfExpiration, SOE_REQUIRED)
<< SOElement(sfBondAmount, SOE_REQUIRED)
<< SOElement(sfCreateCode, SOE_REQUIRED)
<< SOElement(sfFundCode, SOE_REQUIRED)
<< SOElement(sfRemoveCode, SOE_REQUIRED)
<< SOElement(sfExpireCode, SOE_REQUIRED)
;
DECLARE_LEF(DirectoryNode, ltDIR_NODE)
<< SOElement(sfIndexes, SOE_REQUIRED)
<< SOElement(sfIndexNext, SOE_OPTIONAL)
<< SOElement(sfIndexPrevious, SOE_OPTIONAL)
;
DECLARE_LEF(GeneratorMap, ltGENERATOR_MAP)
<< SOElement(sfGenerator, SOE_REQUIRED)
;
DECLARE_LEF(Nickname, ltNICKNAME)
<< SOElement(sfAccount, SOE_REQUIRED)
<< SOElement(sfMinimumOffer, SOE_OPTIONAL)
;
DECLARE_LEF(Offer, ltOFFER)
<< SOElement(sfAccount, SOE_REQUIRED)
<< SOElement(sfSequence, SOE_REQUIRED)
<< SOElement(sfTakerPays, SOE_REQUIRED)
<< SOElement(sfTakerGets, SOE_REQUIRED)
<< SOElement(sfBookDirectory, SOE_REQUIRED)
<< SOElement(sfBookNode, SOE_REQUIRED)
<< SOElement(sfOwnerNode, SOE_REQUIRED)
<< SOElement(sfLastTxnID, SOE_REQUIRED)
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
<< SOElement(sfExpiration, SOE_OPTIONAL)
;
DECLARE_LEF(RippleState, ltRIPPLE_STATE)
<< SOElement(sfBalance, SOE_REQUIRED)
<< SOElement(sfLowLimit, SOE_REQUIRED)
<< SOElement(sfHighLimit, SOE_REQUIRED)
<< SOElement(sfLastTxnID, SOE_REQUIRED)
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
<< SOElement(sfLowQualityIn, SOE_OPTIONAL)
<< SOElement(sfLowQualityOut, SOE_OPTIONAL)
<< SOElement(sfHighQualityIn, SOE_OPTIONAL)
<< SOElement(sfHighQualityOut, SOE_OPTIONAL)
;
return true;
}
bool LEFInitComplete = LEFInit();
LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(LedgerEntryType t)
{
std::map<int, LedgerEntryFormat*>::iterator it = byType.find(static_cast<int>(t));
if (it == byType.end())
return NULL;
return it->second;
}
LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(int t)
{
std::map<int, LedgerEntryFormat*>::iterator it = byType.find((t));
if (it == byType.end())
return NULL;
return it->second;
}
LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(const std::string& t)
{
std::map<std::string, LedgerEntryFormat*>::iterator it = byName.find((t));
if (it == byName.end())
return NULL;
return it->second;
}
// vim:ts=4

View File

@@ -13,6 +13,7 @@ enum LedgerEntryType
ltRIPPLE_STATE = 'r',
ltNICKNAME = 'n',
ltOFFER = 'o',
ltCONTRACT = 'c',
};
// Used as a prefix for computing ledger indexes (keys).
@@ -23,12 +24,10 @@ enum LedgerNameSpace
spaceGenerator = 'g',
spaceNickname = 'n',
spaceRipple = 'r',
spaceRippleDir = 'R',
spaceOffer = 'o', // Entry for an offer.
spaceOwnerDir = 'O', // Directory of things owned by an account.
spaceBookDir = 'B', // Directory of order books.
spaceBond = 'b',
spaceInvoice = 'i',
spaceContract = 'c',
};
enum LedgerSpecificFlags
@@ -38,20 +37,33 @@ enum LedgerSpecificFlags
// ltOFFER
lsfPassive = 0x00010000,
// ltRIPPLE_STATE
lsfLowIndexed = 0x00010000,
lsfHighIndexed = 0x00020000,
};
struct LedgerEntryFormat
class LedgerEntryFormat
{
const char *t_name;
LedgerEntryType t_type;
SOElement elements[20];
public:
std::string t_name;
LedgerEntryType t_type;
std::vector<SOElement::ptr> elements;
static std::map<int, LedgerEntryFormat*> byType;
static std::map<std::string, LedgerEntryFormat*> byName;
LedgerEntryFormat(const char *name, LedgerEntryType type) : t_name(name), t_type(type)
{
byName[name] = this;
byType[type] = this;
}
LedgerEntryFormat& operator<<(const SOElement& el)
{
elements.push_back(new SOElement(el));
return *this;
}
static LedgerEntryFormat* getLgrFormat(LedgerEntryType t);
static LedgerEntryFormat* getLgrFormat(const std::string& t);
static LedgerEntryFormat* getLgrFormat(int t);
};
extern LedgerEntryFormat LedgerFormats[];
extern LedgerEntryFormat* getLgrFormat(LedgerEntryType t);
#endif
// vim:ts=4

View File

@@ -23,7 +23,7 @@ LedgerHistory::LedgerHistory() : mLedgersByHash(CACHED_LEDGER_NUM, CACHED_LEDGER
void LedgerHistory::addLedger(Ledger::pointer ledger)
{
mLedgersByHash.canonicalize(ledger->getHash(), ledger);
mLedgersByHash.canonicalize(ledger->getHash(), ledger, true);
}
void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger)
@@ -31,8 +31,10 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger)
assert(ledger && ledger->isAccepted());
uint256 h(ledger->getHash());
boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
mLedgersByHash.canonicalize(h, ledger);
assert(ledger && ledger->isAccepted() && ledger->isImmutable());
mLedgersByHash.canonicalize(h, ledger, true);
assert(ledger);
assert(ledger->isAccepted());
assert(ledger->isImmutable());
mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger));
boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger));
thread.detach();
@@ -88,7 +90,8 @@ Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool s
if (!save)
{ // return input ledger if not in map, otherwise, return corresponding map ledger
Ledger::pointer ret = mLedgersByHash.fetch(h);
if (ret) return ret;
if (ret)
return ret;
return ledger;
}

View File

@@ -1,154 +0,0 @@
#include "Ledger.h"
// For an entry put in the 64 bit index or quality.
uint256 Ledger::getQualityIndex(const uint256& uBase, const uint64 uNodeDir)
{
// Indexes are stored in big endian format: they print as hex as stored.
// Most significant bytes are first. Least significant bytes represent adjacent entries.
// We place uNodeDir in the 8 right most bytes to be adjacent.
// Want uNodeDir in big endian format so ++ goes to the next entry for indexes.
uint256 uNode(uBase);
((uint64*) uNode.end())[-1] = htobe64(uNodeDir);
return uNode;
}
// Return the last 64 bits.
uint64 Ledger::getQuality(const uint256& uBase)
{
return be64toh(((uint64*) uBase.end())[-1]);
}
uint256 Ledger::getQualityNext(const uint256& uBase)
{
static uint256 uNext("10000000000000000");
uint256 uResult = uBase;
uResult += uNext;
return uResult;
}
uint256 Ledger::getAccountRootIndex(const uint160& uAccountID)
{
Serializer s(22);
s.add16(spaceAccount); // 2
s.add160(uAccountID); // 20
return s.getSHA512Half();
}
uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID)
{
bool bInNative = uTakerPaysCurrency.isZero();
bool bOutNative = uTakerGetsCurrency.isZero();
assert(!bInNative || !bOutNative); // Stamps to stamps not allowed.
assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed.
assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed.
assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ.
Serializer s(82);
s.add16(spaceBookDir); // 2
s.add160(uTakerPaysCurrency); // 20
s.add160(uTakerGetsCurrency); // 20
s.add160(uTakerPaysIssuerID); // 20
s.add160(uTakerGetsIssuerID); // 20
return getQualityIndex(s.getSHA512Half()); // Return with quality 0.
}
uint256 Ledger::getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex)
{
if (uNodeIndex)
{
Serializer s(42);
s.add16(spaceDirNode); // 2
s.add256(uDirRoot); // 32
s.add64(uNodeIndex); // 8
return s.getSHA512Half();
}
else
{
return uDirRoot;
}
}
uint256 Ledger::getGeneratorIndex(const uint160& uGeneratorID)
{
Serializer s(22);
s.add16(spaceGenerator); // 2
s.add160(uGeneratorID); // 20
return s.getSHA512Half();
}
// What is important:
// --> uNickname: is a Sha256
// <-- SHA512/2: for consistency and speed in generating indexes.
uint256 Ledger::getNicknameIndex(const uint256& uNickname)
{
Serializer s(34);
s.add16(spaceNickname); // 2
s.add256(uNickname); // 32
return s.getSHA512Half();
}
uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence)
{
Serializer s(26);
s.add16(spaceOffer); // 2
s.add160(uAccountID); // 20
s.add32(uSequence); // 4
return s.getSHA512Half();
}
uint256 Ledger::getOwnerDirIndex(const uint160& uAccountID)
{
Serializer s(22);
s.add16(spaceOwnerDir); // 2
s.add160(uAccountID); // 20
return s.getSHA512Half();
}
uint256 Ledger::getRippleDirIndex(const uint160& uAccountID)
{
Serializer s(22);
s.add16(spaceRippleDir); // 2
s.add160(uAccountID); // 20
return s.getSHA512Half();
}
uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency)
{
uint160 uAID = naA.getAccountID();
uint160 uBID = naB.getAccountID();
bool bAltB = uAID < uBID;
Serializer s(62);
s.add16(spaceRipple); // 2
s.add160(bAltB ? uAID : uBID); // 20
s.add160(bAltB ? uBID : uAID); // 20
s.add160(uCurrency); // 20
return s.getSHA512Half();
}
// vim:ts=4

View File

@@ -5,7 +5,6 @@
#include "Application.h"
#include "NewcoinAddress.h"
#include "Conversion.h"
#include "Log.h"
uint32 LedgerMaster::getCurrentLedgerIndex()
@@ -13,37 +12,39 @@ uint32 LedgerMaster::getCurrentLedgerIndex()
return mCurrentLedger->getLedgerSeq();
}
bool LedgerMaster::addHeldTransaction(Transaction::pointer transaction)
bool LedgerMaster::addHeldTransaction(const Transaction::pointer& transaction)
{ // returns true if transaction was added
boost::recursive_mutex::scoped_lock ml(mLock);
return mHeldTransactionsByID.insert(std::make_pair(transaction->getID(), transaction)).second;
}
void LedgerMaster::pushLedger(Ledger::pointer newLedger)
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
Log(lsINFO) << "PushLedger: " << newLedger->getHash().GetHex();
Log(lsINFO) << "PushLedger: " << newLedger->getHash();
ScopedLock sl(mLock);
if (!!mFinalizedLedger)
{
mFinalizedLedger->setClosed();
Log(lsTRACE) << "Finalizes: " << mFinalizedLedger->getHash().GetHex();
Log(lsTRACE) << "Finalizes: " << mFinalizedLedger->getHash();
}
mFinalizedLedger = mCurrentLedger;
mCurrentLedger = newLedger;
mEngine.setLedger(newLedger);
}
void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL)
void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL)
{
assert(newLCL->isClosed() && newLCL->isAccepted());
assert(!newOL->isClosed() && !newOL->isAccepted());
if (newLCL->isAccepted())
{
assert(newLCL->isClosed());
assert(newLCL->isImmutable());
mLedgerHistory.addAcceptedLedger(newLCL);
Log(lsINFO) << "StashAccepted: " << newLCL->getHash().GetHex();
Log(lsINFO) << "StashAccepted: " << newLCL->getHash();
}
mFinalizedLedger = newLCL;
@@ -52,7 +53,7 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL)
mEngine.setLedger(newOL);
}
void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer current)
void LedgerMaster::switchLedgers(Ledger::ref lastClosed, Ledger::ref current)
{
assert(lastClosed && current);
mFinalizedLedger = lastClosed;
@@ -64,7 +65,7 @@ void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer cur
mEngine.setLedger(mCurrentLedger);
}
void LedgerMaster::storeLedger(Ledger::pointer ledger)
void LedgerMaster::storeLedger(Ledger::ref ledger)
{
mLedgerHistory.addLedger(ledger);
}
@@ -78,10 +79,9 @@ Ledger::pointer LedgerMaster::closeLedger()
return closingLedger;
}
TransactionEngineResult LedgerMaster::doTransaction(const SerializedTransaction& txn, uint32 targetLedger,
TransactionEngineParams params)
TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEngineParams params)
{
TransactionEngineResult result = mEngine.applyTransaction(txn, params);
TER result = mEngine.applyTransaction(txn, params);
theApp->getOPs().pubTransaction(mEngine.getLedger(), txn, result);
return result;
}

View File

@@ -26,8 +26,8 @@ class LedgerMaster
std::map<uint256, Transaction::pointer> mHeldTransactionsByID;
void applyFutureTransactions(uint32 ledgerIndex);
bool isValidTransaction(Transaction::pointer trans);
bool isTransactionOnFutureList(Transaction::pointer trans);
bool isValidTransaction(const Transaction::pointer& trans);
bool isTransactionOnFutureList(const Transaction::pointer& trans);
public:
@@ -43,14 +43,15 @@ public:
// The finalized ledger is the last closed/accepted ledger
Ledger::pointer getClosedLedger() { return mFinalizedLedger; }
TransactionEngineResult doTransaction(const SerializedTransaction& txn, uint32 targetLedger,
TransactionEngineParams params);
void runStandAlone() { mFinalizedLedger = mCurrentLedger; }
void pushLedger(Ledger::pointer newLedger);
void pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL);
void storeLedger(Ledger::pointer);
TER doTransaction(const SerializedTransaction& txn, TransactionEngineParams params);
void switchLedgers(Ledger::pointer lastClosed, Ledger::pointer newCurrent);
void pushLedger(Ledger::ref newLedger);
void pushLedger(Ledger::ref newLCL, Ledger::ref newOL);
void storeLedger(Ledger::ref);
void switchLedgers(Ledger::ref lastClosed, Ledger::ref newCurrent);
Ledger::pointer closeLedger();
@@ -65,14 +66,19 @@ public:
Ledger::pointer getLedgerByHash(const uint256& hash)
{
if (!hash)
return mCurrentLedger;
if (mCurrentLedger && (mCurrentLedger->getHash() == hash))
return mCurrentLedger;
if (mFinalizedLedger && (mFinalizedLedger->getHash() == hash))
return mFinalizedLedger;
return mLedgerHistory.getLedgerByHash(hash);
}
bool addHeldTransaction(Transaction::pointer trans);
bool addHeldTransaction(const Transaction::pointer& trans);
};
#endif

View File

@@ -1,200 +0,0 @@
#include "Ledger.h"
#include <boost/make_shared.hpp>
#include "utils.h"
#include "Log.h"
// XXX Use shared locks where possible?
LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry)
{
ScopedLock l(mAccountStateMap->Lock());
bool create = false;
if (!mAccountStateMap->hasItem(entry->getIndex()))
{
if ((parms & lepCREATE) == 0)
{
Log(lsERROR) << "WriteBack non-existent node without create";
return lepMISSING;
}
create = true;
}
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(entry->getIndex());
entry->add(item->peekSerializer());
if (create)
{
assert(!mAccountStateMap->hasItem(entry->getIndex()));
if(!mAccountStateMap->addGiveItem(item, false, false)) // FIXME: TX metadata
{
assert(false);
return lepERROR;
}
return lepCREATED;
}
if (!mAccountStateMap->updateGiveItem(item, false, false)) // FIXME: TX metadata
{
assert(false);
return lepERROR;
}
return lepOKAY;
}
SLE::pointer Ledger::getSLE(const uint256& uHash)
{
SHAMapItem::pointer node = mAccountStateMap->peekItem(uHash);
if (!node)
return SLE::pointer();
return boost::make_shared<SLE>(node->peekSerializer(), node->getTag());
}
uint256 Ledger::getFirstLedgerIndex()
{
SHAMapItem::pointer node = mAccountStateMap->peekFirstItem();
return node ? node->getTag() : uint256();
}
uint256 Ledger::getLastLedgerIndex()
{
SHAMapItem::pointer node = mAccountStateMap->peekLastItem();
return node ? node->getTag() : uint256();
}
uint256 Ledger::getNextLedgerIndex(const uint256& uHash)
{
SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash);
return node ? node->getTag() : uint256();
}
uint256 Ledger::getNextLedgerIndex(const uint256& uHash, const uint256& uEnd)
{
SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash);
if ((!node) || (node->getTag() > uEnd))
return uint256();
return node->getTag();
}
uint256 Ledger::getPrevLedgerIndex(const uint256& uHash)
{
SHAMapItem::pointer node = mAccountStateMap->peekPrevItem(uHash);
return node ? node->getTag() : uint256();
}
uint256 Ledger::getPrevLedgerIndex(const uint256& uHash, const uint256& uBegin)
{
SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash);
if ((!node) || (node->getTag() < uBegin))
return uint256();
return node->getTag();
}
SLE::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID,
LedgerEntryType let )
{
SHAMapItem::pointer account = mAccountStateMap->peekItem(nodeID);
if (!account)
{
if ( (parms & lepCREATE) == 0 )
{
parms = lepMISSING;
return SLE::pointer();
}
parms = parms | lepCREATED | lepOKAY;
SLE::pointer sle=boost::make_shared<SLE>(let);
sle->setIndex(nodeID);
return sle;
}
SLE::pointer sle =
boost::make_shared<SLE>(account->peekSerializer(), nodeID);
if (sle->getType() != let)
{ // maybe it's a currency or something
parms = parms | lepWRONGTYPE;
return SLE::pointer();
}
parms = parms | lepOKAY;
return sle;
}
SLE::pointer Ledger::getAccountRoot(const uint160& accountID)
{
LedgerStateParms qry = lepNONE;
return getASNode(qry, getAccountRootIndex(accountID), ltACCOUNT_ROOT);
}
SLE::pointer Ledger::getAccountRoot(const NewcoinAddress& naAccountID)
{
LedgerStateParms qry = lepNONE;
return getASNode(qry, getAccountRootIndex(naAccountID.getAccountID()), ltACCOUNT_ROOT);
}
//
// Directory
//
SLE::pointer Ledger::getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uNodeIndex, ltDIR_NODE);
}
//
// Generator Map
//
SLE::pointer Ledger::getGenerator(LedgerStateParms& parms, const uint160& uGeneratorID)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, getGeneratorIndex(uGeneratorID), ltGENERATOR_MAP);
}
//
// Nickname
//
SLE::pointer Ledger::getNickname(LedgerStateParms& parms, const uint256& uNickname)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uNickname, ltNICKNAME);
}
//
// Offer
//
SLE::pointer Ledger::getOffer(LedgerStateParms& parms, const uint256& uIndex)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uIndex, ltOFFER);
}
//
// Ripple State
//
SLE::pointer Ledger::getRippleState(LedgerStateParms& parms, const uint256& uNode)
{
ScopedLock l(mAccountStateMap->Lock());
return getASNode(parms, uNode, ltRIPPLE_STATE);
}
// vim:ts=4

View File

@@ -9,14 +9,14 @@
LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& tx, uint32 closeTime,
const NewcoinAddress& naPeerPublic) :
mPreviousLedger(pLgr), mCurrentHash(tx), mCloseTime(closeTime), mProposeSeq(seq)
mPreviousLedger(pLgr), mCurrentHash(tx), mCloseTime(closeTime), mProposeSeq(seq), mPublicKey(naPeerPublic)
{
mPublicKey = naPeerPublic;
// XXX Validate key.
// if (!mKey->SetPubKey(pubKey))
// throw std::runtime_error("Invalid public key in proposal");
mPeerID = mPublicKey.getNodeID();
mTime = boost::posix_time::second_clock::universal_time();
}
@@ -27,12 +27,13 @@ LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prev
mPublicKey = NewcoinAddress::createNodePublic(naSeed);
mPrivateKey = NewcoinAddress::createNodePrivate(naSeed);
mPeerID = mPublicKey.getNodeID();
mTime = boost::posix_time::second_clock::universal_time();
}
LedgerProposal::LedgerProposal(const uint256& prevLgr, const uint256& position, uint32 closeTime) :
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0)
{
;
mTime = boost::posix_time::second_clock::universal_time();
}
uint256 LedgerProposal::getSigningHash() const
@@ -53,11 +54,22 @@ bool LedgerProposal::checkSign(const std::string& signature, const uint256& sign
return mPublicKey.verifyNodePublic(signingHash, signature);
}
void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime)
bool LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime)
{
mCurrentHash = newPosition;
mCloseTime = closeTime;
if (mProposeSeq == seqLeave)
return false;
mCurrentHash = newPosition;
mCloseTime = closeTime;
mTime = boost::posix_time::second_clock::universal_time();
++mProposeSeq;
return true;
}
void LedgerProposal::bowOut()
{
mTime = boost::posix_time::second_clock::universal_time();
mProposeSeq = seqLeave;
}
std::vector<unsigned char> LedgerProposal::sign(void)
@@ -76,9 +88,14 @@ Json::Value LedgerProposal::getJson() const
{
Json::Value ret = Json::objectValue;
ret["previous_ledger"] = mPreviousLedger.GetHex();
ret["transaction_hash"] = mCurrentHash.GetHex();
if (mProposeSeq != seqLeave)
{
ret["transaction_hash"] = mCurrentHash.GetHex();
ret["propose_seq"] = mProposeSeq;
}
ret["close_time"] = mCloseTime;
ret["propose_seq"] = mProposeSeq;
if (mPublicKey.isValid())
ret["peer_id"] = mPublicKey.humanNodePublic();

View File

@@ -1,7 +1,8 @@
#ifndef __PROPOSELEDGER__
#define __PROPOSELEDEGR__
#define __PROPOSELEDGER__
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
@@ -21,7 +22,11 @@ protected:
NewcoinAddress mPublicKey;
NewcoinAddress mPrivateKey; // If ours
std::string mSignature; // set only if needed
boost::posix_time::ptime mTime;
public:
static const uint32 seqLeave = 0xffffffff; // leaving the consensus process
typedef boost::shared_ptr<LedgerProposal> pointer;
@@ -39,17 +44,28 @@ public:
uint256 getSigningHash() const;
bool checkSign(const std::string& signature, const uint256& signingHash);
bool checkSign(const std::string& signature) { return checkSign(signature, getSigningHash()); }
bool checkSign() { return checkSign(mSignature, getSigningHash()); }
const uint160& getPeerID() const { return mPeerID; }
const uint256& getCurrentHash() const { return mCurrentHash; }
const uint256& getPrevLedger() const { return mPreviousLedger; }
uint32 getProposeSeq() const { return mProposeSeq; }
uint32 getCloseTime() const { return mCloseTime; }
const NewcoinAddress& peekPublic() const { return mPublicKey; }
std::vector<unsigned char> getPubKey() const { return mPublicKey.getNodePublic(); }
const NewcoinAddress& peekPublic() const { return mPublicKey; }
std::vector<unsigned char> getPubKey() const { return mPublicKey.getNodePublic(); }
std::vector<unsigned char> sign();
void changePosition(const uint256& newPosition, uint32 newCloseTime);
void setPrevLedger(const uint256& prevLedger) { mPreviousLedger = prevLedger; }
void setSignature(const std::string& signature) { mSignature = signature; }
bool hasSignature() { return !mSignature.empty(); }
bool isPrevLedger(const uint256& pl) { return mPreviousLedger == pl; }
bool isBowOut() { return mProposeSeq == seqLeave; }
const boost::posix_time::ptime getCreateTime() { return mTime; }
bool isStale(boost::posix_time::ptime cutoff) { return mTime <= cutoff; }
bool changePosition(const uint256& newPosition, uint32 newCloseTime);
void bowOut();
Json::Value getJson() const;
};

View File

@@ -12,46 +12,45 @@ int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 1
// Called when a ledger is open and no close is in progress -- when a transaction is received and no close
// is in process, or when a close completes. Returns the number of seconds the ledger should be be open.
int ContinuousLedgerTiming::shouldClose(
bool ContinuousLedgerTiming::shouldClose(
bool anyTransactions,
int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed this ledgers
int previousMSeconds, // seconds the previous ledger took to reach consensus
int currentMSeconds) // seconds since the previous ledger closed
int currentMSeconds, // seconds since the previous ledger closed
int idleInterval) // network's desired idle interval
{
assert((previousMSeconds > 0) && (previousMSeconds < 600000));
assert((currentMSeconds >= 0) && (currentMSeconds < 600000));
#if 0
Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") %
(anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds);
#endif
if ((previousMSeconds < -1000) || (previousMSeconds > 600000) ||
(currentMSeconds < -1000) || (currentMSeconds > 600000))
{
Log(lsWARNING) <<
boost::str(boost::format("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)")
% (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed
% currentMSeconds % previousMSeconds);
return true;
}
if (!anyTransactions)
{ // no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
{
Log(lsTRACE) << "no transactions, many proposers: now";
return currentMSeconds;
Log(lsTRACE) << "no transactions, many proposers: now (" << proposersClosed << " closed, "
<< previousProposers << " before)";
return true;
}
#if 0 // This false triggers on the genesis ledger
if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close
{
Log(lsTRACE) << "slow to close";
Log(lsTRACE) << "was slow to converge (p=" << (previousMSeconds) << ")";
if (previousMSeconds < 2000)
return previousMSeconds;
return previousMSeconds - 1000;
}
return LEDGER_IDLE_INTERVAL * 1000; // normal idle
#endif
return currentMSeconds >= (idleInterval * 1000); // normal idle
}
if (previousMSeconds == (1000 * LEDGER_IDLE_INTERVAL)) // coming out of idle, close now
{
Log(lsTRACE) << "leaving idle, close now";
return currentMSeconds;
}
Log(lsTRACE) << "close now";
return currentMSeconds; // this ledger should close now
return true; // this ledger should close now
}
// Returns whether we have a consensus or not. If so, we expect all honest nodes
@@ -101,7 +100,6 @@ bool ContinuousLedgerTiming::haveConsensus(
int ContinuousLedgerTiming::getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq)
{
assert(ledgerSeq);
assert(previousAgree); // TEMPORARY
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
{ // reduce resolution
int i = 1;

View File

@@ -4,8 +4,14 @@
// The number of seconds a ledger may remain idle before closing
# define LEDGER_IDLE_INTERVAL 15
// The number of seconds a validation remains current
# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 4)
// The number of seconds a validation remains current after its ledger's close time
// This is a safety to protect against very old validations and the time it takes to adjust
// the close time accuracy window
# define LEDGER_VAL_INTERVAL 600
// The number of seconds before a close time that we consider a validation acceptable
// This protects against extreme clock errors
# define LEDGER_EARLY_INTERVAL 240
// The number of milliseconds we wait minimum to ensure participation
# define LEDGER_MIN_CONSENSUS 2000
@@ -22,6 +28,16 @@
// How often we check state or change positions (in milliseconds)
# define LEDGER_GRANULARITY 1000
// The percentage of active trusted validators that must be able to
// keep up with the network or we consider the network overloaded
# define LEDGER_NET_RATIO 70
// How long we consider a proposal fresh
# define PROPOSE_FRESHNESS 20
// How often we force generating a new proposal to keep ours fresh
# define PROPOSE_INTERVAL 12
// Avalanche tuning
#define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
@@ -40,10 +56,11 @@ public:
// Returns the number of seconds the ledger was or should be open
// Call when a consensus is reached and when any transaction is relayed to be added
static int shouldClose(
static bool shouldClose(
bool anyTransactions,
int previousProposers, int proposersClosed,
int previousSeconds, int currentSeconds);
int previousSeconds, int currentSeconds,
int idleInterval);
static bool haveConsensus(
int previousProposers, int currentProposers,

View File

@@ -10,6 +10,8 @@ boost::recursive_mutex Log::sLock;
LogSeverity Log::sMinSeverity = lsINFO;
std::ofstream* Log::outStream = NULL;
boost::filesystem::path *Log::pathToLog = NULL;
uint32 Log::logRotateCounter = 0;
Log::~Log()
{
@@ -31,6 +33,48 @@ Log::~Log()
(*outStream) << logMsg << std::endl;
}
std::string Log::rotateLog(void)
{
boost::recursive_mutex::scoped_lock sl(sLock);
boost::filesystem::path abs_path;
std::string abs_path_str;
uint32 failsafe = 0;
std::string abs_new_path_str;
do {
std::string s;
std::stringstream out;
failsafe++;
if (failsafe == std::numeric_limits<uint32>::max()) {
return "unable to create new log file; too many log files!";
}
abs_path = boost::filesystem::absolute("");
abs_path /= *pathToLog;
abs_path_str = abs_path.parent_path().string();
out << logRotateCounter;
s = out.str();
abs_new_path_str = abs_path_str + "/" + s + + "_" + pathToLog->filename().string();
logRotateCounter++;
} while (boost::filesystem::exists(boost::filesystem::path(abs_new_path_str)));
outStream->close();
boost::filesystem::rename(abs_path, boost::filesystem::path(abs_new_path_str));
setLogFile(*pathToLog);
return abs_new_path_str;
}
void Log::setMinSeverity(LogSeverity s)
{
boost::recursive_mutex::scoped_lock sl(sLock);
@@ -52,4 +96,6 @@ void Log::setLogFile(boost::filesystem::path path)
outStream = newStream;
if (outStream)
Log(lsINFO) << "Starting up";
pathToLog = new boost::filesystem::path(path);
}

View File

@@ -6,6 +6,12 @@
#include <boost/thread/recursive_mutex.hpp>
#include <boost/filesystem.hpp>
// Ensure that we don't get value.h without writer.h
#include "../json/json.h"
#include "types.h"
#include <limits>
enum LogSeverity
{
lsTRACE = 0,
@@ -30,6 +36,9 @@ protected:
mutable std::ostringstream oss;
LogSeverity mSeverity;
static boost::filesystem::path *pathToLog;
static uint32 logRotateCounter;
public:
Log(LogSeverity s) : mSeverity(s)
{ ; }
@@ -48,6 +57,7 @@ public:
static void setMinSeverity(LogSeverity);
static void setLogFile(boost::filesystem::path);
static std::string rotateLog(void);
};
#endif

View File

@@ -25,7 +25,7 @@
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0),
mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL)
mLastCloseProposers(0), mLastCloseConvergeTime(1000 * LEDGER_IDLE_INTERVAL), mLastValidationTime(0)
{
}
@@ -33,7 +33,7 @@ boost::posix_time::ptime NetworkOPs::getNetworkTimePT()
{
int offset = 0;
theApp->getSystemTimeOffset(offset);
return boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(offset);
return boost::posix_time::microsec_clock::universal_time() + boost::posix_time::seconds(offset);
}
uint32 NetworkOPs::getNetworkTimeNC()
@@ -46,32 +46,62 @@ uint32 NetworkOPs::getCloseTimeNC()
return iToSeconds(getNetworkTimePT() + boost::posix_time::seconds(mCloseTimeOffset));
}
uint32 NetworkOPs::getValidationTimeNC()
{
uint32 vt = getNetworkTimeNC();
if (vt <= mLastValidationTime)
vt = mLastValidationTime + 1;
mLastValidationTime = vt;
return vt;
}
void NetworkOPs::closeTimeOffset(int offset)
{ // take large offsets, ignore small offsets, push towards our wall time
if (offset > 1)
mCloseTimeOffset += (offset + 3) / 4;
else if (offset < -1)
mCloseTimeOffset += (offset - 3) / 4;
else
mCloseTimeOffset = (mCloseTimeOffset * 3) / 4;
if (mCloseTimeOffset)
Log(lsINFO) << "Close time offset now " << mCloseTimeOffset;
}
uint32 NetworkOPs::getLedgerID(const uint256& hash)
{
Ledger::ref lrLedger = mLedgerMaster->getLedgerByHash(hash);
return lrLedger ? lrLedger->getLedgerSeq() : 0;
}
uint32 NetworkOPs::getCurrentLedgerID()
{
return mLedgerMaster->getCurrentLedger()->getLedgerSeq();
}
// Sterilize transaction through serialization.
Transaction::pointer NetworkOPs::submitTransaction(Transaction::pointer tpTrans)
Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& tpTrans)
{
Serializer s;
tpTrans->getSTransaction()->add(s);
std::vector<unsigned char> vucTransaction = s.getData();
SerializerIterator sit(s);
Transaction::pointer tpTransNew = Transaction::sharedTransaction(s.getData(), true);
assert(tpTransNew);
if(!tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction()))
{
Log(lsFATAL) << "Transaction reconstruction failure";
Log(lsFATAL) << tpTransNew->getSTransaction()->getJson(0);
Log(lsFATAL) << tpTrans->getSTransaction()->getJson(0);
assert(false);
}
(void) NetworkOPs::processTransaction(tpTransNew);
return tpTransNew;
}
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, uint32 tgtLedger, Peer* source)
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
{
Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
if (dbtx) return dbtx;
@@ -83,8 +113,19 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
return trans;
}
TransactionEngineResult r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tepNONE);
if (r == tenFAILED) throw Fault(IO_ERROR);
TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER);
#ifdef DEBUG
if (r != tesSUCCESS)
{
std::string token, human;
if (transResultInfo(r, token, human))
Log(lsINFO) << "TransactionResult: " << token << ": " << human;
}
#endif
if (r == tefFAILURE)
throw Fault(IO_ERROR);
if (r == terPRE_SEQ)
{ // transaction should be held
@@ -94,14 +135,14 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
mLedgerMaster->addHeldTransaction(trans);
return trans;
}
if ((r == terPAST_SEQ) || (r == terPAST_LEDGER))
if ((r == tefPAST_SEQ))
{ // duplicate or conflict
Log(lsINFO) << "Transaction is obsolete";
trans->setStatus(OBSOLETE);
return trans;
}
if (r == terSUCCESS)
if (r == tesSUCCESS)
{
Log(lsINFO) << "Transaction is now included";
trans->setStatus(INCLUDED);
@@ -118,10 +159,10 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
tx.set_rawtransaction(&s.getData().front(), s.getLength());
tx.set_status(newcoin::tsCURRENT);
tx.set_receivetimestamp(getNetworkTimeNC());
tx.set_ledgerindexpossible(trans->getLedger());
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, newcoin::mtTRANSACTION);
theApp->getConnectionPool().relayMessage(source, packet);
int sentTo = theApp->getConnectionPool().relayMessage(source, packet);
Log(lsINFO) << "Transaction relayed to " << sentTo << " node(s)";
return trans;
}
@@ -135,7 +176,6 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
tx.set_rawtransaction(&s.getData().front(), s.getLength());
tx.set_status(newcoin::tsCURRENT);
tx.set_receivetimestamp(getNetworkTimeNC());
tx.set_ledgerindexpossible(tgtLedger);
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, newcoin::mtTRANSACTION);
theApp->getConnectionPool().relayMessage(source, packet);
}
@@ -191,7 +231,11 @@ SLE::pointer NetworkOPs::getGenerator(const uint256& uLedger, const uint160& uGe
{
LedgerStateParms qry = lepNONE;
return mLedgerMaster->getLedgerByHash(uLedger)->getGenerator(qry, uGeneratorID);
Ledger::pointer ledger = mLedgerMaster->getLedgerByHash(uLedger);
if (!ledger)
return SLE::pointer();
else
return ledger->getGenerator(qry, uGeneratorID);
}
//
@@ -213,12 +257,12 @@ STVector256 NetworkOPs::getDirNodeInfo(
{
Log(lsDEBUG) << "getDirNodeInfo: node index: " << uNodeIndex.ToString();
Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(sleNode->getIFieldU64(sfIndexPrevious));
Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(sleNode->getIFieldU64(sfIndexNext));
Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(sleNode->getFieldU64(sfIndexPrevious));
Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(sleNode->getFieldU64(sfIndexNext));
uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious);
uNodeNext = sleNode->getIFieldU64(sfIndexNext);
svIndexes = sleNode->getIFieldV256(sfIndexes);
uNodePrevious = sleNode->getFieldU64(sfIndexPrevious);
uNodeNext = sleNode->getFieldU64(sfIndexNext);
svIndexes = sleNode->getFieldV256(sfIndexes);
Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(uNodePrevious);
Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(uNodeNext);
@@ -254,7 +298,7 @@ Json::Value NetworkOPs::getOwnerInfo(const uint256& uLedger, const NewcoinAddres
Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddress& naAccount)
{
Json::Value jvObjects(Json::arrayValue);
Json::Value jvObjects(Json::objectValue);
uint256 uRootIndex = lpLedger->getOwnerDirIndex(naAccount.getAccountID());
@@ -267,18 +311,40 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr
do
{
STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes);
STVector256 svIndexes = sleNode->getFieldV256(sfIndexes);
const std::vector<uint256>& vuiIndexes = svIndexes.peekValue();
BOOST_FOREACH(const uint256& uDirEntry, vuiIndexes)
{
LedgerStateParms lspOffer = lepNONE;
SLE::pointer sleOffer = lpLedger->getOffer(lspOffer, uDirEntry);
SLE::pointer sleCur = lpLedger->getSLE(uDirEntry);
jvObjects.append(sleOffer->getJson(0));
switch (sleCur->getType())
{
case ltOFFER:
if (!jvObjects.isMember("offers"))
jvObjects["offers"] = Json::Value(Json::arrayValue);
jvObjects["offers"].append(sleCur->getJson(0));
break;
case ltRIPPLE_STATE:
if (!jvObjects.isMember("ripple_lines"))
jvObjects["ripple_lines"] = Json::Value(Json::arrayValue);
jvObjects["ripple_lines"].append(sleCur->getJson(0));
break;
case ltACCOUNT_ROOT:
case ltDIR_NODE:
case ltGENERATOR_MAP:
case ltNICKNAME:
default:
assert(false);
break;
}
}
uNodeDir = sleNode->getIFieldU64(sfIndexNext);
uNodeDir = sleNode->getFieldU64(sfIndexNext);
if (uNodeDir)
{
lspNode = lepNONE;
@@ -292,15 +358,6 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr
return jvObjects;
}
//
// Ripple functions
//
RippleState::pointer NetworkOPs::accessRippleState(const uint256& uLedger, const uint256& uIndex)
{
return mLedgerMaster->getLedgerByHash(uLedger)->accessRippleState(uIndex);
}
//
// Other
//
@@ -322,16 +379,20 @@ public:
{
if (trustedValidations > v.trustedValidations) return true;
if (trustedValidations < v.trustedValidations) return false;
if (nodesUsing > v.nodesUsing) return true;
if (nodesUsing < v.nodesUsing) return false;
if (trustedValidations == 0)
{
if (nodesUsing > v.nodesUsing) return true;
if (nodesUsing < v.nodesUsing) return false;
}
return highNode > v.highNode;
}
};
void NetworkOPs::checkState(const boost::system::error_code& result)
{ // Network state machine
if (result == boost::asio::error::operation_aborted)
if ((result == boost::asio::error::operation_aborted) || theConfig.RUN_STANDALONE)
return;
setStateTimer();
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
@@ -344,7 +405,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
Log(lsWARNING) << "Node count (" << peerList.size() <<
") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ").";
}
setStateTimer();
return;
}
if (mMode == omDISCONNECTED)
@@ -356,7 +416,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
if (mConsensus)
{
mConsensus->timerEntry();
setStateTimer();
return;
}
@@ -383,15 +442,13 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
// check if the ledger is good enough to go to omFULL
// Note: Do not go to omFULL if we don't have the previous ledger
// check if the ledger is bad enough to go to omCONNECTED -- TODO
if (theApp->getOPs().getNetworkTimeNC() <
(theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4))
if (theApp->getOPs().getNetworkTimeNC() < theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC())
setMode(omFULL);
else
Log(lsINFO) << "Will try to go to FULL in consensus window";
}
if (mMode == omFULL)
{
// WRITEME
// check if the ledger is bad enough to go to omTRACKING
}
@@ -399,7 +456,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger());
if (mConsensus)
mConsensus->timerEntry();
setStateTimer();
}
bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerList, uint256& networkClosed)
@@ -412,17 +468,18 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
// node is using. THis is kind of fundamental.
Log(lsTRACE) << "NetworkOPs::checkLastClosedLedger";
boost::unordered_map<uint256, ValidationCount> ledgers;
{
boost::unordered_map<uint256, int> current = theApp->getValidations().getCurrentValidations();
for (boost::unordered_map<uint256, int>::iterator it = current.begin(), end = current.end(); it != end; ++it)
ledgers[it->first].trustedValidations += it->second;
}
Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger();
uint256 closedLedger = ourClosed->getHash();
uint256 prevClosedLedger = ourClosed->getParentHash();
boost::unordered_map<uint256, ValidationCount> ledgers;
{
boost::unordered_map<uint256, int> current = theApp->getValidations().getCurrentValidations(closedLedger);
typedef std::pair<const uint256, int> u256_int_pair;
BOOST_FOREACH(u256_int_pair& it, current)
ledgers[it.first].trustedValidations += it.second;
}
ValidationCount& ourVC = ledgers[closedLedger];
if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING))
@@ -431,23 +488,22 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
ourVC.highNode = theApp->getWallet().getNodePublic();
}
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
BOOST_FOREACH(Peer::ref it, peerList)
{
if (!*it)
if (!it)
{
Log(lsDEBUG) << "NOP::CS Dead pointer in peer list";
}
else if ((*it)->isConnected())
else if (it->isConnected())
{
uint256 peerLedger = (*it)->getClosedLedgerHash();
uint256 peerLedger = it->getClosedLedgerHash();
if (peerLedger.isNonZero())
{
ValidationCount& vc = ledgers[peerLedger];
if ((vc.nodesUsing == 0) || ((*it)->getNodePublic() > vc.highNode))
vc.highNode = (*it)->getNodePublic();
if ((vc.nodesUsing == 0) || (it->getNodePublic() > vc.highNode))
vc.highNode = it->getNodePublic();
++vc.nodesUsing;
}
else Log(lsTRACE) << "Connected peer announces no LCL " << (*it)->getIP();
}
}
@@ -458,9 +514,9 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
for (boost::unordered_map<uint256, ValidationCount>::iterator it = ledgers.begin(), end = ledgers.end();
it != end; ++it)
{
Log(lsTRACE) << "L: " << it->first.GetHex() <<
" t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing;
if ((it->second > bestVC) && !theApp->getValidations().isDeadLedger(it->first))
Log(lsTRACE) << "L: " << it->first << " t=" << it->second.trustedValidations <<
", n=" << it->second.nodesUsing;
if (it->second > bestVC)
{
bestVC = it->second;
closedLedger = it->first;
@@ -488,16 +544,17 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
}
Log(lsWARNING) << "We are not running on the consensus ledger";
Log(lsINFO) << "Our LCL " << ourClosed->getHash().GetHex();
Log(lsINFO) << "Net LCL " << closedLedger.GetHex();
Log(lsINFO) << "Our LCL " << ourClosed->getHash();
Log(lsINFO) << "Net LCL " << closedLedger;
if ((mMode == omTRACKING) || (mMode == omFULL))
setMode(omCONNECTED);
Ledger::pointer consensus = mLedgerMaster->getLedgerByHash(closedLedger);
if (!consensus)
{
Log(lsINFO) << "Acquiring consensus ledger " << closedLedger.GetHex();
LedgerAcquire::pointer mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
Log(lsINFO) << "Acquiring consensus ledger " << closedLedger;
if (!mAcquiringLedger || (mAcquiringLedger->getHash() != closedLedger))
mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
if (!mAcquiringLedger || mAcquiringLedger->isFailed())
{
theApp->getMasterLedgerAcquire().dropLedger(closedLedger);
@@ -508,23 +565,19 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
{ // add more peers
int count = 0;
std::vector<Peer::pointer> peers=theApp->getConnectionPool().getPeerVector();
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end();
it != end; ++it)
BOOST_FOREACH(Peer::ref it, peerList)
{
if ((*it)->getClosedLedgerHash() == closedLedger)
if (it->getClosedLedgerHash() == closedLedger)
{
++count;
mAcquiringLedger->peerHas(*it);
mAcquiringLedger->peerHas(it);
}
}
if (!count)
{ // just ask everyone
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end();
it != end; ++it)
{
if ((*it)->isConnected())
mAcquiringLedger->peerHas(*it);
}
BOOST_FOREACH(Peer::ref it, peerList)
if (it->isConnected())
mAcquiringLedger->peerHas(it);
}
return true;
}
@@ -542,9 +595,9 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringCo
{ // set the newledger as our last closed ledger -- this is abnormal code
if (duringConsensus)
Log(lsERROR) << "JUMPdc last closed ledger to " << newLedger->getHash().GetHex();
Log(lsERROR) << "JUMPdc last closed ledger to " << newLedger->getHash();
else
Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash().GetHex();
Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash();
newLedger->setClosed();
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*newLedger));
@@ -565,7 +618,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringCo
int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger)
{
Log(lsINFO) << "Consensus time for ledger " << closingLedger->getLedgerSeq();
Log(lsINFO) << " LCL is " << closingLedger->getParentHash().GetHex();
Log(lsINFO) << " LCL is " << closingLedger->getParentHash();
Ledger::pointer prevLedger = mLedgerMaster->getLedgerByHash(closingLedger->getParentHash());
if (!prevLedger)
@@ -582,14 +635,33 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo
prevLedger->setImmutable();
mConsensus = boost::make_shared<LedgerConsensus>(
networkClosed, prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
mConsensus->swapDefer(mDeferredProposals);
Log(lsDEBUG) << "Initiating consensus engine";
return mConsensus->startup();
}
bool NetworkOPs::haveConsensusObject()
{
if (mConsensus)
return true;
if (mMode != omFULL)
return false;
uint256 networkClosed;
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
bool ledgerChange = checkLastClosedLedger(peerList, networkClosed);
if (!ledgerChange)
{
Log(lsWARNING) << "Beginning consensus due to peer action";
beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger());
}
return mConsensus;
}
// <-- bool: true to relay
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime,
const std::string& pubKey, const std::string& signature)
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger,
uint32 closeTime, const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic)
{
// JED: does mConsensus need to be locked?
@@ -597,89 +669,123 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint
// XXX Take a vuc for pubkey.
// Get a preliminary hash to use to suppress duplicates
Serializer s(128);
Serializer s(256);
s.add256(proposeHash);
s.add256(prevLedger);
s.add32(proposeSeq);
s.add32(getCurrentLedgerID());
s.add32(closeTime);
s.addRaw(pubKey);
s.addRaw(signature);
if (!theApp->isNew(s.getSHA512Half()))
return false;
if (!mConsensus)
{ // FIXME: CLC
Log(lsWARNING) << "Received proposal when full but not during consensus window";
NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey));
if (!haveConsensusObject())
{
Log(lsINFO) << "Received proposal outside consensus window";
return mMode != omFULL;
}
// Is this node on our UNL?
if (!theApp->getUNL().nodeInUNL(naPeerPublic))
{
Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << proposeHash;
return true;
}
if (prevLedger.isNonZero())
{ // proposal includes a previous ledger
LedgerProposal::pointer proposal =
boost::make_shared<LedgerProposal>(prevLedger, proposeSeq, proposeHash, closeTime, naPeerPublic);
if (!proposal->checkSign(signature))
{
Log(lsWARNING) << "New-style ledger proposal fails signature check";
return false;
}
if (prevLedger == mConsensus->getLCL())
return mConsensus->peerPosition(proposal);
mConsensus->deferProposal(proposal, nodePublic);
return false;
}
NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey));
LedgerProposal::pointer proposal =
boost::make_shared<LedgerProposal>(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, naPeerPublic);
if (!proposal->checkSign(signature))
{ // Note that if the LCL is different, the signature check will fail
Log(lsWARNING) << "Ledger proposal fails signature check";
proposal->setSignature(signature);
mConsensus->deferProposal(proposal, nodePublic);
return false;
}
// Is this node on our UNL?
if (!theApp->getUNL().nodeInUNL(proposal->peekPublic()))
{
Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " <<
proposal->getCurrentHash().GetHex();
return true;
}
return mConsensus->peerPosition(proposal);
}
SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash)
{
if (!mConsensus) return SHAMap::pointer();
if (!haveConsensusObject())
return SHAMap::pointer();
return mConsensus->getTransactionTree(hash, false);
}
bool NetworkOPs::gotTXData(boost::shared_ptr<Peer> peer, const uint256& hash,
bool NetworkOPs::gotTXData(const boost::shared_ptr<Peer>& peer, const uint256& hash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData)
{
if (!mConsensus) return false;
if (!haveConsensusObject())
return false;
return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData);
}
bool NetworkOPs::hasTXSet(boost::shared_ptr<Peer> peer, const uint256& set, newcoin::TxSetStatus status)
bool NetworkOPs::hasTXSet(const boost::shared_ptr<Peer>& peer, const uint256& set, newcoin::TxSetStatus status)
{
if (!mConsensus) return false;
if (!haveConsensusObject())
{
Log(lsINFO) << "Peer has TX set, not during consensus";
return false;
}
return mConsensus->peerHasSet(peer, set, status);
}
void NetworkOPs::mapComplete(const uint256& hash, SHAMap::pointer map)
void NetworkOPs::mapComplete(const uint256& hash, SHAMap::ref map)
{
if (mConsensus)
if (!haveConsensusObject())
mConsensus->mapComplete(hash, map, true);
}
void NetworkOPs::endConsensus(bool correctLCL)
{
uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash();
Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead";
theApp->getValidations().addDeadLedger(deadLedger);
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
if (*it && ((*it)->getClosedLedgerHash() == deadLedger))
{
Log(lsTRACE) << "Killing obsolete peer status";
(*it)->cycleStatus();
}
BOOST_FOREACH(Peer::ref it, peerList)
if (it && (it->getClosedLedgerHash() == deadLedger))
{
Log(lsTRACE) << "Killing obsolete peer status";
it->cycleStatus();
}
mConsensus->swapDefer(mDeferredProposals);
mConsensus = boost::shared_ptr<LedgerConsensus>();
}
void NetworkOPs::consensusViewChange()
{
if ((mMode == omFULL) || (mMode == omTRACKING))
setMode(omCONNECTED);
}
void NetworkOPs::setMode(OperatingMode om)
{
if (mMode == om) return;
if ((om >= omCONNECTED) && (mMode == omDISCONNECTED))
mConnectTime = boost::posix_time::second_clock::universal_time();
Log l((om < mMode) ? lsWARNING : lsINFO);
if (om == omDISCONNECTED) l << "STATE->Disonnected";
else if (om == omCONNECTED) l << "STATE->Connected";
else if (om == omTRACKING) l << "STATE->Tracking";
else l << "STATE->Full";
Log lg((om < mMode) ? lsWARNING : lsINFO);
if (om == omDISCONNECTED)
lg << "STATE->Disconnected";
else if (om == omCONNECTED)
lg << "STATE->Connected";
else if (om == omTRACKING)
lg << "STATE->Tracking";
else
lg << "STATE->Full";
mMode = om;
}
@@ -726,9 +832,9 @@ std::vector<NewcoinAddress>
return accounts;
}
bool NetworkOPs::recvValidation(SerializedValidation::pointer val)
bool NetworkOPs::recvValidation(const SerializedValidation::pointer& val)
{
Log(lsINFO) << "recvValidation " << val->getLedgerHash().GetHex();
Log(lsINFO) << "recvValidation " << val->getLedgerHash();
return theApp->getValidations().addValidation(val);
}
@@ -748,6 +854,11 @@ Json::Value NetworkOPs::getServerInfo()
if (!theConfig.VALIDATION_SEED.isValid()) info["serverState"] = "none";
else info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic();
Json::Value lastClose = Json::objectValue;
lastClose["proposers"] = theApp->getOPs().getPreviousProposers();
lastClose["convergeTime"] = theApp->getOPs().getPreviousConvergeTime();
info["lastClose"] = lastClose;
if (mConsensus)
info["consensus"] = mConsensus->getJson();
@@ -758,7 +869,7 @@ Json::Value NetworkOPs::getServerInfo()
// Monitoring: publisher side
//
Json::Value NetworkOPs::pubBootstrapAccountInfo(const Ledger::pointer& lpAccepted, const NewcoinAddress& naAccountID)
Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const NewcoinAddress& naAccountID)
{
Json::Value jvObj(Json::objectValue);
@@ -793,7 +904,7 @@ void NetworkOPs::pubAccountInfo(const NewcoinAddress& naAccountID, const Json::V
}
}
void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted)
void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
{
{
boost::interprocess::sharable_lock<boost::interprocess::interprocess_upgradable_mutex> sl(mMonitorLock);
@@ -854,7 +965,7 @@ void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted)
SerializedTransaction::pointer stTxn = theApp->getMasterTransaction().fetch(item, false, 0);
// XXX Need to support other results.
// XXX Need to give failures too.
TransactionEngineResult terResult = terSUCCESS;
TER terResult = tesSUCCESS;
if (bAll)
{
@@ -888,7 +999,7 @@ void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted)
// XXX Publish delta information for accounts.
}
Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TransactionEngineResult terResult, const std::string& strStatus, int iSeq, const std::string& strType)
Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terResult, const std::string& strStatus, int iSeq, const std::string& strType)
{
Json::Value jvObj(Json::objectValue);
std::string strToken;
@@ -906,7 +1017,7 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, Transactio
return jvObj;
}
void NetworkOPs::pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState)
void NetworkOPs::pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState)
{
Json::Value jvObj = transJson(stTxn, terResult, pState, lpCurrent->getLedgerSeq(), "transaction");
@@ -916,7 +1027,7 @@ void NetworkOPs::pubTransactionAll(const Ledger::pointer& lpCurrent, const Seria
}
}
void NetworkOPs::pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState)
void NetworkOPs::pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState)
{
boost::unordered_set<InfoSub*> usisNotify;
@@ -951,7 +1062,7 @@ void NetworkOPs::pubTransactionAccounts(const Ledger::pointer& lpCurrent, const
}
}
void NetworkOPs::pubTransaction(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult)
void NetworkOPs::pubTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult)
{
boost::interprocess::sharable_lock<boost::interprocess::interprocess_upgradable_mutex> sl(mMonitorLock);

View File

@@ -1,17 +1,18 @@
#ifndef __NETWORK_OPS__
#define __NETWORK_OPS__
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "AccountState.h"
#include "LedgerMaster.h"
#include "NicknameState.h"
#include "RippleState.h"
#include "SerializedValidation.h"
#include "LedgerAcquire.h"
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "LedgerProposal.h"
// Operations that clients may wish to perform against the network
// Master operational handler, server sequencer, network tracker
@@ -54,6 +55,8 @@ protected:
boost::posix_time::ptime mConnectTime;
boost::asio::deadline_timer mNetTimer;
boost::shared_ptr<LedgerConsensus> mConsensus;
boost::unordered_map<uint160,
std::list<LedgerProposal::pointer> > mDeferredProposals;
LedgerMaster* mLedgerMaster;
LedgerAcquire::pointer mAcquiringLedger;
@@ -63,7 +66,8 @@ protected:
// last ledger close
int mLastCloseProposers, mLastCloseConvergeTime;
uint256 mLastCloseHash;
uint32 mLastCloseNetTime;
uint32 mLastCloseTime;
uint32 mLastValidationTime;
// XXX Split into more locks.
boost::interprocess::interprocess_upgradable_mutex mMonitorLock;
@@ -77,11 +81,12 @@ protected:
void setMode(OperatingMode);
Json::Value transJson(const SerializedTransaction& stTxn, TransactionEngineResult terResult, const std::string& strStatus, int iSeq, const std::string& strType);
void pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState);
void pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState);
Json::Value transJson(const SerializedTransaction& stTxn, TER terResult, const std::string& strStatus, int iSeq, const std::string& strType);
void pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState);
void pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState);
bool haveConsensusObject();
Json::Value pubBootstrapAccountInfo(const Ledger::pointer& lpAccepted, const NewcoinAddress& naAccountID);
Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const NewcoinAddress& naAccountID);
public:
NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster);
@@ -89,7 +94,10 @@ public:
// network information
uint32 getNetworkTimeNC();
uint32 getCloseTimeNC();
uint32 getValidationTimeNC();
void closeTimeOffset(int);
boost::posix_time::ptime getNetworkTimePT();
uint32 getLedgerID(const uint256& hash);
uint32 getCurrentLedgerID();
OperatingMode getOperatingMode() { return mMode; }
inline bool available() {
@@ -97,21 +105,21 @@ public:
return mMode >= omTRACKING;
}
Ledger::pointer getCurrentLedger() { return mLedgerMaster->getCurrentLedger(); }
Ledger::pointer getLedgerByHash(const uint256& hash) { return mLedgerMaster->getLedgerByHash(hash); }
Ledger::pointer getLedgerBySeq(const uint32 seq) { return mLedgerMaster->getLedgerBySeq(seq); }
uint256 getClosedLedger()
{ return mLedgerMaster->getClosedLedger()->getHash(); }
// FIXME: This function is basically useless since the hash is constantly changing and the ledger
// is ephemeral and mutable.
uint256 getCurrentLedger()
{ return mLedgerMaster->getCurrentLedger()->getHash(); }
SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); }
//
// Transaction operations
//
Transaction::pointer submitTransaction(Transaction::pointer tpTrans);
Transaction::pointer submitTransaction(const Transaction::pointer& tpTrans);
Transaction::pointer processTransaction(Transaction::pointer transaction, uint32 targetLedger = 0,
Peer* source = NULL);
Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL);
Transaction::pointer findTransactionByID(const uint256& transactionID);
int findTransactionsBySource(const uint256& uLedger, std::list<Transaction::pointer>&, const NewcoinAddress& sourceAccount,
uint32 minSeq, uint32 maxSeq);
@@ -129,8 +137,8 @@ public:
// Directory functions
//
STVector256 getDirNodeInfo(const uint256& uLedger, const uint256& uRootIndex,
uint64& uNodePrevious, uint64& uNodeNext);
STVector256 getDirNodeInfo(const uint256& uLedger, const uint256& uRootIndex,
uint64& uNodePrevious, uint64& uNodeNext);
//
// Nickname functions
@@ -145,21 +153,6 @@ public:
Json::Value getOwnerInfo(const uint256& uLedger, const NewcoinAddress& naAccount);
Json::Value getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddress& naAccount);
//
// Ripple functions
//
bool getDirLineInfo(const uint256& uLedger, const NewcoinAddress& naAccount, uint256& uRootIndex)
{
LedgerStateParms lspNode = lepNONE;
uRootIndex = Ledger::getRippleDirIndex(naAccount.getAccountID());
return !!mLedgerMaster->getLedgerByHash(uLedger)->getDirNode(lspNode, uRootIndex);
}
RippleState::pointer accessRippleState(const uint256& uLedger, const uint256& uIndex);
// raw object operations
bool findRawLedger(const uint256& ledgerHash, std::vector<unsigned char>& rawLedger);
bool findRawTransaction(const uint256& transactionHash, std::vector<unsigned char>& rawTransaction);
@@ -173,14 +166,14 @@ public:
const std::vector<unsigned char>& myNode, std::list< std::vector<unsigned char> >& newNodes);
// ledger proposal/close functions
bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime,
const std::string& pubKey, const std::string& signature);
bool gotTXData(boost::shared_ptr<Peer> peer, const uint256& hash,
bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, uint32 closeTime,
const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic);
bool gotTXData(const boost::shared_ptr<Peer>& peer, const uint256& hash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
bool recvValidation(SerializedValidation::pointer val);
bool recvValidation(const SerializedValidation::pointer& val);
SHAMap::pointer getTXMap(const uint256& hash);
bool hasTXSet(boost::shared_ptr<Peer> peer, const uint256& set, newcoin::TxSetStatus status);
void mapComplete(const uint256& hash, SHAMap::pointer map);
bool hasTXSet(const boost::shared_ptr<Peer>& peer, const uint256& set, newcoin::TxSetStatus status);
void mapComplete(const uint256& hash, SHAMap::ref map);
// network state machine
void checkState(const boost::system::error_code& result);
@@ -188,12 +181,14 @@ public:
bool checkLastClosedLedger(const std::vector<Peer::pointer>&, uint256& networkClosed);
int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger);
void endConsensus(bool correctLCL);
void setStandAlone() { setMode(omFULL); }
void setStateTimer();
void newLCL(int proposers, int convergeTime, const uint256& ledgerHash);
void consensusViewChange();
int getPreviousProposers() { return mLastCloseProposers; }
int getPreviousConvergeTime() { return mLastCloseConvergeTime; }
uint32 getLastCloseNetTime() { return mLastCloseNetTime; }
void setLastCloseNetTime(uint32 t) { mLastCloseNetTime = t; }
uint32 getLastCloseTime() { return mLastCloseTime; }
void setLastCloseTime(uint32 t) { mLastCloseTime = t; }
Json::Value getServerInfo();
// client information retrieval functions
@@ -207,8 +202,8 @@ public:
//
void pubAccountInfo(const NewcoinAddress& naAccountID, const Json::Value& jvObj);
void pubLedger(const Ledger::pointer& lpAccepted);
void pubTransaction(const Ledger::pointer& lpLedger, const SerializedTransaction& stTxn, TransactionEngineResult terResult);
void pubLedger(Ledger::ref lpAccepted);
void pubTransaction(Ledger::ref lpLedger, const SerializedTransaction& stTxn, TER terResult);
//
// Monitoring: subscriber side

View File

@@ -95,6 +95,15 @@ NewcoinAddress NewcoinAddress::createNodePublic(const std::vector<unsigned char>
return naNew;
}
NewcoinAddress NewcoinAddress::createNodePublic(const std::string& strPublic)
{
NewcoinAddress naNew;
naNew.setNodePublic(strPublic);
return naNew;
}
uint160 NewcoinAddress::getNodeID() const
{
switch (nVersion) {

View File

@@ -46,6 +46,7 @@ public:
static NewcoinAddress createNodePublic(const NewcoinAddress& naSeed);
static NewcoinAddress createNodePublic(const std::vector<unsigned char>& vPublic);
static NewcoinAddress createNodePublic(const std::string& strPublic);
//
// Node Private
@@ -72,6 +73,9 @@ public:
bool setAccountID(const std::string& strAccountID);
void setAccountID(const uint160& hash160In);
static NewcoinAddress createAccountID(const std::string& strAccountID)
{ NewcoinAddress na; na.setAccountID(strAccountID); return na; }
static NewcoinAddress createAccountID(const uint160& uiAccountID);
static std::string createHumanAccountID(const uint160& uiAccountID)

View File

@@ -8,19 +8,19 @@ NicknameState::NicknameState(SerializedLedgerEntry::pointer ledgerEntry) :
bool NicknameState::haveMinimumOffer() const
{
return mLedgerEntry->getIFieldPresent(sfMinimumOffer);
return mLedgerEntry->isFieldPresent(sfMinimumOffer);
}
STAmount NicknameState::getMinimumOffer() const
{
return mLedgerEntry->getIFieldPresent(sfMinimumOffer)
? mLedgerEntry->getIValueFieldAmount(sfMinimumOffer)
return mLedgerEntry->isFieldPresent(sfMinimumOffer)
? mLedgerEntry->getFieldAmount(sfMinimumOffer)
: STAmount();
}
NewcoinAddress NicknameState::getAccountID() const
{
return mLedgerEntry->getIValueFieldAccount(sfAccount);
return mLedgerEntry->getFieldAccount(sfAccount);
}
void NicknameState::addJson(Json::Value& val)

17
src/Operation.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include "Operation.h"
#include "Config.h"
/*
We also need to charge for each op
*/
namespace Script {
int Operation::getFee()
{
return(theConfig.FEE_CONTRACT_OPERATION);
}
}

222
src/Operation.h Normal file
View File

@@ -0,0 +1,222 @@
#include "Interpreter.h"
namespace Script {
// Contracts are non typed have variable data types
class Operation
{
public:
// returns false if there was an error
virtual bool work(Interpreter* interpreter)=0;
virtual int getFee();
virtual ~Operation() { ; }
};
// this is just an Int in the code
class IntOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->getIntData();
if(data->isInt32())
{
interpreter->pushStack( data );
return(true);
}
return(false);
}
};
class FloatOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->getFloatData();
if(data->isFloat())
{
interpreter->pushStack( data );
return(true);
}
return(false);
}
};
class Uint160Op : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->getUint160Data();
if(data->isUint160())
{
interpreter->pushStack( data );
return(true);
}
return(false);
}
};
class AddOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()+data2->getFloat())));
else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()+data2->getInt())));
return(true);
}else
{
return(false);
}
}
};
class SubOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()-data2->getFloat())));
else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()-data2->getInt())));
return(true);
}else
{
return(false);
}
}
};
class StartBlockOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer offset=interpreter->getIntData();
return(interpreter->startBlock(offset->getInt()));
}
};
class EndBlockOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
return(interpreter->endBlock());
}
};
class StopOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
interpreter->stop();
return(true);
}
};
class AcceptDataOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->popStack();
if(data->isInt32())
{
interpreter->pushStack( interpreter->getAcceptData(data->getInt()) );
return(true);
}
return(false);
}
};
class JumpIfOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer offset=interpreter->getIntData();
Data::pointer cond=interpreter->popStack();
if(cond->isBool() && offset->isInt32())
{
if(cond->isTrue())
{
return(interpreter->jumpTo(offset->getInt()));
}
return(true);
}
return(false);
}
};
class JumpOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer offset=interpreter->getIntData();
if(offset->isInt32())
{
return(interpreter->jumpTo(offset->getInt()));
}
return(false);
}
};
class SendXNSOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer sourceID=interpreter->popStack();
Data::pointer destID=interpreter->popStack();
Data::pointer amount=interpreter->popStack();
if(sourceID->isUint160() && destID->isUint160() && amount->isInt32() && interpreter->canSign(sourceID->getUint160()))
{
// make sure:
// source is either, this contract, issuer, or acceptor
// TODO do the send
//interpreter->pushStack( send result);
return(true);
}
return(false);
}
};
class GetDataOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer index=interpreter->popStack();
if(index->isInt32())
{
interpreter->pushStack( interpreter->getContractData(index->getInt()));
return(true);
}
return(false);
}
};
}

23
src/OrderBook.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include "OrderBook.h"
#include "Ledger.h"
OrderBook::pointer OrderBook::newOrderBook(SerializedLedgerEntry::pointer ledgerEntry)
{
if(ledgerEntry->getType() != ltOFFER) return( OrderBook::pointer());
return( OrderBook::pointer(new OrderBook(ledgerEntry)));
}
OrderBook::OrderBook(SerializedLedgerEntry::pointer ledgerEntry)
{
const STAmount saTakerGets = ledgerEntry->getFieldAmount(sfTakerGets);
const STAmount saTakerPays = ledgerEntry->getFieldAmount(sfTakerPays);
mCurrencyIn = saTakerGets.getCurrency();
mCurrencyOut = saTakerPays.getCurrency();
mIssuerIn = saTakerGets.getIssuer();
mIssuerOut = saTakerPays.getIssuer();
mBookBase=Ledger::getBookBase(mCurrencyOut,mIssuerOut,mCurrencyIn,mIssuerIn);
}
// vim:ts=4

34
src/OrderBook.h Normal file
View File

@@ -0,0 +1,34 @@
#include "SerializedLedger.h"
#include <boost/shared_ptr.hpp>
/*
Encapsulates the SLE for an orderbook
*/
class OrderBook
{
uint256 mBookBase;
uint160 mCurrencyIn;
uint160 mCurrencyOut;
uint160 mIssuerIn;
uint160 mIssuerOut;
//SerializedLedgerEntry::pointer mLedgerEntry;
OrderBook(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
public:
typedef boost::shared_ptr<OrderBook> pointer;
// returns NULL if ledgerEntry doesn't point to an order
// if ledgerEntry is an Order it creates the OrderBook this order would live in
static OrderBook::pointer newOrderBook(SerializedLedgerEntry::pointer ledgerEntry);
uint256& getBookBase(){ return(mBookBase); }
uint160& getCurrencyIn(){ return(mCurrencyIn); }
uint160& getCurrencyOut(){ return(mCurrencyOut); }
uint160& getIssuerIn(){ return(mIssuerIn); }
uint160& getIssuerOut(){ return(mIssuerOut); }
// looks through the best offers to see how much it would cost to take the given amount
STAmount& getTakePrice(STAmount& takeAmount);
};

56
src/OrderBookDB.cpp Normal file
View File

@@ -0,0 +1,56 @@
#include "OrderBookDB.h"
#include "Log.h"
#include <boost/foreach.hpp>
// TODO: this would be way faster if we could just look under the order dirs
OrderBookDB::OrderBookDB(Ledger::pointer ledger)
{
// walk through the entire ledger looking for orderbook entries
uint256 currentIndex=ledger->getFirstLedgerIndex();
while(currentIndex.isNonZero())
{
SLE::pointer entry=ledger->getSLE(currentIndex);
OrderBook::pointer book=OrderBook::newOrderBook(entry);
if(book)
{
if( mKnownMap.find(book->getBookBase()) != mKnownMap.end() )
{
mKnownMap[book->getBookBase()]=true;
if(!book->getCurrencyIn())
{ // XNS
mXNSOrders.push_back(book);
}else
{
mIssuerMap[book->getIssuerIn()].push_back(book);
}
}
}
currentIndex=ledger->getNextLedgerIndex(currentIndex);
}
}
// return list of all orderbooks that want IssuerID
std::vector<OrderBook::pointer>& OrderBookDB::getBooks(const uint160& issuerID)
{
if( mIssuerMap.find(issuerID) == mIssuerMap.end() ) return mEmptyVector;
else return( mIssuerMap[issuerID]);
}
// return list of all orderbooks that want this issuerID and currencyID
void OrderBookDB::getBooks(const uint160& issuerID, const uint160& currencyID, std::vector<OrderBook::pointer>& bookRet)
{
if( mIssuerMap.find(issuerID) == mIssuerMap.end() )
{
BOOST_FOREACH(OrderBook::pointer book, mIssuerMap[issuerID])
{
if(book->getCurrencyIn()==currencyID)
{
bookRet.push_back(book);
}
}
}
}

30
src/OrderBookDB.h Normal file
View File

@@ -0,0 +1,30 @@
#include "Ledger.h"
#include "OrderBook.h"
/*
we can eventually make this cached and just update it as transactions come in.
But for now it is probably faster to just generate it each time
*/
class OrderBookDB
{
std::vector<OrderBook::pointer> mEmptyVector;
std::vector<OrderBook::pointer> mXNSOrders;
std::map<uint160, std::vector<OrderBook::pointer> > mIssuerMap;
std::map<uint256, bool > mKnownMap;
public:
OrderBookDB(Ledger::pointer ledger);
// return list of all orderbooks that want XNS
std::vector<OrderBook::pointer>& getXNSInBooks(){ return mXNSOrders; }
// return list of all orderbooks that want IssuerID
std::vector<OrderBook::pointer>& getBooks(const uint160& issuerID);
// return list of all orderbooks that want this issuerID and currencyID
void getBooks(const uint160& issuerID, const uint160& currencyID, std::vector<OrderBook::pointer>& bookRet);
// returns the best rate we can find
float getPrice(uint160& currencyIn,uint160& currencyOut);
};

201
src/Pathfinder.cpp Normal file
View File

@@ -0,0 +1,201 @@
#include "Pathfinder.h"
#include "Application.h"
#include "RippleLines.h"
#include "Log.h"
#include <boost/foreach.hpp>
/*
JED: V IIII
we just need to find a succession of the highest quality paths there until we find enough width
Don't do branching within each path
We have a list of paths we are working on but how do we compare the ones that are terminating in a different currency?
Loops
TODO: what is a good way to come up with multiple paths?
Maybe just change the sort criteria?
first a low cost one and then a fat short one?
OrderDB:
getXNSOffers();
// return list of all orderbooks that want XNS
// return list of all orderbooks that want IssuerID
// return list of all orderbooks that want this issuerID and currencyID
*/
/*
Test sending to XNS
Test XNS to XNS
Test offer in middle
Test XNS to USD
Test USD to EUR
*/
// we sort the options by:
// cost of path
// length of path
// width of path
// correct currency at the end
bool sortPathOptions(PathOption::pointer first, PathOption::pointer second)
{
if(first->mTotalCost<second->mTotalCost) return(true);
if(first->mTotalCost>second->mTotalCost) return(false);
if(first->mCorrectCurrency && !second->mCorrectCurrency) return(true);
if(!first->mCorrectCurrency && second->mCorrectCurrency) return(false);
if(first->mPath.getElementCount()<second->mPath.getElementCount()) return(true);
if(first->mPath.getElementCount()>second->mPath.getElementCount()) return(false);
if(first->mMinWidth<second->mMinWidth) return true;
return false;
}
PathOption::PathOption(uint160& srcAccount,uint160& srcCurrencyID,const uint160& dstCurrencyID)
{
mCurrentAccount=srcAccount;
mCurrencyID=srcCurrencyID;
mCorrectCurrency=(srcCurrencyID==dstCurrencyID);
mQuality=0;
mMinWidth=STAmount(dstCurrencyID,99999,80); // this will get lowered when we convert back to the correct currency
}
PathOption::PathOption(PathOption::pointer other)
{
// TODO:
}
Pathfinder::Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) :
mSrcAccountID(srcAccountID.getAccountID()), mDstAccountID(dstAccountID.getAccountID()), mDstAmount(dstAmount), mSrcCurrencyID(srcCurrencyID), mOrderBook(theApp->getMasterLedger().getCurrentLedger())
{
mLedger=theApp->getMasterLedger().getCurrentLedger();
}
bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet)
{
if(mLedger)
{
PathOption::pointer head(new PathOption(mSrcAccountID,mSrcCurrencyID,mDstAmount.getCurrency()));
addOptions(head);
for(int n=0; n<maxSearchSteps; n++)
{
std::list<PathOption::pointer> tempPaths=mBuildingPaths;
mBuildingPaths.clear();
BOOST_FOREACH(PathOption::pointer path,tempPaths)
{
addOptions(path);
}
if(checkComplete(retPathSet)) return(true);
}
}
return(false);
}
bool Pathfinder::checkComplete(STPathSet& retPathSet)
{
if(mCompletePaths.size())
{ // TODO: look through these and pick the most promising
int count=0;
BOOST_FOREACH(PathOption::pointer pathOption,mCompletePaths)
{
retPathSet.addPath(pathOption->mPath);
count++;
if(count>2) return(true);
}
return(true);
}
return(false);
}
// get all the options from this accountID
// if source is XNS
// every offer that wants XNS
// else
// every ripple line that starts with the source currency
// every offer that we can take that wants the source currency
void Pathfinder::addOptions(PathOption::pointer tail)
{
if(!tail->mCurrencyID)
{ // source XNS
BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXNSInBooks())
{
PathOption::pointer pathOption(new PathOption(tail));
STPathElement ele(uint160(), book->getCurrencyOut(), book->getIssuerOut());
pathOption->mPath.addElement(ele);
pathOption->mCurrentAccount=book->getIssuerOut();
pathOption->mCurrencyID=book->getCurrencyOut();
addPathOption(pathOption);
}
}else
{ // ripple
RippleLines rippleLines(tail->mCurrentAccount);
BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines())
{
// TODO: make sure we can move in the correct direction
STAmount balance=line->getBalance();
if(balance.getCurrency()==tail->mCurrencyID)
{ // we have a ripple line from the tail to somewhere else
PathOption::pointer pathOption(new PathOption(tail));
STPathElement ele(line->getAccountIDPeer().getAccountID(), uint160(), uint160());
pathOption->mPath.addElement(ele);
pathOption->mCurrentAccount=line->getAccountIDPeer().getAccountID();
addPathOption(pathOption);
}
}
// every offer that wants the source currency
std::vector<OrderBook::pointer> books;
mOrderBook.getBooks(tail->mCurrentAccount, tail->mCurrencyID, books);
BOOST_FOREACH(OrderBook::pointer book,books)
{
PathOption::pointer pathOption(new PathOption(tail));
STPathElement ele(uint160(), book->getCurrencyOut(), book->getIssuerOut());
pathOption->mPath.addElement(ele);
pathOption->mCurrentAccount=book->getIssuerOut();
pathOption->mCurrencyID=book->getCurrencyOut();
addPathOption(pathOption);
}
}
}
void Pathfinder::addPathOption(PathOption::pointer pathOption)
{
if(pathOption->mCurrencyID==mDstAmount.getCurrency())
{
pathOption->mCorrectCurrency=true;
if(pathOption->mCurrentAccount==mDstAccountID)
{ // this path is complete
mCompletePaths.push_back(pathOption);
}else mBuildingPaths.push_back(pathOption);
}
else
{
pathOption->mCorrectCurrency=false;
mBuildingPaths.push_back(pathOption);
}
}
// vim:ts=4

52
src/Pathfinder.h Normal file
View File

@@ -0,0 +1,52 @@
#include "SerializedTypes.h"
#include "NewcoinAddress.h"
#include "OrderBookDB.h"
#include <boost/shared_ptr.hpp>
/* this is a very simple implementation. This can be made way better.
We are simply flooding from the start. And doing an exhaustive search of all paths under maxSearchSteps. An easy improvement would be to flood from both directions
*/
class PathOption
{
public:
typedef boost::shared_ptr<PathOption> pointer;
STPath mPath;
bool mCorrectCurrency; // for the sorting
uint160 mCurrencyID; // what currency we currently have at the end of the path
uint160 mCurrentAccount; // what account is at the end of the path
int mTotalCost; // in send currency
STAmount mMinWidth; // in dest currency
float mQuality;
PathOption(uint160& srcAccount,uint160& srcCurrencyID,const uint160& dstCurrencyID);
PathOption(PathOption::pointer other);
};
class Pathfinder
{
uint160 mSrcAccountID;
uint160 mDstAccountID;
STAmount mDstAmount;
uint160 mSrcCurrencyID;
OrderBookDB mOrderBook;
Ledger::pointer mLedger;
std::list<PathOption::pointer> mBuildingPaths;
std::list<PathOption::pointer> mCompletePaths;
void addOptions(PathOption::pointer tail);
// returns true if any building paths are now complete?
bool checkComplete(STPathSet& retPathSet);
void addPathOption(PathOption::pointer pathOption);
public:
Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount);
// returns false if there is no path. otherwise fills out retPath
bool findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet);
};
// vim:ts=4

View File

@@ -12,7 +12,6 @@
#include "Peer.h"
#include "Config.h"
#include "Application.h"
#include "Conversion.h"
#include "SerializedTransaction.h"
#include "utils.h"
#include "Log.h"
@@ -140,7 +139,7 @@ void Peer::handleVerifyTimer(const boost::system::error_code& ecResult)
// Begin trying to connect. We are not connected till we know and accept peer's public key.
// Only takes IP addresses (not domains).
void Peer::connect(const std::string strIp, int iPort)
void Peer::connect(const std::string& strIp, int iPort)
{
int iPortAct = (iPort <= 0) ? SYSTEM_PEER_PORT : iPort;
@@ -260,7 +259,7 @@ void Peer::connected(const boost::system::error_code& error)
}
}
void Peer::sendPacketForce(PackedMessage::pointer packet)
void Peer::sendPacketForce(const PackedMessage::pointer& packet)
{
if (!mDetaching)
{
@@ -273,7 +272,7 @@ void Peer::sendPacketForce(PackedMessage::pointer packet)
}
}
void Peer::sendPacket(PackedMessage::pointer packet)
void Peer::sendPacket(const PackedMessage::pointer& packet)
{
if (packet)
{
@@ -572,8 +571,8 @@ void Peer::recvHello(newcoin::TMHello& packet)
(void) mVerifyTimer.cancel();
uint32 ourTime = theApp->getOPs().getNetworkTimeNC();
uint32 minTime = ourTime - 10;
uint32 maxTime = ourTime + 10;
uint32 minTime = ourTime - 20;
uint32 maxTime = ourTime + 20;
#ifdef DEBUG
if (packet.has_nettime())
@@ -586,7 +585,10 @@ void Peer::recvHello(newcoin::TMHello& packet)
if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime)))
{
Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off";
if (packet.nettime() > maxTime)
Log(lsINFO) << "Recv(Hello): " << getIP() << " :Clock far off +" << packet.nettime() - ourTime;
else if(packet.nettime() < minTime)
Log(lsINFO) << "Recv(Hello): " << getIP() << " :Clock far off -" << ourTime - packet.nettime();
}
else if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR))
{
@@ -646,9 +648,11 @@ void Peer::recvHello(newcoin::TMHello& packet)
{
memcpy(mClosedLedgerHash.begin(), packet.ledgerclosed().data(), 256 / 8);
if ((packet.has_ledgerprevious()) && (packet.ledgerprevious().size() == (256 / 8)))
{
memcpy(mPreviousLedgerHash.begin(), packet.ledgerprevious().data(), 256 / 8);
addLedger(mPreviousLedgerHash);
}
else mPreviousLedgerHash.zero();
mClosedLedgerTime = boost::posix_time::second_clock::universal_time();
}
bDetach = false;
@@ -697,13 +701,7 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet)
}
#endif
uint32 targetLedger = 0;
if (packet.has_ledgerindexfinal())
targetLedger = packet.ledgerindexfinal();
else if (packet.has_ledgerindexpossible())
targetLedger = packet.ledgerindexpossible();
tx = theApp->getOPs().processTransaction(tx, targetLedger, this);
tx = theApp->getOPs().processTransaction(tx, this);
if(tx->getStatus() != INCLUDED)
{ // transaction wasn't accepted into ledger
@@ -722,12 +720,14 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet)
return;
}
uint32 proposeSeq = packet.proposeseq();
uint256 currentTxHash;
uint256 currentTxHash, prevLedger;
memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32);
if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.closetime(),
packet.nodepubkey(), packet.signature()))
if ((packet.has_previousledger()) && (packet.previousledger().size() == 32))
memcpy(prevLedger.begin(), packet.previousledger().data(), 32);
if(theApp->getOPs().recvPropose(packet.proposeseq(), currentTxHash, prevLedger, packet.closetime(),
packet.nodepubkey(), packet.signature(), mNodePublic))
{ // FIXME: Not all nodes will want proposals
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, newcoin::mtPROPOSE_LEDGER);
theApp->getConnectionPool().relayMessage(this, message);
@@ -744,8 +744,11 @@ void Peer::recvHaveTxSet(newcoin::TMHaveTransactionSet& packet)
punishPeer(PP_INVALID_REQUEST);
return;
}
memcpy(hashes.begin(), packet.hash().data(), 32);
if (!theApp->getOPs().hasTXSet(shared_from_this(), hashes, packet.status()))
uint256 hash;
memcpy(hash.begin(), packet.hash().data(), 32);
if (packet.status() == newcoin::tsHAVE)
addTxSet(hash);
if (!theApp->getOPs().hasTXSet(shared_from_this(), hash, packet.status()))
punishPeer(PP_UNWANTED_DATA);
}
@@ -900,16 +903,19 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet)
if (packet.newevent() == newcoin::neLOST_SYNC)
{
Log(lsTRACE) << "peer has lost sync " << getIP();
if (!mClosedLedgerHash.isZero())
{
Log(lsTRACE) << "peer has lost sync " << getIP();
mClosedLedgerHash.zero();
}
mPreviousLedgerHash.zero();
mClosedLedgerHash.zero();
return;
}
if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8)))
{ // a peer has changed ledgers
memcpy(mClosedLedgerHash.begin(), packet.ledgerhash().data(), 256 / 8);
mClosedLedgerTime = ptFromSeconds(packet.networktime());
Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash.GetHex() << " " << getIP();
addLedger(mClosedLedgerHash);
Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash << " " << getIP();
}
else
{
@@ -920,6 +926,7 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet)
if (packet.has_ledgerhashprevious() && packet.ledgerhashprevious().size() == (256 / 8))
{
memcpy(mPreviousLedgerHash.begin(), packet.ledgerhashprevious().data(), 256 / 8);
addLedger(mPreviousLedgerHash);
}
else mPreviousLedgerHash.zero();
}
@@ -928,12 +935,11 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
{
SHAMap::pointer map;
newcoin::TMLedgerData reply;
bool fatLeaves = true;
bool fatLeaves = true, fatRoot = false;
if (packet.itype() == newcoin::liTS_CANDIDATE)
{ // Request is for a transaction candidate set
Log(lsINFO) << "Received request for TX candidate set data " << getIP();
Ledger::pointer ledger;
if ((!packet.has_ledgerhash() || packet.ledgerhash().size() != 32))
{
punishPeer(PP_INVALID_REQUEST);
@@ -944,7 +950,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
map = theApp->getOPs().getTXMap(txHash);
if (!map)
{
Log(lsERROR) << "We do not hav the map our peer wants";
Log(lsERROR) << "We do not have the map our peer wants";
punishPeer(PP_INVALID_REQUEST);
return;
}
@@ -952,6 +958,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
reply.set_ledgerhash(txHash.begin(), txHash.size());
reply.set_type(newcoin::liTS_CANDIDATE);
fatLeaves = false; // We'll already have most transactions
fatRoot = true; // Save a pass
}
else
{ // Figure out what ledger they want
@@ -968,6 +975,8 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
}
memcpy(ledgerhash.begin(), packet.ledgerhash().data(), 32);
ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash);
if (!ledger)
Log(lsINFO) << "Don't have ledger " << ledgerhash;
}
else if (packet.has_ledgerseq())
ledger = theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq());
@@ -986,7 +995,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
return;
}
if ((!ledger) || (packet.has_ledgerseq() && (packet.ledgerseq()!=ledger->getLedgerSeq())))
if ((!ledger) || (packet.has_ledgerseq() && (packet.ledgerseq() != ledger->getLedgerSeq())))
{
punishPeer(PP_UNKNOWN_REQUEST);
Log(lsWARNING) << "Can't find the ledger they want";
@@ -1007,13 +1016,13 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
reply.add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
if (packet.nodeids().size() != 0)
{
{ // new-style root request
Log(lsINFO) << "Ledger root w/map roots request";
SHAMap::pointer map = ledger->peekAccountStateMap();
if (map)
{
{ // return account state root node if possible
Serializer rootNode(768);
if (map->getRootNode(rootNode, STN_ARF_WIRE))
if (map->getRootNode(rootNode, snfWIRE))
{
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
if (ledger->getTransHash().isNonZero())
@@ -1022,7 +1031,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
if (map)
{
rootNode.resize(0);
if (map->getRootNode(rootNode, STN_ARF_WIRE))
if (map->getRootNode(rootNode, snfWIRE))
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
}
}
@@ -1057,7 +1066,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
}
std::vector<SHAMapNode> nodeIDs;
std::list< std::vector<unsigned char> > rawNodes;
if(map->getNodeFat(mn, nodeIDs, rawNodes, fatLeaves))
if(map->getNodeFat(mn, nodeIDs, rawNodes, fatRoot, fatLeaves))
{
std::vector<SHAMapNode>::iterator nodeIDIterator;
std::list< std::vector<unsigned char> >::iterator rawNodeIterator;
@@ -1074,7 +1083,8 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
}
}
}
if (packet.has_requestcookie()) reply.set_requestcookie(packet.requestcookie());
if (packet.has_requestcookie())
reply.set_requestcookie(packet.requestcookie());
PackedMessage::pointer oPacket = boost::make_shared<PackedMessage>(reply, newcoin::mtLEDGER_DATA);
sendPacket(oPacket);
}
@@ -1124,7 +1134,38 @@ void Peer::recvLedger(newcoin::TMLedgerData& packet)
bool Peer::hasLedger(const uint256& hash) const
{
return (hash == mClosedLedgerHash) || (hash == mPreviousLedgerHash);
BOOST_FOREACH(const uint256& ledger, mRecentLedgers)
if (ledger == hash)
return true;
return false;
}
void Peer::addLedger(const uint256& hash)
{
BOOST_FOREACH(const uint256& ledger, mRecentLedgers)
if (ledger == hash)
return;
if (mRecentLedgers.size() == 128)
mRecentLedgers.pop_front();
mRecentLedgers.push_back(hash);
}
bool Peer::hasTxSet(const uint256& hash) const
{
BOOST_FOREACH(const uint256& set, mRecentTxSets)
if (set == hash)
return true;
return false;
}
void Peer::addTxSet(const uint256& hash)
{
BOOST_FOREACH(const uint256& set, mRecentTxSets)
if (set == hash)
return;
if (mRecentTxSets.size() == 128)
mRecentTxSets.pop_front();
mRecentTxSets.push_back(hash);
}
// Get session information we can sign to prevent man in the middle attack.
@@ -1212,7 +1253,8 @@ Json::Value Peer::getJson()
//ret["this"] = ADDRESS(this);
ret["public_key"] = mNodePublic.ToString();
ret["ip"] = mIpPortConnect.first;
ret["port"] = mIpPortConnect.second;
//ret["port"] = mIpPortConnect.second;
ret["port"] = mIpPort.second;
if (mHello.has_fullversion())
ret["version"] = mHello.fullversion();

View File

@@ -24,13 +24,14 @@ typedef std::pair<std::string,int> ipPort;
class Peer : public boost::enable_shared_from_this<Peer>
{
public:
typedef boost::shared_ptr<Peer> pointer;
typedef boost::shared_ptr<Peer> pointer;
typedef const boost::shared_ptr<Peer>& ref;
static const int psbGotHello = 0, psbSentHello = 1, psbInMap = 2, psbTrusted = 3;
static const int psbNoLedgers = 4, psbNoTransactions = 5, psbDownLevel = 6;
void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it);
static void sHandleConnect(Peer::pointer ptr, const boost::system::error_code& error,
static void sHandleConnect(Peer::ref ptr, const boost::system::error_code& error,
boost::asio::ip::tcp::resolver::iterator it)
{ ptr->handleConnect(error, it); }
@@ -43,20 +44,20 @@ private:
ipPort mIpPortConnect;
uint256 mCookieHash;
// network state information
uint256 mClosedLedgerHash, mPreviousLedgerHash;
boost::posix_time::ptime mClosedLedgerTime;
uint256 mClosedLedgerHash, mPreviousLedgerHash;
std::list<uint256> mRecentLedgers;
std::list<uint256> mRecentTxSets;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> mSocketSsl;
boost::asio::deadline_timer mVerifyTimer;
void handleStart(const boost::system::error_code& ecResult);
static void sHandleStart(Peer::pointer ptr, const boost::system::error_code& ecResult)
static void sHandleStart(Peer::ref ptr, const boost::system::error_code& ecResult)
{ ptr->handleStart(ecResult); }
void handleVerifyTimer(const boost::system::error_code& ecResult);
static void sHandleVerifyTimer(Peer::pointer ptr, const boost::system::error_code& ecResult)
static void sHandleVerifyTimer(Peer::ref ptr, const boost::system::error_code& ecResult)
{ ptr->handleVerifyTimer(ecResult); }
protected:
@@ -70,26 +71,26 @@ protected:
Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx);
void handleShutdown(const boost::system::error_code& error) { ; }
static void sHandleShutdown(Peer::pointer ptr, const boost::system::error_code& error)
static void sHandleShutdown(Peer::ref ptr, const boost::system::error_code& error)
{ ptr->handleShutdown(error); }
void handle_write(const boost::system::error_code& error, size_t bytes_transferred);
static void sHandle_write(Peer::pointer ptr, const boost::system::error_code& error, size_t bytes_transferred)
static void sHandle_write(Peer::ref ptr, const boost::system::error_code& error, size_t bytes_transferred)
{ ptr->handle_write(error, bytes_transferred); }
void handle_read_header(const boost::system::error_code& error);
static void sHandle_read_header(Peer::pointer ptr, const boost::system::error_code& error)
static void sHandle_read_header(Peer::ref ptr, const boost::system::error_code& error)
{ ptr->handle_read_header(error); }
void handle_read_body(const boost::system::error_code& error);
static void sHandle_read_body(Peer::pointer ptr, const boost::system::error_code& error)
static void sHandle_read_body(Peer::ref ptr, const boost::system::error_code& error)
{ ptr->handle_read_body(error); }
void processReadBuffer();
void start_read_header();
void start_read_body(unsigned msg_len);
void sendPacketForce(PackedMessage::pointer packet);
void sendPacketForce(const PackedMessage::pointer& packet);
void sendHello();
@@ -117,6 +118,9 @@ protected:
void getSessionCookie(std::string& strDst);
void addLedger(const uint256& ledger);
void addTxSet(const uint256& TxSet);
public:
//bool operator == (const Peer& other);
@@ -136,31 +140,27 @@ public:
return mSocketSsl.lowest_layer();
}
void connect(const std::string strIp, int iPort);
void connect(const std::string& strIp, int iPort);
void connected(const boost::system::error_code& error);
void detach(const char *);
bool samePeer(Peer::pointer p) { return samePeer(*p); }
bool samePeer(const Peer& p) { return this == &p; }
bool samePeer(Peer::ref p) { return samePeer(*p); }
bool samePeer(const Peer& p) { return this == &p; }
void sendPacket(PackedMessage::pointer packet);
void sendLedgerProposal(Ledger::pointer ledger);
void sendFullLedger(Ledger::pointer ledger);
void sendPacket(const PackedMessage::pointer& packet);
void sendLedgerProposal(Ledger::ref ledger);
void sendFullLedger(Ledger::ref ledger);
void sendGetFullLedger(uint256& hash);
void sendGetPeers();
void punishPeer(PeerPunish pp);
Json::Value getJson();
bool isConnected() const { return mHelloed && !mDetaching; }
bool isConnected() const { return mHelloed && !mDetaching; }
//static PackedMessage::pointer createFullLedger(Ledger::pointer ledger);
static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger);
static PackedMessage::pointer createValidation(Ledger::pointer ledger);
static PackedMessage::pointer createGetFullLedger(uint256& hash);
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
bool hasLedger(const uint256& hash) const;
NewcoinAddress getNodePublic() const { return mNodePublic; }
bool hasTxSet(const uint256& hash) const;
NewcoinAddress getNodePublic() const { return mNodePublic; }
void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); }
};

View File

@@ -6,7 +6,6 @@
CKey::pointer PubKeyCache::locate(const NewcoinAddress& id)
{
if(1)
{ // is it in cache
boost::mutex::scoped_lock sl(mLock);
std::map<NewcoinAddress, CKey::pointer>::iterator it(mCache.find(id));
@@ -43,7 +42,7 @@ CKey::pointer PubKeyCache::locate(const NewcoinAddress& id)
return ckp;
}
CKey::pointer PubKeyCache::store(const NewcoinAddress& id, CKey::pointer key)
CKey::pointer PubKeyCache::store(const NewcoinAddress& id, const CKey::pointer& key)
{ // stored if needed, returns cached copy (possibly the original)
{
boost::mutex::scoped_lock sl(mLock);
@@ -52,14 +51,14 @@ CKey::pointer PubKeyCache::store(const NewcoinAddress& id, CKey::pointer key)
return pit.first->second;
}
std::vector<unsigned char> pk=key->GetPubKey();
std::vector<unsigned char> pk = key->GetPubKey();
std::string encodedPK;
theApp->getTxnDB()->getDB()->escape(&(pk.front()), pk.size(), encodedPK);
std::string sql="INSERT INTO PubKeys (ID,PubKey) VALUES ('";
sql+=id.humanAccountID();
sql+="',";
sql+=encodedPK;
std::string sql = "INSERT INTO PubKeys (ID,PubKey) VALUES ('";
sql += id.humanAccountID();
sql += "',";
sql += encodedPK;
sql.append(");");
ScopedLock dbl(theApp->getTxnDB()->getDBLock());

View File

@@ -18,7 +18,7 @@ public:
PubKeyCache() { ; }
CKey::pointer locate(const NewcoinAddress& id);
CKey::pointer store(const NewcoinAddress& id, CKey::pointer key);
CKey::pointer store(const NewcoinAddress& id, const CKey::pointer& key);
void clear();
};

File diff suppressed because it is too large Load Diff

View File

@@ -48,8 +48,10 @@ public:
// Bad parameter
rpcACT_MALFORMED,
rpcQUALITY_MALFORMED,
rpcBAD_SEED,
rpcDST_ACT_MALFORMED,
rpcDST_ACT_MISSING,
rpcDST_AMT_MALFORMED,
rpcGETS_ACT_MALFORMED,
rpcGETS_AMT_MALFORMED,
@@ -63,6 +65,7 @@ public:
rpcPORT_MALFORMED,
rpcPUBLIC_MALFORMED,
rpcSRC_ACT_MALFORMED,
rpcSRC_ACT_MISSING,
rpcSRC_AMT_MALFORMED,
// Internal error (should never happen)
@@ -138,6 +141,7 @@ private:
Json::Value doDataFetch(const Json::Value& params);
Json::Value doDataStore(const Json::Value& params);
Json::Value doLedger(const Json::Value& params);
Json::Value doLogRotate(const Json::Value& params);
Json::Value doNicknameInfo(const Json::Value& params);
Json::Value doNicknameSet(const Json::Value& params);
Json::Value doOfferCreate(const Json::Value& params);
@@ -145,7 +149,9 @@ private:
Json::Value doOwnerInfo(const Json::Value& params);
Json::Value doPasswordFund(const Json::Value& params);
Json::Value doPasswordSet(const Json::Value& params);
Json::Value doProfile(const Json::Value& params);
Json::Value doPeers(const Json::Value& params);
Json::Value doRipple(const Json::Value &params);
Json::Value doRippleLinesGet(const Json::Value &params);
Json::Value doRippleLineSet(const Json::Value& params);
Json::Value doSend(const Json::Value& params);
@@ -180,6 +186,7 @@ private:
Json::Value doLogin(const Json::Value& params);
public:
static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps)
{

2400
src/RippleCalc.cpp Normal file

File diff suppressed because it is too large Load Diff

190
src/RippleCalc.h Normal file
View File

@@ -0,0 +1,190 @@
#ifndef __RIPPLE_CALC__
#define __RIPPLE_CALC__
#include <boost/unordered_set.hpp>
#include "LedgerEntrySet.h"
class PaymentNode {
protected:
friend class RippleCalc;
friend class PathState;
uint16 uFlags; // --> From path.
uint160 uAccountID; // --> Accounts: Recieving/sending account.
uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send.
// --- For offer's next has currency out.
uint160 uIssuerID; // --> Currency's issuer
STAmount saTransferRate; // Transfer rate for uIssuerID.
// Computed by Reverse.
STAmount saRevRedeem; // <-- Amount to redeem to next.
STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs.
// Issue isn't used by offers.
STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee.
// Computed by forward.
STAmount saFwdRedeem; // <-- Amount node will redeem to next.
STAmount saFwdIssue; // <-- Amount node will issue to next.
// Issue isn't used by offers.
STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee.
// For offers:
STAmount saRateMax; // XXX Should rate be sticky for forward too?
// Directory
uint256 uDirectTip; // Current directory.
uint256 uDirectEnd; // Next order book.
bool bDirectAdvance; // Need to advance directory.
SLE::pointer sleDirectDir;
STAmount saOfrRate; // For correct ratio.
// Node
bool bEntryAdvance; // Need to advance entry.
unsigned int uEntry;
uint256 uOfferIndex;
SLE::pointer sleOffer;
uint160 uOfrOwnerID;
bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets.
STAmount saOfferFunds;
STAmount saTakerPays;
STAmount saTakerGets;
};
// account id, currency id, issuer id :: node
typedef boost::tuple<uint160, uint160, uint160> aciSource;
typedef boost::unordered_map<aciSource, unsigned int> curIssuerNode; // Map of currency, issuer to node index.
typedef boost::unordered_map<aciSource, unsigned int>::const_iterator curIssuerNodeConstIterator;
extern std::size_t hash_value(const aciSource& asValue);
// Holds a path state under incremental application.
class PathState
{
protected:
const Ledger::pointer& mLedger;
TER pushNode(const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
TER pushImply(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
public:
typedef boost::shared_ptr<PathState> pointer;
TER terStatus;
std::vector<PaymentNode> vpnNodes;
// When processing, don't want to complicate directory walking with deletion.
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded or were completely consumed.
// First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be
// used there.
curIssuerNode umForward; // Map of currency, issuer to node index.
// First time working in reverse a funding source was used.
// Source may only be used there if not mentioned by an account.
curIssuerNode umReverse; // Map of currency, issuer to node index.
LedgerEntrySet lesEntries;
int mIndex;
uint64 uQuality; // 0 = none.
STAmount saInReq; // Max amount to spend by sender
STAmount saInAct; // Amount spent by sender (calc output)
STAmount saOutReq; // Amount to send (calc input)
STAmount saOutAct; // Amount actually sent (calc output).
PathState(
const int iIndex,
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID,
const STAmount& saSend,
const STAmount& saSendMax
);
Json::Value getJson() const;
static PathState::pointer createPathState(
const int iIndex,
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID,
const STAmount& saSend,
const STAmount& saSendMax
)
{
return boost::make_shared<PathState>(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax);
}
static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs);
};
class RippleCalc
{
protected:
LedgerEntrySet& lesActive;
public:
// First time working in reverse a funding source was mentioned. Source may only be used there.
curIssuerNode mumSource; // Map of currency, issuer to node index.
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
PathState::pointer pathCreate(const STPath& spPath);
void pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
TER calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
TER calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
TER calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
TER calcNodeOfferRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
TER calcNodeOfferFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
TER calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
TER calcNodeAccountFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
TER calcNodeAdvance(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality, const bool bReverse);
TER calcNodeDeliverRev(
const unsigned int uIndex,
const PathState::pointer& pspCur,
const bool bMultiQuality,
const uint160& uOutAccountID,
const STAmount& saOutReq,
STAmount& saOutAct);
TER calcNodeDeliverFwd(
const unsigned int uIndex,
const PathState::pointer& pspCur,
const bool bMultiQuality,
const uint160& uInAccountID,
const STAmount& saInFunds,
const STAmount& saInReq,
STAmount& saInAct,
STAmount& saInFees);
void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut,
const STAmount& saPrvReq, const STAmount& saCurReq,
STAmount& saPrvAct, STAmount& saCurAct,
uint64& uRateMax);
RippleCalc(LedgerEntrySet& lesNodes) : lesActive(lesNodes) { ; }
static TER rippleCalc(
LedgerEntrySet& lesActive,
STAmount& saMaxAmountAct,
STAmount& saDstAmountAct,
const STAmount& saDstAmountReq,
const STAmount& saMaxAmountReq,
const uint160& uDstAccountID,
const uint160& uSrcAccountID,
const STPathSet& spsPaths,
const bool bPartialPayment,
const bool bLimitQuality,
const bool bNoRippleDirect
);
};
#endif
// vim:ts=4

54
src/RippleLines.cpp Normal file
View File

@@ -0,0 +1,54 @@
#include "RippleLines.h"
#include "Application.h"
#include "Log.h"
#include <boost/foreach.hpp>
RippleLines::RippleLines(const uint160& accountID, Ledger::pointer ledger)
{
fillLines(accountID,ledger);
}
RippleLines::RippleLines(const uint160& accountID )
{
fillLines(accountID,theApp->getMasterLedger().getCurrentLedger());
}
void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger)
{
uint256 rootIndex = Ledger::getOwnerDirIndex(accountID);
uint256 currentIndex = rootIndex;
LedgerStateParms lspNode = lepNONE;
while (1)
{
SLE::pointer rippleDir=ledger->getDirNode(lspNode, currentIndex);
if (!rippleDir) return;
STVector256 svOwnerNodes = rippleDir->getFieldV256(sfIndexes);
BOOST_FOREACH(uint256& uNode, svOwnerNodes.peekValue())
{
SLE::pointer sleCur = ledger->getSLE(uNode);
if (ltRIPPLE_STATE == sleCur->getType())
{
RippleState::pointer rsLine = ledger->accessRippleState(uNode);
if (rsLine)
{
rsLine->setViewAccount(accountID);
mLines.push_back(rsLine);
}
else
{
Log(lsWARNING) << "doRippleLinesGet: Bad index: " << uNode.ToString();
}
}
}
uint64 uNodeNext = rippleDir->getFieldU64(sfIndexNext);
if (!uNodeNext) return;
currentIndex = Ledger::getDirNodeIndex(rootIndex, uNodeNext);
}
}
// vim:ts=4

19
src/RippleLines.h Normal file
View File

@@ -0,0 +1,19 @@
#include "Ledger.h"
#include "RippleState.h"
/*
This pulls all the ripple lines of a given account out of the ledger.
It provides a vector so you to easily iterate through them
*/
class RippleLines
{
std::vector<RippleState::pointer> mLines;
void fillLines(const uint160& accountID, Ledger::pointer ledger);
public:
RippleLines(const uint160& accountID, Ledger::pointer ledger);
RippleLines(const uint160& accountID ); // looks in the current ledger
std::vector<RippleState::pointer>& getLines(){ return(mLines); }
};

View File

@@ -7,20 +7,26 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) :
{
if (!mLedgerEntry || mLedgerEntry->getType() != ltRIPPLE_STATE) return;
mLowID = mLedgerEntry->getIValueFieldAccount(sfLowID);
mHighID = mLedgerEntry->getIValueFieldAccount(sfHighID);
mLowLimit = mLedgerEntry->getFieldAmount(sfLowLimit);
mHighLimit = mLedgerEntry->getFieldAmount(sfHighLimit);
mLowLimit = mLedgerEntry->getIValueFieldAmount(sfLowLimit);
mHighLimit = mLedgerEntry->getIValueFieldAmount(sfHighLimit);
mLowID = NewcoinAddress::createAccountID(mLowLimit.getIssuer());
mHighID = NewcoinAddress::createAccountID(mHighLimit.getIssuer());
mBalance = mLedgerEntry->getIValueFieldAmount(sfBalance);
mLowQualityIn = mLedgerEntry->getFieldU32(sfLowQualityIn);
mLowQualityOut = mLedgerEntry->getFieldU32(sfLowQualityOut);
mHighQualityIn = mLedgerEntry->getFieldU32(sfHighQualityIn);
mHighQualityOut = mLedgerEntry->getFieldU32(sfHighQualityOut);
mBalance = mLedgerEntry->getFieldAmount(sfBalance);
mValid = true;
}
void RippleState::setViewAccount(const NewcoinAddress& naView)
void RippleState::setViewAccount(const uint160& accountID)
{
bool bViewLowestNew = mLowID.getAccountID() == naView.getAccountID();
bool bViewLowestNew = mLowID.getAccountID() == accountID;
if (bViewLowestNew != mViewLowest)
{

View File

@@ -24,6 +24,11 @@ private:
STAmount mLowLimit;
STAmount mHighLimit;
uint64 mLowQualityIn;
uint64 mLowQualityOut;
uint64 mHighQualityIn;
uint64 mHighQualityOut;
STAmount mBalance;
bool mValid;
@@ -32,7 +37,7 @@ private:
public:
RippleState(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
void setViewAccount(const NewcoinAddress& naView);
void setViewAccount(const uint160& accountID);
const NewcoinAddress getAccountID() const { return mViewLowest ? mLowID : mHighID; }
const NewcoinAddress getAccountIDPeer() const { return mViewLowest ? mHighID : mLowID; }
@@ -42,6 +47,9 @@ public:
STAmount getLimit() const { return mViewLowest ? mLowLimit : mHighLimit; }
STAmount getLimitPeer() const { return mViewLowest ? mHighLimit : mLowLimit; }
uint32 getQualityIn() const { return((uint32) (mViewLowest ? mLowQualityIn : mHighQualityIn)); }
uint32 getQualityOut() const { return((uint32) (mViewLowest ? mLowQualityOut : mHighQualityOut)); }
SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; }
const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; }
SerializedLedgerEntry& peekSLE() { return *mLedgerEntry; }

View File

@@ -39,14 +39,14 @@ std::size_t hash_value(const uint160& u)
}
SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(Modifying)
SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(smsModifying)
{
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
root->makeInner();
mTNByID[*root] = root;
}
SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(Synching)
SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(smsSynching)
{ // FIXME: Need to acquire root node
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
root->makeInner();
@@ -62,7 +62,7 @@ SHAMap::pointer SHAMap::snapShot(bool isMutable)
newMap.mTNByID = mTNByID;
newMap.root = root;
if (!isMutable)
newMap.mState = Immutable;
newMap.mState = smsImmutable;
return ret;
}
@@ -105,7 +105,7 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
{ // walk the tree up from through the inner nodes to the root
// update linking hashes and add nodes to dirty list
assert((mState != Synching) && (mState != Immutable));
assert((mState != smsSynching) && (mState != smsImmutable));
while (!stack.empty())
{
@@ -125,7 +125,7 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
return;
}
#ifdef ST_DEBUG
std::cerr << "dirtyUp sets branch " << branch << " to " << prevHash.GetHex() << std::endl;
std::cerr << "dirtyUp sets branch " << branch << " to " << prevHash << std::endl;
#endif
prevHash = node->getNodeHash();
assert(prevHash.isNonZero());
@@ -187,9 +187,9 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
if (node->getNodeHash() != hash)
{
std::cerr << "Attempt to get node, hash not in tree" << std::endl;
std::cerr << "ID: " << id.getString() << std::endl;
std::cerr << "TgtHash " << hash.GetHex() << std::endl;
std::cerr << "NodHash " << node->getNodeHash().GetHex() << std::endl;
std::cerr << "ID: " << id << std::endl;
std::cerr << "TgtHash " << hash << std::endl;
std::cerr << "NodHash " << node->getNodeHash() << std::endl;
dump();
throw std::runtime_error("invalid node");
}
@@ -238,42 +238,44 @@ SHAMapItem::SHAMapItem(const uint256& tag, const Serializer& data)
: mTag(tag), mData(data.peekData())
{ ; }
SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node)
SHAMapTreeNode* SHAMap::firstBelow(SHAMapTreeNode* node)
{
// Return the first item below this node
#ifdef ST_DEBUG
std::cerr << "firstBelow(" << node->getString() << ")" << std::endl;
std::cerr << "firstBelow(" << *node << ")" << std::endl;
#endif
do
{ // Walk down the tree
if (node->hasItem()) return node->peekItem();
if (node->hasItem()) return node;
bool foundNode = false;
for (int i = 0; i < 16; ++i)
if (!node->isEmptyBranch(i))
{
#ifdef ST_DEBUG
std::cerr << " FB: node " << node->getString() << std::endl;
std::cerr << " FB: node " << *node << std::endl;
std::cerr << " has non-empty branch " << i << " : " <<
node->getChildNodeID(i).getString() << ", " << node->getChildHash(i).GetHex() << std::endl;
node->getChildNodeID(i) << ", " << node->getChildHash(i) << std::endl;
#endif
node = getNodePointer(node->getChildNodeID(i), node->getChildHash(i));
foundNode = true;
break;
}
if (!foundNode) return SHAMapItem::pointer();
} while (1);
if (!foundNode)
return NULL;
} while (true);
}
SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node)
SHAMapTreeNode* SHAMap::lastBelow(SHAMapTreeNode* node)
{
#ifdef DEBUG
std::cerr << "lastBelow(" << node->getString() << ")" << std::endl;
std::cerr << "lastBelow(" << *node << ")" << std::endl;
#endif
do
{ // Walk down the tree
if (node->hasItem()) return node->peekItem();
if (node->hasItem())
return node;
bool foundNode = false;
for (int i = 15; i >= 0; ++i)
@@ -283,8 +285,9 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node)
foundNode = true;
break;
}
if (!foundNode) return SHAMapItem::pointer();
} while (1);
if (!foundNode)
return NULL;
} while (true);
}
SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode* node)
@@ -306,7 +309,7 @@ SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode* node)
if (!found)
{
std::cerr << node->getString() << std::endl;
std::cerr << *node << std::endl;
assert(false);
return SHAMapItem::pointer();
}
@@ -345,38 +348,69 @@ void SHAMap::eraseChildren(SHAMapTreeNode::pointer node)
SHAMapItem::pointer SHAMap::peekFirstItem()
{
boost::recursive_mutex::scoped_lock sl(mLock);
return firstBelow(root.get());
SHAMapTreeNode *node = firstBelow(root.get());
if (!node)
return SHAMapItem::pointer();
return node->peekItem();
}
SHAMapItem::pointer SHAMap::peekFirstItem(SHAMapTreeNode::TNType& type)
{
boost::recursive_mutex::scoped_lock sl(mLock);
SHAMapTreeNode *node = firstBelow(root.get());
if (!node)
return SHAMapItem::pointer();
type = node->getType();
return node->peekItem();
}
SHAMapItem::pointer SHAMap::peekLastItem()
{
boost::recursive_mutex::scoped_lock sl(mLock);
return lastBelow(root.get());
SHAMapTreeNode *node = lastBelow(root.get());
if (!node)
return SHAMapItem::pointer();
return node->peekItem();
}
SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
{
SHAMapTreeNode::TNType type;
return peekNextItem(id, type);
}
SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id, SHAMapTreeNode::TNType& type)
{ // Get a pointer to the next item in the tree after a given item - item must be in tree
boost::recursive_mutex::scoped_lock sl(mLock);
std::stack<SHAMapTreeNode::pointer> stack = getStack(id, true, false);
while(!stack.empty())
while (!stack.empty())
{
SHAMapTreeNode::pointer node = stack.top();
stack.pop();
if(node->isLeaf())
if (node->isLeaf())
{
if(node->peekItem()->getTag()>id)
return node->peekItem();
}
else for(int i = node->selectBranch(id) + 1; i < 16; ++i)
if(!node->isEmptyBranch(i))
if (node->peekItem()->getTag() > id)
{
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
SHAMapItem::pointer item = firstBelow(node.get());
if (!item) throw std::runtime_error("missing node");
return item;
type = node->getType();
return node->peekItem();
}
}
else
for (int i = node->selectBranch(id) + 1; i < 16; ++i)
if (!node->isEmptyBranch(i))
{
SHAMapTreeNode *firstNode = getNodePointer(node->getChildNodeID(i), node->getChildHash(i));
if (!firstNode)
throw std::runtime_error("missing node");
firstNode = firstBelow(firstNode);
if (!firstNode)
throw std::runtime_error("missing node");
type = firstNode->getType();
return firstNode->peekItem();
}
}
// must be last item
return SHAMapItem::pointer();
@@ -392,18 +426,19 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id)
SHAMapTreeNode::pointer node = stack.top();
stack.pop();
if(node->isLeaf())
if (node->isLeaf())
{
if(node->peekItem()->getTag()<id)
if (node->peekItem()->getTag() < id)
return node->peekItem();
}
else for(int i = node->selectBranch(id) - 1; i >= 0; --i)
if(!node->isEmptyBranch(i))
else for (int i = node->selectBranch(id) - 1; i >= 0; --i)
if (!node->isEmptyBranch(i))
{
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
SHAMapItem::pointer item = firstBelow(node.get());
if (!item) throw std::runtime_error("missing node");
return item;
SHAMapTreeNode* item = firstBelow(node.get());
if (!item)
throw std::runtime_error("missing node");
return item->peekItem();
}
}
// must be last item
@@ -414,7 +449,18 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id)
{
boost::recursive_mutex::scoped_lock sl(mLock);
SHAMapTreeNode* leaf = walkToPointer(id);
if (!leaf) return SHAMapItem::pointer();
if (!leaf)
return SHAMapItem::pointer();
return leaf->peekItem();
}
SHAMapItem::pointer SHAMap::peekItem(const uint256& id, SHAMapTreeNode::TNType& type)
{
boost::recursive_mutex::scoped_lock sl(mLock);
SHAMapTreeNode* leaf = walkToPointer(id);
if (!leaf)
return SHAMapItem::pointer();
type = leaf->getType();
return leaf->peekItem();
}
@@ -429,10 +475,10 @@ bool SHAMap::hasItem(const uint256& id)
bool SHAMap::delItem(const uint256& id)
{ // delete the item with this ID
boost::recursive_mutex::scoped_lock sl(mLock);
assert(mState != Immutable);
assert(mState != smsImmutable);
std::stack<SHAMapTreeNode::pointer> stack = getStack(id, true, false);
if(stack.empty())
if (stack.empty())
throw std::runtime_error("missing node");
SHAMapTreeNode::pointer leaf=stack.top();
@@ -442,7 +488,7 @@ bool SHAMap::delItem(const uint256& id)
SHAMapTreeNode::TNType type=leaf->getType();
returnNode(leaf, true);
if(mTNByID.erase(*leaf)==0)
if (mTNByID.erase(*leaf) == 0)
assert(false);
uint256 prevHash;
@@ -460,8 +506,8 @@ bool SHAMap::delItem(const uint256& id)
}
if (!node->isRoot())
{ // we may have made this a node with 1 or 0 children
int bc=node->getBranchCount();
if(bc==0)
int bc = node->getBranchCount();
if (bc == 0)
{
#ifdef DEBUG
std::cerr << "delItem makes empty node" << std::endl;
@@ -470,14 +516,14 @@ bool SHAMap::delItem(const uint256& id)
if (!mTNByID.erase(*node))
assert(false);
}
else if(bc==1)
else if (bc == 1)
{ // pull up on the thread
SHAMapItem::pointer item = onlyBelow(node.get());
if(item)
if (item)
{
eraseChildren(node);
#ifdef ST_DEBUG
std::cerr << "Making item node " << node->getString() << std::endl;
std::cerr << "Making item node " << *node << std::endl;
#endif
node->setItem(item, type);
}
@@ -495,10 +541,10 @@ bool SHAMap::delItem(const uint256& id)
return true;
}
bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta)
bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bool hasMeta)
{ // add the specified item, does not update
#ifdef ST_DEBUG
std::cerr << "aGI " << item->getTag().GetHex() << std::endl;
std::cerr << "aGI " << item->getTag() << std::endl;
#endif
uint256 tag = item->getTag();
@@ -506,7 +552,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM);
boost::recursive_mutex::scoped_lock sl(mLock);
assert(mState != Immutable);
assert(mState != smsImmutable);
std::stack<SHAMapTreeNode::pointer> stack = getStack(tag, true, false);
if (stack.empty())
@@ -521,19 +567,19 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
uint256 prevHash;
returnNode(node, true);
if(node->isInner())
if (node->isInner())
{ // easy case, we end on an inner node
#ifdef ST_DEBUG
std::cerr << "aGI inner " << node->getString() << std::endl;
std::cerr << "aGI inner " << *node << std::endl;
#endif
int branch = node->selectBranch(tag);
assert(node->isEmptyBranch(branch));
SHAMapTreeNode::pointer newNode =
boost::make_shared<SHAMapTreeNode>(node->getChildNodeID(branch), item, type, mSeq);
if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
{
std::cerr << "Node: " << node->getString() << std::endl;
std::cerr << "NewNode: " << newNode->getString() << std::endl;
std::cerr << "Node: " << *node << std::endl;
std::cerr << "NewNode: " << *newNode << std::endl;
dump();
assert(false);
throw std::runtime_error("invalid inner node");
@@ -543,8 +589,8 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
else
{ // this is a leaf node that has to be made an inner node holding two items
#ifdef ST_DEBUG
std::cerr << "aGI leaf " << node->getString() << std::endl;
std::cerr << "Existing: " << node->peekItem()->getTag().GetHex() << std::endl;
std::cerr << "aGI leaf " << *node << std::endl;
std::cerr << "Existing: " << node->peekItem()->getTag() << std::endl;
#endif
SHAMapItem::pointer otherItem = node->peekItem();
assert(otherItem && (tag != otherItem->getTag()));
@@ -562,7 +608,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
SHAMapTreeNode::pointer newNode =
boost::make_shared<SHAMapTreeNode>(mSeq, node->getChildNodeID(b1));
newNode->makeInner();
if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
assert(false);
stack.push(node);
node = newNode;
@@ -579,7 +625,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM
newNode = boost::make_shared<SHAMapTreeNode>(node->getChildNodeID(b2), otherItem, type, mSeq);
assert(newNode->isValid() && newNode->isLeaf());
if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
assert(false);
node->setChildHash(b2, newNode->getNodeHash());
}
@@ -593,12 +639,12 @@ bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction, bool hasMetaData)
return addGiveItem(boost::make_shared<SHAMapItem>(i), isTransaction, hasMetaData);
}
bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta)
bool SHAMap::updateGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bool hasMeta)
{ // can't change the tag but can change the hash
uint256 tag = item->getTag();
boost::recursive_mutex::scoped_lock sl(mLock);
assert(mState != Immutable);
assert(mState != smsImmutable);
std::stack<SHAMapTreeNode::pointer> stack = getStack(tag, true, false);
if (stack.empty()) throw std::runtime_error("missing node");
@@ -626,7 +672,7 @@ bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction, bool h
void SHAMapItem::dump()
{
std::cerr << "SHAMapItem(" << mTag.GetHex() << ") " << mData.size() << "bytes" << std::endl;
std::cerr << "SHAMapItem(" << mTag << ") " << mData.size() << "bytes" << std::endl;
}
SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const uint256& hash)
@@ -635,13 +681,13 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
throw SHAMapMissingNode(id, hash);
HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash));
if(!obj)
if (!obj)
throw SHAMapMissingNode(id, hash);
assert(Serializer::getSHA512Half(obj->getData()) == hash);
try
{
SHAMapTreeNode::pointer ret = boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq, STN_ARF_PREFIXED);
SHAMapTreeNode::pointer ret = boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq, snfPREFIX);
#ifdef DEBUG
assert((ret->getNodeHash() == hash) && (id == *ret));
#endif
@@ -649,7 +695,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
}
catch (...)
{
Log(lsWARNING) << "fetchNodeExternal gets an invalid node: " << hash.GetHex();
Log(lsWARNING) << "fetchNodeExternal gets an invalid node: " << hash;
throw SHAMapMissingNode(id, hash);
}
}
@@ -665,14 +711,14 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq)
int flushed = 0;
Serializer s;
if(mDirtyNodes)
if (mDirtyNodes)
{
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>& dirtyNodes = *mDirtyNodes;
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = dirtyNodes.begin();
while (it != dirtyNodes.end())
{
s.erase();
it->second->addRaw(s, STN_ARF_PREFIXED);
it->second->addRaw(s, snfPREFIX);
theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half());
if (flushed++ >= maxNodes)
return flushed;
@@ -714,10 +760,10 @@ void SHAMap::dump(bool hash)
#if 0
std::cerr << "SHAMap::dump" << std::endl;
SHAMapItem::pointer i=peekFirstItem();
while(i)
while (i)
{
std::cerr << "Item: id=" << i->getTag().GetHex() << std::endl;
i=peekNextItem(i->getTag());
std::cerr << "Item: id=" << i->getTag() << std::endl;
i = peekNextItem(i->getTag());
}
std::cerr << "SHAMap::dump done" << std::endl;
#endif
@@ -728,7 +774,8 @@ void SHAMap::dump(bool hash)
it != mTNByID.end(); ++it)
{
std::cerr << it->second->getString() << std::endl;
if(hash) std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl;
if (hash)
std::cerr << " " << it->second->getNodeHash() << std::endl;
}
}
@@ -756,8 +803,8 @@ BOOST_AUTO_TEST_CASE( SHAMap_test )
SHAMap sMap;
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
if(!sMap.addItem(i2, true, false)) BOOST_FAIL("no add");
if(!sMap.addItem(i1, true, false)) BOOST_FAIL("no add");
if (!sMap.addItem(i2, true, false)) BOOST_FAIL("no add");
if (!sMap.addItem(i1, true, false)) BOOST_FAIL("no add");
SHAMapItem::pointer i;

View File

@@ -24,7 +24,8 @@ class SHAMap;
class SHAMapNode
{ // Identifies a node in a SHA256 hash
public:
typedef boost::shared_ptr<SHAMapNode> pointer;
typedef boost::shared_ptr<SHAMapNode> pointer;
typedef const boost::shared_ptr<SHAMapNode>& ref;
private:
static uint256 smMasks[65]; // AND with hash to get node id
@@ -78,6 +79,8 @@ public:
extern std::size_t hash_value(const SHAMapNode& mn);
inline std::ostream& operator<<(std::ostream& out, const SHAMapNode& node) { return out << node.getString(); }
class SHAMapItem
{ // an item stored in a SHAMap
public:
@@ -122,6 +125,12 @@ public:
virtual void dump();
};
enum SHANodeFormat
{
snfPREFIX = 1, // Form that hashes to its official hash
snfWIRE = 2, // Compressed form used on the wire
};
class SHAMapTreeNode : public SHAMapNode
{
friend class SHAMap;
@@ -154,14 +163,11 @@ private:
public:
SHAMapTreeNode(uint32 seq, const SHAMapNode& nodeID); // empty node
SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq); // copy node from older tree
SHAMapTreeNode(const SHAMapNode& nodeID, SHAMapItem::pointer item, TNType type, uint32 seq);
#define STN_ARF_PREFIXED 1
#define STN_ARF_WIRE 2
SHAMapTreeNode(const SHAMapNode& nodeID, const SHAMapItem::pointer& item, TNType type, uint32 seq);
// raw node functions
SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& contents, uint32 seq, int format);
void addRaw(Serializer &, int format);
SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& data, uint32 seq, SHANodeFormat format);
void addRaw(Serializer &, SHANodeFormat format);
virtual bool isPopulated() const { return true; }
@@ -196,7 +202,7 @@ public:
bool hasItem() const { return !!mItem; }
SHAMapItem::pointer peekItem() { return mItem; }
SHAMapItem::pointer getItem() const;
bool setItem(SHAMapItem::pointer& i, TNType type);
bool setItem(const SHAMapItem::pointer& i, TNType type);
const uint256& getTag() const { return mItem->getTag(); }
const std::vector<unsigned char>& peekData() { return mItem->peekData(); }
std::vector<unsigned char> getData() const { return mItem->getData(); }
@@ -211,11 +217,11 @@ public:
enum SHAMapState
{
Modifying = 0, // Objects can be added and removed (like an open ledger)
Immutable = 1, // Map cannot be changed (like a closed ledger)
Synching = 2, // Map's hash is locked in, valid nodes can be added (like a peer's closing ledger)
Floating = 3, // Map is free to change hash (like a synching open ledger)
Invalid = 4, // Map is known not to be valid (usually synching a corrupt ledger)
smsModifying = 0, // Objects can be added and removed (like an open ledger)
smsImmutable = 1, // Map cannot be changed (like a closed ledger)
smsSynching = 2, // Map's hash is locked in, valid nodes can be added (like a peer's closing ledger)
smsFloating = 3, // Map is free to change hash (like a synching open ledger)
smsInvalid = 4, // Map is known not to be valid (usually synching a corrupt ledger)
};
class SHAMapSyncFilter
@@ -223,9 +229,11 @@ class SHAMapSyncFilter
public:
SHAMapSyncFilter() { ; }
virtual ~SHAMapSyncFilter() { ; }
virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash,
const std::vector<unsigned char>& nodeData, bool isLeaf)
{ ; }
virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector<unsigned char>& nodeData)
{ return false; }
};
@@ -242,6 +250,7 @@ public:
{ ; }
virtual ~SHAMapMissingNode() throw()
{ ; }
const SHAMapNode& getNodeID() const { return mNodeID; }
const uint256& getNodeHash() const { return mNodeHash; }
};
@@ -250,6 +259,8 @@ class SHAMap
{
public:
typedef boost::shared_ptr<SHAMap> pointer;
typedef const boost::shared_ptr<SHAMap>& ref;
typedef std::map<uint256, std::pair<SHAMapItem::pointer, SHAMapItem::pointer> > SHAMapDiff;
private:
@@ -275,9 +286,9 @@ protected:
SHAMapTreeNode::pointer getNode(const SHAMapNode& id);
SHAMapTreeNode::pointer getNode(const SHAMapNode& id, const uint256& hash, bool modify);
SHAMapTreeNode* getNodePointer(const SHAMapNode& id, const uint256& hash);
SHAMapTreeNode* firstBelow(SHAMapTreeNode*);
SHAMapTreeNode* lastBelow(SHAMapTreeNode*);
SHAMapItem::pointer firstBelow(SHAMapTreeNode*);
SHAMapItem::pointer lastBelow(SHAMapTreeNode*);
SHAMapItem::pointer onlyBelow(SHAMapTreeNode*);
void eraseChildren(SHAMapTreeNode::pointer);
@@ -290,6 +301,8 @@ public:
SHAMap(uint32 seq = 0);
SHAMap(const uint256& hash);
~SHAMap() { mState = smsInvalid; }
// Returns a new map that's a snapshot of this one. Force CoW
SHAMap::pointer snapShot(bool isMutable);
@@ -308,41 +321,44 @@ public:
uint256 getHash() { return root->getNodeHash(); }
// save a copy if you have a temporary anyway
bool updateGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta);
bool addGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta);
bool updateGiveItem(const SHAMapItem::pointer&, bool isTransaction, bool hasMeta);
bool addGiveItem(const SHAMapItem::pointer&, bool isTransaction, bool hasMeta);
// save a copy if you only need a temporary
SHAMapItem::pointer peekItem(const uint256& id);
SHAMapItem::pointer peekItem(const uint256& id, SHAMapTreeNode::TNType& type);
// traverse functions
SHAMapItem::pointer peekFirstItem();
SHAMapItem::pointer peekFirstItem(SHAMapTreeNode::TNType& type);
SHAMapItem::pointer peekLastItem();
SHAMapItem::pointer peekNextItem(const uint256&);
SHAMapItem::pointer peekNextItem(const uint256&, SHAMapTreeNode::TNType& type);
SHAMapItem::pointer peekPrevItem(const uint256&);
// comparison/sync functions
void getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& hashes, int max,
SHAMapSyncFilter* filter);
bool getNodeFat(const SHAMapNode& node, std::vector<SHAMapNode>& nodeIDs,
std::list<std::vector<unsigned char> >& rawNode, bool fatLeaves);
bool getRootNode(Serializer& s, int format);
bool addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, int format);
bool addRootNode(const std::vector<unsigned char>& rootNode, int format);
std::list<std::vector<unsigned char> >& rawNode, bool fatRoot, bool fatLeaves);
bool getRootNode(Serializer& s, SHANodeFormat format);
bool addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, SHANodeFormat format);
bool addRootNode(const std::vector<unsigned char>& rootNode, SHANodeFormat format);
bool addKnownNode(const SHAMapNode& nodeID, const std::vector<unsigned char>& rawNode,
SHAMapSyncFilter* filter);
// status functions
void setImmutable(void) { assert(mState != Invalid); mState = Immutable; }
void clearImmutable(void) { mState = Modifying; }
bool isSynching(void) const { return (mState == Floating) || (mState == Synching); }
void setSynching(void) { mState = Synching; }
void setFloating(void) { mState = Floating; }
void clearSynching(void) { mState = Modifying; }
bool isValid(void) { return mState != Invalid; }
void setImmutable() { assert(mState != smsInvalid); mState = smsImmutable; }
void clearImmutable() { mState = smsModifying; }
bool isSynching() const { return (mState == smsFloating) || (mState == smsSynching); }
void setSynching() { mState = smsSynching; }
void setFloating() { mState = smsFloating; }
void clearSynching() { mState = smsModifying; }
bool isValid() { return mState != smsInvalid; }
// caution: otherMap must be accessed only by this function
// return value: true=successfully completed, false=too different
bool compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxCount);
bool compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount);
void armDirty();
int flushDirty(int maxNodes, HashedObjectType t, uint32 seq);

View File

@@ -91,17 +91,22 @@ bool SHAMap::walkBranch(SHAMapTreeNode* node, SHAMapItem::pointer otherMapItem,
return true;
}
bool SHAMap::compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxCount)
bool SHAMap::compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount)
{ // compare two hash trees, add up to maxCount differences to the difference table
// return value: true=complete table of differences given, false=too many differences
// throws on corrupt tables or missing nodes
// CAUTION: otherMap is not locked and must be immutable
assert(isValid() && otherMap && otherMap->isValid());
std::stack<SHAMapDiffNode> nodeStack; // track nodes we've pushed
ScopedLock sl(Lock());
if (getHash() == otherMap->getHash()) return true;
nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash()));
boost::recursive_mutex::scoped_lock sl(mLock);
if (getHash() == otherMap->getHash())
return true;
nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash()));
while (!nodeStack.empty())
{
SHAMapDiffNode dNode(nodeStack.top());
@@ -109,6 +114,11 @@ bool SHAMap::compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxC
SHAMapTreeNode* ourNode = getNodePointer(dNode.mNodeID, dNode.mOurHash);
SHAMapTreeNode* otherNode = otherMap->getNodePointer(dNode.mNodeID, dNode.mOtherHash);
if (!ourNode || !otherNode)
{
assert(false);
throw SHAMapMissingNode(dNode.mNodeID, uint256());
}
if (ourNode->isLeaf() && otherNode->isLeaf())
{ // two leaves
@@ -118,17 +128,20 @@ bool SHAMap::compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxC
{
differences.insert(std::make_pair(ourNode->getTag(),
std::make_pair(ourNode->getItem(), otherNode->getItem())));
if (--maxCount <= 0) return false;
if (--maxCount <= 0)
return false;
}
}
else
{
differences.insert(std::make_pair(ourNode->getTag(),
std::make_pair(ourNode->getItem(), SHAMapItem::pointer())));
if (--maxCount <= 0) return false;
if (--maxCount <= 0)
return false;
differences.insert(std::make_pair(otherNode->getTag(),
std::make_pair(SHAMapItem::pointer(), otherNode->getItem())));
if (--maxCount <= 0) return false;
if (--maxCount <= 0)
return false;
}
}
else if (ourNode->isInner() && otherNode->isLeaf())
@@ -164,7 +177,8 @@ bool SHAMap::compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxC
ourNode->getChildHash(i), otherNode->getChildHash(i)));
}
}
else assert(false);
else
assert(false);
}
return true;

View File

@@ -27,58 +27,58 @@ uint256 SHAMapNode::smMasks[65];
bool SHAMapNode::operator<(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return true;
if(s.mDepth>mDepth) return false;
return mNodeID<s.mNodeID;
if (s.mDepth < mDepth) return true;
if (s.mDepth > mDepth) return false;
return mNodeID < s.mNodeID;
}
bool SHAMapNode::operator>(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return false;
if(s.mDepth>mDepth) return true;
return mNodeID>s.mNodeID;
if (s.mDepth < mDepth) return false;
if (s.mDepth > mDepth) return true;
return mNodeID > s.mNodeID;
}
bool SHAMapNode::operator<=(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return true;
if(s.mDepth>mDepth) return false;
return mNodeID<=s.mNodeID;
if (s.mDepth < mDepth) return true;
if (s.mDepth > mDepth) return false;
return mNodeID <= s.mNodeID;
}
bool SHAMapNode::operator>=(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return false;
if(s.mDepth>mDepth) return true;
return mNodeID>=s.mNodeID;
if (s.mDepth < mDepth) return false;
if (s.mDepth > mDepth) return true;
return mNodeID >= s.mNodeID;
}
bool SHAMapNode::operator==(const SHAMapNode &s) const
{
return (s.mDepth==mDepth) && (s.mNodeID==mNodeID);
return (s.mDepth == mDepth) && (s.mNodeID == mNodeID);
}
bool SHAMapNode::operator!=(const SHAMapNode &s) const
{
return (s.mDepth!=mDepth) || (s.mNodeID!=mNodeID);
return (s.mDepth != mDepth) || (s.mNodeID != mNodeID);
}
bool SHAMapNode::operator==(const uint256 &s) const
{
return s==mNodeID;
return s == mNodeID;
}
bool SHAMapNode::operator!=(const uint256 &s) const
{
return s!=mNodeID;
return s != mNodeID;
}
static bool j = SHAMapNode::ClassInit();
bool SMN_j = SHAMapNode::ClassInit();
bool SHAMapNode::ClassInit()
{ // set up the depth masks
uint256 selector;
for(int i = 0; i < 64; i += 2)
for (int i = 0; i < 64; i += 2)
{
smMasks[i] = selector;
*(selector.begin() + (i / 2)) = 0xF0;
@@ -147,7 +147,7 @@ int SHAMapNode::selectBranch(const uint256& hash) const
if ((hash & smMasks[mDepth]) != mNodeID)
{
std::cerr << "selectBranch(" << getString() << std::endl;
std::cerr << " " << hash.GetHex() << " off branch" << std::endl;
std::cerr << " " << hash << " off branch" << std::endl;
assert(false);
return -1; // does not go under this node
}
@@ -182,17 +182,17 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq) : SHAMapN
memcpy(mHashes, node.mHashes, sizeof(mHashes));
}
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::pointer item, TNType type, uint32 seq) :
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, const SHAMapItem::pointer& item, TNType type, uint32 seq) :
SHAMapNode(node), mItem(item), mSeq(seq), mType(type), mFullBelow(true)
{
assert(item->peekData().size() >= 12);
updateHash();
}
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& rawNode, uint32 seq, int format)
: SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false)
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& rawNode, uint32 seq,
SHANodeFormat format) : SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false)
{
if (format == STN_ARF_WIRE)
if (format == snfWIRE)
{
Serializer s(rawNode);
int type = s.removeLastByte();
@@ -256,7 +256,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
}
}
if (format == STN_ARF_PREFIXED)
if (format == snfPREFIX)
{
if (rawNode.size() < 4)
{
@@ -296,8 +296,9 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
}
else if (prefix == sHP_TransactionNode)
{
uint256 txID; // WRITEME: Need code to extract transaction ID from TX+MD
assert(false);
uint256 txID;
s.get256(txID, s.getLength() - 32);
s.chop(32);
mItem = boost::make_shared<SHAMapItem>(txID, s.peekData());
mType = tnTRANSACTION_MD;
}
@@ -350,14 +351,14 @@ bool SHAMapTreeNode::updateHash()
return true;
}
void SHAMapTreeNode::addRaw(Serializer& s, int format)
void SHAMapTreeNode::addRaw(Serializer& s, SHANodeFormat format)
{
assert((format == STN_ARF_PREFIXED) || (format == STN_ARF_WIRE));
assert((format == snfPREFIX) || (format == snfWIRE));
if (mType == tnERROR) throw std::runtime_error("invalid I node type");
if (mType == tnINNER)
{
if (format == STN_ARF_PREFIXED)
if (format == snfPREFIX)
{
s.add32(sHP_InnerNode);
for (int i = 0; i < 16; ++i)
@@ -385,7 +386,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
}
else if (mType == tnACCOUNT_STATE)
{
if (format == STN_ARF_PREFIXED)
if (format == snfPREFIX)
{
s.add32(sHP_LeafNode);
mItem->addRaw(s);
@@ -400,7 +401,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
}
else if (mType == tnTRANSACTION_NM)
{
if (format == STN_ARF_PREFIXED)
if (format == snfPREFIX)
{
s.add32(sHP_TransactionID);
mItem->addRaw(s);
@@ -413,7 +414,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
}
else if (mType == tnTRANSACTION_MD)
{
if (format == STN_ARF_PREFIXED)
if (format == snfPREFIX)
{
s.add32(sHP_TransactionNode);
mItem->addRaw(s);
@@ -429,7 +430,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format)
assert(false);
}
bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type)
bool SHAMapTreeNode::setItem(const SHAMapItem::pointer& i, TNType type)
{
uint256 hash = getNodeHash();
mType = type;
@@ -464,7 +465,7 @@ void SHAMapTreeNode::makeInner()
void SHAMapTreeNode::dump()
{
Log(lsDEBUG) << "SHAMapTreeNode(" << getNodeID().GetHex() << ")";
Log(lsDEBUG) << "SHAMapTreeNode(" << getNodeID() << ")";
}
std::string SHAMapTreeNode::getString() const
@@ -476,7 +477,7 @@ std::string SHAMapTreeNode::getString() const
ret += ")";
if (isInner())
{
for(int i = 0; i < 16; ++i)
for (int i = 0; i < 16; ++i)
if (!isEmptyBranch(i))
{
ret += "\nb";

View File

@@ -58,7 +58,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
std::vector<unsigned char> nodeData;
if (filter->haveNode(childID, childHash, nodeData))
{
d = boost::make_shared<SHAMapTreeNode>(childID, nodeData, mSeq, STN_ARF_PREFIXED);
d = boost::make_shared<SHAMapTreeNode>(childID, nodeData, mSeq, snfPREFIX);
if (childHash != d->getNodeHash())
{
Log(lsERROR) << "Wrong hash from cached object";
@@ -66,7 +66,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
}
else
{
Log(lsTRACE) << "Got sync node from cache: " << d->getString();
Log(lsTRACE) << "Got sync node from cache: " << *d;
mTNByID[*d] = d;
}
}
@@ -86,7 +86,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
}
bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector<SHAMapNode>& nodeIDs,
std::list<std::vector<unsigned char> >& rawNodes, bool fatLeaves)
std::list<std::vector<unsigned char> >& rawNodes, bool fatRoot, bool fatLeaves)
{ // Gets a node and some of its children
boost::recursive_mutex::scoped_lock sl(mLock);
@@ -99,10 +99,10 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector<SHAMapNode>& nodeI
nodeIDs.push_back(*node);
Serializer s;
node->addRaw(s, STN_ARF_WIRE);
node->addRaw(s, snfWIRE);
rawNodes.push_back(s.peekData());
if (node->isRoot() || node->isLeaf()) // don't get a fat root, can't get a fat leaf
if ((!fatRoot && node->isRoot()) || node->isLeaf()) // don't get a fat root, can't get a fat leaf
return true;
for (int i = 0; i < 16; ++i)
@@ -114,7 +114,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector<SHAMapNode>& nodeI
{
nodeIDs.push_back(*nextNode);
Serializer s;
nextNode->addRaw(s, STN_ARF_WIRE);
nextNode->addRaw(s, snfWIRE);
rawNodes.push_back(s.peekData());
}
}
@@ -122,14 +122,14 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector<SHAMapNode>& nodeI
return true;
}
bool SHAMap::getRootNode(Serializer& s, int format)
bool SHAMap::getRootNode(Serializer& s, SHANodeFormat format)
{
boost::recursive_mutex::scoped_lock sl(mLock);
root->addRaw(s, format);
return true;
}
bool SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, int format)
bool SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, SHANodeFormat format)
{
boost::recursive_mutex::scoped_lock sl(mLock);
@@ -141,7 +141,8 @@ bool SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, int format)
}
SHAMapTreeNode::pointer node = boost::make_shared<SHAMapTreeNode>(SHAMapNode(), rootNode, 0, format);
if (!node) return false;
if (!node)
return false;
#ifdef DEBUG
node->dump();
@@ -160,7 +161,7 @@ bool SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, int format)
return true;
}
bool SHAMap::addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, int format)
bool SHAMap::addRootNode(const uint256& hash, const std::vector<unsigned char>& rootNode, SHANodeFormat format)
{
boost::recursive_mutex::scoped_lock sl(mLock);
@@ -221,8 +222,8 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
if (iNode->getDepth() != (node.getDepth() - 1))
{ // Either this node is broken or we didn't request it (yet)
Log(lsINFO) << "unable to hook node " << node.getString();
Log(lsINFO) << " stuck at " << iNode->getString();
Log(lsINFO) << "unable to hook node " << node;
Log(lsINFO) << " stuck at " << *iNode;
Log(lsINFO) << "got depth=" << node.getDepth() << ", walked to= " << iNode->getDepth();
return false;
}
@@ -236,14 +237,14 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
uint256 hash = iNode->getChildHash(branch);
if (!hash) return false;
SHAMapTreeNode::pointer newNode = boost::make_shared<SHAMapTreeNode>(node, rawNode, mSeq, STN_ARF_WIRE);
SHAMapTreeNode::pointer newNode = boost::make_shared<SHAMapTreeNode>(node, rawNode, mSeq, snfWIRE);
if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for
return false;
if (filter)
{
Serializer s;
newNode->addRaw(s, STN_ARF_PREFIXED);
newNode->addRaw(s, snfPREFIX);
filter->gotNode(node, hash, s.peekData(), newNode->isLeaf());
}
@@ -303,7 +304,7 @@ bool SHAMap::deepCompare(SHAMap& other)
return false;
}
// Log(lsTRACE) << "Comparing inner nodes " << node->getString();
// Log(lsTRACE) << "Comparing inner nodes " << *node;
if (node->getNodeHash() != otherNode->getNodeHash())
return false;
@@ -399,7 +400,7 @@ std::list<std::vector<unsigned char> > SHAMap::getTrustedPath(const uint256& ind
Serializer s;
while (!stack.empty())
{
stack.top()->addRaw(s, STN_ARF_WIRE);
stack.top()->addRaw(s, snfWIRE);
path.push_back(s.getData());
s.erase();
stack.pop();
@@ -444,17 +445,17 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test )
destination.setSynching();
if (!source.getNodeFat(SHAMapNode(), nodeIDs, gotNodes, (rand() % 2) == 0))
if (!source.getNodeFat(SHAMapNode(), nodeIDs, gotNodes, (rand() % 2) == 0, (rand() % 2) == 0))
{
Log(lsFATAL) << "GetNodeFat(root) fails";
BOOST_FAIL("GetNodeFat");
}
if (gotNodes.size() != 1)
if (gotNodes.size() < 1)
{
Log(lsFATAL) << "Didn't get root node " << gotNodes.size();
BOOST_FAIL("NodeSize");
}
if (!destination.addRootNode(*gotNodes.begin(), STN_ARF_WIRE))
if (!destination.addRootNode(*gotNodes.begin(), snfWIRE))
{
Log(lsFATAL) << "AddRootNode fails";
BOOST_FAIL("AddRootNode");
@@ -481,7 +482,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test )
// get as many nodes as possible based on this information
for (nodeIDIterator = nodeIDs.begin(); nodeIDIterator != nodeIDs.end(); ++nodeIDIterator)
{
if (!source.getNodeFat(*nodeIDIterator, gotNodeIDs, gotNodes, (rand() % 2) == 0))
if (!source.getNodeFat(*nodeIDIterator, gotNodeIDs, gotNodes, (rand() % 2) == 0, (rand() % 2) == 0))
{
Log(lsFATAL) << "GetNodeFat fails";
BOOST_FAIL("GetNodeFat");

View File

@@ -37,7 +37,7 @@ public:
virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash,
const std::vector<unsigned char>& nodeData, bool isLeaf)
{
theApp->getHashedObjectStore().store(ACCOUNT_NODE, mLedgerSeq, nodeData, nodeHash);
theApp->getHashedObjectStore().store(hotACCOUNT_NODE, mLedgerSeq, nodeData, nodeHash);
}
virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector<unsigned char>& nodeData)
{ // fetchNodeExternal already tried
@@ -58,7 +58,8 @@ public:
virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash,
const std::vector<unsigned char>& nodeData, bool isLeaf)
{
theApp->getHashedObjectStore().store(isLeaf ? TRANSACTION : TRANSACTION_NODE, mLedgerSeq, nodeData, nodeHash);
theApp->getHashedObjectStore().store(isLeaf ? hotTRANSACTION : hotTRANSACTION_NODE, mLedgerSeq,
nodeData, nodeHash);
}
virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector<unsigned char>& nodeData)
{ // fetchNodeExternal already tried

View File

@@ -6,15 +6,19 @@
#include <openssl/rand.h>
#include "utils.h"
#include "Config.h"
#include "Log.h"
static uint8_t SNTPQueryData[48] = {
0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
// #define SNTP_DEBUG
// NTP query frequency - 5 minutes
#define NTP_QUERY_FREQUENCY (5 * 60)
static uint8_t SNTPQueryData[48] =
{ 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
// NTP query frequency - 4 minutes
#define NTP_QUERY_FREQUENCY (4 * 60)
// NTP minimum interval to query same servers - 3 minutes
#define NTP_MIN_QUERY (3 * 60)
// NTP sample window (should be odd)
#define NTP_SAMPLE_WINDOW 9
@@ -22,6 +26,9 @@ static uint8_t SNTPQueryData[48] = {
// NTP timestamp constant
#define NTP_UNIX_OFFSET 0x83AA7E80
// NTP timestamp validity
#define NTP_TIMESTAMP_VALID ((NTP_QUERY_FREQUENCY + NTP_MIN_QUERY) * 2)
// SNTP packet offsets
#define NTP_OFF_INFO 0
#define NTP_OFF_ROOTDELAY 1
@@ -37,15 +44,14 @@ static uint8_t SNTPQueryData[48] = {
#define NTP_OFF_XMITTS_FRAC 11
SNTPClient::SNTPClient(boost::asio::io_service& service) :
mIOService(service), mSocket(service), mTimer(service), mResolver(service),
SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service),
mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256)
{
mSocket.open(boost::asio::ip::udp::v4());
mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint,
boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY));
mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
}
@@ -65,7 +71,7 @@ void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::
SNTPQuery& query = mQueries[*sel];
time_t now = time(NULL);
if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now))
{
{ // This can happen if the same IP address is reached through multiple names
Log(lsTRACE) << "SNTP: Redundant query suppressed";
return;
}
@@ -86,21 +92,24 @@ void SNTPClient::receivePacket(const boost::system::error_code& error, std::size
if (!error)
{
boost::mutex::scoped_lock sl(mLock);
#ifdef SNTP_DEBUG
Log(lsTRACE) << "SNTP: Packet from " << mReceiveEndpoint;
#endif
std::map<boost::asio::ip::udp::endpoint, SNTPQuery>::iterator query = mQueries.find(mReceiveEndpoint);
if (query == mQueries.end())
Log(lsDEBUG) << "SNTP: Reply found without matching query";
Log(lsDEBUG) << "SNTP: Reply from " << mReceiveEndpoint << " found without matching query";
else if (query->second.mReceivedReply)
Log(lsDEBUG) << "SNTP: Duplicate response to query";
Log(lsDEBUG) << "SNTP: Duplicate response from " << mReceiveEndpoint;
else
{
query->second.mReceivedReply = true;
if (time(NULL) > (query->second.mLocalTimeSent + 1))
Log(lsWARNING) << "SNTP: Late response";
Log(lsWARNING) << "SNTP: Late response from " << mReceiveEndpoint;
else if (bytes_xferd < 48)
Log(lsWARNING) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size();
Log(lsWARNING) << "SNTP: Short reply from " << mReceiveEndpoint
<< " (" << bytes_xferd << ") " << mReceiveBuffer.size();
else if (reinterpret_cast<uint32*>(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryNonce)
Log(lsWARNING) << "SNTP: Reply had wrong nonce";
Log(lsWARNING) << "SNTP: Reply from " << mReceiveEndpoint << "had wrong nonce";
else
processReply();
}
@@ -128,12 +137,12 @@ void SNTPClient::processReply()
if ((info >> 30) == 3)
{
Log(lsINFO) << "SNTP: Alarm condition";
Log(lsINFO) << "SNTP: Alarm condition " << mReceiveEndpoint;
return;
}
if ((stratum == 0) || (stratum > 14))
{
Log(lsINFO) << "SNTP: Unreasonable stratum";
Log(lsINFO) << "SNTP: Unreasonable stratum (" << stratum << ") from " << mReceiveEndpoint;
return;
}
@@ -161,7 +170,10 @@ void SNTPClient::processReply()
if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good
mOffset = 0;
Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset;
#ifndef SNTP_DEBUG
if (timev || mOffset)
#endif
Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset;
}
void SNTPClient::timerEntry(const boost::system::error_code& error)
@@ -196,14 +208,14 @@ void SNTPClient::init(const std::vector<std::string>& servers)
void SNTPClient::queryAll()
{
while(doQuery())
while (doQuery())
nothing();
}
bool SNTPClient::getOffset(int& offset)
{
boost::mutex::scoped_lock sl(mLock);
if ((mLastOffsetUpdate == (time_t) -1) || ((mLastOffsetUpdate + 90) < time(NULL)))
if ((mLastOffsetUpdate == (time_t) -1) || ((mLastOffsetUpdate + NTP_TIMESTAMP_VALID) < time(NULL)))
return false;
offset = mOffset;
return true;
@@ -223,7 +235,7 @@ bool SNTPClient::doQuery()
return false;
}
time_t now = time(NULL);
if ((best->second == now) || (best->second == (now - 1)))
if ((best->second != (time_t) -1) && ((best->second + NTP_MIN_QUERY) >= now))
{
Log(lsTRACE) << "SNTP: All servers recently queried";
return false;
@@ -234,6 +246,9 @@ bool SNTPClient::doQuery()
mResolver.async_resolve(query,
boost::bind(&SNTPClient::resolveComplete, this,
boost::asio::placeholders::error, boost::asio::placeholders::iterator));
#ifdef SNTP_DEBUG
Log(lsTRACE) << "SNTP: Resolve pending for " << best->first;
#endif
return true;
}
// vim:ts=4

View File

@@ -9,26 +9,24 @@
#include <boost/thread/mutex.hpp>
#include <boost/asio.hpp>
#include "types.h"
class SNTPQuery
{
public:
bool mReceivedReply;
time_t mLocalTimeSent;
int mQueryNonce;
uint32 mQueryNonce;
SNTPQuery(time_t j = (time_t) -1) : mReceivedReply(false), mLocalTimeSent(j) { ; }
};
class SNTPClient
{
public:
typedef boost::shared_ptr<SNTPClient> pointer;
protected:
std::map<boost::asio::ip::udp::endpoint, SNTPQuery> mQueries;
boost::mutex mLock;
boost::asio::io_service& mIOService;
boost::asio::ip::udp::socket mSocket;
boost::asio::deadline_timer mTimer;
boost::asio::ip::udp::resolver mResolver;
@@ -60,3 +58,4 @@ public:
};
#endif
// vim:ts=4

1
src/ScriptData.cpp Normal file
View File

@@ -0,0 +1 @@
#include "ScriptData.h"

96
src/ScriptData.h Normal file
View File

@@ -0,0 +1,96 @@
#ifndef __SCRIPT_DATA__
#define __SCRIPT_DATA__
#include "uint256.h"
#include <boost/shared_ptr.hpp>
namespace Script {
class Data
{
public:
typedef boost::shared_ptr<Data> pointer;
virtual ~Data(){ ; }
virtual bool isInt32(){ return(false); }
virtual bool isFloat(){ return(false); }
virtual bool isUint160(){ return(false); }
virtual bool isError(){ return(false); }
virtual bool isTrue(){ return(false); }
virtual bool isBool(){ return(false); }
//virtual bool isBlockEnd(){ return(false); }
virtual int getInt(){ return(0); }
virtual float getFloat(){ return(0); }
virtual uint160 getUint160(){ return(0); }
//virtual bool isCurrency(){ return(false); }
};
class IntData : public Data
{
int mValue;
public:
IntData(int value)
{
mValue=value;
}
bool isInt32(){ return(true); }
int getInt(){ return(mValue); }
float getFloat(){ return((float)mValue); }
bool isTrue(){ return(mValue!=0); }
};
class FloatData : public Data
{
float mValue;
public:
FloatData(float value)
{
mValue=value;
}
bool isFloat(){ return(true); }
float getFloat(){ return(mValue); }
bool isTrue(){ return(mValue!=0); }
};
class Uint160Data : public Data
{
uint160 mValue;
public:
Uint160Data(uint160 value)
{
mValue=value;
}
bool isUint160(){ return(true); }
uint160 getUint160(){ return(mValue); }
};
class BoolData : public Data
{
bool mValue;
public:
BoolData(bool value)
{
mValue=value;
}
bool isBool(){ return(true); }
bool isTrue(){ return(mValue); }
};
class ErrorData : public Data
{
public:
bool isError(){ return(true); }
};
class BlockEndData : public Data
{
public:
bool isBlockEnd(){ return(true); }
};
}
#endif

134
src/SerializeProto.h Normal file
View File

@@ -0,0 +1,134 @@
// This is not really a header file, but it can be used as one with
// appropriate #define statements.
// types (common)
TYPE("Int16", UINT16, 1)
TYPE("Int32", UINT32, 2)
TYPE("Int64", UINT64, 3)
TYPE("Hash128", HASH128, 4)
TYPE("Hash256", HASH256, 5)
TYPE("Amount", AMOUNT, 6)
TYPE("VariableLength", VL, 7)
TYPE("Account", ACCOUNT, 8)
// 9-13 are reserved
TYPE("Object", OBJECT, 14)
TYPE("Array", ARRAY, 15)
// types (uncommon)
TYPE("Int8", UINT8, 16)
TYPE("Hash160", HASH160, 17)
TYPE("PathSet", PATHSET, 18)
TYPE("Vector256", VECTOR256, 19)
// 8-bit integers
FIELD(CloseResolution, UINT8, 1)
// 16-bit integers
FIELD(LedgerEntryType, UINT16, 1)
FIELD(TransactionType, UINT16, 2)
// 32-bit integers (common)
FIELD(ObjectType, UINT32, 1)
FIELD(Flags, UINT32, 2)
FIELD(SourceTag, UINT32, 3)
FIELD(Sequence, UINT32, 4)
FIELD(LastTxnSeq, UINT32, 5)
FIELD(LedgerSequence, UINT32, 6)
FIELD(CloseTime, UINT32, 7)
FIELD(ParentCloseTime, UINT32, 8)
FIELD(SigningTime, UINT32, 9)
FIELD(Expiration, UINT32, 10)
FIELD(TransferRate, UINT32, 11)
FIELD(PublishSize, UINT32, 12)
// 32-bit integers (uncommon)
FIELD(HighQualityIn, UINT32, 16)
FIELD(HighQualityOut, UINT32, 17)
FIELD(LowQualityIn, UINT32, 18)
FIELD(LowQualityOut, UINT32, 19)
FIELD(QualityIn, UINT32, 20)
FIELD(QualityOut, UINT32, 21)
FIELD(StampEscrow, UINT32, 22)
FIELD(BondAmount, UINT32, 23)
FIELD(LoadFee, UINT32, 24)
FIELD(OfferSequence, UINT32, 25)
// 64-bit integers
FIELD(IndexNext, UINT64, 1)
FIELD(IndexPrevious, UINT64, 2)
FIELD(BookNode, UINT64, 3)
FIELD(OwnerNode, UINT64, 4)
FIELD(BaseFee, UINT64, 5)
// 128-bit
FIELD(EmailHash, HASH128, 1)
// 256-bit (common)
FIELD(LedgerHash, HASH256, 1)
FIELD(ParentHash, HASH256, 2)
FIELD(TransactionHash, HASH256, 3)
FIELD(AccountHash, HASH256, 4)
FIELD(LastTxnID, HASH256, 5)
FIELD(LedgerIndex, HASH256, 6)
FIELD(WalletLocator, HASH256, 7)
FIELD(PublishHash, HASH256, 8)
// 256-bit (uncommon)
FIELD(BookDirectory, HASH256, 16)
FIELD(InvoiceID, HASH256, 17)
FIELD(Nickname, HASH256, 18)
// currency amount (common)
FIELD(Amount, AMOUNT, 1)
FIELD(Balance, AMOUNT, 2)
FIELD(LimitAmount, AMOUNT, 3)
FIELD(TakerPays, AMOUNT, 4)
FIELD(TakerGets, AMOUNT, 5)
FIELD(LowLimit, AMOUNT, 6)
FIELD(HighLimit, AMOUNT, 7)
FIELD(Fee, AMOUNT, 8)
FIELD(SendMax, AMOUNT, 9)
// current amount (uncommon)
FIELD(MinimumOffer, AMOUNT, 16)
FIELD(RippleEscrow, AMOUNT, 17)
// variable length
FIELD(PublicKey, VL, 1)
FIELD(MessageKey, VL, 2)
FIELD(SigningPubKey, VL, 3)
FIELD(TxnSignature, VL, 4)
FIELD(Generator, VL, 5)
FIELD(Signature, VL, 6)
FIELD(Domain, VL, 7)
FIELD(FundCode, VL, 8)
FIELD(RemoveCode, VL, 9)
FIELD(ExpireCode, VL, 10)
FIELD(CreateCode, VL, 11)
// account
FIELD(Account, ACCOUNT, 1)
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)
// path set
FIELD(Paths, PATHSET, 1)
// vector of 256-bit
FIELD(Indexes, VECTOR256, 1)
// inner object
// OBJECT/1 is reserved for end of object
// array of objects
// ARRAY/1 is reserved for end of array
FIELD(SigningAccounts, ARRAY, 2)
FIELD(TxnSignatures, ARRAY, 3)
FIELD(Signatures, ARRAY, 4)

View File

@@ -2,36 +2,47 @@
#include <boost/format.hpp>
#include "Ledger.h"
#include "Log.h"
SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index)
: SerializedType("LedgerEntry"), mIndex(index)
: STObject(sfLedgerEntry), mIndex(index)
{
uint16 type = sit.get16();
mFormat = getLgrFormat(static_cast<LedgerEntryType>(type));
if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type");
set(sit);
uint16 type = getFieldU16(sfLedgerEntryType);
mFormat = LedgerEntryFormat::getLgrFormat(static_cast<LedgerEntryType>(type));
if (mFormat == NULL)
throw std::runtime_error("invalid ledger entry type");
mType = mFormat->t_type;
mVersion.setValue(type);
mObject = STObject(mFormat->elements, sit);
if (!setType(mFormat->elements))
throw std::runtime_error("ledger entry not valid for type");
}
SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& index)
: SerializedType("LedgerEntry"), mIndex(index)
: STObject(sfLedgerEntry), mIndex(index)
{
SerializerIterator sit(s);
set(sit);
uint16 type = sit.get16();
mFormat = getLgrFormat(static_cast<LedgerEntryType>(type));
if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type");
uint16 type = getFieldU16(sfLedgerEntryType);
mFormat = LedgerEntryFormat::getLgrFormat(static_cast<LedgerEntryType>(type));
if (mFormat == NULL)
throw std::runtime_error("invalid ledger entry type");
mType = mFormat->t_type;
mVersion.setValue(type);
mObject.set(mFormat->elements, sit);
if (!setType(mFormat->elements))
{
Log(lsWARNING) << "Ledger entry not valid for type " << mFormat->t_name;
Log(lsWARNING) << getJson(0);
throw std::runtime_error("ledger entry not valid for type");
}
}
SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : SerializedType("LedgerEntry"), mType(type)
SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : STObject(sfLedgerEntry), mType(type)
{
mFormat = getLgrFormat(type);
mFormat = LedgerEntryFormat::getLgrFormat(type);
if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type");
mVersion.setValue(static_cast<uint16>(mFormat->t_type));
mObject.set(mFormat->elements);
set(mFormat->elements);
setFieldU16(sfLedgerEntryType, static_cast<uint16>(mFormat->t_type));
}
std::string SerializedLedgerEntry::getFullText() const
@@ -41,36 +52,113 @@ std::string SerializedLedgerEntry::getFullText() const
ret += "\" = { ";
ret += mFormat->t_name;
ret += ", ";
ret += mObject.getFullText();
ret += STObject::getFullText();
ret += "}";
return ret;
}
std::string SerializedLedgerEntry::getText() const
{
return str(boost::format("{ %s, %s, %s }")
return str(boost::format("{ %s, %s }")
% mIndex.GetHex()
% mVersion.getText()
% mObject.getText());
% STObject::getText());
}
Json::Value SerializedLedgerEntry::getJson(int options) const
{
Json::Value ret(mObject.getJson(options));
Json::Value ret(STObject::getJson(options));
ret["type"] = mFormat->t_name;
ret["index"] = mIndex.GetHex();
ret["version"] = std::string(1, mVersion);
return ret;
}
bool SerializedLedgerEntry::isEquivalent(const SerializedType& t) const
{ // locators are not compared
const SerializedLedgerEntry* v = dynamic_cast<const SerializedLedgerEntry*>(&t);
if (!v) return false;
if (mType != v->mType) return false;
if (mObject != v->mObject) return false;
bool SerializedLedgerEntry::isThreadedType()
{
return getFieldIndex(sfLastTxnID) != -1;
}
bool SerializedLedgerEntry::isThreaded()
{
return isFieldPresent(sfLastTxnID);
}
uint256 SerializedLedgerEntry::getThreadedTransaction()
{
return getFieldH256(sfLastTxnID);
}
uint32 SerializedLedgerEntry::getThreadedLedger()
{
return getFieldU32(sfLastTxnSeq);
}
bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID)
{
uint256 oldPrevTxID = getFieldH256(sfLastTxnID);
Log(lsTRACE) << "Thread Tx:" << txID << " prev:" << oldPrevTxID;
if (oldPrevTxID == txID)
return false;
prevTxID = oldPrevTxID;
prevLedgerID = getFieldU32(sfLastTxnSeq);
assert(prevTxID != txID);
setFieldH256(sfLastTxnID, txID);
setFieldU32(sfLastTxnSeq, ledgerSeq);
return true;
}
bool SerializedLedgerEntry::hasOneOwner()
{
return (mType != ltACCOUNT_ROOT) && (getFieldIndex(sfAccount) != -1);
}
bool SerializedLedgerEntry::hasTwoOwners()
{
return mType == ltRIPPLE_STATE;
}
NewcoinAddress SerializedLedgerEntry::getOwner()
{
return getFieldAccount(sfAccount);
}
NewcoinAddress SerializedLedgerEntry::getFirstOwner()
{
return NewcoinAddress::createAccountID(getFieldAmount(sfLowLimit).getIssuer());
}
NewcoinAddress SerializedLedgerEntry::getSecondOwner()
{
return NewcoinAddress::createAccountID(getFieldAmount(sfHighLimit).getIssuer());
}
std::vector<uint256> SerializedLedgerEntry::getOwners()
{
std::vector<uint256> owners;
uint160 account;
for (int i = 0, fields = getCount(); i < fields; ++i)
{
SField::ref fc = getFieldSType(i);
if ((fc == sfAccount) || (fc == sfOwner))
{
const STAccount* entry = dynamic_cast<const STAccount *>(peekAtPIndex(i));
if ((entry != NULL) && entry->getValueH160(account))
owners.push_back(Ledger::getAccountRootIndex(account));
}
if ((fc == sfLowLimit) || (fc == sfHighLimit))
{
const STAmount* entry = dynamic_cast<const STAmount *>(peekAtPIndex(i));
if ((entry != NULL))
{
uint160 issuer = entry->getIssuer();
if (issuer.isNonZero())
owners.push_back(Ledger::getAccountRootIndex(issuer));
}
}
}
return owners;
}
// vim:ts=4

View File

@@ -5,17 +5,16 @@
#include "LedgerFormats.h"
#include "NewcoinAddress.h"
class SerializedLedgerEntry : public SerializedType
class SerializedLedgerEntry : public STObject
{
public:
typedef boost::shared_ptr<SerializedLedgerEntry> pointer;
typedef boost::shared_ptr<SerializedLedgerEntry> pointer;
typedef const boost::shared_ptr<SerializedLedgerEntry>& ref;
protected:
uint256 mIndex;
LedgerEntryType mType;
STUInt16 mVersion;
STObject mObject;
const LedgerEntryFormat* mFormat;
uint256 mIndex;
LedgerEntryType mType;
const LedgerEntryFormat* mFormat;
SerializedLedgerEntry* duplicate() const { return new SerializedLedgerEntry(*this); }
@@ -24,66 +23,29 @@ public:
SerializedLedgerEntry(SerializerIterator& sit, const uint256& index);
SerializedLedgerEntry(LedgerEntryType type);
int getLength() const { return mVersion.getLength() + mObject.getLength(); }
SerializedTypeID getSType() const { return STI_LEDGERENTRY; }
std::string getFullText() const;
std::string getText() const;
Json::Value getJson(int options) const;
void add(Serializer& s) const { mVersion.add(s); mObject.add(s); }
virtual bool isEquivalent(const SerializedType& t) const;
bool setFlag(uint32 uSet) { return mObject.setFlag(uSet); }
bool clearFlag(uint32 uClear) { return mObject.clearFlag(uClear); }
uint32 getFlags() const { return mObject.getFlags(); }
const uint256& getIndex() const { return mIndex; }
void setIndex(const uint256& i) { mIndex = i; }
const uint256& getIndex() const { return mIndex; }
void setIndex(const uint256& i) { mIndex = i; }
LedgerEntryType getType() const { return mType; }
uint16 getVersion() const { return mVersion.getValue(); }
uint16 getVersion() const { return getFieldU16(sfLedgerEntryType); }
const LedgerEntryFormat* getFormat() { return mFormat; }
int getIFieldIndex(SOE_Field field) const { return mObject.getFieldIndex(field); }
int getIFieldCount() const { return mObject.getCount(); }
const SerializedType& peekIField(SOE_Field field) const { return mObject.peekAtField(field); }
SerializedType& getIField(SOE_Field field) { return mObject.getField(field); }
std::string getIFieldString(SOE_Field field) const { return mObject.getFieldString(field); }
unsigned char getIFieldU8(SOE_Field field) const { return mObject.getValueFieldU8(field); }
uint16 getIFieldU16(SOE_Field field) const { return mObject.getValueFieldU16(field); }
uint32 getIFieldU32(SOE_Field field) const { return mObject.getValueFieldU32(field); }
uint64 getIFieldU64(SOE_Field field) const { return mObject.getValueFieldU64(field); }
uint128 getIFieldH128(SOE_Field field) const { return mObject.getValueFieldH128(field); }
uint160 getIFieldH160(SOE_Field field) const { return mObject.getValueFieldH160(field); }
uint256 getIFieldH256(SOE_Field field) const { return mObject.getValueFieldH256(field); }
std::vector<unsigned char> getIFieldVL(SOE_Field field) const { return mObject.getValueFieldVL(field); }
std::vector<TaggedListItem> getIFieldTL(SOE_Field field) const { return mObject.getValueFieldTL(field); }
NewcoinAddress getIValueFieldAccount(SOE_Field field) const { return mObject.getValueFieldAccount(field); }
STAmount getIValueFieldAmount(SOE_Field field) const { return mObject.getValueFieldAmount(field); }
STVector256 getIFieldV256(SOE_Field field) { return mObject.getValueFieldV256(field); }
void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); }
void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); }
void setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); }
void setIFieldU64(SOE_Field field, uint64 v) { return mObject.setValueFieldU64(field, v); }
void setIFieldH128(SOE_Field field, const uint128& v) { return mObject.setValueFieldH128(field, v); }
void setIFieldH160(SOE_Field field, const uint160& v) { return mObject.setValueFieldH160(field, v); }
void setIFieldH256(SOE_Field field, const uint256& v) { return mObject.setValueFieldH256(field, v); }
void setIFieldVL(SOE_Field field, const std::vector<unsigned char>& v)
{ return mObject.setValueFieldVL(field, v); }
void setIFieldTL(SOE_Field field, const std::vector<TaggedListItem>& v)
{ return mObject.setValueFieldTL(field, v); }
void setIFieldAccount(SOE_Field field, const uint160& account)
{ return mObject.setValueFieldAccount(field, account); }
void setIFieldAccount(SOE_Field field, const NewcoinAddress& account)
{ return mObject.setValueFieldAccount(field, account); }
void setIFieldAmount(SOE_Field field, const STAmount& amount)
{ return mObject.setValueFieldAmount(field, amount); }
void setIFieldV256(SOE_Field field, const STVector256& v) { return mObject.setValueFieldV256(field, v); }
bool getIFieldPresent(SOE_Field field) const { return mObject.isFieldPresent(field); }
void makeIFieldPresent(SOE_Field field) { mObject.makeFieldPresent(field); }
void makeIFieldAbsent(SOE_Field field) { return mObject.makeFieldAbsent(field); }
bool isThreadedType(); // is this a ledger entry that can be threaded
bool isThreaded(); // is this ledger entry actually threaded
bool hasOneOwner(); // This node has one other node that owns it (like nickname)
bool hasTwoOwners(); // This node has two nodes that own it (like ripple balance)
NewcoinAddress getOwner();
NewcoinAddress getFirstOwner();
NewcoinAddress getSecondOwner();
uint256 getThreadedTransaction();
uint32 getThreadedLedger();
bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID);
std::vector<uint256> getOwners(); // nodes notified if this node is deleted
};
typedef SerializedLedgerEntry SLE;

File diff suppressed because it is too large Load Diff

View File

@@ -9,145 +9,71 @@
#include "SerializedTypes.h"
enum SOE_Type
{
SOE_NEVER = -1, // never occurs (marks end of object)
SOE_REQUIRED = 0, // required
SOE_FLAGS = 1, // flags field
SOE_IFFLAG = 2, // present if flag set
SOE_IFNFLAG = 3 // present if flag not set
};
// Serializable object/array types
enum SOE_Field
{
sfInvalid = -1,
sfGeneric = 0,
// common fields
sfAcceptExpire,
sfAcceptRate,
sfAcceptStart,
sfAccount,
sfAccountID,
sfAmount,
sfAuthorizedKey,
sfBalance,
sfBookDirectory,
sfBookNode,
sfBorrowExpire,
sfBorrowRate,
sfBorrowStart,
sfBorrower,
sfCloseTime,
sfCurrency,
sfCurrencyIn,
sfCurrencyOut,
sfDestination,
sfDomain,
sfEmailHash,
sfExpiration,
sfExtensions,
sfFirstNode,
sfFlags,
sfGenerator,
sfGeneratorID,
sfGetsIssuer,
sfHash,
sfHighID,
sfHighLimit,
sfHighQualityIn,
sfHighQualityOut,
sfIdentifier,
sfIndexes,
sfIndexNext,
sfIndexPrevious,
sfInvoiceID,
sfLastNode,
sfLastReceive,
sfLastTxn,
sfLedgerHash,
sfLimitAmount,
sfLowID,
sfLowLimit,
sfLowQualityIn,
sfLowQualityOut,
sfMessageKey,
sfMinimumOffer,
sfNextAcceptExpire,
sfNextAcceptRate,
sfNextAcceptStart,
sfNextTransitExpire,
sfNextTransitRate,
sfNextTransitStart,
sfNickname,
sfOfferSequence,
sfOwnerNode,
sfPaths,
sfPaysIssuer,
sfPubKey,
sfPublishHash,
sfPublishSize,
sfQualityIn,
sfQualityOut,
sfSendMax,
sfSequence,
sfSignature,
sfSigningKey,
sfSourceTag,
sfTakerGets,
sfTakerPays,
sfTarget,
sfTargetLedger,
sfTransferRate,
sfVersion,
sfWalletLocator,
// test fields
sfTest1, sfTest2, sfTest3, sfTest4
};
struct SOElement
class SOElement
{ // An element in the description of a serialized object
SOE_Field e_field;
const char *e_name;
SerializedTypeID e_id;
SOE_Type e_type;
int e_flags;
public:
typedef SOElement const * ptr; // used to point to one element
SField::ref e_field;
const SOE_Flags flags;
SOElement(SField::ref fi, SOE_Flags fl) : e_field(fi), flags(fl) { ; }
};
class STObject : public SerializedType
{
protected:
int mFlagIdx; // the offset to the flags object, -1 if none
boost::ptr_vector<SerializedType> mData;
std::vector<const SOElement*> mType;
std::vector<SOElement::ptr> mType;
STObject* duplicate() const { return new STObject(*this); }
STObject(SField::ref name, boost::ptr_vector<SerializedType>& data) : SerializedType(name) { mData.swap(data); }
public:
STObject(const char *n = NULL) : SerializedType(n), mFlagIdx(-1) { ; }
STObject(const SOElement *t, const char *n = NULL);
STObject(const SOElement *t, SerializerIterator& u, const char *n = NULL);
STObject() { ; }
STObject(SField::ref name) : SerializedType(name) { ; }
STObject(const std::vector<SOElement::ptr>& type, SField::ref name) : SerializedType(name)
{ set(type); }
STObject(const std::vector<SOElement::ptr>& type, SerializerIterator& sit, SField::ref name) : SerializedType(name)
{ set(sit); setType(type); }
static std::auto_ptr<STObject> parseJson(const Json::Value& value, SField::ref name = sfGeneric, int depth = 0);
virtual ~STObject() { ; }
void set(const SOElement* t);
void set(const SOElement* t, SerializerIterator& u);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name);
bool setType(const std::vector<SOElement::ptr>& type);
bool isValidForType();
bool isFieldAllowed(SField::ref);
void set(const std::vector<SOElement::ptr>&);
bool set(SerializerIterator& u, int depth = 0);
int getLength() const;
virtual SerializedTypeID getSType() const { return STI_OBJECT; }
virtual bool isEquivalent(const SerializedType& t) const;
void add(Serializer& s) const;
virtual void add(Serializer& s) const { add(s, true); } // just inner elements
void add(Serializer& s, bool withSignature) const;
Serializer getSerializer() const { Serializer s; add(s); return s; }
std::string getFullText() const;
std::string getText() const;
virtual Json::Value getJson(int options) const;
int addObject(const SerializedType& t) { mData.push_back(t.clone()); return mData.size() - 1; }
int giveObject(std::auto_ptr<SerializedType> t) { mData.push_back(t); return mData.size() - 1; }
int giveObject(SerializedType* t) { mData.push_back(t); return mData.size() - 1; }
int addObject(const SerializedType& t) { mData.push_back(t.clone()); return mData.size() - 1; }
int giveObject(std::auto_ptr<SerializedType> t) { mData.push_back(t); return mData.size() - 1; }
int giveObject(SerializedType* t) { mData.push_back(t); return mData.size() - 1; }
const boost::ptr_vector<SerializedType>& peekData() const { return mData; }
boost::ptr_vector<SerializedType>& peekData() { return mData; }
boost::ptr_vector<SerializedType>& peekData() { return mData; }
SerializedType& front() { return mData.front(); }
const SerializedType& front() const { return mData.front(); }
SerializedType& back() { return mData.back(); }
const SerializedType& back() const { return mData.back(); }
int getCount() const { return mData.size(); }
@@ -155,63 +81,137 @@ public:
bool clearFlag(uint32);
uint32 getFlags() const;
uint256 getHash(uint32 prefix) const;
uint256 getSigningHash(uint32 prefix) const;
const SerializedType& peekAtIndex(int offset) const { return mData[offset]; }
SerializedType& getIndex(int offset) { return mData[offset]; }
const SerializedType* peekAtPIndex(int offset) const { return &(mData[offset]); }
SerializedType* getPIndex(int offset) { return &(mData[offset]); }
int getFieldIndex(SOE_Field field) const;
int getFieldIndex(SField::ref field) const;
SField::ref getFieldSType(int index) const;
const SerializedType& peekAtField(SOE_Field field) const;
SerializedType& getField(SOE_Field field);
const SerializedType* peekAtPField(SOE_Field field) const;
SerializedType* getPField(SOE_Field field);
const SOElement* getFieldType(SOE_Field field) const;
const SerializedType& peekAtField(SField::ref field) const;
SerializedType& getField(SField::ref field);
const SerializedType* peekAtPField(SField::ref field) const;
SerializedType* getPField(SField::ref field);
// these throw if the field type doesn't match, or return default values if the
// field is optional but not present
std::string getFieldString(SOE_Field field) const;
unsigned char getValueFieldU8(SOE_Field field) const;
uint16 getValueFieldU16(SOE_Field field) const;
uint32 getValueFieldU32(SOE_Field field) const;
uint64 getValueFieldU64(SOE_Field field) const;
uint128 getValueFieldH128(SOE_Field field) const;
uint160 getValueFieldH160(SOE_Field field) const;
uint256 getValueFieldH256(SOE_Field field) const;
NewcoinAddress getValueFieldAccount(SOE_Field field) const;
std::vector<unsigned char> getValueFieldVL(SOE_Field field) const;
std::vector<TaggedListItem> getValueFieldTL(SOE_Field field) const;
STAmount getValueFieldAmount(SOE_Field field) const;
STPathSet getValueFieldPathSet(SOE_Field field) const;
STVector256 getValueFieldV256(SOE_Field field) const;
std::string getFieldString(SField::ref field) const;
unsigned char getFieldU8(SField::ref field) const;
uint16 getFieldU16(SField::ref field) const;
uint32 getFieldU32(SField::ref field) const;
uint64 getFieldU64(SField::ref field) const;
uint128 getFieldH128(SField::ref field) const;
uint160 getFieldH160(SField::ref field) const;
uint256 getFieldH256(SField::ref field) const;
NewcoinAddress getFieldAccount(SField::ref field) const;
uint160 getFieldAccount160(SField::ref field) const;
std::vector<unsigned char> getFieldVL(SField::ref field) const;
std::vector<TaggedListItem> getFieldTL(SField::ref field) const;
STAmount getFieldAmount(SField::ref field) const;
STPathSet getFieldPathSet(SField::ref field) const;
STVector256 getFieldV256(SField::ref field) const;
void setValueFieldU8(SOE_Field field, unsigned char);
void setValueFieldU16(SOE_Field field, uint16);
void setValueFieldU32(SOE_Field field, uint32);
void setValueFieldU64(SOE_Field field, uint64);
void setValueFieldH128(SOE_Field field, const uint128&);
void setValueFieldH160(SOE_Field field, const uint160&);
void setValueFieldH256(SOE_Field field, const uint256&);
void setValueFieldVL(SOE_Field field, const std::vector<unsigned char>&);
void setValueFieldTL(SOE_Field field, const std::vector<TaggedListItem>&);
void setValueFieldAccount(SOE_Field field, const uint160&);
void setValueFieldAccount(SOE_Field field, const NewcoinAddress& addr)
{ setValueFieldAccount(field, addr.getAccountID()); }
void setValueFieldAmount(SOE_Field field, const STAmount&);
void setValueFieldPathSet(SOE_Field field, const STPathSet&);
void setValueFieldV256(SOE_Field field, const STVector256& v);
void setFieldU8(SField::ref field, unsigned char);
void setFieldU16(SField::ref field, uint16);
void setFieldU32(SField::ref field, uint32);
void setFieldU64(SField::ref field, uint64);
void setFieldH128(SField::ref field, const uint128&);
void setFieldH160(SField::ref field, const uint160&);
void setFieldH256(SField::ref field, const uint256&);
void setFieldVL(SField::ref field, const std::vector<unsigned char>&);
void setFieldTL(SField::ref field, const std::vector<TaggedListItem>&);
void setFieldAccount(SField::ref field, const uint160&);
void setFieldAccount(SField::ref field, const NewcoinAddress& addr)
{ setFieldAccount(field, addr.getAccountID()); }
void setFieldAmount(SField::ref field, const STAmount&);
void setFieldPathSet(SField::ref field, const STPathSet&);
void setFieldV256(SField::ref field, const STVector256& v);
bool isFieldPresent(SOE_Field field) const;
SerializedType* makeFieldPresent(SOE_Field field);
void makeFieldAbsent(SOE_Field field);
bool isFieldPresent(SField::ref field) const;
SerializedType* makeFieldPresent(SField::ref field);
void makeFieldAbsent(SField::ref field);
bool delField(SField::ref field);
void delField(int index);
static std::auto_ptr<SerializedType> makeDefaultObject(SerializedTypeID id, const char *name);
static std::auto_ptr<SerializedType> makeDeserializedObject(SerializedTypeID id, const char *name,
SerializerIterator&);
static std::auto_ptr<SerializedType> makeDefaultObject(SerializedTypeID id, SField::ref name);
static std::auto_ptr<SerializedType> makeDeserializedObject(SerializedTypeID id, SField::ref name,
SerializerIterator&, int depth);
static std::auto_ptr<SerializedType> makeNonPresentObject(SField::ref name)
{ return makeDefaultObject(STI_NOTPRESENT, name); }
static std::auto_ptr<SerializedType> makeDefaultObject(SField::ref name)
{ return makeDefaultObject(name.fieldType, name); }
static void unitTest();
};
class STArray : public SerializedType
{
public:
typedef std::vector<STObject> vector;
typedef std::vector<STObject>::iterator iterator;
typedef std::vector<STObject>::const_iterator const_iterator;
typedef std::vector<STObject>::reverse_iterator reverse_iterator;
typedef std::vector<STObject>::const_reverse_iterator const_reverse_iterator;
typedef std::vector<STObject>::size_type size_type;
protected:
vector value;
STArray* duplicate() const { return new STArray(*this); }
static STArray* construct(SerializerIterator&, SField::ref);
public:
STArray() { ; }
STArray(SField::ref f) : SerializedType(f) { ; }
STArray(SField::ref f, const vector& v) : SerializedType(f), value(v) { ; }
STArray(vector& v) : value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
const vector& getValue() const { return value; }
vector& getValue() { return value; }
// vector-like functions
void push_back(const STObject& object) { value.push_back(object); }
STObject& operator[](int j) { return value[j]; }
const STObject& operator[](int j) const { return value[j]; }
iterator begin() { return value.begin(); }
const_iterator begin() const { return value.begin(); }
iterator end() { return value.end(); }
const_iterator end() const { return value.end(); }
size_type size() const { return value.size(); }
reverse_iterator rbegin() { return value.rbegin(); }
const_reverse_iterator rbegin() const { return value.rbegin(); }
reverse_iterator rend() { return value.rend(); }
const_reverse_iterator rend() const { return value.rend(); }
iterator erase(iterator pos) { return value.erase(pos); }
STObject& front() { return value.front(); }
const STObject& front() const { return value.front(); }
STObject& back() { return value.back(); }
const STObject& back() const { return value.back(); }
void pop_back() { value.pop_back(); }
bool empty() const { return value.empty(); }
void clear() { value.clear(); }
virtual std::string getFullText() const;
virtual std::string getText() const;
virtual Json::Value getJson(int) const;
virtual void add(Serializer& s) const;
bool operator==(const STArray &s) { return value == s.value; }
bool operator!=(const STArray &s) { return value != s.value; }
virtual SerializedTypeID getSType() const { return STI_ARRAY; }
virtual bool isEquivalent(const SerializedType& t) const;
};
#endif
// vim:ts=4

View File

@@ -1,25 +1,22 @@
#include "SerializedTransaction.h"
#include <boost/foreach.hpp>
#include "Application.h"
#include "Log.h"
#include "HashPrefixes.h"
SerializedTransaction::SerializedTransaction(TransactionType type) : mType(type)
SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sfTransaction), mType(type)
{
mFormat = getTxnFormat(type);
if (mFormat == NULL) throw std::runtime_error("invalid transaction type");
mMiddleTxn.giveObject(new STVariableLength("SigningPubKey"));
mMiddleTxn.giveObject(new STAccount("SourceAccount"));
mMiddleTxn.giveObject(new STUInt32("Sequence"));
mMiddleTxn.giveObject(new STUInt16("Type", static_cast<uint16>(type)));
mMiddleTxn.giveObject(new STAmount("Fee"));
mInnerTxn = STObject(mFormat->elements, "InnerTransaction");
mFormat = TransactionFormat::getTxnFormat(type);
if (mFormat == NULL)
throw std::runtime_error("invalid transaction type");
set(mFormat->elements);
setFieldU16(sfTransactionType, mFormat->t_type);
}
SerializedTransaction::SerializedTransaction(SerializerIterator& sit)
SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject(sfTransaction)
{
int length = sit.getBytesLeft();
if ((length < TransactionMinLen) || (length > TransactionMaxLen))
@@ -28,32 +25,17 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit)
throw std::runtime_error("Transaction length invalid");
}
mSignature.setValue(sit.getVL());
set(sit);
mType = static_cast<TransactionType>(getFieldU16(sfTransactionType));
mMiddleTxn.giveObject(new STVariableLength("SigningPubKey", sit.getVL()));
STAccount sa("SourceAccount", sit.getVL());
mSourceAccount = sa.getValueNCA();
mMiddleTxn.giveObject(new STAccount(sa));
mMiddleTxn.giveObject(new STUInt32("Sequence", sit.get32()));
mType = static_cast<TransactionType>(sit.get16());
mMiddleTxn.giveObject(new STUInt16("Type", static_cast<uint16>(mType)));
mFormat = getTxnFormat(mType);
mFormat = TransactionFormat::getTxnFormat(mType);
if (!mFormat)
throw std::runtime_error("invalid transaction type");
if (!setType(mFormat->elements))
{
Log(lsERROR) << "Transaction has invalid type";
throw std::runtime_error("Transaction has invalid type");
assert(false);
throw std::runtime_error("transaction not valid");
}
mMiddleTxn.giveObject(STAmount::deserialize(sit, "Fee"));
mInnerTxn = STObject(mFormat->elements, sit, "InnerTransaction");
}
int SerializedTransaction::getLength() const
{
return mSignature.getLength() + mMiddleTxn.getLength() + mInnerTxn.getLength();
}
std::string SerializedTransaction::getFullText() const
@@ -61,32 +43,23 @@ std::string SerializedTransaction::getFullText() const
std::string ret = "\"";
ret += getTransactionID().GetHex();
ret += "\" = {";
ret += mSignature.getFullText();
ret += mMiddleTxn.getFullText();
ret += mInnerTxn.getFullText();
ret += STObject::getFullText();
ret += "}";
return ret;
}
std::string SerializedTransaction::getText() const
{
std::string ret = "{";
ret += mSignature.getText();
ret += mMiddleTxn.getText();
ret += mInnerTxn.getText();
ret += "}";
return ret;
return STObject::getText();
}
std::vector<NewcoinAddress> SerializedTransaction::getAffectedAccounts() const
{
std::vector<NewcoinAddress> accounts;
accounts.push_back(mSourceAccount);
for(boost::ptr_vector<SerializedType>::const_iterator it = mInnerTxn.peekData().begin(),
end = mInnerTxn.peekData().end(); it != end ; ++it)
BOOST_FOREACH(const SerializedType& it, peekData())
{
const STAccount* sa = dynamic_cast<const STAccount*>(&*it);
const STAccount* sa = dynamic_cast<const STAccount*>(&it);
if (sa != NULL)
{
bool found = false;
@@ -107,197 +80,61 @@ std::vector<NewcoinAddress> SerializedTransaction::getAffectedAccounts() const
return accounts;
}
void SerializedTransaction::add(Serializer& s) const
{
mSignature.add(s);
mMiddleTxn.add(s);
mInnerTxn.add(s);
}
bool SerializedTransaction::isEquivalent(const SerializedType& t) const
{ // Signatures are not compared
const SerializedTransaction* v = dynamic_cast<const SerializedTransaction*>(&t);
if (!v) return false;
if (mType != v->mType) return false;
if (mMiddleTxn != v->mMiddleTxn) return false;
if (mInnerTxn != v->mInnerTxn) return false;
return true;
}
uint256 SerializedTransaction::getSigningHash() const
{
Serializer s;
s.add32(sHP_TransactionSign);
mMiddleTxn.add(s);
mInnerTxn.add(s);
return s.getSHA512Half();
return STObject::getSigningHash(sHP_TransactionSign);
}
uint256 SerializedTransaction::getTransactionID() const
{ // perhaps we should cache this
Serializer s;
s.add32(sHP_TransactionID);
mSignature.add(s);
mMiddleTxn.add(s);
mInnerTxn.add(s);
return s.getSHA512Half();
return getHash(sHP_TransactionID);
}
std::vector<unsigned char> SerializedTransaction::getSignature() const
{
return mSignature.getValue();
try
{
return getFieldVL(sfTxnSignature);
}
catch (...)
{
return std::vector<unsigned char>();
}
}
const std::vector<unsigned char>& SerializedTransaction::peekSignature() const
void SerializedTransaction::sign(const NewcoinAddress& naAccountPrivate)
{
return mSignature.peekValue();
}
bool SerializedTransaction::sign(const NewcoinAddress& naAccountPrivate)
{
return naAccountPrivate.accountPrivateSign(getSigningHash(), mSignature.peekValue());
std::vector<unsigned char> signature;
naAccountPrivate.accountPrivateSign(getSigningHash(), signature);
setFieldVL(sfTxnSignature, signature);
}
bool SerializedTransaction::checkSign(const NewcoinAddress& naAccountPublic) const
{
return naAccountPublic.accountPublicVerify(getSigningHash(), mSignature.getValue());
try
{
return naAccountPublic.accountPublicVerify(getSigningHash(), getFieldVL(sfTxnSignature));
}
catch (...)
{
return false;
}
}
void SerializedTransaction::setSignature(const std::vector<unsigned char>& sig)
void SerializedTransaction::setSigningPubKey(const NewcoinAddress& naSignPubKey)
{
mSignature.setValue(sig);
setFieldVL(sfSigningPubKey, naSignPubKey.getAccountPublic());
}
STAmount SerializedTransaction::getTransactionFee() const
void SerializedTransaction::setSourceAccount(const NewcoinAddress& naSource)
{
const STAmount* v = dynamic_cast<const STAmount*>(mMiddleTxn.peekAtPIndex(TransactionIFee));
if (!v) throw std::runtime_error("corrupt transaction");
return *v;
}
void SerializedTransaction::setTransactionFee(const STAmount& fee)
{
STAmount* v = dynamic_cast<STAmount*>(mMiddleTxn.getPIndex(TransactionIFee));
if (!v) throw std::runtime_error("corrupt transaction");
v->setValue(fee);
}
uint32 SerializedTransaction::getSequence() const
{
const STUInt32* v = dynamic_cast<const STUInt32*>(mMiddleTxn.peekAtPIndex(TransactionISequence));
if (!v) throw std::runtime_error("corrupt transaction");
return v->getValue();
}
void SerializedTransaction::setSequence(uint32 seq)
{
STUInt32* v = dynamic_cast<STUInt32*>(mMiddleTxn.getPIndex(TransactionISequence));
if (!v) throw std::runtime_error("corrupt transaction");
v->setValue(seq);
}
std::vector<unsigned char> SerializedTransaction::getSigningPubKey() const
{
const STVariableLength* v =
dynamic_cast<const STVariableLength*>(mMiddleTxn.peekAtPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
return v->getValue();
}
const std::vector<unsigned char>& SerializedTransaction::peekSigningPubKey() const
{
const STVariableLength* v=
dynamic_cast<const STVariableLength*>(mMiddleTxn.peekAtPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
return v->peekValue();
}
std::vector<unsigned char>& SerializedTransaction::peekSigningPubKey()
{
STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
return v->peekValue();
}
const NewcoinAddress& SerializedTransaction::setSigningPubKey(const NewcoinAddress& naSignPubKey)
{
mSignPubKey = naSignPubKey;
STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
v->setValue(mSignPubKey.getAccountPublic());
return mSignPubKey;
}
const NewcoinAddress& SerializedTransaction::setSourceAccount(const NewcoinAddress& naSource)
{
mSourceAccount = naSource;
STAccount* v = dynamic_cast<STAccount*>(mMiddleTxn.getPIndex(TransactionISourceID));
if (!v) throw std::runtime_error("corrupt transaction");
v->setValueNCA(mSourceAccount);
return mSourceAccount;
}
uint160 SerializedTransaction::getITFieldAccount(SOE_Field field) const
{
uint160 r;
const SerializedType* st = mInnerTxn.peekAtPField(field);
if (!st) return r;
const STAccount* ac = dynamic_cast<const STAccount*>(st);
if (!ac) return r;
ac->getValueH160(r);
return r;
}
int SerializedTransaction::getITFieldIndex(SOE_Field field) const
{
return mInnerTxn.getFieldIndex(field);
}
int SerializedTransaction::getITFieldCount() const
{
return mInnerTxn.getCount();
}
bool SerializedTransaction::getITFieldPresent(SOE_Field field) const
{
return mInnerTxn.isFieldPresent(field);
}
const SerializedType& SerializedTransaction::peekITField(SOE_Field field) const
{
return mInnerTxn.peekAtField(field);
}
SerializedType& SerializedTransaction::getITField(SOE_Field field)
{
return mInnerTxn.getField(field);
}
void SerializedTransaction::makeITFieldPresent(SOE_Field field)
{
mInnerTxn.makeFieldPresent(field);
}
void SerializedTransaction::makeITFieldAbsent(SOE_Field field)
{
return mInnerTxn.makeFieldAbsent(field);
setFieldAccount(sfAccount, naSource);
}
Json::Value SerializedTransaction::getJson(int options) const
{
Json::Value ret = Json::objectValue;
Json::Value ret = STObject::getJson(0);
ret["id"] = getTransactionID().GetHex();
ret["signature"] = mSignature.getText();
Json::Value middle = mMiddleTxn.getJson(options);
middle["type"] = mFormat->t_name;
ret["middle"] = middle;
ret["inner"] = mInnerTxn.getJson(options);
return ret;
}

View File

@@ -17,18 +17,14 @@
#define TXN_SQL_INCLUDED 'I'
#define TXN_SQL_UNKNOWN 'U'
class SerializedTransaction : public SerializedType
class SerializedTransaction : public STObject
{
public:
typedef boost::shared_ptr<SerializedTransaction> pointer;
protected:
NewcoinAddress mSignPubKey;
NewcoinAddress mSourceAccount;
TransactionType mType;
STVariableLength mSignature;
STObject mMiddleTxn, mInnerTxn;
TransactionFormat* mFormat;
const TransactionFormat* mFormat;
SerializedTransaction* duplicate() const { return new SerializedTransaction(*this); }
@@ -37,84 +33,27 @@ public:
SerializedTransaction(TransactionType type);
// STObject functions
int getLength() const;
SerializedTypeID getSType() const { return STI_TRANSACTION; }
std::string getFullText() const;
std::string getText() const;
void add(Serializer& s) const;
virtual bool isEquivalent(const SerializedType& t) const;
// outer transaction functions / signature functions
std::vector<unsigned char> getSignature() const;
const std::vector<unsigned char>& peekSignature() const;
void setSignature(const std::vector<unsigned char>& s);
void setSignature(const std::vector<unsigned char>& s) { setFieldVL(sfTxnSignature, s); }
uint256 getSigningHash() const;
TransactionType getTxnType() const { return mType; }
STAmount getTransactionFee() const;
void setTransactionFee(const STAmount& fee);
TransactionType getTxnType() const { return mType; }
STAmount getTransactionFee() const { return getFieldAmount(sfFee); }
void setTransactionFee(const STAmount& fee) { setFieldAmount(sfFee, fee); }
const NewcoinAddress& getSourceAccount() const { return mSourceAccount; }
std::vector<unsigned char> getSigningPubKey() const;
const std::vector<unsigned char>& peekSigningPubKey() const;
std::vector<unsigned char>& peekSigningPubKey();
const NewcoinAddress& setSigningPubKey(const NewcoinAddress& naSignPubKey);
const NewcoinAddress& setSourceAccount(const NewcoinAddress& naSource);
NewcoinAddress getSourceAccount() const { return getFieldAccount(sfAccount); }
std::vector<unsigned char> getSigningPubKey() const { return getFieldVL(sfSigningPubKey); }
void setSigningPubKey(const NewcoinAddress& naSignPubKey);
void setSourceAccount(const NewcoinAddress& naSource);
std::string getTransactionType() const { return mFormat->t_name; }
// inner transaction functions
uint32 getFlags() const { return mInnerTxn.getFlags(); }
void setFlag(uint32 v) { mInnerTxn.setFlag(v); }
void clearFlag(uint32 v) { mInnerTxn.clearFlag(v); }
uint32 getSequence() const;
void setSequence(uint32);
// inner transaction field functions
int getITFieldIndex(SOE_Field field) const;
int getITFieldCount() const;
const SerializedType& peekITField(SOE_Field field) const;
SerializedType& getITField(SOE_Field field);
// inner transaction field value functions
std::string getITFieldString(SOE_Field field) const { return mInnerTxn.getFieldString(field); }
unsigned char getITFieldU8(SOE_Field field) const { return mInnerTxn.getValueFieldU8(field); }
uint16 getITFieldU16(SOE_Field field) const { return mInnerTxn.getValueFieldU16(field); }
uint32 getITFieldU32(SOE_Field field) const { return mInnerTxn.getValueFieldU32(field); }
uint64 getITFieldU64(SOE_Field field) const { return mInnerTxn.getValueFieldU64(field); }
uint128 getITFieldH128(SOE_Field field) const { return mInnerTxn.getValueFieldH128(field); }
uint160 getITFieldH160(SOE_Field field) const { return mInnerTxn.getValueFieldH160(field); }
uint160 getITFieldAccount(SOE_Field field) const;
uint256 getITFieldH256(SOE_Field field) const { return mInnerTxn.getValueFieldH256(field); }
std::vector<unsigned char> getITFieldVL(SOE_Field field) const { return mInnerTxn.getValueFieldVL(field); }
std::vector<TaggedListItem> getITFieldTL(SOE_Field field) const { return mInnerTxn.getValueFieldTL(field); }
STAmount getITFieldAmount(SOE_Field field) const { return mInnerTxn.getValueFieldAmount(field); }
STPathSet getITFieldPathSet(SOE_Field field) const { return mInnerTxn.getValueFieldPathSet(field); }
void setITFieldU8(SOE_Field field, unsigned char v) { return mInnerTxn.setValueFieldU8(field, v); }
void setITFieldU16(SOE_Field field, uint16 v) { return mInnerTxn.setValueFieldU16(field, v); }
void setITFieldU32(SOE_Field field, uint32 v) { return mInnerTxn.setValueFieldU32(field, v); }
void setITFieldU64(SOE_Field field, uint32 v) { return mInnerTxn.setValueFieldU64(field, v); }
void setITFieldH128(SOE_Field field, const uint128& v) { return mInnerTxn.setValueFieldH128(field, v); }
void setITFieldH160(SOE_Field field, const uint160& v) { return mInnerTxn.setValueFieldH160(field, v); }
void setITFieldH256(SOE_Field field, const uint256& v) { return mInnerTxn.setValueFieldH256(field, v); }
void setITFieldVL(SOE_Field field, const std::vector<unsigned char>& v)
{ return mInnerTxn.setValueFieldVL(field, v); }
void setITFieldTL(SOE_Field field, const std::vector<TaggedListItem>& v)
{ return mInnerTxn.setValueFieldTL(field, v); }
void setITFieldAccount(SOE_Field field, const uint160& v)
{ return mInnerTxn.setValueFieldAccount(field, v); }
void setITFieldAccount(SOE_Field field, const NewcoinAddress& v)
{ return mInnerTxn.setValueFieldAccount(field, v); }
void setITFieldAmount(SOE_Field field, const STAmount& v)
{ return mInnerTxn.setValueFieldAmount(field, v); }
void setITFieldPathSet(SOE_Field field, const STPathSet& v)
{ return mInnerTxn.setValueFieldPathSet(field, v); }
// optional field functions
bool getITFieldPresent(SOE_Field field) const;
void makeITFieldPresent(SOE_Field field);
void makeITFieldAbsent(SOE_Field field);
uint32 getSequence() const { return getFieldU32(sfSequence); }
void setSequence(uint32 seq) { return setFieldU32(sfSequence, seq); }
std::vector<NewcoinAddress> getAffectedAccounts() const;
@@ -122,7 +61,7 @@ public:
virtual Json::Value getJson(int options) const;
bool sign(const NewcoinAddress& naAccountPrivate);
void sign(const NewcoinAddress& naAccountPrivate);
bool checkSign(const NewcoinAddress& naAccountPublic) const;
// SQL Functions

View File

@@ -5,17 +5,23 @@
#include "SerializedTypes.h"
#include "SerializedObject.h"
#include "TransactionFormats.h"
#include "LedgerFormats.h"
#include "FieldNames.h"
#include "Log.h"
#include "NewcoinAddress.h"
#include "utils.h"
STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0);
STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1);
std::string SerializedType::getFullText() const
{
std::string ret;
if (getSType() != STI_NOTPRESENT)
{
if(name != NULL)
if(fName->hasName())
{
ret = name;
ret = fName->fieldName;
ret += " = ";
}
ret += getText();
@@ -23,7 +29,7 @@ std::string SerializedType::getFullText() const
return ret;
}
STUInt8* STUInt8::construct(SerializerIterator& u, const char *name)
STUInt8* STUInt8::construct(SerializerIterator& u, SField::ref name)
{
return new STUInt8(name, u.get8());
}
@@ -39,13 +45,25 @@ bool STUInt8::isEquivalent(const SerializedType& t) const
return v && (value == v->value);
}
STUInt16* STUInt16::construct(SerializerIterator& u, const char *name)
STUInt16* STUInt16::construct(SerializerIterator& u, SField::ref name)
{
return new STUInt16(name, u.get16());
}
std::string STUInt16::getText() const
{
if (getFName() == sfLedgerEntryType)
{
LedgerEntryFormat *f = LedgerEntryFormat::getLgrFormat(value);
if (f != NULL)
return f->t_name;
}
if (getFName() == sfTransactionType)
{
TransactionFormat *f = TransactionFormat::getTxnFormat(value);
if (f != NULL)
return f->t_name;
}
return boost::lexical_cast<std::string>(value);
}
@@ -55,7 +73,7 @@ bool STUInt16::isEquivalent(const SerializedType& t) const
return v && (value == v->value);
}
STUInt32* STUInt32::construct(SerializerIterator& u, const char *name)
STUInt32* STUInt32::construct(SerializerIterator& u, SField::ref name)
{
return new STUInt32(name, u.get32());
}
@@ -71,7 +89,7 @@ bool STUInt32::isEquivalent(const SerializedType& t) const
return v && (value == v->value);
}
STUInt64* STUInt64::construct(SerializerIterator& u, const char *name)
STUInt64* STUInt64::construct(SerializerIterator& u, SField::ref name)
{
return new STUInt64(name, u.get64());
}
@@ -87,7 +105,7 @@ bool STUInt64::isEquivalent(const SerializedType& t) const
return v && (value == v->value);
}
STHash128* STHash128::construct(SerializerIterator& u, const char *name)
STHash128* STHash128::construct(SerializerIterator& u, SField::ref name)
{
return new STHash128(name, u.get128());
}
@@ -103,7 +121,7 @@ bool STHash128::isEquivalent(const SerializedType& t) const
return v && (value == v->value);
}
STHash160* STHash160::construct(SerializerIterator& u, const char *name)
STHash160* STHash160::construct(SerializerIterator& u, SField::ref name)
{
return new STHash160(name, u.get160());
}
@@ -119,7 +137,7 @@ bool STHash160::isEquivalent(const SerializedType& t) const
return v && (value == v->value);
}
STHash256* STHash256::construct(SerializerIterator& u, const char *name)
STHash256* STHash256::construct(SerializerIterator& u, SField::ref name)
{
return new STHash256(name, u.get256());
}
@@ -135,7 +153,7 @@ bool STHash256::isEquivalent(const SerializedType& t) const
return v && (value == v->value);
}
STVariableLength::STVariableLength(SerializerIterator& st, const char *name) : SerializedType(name)
STVariableLength::STVariableLength(SerializerIterator& st, SField::ref name) : SerializedType(name)
{
value = st.getVL();
}
@@ -145,16 +163,11 @@ std::string STVariableLength::getText() const
return strHex(value);
}
STVariableLength* STVariableLength::construct(SerializerIterator& u, const char *name)
STVariableLength* STVariableLength::construct(SerializerIterator& u, SField::ref name)
{
return new STVariableLength(name, u.getVL());
}
int STVariableLength::getLength() const
{
return Serializer::encodeLengthLength(value.size()) + value.size();
}
bool STVariableLength::isEquivalent(const SerializedType& t) const
{
const STVariableLength* v = dynamic_cast<const STVariableLength*>(&t);
@@ -172,7 +185,7 @@ std::string STAccount::getText() const
return a.humanAccountID();
}
STAccount* STAccount::construct(SerializerIterator& u, const char *name)
STAccount* STAccount::construct(SerializerIterator& u, SField::ref name)
{
return new STAccount(name, u.getVL());
}
@@ -182,7 +195,7 @@ STAccount* STAccount::construct(SerializerIterator& u, const char *name)
//
// Return a new object from a SerializerIterator.
STVector256* STVector256::construct(SerializerIterator& u, const char *name)
STVector256* STVector256::construct(SerializerIterator& u, SField::ref name)
{
std::vector<unsigned char> data = u.getVL();
std::vector<uint256> value;
@@ -218,9 +231,14 @@ bool STVector256::isEquivalent(const SerializedType& t) const
// STAccount
//
STAccount::STAccount(SField::ref n, const uint160& v) : STVariableLength(n)
{
peekValue().insert(peekValue().end(), v.begin(), v.end());
}
bool STAccount::isValueH160() const
{
return peekValue().size() == (160/8);
return peekValue().size() == (160 / 8);
}
void STAccount::setValueH160(const uint160& v)
@@ -251,93 +269,91 @@ void STAccount::setValueNCA(const NewcoinAddress& nca)
setValueH160(nca.getAccountID());
}
std::string STTaggedList::getText() const
{
std::string ret;
for (std::vector<TaggedListItem>::const_iterator it=value.begin(); it!=value.end(); ++it)
{
ret += boost::lexical_cast<std::string>(it->first);
ret += ",";
ret += strHex(it->second);
}
return ret;
}
Json::Value STTaggedList::getJson(int) const
{
Json::Value ret(Json::arrayValue);
for (std::vector<TaggedListItem>::const_iterator it=value.begin(); it!=value.end(); ++it)
{
Json::Value elem(Json::arrayValue);
elem.append(it->first);
elem.append(strHex(it->second));
ret.append(elem);
}
return ret;
}
STTaggedList* STTaggedList::construct(SerializerIterator& u, const char *name)
{
return new STTaggedList(name, u.getTaggedList());
}
int STTaggedList::getLength() const
{
int ret = Serializer::getTaggedListLength(value);
if (ret<0) throw std::overflow_error("bad TL length");
return ret;
}
bool STTaggedList::isEquivalent(const SerializedType& t) const
{
const STTaggedList* v = dynamic_cast<const STTaggedList*>(&t);
return v && (value == v->value);
}
STPathSet* STPathSet::construct(SerializerIterator& s, const char *name)
STPathSet* STPathSet::construct(SerializerIterator& s, SField::ref name)
{
std::vector<STPath> paths;
std::vector<STPathElement> path;
do
{
switch(s.get8())
int iType = s.get8();
if (iType == STPathElement::typeEnd || iType == STPathElement::typeBoundary)
{
case STPathElement::typeEnd:
if (path.empty())
{
if (!paths.empty())
throw std::runtime_error("empty last path");
}
else paths.push_back(path);
if (path.empty())
{
Log(lsINFO) << "STPathSet: Empty path.";
throw std::runtime_error("empty path");
}
paths.push_back(path);
path.clear();
if (iType == STPathElement::typeEnd)
{
return new STPathSet(name, paths);
}
}
else if (iType & ~STPathElement::typeValidBits)
{
Log(lsINFO) << "STPathSet: Bad path element: " << iType;
case STPathElement::typeBoundary:
if (path.empty())
throw std::runtime_error("empty path");
paths.push_back(path);
path.clear();
throw std::runtime_error("bad path element");
}
else
{
const bool bAccount = !!(iType & STPathElement::typeAccount);
const bool bCurrency = !!(iType & STPathElement::typeCurrency);
const bool bIssuer = !!(iType & STPathElement::typeIssuer);
case STPathElement::typeAccount:
path.push_back(STPathElement(STPathElement::typeAccount, s.get160()));
break;
uint160 uAccountID;
uint160 uCurrency;
uint160 uIssuerID;
case STPathElement::typeOffer:
path.push_back(STPathElement(STPathElement::typeOffer, s.get160()));
break;
if (bAccount)
uAccountID = s.get160();
default: throw std::runtime_error("Unknown path element");
if (bCurrency)
uCurrency = s.get160();
if (bIssuer)
uIssuerID = s.get160();
path.push_back(STPathElement(uAccountID, uCurrency, uIssuerID));
}
} while(1);
}
int STPathSet::getLength() const
bool STPathSet::isEquivalent(const SerializedType& t) const
{
int ret = 0;
for (std::vector<STPath>::const_iterator it = value.begin(), end = value.end(); it != end; ++it)
ret += it->getSerializeSize();
return (ret != 0) ? ret : (ret + 1);
const STPathSet* v = dynamic_cast<const STPathSet*>(&t);
return v && (value == v->value);
}
int STPath::getSerializeSize() const
{
int iBytes = 0;
BOOST_FOREACH(const STPathElement& speElement, mPath)
{
int iType = speElement.getNodeType();
iBytes += 1; // mType
if (iType & STPathElement::typeAccount)
iBytes += 160/8;
if (iType & STPathElement::typeCurrency)
iBytes += 160/8;
if (iType & STPathElement::typeIssuer)
iBytes += 160/8;
}
iBytes += 1; // typeBoundary | typeEnd
return iBytes;
}
Json::Value STPath::getJson(int) const
@@ -346,30 +362,22 @@ Json::Value STPath::getJson(int) const
BOOST_FOREACH(std::vector<STPathElement>::const_iterator::value_type it, mPath)
{
switch (it.getNodeType())
{
case STPathElement::typeAccount:
{
Json::Value elem(Json::objectValue);
Json::Value elem(Json::objectValue);
int iType = it.getNodeType();
elem["account"] = NewcoinAddress::createHumanAccountID(it.getNode());
elem["type"] = iType;
elem["type_hex"] = strHex(iType);
ret.append(elem);
break;
}
if (iType & STPathElement::typeAccount)
elem["account"] = NewcoinAddress::createHumanAccountID(it.getAccountID());
case STPathElement::typeOffer:
{
Json::Value elem(Json::objectValue);
if (iType & STPathElement::typeCurrency)
elem["currency"] = STAmount::createHumanCurrency(it.getCurrency());
elem["offer"] = it.getNode().GetHex();
if (iType & STPathElement::typeIssuer)
elem["issuer"] = NewcoinAddress::createHumanAccountID(it.getIssuerID());
ret.append(elem);
break;
}
default: throw std::runtime_error("Unknown path element");
}
ret.append(elem);
}
return ret;
@@ -385,12 +393,13 @@ Json::Value STPathSet::getJson(int options) const
return ret;
}
#if 0
std::string STPath::getText() const
{
std::string ret("[");
bool first = true;
BOOST_FOREACH(std::vector<STPathElement>::const_iterator::value_type it, mPath)
BOOST_FOREACH(const STPathElement& it, mPath)
{
if (!first) ret += ", ";
switch (it.getNodeType())
@@ -416,7 +425,9 @@ std::string STPath::getText() const
return ret + "]";
}
#endif
#if 0
std::string STPathSet::getText() const
{
std::string ret("{");
@@ -433,23 +444,34 @@ std::string STPathSet::getText() const
}
return ret + "}";
}
#endif
void STPathSet::add(Serializer& s) const
{
bool firstPath = true;
bool bFirst = true;
BOOST_FOREACH(std::vector<STPath>::const_iterator::value_type pit, value)
BOOST_FOREACH(const STPath& spPath, value)
{
if (!firstPath)
if (!bFirst)
{
s.add8(STPathElement::typeBoundary);
firstPath = false;
bFirst = false;
}
for (std::vector<STPathElement>::const_iterator eit = pit.begin(), eend = pit.end(); eit != eend; ++eit)
BOOST_FOREACH(const STPathElement& speElement, spPath)
{
s.add8(eit->getNodeType());
s.add160(eit->getNode());
int iType = speElement.getNodeType();
s.add8(iType);
if (iType & STPathElement::typeAccount)
s.add160(speElement.getAccountID());
if (iType & STPathElement::typeCurrency)
s.add160(speElement.getCurrency());
if (iType & STPathElement::typeIssuer)
s.add160(speElement.getIssuerID());
}
}
s.add8(STPathElement::typeEnd);

View File

@@ -8,38 +8,13 @@
#include "uint256.h"
#include "Serializer.h"
#include "FieldNames.h"
enum SerializedTypeID
{
// special types
STI_DONE = -1,
STI_NOTPRESENT = 0,
// standard types
STI_OBJECT = 1,
STI_UINT8 = 2,
STI_UINT16 = 3,
STI_UINT32 = 4,
STI_UINT64 = 5,
STI_HASH128 = 6,
STI_HASH160 = 7,
STI_HASH256 = 8,
STI_VL = 9,
STI_TL = 10,
STI_AMOUNT = 11,
STI_PATHSET = 12,
STI_VECTOR256 = 13,
// high level types
STI_ACCOUNT = 100,
STI_TRANSACTION = 101,
STI_LEDGERENTRY = 102
};
enum PathFlags
{
PF_END = 0x00, // End of current path & path list.
PF_BOUNDRY = 0xFF, // End of current path & new path follows.
PF_BOUNDARY = 0xFF, // End of current path & new path follows.
PF_ACCOUNT = 0x01,
PF_OFFER = 0x02,
@@ -50,27 +25,33 @@ enum PathFlags
PF_ISSUE = 0x80,
};
#define CURRENCY_XNS uint160(0)
#define CURRENCY_ONE uint160(1) // Used as a place holder
#define ACCOUNT_XNS uint160(0)
#define ACCOUNT_ONE uint160(1) // Used as a place holder
class SerializedType
{
protected:
const char* name;
SField::ptr fName;
virtual SerializedType* duplicate() const { return new SerializedType(name); }
virtual SerializedType* duplicate() const { return new SerializedType(*fName); }
SerializedType(SField::ptr n) : fName(n) { assert(fName); }
public:
SerializedType() : name(NULL) { ; }
SerializedType(const char* n) : name(n) { ; }
SerializedType(const SerializedType& n) : name(n.name) { ; }
SerializedType() : fName(&sfGeneric) { ; }
SerializedType(SField::ref n) : fName(&n) { assert(fName); }
SerializedType(const SerializedType& n) : fName(n.fName) { ; }
virtual ~SerializedType() { ; }
static std::auto_ptr<SerializedType> deserialize(const char* name)
static std::auto_ptr<SerializedType> deserialize(SField::ref name)
{ return std::auto_ptr<SerializedType>(new SerializedType(name)); }
void setName(const char* n) { name=n; }
const char *getName() const { return name; }
void setFName(SField::ref n) { fName = &n; assert(fName); }
SField::ref getFName() const { return *fName; }
std::string getName() const { return fName->fieldName; }
virtual int getLength() const { return 0; }
virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; }
std::auto_ptr<SerializedType> clone() const { return std::auto_ptr<SerializedType>(duplicate()); }
@@ -80,11 +61,15 @@ public:
virtual Json::Value getJson(int) const
{ return getText(); }
virtual void add(Serializer& s) const { return; }
virtual void add(Serializer& s) const { ; }
virtual bool isEquivalent(const SerializedType& t) const
{ assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; }
void addFieldID(Serializer& s) const { s.addFieldID(fName->fieldType, fName->fieldValue); }
SerializedType& operator=(const SerializedType& t)
{ if (!fName->fieldCode) fName = t.fName; return *this; }
bool operator==(const SerializedType& t) const
{ return (getSType() == t.getSType()) && isEquivalent(t); }
bool operator!=(const SerializedType& t) const
@@ -93,32 +78,31 @@ public:
inline SerializedType* new_clone(const SerializedType& s) { return s.clone().release(); }
inline void delete_clone(const SerializedType* s) { boost::checked_delete(s); }
inline std::ostream& operator<<(std::ostream& out, const SerializedType& t) { return out << t.getFullText(); }
class STUInt8 : public SerializedType
{
protected:
unsigned char value;
STUInt8* duplicate() const { return new STUInt8(name, value); }
static STUInt8* construct(SerializerIterator&, const char* name = NULL);
STUInt8* duplicate() const { return new STUInt8(*this); }
static STUInt8* construct(SerializerIterator&, SField::ref f);
public:
STUInt8(unsigned char v=0) : value(v) { ; }
STUInt8(const char* n, unsigned char v=0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
STUInt8(unsigned char v = 0) : value(v) { ; }
STUInt8(SField::ref n, unsigned char v = 0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 1; }
SerializedTypeID getSType() const { return STI_UINT8; }
std::string getText() const;
void add(Serializer& s) const { s.add8(value); }
unsigned char getValue() const { return value; }
void setValue(unsigned char v) { value=v; }
void setValue(unsigned char v) { value = v; }
operator unsigned char() const { return value; }
STUInt8& operator=(unsigned char v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
@@ -127,17 +111,16 @@ class STUInt16 : public SerializedType
protected:
uint16 value;
STUInt16* duplicate() const { return new STUInt16(name, value); }
static STUInt16* construct(SerializerIterator&, const char* name = NULL);
STUInt16* duplicate() const { return new STUInt16(*this); }
static STUInt16* construct(SerializerIterator&, SField::ref name);
public:
STUInt16(uint16 v=0) : value(v) { ; }
STUInt16(const char* n, uint16 v=0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
STUInt16(uint16 v = 0) : value(v) { ; }
STUInt16(SField::ref n, uint16 v = 0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 2; }
SerializedTypeID getSType() const { return STI_UINT16; }
std::string getText() const;
void add(Serializer& s) const { s.add16(value); }
@@ -146,7 +129,6 @@ public:
void setValue(uint16 v) { value=v; }
operator uint16() const { return value; }
STUInt16& operator=(uint16 v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
@@ -155,17 +137,16 @@ class STUInt32 : public SerializedType
protected:
uint32 value;
STUInt32* duplicate() const { return new STUInt32(name, value); }
static STUInt32* construct(SerializerIterator&, const char* name = NULL);
STUInt32* duplicate() const { return new STUInt32(*this); }
static STUInt32* construct(SerializerIterator&, SField::ref name);
public:
STUInt32(uint32 v=0) : value(v) { ; }
STUInt32(const char* n, uint32 v=0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
STUInt32(uint32 v = 0) : value(v) { ; }
STUInt32(SField::ref n, uint32 v = 0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 4; }
SerializedTypeID getSType() const { return STI_UINT32; }
std::string getText() const;
void add(Serializer& s) const { s.add32(value); }
@@ -174,7 +155,6 @@ public:
void setValue(uint32 v) { value=v; }
operator uint32() const { return value; }
STUInt32& operator=(uint32 v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
@@ -183,17 +163,16 @@ class STUInt64 : public SerializedType
protected:
uint64 value;
STUInt64* duplicate() const { return new STUInt64(name, value); }
static STUInt64* construct(SerializerIterator&, const char* name = NULL);
STUInt64* duplicate() const { return new STUInt64(*this); }
static STUInt64* construct(SerializerIterator&, SField::ref name);
public:
STUInt64(uint64 v=0) : value(v) { ; }
STUInt64(const char* n, uint64 v=0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
STUInt64(uint64 v = 0) : value(v) { ; }
STUInt64(SField::ref n, uint64 v = 0) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 8; }
SerializedTypeID getSType() const { return STI_UINT64; }
std::string getText() const;
void add(Serializer& s) const { s.add64(value); }
@@ -202,7 +181,6 @@ public:
void setValue(uint64 v) { value=v; }
operator uint64() const { return value; }
STUInt64& operator=(uint64 v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
@@ -230,7 +208,7 @@ protected:
void canonicalize();
STAmount* duplicate() const { return new STAmount(*this); }
static STAmount* construct(SerializerIterator&, const char* name = NULL);
static STAmount* construct(SerializerIterator&, SField::ref name);
static const int cMinOffset = -96, cMaxOffset = 80;
static const uint64 cMinValue = 1000000000000000ull, cMaxValue = 9999999999999999ull;
@@ -238,40 +216,46 @@ protected:
static const uint64 cNotNative = 0x8000000000000000ull;
static const uint64 cPosNative = 0x4000000000000000ull;
STAmount(bool isNeg, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; }
STAmount(const char *name, uint64 value, bool isNegative)
: SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative)
{ ; }
STAmount(const char *n, const uint160& cur, uint64 val, int off, bool isNative, bool isNegative)
: SerializedType(n), mCurrency(cur), mValue(val), mOffset(off), mIsNative(isNative), mIsNegative(isNegative)
{ ; }
STAmount(SField::ref name, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg)
: SerializedType(name), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off),
mIsNative(isNat), mIsNegative(isNeg) { ; }
uint64 toUInt64() const;
static uint64 muldiv(uint64, uint64, uint64);
public:
STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg)
{ if (v==0) mIsNegative = false; }
static uint64 uRateOne;
STAmount(const char* n, uint64 v = 0)
: SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false)
STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg)
{ if (v == 0) mIsNegative = false; }
STAmount(SField::ref n, uint64 v = 0, bool isNeg = false)
: SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg)
{ ; }
STAmount(const uint160& currency, uint64 v = 0, int off = 0)
: mCurrency(currency), mValue(v), mOffset(off), mIsNegative(false)
STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV = 0, int iOff = 0, bool bNegative = false)
: mCurrency(uCurrencyID), mIssuer(uIssuerID), mValue(uV), mOffset(iOff), mIsNegative(bNegative)
{ canonicalize(); }
STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) :
SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg)
// YYY This should probably require issuer too.
STAmount(SField::ref n, const uint160& currency, const uint160& issuer,
uint64 v = 0, int off = 0, bool isNeg = false) :
SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg)
{ canonicalize(); }
STAmount(const char* n, int64 v);
STAmount(SField::ref, const Json::Value&);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
static STAmount createFromInt64(SField::ref n, int64 v);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return mIsNative ? 8 : 28; }
static STAmount saFromRate(uint64 uRate = 0)
{ return STAmount(CURRENCY_ONE, ACCOUNT_ONE, uRate, -9, false); }
static STAmount saFromSigned(const uint160& uCurrencyID, const uint160& uIssuerID, int64 iV = 0, int iOff = 0)
{ return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0); }
SerializedTypeID getSType() const { return STI_AMOUNT; }
std::string getText() const;
std::string getRaw() const;
@@ -281,6 +265,7 @@ public:
int getExponent() const { return mOffset; }
uint64 getMantissa() const { return mValue; }
// When the currency is XNS, the value in raw units. S=signed
uint64 getNValue() const { if (!mIsNative) throw std::runtime_error("not native"); return mValue; }
void setNValue(uint64 v) { if (!mIsNative) throw std::runtime_error("not native"); mValue = v; }
int64 getSNValue() const;
@@ -290,6 +275,7 @@ public:
bool isNative() const { return mIsNative; }
bool isZero() const { return mValue == 0; }
bool isNonZero() const { return mValue != 0; }
bool isNegative() const { return mIsNegative && !isZero(); }
bool isPositive() const { return !mIsNegative && !isZero(); }
bool isGEZero() const { return !mIsNegative; }
@@ -302,6 +288,7 @@ public:
void setIssuer(const uint160& uIssuer) { mIssuer = uIssuer; }
const uint160& getCurrency() const { return mCurrency; }
bool setValue(const std::string& sAmount);
bool setFullValue(const std::string& sAmount, const std::string& sCurrency = "", const std::string& sIssuer = "");
void setValue(const STAmount &);
@@ -327,7 +314,6 @@ public:
STAmount& operator+=(const STAmount&);
STAmount& operator-=(const STAmount&);
STAmount& operator=(const STAmount&);
STAmount& operator+=(uint64);
STAmount& operator-=(uint64);
STAmount& operator=(uint64);
@@ -337,19 +323,32 @@ public:
friend STAmount operator+(const STAmount& v1, const STAmount& v2);
friend STAmount operator-(const STAmount& v1, const STAmount& v2);
static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& currencyOut);
static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut);
static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID);
static STAmount divide(const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
{ return divide(v1, v2, saUnit.getCurrency(), saUnit.getIssuer()); }
static STAmount divide(const STAmount& v1, const STAmount& v2)
{ return divide(v1, v2, v1); }
static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID);
static STAmount multiply(const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
{ return multiply(v1, v2, saUnit.getCurrency(), saUnit.getIssuer()); }
static STAmount multiply(const STAmount& v1, const STAmount& v2)
{ return multiply(v1, v2, v1); }
// Someone is offering X for Y, what is the rate?
// Rate: smaller is better, the taker wants the most out: in/out
static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn);
static STAmount setRate(uint64 rate);
// Someone is offering X for Y, I try to pay Z, how much do I get?
// And what's left of the offer? And how much do I actually pay?
static bool 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);
// Someone is offering X for Y, I need Z, how much do I pay
static STAmount getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed);
@@ -357,7 +356,7 @@ public:
// Native currency conversions, to/from display format
static uint64 convertToDisplayAmount(const STAmount& internalAmount, uint64 totalNow, uint64 totalInit);
static STAmount convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit,
const char* name = NULL);
SField::ref name = sfGeneric);
static std::string createHumanCurrency(const uint160& uCurrency);
static STAmount deserialize(SerializerIterator&);
@@ -366,24 +365,28 @@ public:
Json::Value getJson(int) const;
};
extern STAmount saZero;
extern STAmount saOne;
class STHash128 : public SerializedType
{
protected:
uint128 value;
STHash128* duplicate() const { return new STHash128(name, value); }
static STHash128* construct(SerializerIterator&, const char* name = NULL);
STHash128* duplicate() const { return new STHash128(*this); }
static STHash128* construct(SerializerIterator&, SField::ref name);
public:
STHash128(const uint128& v) : value(v) { ; }
STHash128(const char* n, const uint128& v) : SerializedType(n), value(v) { ; }
STHash128(const char* n) : SerializedType(n) { ; }
STHash128(SField::ref n, const uint128& v) : SerializedType(n), value(v) { ; }
STHash128(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); }
STHash128(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); }
STHash128(SField::ref n) : SerializedType(n) { ; }
STHash128() { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH128; }
virtual std::string getText() const;
void add(Serializer& s) const { s.add128(value); }
@@ -392,7 +395,6 @@ public:
void setValue(const uint128& v) { value=v; }
operator uint128() const { return value; }
STHash128& operator=(const uint128& v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
@@ -401,19 +403,20 @@ class STHash160 : public SerializedType
protected:
uint160 value;
STHash160* duplicate() const { return new STHash160(name, value); }
static STHash160* construct(SerializerIterator&, const char* name = NULL);
STHash160* duplicate() const { return new STHash160(*this); }
static STHash160* construct(SerializerIterator&, SField::ref name);
public:
STHash160(const uint160& v) : value(v) { ; }
STHash160(const char* n, const uint160& v) : SerializedType(n), value(v) { ; }
STHash160(const char* n) : SerializedType(n) { ; }
STHash160(SField::ref n, const uint160& v) : SerializedType(n), value(v) { ; }
STHash160(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); }
STHash160(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); }
STHash160(SField::ref n) : SerializedType(n) { ; }
STHash160() { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH160; }
virtual std::string getText() const;
void add(Serializer& s) const { s.add160(value); }
@@ -422,7 +425,6 @@ public:
void setValue(const uint160& v) { value=v; }
operator uint160() const { return value; }
STHash160& operator=(const uint160& v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
@@ -431,19 +433,20 @@ class STHash256 : public SerializedType
protected:
uint256 value;
STHash256* duplicate() const { return new STHash256(name, value); }
static STHash256* construct(SerializerIterator&, const char* name = NULL);
STHash256* duplicate() const { return new STHash256(*this); }
static STHash256* construct(SerializerIterator&, SField::ref);
public:
STHash256(const uint256& v) : value(v) { ; }
STHash256(const char* n, const uint256& v) : SerializedType(n), value(v) { ; }
STHash256(const char* n) : SerializedType(n) { ; }
STHash256(SField::ref n, const uint256& v) : SerializedType(n), value(v) { ; }
STHash256(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); }
STHash256(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); }
STHash256(SField::ref n) : SerializedType(n) { ; }
STHash256() { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 32; }
SerializedTypeID getSType() const { return STI_HASH256; }
std::string getText() const;
void add(Serializer& s) const { s.add256(value); }
@@ -452,7 +455,6 @@ public:
void setValue(const uint256& v) { value=v; }
operator uint256() const { return value; }
STHash256& operator=(const uint256& v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
@@ -461,20 +463,19 @@ class STVariableLength : public SerializedType
protected:
std::vector<unsigned char> value;
virtual STVariableLength* duplicate() const { return new STVariableLength(name, value); }
static STVariableLength* construct(SerializerIterator&, const char* name = NULL);
virtual STVariableLength* duplicate() const { return new STVariableLength(*this); }
static STVariableLength* construct(SerializerIterator&, SField::ref);
public:
STVariableLength(const std::vector<unsigned char>& v) : value(v) { ; }
STVariableLength(const char* n, const std::vector<unsigned char>& v) : SerializedType(n), value(v) { ; }
STVariableLength(const char* n) : SerializedType(n) { ; }
STVariableLength(SerializerIterator&, const char* name = NULL);
STVariableLength(SField::ref n, const std::vector<unsigned char>& v) : SerializedType(n), value(v) { ; }
STVariableLength(SField::ref n) : SerializedType(n) { ; }
STVariableLength(SerializerIterator&, SField::ref name = sfGeneric);
STVariableLength() { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const;
virtual SerializedTypeID getSType() const { return STI_VL; }
virtual std::string getText() const;
void add(Serializer& s) const { s.addVL(value); }
@@ -485,23 +486,23 @@ public:
void setValue(const std::vector<unsigned char>& v) { value=v; }
operator std::vector<unsigned char>() const { return value; }
STVariableLength& operator=(const std::vector<unsigned char>& v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
class STAccount : public STVariableLength
{
protected:
virtual STAccount* duplicate() const { return new STAccount(name, value); }
static STAccount* construct(SerializerIterator&, const char* name = NULL);
virtual STAccount* duplicate() const { return new STAccount(*this); }
static STAccount* construct(SerializerIterator&, SField::ref);
public:
STAccount(const std::vector<unsigned char>& v) : STVariableLength(v) { ; }
STAccount(const char* n, const std::vector<unsigned char>& v) : STVariableLength(n, v) { ; }
STAccount(const char* n) : STVariableLength(n) { ; }
STAccount(SField::ref n, const std::vector<unsigned char>& v) : STVariableLength(n, v) { ; }
STAccount(SField::ref n, const uint160& v);
STAccount(SField::ref n) : STVariableLength(n) { ; }
STAccount() { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
SerializedTypeID getSType() const { return STI_ACCOUNT; }
@@ -518,26 +519,50 @@ public:
class STPathElement
{
public:
static const int typeEnd = 0x00;
static const int typeAccount = 0x01; // Rippling through an account
static const int typeOffer = 0x02; // Claiming an offer
static const int typeBoundary = 0xFF; // boundary between alternate paths
enum {
typeEnd = 0x00,
typeAccount = 0x01, // Rippling through an account (vs taking an offer).
typeCurrency = 0x10, // Currency follows.
typeIssuer = 0x20, // Issuer follows.
typeBoundary = 0xFF, // Boundary between alternate paths.
typeValidBits = (
typeAccount
| typeCurrency
| typeIssuer
), // Bits that may be non-zero.
};
protected:
int mType;
uint160 mNode;
int mType;
uint160 mAccountID;
uint160 mCurrencyID;
uint160 mIssuerID;
public:
STPathElement(int type, const uint160& node) : mType(type), mNode(node) { ; }
int getNodeType() const { return mType; }
bool isAccount() const { return mType == typeAccount; }
bool isOffer() const { return mType == typeOffer; }
STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID,
bool forceCurrency = false)
: mAccountID(uAccountID), mCurrencyID(uCurrencyID), mIssuerID(uIssuerID)
{
mType =
(uAccountID.isZero() ? 0 : STPathElement::typeAccount)
| ((uCurrencyID.isZero() && !forceCurrency) ? 0 : STPathElement::typeCurrency)
| (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer);
}
int getNodeType() const { return mType; }
bool isOffer() const { return mAccountID.isZero(); }
bool isAccount() const { return !isOffer(); }
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a class of offers.
const uint160& getNode() const { return mNode; }
const uint160& getAccountID() const { return mAccountID; }
const uint160& getCurrency() const { return mCurrencyID; }
const uint160& getIssuerID() const { return mIssuerID; }
void setType(int type) { mType = type; }
void setNode(const uint160& n) { mNode = n; }
bool operator==(const STPathElement& t) const
{
return mType == t.mType && mAccountID == t.mAccountID && mCurrencyID == t.mCurrencyID &&
mIssuerID == t.mIssuerID;
}
};
class STPath
@@ -555,32 +580,71 @@ public:
const STPathElement& getElemet(int offset) { return mPath[offset]; }
void addElement(const STPathElement& e) { mPath.push_back(e); }
void clear() { mPath.clear(); }
int getSerializeSize() const { return 1 + mPath.size() * 21; }
std::string getText() const;
int getSerializeSize() const;
// std::string getText() const;
Json::Value getJson(int) const;
std::vector<STPathElement>::iterator begin() { return mPath.begin(); }
std::vector<STPathElement>::iterator end() { return mPath.end(); }
std::vector<STPathElement>::const_iterator begin() const { return mPath.begin(); }
std::vector<STPathElement>::const_iterator end() const { return mPath.end(); }
bool operator==(const STPath& t) const { return mPath == t.mPath; }
};
inline std::vector<STPathElement>::iterator range_begin(STPath & x)
{
return x.begin();
}
inline std::vector<STPathElement>::iterator range_end(STPath & x)
{
return x.end();
}
inline std::vector<STPathElement>::const_iterator range_begin(const STPath& x)
{
return x.begin();
}
inline std::vector<STPathElement>::const_iterator range_end(const STPath& x)
{
return x.end();
}
namespace boost
{
template<>
struct range_mutable_iterator< STPath >
{
typedef std::vector<STPathElement>::iterator type;
};
template<>
struct range_const_iterator< STPath >
{
typedef std::vector<STPathElement>::const_iterator type;
};
}
class STPathSet : public SerializedType
{ // A set of zero or more payment paths
protected:
std::vector<STPath> value;
STPathSet* duplicate() const { return new STPathSet(name, value); }
static STPathSet* construct(SerializerIterator&, const char* name = NULL);
STPathSet* duplicate() const { return new STPathSet(*this); }
static STPathSet* construct(SerializerIterator&, SField::ref);
public:
STPathSet() { ; }
STPathSet(const char* n) : SerializedType(n) { ; }
STPathSet(SField::ref n) : SerializedType(n) { ; }
STPathSet(const std::vector<STPath>& v) : value(v) { ; }
STPathSet(const char* n, const std::vector<STPath>& v) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
STPathSet(SField::ref n, const std::vector<STPath>& v) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const;
std::string getText() const;
// std::string getText() const;
void add(Serializer& s) const;
virtual Json::Value getJson(int) const;
@@ -592,6 +656,8 @@ public:
void clear() { value.clear(); }
void addPath(const STPath& e) { value.push_back(e); }
virtual bool isEquivalent(const SerializedType& t) const;
std::vector<STPath>::iterator begin() { return value.begin(); }
std::vector<STPath>::iterator end() { return value.end(); }
std::vector<STPath>::const_iterator begin() const { return value.begin(); }
@@ -633,77 +699,35 @@ namespace boost
};
}
class STTaggedList : public SerializedType
{
protected:
std::vector<TaggedListItem> value;
STTaggedList* duplicate() const { return new STTaggedList(name, value); }
static STTaggedList* construct(SerializerIterator&, const char* name = NULL);
public:
STTaggedList() { ; }
STTaggedList(const char* n) : SerializedType(n) { ; }
STTaggedList(const std::vector<TaggedListItem>& v) : value(v) { ; }
STTaggedList(const char* n, const std::vector<TaggedListItem>& v) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const;
SerializedTypeID getSType() const { return STI_TL; }
std::string getText() const;
void add(Serializer& s) const { if(s.addTaggedList(value)<0) throw(0); }
const std::vector<TaggedListItem>& peekValue() const { return value; }
std::vector<TaggedListItem>& peekValue() { return value; }
std::vector<TaggedListItem> getValue() const { return value; }
virtual Json::Value getJson(int) const;
void setValue(const std::vector<TaggedListItem>& v) { value=v; }
int getItemCount() const { return value.size(); }
bool isEmpty() const { return value.empty(); }
void clear() { value.erase(value.begin(), value.end()); }
void addItem(const TaggedListItem& v) { value.push_back(v); }
operator std::vector<TaggedListItem>() const { return value; }
STTaggedList& operator=(const std::vector<TaggedListItem>& v) { value=v; return *this; }
virtual bool isEquivalent(const SerializedType& t) const;
};
class STVector256 : public SerializedType
{
protected:
std::vector<uint256> mValue;
STVector256* duplicate() const { return new STVector256(name, mValue); }
static STVector256* construct(SerializerIterator&, const char* name = NULL);
STVector256* duplicate() const { return new STVector256(*this); }
static STVector256* construct(SerializerIterator&, SField::ref);
public:
STVector256() { ; }
STVector256(const char* n) : SerializedType(n) { ; }
STVector256(const char* n, const std::vector<uint256>& v) : SerializedType(n), mValue(v) { ; }
STVector256(SField::ref n) : SerializedType(n) { ; }
STVector256(SField::ref n, const std::vector<uint256>& v) : SerializedType(n), mValue(v) { ; }
STVector256(const std::vector<uint256>& vector) : mValue(vector) { ; }
SerializedTypeID getSType() const { return STI_VECTOR256; }
int getLength() const { return Serializer::lengthVL(mValue.size() * (256 / 8)); }
void add(Serializer& s) const;
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
const std::vector<uint256>& peekValue() const { return mValue; }
std::vector<uint256>& peekValue() { return mValue; }
virtual bool isEquivalent(const SerializedType& t) const;
std::vector<uint256> getValue() const { return mValue; }
bool isEmpty() const { return mValue.empty(); }
void setValue(const STVector256& v) { mValue = v.mValue; }
void setValue(const std::vector<uint256>& v) { mValue = v; }
std::vector<uint256> getValue() const { return mValue; }
bool isEmpty() const { return mValue.empty(); }
void setValue(const STVector256& v) { mValue = v.mValue; }
void setValue(const std::vector<uint256>& v) { mValue = v; }
void addValue(const uint256& v) { mValue.push_back(v); }
Json::Value getJson(int) const;
};

View File

@@ -3,30 +3,39 @@
#include "HashPrefixes.h"
SOElement SerializedValidation::sValidationFormat[] = {
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
{ sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 },
{ sfCloseTime, "CloseTime", STI_UINT32, SOE_REQUIRED, 0 },
{ sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 },
std::vector<SOElement::ptr> sValidationFormat;
static bool SVFInit()
{
sValidationFormat.push_back(new SOElement(sfFlags, SOE_REQUIRED));
sValidationFormat.push_back(new SOElement(sfLedgerHash, SOE_REQUIRED));
sValidationFormat.push_back(new SOElement(sfLedgerSequence, SOE_OPTIONAL));
sValidationFormat.push_back(new SOElement(sfCloseTime, SOE_OPTIONAL));
sValidationFormat.push_back(new SOElement(sfLoadFee, SOE_OPTIONAL));
sValidationFormat.push_back(new SOElement(sfBaseFee, SOE_OPTIONAL));
sValidationFormat.push_back(new SOElement(sfSigningTime, SOE_REQUIRED));
sValidationFormat.push_back(new SOElement(sfSigningPubKey, SOE_REQUIRED));
return true;
};
bool SVFinitComplete = SVFInit();
const uint32 SerializedValidation::sFullFlag = 0x00010000;
SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature)
: STObject(sValidationFormat, sit), mSignature(sit, "Signature"), mTrusted(false)
: STObject(sValidationFormat, sit, sfValidation), mSignature(sit, sfSignature), mTrusted(false)
{
if (checkSignature && !isValid()) throw std::runtime_error("Invalid validation");
}
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 closeTime,
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 signTime,
const NewcoinAddress& naSeed, bool isFull)
: STObject(sValidationFormat), mSignature("Signature"), mTrusted(false)
: STObject(sValidationFormat, sfValidation), mSignature(sfSignature), mTrusted(false)
{
setValueFieldH256(sfLedgerHash, ledgerHash);
setValueFieldU32(sfCloseTime, closeTime);
setFieldH256(sfLedgerHash, ledgerHash);
setFieldU32(sfSigningTime, signTime);
if (naSeed.isValid())
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
setFieldVL(sfSigningPubKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
if (!isFull) setFlag(sFullFlag);
NewcoinAddress::createNodePrivate(naSeed).signNodePrivate(getSigningHash(), mSignature.peekValue());
@@ -47,17 +56,17 @@ uint256 SerializedValidation::getSigningHash() const
uint256 SerializedValidation::getLedgerHash() const
{
return getValueFieldH256(sfLedgerHash);
return getFieldH256(sfLedgerHash);
}
uint32 SerializedValidation::getCloseTime() const
uint32 SerializedValidation::getSignTime() const
{
return getValueFieldU32(sfCloseTime);
return getFieldU32(sfSigningTime);
}
uint32 SerializedValidation::getFlags() const
{
return getValueFieldU32(sfFlags);
return getFieldU32(sfFlags);
}
bool SerializedValidation::isValid() const
@@ -69,7 +78,7 @@ bool SerializedValidation::isValid(const uint256& signingHash) const
{
try
{
NewcoinAddress naPublicKey = NewcoinAddress::createNodePublic(getValueFieldVL(sfSigningKey));
NewcoinAddress naPublicKey = NewcoinAddress::createNodePublic(getFieldVL(sfSigningPubKey));
return naPublicKey.isValid() && naPublicKey.verifyNodePublic(signingHash, mSignature.peekValue());
}
catch (...)
@@ -81,7 +90,7 @@ bool SerializedValidation::isValid(const uint256& signingHash) const
NewcoinAddress SerializedValidation::getSignerPublic() const
{
NewcoinAddress a;
a.setNodePublic(getValueFieldVL(sfSigningKey));
a.setNodePublic(getFieldVL(sfSigningPubKey));
return a;
}

View File

@@ -8,24 +8,25 @@ class SerializedValidation : public STObject
{
protected:
STVariableLength mSignature;
uint256 mPreviousHash;
bool mTrusted;
void setNode();
public:
typedef boost::shared_ptr<SerializedValidation> pointer;
typedef boost::shared_ptr<SerializedValidation> pointer;
typedef const boost::shared_ptr<SerializedValidation>& ref;
static SOElement sValidationFormat[16];
static const uint32 sFullFlag;
// These throw if the object is not valid
SerializedValidation(SerializerIterator& sit, bool checkSignature = true);
SerializedValidation(const Serializer& s, bool checkSignature = true);
SerializedValidation(const uint256& ledgerHash, uint32 closeTime, const NewcoinAddress& naSeed, bool isFull);
SerializedValidation(const uint256& ledgerHash, uint32 signTime, const NewcoinAddress& naSeed, bool isFull);
uint256 getLedgerHash() const;
uint32 getCloseTime() const;
uint32 getSignTime() const;
uint32 getFlags() const;
NewcoinAddress getSignerPublic() const;
bool isValid() const;
@@ -39,6 +40,11 @@ public:
void addSignature(Serializer&) const;
std::vector<unsigned char> getSigned() const;
std::vector<unsigned char> getSignature() const;
// The validation this replaced
const uint256& getPreviousHash() { return mPreviousHash; }
bool isPreviousHash(const uint256& h) { return mPreviousHash == h; }
void setPreviousHash(const uint256& h) { mPreviousHash = h; }
};
#endif

View File

@@ -154,6 +154,57 @@ uint256 Serializer::get256(int offset) const
return ret;
}
int Serializer::addFieldID(int type, int name)
{
int ret = mData.size();
assert((type > 0) && (type < 256) && (name > 0) && (name < 256));
if (type < 16)
{
if (name < 16) // common type, common name
mData.push_back(static_cast<unsigned char>((type << 4) | name));
else
{ // common type, uncommon name
mData.push_back(static_cast<unsigned char>(type << 4));
mData.push_back(static_cast<unsigned char>(name));
}
}
else if (name < 16)
{ // uncommon type, common name
mData.push_back(static_cast<unsigned char>(name));
mData.push_back(static_cast<unsigned char>(type));
}
else
{ // uncommon type, uncommon name
mData.push_back(static_cast<unsigned char>(0));
mData.push_back(static_cast<unsigned char>(type));
mData.push_back(static_cast<unsigned char>(name));
}
return ret;
}
bool Serializer::getFieldID(int& type, int & name, int offset) const
{
if (!get8(type, offset))
return false;
name = type & 15;
type >>= 4;
if (type == 0)
{ // uncommon type
if (!get8(type, ++offset))
return false;
if ((type == 0) || (type < 16))
return false;
}
if (name == 0)
{ // uncommon name
if (!get8(name, ++offset))
return false;
if ((name == 0) || (name < 16))
return false;
}
return true;
}
int Serializer::add8(unsigned char byte)
{
int ret = mData.size();
@@ -535,6 +586,17 @@ int SerializerIterator::getBytesLeft()
return mSerializer.size() - mPos;
}
void SerializerIterator::getFieldID(int& type, int& field)
{
if (!mSerializer.getFieldID(type, field, mPos))
throw std::runtime_error("invalid serializer getFieldID");
++mPos;
if (type >= 16)
++mPos;
if (field >= 16)
++mPos;
}
unsigned char SerializerIterator::get8()
{
int val;

Some files were not shown because too many files have changed in this diff Show More