mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-26 16:40:20 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
Conflicts: newcoin.vcxproj.filters
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -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
205
js/remote.js
Normal 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
44
js/serializer.js
Normal 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
137
js/utils.js
Normal 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
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
29
newcoind.cfg
29
newcoind.cfg
@@ -5,31 +5,8 @@
|
||||
# or Mac style end of lines. Blank lines and lines beginning with '#' are
|
||||
# ignored. Undefined sections are reserved. No escapes are currently defined.
|
||||
#
|
||||
# When you launch newcoind, it will attempt to find this file.
|
||||
#
|
||||
# --conf=<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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
520
src/Amount.cpp
520
src/Amount.cpp
@@ -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");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
35
src/Contract.cpp
Normal 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
30
src/Contract.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
97
src/FieldNames.cpp
Normal 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
85
src/FieldNames.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
200
src/Interpreter.cpp
Normal 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
82
src/Interpreter.h
Normal 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
|
||||
492
src/Ledger.cpp
492
src/Ledger.cpp
@@ -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
|
||||
|
||||
28
src/Ledger.h
28
src/Ledger.h
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
46
src/Log.cpp
46
src/Log.cpp
@@ -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);
|
||||
}
|
||||
|
||||
10
src/Log.h
10
src/Log.h
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
17
src/Operation.cpp
Normal 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
222
src/Operation.h
Normal 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
23
src/OrderBook.cpp
Normal 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
34
src/OrderBook.h
Normal 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
56
src/OrderBookDB.cpp
Normal 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
30
src/OrderBookDB.h
Normal 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
201
src/Pathfinder.cpp
Normal 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
52
src/Pathfinder.h
Normal 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
|
||||
116
src/Peer.cpp
116
src/Peer.cpp
@@ -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();
|
||||
|
||||
52
src/Peer.h
52
src/Peer.h
@@ -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(); }
|
||||
};
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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 ¶ms);
|
||||
Json::Value doRippleLinesGet(const Json::Value ¶ms);
|
||||
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
2400
src/RippleCalc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
190
src/RippleCalc.h
Normal file
190
src/RippleCalc.h
Normal 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
54
src/RippleLines.cpp
Normal 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
19
src/RippleLines.h
Normal 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); }
|
||||
};
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
|
||||
199
src/SHAMap.cpp
199
src/SHAMap.cpp
@@ -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;
|
||||
|
||||
|
||||
74
src/SHAMap.h
74
src/SHAMap.h
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
1
src/ScriptData.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "ScriptData.h"
|
||||
96
src/ScriptData.h
Normal file
96
src/ScriptData.h
Normal 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
134
src/SerializeProto.h
Normal 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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user