Browse Source

Merge remote-tracking branch 'upstream/develop' into stateTests

Conflicts:
	test/vmBitwiseLogicOperationTestFiller.json
cl-refactor
Christoph Jentzsch 10 years ago
parent
commit
6df4e33f2b
  1. 3
      .gitignore
  2. 7
      CMakeLists.txt
  3. 6
      README.md
  4. 2
      alethzero/CMakeLists.txt
  5. 76
      alethzero/MainWin.cpp
  6. 15
      alethzero/MainWin.h
  7. 1
      alethzero/main.cpp
  8. 379
      eth/BigInteger.js
  9. 4
      eth/CMakeLists.txt
  10. 217
      eth/EthStubServer.cpp
  11. 66
      eth/EthStubServer.h
  12. 162
      eth/abstractethstubserver.h
  13. 137
      eth/eth.js
  14. 62
      eth/ethString.js
  15. 13
      eth/main.cpp
  16. 24
      eth/spec.json
  17. 25
      libdevcore/CommonJS.cpp
  18. 65
      libdevcore/CommonJS.h
  19. 1
      libdevcore/_libdevcore.cpp
  20. 48
      libevm/VM.h
  21. 8
      libevmface/Instruction.cpp
  22. 19
      libevmface/Instruction.h
  23. 24
      libjsqrc/CMakeLists.txt
  24. 966
      libjsqrc/es6-promise-2.0.0.js
  25. 8
      libjsqrc/js.qrc
  26. 458
      libjsqrc/main.js
  27. 49
      libjsqrc/qt.js
  28. 44
      libjsqrc/setup.js
  29. 4
      liblll/Assembly.cpp
  30. 14
      liblll/CodeFragment.cpp
  31. 3
      libqethereum/CMakeLists.txt
  32. 836
      libqethereum/QEthereum.cpp
  33. 332
      libqethereum/QEthereum.h
  34. 49
      libserpent/opcodes.h
  35. 61
      libsolidity/AST.cpp
  36. 163
      libsolidity/AST.h
  37. 30
      libsolidity/ASTPrinter.cpp
  38. 5
      libsolidity/ASTPrinter.h
  39. 12
      libsolidity/ASTVisitor.h
  40. 6
      libsolidity/BaseTypes.h
  41. 401
      libsolidity/Compiler.cpp
  42. 146
      libsolidity/Compiler.h
  43. 21
      libsolidity/NameAndTypeResolver.cpp
  44. 23
      libsolidity/NameAndTypeResolver.h
  45. 13
      libsolidity/Parser.h
  46. 43
      libsolidity/Scanner.cpp
  47. 40
      libsolidity/Scanner.h
  48. 4
      libsolidity/Scope.cpp
  49. 10
      libsolidity/Scope.h
  50. 36
      libsolidity/SourceReferenceFormatter.cpp
  51. 20
      libsolidity/Token.h
  52. 92
      libsolidity/Types.cpp
  53. 68
      libsolidity/Types.h
  54. 55
      libweb3jsonrpc/CMakeLists.txt
  55. 42
      libweb3jsonrpc/CorsHttpServer.cpp
  56. 35
      libweb3jsonrpc/CorsHttpServer.h
  57. 657
      libweb3jsonrpc/WebThreeStubServer.cpp
  58. 124
      libweb3jsonrpc/WebThreeStubServer.h
  59. 323
      libweb3jsonrpc/abstractwebthreestubserver.h
  60. 55
      libweb3jsonrpc/spec.json
  61. 3
      libwebthree/WebThree.h
  62. 4
      neth/CMakeLists.txt
  63. 18
      neth/main.cpp
  64. 43
      solc/main.cpp
  65. 6
      test/CMakeLists.txt
  66. 250
      test/jsonrpc.cpp
  67. 229
      test/solidityCompiler.cpp
  68. 2
      test/solidityNameAndTypeResolution.cpp
  69. 2
      test/solidityParser.cpp
  70. 587
      test/webthreestubclient.h
  71. 2
      third/CMakeLists.txt
  72. 48
      third/MainWin.cpp
  73. 10
      third/MainWin.h
  74. 1
      third/main.cpp
  75. 4
      windows/LibEthereum.vcxproj
  76. 12
      windows/LibEthereum.vcxproj.filters

3
.gitignore

@ -19,6 +19,9 @@ ipch
*.opensdf *.opensdf
*.suo *.suo
# VIM stuff
*.swp
#Xcode stuff #Xcode stuff
build_xc build_xc

7
CMakeLists.txt

@ -119,6 +119,9 @@ endif()
add_subdirectory(lllc) add_subdirectory(lllc)
add_subdirectory(solc) add_subdirectory(solc)
add_subdirectory(sc) add_subdirectory(sc)
if (JSONRPC_LS)
add_subdirectory(libweb3jsonrpc)
endif()
if (NOT LANGUAGES) if (NOT LANGUAGES)
add_subdirectory(secp256k1) add_subdirectory(secp256k1)
add_subdirectory(libp2p) add_subdirectory(libp2p)
@ -147,7 +150,11 @@ if (NOT LANGUAGES)
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")
cmake_policy(SET CMP0020 NEW) cmake_policy(SET CMP0020 NEW)
endif () endif ()
if (NOT JSONRPC_LS)
message(FATAL_ERROR "Alethzero requires jsonrpc.")
endif()
add_subdirectory(libjsqrc)
add_subdirectory(libqethereum) add_subdirectory(libqethereum)
add_subdirectory(alethzero) add_subdirectory(alethzero)
add_subdirectory(third) add_subdirectory(third)

6
README.md

@ -33,6 +33,8 @@ All development goes in develop branch - please don't submit pull requests to ma
Please read [CodingStandards.txt](CodingStandards.txt) thoroughly before making alterations to the code base. Please do *NOT* use an editor that automatically reformats whitespace away from astylerc or the formatting guidelines as described in [CodingStandards.txt](CodingStandards.txt). Please read [CodingStandards.txt](CodingStandards.txt) thoroughly before making alterations to the code base. Please do *NOT* use an editor that automatically reformats whitespace away from astylerc or the formatting guidelines as described in [CodingStandards.txt](CodingStandards.txt).
When altering eth/spec.json, mirror the changes to eth/eth.js. This should simply be cutting and pasting the relevant part from spec.json into eth.js. Don't alter the spec part from eth.js independently. libweb3jsonrpc/abstractwebthreestubserver.h is autogenerated from the jsonrpcstub executable that comes with the libjsonrpc library (json-rpc-cpp project). It shouldn't be maually altered.
eth/abstractethstubserver.h is autogenerated from the jsonrpcstub executable that comes with the libjsonrpc library (json-rpc-cpp project). It shouldn't be maually altered. ```bash
jsonrpcstub -s -c spec.json WebThreeStub
```

2
alethzero/CMakeLists.txt

@ -53,7 +53,7 @@ else ()
endif () endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore web3jsonrpc jsqrc)
if (APPLE) if (APPLE)
# First have qt5 install plugins and frameworks # First have qt5 install plugins and frameworks

76
alethzero/MainWin.cpp

@ -33,6 +33,7 @@
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
#include <libserpent/util.h> #include <libserpent/util.h>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libdevcore/CommonJS.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
#include <libevm/VM.h> #include <libevm/VM.h>
@ -41,6 +42,7 @@
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>
#include <libethereum/DownloadMan.h> #include <libethereum/DownloadMan.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include "DownloadView.h" #include "DownloadView.h"
#include "MiningView.h" #include "MiningView.h"
#include "BuildInfo.h" #include "BuildInfo.h"
@ -83,6 +85,21 @@ static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
return QString(); return QString();
} }
static std::vector<dev::KeyPair> keysAsVector(QList<dev::KeyPair> const& keys)
{
auto list = keys.toStdList();
return {begin(list), end(list)};
}
static QString contentsOfQResource(std::string const& res)
{
QFile file(QString::fromStdString(res));
if (!file.open(QFile::ReadOnly))
BOOST_THROW_EXCEPTION(FileError());
QTextStream in(&file);
return in.readAll();
}
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
Main::Main(QWidget *parent) : Main::Main(QWidget *parent) :
@ -131,32 +148,28 @@ Main::Main(QWidget *parent) :
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"}));
m_ldb = new QLDB(this);
m_server = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(&m_qwebConnector, *web3(), keysAsVector(m_myKeys)));
m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening();
connect(ui->webView, &QWebView::loadStarted, [this]() connect(ui->webView, &QWebView::loadStarted, [this]()
{ {
m_ethereum = nullptr;
m_whisper = nullptr;
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this); m_qweb = new QWebThree(this);
m_ethereum = new QEthereum(this, ethereum(), m_myKeys); auto qweb = m_qweb;
m_whisper = new QWhisper(this, whisper(), owned()); m_qwebConnector.setQWeb(qweb);
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebFrame* f = ui->webView->page()->mainFrame(); QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qdev = m_dev; connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qweb));
auto qeth = m_ethereum; connect(m_qweb, SIGNAL(onNewId(QString)), this, SLOT(addNewId(QString)));
auto qshh = m_whisper;
auto qldb = m_ldb;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb));
connect(m_whisper, SIGNAL(newIdToAdd(QString)), this, SLOT(addNewId(QString)));
}); });
connect(ui->webView, &QWebView::loadFinished, [=]() connect(ui->webView, &QWebView::loadFinished, [=]()
{ {
m_ethereum->poll(); m_qweb->poll();
m_whisper->poll();
}); });
connect(ui->webView, &QWebView::titleChanged, [=]() connect(ui->webView, &QWebView::titleChanged, [=]()
@ -165,9 +178,7 @@ Main::Main(QWidget *parent) :
}); });
readSettings(); readSettings();
installWatches(); installWatches();
startTimer(100); startTimer(100);
{ {
@ -184,19 +195,17 @@ Main::~Main()
{ {
// Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor) // Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor)
// *after* the client is dead. // *after* the client is dead.
m_ethereum->clientDieing(); m_qweb->clientDieing();
m_whisper->faceDieing();
g_logPost = simpleDebugOut; g_logPost = simpleDebugOut;
writeSettings(); writeSettings();
} }
void Main::addNewId(QString _ids) void Main::addNewId(QString _ids)
{ {
Secret _id = toSecret(_ids); Secret _id = jsToSecret(_ids.toStdString());
KeyPair kp(_id); KeyPair kp(_id);
m_myIdentities.push_back(kp); m_myIdentities.push_back(kp);
m_whisper->setIdentities(owned()); m_server->setIdentities(keysAsVector(owned()));
} }
dev::p2p::NetworkPreferences Main::netPrefs() const dev::p2p::NetworkPreferences Main::netPrefs() const
@ -1056,10 +1065,8 @@ void Main::timerEvent(QTimerEvent*)
else else
interval += 100; interval += 100;
if (m_ethereum) if (m_qweb)
m_ethereum->poll(); m_qweb->poll();
if (m_whisper)
m_whisper->poll();
for (auto const& i: m_handlers) for (auto const& i: m_handlers)
if (ethereum()->checkWatch(i.first)) if (ethereum()->checkWatch(i.first))
@ -1182,8 +1189,9 @@ void Main::ourAccountsRowsMoved()
myKeys.push_back(i); myKeys.push_back(i);
} }
m_myKeys = myKeys; m_myKeys = myKeys;
if (m_ethereum)
m_ethereum->setAccounts(myKeys); if (m_server.get())
m_server->setAccounts(keysAsVector(m_myKeys));
} }
void Main::on_inject_triggered() void Main::on_inject_triggered()
@ -1629,7 +1637,6 @@ void Main::on_killBlockchain_triggered()
ui->net->setChecked(false); ui->net->setChecked(false);
web3()->stopNetwork(); web3()->stopNetwork();
ethereum()->killChain(); ethereum()->killChain();
m_ethereum->setClient(ethereum());
readSettings(true); readSettings(true);
installWatches(); installWatches();
refreshAll(); refreshAll();
@ -1785,7 +1792,6 @@ void Main::on_debug_clicked()
t.gasPrice = gasPrice(); t.gasPrice = gasPrice();
t.gas = ui->gas->value(); t.gas = ui->gas->value();
t.data = m_data; t.data = m_data;
t.type = isCreation() ? Transaction::ContractCreation : Transaction::MessageCall;
t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText());
t.sign(s); t.sign(s);
auto r = t.rlp(); auto r = t.rlp();
@ -2139,20 +2145,22 @@ void Main::on_post_clicked()
m.setPayload(dataFromText(ui->shhData->toPlainText())); m.setPayload(dataFromText(ui->shhData->toPlainText()));
Public f = stringToPublic(ui->shhFrom->currentText()); Public f = stringToPublic(ui->shhFrom->currentText());
Secret from; Secret from;
if (m_whisper->ids().count(f)) if (m_server->ids().count(f))
from = m_whisper->ids().at(f); from = m_server->ids().at(f);
whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value()));
} }
void Main::on_newIdentity_triggered() void Main::on_newIdentity_triggered()
{ {
m_whisper->makeIdentity(); KeyPair kp = KeyPair::create();
m_myIdentities.append(kp);
m_server->setIdentities(keysAsVector(owned()));
} }
void Main::refreshWhisper() void Main::refreshWhisper()
{ {
ui->shhFrom->clear(); ui->shhFrom->clear();
for (auto i: m_whisper->ids()) for (auto i: m_server ->ids())
ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref())));
} }
@ -2163,7 +2171,7 @@ void Main::refreshWhispers()
{ {
shh::Envelope const& e = w.second; shh::Envelope const& e = w.second;
shh::Message m; shh::Message m;
for (pair<Public, Secret> const& i: m_whisper->ids()) for (pair<Public, Secret> const& i: m_server->ids())
if (!!(m = e.open(i.second))) if (!!(m = e.open(i.second)))
break; break;
if (!m) if (!m)

15
alethzero/MainWin.h

@ -47,6 +47,7 @@ class MessageFilter;
}} }}
class QQuickView; class QQuickView;
class WebThreeStubServer;
struct WorldState struct WorldState
{ {
@ -153,11 +154,10 @@ private slots:
void on_newIdentity_triggered(); void on_newIdentity_triggered();
void refreshWhisper(); void refreshWhisper();
void addNewId(QString); void addNewId(QString _ids);
signals: signals:
void poll(); void poll();
void idsChanged();
private: private:
dev::p2p::NetworkPreferences netPrefs() const; dev::p2p::NetworkPreferences netPrefs() const;
@ -181,8 +181,6 @@ private:
void readSettings(bool _skipGeometry = false); void readSettings(bool _skipGeometry = false);
void writeSettings(); void writeSettings();
void keysChanged();
bool isCreation() const; bool isCreation() const;
dev::u256 fee() const; dev::u256 fee() const;
dev::u256 total() const; dev::u256 total() const;
@ -193,6 +191,8 @@ private:
unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f); unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f);
void uninstallWatch(unsigned _w); void uninstallWatch(unsigned _w);
void keysChanged();
void onNewPending(); void onNewPending();
void onNewBlock(); void onNewBlock();
void onNameRegChange(); void onNameRegChange();
@ -255,8 +255,7 @@ private:
QString m_logHistory; QString m_logHistory;
bool m_logChanged = true; bool m_logChanged = true;
QDev* m_dev = nullptr; std::unique_ptr<WebThreeStubServer> m_server;
QEthereum* m_ethereum = nullptr; QWebThreeConnector m_qwebConnector;
QWhisper* m_whisper = nullptr; QWebThree* m_qweb = nullptr;
QLDB* m_ldb = nullptr;
}; };

1
alethzero/main.cpp

@ -4,6 +4,7 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
Q_INIT_RESOURCE(js);
Main w; Main w;
w.show(); w.show();

379
eth/BigInteger.js

@ -1,379 +0,0 @@
var bigInt = (function () {
var base = 10000000, logBase = 7;
var sign = {
positive: false,
negative: true
};
var normalize = function (first, second) {
var a = first.value, b = second.value;
var length = a.length > b.length ? a.length : b.length;
for (var i = 0; i < length; i++) {
a[i] = a[i] || 0;
b[i] = b[i] || 0;
}
for (var i = length - 1; i >= 0; i--) {
if (a[i] === 0 && b[i] === 0) {
a.pop();
b.pop();
} else break;
}
if (!a.length) a = [0], b = [0];
first.value = a;
second.value = b;
};
var parse = function (text, first) {
if (typeof text === "object") return text;
text += "";
var s = sign.positive, value = [];
if (text[0] === "-") {
s = sign.negative;
text = text.slice(1);
}
var base = 10;
if (text.slice(0, 2) == "0x") {
base = 16;
text = text.slice(2);
}
else {
var texts = text.split("e");
if (texts.length > 2) throw new Error("Invalid integer");
if (texts[1]) {
var exp = texts[1];
if (exp[0] === "+") exp = exp.slice(1);
exp = parse(exp);
if (exp.lesser(0)) throw new Error("Cannot include negative exponent part for integers");
while (exp.notEquals(0)) {
texts[0] += "0";
exp = exp.prev();
}
}
text = texts[0];
}
if (text === "-0") text = "0";
text = text.toUpperCase();
var isValid = (base == 16 ? /^[0-9A-F]*$/ : /^[0-9]+$/).test(text);
if (!isValid) throw new Error("Invalid integer");
if (base == 16) {
var val = bigInt(0);
while (text.length) {
v = text.charCodeAt(0) - 48;
if (v > 9)
v -= 7;
text = text.slice(1);
val = val.times(16).plus(v);
}
return val;
}
else {
while (text.length) {
var divider = text.length > logBase ? text.length - logBase : 0;
value.push(+text.slice(divider));
text = text.slice(0, divider);
}
var val = bigInt(value, s);
if (first) normalize(first, val);
return val;
}
};
var goesInto = function (a, b) {
var a = bigInt(a, sign.positive), b = bigInt(b, sign.positive);
if (a.equals(0)) throw new Error("Cannot divide by 0");
var n = 0;
do {
var inc = 1;
var c = bigInt(a.value, sign.positive), t = c.times(10);
while (t.lesser(b)) {
c = t;
inc *= 10;
t = t.times(10);
}
while (c.lesserOrEquals(b)) {
b = b.minus(c);
n += inc;
}
} while (a.lesserOrEquals(b));
return {
remainder: b.value,
result: n
};
};
var bigInt = function (value, s) {
var self = {
value: value,
sign: s
};
var o = {
value: value,
sign: s,
negate: function (m) {
var first = m || self;
return bigInt(first.value, !first.sign);
},
abs: function (m) {
var first = m || self;
return bigInt(first.value, sign.positive);
},
add: function (n, m) {
var s, first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
s = first.sign;
if (first.sign !== second.sign) {
first = bigInt(first.value, sign.positive);
second = bigInt(second.value, sign.positive);
return s === sign.positive ?
o.subtract(first, second) :
o.subtract(second, first);
}
normalize(first, second);
var a = first.value, b = second.value;
var result = [],
carry = 0;
for (var i = 0; i < a.length || carry > 0; i++) {
var sum = (a[i] || 0) + (b[i] || 0) + carry;
carry = sum >= base ? 1 : 0;
sum -= carry * base;
result.push(sum);
}
return bigInt(result, s);
},
plus: function (n, m) {
return o.add(n, m);
},
subtract: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
if (first.sign !== second.sign) return o.add(first, o.negate(second));
if (first.sign === sign.negative) return o.subtract(o.negate(second), o.negate(first));
if (o.compare(first, second) === -1) return o.negate(o.subtract(second, first));
var a = first.value, b = second.value;
var result = [],
borrow = 0;
for (var i = 0; i < a.length; i++) {
var tmp = a[i] - borrow;
borrow = tmp < b[i] ? 1 : 0;
var minuend = (borrow * base) + tmp - b[i];
result.push(minuend);
}
return bigInt(result, sign.positive);
},
minus: function (n, m) {
return o.subtract(n, m);
},
multiply: function (n, m) {
var s, first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
s = first.sign !== second.sign;
var a = first.value, b = second.value;
var resultSum = [];
for (var i = 0; i < a.length; i++) {
resultSum[i] = [];
var j = i;
while (j--) {
resultSum[i].push(0);
}
}
var carry = 0;
for (var i = 0; i < a.length; i++) {
var x = a[i];
for (var j = 0; j < b.length || carry > 0; j++) {
var y = b[j];
var product = y ? (x * y) + carry : carry;
carry = product > base ? Math.floor(product / base) : 0;
product -= carry * base;
resultSum[i].push(product);
}
}
var max = -1;
for (var i = 0; i < resultSum.length; i++) {
var len = resultSum[i].length;
if (len > max) max = len;
}
var result = [], carry = 0;
for (var i = 0; i < max || carry > 0; i++) {
var sum = carry;
for (var j = 0; j < resultSum.length; j++) {
sum += resultSum[j][i] || 0;
}
carry = sum > base ? Math.floor(sum / base) : 0;
sum -= carry * base;
result.push(sum);
}
return bigInt(result, s);
},
times: function (n, m) {
return o.multiply(n, m);
},
divmod: function (n, m) {
var s, first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
s = first.sign !== second.sign;
if (bigInt(first.value, first.sign).equals(0)) return {
quotient: bigInt([0], sign.positive),
remainder: bigInt([0], sign.positive)
};
if (second.equals(0)) throw new Error("Cannot divide by zero");
var a = first.value, b = second.value;
var result = [], remainder = [];
for (var i = a.length - 1; i >= 0; i--) {
var n = [a[i]].concat(remainder);
var quotient = goesInto(b, n);
result.push(quotient.result);
remainder = quotient.remainder;
}
result.reverse();
return {
quotient: bigInt(result, s),
remainder: bigInt(remainder, first.sign)
};
},
divide: function (n, m) {
return o.divmod(n, m).quotient;
},
over: function (n, m) {
return o.divide(n, m);
},
mod: function (n, m) {
return o.divmod(n, m).remainder;
},
pow: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
var a = first, b = second;
if (b.lesser(0)) return ZERO;
if (b.equals(0)) return ONE;
var result = bigInt(a.value, a.sign);
if (b.mod(2).equals(0)) {
var c = result.pow(b.over(2));
return c.times(c);
} else {
return result.times(result.pow(b.minus(1)));
}
},
next: function (m) {
var first = m || self;
return o.add(first, 1);
},
prev: function (m) {
var first = m || self;
return o.subtract(first, 1);
},
compare: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m, first));
else second = parse(n, first);
normalize(first, second);
if (first.value.length === 1 && second.value.length === 1 && first.value[0] === 0 && second.value[0] === 0) return 0;
if (second.sign !== first.sign) return first.sign === sign.positive ? 1 : -1;
var multiplier = first.sign === sign.positive ? 1 : -1;
var a = first.value, b = second.value;
for (var i = a.length - 1; i >= 0; i--) {
if (a[i] > b[i]) return 1 * multiplier;
if (b[i] > a[i]) return -1 * multiplier;
}
return 0;
},
compareAbs: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m, first));
else second = parse(n, first);
first.sign = second.sign = sign.positive;
return o.compare(first, second);
},
equals: function (n, m) {
return o.compare(n, m) === 0;
},
notEquals: function (n, m) {
return !o.equals(n, m);
},
lesser: function (n, m) {
return o.compare(n, m) < 0;
},
greater: function (n, m) {
return o.compare(n, m) > 0;
},
greaterOrEquals: function (n, m) {
return o.compare(n, m) >= 0;
},
lesserOrEquals: function (n, m) {
return o.compare(n, m) <= 0;
},
isPositive: function (m) {
var first = m || self;
return first.sign === sign.positive;
},
isNegative: function (m) {
var first = m || self;
return first.sign === sign.negative;
},
isEven: function (m) {
var first = m || self;
return first.value[0] % 2 === 0;
},
isOdd: function (m) {
var first = m || self;
return first.value[0] % 2 === 1;
},
toString: function (m) {
var first = m || self;
var str = "", len = first.value.length;
while (len--) {
if (first.value[len].toString().length === 8) str += first.value[len];
else str += (base.toString() + first.value[len]).slice(-logBase);
}
while (str[0] === "0") {
str = str.slice(1);
}
if (!str.length) str = "0";
var s = (first.sign === sign.positive || str == "0") ? "" : "-";
return s + str;
},
toHex: function (m) {
var first = m || self;
var str = "";
var l = this.abs();
while (l > 0) {
var qr = l.divmod(256);
var b = qr.remainder.toJSNumber();
str = (b >> 4).toString(16) + (b & 15).toString(16) + str;
l = qr.quotient;
}
return (this.isNegative() ? "-" : "") + "0x" + str;
},
toJSNumber: function (m) {
return +o.toString(m);
},
valueOf: function (m) {
return o.toJSNumber(m);
}
};
return o;
};
var ZERO = bigInt([0], sign.positive);
var ONE = bigInt([1], sign.positive);
var MINUS_ONE = bigInt([1], sign.negative);
var fnReturn = function (a) {
if (typeof a === "undefined") return ZERO;
return parse(a);
};
fnReturn.zero = ZERO;
fnReturn.one = ONE;
fnReturn.minusOne = MINUS_ONE;
return fnReturn;
})();
if (typeof module !== "undefined") {
module.exports = bigInt;
}

4
eth/CMakeLists.txt

@ -3,8 +3,6 @@ cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(..)
link_directories(../libethcore)
link_directories(../libwebthree)
set(EXECUTABLE eth) set(EXECUTABLE eth)
@ -20,7 +18,7 @@ endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS})
if(JSONRPC_LS) if(JSONRPC_LS)
target_link_libraries(${EXECUTABLE} ${JSONRPC_LS}) target_link_libraries(${EXECUTABLE} web3jsonrpc)
endif() endif()
if(READLINE_LS) if(READLINE_LS)
target_link_libraries(${EXECUTABLE} ${READLINE_LS}) target_link_libraries(${EXECUTABLE} ${READLINE_LS})

217
eth/EthStubServer.cpp

@ -1,217 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthStubServer.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* @date 2014
*/
#if ETH_JSONRPC
#include "EthStubServer.h"
#include <libevmface/Instruction.h>
#include <liblll/Compiler.h>
#include <libethereum/Client.h>
#include <libwebthree/WebThree.h>
#include "CommonJS.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3):
AbstractEthStubServer(_conn),
m_web3(_web3)
{
}
//only works with a json spec that doesn't have notifications for now
Json::Value EthStubServer::procedures()
{
Json::Value ret;
for (auto proc: this->GetProtocolHanlder()->GetProcedures())
{
Json::Value proc_j;
proc_j[proc.second->GetProcedureType() == 0 ? "method" : "notification"] = proc.first;
Json::Value params_j;
for (auto params: proc.second->GetParameters())
params_j[params.first] = jsontypeToValue(params.second);
proc_j["params"] = params_j;
proc_j["returns"] = jsontypeToValue(proc.second->GetReturnType());
ret.append(proc_j);
}
return ret;
}
dev::eth::Client& EthStubServer::ethereum() const
{
return *m_web3.ethereum();
}
std::string EthStubServer::coinbase()
{
return toJS(ethereum().address());
}
std::string EthStubServer::balanceAt(std::string const& _a)
{
return toJS(ethereum().balanceAt(jsToAddress(_a), 0));
}
Json::Value EthStubServer::check(Json::Value const& _as)
{
// TODO
// if (ethereum().changed())
return _as;
/* else
{
Json::Value ret;
ret.resize(0);
return ret;
}*/
}
std::string EthStubServer::create(const std::string& _bCode, const std::string& _sec, const std::string& _xEndowment, const std::string& _xGas, const std::string& _xGasPrice)
{
Address ret = ethereum().transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice));
return toJS(ret);
}
std::string EthStubServer::lll(const std::string& _s)
{
return "0x" + toHex(dev::eth::compileLLL(_s));
}
std::string EthStubServer::gasPrice()
{
return "100000000000000";
}
bool EthStubServer::isContractAt(const std::string& _a)
{
return ethereum().codeAt(jsToAddress(_a), 0).size();
}
bool EthStubServer::isListening()
{
return m_web3.haveNetwork();
}
bool EthStubServer::isMining()
{
return ethereum().isMining();
}
std::string EthStubServer::key()
{
if (!m_keys.size())
return std::string();
return toJS(m_keys[0].sec());
}
Json::Value EthStubServer::keys()
{
Json::Value ret;
for (auto i: m_keys)
ret.append(toJS(i.secret()));
return ret;
}
int EthStubServer::peerCount()
{
return m_web3.peerCount();
}
std::string EthStubServer::storageAt(const std::string& _a, const std::string& x)
{
return toJS(ethereum().stateAt(jsToAddress(_a), jsToU256(x), 0));
}
std::string EthStubServer::stateAt(const std::string& _a, const std::string& x, const std::string& s)
{
return toJS(ethereum().stateAt(jsToAddress(_a), jsToU256(x), std::atol(s.c_str())));
}
Json::Value EthStubServer::transact(const std::string& _aDest, const std::string& _bData, const std::string& _sec, const std::string& _xGas, const std::string& _xGasPrice, const std::string& _xValue)
{
ethereum().transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice));
return Json::Value();
}
std::string EthStubServer::txCountAt(const std::string& _a)
{
return toJS(ethereum().countAt(jsToAddress(_a), 0));
}
std::string EthStubServer::secretToAddress(const std::string& _a)
{
return toJS(KeyPair(jsToSecret(_a)).address());
}
Json::Value EthStubServer::lastBlock()
{
return blockJson("");
}
Json::Value EthStubServer::block(const std::string& _hash)
{
return blockJson(_hash);
}
Json::Value EthStubServer::blockJson(const std::string& _hash)
{
Json::Value res;
auto const& bc = ethereum().blockChain();
auto b = _hash.length() ? bc.block(h256(_hash)) : bc.block();
auto bi = BlockInfo(b);
res["number"] = boost::lexical_cast<string>(bi.number);
res["hash"] = boost::lexical_cast<string>(bi.hash);
res["parentHash"] = boost::lexical_cast<string>(bi.parentHash);
res["sha3Uncles"] = boost::lexical_cast<string>(bi.sha3Uncles);
res["coinbaseAddress"] = boost::lexical_cast<string>(bi.coinbaseAddress);
res["stateRoot"] = boost::lexical_cast<string>(bi.stateRoot);
res["transactionsRoot"] = boost::lexical_cast<string>(bi.transactionsRoot);
res["minGasPrice"] = boost::lexical_cast<string>(bi.minGasPrice);
res["gasLimit"] = boost::lexical_cast<string>(bi.gasLimit);
res["gasUsed"] = boost::lexical_cast<string>(bi.gasUsed);
res["difficulty"] = boost::lexical_cast<string>(bi.difficulty);
res["timestamp"] = boost::lexical_cast<string>(bi.timestamp);
res["nonce"] = boost::lexical_cast<string>(bi.nonce);
return res;
}
Json::Value EthStubServer::jsontypeToValue(int _jsontype)
{
switch (_jsontype)
{
case jsonrpc::JSON_STRING: return ""; //Json::stringValue segfault, fuck knows why
case jsonrpc::JSON_BOOLEAN: return Json::booleanValue;
case jsonrpc::JSON_INTEGER: return Json::intValue;
case jsonrpc::JSON_REAL: return Json::realValue;
case jsonrpc::JSON_OBJECT: return Json::objectValue;
case jsonrpc::JSON_ARRAY: return Json::arrayValue;
default: return Json::nullValue;
}
}
#endif

66
eth/EthStubServer.h

@ -1,66 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthStubServer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <iostream>
#include <jsonrpc/rpc.h>
#include <libdevcrypto/Common.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "abstractethstubserver.h"
#pragma GCC diagnostic pop
namespace dev { class WebThreeDirect; namespace eth { class Client; } class KeyPair; }
class EthStubServer: public AbstractEthStubServer
{
public:
EthStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3);
virtual Json::Value procedures();
virtual std::string balanceAt(std::string const& _a);
virtual Json::Value check(Json::Value const& _as);
virtual std::string coinbase();
virtual std::string create(const std::string& bCode, const std::string& sec, const std::string& xEndowment, const std::string& xGas, const std::string& xGasPrice);
virtual std::string gasPrice();
virtual bool isContractAt(const std::string& a);
virtual bool isListening();
virtual bool isMining();
virtual std::string key();
virtual Json::Value keys();
virtual int peerCount();
virtual std::string storageAt(const std::string& a, const std::string& x);
virtual std::string stateAt(const std::string& a, const std::string& x, const std::string& s);
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue);
virtual std::string txCountAt(const std::string& a);
virtual std::string secretToAddress(const std::string& a);
virtual Json::Value lastBlock();
virtual std::string lll(const std::string& s);
virtual Json::Value block(const std::string&);
void setKeys(std::vector<dev::KeyPair> _keys) { m_keys = _keys; }
private:
dev::eth::Client& ethereum() const;
dev::WebThreeDirect& m_web3;
std::vector<dev::KeyPair> m_keys;
Json::Value jsontypeToValue(int);
Json::Value blockJson(const std::string&);
};

162
eth/abstractethstubserver.h

@ -1,162 +0,0 @@
/**
* THIS FILE IS GENERATED BY jsonrpcstub, DO NOT CHANGE IT!!!!!
*/
#ifndef _ABSTRACTETHSTUBSERVER_H_
#define _ABSTRACTETHSTUBSERVER_H_
#include <jsonrpc/rpc.h>
class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServer>
{
public:
AbstractEthStubServer(jsonrpc::AbstractServerConnector* conn) :
jsonrpc::AbstractServer<AbstractEthStubServer>(conn)
{
this->bindAndAddMethod(new jsonrpc::Procedure("balanceAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::balanceAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("block", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::blockI);
this->bindAndAddMethod(new jsonrpc::Procedure("check", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, "a",jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::checkI);
this->bindAndAddMethod(new jsonrpc::Procedure("coinbase", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::coinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("create", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "bCode",jsonrpc::JSON_STRING,"sec",jsonrpc::JSON_STRING,"xEndowment",jsonrpc::JSON_STRING,"xGas",jsonrpc::JSON_STRING,"xGasPrice",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::createI);
this->bindAndAddMethod(new jsonrpc::Procedure("gasPrice", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::gasPriceI);
this->bindAndAddMethod(new jsonrpc::Procedure("isContractAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_BOOLEAN, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::isContractAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("isListening", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_BOOLEAN, NULL), &AbstractEthStubServer::isListeningI);
this->bindAndAddMethod(new jsonrpc::Procedure("isMining", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_BOOLEAN, NULL), &AbstractEthStubServer::isMiningI);
this->bindAndAddMethod(new jsonrpc::Procedure("key", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::keyI);
this->bindAndAddMethod(new jsonrpc::Procedure("keys", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::keysI);
this->bindAndAddMethod(new jsonrpc::Procedure("lastBlock", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, NULL), &AbstractEthStubServer::lastBlockI);
this->bindAndAddMethod(new jsonrpc::Procedure("lll", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "s",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::lllI);
this->bindAndAddMethod(new jsonrpc::Procedure("peerCount", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_INTEGER, NULL), &AbstractEthStubServer::peerCountI);
this->bindAndAddMethod(new jsonrpc::Procedure("procedures", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::proceduresI);
this->bindAndAddMethod(new jsonrpc::Procedure("secretToAddress", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::secretToAddressI);
this->bindAndAddMethod(new jsonrpc::Procedure("storageAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::storageAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("stateAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING,"s",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::stateAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "aDest",jsonrpc::JSON_STRING,"bData",jsonrpc::JSON_STRING,"sec",jsonrpc::JSON_STRING,"xGas",jsonrpc::JSON_STRING,"xGasPrice",jsonrpc::JSON_STRING,"xValue",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::transactI);
this->bindAndAddMethod(new jsonrpc::Procedure("txCountAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::txCountAtI);
}
inline virtual void balanceAtI(const Json::Value& request, Json::Value& response)
{
response = this->balanceAt(request["a"].asString());
}
inline virtual void blockI(const Json::Value& request, Json::Value& response)
{
response = this->block(request["a"].asString());
}
inline virtual void checkI(const Json::Value& request, Json::Value& response)
{
response = this->check(request["a"]);
}
inline virtual void coinbaseI(const Json::Value& request, Json::Value& response)
{
response = this->coinbase();
}
inline virtual void createI(const Json::Value& request, Json::Value& response)
{
response = this->create(request["bCode"].asString(), request["sec"].asString(), request["xEndowment"].asString(), request["xGas"].asString(), request["xGasPrice"].asString());
}
inline virtual void gasPriceI(const Json::Value& request, Json::Value& response)
{
response = this->gasPrice();
}
inline virtual void isContractAtI(const Json::Value& request, Json::Value& response)
{
response = this->isContractAt(request["a"].asString());
}
inline virtual void isListeningI(const Json::Value& request, Json::Value& response)
{
response = this->isListening();
}
inline virtual void isMiningI(const Json::Value& request, Json::Value& response)
{
response = this->isMining();
}
inline virtual void keyI(const Json::Value& request, Json::Value& response)
{
response = this->key();
}
inline virtual void keysI(const Json::Value& request, Json::Value& response)
{
response = this->keys();
}
inline virtual void lastBlockI(const Json::Value& request, Json::Value& response)
{
response = this->lastBlock();
}
inline virtual void lllI(const Json::Value& request, Json::Value& response)
{
response = this->lll(request["s"].asString());
}
inline virtual void peerCountI(const Json::Value& request, Json::Value& response)
{
response = this->peerCount();
}
inline virtual void proceduresI(const Json::Value& request, Json::Value& response)
{
response = this->procedures();
}
inline virtual void secretToAddressI(const Json::Value& request, Json::Value& response)
{
response = this->secretToAddress(request["a"].asString());
}
inline virtual void storageAtI(const Json::Value& request, Json::Value& response)
{
response = this->storageAt(request["a"].asString(), request["x"].asString());
}
inline virtual void stateAtI(const Json::Value& request, Json::Value& response)
{
response = this->stateAt(request["a"].asString(), request["x"].asString(), request["s"].asString());
}
inline virtual void transactI(const Json::Value& request, Json::Value& response)
{
response = this->transact(request["aDest"].asString(), request["bData"].asString(), request["sec"].asString(), request["xGas"].asString(), request["xGasPrice"].asString(), request["xValue"].asString());
}
inline virtual void txCountAtI(const Json::Value& request, Json::Value& response)
{
response = this->txCountAt(request["a"].asString());
}
virtual std::string balanceAt(const std::string& a) = 0;
virtual Json::Value block(const std::string& a) = 0;
virtual Json::Value check(const Json::Value& a) = 0;
virtual std::string coinbase() = 0;
virtual std::string create(const std::string& bCode, const std::string& sec, const std::string& xEndowment, const std::string& xGas, const std::string& xGasPrice) = 0;
virtual std::string gasPrice() = 0;
virtual bool isContractAt(const std::string& a) = 0;
virtual bool isListening() = 0;
virtual bool isMining() = 0;
virtual std::string key() = 0;
virtual Json::Value keys() = 0;
virtual Json::Value lastBlock() = 0;
virtual std::string lll(const std::string& s) = 0;
virtual int peerCount() = 0;
virtual Json::Value procedures() = 0;
virtual std::string secretToAddress(const std::string& a) = 0;
virtual std::string storageAt(const std::string& a, const std::string& x) = 0;
virtual std::string stateAt(const std::string& a, const std::string& x, const std::string& b) = 0;
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue) = 0;
virtual std::string txCountAt(const std::string& a) = 0;
};
#endif //_ABSTRACTETHSTUBSERVER_H_

137
eth/eth.js

@ -1,137 +0,0 @@
if (typeof(window.eth) === "undefined")
{
if (typeof(require) !== "undefined")
require( ['ethString'], function() {} )
else if (typeof(String.prototype.pad) === "undefined")
{
var scriptTag = document.getElementsByTagName('script');
scriptTag = scriptTag[scriptTag.length - 1];
var scriptPath = scriptTag.src;
var path = scriptPath.substr(0, scriptPath.lastIndexOf( '/' ));
var start = '<script src="' + path + '/';
var slash = '"><'+'/script>';
document.write(start + 'BigInteger.js' + slash);
document.write(start + 'ethString.js' + slash);
}
var spec = [
{ "method": "procedures", "params": null, "order": [], "returns": [] },
{ "method": "coinbase", "params": null, "order": [], "returns" : "" },
{ "method": "isListening", "params": null, "order": [], "returns" : false },
{ "method": "isMining", "params": null, "order": [], "returns" : false },
{ "method": "gasPrice", "params": null, "order": [], "returns" : "" },
{ "method": "key", "params": null, "order": [], "returns" : "" },
{ "method": "keys", "params": null, "order": [], "returns" : [] },
{ "method": "peerCount", "params": null, "order": [], "returns" : 0 },
{ "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" },
{ "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" },
{ "method": "stateAt", "params": { "a": "", "x": "", "s": "" }, "order": ["a", "x", "s"], "returns" : "" },
{ "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" },
{ "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false },
{ "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" },
{ "method": "transact", "params": { "sec": "", "xValue": "", "aDest": "", "bData": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xValue", "aDest", "bData", "xGas", "xGasPrice"], "returns": {} },
{ "method": "secretToAddress", "params": { "a": "" }, "order": ["a"], "returns" : "" },
{ "method": "lll", "params": { "s": "" }, "order": ["s"], "returns" : "" }
];
window.eth = (function ethScope() {
var m_reqId = 0
var ret = {}
function reformat(m, d) { return m == "lll" ? d.bin() : d; }
function reqSync(m, p) {
var req = { "jsonrpc": "2.0", "method": m, "params": p, "id": m_reqId }
m_reqId++
var request = new XMLHttpRequest();
request.open("POST", "http://localhost:8080", false)
// console.log("Sending " + JSON.stringify(req))
request.send(JSON.stringify(req))
return reformat(m, JSON.parse(request.responseText).result)
}
function reqAsync(m, p, f) {
var req = { "jsonrpc": "2.0", "method": m, "params": p, "id": m_reqId }
m_reqId++
var request = new XMLHttpRequest();
request.open("POST", "http://localhost:8080", true)
request.send(JSON.stringify(req))
request.onreadystatechange = function() {
if (request.readyState === 4)
f(reformat(m, JSON.parse(request.responseText).result))
};
}
function isEmpty(obj) {
for (var prop in obj)
if (obj.hasOwnProperty(prop))
return false
return true
}
var m_watching = {};
for (si in spec) (function(s) {
var m = s.method;
var am = "get" + m.slice(0, 1).toUpperCase() + m.slice(1);
var getParams = function(a) {
var p = s.params ? {} : null;
if (m == "stateAt")
if (a.length == 2)
a[2] = "0";
else
a[2] = String(a[2]);
for (j in s.order)
p[s.order[j]] = (s.order[j][0] === "b") ? a[j].unbin() : a[j];
return p
};
if (m == "create" || m == "transact")
ret[m] = function() { return reqAsync(m, getParams(arguments), arguments[s.order.length]) }
else
{
ret[am] = function() { return reqAsync(m, getParams(arguments), arguments[s.order.length]) }
if (s.params)
ret[m] = function() { return reqSync(m, getParams(arguments)) }
else
Object.defineProperty(ret, m, {
get: function() { return reqSync(m, {}); },
set: function(v) {}
})
}
})(spec[si]);
ret.check = function(force) {
if (!force && isEmpty(m_watching))
return
var watching = [];
for (var w in m_watching)
watching.push(w)
var changed = reqSync("check", { "a": watching } );
// console.log("Got " + JSON.stringify(changed));
for (var c in changed)
m_watching[changed[c]]()
var that = this;
setTimeout(function() { that.check() }, 12000)
}
ret.watch = function(a, fx, f) {
var old = isEmpty(m_watching)
if (f)
m_watching[a + fx] = f
else
m_watching[a] = fx
(f ? f : fx)()
if (isEmpty(m_watching) != old)
this.check()
}
ret.unwatch = function(f, fx) {
delete m_watching[fx ? f + fx : f];
}
ret.newBlock = function(f) {
var old = isEmpty(m_watching)
m_watching[""] = f
f()
if (isEmpty(m_watching) != old)
this.check()
}
return ret;
}());
}

62
eth/ethString.js

@ -1,62 +0,0 @@
if (typeof(require) !== "undefined")
require( ['BigInteger'], function() {} )
else if (typeof(bigInt) === "undefined")
alert("You need to have included BigInteger.js for eth to work.")
String.prototype.pad = function(l, r) {
if (r === null) {
r = l
if (!(this.substr(0, 2) == "0x" || /^\d+$/.test(this)))
l = 0
}
var ret = this.bin();
while (ret.length < l)
ret = "\0" + ret
while (ret.length < r)
ret = ret + "\0"
return ret;
}
String.prototype.unpad = function() {
var i = this.length;
while (i && this[i - 1] == "\0")
--i
return this.substr(0, i)
}
String.prototype.bin = function() {
if (this.substr(0, 2) == "0x") {
bytes = []
var i = 2;
// Check if it's odd - pad with a zero if so.
if (this.length % 2)
bytes.push(parseInt(this.substr(i++, 1), 16))
for (; i < this.length - 1; i += 2)
bytes.push(parseInt(this.substr(i, 2), 16));
return String.fromCharCode.apply(String, bytes);
} else if (/^\d+$/.test(this))
return bigInt(this.substr(0)).toHex().bin()
// Otherwise we'll return the "String" object instead of an actual string
return this.substr(0, this.length)
}
String.prototype.unbin = function() {
var i, l, o = '';
for(i = 0, l = this.length; i < l; i++) {
var n = this.charCodeAt(i).toString(16);
o += n.length < 2 ? '0' + n : n;
}
return "0x" + o;
}
String.prototype.dec = function() {
return bigInt(this.substr(0)).toString()
}
String.prototype.hex = function() {
return bigInt(this.substr(0)).toHex()
}

13
eth/main.cpp

@ -29,6 +29,7 @@
#include <boost/algorithm/string/trim_all.hpp> #include <boost/algorithm/string/trim_all.hpp>
#if ETH_JSONRPC #if ETH_JSONRPC
#include <jsonrpc/connectors/httpserver.h> #include <jsonrpc/connectors/httpserver.h>
#include <libweb3jsonrpc/CorsHttpServer.h>
#endif #endif
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libevmface/Instruction.h> #include <libevmface/Instruction.h>
@ -40,7 +41,7 @@
#include <readline/history.h> #include <readline/history.h>
#endif #endif
#if ETH_JSONRPC #if ETH_JSONRPC
#include "EthStubServer.h" #include <libweb3jsonrpc/WebThreeStubServer.h>
#endif #endif
#include "BuildInfo.h" #include "BuildInfo.h"
using namespace std; using namespace std;
@ -336,11 +337,11 @@ int main(int argc, char** argv)
web3.connect(remoteHost, remotePort); web3.connect(remoteHost, remotePort);
#if ETH_JSONRPC #if ETH_JSONRPC
auto_ptr<EthStubServer> jsonrpcServer; auto_ptr<WebThreeStubServer> jsonrpcServer;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3)); jsonrpcServer = auto_ptr<WebThreeStubServer>(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us}));
jsonrpcServer->setKeys({us}); jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
#endif #endif
@ -427,8 +428,8 @@ int main(int argc, char** argv)
{ {
if (jsonrpc < 0) if (jsonrpc < 0)
jsonrpc = 8080; jsonrpc = 8080;
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3)); jsonrpcServer = auto_ptr<WebThreeStubServer>(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us}));
jsonrpcServer->setKeys({us}); jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
else if (cmd == "jsonstop") else if (cmd == "jsonstop")

24
eth/spec.json

@ -1,24 +0,0 @@
[
{ "method": "procedures", "params": null, "order": [], "returns": [] },
{ "method": "coinbase", "params": null, "order": [], "returns" : "" },
{ "method": "isListening", "params": null, "order": [], "returns" : false },
{ "method": "isMining", "params": null, "order": [], "returns" : false },
{ "method": "gasPrice", "params": null, "order": [], "returns" : "" },
{ "method": "key", "params": null, "order": [], "returns" : "" },
{ "method": "keys", "params": null, "order": [], "returns" : [] },
{ "method": "peerCount", "params": null, "order": [], "returns" : 0 },
{ "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" },
{ "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" },
{ "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" },
{ "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false },
{ "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" },
{ "method": "transact", "params": { "sec": "", "xValue": "", "aDest": "", "bData": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xValue", "aDest", "bData", "xGas", "xGasPrice"], "returns": {} },
{ "method": "secretToAddress", "params": { "a": "" }, "order": ["a"], "returns" : "" },
{ "method": "lll", "params": { "s": "" }, "order": ["s"], "returns" : "" }
,
{ "method": "check", "params": { "a": [] }, "order": ["a"], "returns" : [] },
{ "method": "lastBlock", "params": null, "order": [], "returns": {}},
{ "method": "block", "params": {"a":""}, "order": ["a"], "returns": {}}
]

25
eth/CommonJS.cpp → libdevcore/CommonJS.cpp

@ -17,20 +17,21 @@
/** @file CommonJS.cpp /** @file CommonJS.cpp
* @authors: * @authors:
* Gav Wood <i@gavwood.com> * Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
*/ */
#include "CommonJS.h" #include "CommonJS.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
bytes dev::eth::jsToBytes(string const& _s) namespace dev
{
bytes jsToBytes(std::string const& _s)
{ {
if (_s.substr(0, 2) == "0x") if (_s.substr(0, 2) == "0x")
// Hex // Hex
return fromHex(_s.substr(2)); return fromHex(_s.substr(2));
else if (_s.find_first_not_of("0123456789") == string::npos) else if (_s.find_first_not_of("0123456789") == std::string::npos)
// Decimal // Decimal
return toCompactBigEndian(bigint(_s)); return toCompactBigEndian(bigint(_s));
else else
@ -38,19 +39,19 @@ bytes dev::eth::jsToBytes(string const& _s)
return asBytes(_s); return asBytes(_s);
} }
string dev::eth::jsPadded(string const& _s, unsigned _l, unsigned _r) std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r)
{ {
bytes b = jsToBytes(_s); bytes b = jsToBytes(_s);
while (b.size() < _l) while (b.size() < _l)
b.insert(b.begin(), 0); b.insert(b.begin(), 0);
while (b.size() < _r) while (b.size() < _r)
b.push_back(0); b.push_back(0);
return asString(b).substr(b.size() - max(_l, _r)); return asString(b).substr(b.size() - std::max(_l, _r));
} }
string dev::eth::jsPadded(string const& _s, unsigned _l) std::string jsPadded(std::string const& _s, unsigned _l)
{ {
if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == string::npos) if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == std::string::npos)
// Numeric: pad to right // Numeric: pad to right
return jsPadded(_s, _l, _l); return jsPadded(_s, _l, _l);
else else
@ -58,9 +59,11 @@ string dev::eth::jsPadded(string const& _s, unsigned _l)
return jsPadded(_s, 0, _l); return jsPadded(_s, 0, _l);
} }
string dev::eth::jsUnpadded(string _s) std::string jsUnpadded(std::string _s)
{ {
auto p = _s.find_last_not_of((char)0); auto p = _s.find_last_not_of((char)0);
_s.resize(p == string::npos ? 0 : (p + 1)); _s.resize(p == std::string::npos ? 0 : (p + 1));
return _s; return _s;
} }
}

65
eth/CommonJS.h → libdevcore/CommonJS.h

@ -17,22 +17,34 @@
/** @file CommonJS.h /** @file CommonJS.h
* @authors: * @authors:
* Gav Wood <i@gavwood.com> * Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include <libdevcore/Common.h> #include <libethereum/Interface.h>
#include <libdevcore/CommonIO.h> #include "Common.h"
#include <libdevcore/CommonData.h> #include "CommonData.h"
#include <libdevcore/FixedHash.h>
#include <libethcore/CommonEth.h>
namespace dev namespace dev
{ {
namespace eth
template <unsigned S> std::string toJS(FixedHash<S> const& _h)
{
return "0x" + toHex(_h.ref());
}
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n)
{
return "0x" + toHex(toCompactBigEndian(_n));
}
inline std::string toJS(dev::bytes const& _n)
{ {
return "0x" + dev::toHex(_n);
}
bytes jsToBytes(std::string const& _s); bytes jsToBytes(std::string const& _s);
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r); std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r);
@ -52,6 +64,11 @@ template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
return FixedHash<N>(asBytes(jsPadded(_s, N))); return FixedHash<N>(asBytes(jsPadded(_s, N)));
} }
inline std::string jsToFixed(double _s)
{
return toJS(dev::u256(_s * (double)(dev::u256(1) << 128)));
}
template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> jsToInt(std::string const& _s) template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> jsToInt(std::string const& _s)
{ {
if (_s.substr(0, 2) == "0x") if (_s.substr(0, 2) == "0x")
@ -65,27 +82,45 @@ template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_i
return fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N))); return fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N)));
} }
inline Address jsToAddress(std::string const& _s) { return jsToFixed<20>(_s); } inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); }
inline Secret jsToSecret(std::string const& _s) { return jsToFixed<32>(_s); } inline Public jsToPublic(std::string const& _s) { return jsToFixed<sizeof(dev::Public)>(_s); }
inline Secret jsToSecret(std::string const& _s) { return jsToFixed<sizeof(dev::Secret)>(_s); }
inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); } inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); }
template <unsigned S> std::string toJS(FixedHash<S> const& _h) { return "0x" + toHex(_h.ref()); }
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n) { return "0x" + toHex(toCompactBigEndian(_n)); }
inline std::string jsToBinary(std::string const& _s) inline std::string jsToBinary(std::string const& _s)
{ {
return asString(jsToBytes(_s)); return jsUnpadded(dev::toString(jsToBytes(_s)));
} }
inline std::string jsToDecimal(std::string const& _s) inline std::string jsToDecimal(std::string const& _s)
{ {
return toString(jsToU256(_s)); return dev::toString(jsToU256(_s));
} }
inline std::string jsToHex(std::string const& _s) inline std::string jsFromBinary(dev::bytes _s, unsigned _padding = 32)
{ {
return "0x" + toHex(asBytes(_s)); _s.resize(std::max<unsigned>(_s.size(), _padding));
return "0x" + dev::toHex(_s);
} }
inline std::string jsFromBinary(std::string const& _s, unsigned _padding = 32)
{
return jsFromBinary(asBytes(_s), _padding);
} }
inline double jsFromFixed(std::string const& _s)
{
return (double)jsToU256(_s) / (double)(dev::u256(1) << 128);
}
struct TransactionSkeleton
{
Address from;
Address to;
u256 value;
bytes data;
u256 gas;
u256 gasPrice;
};
} }

1
libdevcore/_libdevcore.cpp

@ -3,6 +3,7 @@
#include "Common.cpp" #include "Common.cpp"
#include "CommonData.cpp" #include "CommonData.cpp"
#include "CommonIO.cpp" #include "CommonIO.cpp"
#include "CommonJS.h"
#include "FixedHash.cpp" #include "FixedHash.cpp"
#include "Guards.cpp" #include "Guards.cpp"
#include "Log.cpp" #include "Log.cpp"

48
libevm/VM.h

@ -84,7 +84,7 @@ private:
u256 m_curPC = 0; u256 m_curPC = 0;
bytes m_temp; bytes m_temp;
u256s m_stack; u256s m_stack;
std::set<unsigned> m_jumpDests; std::set<u256> m_jumpDests;
}; };
} }
@ -96,12 +96,26 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (m_jumpDests.empty()) if (m_jumpDests.empty())
{ {
m_jumpDests.insert(0); std::set<u256> implicit;
for (unsigned i = 1; i < _ext.code.size(); ++i) for (unsigned i = 0; i < _ext.code.size(); ++i)
if (_ext.code[i] == (byte)Instruction::JUMPDEST) if (_ext.code[i] == (byte)Instruction::JUMPDEST)
m_jumpDests.insert(i + 1); m_jumpDests.insert(i);
else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32)
i += _ext.code[i] - (int)Instruction::PUSH1 + 1; {
int in = _ext.code[i] - (unsigned)Instruction::PUSH1 + 1;
u256 p = 0;
for (; in--; i++)
p = (p << 8) | _ext.getCode(i);
if ((_ext.getCode(i) == (byte)Instruction::JUMP || _ext.getCode(i) == (byte)Instruction::JUMPI) && !(_ext.getCode(p) == (byte)Instruction::JUMP || _ext.getCode(p) == (byte)Instruction::JUMPI))
if (p >= _ext.code.size())
m_jumpDests.insert(p);
else
implicit.insert(p);
else {}
}
for (unsigned i = 0; i < _ext.code.size(); i += instructionInfo((Instruction)_ext.getCode(i)).additional + 1)
if (implicit.count(i))
m_jumpDests.insert(i);
} }
u256 nextPC = m_curPC + 1; u256 nextPC = m_curPC + 1;
@ -262,8 +276,8 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::PUSH31: case Instruction::PUSH31:
case Instruction::PUSH32: case Instruction::PUSH32:
break; break;
case Instruction::BNOT:
case Instruction::NOT: case Instruction::NOT:
case Instruction::ISZERO:
case Instruction::CALLDATALOAD: case Instruction::CALLDATALOAD:
case Instruction::EXTCODESIZE: case Instruction::EXTCODESIZE:
case Instruction::POP: case Instruction::POP:
@ -395,7 +409,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256);
break; break;
} }
case Instruction::BNOT: case Instruction::NOT:
m_stack.back() = ~m_stack.back(); m_stack.back() = ~m_stack.back();
break; break;
case Instruction::LT: case Instruction::LT:
@ -418,7 +432,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0; m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::NOT: case Instruction::ISZERO:
m_stack.back() = m_stack.back() ? 0 : 1; m_stack.back() = m_stack.back() ? 0 : 1;
break; break;
case Instruction::AND: case Instruction::AND:
@ -506,12 +520,12 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
{ {
unsigned mf = (unsigned)m_stack.back(); unsigned mf = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned cf = (unsigned)m_stack.back(); u256 cf = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned l = (unsigned)m_stack.back(); unsigned l = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned el = cf + l > _ext.data.size() ? _ext.data.size() < cf ? 0 : _ext.data.size() - cf : l; unsigned el = cf + l > (u256)_ext.data.size() ? (u256)_ext.data.size() < cf ? 0 : _ext.data.size() - (unsigned)cf : l;
memcpy(m_temp.data() + mf, _ext.data.data() + cf, el); memcpy(m_temp.data() + mf, _ext.data.data() + (unsigned)cf, el);
memset(m_temp.data() + mf + el, 0, l - el); memset(m_temp.data() + mf + el, 0, l - el);
break; break;
} }
@ -522,12 +536,12 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
{ {
unsigned mf = (unsigned)m_stack.back(); unsigned mf = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned cf = (unsigned)m_stack.back(); u256 cf = (u256)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned l = (unsigned)m_stack.back(); unsigned l = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned el = cf + l > _ext.code.size() ? _ext.code.size() < cf ? 0 : _ext.code.size() - cf : l; unsigned el = cf + l > (u256)_ext.code.size() ? (u256)_ext.code.size() < cf ? 0 : _ext.code.size() - (unsigned)cf : l;
memcpy(m_temp.data() + mf, _ext.code.data() + cf, el); memcpy(m_temp.data() + mf, _ext.code.data() + (unsigned)cf, el);
memset(m_temp.data() + mf + el, 0, l - el); memset(m_temp.data() + mf + el, 0, l - el);
break; break;
} }
@ -540,12 +554,12 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.pop_back(); m_stack.pop_back();
unsigned mf = (unsigned)m_stack.back(); unsigned mf = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned cf = (unsigned)m_stack.back(); u256 cf = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned l = (unsigned)m_stack.back(); unsigned l = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned el = cf + l > _ext.codeAt(a).size() ? _ext.codeAt(a).size() < cf ? 0 : _ext.codeAt(a).size() - cf : l; unsigned el = cf + l > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < cf ? 0 : _ext.codeAt(a).size() - (unsigned)cf : l;
memcpy(m_temp.data() + mf, _ext.codeAt(a).data() + cf, el); memcpy(m_temp.data() + mf, _ext.codeAt(a).data() + (unsigned)cf, el);
memset(m_temp.data() + mf + el, 0, l - el); memset(m_temp.data() + mf + el, 0, l - el);
break; break;
} }

8
libevmface/Instruction.cpp

@ -39,13 +39,13 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "MOD", Instruction::MOD }, { "MOD", Instruction::MOD },
{ "SMOD", Instruction::SMOD }, { "SMOD", Instruction::SMOD },
{ "EXP", Instruction::EXP }, { "EXP", Instruction::EXP },
{ "BNOT", Instruction::BNOT }, { "BNOT", Instruction::NOT },
{ "LT", Instruction::LT }, { "LT", Instruction::LT },
{ "GT", Instruction::GT }, { "GT", Instruction::GT },
{ "SLT", Instruction::SLT }, { "SLT", Instruction::SLT },
{ "SGT", Instruction::SGT }, { "SGT", Instruction::SGT },
{ "EQ", Instruction::EQ }, { "EQ", Instruction::EQ },
{ "NOT", Instruction::NOT }, { "NOT", Instruction::ISZERO },
{ "AND", Instruction::AND }, { "AND", Instruction::AND },
{ "OR", Instruction::OR }, { "OR", Instruction::OR },
{ "XOR", Instruction::XOR }, { "XOR", Instruction::XOR },
@ -172,13 +172,13 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::MOD, { "MOD", 0, 2, 1 } }, { Instruction::MOD, { "MOD", 0, 2, 1 } },
{ Instruction::SMOD, { "SMOD", 0, 2, 1 } }, { Instruction::SMOD, { "SMOD", 0, 2, 1 } },
{ Instruction::EXP, { "EXP", 0, 2, 1 } }, { Instruction::EXP, { "EXP", 0, 2, 1 } },
{ Instruction::BNOT, { "BNOT", 0, 1, 1 } }, { Instruction::NOT, { "BNOT", 0, 1, 1 } },
{ Instruction::LT, { "LT", 0, 2, 1 } }, { Instruction::LT, { "LT", 0, 2, 1 } },
{ Instruction::GT, { "GT", 0, 2, 1 } }, { Instruction::GT, { "GT", 0, 2, 1 } },
{ Instruction::SLT, { "SLT", 0, 2, 1 } }, { Instruction::SLT, { "SLT", 0, 2, 1 } },
{ Instruction::SGT, { "SGT", 0, 2, 1 } }, { Instruction::SGT, { "SGT", 0, 2, 1 } },
{ Instruction::EQ, { "EQ", 0, 2, 1 } }, { Instruction::EQ, { "EQ", 0, 2, 1 } },
{ Instruction::NOT, { "NOT", 0, 1, 1 } }, { Instruction::ISZERO, { "NOT", 0, 1, 1 } },
{ Instruction::AND, { "AND", 0, 2, 1 } }, { Instruction::AND, { "AND", 0, 2, 1 } },
{ Instruction::OR, { "OR", 0, 2, 1 } }, { Instruction::OR, { "OR", 0, 2, 1 } },
{ Instruction::XOR, { "XOR", 0, 2, 1 } }, { Instruction::XOR, { "XOR", 0, 2, 1 } },

19
libevmface/Instruction.h

@ -43,22 +43,23 @@ enum class Instruction: uint8_t
SDIV, ///< signed integer division operation SDIV, ///< signed integer division operation
MOD, ///< modulo remainder operation MOD, ///< modulo remainder operation
SMOD, ///< signed modulo remainder operation SMOD, ///< signed modulo remainder operation
ADDMOD, ///< unsigned modular addition
MULMOD, ///< unsigned modular multiplication
EXP, ///< exponential operation EXP, ///< exponential operation
BNOT, ///< bitwise not SIGNEXTEND, ///< extend length of signed integer
LT, ///< less-than comparision
LT = 0x10, ///< less-than comparision
GT, ///< greater-than comparision GT, ///< greater-than comparision
SLT, ///< signed less-than comparision SLT, ///< signed less-than comparision
SGT, ///< signed greater-than comparision SGT, ///< signed greater-than comparision
EQ, ///< equality comparision EQ, ///< equality comparision
NOT, ///< simple not operator ISZERO, ///< simple not operator
AND, ///< bitwise AND operation
AND = 0x10, ///< bitwise AND operation
OR, ///< bitwise OR operation OR, ///< bitwise OR operation
XOR, ///< bitwise XOR operation XOR, ///< bitwise XOR operation
NOT, ///< bitwise NOT opertation
BYTE, ///< retrieve single byte from word BYTE, ///< retrieve single byte from word
ADDMOD, ///< unsigned modular addition
MULMOD, ///< unsigned modular multiplication
SIGNEXTEND, ///< extend length of signed integer
SHA3 = 0x20, ///< compute SHA3-256 hash SHA3 = 0x20, ///< compute SHA3-256 hash
ADDRESS = 0x30, ///< get address of currently executing account ADDRESS = 0x30, ///< get address of currently executing account
@ -83,7 +84,7 @@ enum class Instruction: uint8_t
GASLIMIT, ///< get the block's gas limit GASLIMIT, ///< get the block's gas limit
POP = 0x50, ///< remove item from stack POP = 0x50, ///< remove item from stack
MLOAD = 0x53, ///< load word from memory MLOAD, ///< load word from memory
MSTORE, ///< save word to memory MSTORE, ///< save word to memory
MSTORE8, ///< save byte to memory MSTORE8, ///< save byte to memory
SLOAD, ///< load word from storage SLOAD, ///< load word from storage

24
libjsqrc/CMakeLists.txt

@ -0,0 +1,24 @@
cmake_policy(SET CMP0015 NEW)
# Find Qt5 for Apple and update src_list for windows
if (APPLE)
# homebrew defaults to qt4 and installs qt5 as 'keg-only'
# which places it into /usr/local/opt insteadof /usr/local.
set(CMAKE_PREFIX_PATH /usr/local/opt/qt5)
include_directories(/usr/local/opt/qt5/include /usr/local/include)
elseif ("${TARGET_PLATFORM}" STREQUAL "w64")
set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp)
elseif (UNIX)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake")
endif ()
find_package(Qt5Core)
set(CMAKE_AUTOMOC OFF)
qt5_add_resources(JSQRC js.qrc)
add_library(jsqrc STATIC ${JSQRC})
qt5_use_modules(jsqrc Core)
install( TARGETS jsqrc ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )

966
libjsqrc/es6-promise-2.0.0.js

@ -0,0 +1,966 @@
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
* @version 2.0.0
*/
(function() {
"use strict";
function $$utils$$objectOrFunction(x) {
return typeof x === 'function' || (typeof x === 'object' && x !== null);
}
function $$utils$$isFunction(x) {
return typeof x === 'function';
}
function $$utils$$isMaybeThenable(x) {
return typeof x === 'object' && x !== null;
}
var $$utils$$_isArray;
if (!Array.isArray) {
$$utils$$_isArray = function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
};
} else {
$$utils$$_isArray = Array.isArray;
}
var $$utils$$isArray = $$utils$$_isArray;
var $$utils$$now = Date.now || function() { return new Date().getTime(); };
function $$utils$$F() { }
var $$utils$$o_create = (Object.create || function (o) {
if (arguments.length > 1) {
throw new Error('Second argument not supported');
}
if (typeof o !== 'object') {
throw new TypeError('Argument must be an object');
}
$$utils$$F.prototype = o;
return new $$utils$$F();
});
var $$asap$$len = 0;
var $$asap$$default = function asap(callback, arg) {
$$asap$$queue[$$asap$$len] = callback;
$$asap$$queue[$$asap$$len + 1] = arg;
$$asap$$len += 2;
if ($$asap$$len === 2) {
// If len is 1, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
$$asap$$scheduleFlush();
}
};
var $$asap$$browserGlobal = (typeof window !== 'undefined') ? window : {};
var $$asap$$BrowserMutationObserver = $$asap$$browserGlobal.MutationObserver || $$asap$$browserGlobal.WebKitMutationObserver;
// test for web worker but not in IE10
var $$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
typeof importScripts !== 'undefined' &&
typeof MessageChannel !== 'undefined';
// node
function $$asap$$useNextTick() {
return function() {
process.nextTick($$asap$$flush);
};
}
function $$asap$$useMutationObserver() {
var iterations = 0;
var observer = new $$asap$$BrowserMutationObserver($$asap$$flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function() {
node.data = (iterations = ++iterations % 2);
};
}
// web worker
function $$asap$$useMessageChannel() {
var channel = new MessageChannel();
channel.port1.onmessage = $$asap$$flush;
return function () {
channel.port2.postMessage(0);
};
}
function $$asap$$useSetTimeout() {
return function() {
setTimeout($$asap$$flush, 1);
};
}
var $$asap$$queue = new Array(1000);
function $$asap$$flush() {
for (var i = 0; i < $$asap$$len; i+=2) {
var callback = $$asap$$queue[i];
var arg = $$asap$$queue[i+1];
callback(arg);
$$asap$$queue[i] = undefined;
$$asap$$queue[i+1] = undefined;
}
$$asap$$len = 0;
}
var $$asap$$scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
$$asap$$scheduleFlush = $$asap$$useNextTick();
} else if ($$asap$$BrowserMutationObserver) {
$$asap$$scheduleFlush = $$asap$$useMutationObserver();
} else if ($$asap$$isWorker) {
$$asap$$scheduleFlush = $$asap$$useMessageChannel();
} else {
$$asap$$scheduleFlush = $$asap$$useSetTimeout();
}
function $$$internal$$noop() {}
var $$$internal$$PENDING = void 0;
var $$$internal$$FULFILLED = 1;
var $$$internal$$REJECTED = 2;
var $$$internal$$GET_THEN_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$selfFullfillment() {
return new TypeError("You cannot resolve a promise with itself");
}
function $$$internal$$cannotReturnOwn() {
return new TypeError('A promises callback cannot return that same promise.')
}
function $$$internal$$getThen(promise) {
try {
return promise.then;
} catch(error) {
$$$internal$$GET_THEN_ERROR.error = error;
return $$$internal$$GET_THEN_ERROR;
}
}
function $$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
try {
then.call(value, fulfillmentHandler, rejectionHandler);
} catch(e) {
return e;
}
}
function $$$internal$$handleForeignThenable(promise, thenable, then) {
$$asap$$default(function(promise) {
var sealed = false;
var error = $$$internal$$tryThen(then, thenable, function(value) {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
$$$internal$$resolve(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}, function(reason) {
if (sealed) { return; }
sealed = true;
$$$internal$$reject(promise, reason);
}, 'Settle: ' + (promise._label || ' unknown promise'));
if (!sealed && error) {
sealed = true;
$$$internal$$reject(promise, error);
}
}, promise);
}
function $$$internal$$handleOwnThenable(promise, thenable) {
if (thenable._state === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, thenable._result);
} else if (promise._state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, thenable._result);
} else {
$$$internal$$subscribe(thenable, undefined, function(value) {
$$$internal$$resolve(promise, value);
}, function(reason) {
$$$internal$$reject(promise, reason);
});
}
}
function $$$internal$$handleMaybeThenable(promise, maybeThenable) {
if (maybeThenable.constructor === promise.constructor) {
$$$internal$$handleOwnThenable(promise, maybeThenable);
} else {
var then = $$$internal$$getThen(maybeThenable);
if (then === $$$internal$$GET_THEN_ERROR) {
$$$internal$$reject(promise, $$$internal$$GET_THEN_ERROR.error);
} else if (then === undefined) {
$$$internal$$fulfill(promise, maybeThenable);
} else if ($$utils$$isFunction(then)) {
$$$internal$$handleForeignThenable(promise, maybeThenable, then);
} else {
$$$internal$$fulfill(promise, maybeThenable);
}
}
}
function $$$internal$$resolve(promise, value) {
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$selfFullfillment());
} else if ($$utils$$objectOrFunction(value)) {
$$$internal$$handleMaybeThenable(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}
function $$$internal$$publishRejection(promise) {
if (promise._onerror) {
promise._onerror(promise._result);
}
$$$internal$$publish(promise);
}
function $$$internal$$fulfill(promise, value) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._result = value;
promise._state = $$$internal$$FULFILLED;
if (promise._subscribers.length === 0) {
} else {
$$asap$$default($$$internal$$publish, promise);
}
}
function $$$internal$$reject(promise, reason) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._state = $$$internal$$REJECTED;
promise._result = reason;
$$asap$$default($$$internal$$publishRejection, promise);
}
function $$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers;
var length = subscribers.length;
parent._onerror = null;
subscribers[length] = child;
subscribers[length + $$$internal$$FULFILLED] = onFulfillment;
subscribers[length + $$$internal$$REJECTED] = onRejection;
if (length === 0 && parent._state) {
$$asap$$default($$$internal$$publish, parent);
}
}
function $$$internal$$publish(promise) {
var subscribers = promise._subscribers;
var settled = promise._state;
if (subscribers.length === 0) { return; }
var child, callback, detail = promise._result;
for (var i = 0; i < subscribers.length; i += 3) {
child = subscribers[i];
callback = subscribers[i + settled];
if (child) {
$$$internal$$invokeCallback(settled, child, callback, detail);
} else {
callback(detail);
}
}
promise._subscribers.length = 0;
}
function $$$internal$$ErrorObject() {
this.error = null;
}
var $$$internal$$TRY_CATCH_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$tryCatch(callback, detail) {
try {
return callback(detail);
} catch(e) {
$$$internal$$TRY_CATCH_ERROR.error = e;
return $$$internal$$TRY_CATCH_ERROR;
}
}
function $$$internal$$invokeCallback(settled, promise, callback, detail) {
var hasCallback = $$utils$$isFunction(callback),
value, error, succeeded, failed;
if (hasCallback) {
value = $$$internal$$tryCatch(callback, detail);
if (value === $$$internal$$TRY_CATCH_ERROR) {
failed = true;
error = value.error;
value = null;
} else {
succeeded = true;
}
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$cannotReturnOwn());
return;
}
} else {
value = detail;
succeeded = true;
}
if (promise._state !== $$$internal$$PENDING) {
// noop
} else if (hasCallback && succeeded) {
$$$internal$$resolve(promise, value);
} else if (failed) {
$$$internal$$reject(promise, error);
} else if (settled === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, value);
} else if (settled === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
}
}
function $$$internal$$initializePromise(promise, resolver) {
try {
resolver(function resolvePromise(value){
$$$internal$$resolve(promise, value);
}, function rejectPromise(reason) {
$$$internal$$reject(promise, reason);
});
} catch(e) {
$$$internal$$reject(promise, e);
}
}
function $$$enumerator$$makeSettledResult(state, position, value) {
if (state === $$$internal$$FULFILLED) {
return {
state: 'fulfilled',
value: value
};
} else {
return {
state: 'rejected',
reason: value
};
}
}
function $$$enumerator$$Enumerator(Constructor, input, abortOnReject, label) {
this._instanceConstructor = Constructor;
this.promise = new Constructor($$$internal$$noop, label);
this._abortOnReject = abortOnReject;
if (this._validateInput(input)) {
this._input = input;
this.length = input.length;
this._remaining = input.length;
this._init();
if (this.length === 0) {
$$$internal$$fulfill(this.promise, this._result);
} else {
this.length = this.length || 0;
this._enumerate();
if (this._remaining === 0) {
$$$internal$$fulfill(this.promise, this._result);
}
}
} else {
$$$internal$$reject(this.promise, this._validationError());
}
}
$$$enumerator$$Enumerator.prototype._validateInput = function(input) {
return $$utils$$isArray(input);
};
$$$enumerator$$Enumerator.prototype._validationError = function() {
return new Error('Array Methods must be provided an Array');
};
$$$enumerator$$Enumerator.prototype._init = function() {
this._result = new Array(this.length);
};
var $$$enumerator$$default = $$$enumerator$$Enumerator;
$$$enumerator$$Enumerator.prototype._enumerate = function() {
var length = this.length;
var promise = this.promise;
var input = this._input;
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
this._eachEntry(input[i], i);
}
};
$$$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
var c = this._instanceConstructor;
if ($$utils$$isMaybeThenable(entry)) {
if (entry.constructor === c && entry._state !== $$$internal$$PENDING) {
entry._onerror = null;
this._settledAt(entry._state, i, entry._result);
} else {
this._willSettleAt(c.resolve(entry), i);
}
} else {
this._remaining--;
this._result[i] = this._makeResult($$$internal$$FULFILLED, i, entry);
}
};
$$$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
var promise = this.promise;
if (promise._state === $$$internal$$PENDING) {
this._remaining--;
if (this._abortOnReject && state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
} else {
this._result[i] = this._makeResult(state, i, value);
}
}
if (this._remaining === 0) {
$$$internal$$fulfill(promise, this._result);
}
};
$$$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) {
return value;
};
$$$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
var enumerator = this;
$$$internal$$subscribe(promise, undefined, function(value) {
enumerator._settledAt($$$internal$$FULFILLED, i, value);
}, function(reason) {
enumerator._settledAt($$$internal$$REJECTED, i, reason);
});
};
var $$promise$all$$default = function all(entries, label) {
return new $$$enumerator$$default(this, entries, true /* abort on reject */, label).promise;
};
var $$promise$race$$default = function race(entries, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
if (!$$utils$$isArray(entries)) {
$$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
return promise;
}
var length = entries.length;
function onFulfillment(value) {
$$$internal$$resolve(promise, value);
}
function onRejection(reason) {
$$$internal$$reject(promise, reason);
}
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
$$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
}
return promise;
};
var $$promise$resolve$$default = function resolve(object, label) {
/*jshint validthis:true */
var Constructor = this;
if (object && typeof object === 'object' && object.constructor === Constructor) {
return object;
}
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$resolve(promise, object);
return promise;
};
var $$promise$reject$$default = function reject(reason, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$reject(promise, reason);
return promise;
};
var $$es6$promise$promise$$counter = 0;
function $$es6$promise$promise$$needsResolver() {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}
function $$es6$promise$promise$$needsNew() {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}
var $$es6$promise$promise$$default = $$es6$promise$promise$$Promise;
/**
Promise objects represent the eventual result of an asynchronous operation. The
primary way of interacting with a promise is through its `then` method, which
registers callbacks to receive either a promises eventual value or the reason
why the promise cannot be fulfilled.
Terminology
-----------
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
- `thenable` is an object or function that defines a `then` method.
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
- `exception` is a value that is thrown using the throw statement.
- `reason` is a value that indicates why a promise was rejected.
- `settled` the final resting state of a promise, fulfilled or rejected.
A promise can be in one of three states: pending, fulfilled, or rejected.
Promises that are fulfilled have a fulfillment value and are in the fulfilled
state. Promises that are rejected have a rejection reason and are in the
rejected state. A fulfillment value is never a thenable.
Promises can also be said to *resolve* a value. If this value is also a
promise, then the original promise's settled state will match the value's
settled state. So a promise that *resolves* a promise that rejects will
itself reject, and a promise that *resolves* a promise that fulfills will
itself fulfill.
Basic Usage:
------------
```js
var promise = new Promise(function(resolve, reject) {
// on success
resolve(value);
// on failure
reject(reason);
});
promise.then(function(value) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Advanced Usage:
---------------
Promises shine when abstracting away asynchronous interactions such as
`XMLHttpRequest`s.
```js
function getJSON(url) {
return new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
}
}
};
});
}
getJSON('/posts.json').then(function(json) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Unlike callbacks, promises are great composable primitives.
```js
Promise.all([
getJSON('/posts'),
getJSON('/comments')
]).then(function(values){
values[0] // => postsJSON
values[1] // => commentsJSON
return values;
});
```
@class Promise
@param {function} resolver
@param {String} label optional string for labeling the promise.
Useful for tooling.
@constructor
*/
function $$es6$promise$promise$$Promise(resolver, label) {
this._id = $$es6$promise$promise$$counter++;
this._label = label;
this._state = undefined;
this._result = undefined;
this._subscribers = [];
if ($$$internal$$noop !== resolver) {
if (!$$utils$$isFunction(resolver)) {
$$es6$promise$promise$$needsResolver();
}
if (!(this instanceof $$es6$promise$promise$$Promise)) {
$$es6$promise$promise$$needsNew();
}
$$$internal$$initializePromise(this, resolver);
}
}
$$es6$promise$promise$$Promise.all = $$promise$all$$default;
$$es6$promise$promise$$Promise.race = $$promise$race$$default;
$$es6$promise$promise$$Promise.resolve = $$promise$resolve$$default;
$$es6$promise$promise$$Promise.reject = $$promise$reject$$default;
$$es6$promise$promise$$Promise.prototype = {
constructor: $$es6$promise$promise$$Promise,
/**
The primary way of interacting with a promise is through its `then` method,
which registers callbacks to receive either a promise's eventual value or the
reason why the promise cannot be fulfilled.
```js
findUser().then(function(user){
// user is available
}, function(reason){
// user is unavailable, and you are given the reason why
});
```
Chaining
--------
The return value of `then` is itself a promise. This second, 'downstream'
promise is resolved with the return value of the first promise's fulfillment
or rejection handler, or rejected if the handler throws an exception.
```js
findUser().then(function (user) {
return user.name;
}, function (reason) {
return 'default name';
}).then(function (userName) {
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
// will be `'default name'`
});
findUser().then(function (user) {
throw new Error('Found user, but still unhappy');
}, function (reason) {
throw new Error('`findUser` rejected and we're unhappy');
}).then(function (value) {
// never reached
}, function (reason) {
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
});
```
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
```js
findUser().then(function (user) {
throw new PedagogicalException('Upstream error');
}).then(function (value) {
// never reached
}).then(function (value) {
// never reached
}, function (reason) {
// The `PedgagocialException` is propagated all the way down to here
});
```
Assimilation
------------
Sometimes the value you want to propagate to a downstream promise can only be
retrieved asynchronously. This can be achieved by returning a promise in the
fulfillment or rejection handler. The downstream promise will then be pending
until the returned promise is settled. This is called *assimilation*.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// The user's comments are now available
});
```
If the assimliated promise rejects, then the downstream promise will also reject.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// If `findCommentsByAuthor` fulfills, we'll have the value here
}, function (reason) {
// If `findCommentsByAuthor` rejects, we'll have the reason here
});
```
Simple Example
--------------
Synchronous Example
```javascript
var result;
try {
result = findResult();
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
findResult(function(result, err){
if (err) {
// failure
} else {
// success
}
});
```
Promise Example;
```javascript
findResult().then(function(result){
// success
}, function(reason){
// failure
});
```
Advanced Example
--------------
Synchronous Example
```javascript
var author, books;
try {
author = findAuthor();
books = findBooksByAuthor(author);
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
function foundBooks(books) {
}
function failure(reason) {
}
findAuthor(function(author, err){
if (err) {
failure(err);
// failure
} else {
try {
findBoooksByAuthor(author, function(books, err) {
if (err) {
failure(err);
} else {
try {
foundBooks(books);
} catch(reason) {
failure(reason);
}
}
});
} catch(error) {
failure(err);
}
// success
}
});
```
Promise Example;
```javascript
findAuthor().
then(findBooksByAuthor).
then(function(books){
// found books
}).catch(function(reason){
// something went wrong
});
```
@method then
@param {Function} onFulfilled
@param {Function} onRejected
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
then: function(onFulfillment, onRejection, label) {
var parent = this;
var state = parent._state;
if (state === $$$internal$$FULFILLED && !onFulfillment || state === $$$internal$$REJECTED && !onRejection) {
return this;
}
parent._onerror = null;
var child = new this.constructor($$$internal$$noop, label);
var result = parent._result;
if (state) {
var callback = arguments[state - 1];
$$asap$$default(function(){
$$$internal$$invokeCallback(state, child, callback, result);
});
} else {
$$$internal$$subscribe(parent, child, onFulfillment, onRejection);
}
return child;
},
/**
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
as the catch block of a try/catch statement.
```js
function findAuthor(){
throw new Error('couldn't find that author');
}
// synchronous
try {
findAuthor();
} catch(reason) {
// something went wrong
}
// async with promises
findAuthor().catch(function(reason){
// something went wrong
});
```
@method catch
@param {Function} onRejection
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
'catch': function(onRejection, label) {
return this.then(null, onRejection, label);
}
};
var $$es6$promise$polyfill$$default = function polyfill() {
var local;
if (typeof global !== 'undefined') {
local = global;
} else if (typeof window !== 'undefined' && window.document) {
local = window;
} else {
local = self;
}
var es6PromiseSupport =
"Promise" in local &&
// Some of these methods are missing from
// Firefox/Chrome experimental implementations
"resolve" in local.Promise &&
"reject" in local.Promise &&
"all" in local.Promise &&
"race" in local.Promise &&
// Older version of the spec had a resolver object
// as the arg rather than a function
(function() {
var resolve;
new local.Promise(function(r) { resolve = r; });
return $$utils$$isFunction(resolve);
}());
if (!es6PromiseSupport) {
local.Promise = $$es6$promise$promise$$default;
}
};
var es6$promise$umd$$ES6Promise = {
Promise: $$es6$promise$promise$$default,
polyfill: $$es6$promise$polyfill$$default
};
/* global define:true module:true window: true */
if (typeof define === 'function' && define['amd']) {
define(function() { return es6$promise$umd$$ES6Promise; });
} else if (typeof module !== 'undefined' && module['exports']) {
module['exports'] = es6$promise$umd$$ES6Promise;
} else if (typeof this !== 'undefined') {
this['ES6Promise'] = es6$promise$umd$$ES6Promise;
}
}).call(this);

8
libjsqrc/js.qrc

@ -0,0 +1,8 @@
<RCC version="1.0">
<qresource prefix="/js">
<file>es6-promise-2.0.0.js</file>
<file>setup.js</file>
<file>main.js</file>
<file>qt.js</file>
</qresource>
</RCC>

458
libjsqrc/main.js

@ -0,0 +1,458 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethereum.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
(function(window) {
function isPromise(o) {
return o instanceof Promise
}
function flattenPromise (obj) {
if (obj instanceof Promise) {
return Promise.resolve(obj);
}
if (obj instanceof Array) {
return new Promise(function (resolve) {
var promises = obj.map(function (o) {
return flattenPromise(o);
});
return Promise.all(promises).then(function (res) {
for (var i = 0; i < obj.length; i++) {
obj[i] = res[i];
}
resolve(obj);
});
});
}
if (obj instanceof Object) {
return new Promise(function (resolve) {
var keys = Object.keys(obj);
var promises = keys.map(function (key) {
return flattenPromise(obj[key]);
});
return Promise.all(promises).then(function (res) {
for (var i = 0; i < keys.length; i++) {
obj[keys[i]] = res[i];
}
resolve(obj);
});
});
}
return Promise.resolve(obj);
};
var ethMethods = function () {
var blockCall = function (args) {
return typeof args[0] === "string" ? "blockByHash" : "blockByNumber";
};
var transactionCall = function (args) {
return typeof args[0] === "string" ? 'transactionByHash' : 'transactionByNumber';
};
var uncleCall = function (args) {
return typeof args[0] === "string" ? 'uncleByHash' : 'uncleByNumber';
};
var methods = [
{ name: 'balanceAt', call: 'balanceAt' },
{ name: 'stateAt', call: 'stateAt' },
{ name: 'countAt', call: 'countAt'},
{ name: 'codeAt', call: 'codeAt' },
{ name: 'transact', call: 'transact' },
{ name: 'call', call: 'call' },
{ name: 'block', call: blockCall },
{ name: 'transaction', call: transactionCall },
{ name: 'uncle', call: uncleCall },
{ name: 'compile', call: 'compile' }
];
return methods;
};
var ethProperties = function () {
return [
{ name: 'coinbase', getter: 'coinbase', setter: 'setCoinbase' },
{ name: 'listening', getter: 'listening', setter: 'setListening' },
{ name: 'mining', getter: 'mining', setter: 'setMining' },
{ name: 'gasPrice', getter: 'gasPrice' },
{ name: 'account', getter: 'account' },
{ name: 'accounts', getter: 'accounts' },
{ name: 'peerCount', getter: 'peerCount' },
{ name: 'defaultBlock', getter: 'defaultBlock', setter: 'setDefaultBlock' },
{ name: 'number', getter: 'number'}
];
};
var dbMethods = function () {
return [
{ name: 'put', call: 'put' },
{ name: 'get', call: 'get' },
{ name: 'putString', call: 'putString' },
{ name: 'getString', call: 'getString' }
];
};
var shhMethods = function () {
return [
{ name: 'post', call: 'post' },
{ name: 'newIdentity', call: 'newIdentity' },
{ name: 'haveIdentity', call: 'haveIdentity' },
{ name: 'newGroup', call: 'newGroup' },
{ name: 'addToGroup', call: 'addToGroup' }
];
};
var ethWatchMethods = function () {
var newFilter = function (args) {
return typeof args[0] === 'string' ? 'newFilterString' : 'newFilter';
};
return [
{ name: 'newFilter', call: newFilter },
{ name: 'uninstallFilter', call: 'uninstallFilter' },
{ name: 'getMessages', call: 'getMessages' }
];
};
var shhWatchMethods = function () {
return [
{ name: 'newFilter', call: 'shhNewFilter' },
{ name: 'uninstallFilter', call: 'shhUninstallFilter' },
{ name: 'getMessage', call: 'shhGetMessages' }
];
};
var setupMethods = function (obj, methods) {
methods.forEach(function (method) {
obj[method.name] = function () {
return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {
var call = typeof method.call === "function" ? method.call(args) : method.call;
return {call: call, args: args};
}).then(function (request) {
return new Promise(function (resolve, reject) {
web3.provider.send(request, function (result) {
if (result || typeof result === "boolean") {
resolve(result);
return;
}
reject(result);
});
});
}).catch(function( err) {
console.error(err);
});
};
});
};
var setupProperties = function (obj, properties) {
properties.forEach(function (property) {
var proto = {};
proto.get = function () {
return new Promise(function(resolve, reject) {
web3.provider.send({call: property.getter}, function(result) {
resolve(result);
});
});
};
if (property.setter) {
proto.set = function (val) {
return flattenPromise([val]).then(function (args) {
return new Promise(function (resolve) {
web3.provider.send({call: property.setter, args: args}, function (result) {
if (result) {
resolve(result);
} else {
reject(result);
}
});
});
}).catch(function (err) {
console.error(err);
});
}
}
Object.defineProperty(obj, property.name, proto);
});
};
var web3 = {
_callbacks: {},
_events: {},
providers: {},
toHex: function(str) {
var hex = "";
for(var i = 0; i < str.length; i++) {
var n = str.charCodeAt(i).toString(16);
hex += n.length < 2 ? '0' + n : n;
}
return hex;
},
toAscii: function(hex) {
// Find termination
var str = "";
var i = 0, l = hex.length;
for(; i < l; i+=2) {
var code = hex.charCodeAt(i)
if(code == 0) {
break;
}
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return str;
},
toDecimal: function (val) {
return parseInt(val, 16);
},
fromAscii: function(str, pad) {
pad = pad === undefined ? 32 : pad;
var hex = this.toHex(str);
while(hex.length < pad*2)
hex += "00";
return hex
},
eth: {
prototype: Object(),
watch: function (params) {
return new Filter(params, ethWatch);
},
},
db: {
prototype: Object()
},
shh: {
prototype: Object(),
watch: function (params) {
return new Filter(params, shhWatch);
}
},
on: function(event, id, cb) {
if(web3._events[event] === undefined) {
web3._events[event] = {};
}
web3._events[event][id] = cb;
return this
},
off: function(event, id) {
if(web3._events[event] !== undefined) {
delete web3._events[event][id];
}
return this
},
trigger: function(event, id, data) {
var callbacks = web3._events[event];
if (!callbacks || !callbacks[id]) {
return;
}
var cb = callbacks[id];
cb(data);
},
};
var eth = web3.eth;
setupMethods(eth, ethMethods());
setupProperties(eth, ethProperties());
setupMethods(web3.db, dbMethods());
setupMethods(web3.shh, shhMethods());
var ethWatch = {
changed: 'changed'
};
setupMethods(ethWatch, ethWatchMethods());
var shhWatch = {
changed: 'shhChanged'
};
setupMethods(shhWatch, shhWatchMethods());
var ProviderManager = function() {
this.queued = [];
this.polls = [];
this.ready = false;
this.provider = undefined;
this.id = 1;
var self = this;
var poll = function () {
if (self.provider && self.provider.poll) {
self.polls.forEach(function (data) {
data.data._id = self.id;
self.id++;
self.provider.poll(data.data, data.id);
});
}
setTimeout(poll, 12000);
};
poll();
};
ProviderManager.prototype.send = function(data, cb) {
data._id = this.id;
if (cb) {
web3._callbacks[data._id] = cb;
}
data.args = data.args || [];
this.id++;
if(this.provider !== undefined) {
this.provider.send(data);
} else {
console.warn("provider is not set");
this.queued.push(data);
}
};
ProviderManager.prototype.set = function(provider) {
if(this.provider !== undefined && this.provider.unload !== undefined) {
this.provider.unload();
}
this.provider = provider;
this.ready = true;
};
ProviderManager.prototype.sendQueued = function() {
for(var i = 0; this.queued.length; i++) {
// Resend
this.send(this.queued[i]);
}
};
ProviderManager.prototype.installed = function() {
return this.provider !== undefined;
};
ProviderManager.prototype.startPolling = function (data, pollId) {
if (!this.provider || !this.provider.poll) {
return;
}
this.polls.push({data: data, id: pollId});
};
ProviderManager.prototype.stopPolling = function (pollId) {
for (var i = this.polls.length; i--;) {
var poll = this.polls[i];
if (poll.id === pollId) {
this.polls.splice(i, 1);
}
}
};
web3.provider = new ProviderManager();
web3.setProvider = function(provider) {
provider.onmessage = messageHandler;
web3.provider.set(provider);
web3.provider.sendQueued();
};
var Filter = function(options, impl) {
this.impl = impl;
this.callbacks = [];
var self = this;
this.promise = impl.newFilter(options);
this.promise.then(function (id) {
self.id = id;
web3.on(impl.changed, id, self.trigger.bind(self));
web3.provider.startPolling({call: impl.changed, args: [id]}, id);
});
};
Filter.prototype.arrived = function(callback) {
this.changed(callback);
}
Filter.prototype.changed = function(callback) {
var self = this;
this.promise.then(function(id) {
self.callbacks.push(callback);
});
};
Filter.prototype.trigger = function(messages) {
for(var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].call(this, messages);
}
};
Filter.prototype.uninstall = function() {
var self = this;
this.promise.then(function (id) {
self.impl.uninstallFilter(id);
web3.provider.stopPolling(id);
web3.off(impl.changed, id);
});
};
Filter.prototype.messages = function() {
var self = this;
return this.promise.then(function (id) {
return self.impl.getMessages(id);
});
};
function messageHandler(data) {
if(data._event !== undefined) {
web3.trigger(data._event, data._id, data.data);
return;
}
if(data._id) {
var cb = web3._callbacks[data._id];
if (cb) {
cb.call(this, data.data)
delete web3._callbacks[data._id];
}
}
}
/*
// Install default provider
if(!web3.provider.installed()) {
var sock = new web3.WebSocket("ws://localhost:40404/eth");
web3.setProvider(sock);
}
*/
window.web3 = web3;
})(this);

49
libjsqrc/qt.js

@ -0,0 +1,49 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethereum.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
(function() {
var QtProvider = function() {
this.handlers = [];
var self = this;
navigator.qt.onmessage = function (message) {
self.handlers.forEach(function (handler) {
handler.call(self, JSON.parse(message.data));
});
}
};
QtProvider.prototype.send = function(payload) {
navigator.qt.postMessage(JSON.stringify(payload));
};
Object.defineProperty(QtProvider.prototype, "onmessage", {
set: function(handler) {
this.handlers.push(handler);
},
});
if(typeof(web3) !== "undefined" && web3.providers !== undefined) {
web3.providers.QtProvider = QtProvider;
}
})();

44
libjsqrc/setup.js

@ -0,0 +1,44 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file QEthereum.cpp
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
navigator.qt = _web3;
(function () {
navigator.qt.handlers = [];
Object.defineProperty(navigator.qt, 'onmessage', {
set: function (handler) {
navigator.qt.handlers.push(handler);
}
});
})();
navigator.qt.response.connect(function (res) {
navigator.qt.handlers.forEach(function (handler) {
handler({data: res});
});
});
if (window.Promise === undefined) {
window.Promise = ES6Promise.Promise;
}
web3.setProvider(new web3.providers.QtProvider());

4
liblll/Assembly.cpp

@ -251,7 +251,7 @@ Assembly& Assembly::optimise(bool _enable)
{ { PushSub, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushSub, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { PushSubSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushSubSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } }, { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } },
{ { Instruction::NOT, Instruction::NOT }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { Instruction::ISZERO, Instruction::ISZERO }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
}; };
for (auto const& i: c_simple) for (auto const& i: c_simple)
@ -413,8 +413,8 @@ bytes Assembly::assemble() const
break; break;
} }
case Tag: case Tag:
ret.push_back((byte)Instruction::JUMPDEST);
tagPos[(unsigned)i.m_data] = ret.size(); tagPos[(unsigned)i.m_data] = ret.size();
ret.push_back((byte)Instruction::JUMPDEST);
break; break;
default:; default:;
} }

14
liblll/CodeFragment.cpp

@ -328,7 +328,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
std::map<std::string, Instruction> const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD }, { "&", Instruction::AND }, { "|", Instruction::OR }, { "^", Instruction::XOR } }; std::map<std::string, Instruction> const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD }, { "&", Instruction::AND }, { "|", Instruction::OR }, { "^", Instruction::XOR } };
std::map<std::string, pair<Instruction, bool>> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "S<", { Instruction::SLT, false } }, { "S<=", { Instruction::SGT, true } }, { "S>", { Instruction::SGT, false } }, { "S>=", { Instruction::SLT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } }; std::map<std::string, pair<Instruction, bool>> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "S<", { Instruction::SLT, false } }, { "S<=", { Instruction::SGT, true } }, { "S>", { Instruction::SGT, false } }, { "S>=", { Instruction::SLT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } };
std::map<std::string, Instruction> const c_unary = { { "!", Instruction::NOT } }; std::map<std::string, Instruction> const c_unary = { { "!", Instruction::ISZERO } };
vector<CodeFragment> code; vector<CodeFragment> code;
CompilerState ns = _s; CompilerState ns = _s;
@ -403,7 +403,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm.append(code[0].m_asm, 1); m_asm.append(code[0].m_asm, 1);
m_asm.append(it->second.first); m_asm.append(it->second.first);
if (it->second.second) if (it->second.second)
m_asm.append(Instruction::NOT); m_asm.append(Instruction::ISZERO);
} }
else if (c_unary.count(us)) else if (c_unary.count(us))
{ {
@ -437,7 +437,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm.append(code[0].m_asm); m_asm.append(code[0].m_asm);
if (us == "WHEN") if (us == "WHEN")
m_asm.append(Instruction::NOT); m_asm.append(Instruction::ISZERO);
auto end = m_asm.appendJumpI(); auto end = m_asm.appendJumpI();
m_asm.onePath(); m_asm.onePath();
m_asm.otherPath(); m_asm.otherPath();
@ -452,7 +452,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
auto begin = m_asm.append(); auto begin = m_asm.append();
m_asm.append(code[0].m_asm); m_asm.append(code[0].m_asm);
m_asm.append(Instruction::NOT); m_asm.append(Instruction::ISZERO);
auto end = m_asm.appendJumpI(); auto end = m_asm.appendJumpI();
m_asm.append(code[1].m_asm, 0); m_asm.append(code[1].m_asm, 0);
m_asm.appendJump(begin); m_asm.appendJump(begin);
@ -466,7 +466,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm.append(code[0].m_asm, 0); m_asm.append(code[0].m_asm, 0);
auto begin = m_asm.append(); auto begin = m_asm.append();
m_asm.append(code[1].m_asm); m_asm.append(code[1].m_asm);
m_asm.append(Instruction::NOT); m_asm.append(Instruction::ISZERO);
auto end = m_asm.appendJumpI(); auto end = m_asm.appendJumpI();
m_asm.append(code[3].m_asm, 0); m_asm.append(code[3].m_asm, 0);
m_asm.append(code[2].m_asm, 0); m_asm.append(code[2].m_asm, 0);
@ -502,7 +502,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
requireDeposit(2, 1); requireDeposit(2, 1);
m_asm.append(code[2].m_asm, 1); m_asm.append(code[2].m_asm, 1);
m_asm.append(Instruction::LT); m_asm.append(Instruction::LT);
m_asm.append(Instruction::NOT); m_asm.append(Instruction::ISZERO);
m_asm.append(Instruction::MUL); m_asm.append(Instruction::MUL);
m_asm.append(Instruction::DUP1); m_asm.append(Instruction::DUP1);
} }
@ -525,7 +525,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
// Check if true - predicate // Check if true - predicate
m_asm.append(code[i - 1].m_asm, 1); m_asm.append(code[i - 1].m_asm, 1);
if (us == "&&") if (us == "&&")
m_asm.append(Instruction::NOT); m_asm.append(Instruction::ISZERO);
m_asm.appendJumpI(end); m_asm.appendJumpI(end);
} }
m_asm.append(Instruction::POP); m_asm.append(Instruction::POP);

3
libqethereum/CMakeLists.txt

@ -50,7 +50,6 @@ if (APPLE)
set(MACOSX_BUNDLE_BUNDLE_NAME ${EXECUTABLE}) set(MACOSX_BUNDLE_BUNDLE_NAME ${EXECUTABLE})
include(BundleUtilities) include(BundleUtilities)
endif () endif ()
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) if(ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS}) add_library(${EXECUTABLE} STATIC ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS})
@ -60,7 +59,7 @@ endif()
include_directories(/) include_directories(/)
qt5_use_modules(${EXECUTABLE} Core Gui WebKit WebKitWidgets Widgets Network Quick Qml) qt5_use_modules(${EXECUTABLE} Core Gui WebKit WebKitWidgets Widgets Network Quick Qml)
target_link_libraries(${EXECUTABLE} ethereum secp256k1 ${CRYPTOPP_LS}) target_link_libraries(${EXECUTABLE} ethereum secp256k1 ${CRYPTOPP_LS} ${JSONRPC_LS})
if (APPLE) if (APPLE)
if (${ADDFRAMEWORKS}) if (${ADDFRAMEWORKS})

836
libqethereum/QEthereum.cpp

@ -15,818 +15,210 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file QEthereum.cpp /** @file QEthereum.cpp
* @author Gav Wood <i@gavwood.com> * @authors:
* Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
*/ */
#include <boost/filesystem.hpp>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <QtWebKitWidgets/QWebFrame>
#include <libdevcrypto/FileSystem.h>
#include <libevmface/Instruction.h>
#include <liblll/Compiler.h>
#include <libethereum/Client.h>
#include <libethereum/EthereumHost.h>
#include <libwhisper/Message.h>
#include <libwhisper/WhisperHost.h>
#include "QEthereum.h" #include "QEthereum.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
dev::bytes toBytes(QString const& _s)
{
if (_s.startsWith("0x"))
// Hex
return dev::fromHex(_s.mid(2).toStdString());
else if (!_s.contains(QRegExp("[^0-9]")))
// Decimal
return dev::toCompactBigEndian(dev::bigint(_s.toStdString()));
else
{
// Binary
cwarn << "'" << _s.toStdString() << "': Unrecognised format for number/hash. USE eth.fromAscii() if you mean to convert from ASCII.";
return asBytes(_s);
}
}
QString padded(QString const& _s, unsigned _l, unsigned _r)
{
dev::bytes b = toBytes(_s);
while (b.size() < _l)
b.insert(b.begin(), 0);
while (b.size() < _r)
b.push_back(0);
return asQString(dev::asBytes(dev::asString(b).substr(b.size() - max(_l, _r))));
}
//"0xff".bin().unbin() using namespace std;
QString padded(QString const& _s, unsigned _l)
{
if (_s.startsWith("0x") || !_s.contains(QRegExp("[^0-9]")))
// Numeric: pad to right
return padded(_s, _l, _l);
else
// Text: pad to the left
return padded(_s, 0, _l);
}
QString unpadded(QString _s)
{
while (_s.size() && _s.endsWith(QChar(0)))
_s.chop(1);
return _s;
}
QEthereum::QEthereum(QObject* _p, eth::Interface* _c, QList<dev::KeyPair> _accounts): QWebThree::QWebThree(QObject* _p): QObject(_p)
QObject(_p), m_client(_c)
{ {
// required to prevent crash on osx when performing addto/evaluatejavascript calls
moveToThread(_p->thread()); moveToThread(_p->thread());
setAccounts(_accounts);
}
QEthereum::~QEthereum()
{
clearWatches();
}
void QEthereum::clientDieing()
{
clearWatches();
m_client = nullptr;
}
void QEthereum::clearWatches()
{
if (m_client)
for (auto i: m_watches)
m_client->uninstallWatch(i);
m_watches.clear();
} }
eth::Interface* QEthereum::client() const QWebThree::~QWebThree()
{ {
return m_client; clientDieing();
} }
QString QEthereum::lll(QString _s) const static QString toJsonRpcBatch(std::vector<unsigned> const& _watches, QString _method)
{ {
return toQJS(dev::eth::compileLLL(_s.toStdString())); QJsonArray batch;
} for (int w: _watches)
QString QDev::sha3(QString _s) const
{
return toQJS(dev::sha3(toBytes(_s)));
}
QString QDev::sha3(QString _s1, QString _s2) const
{
return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32))));
}
QString QDev::sha3(QString _s1, QString _s2, QString _s3) const
{
return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)) + asBytes(padded(_s3, 32))));
}
QString QDev::offset(QString _s, int _i) const
{
return toQJS(toU256(_s) + _i);
}
QString QEthereum::coinbase() const
{
return m_client ? toQJS(client()->address()) : "";
}
QString QEthereum::number() const
{
return m_client ? QString::number(client()->number() + 1) : "";
}
QStringList QEthereum::accounts() const
{
QStringList ret;
for (auto i: m_accounts)
ret.push_back(toQJS(i.first));
return ret;
}
void QEthereum::setCoinbase(QString _a)
{
if (m_client && client()->address() != toAddress(_a))
{ {
client()->setAddress(toAddress(_a)); QJsonObject res;
coinbaseChanged(); res["jsonrpc"] = QString::fromStdString("2.0");
} res["method"] = _method;
}
void QEthereum::setDefault(int _block)
{
if (m_client)
m_client->setDefault(_block);
}
int QEthereum::getDefault() const
{
return m_client ? m_client->getDefault() : 0;
}
QString QEthereum::balanceAt(QString _a) const
{
return m_client ? toQJS(client()->balanceAt(toAddress(_a))) : "";
}
QString QEthereum::balanceAt(QString _a, int _block) const
{
return m_client ? toQJS(client()->balanceAt(toAddress(_a), _block)) : "";
}
QString QEthereum::stateAt(QString _a, QString _p) const
{
return m_client ? toQJS(client()->stateAt(toAddress(_a), toU256(_p))) : "";
}
QString QEthereum::stateAt(QString _a, QString _p, int _block) const QJsonArray params;
{ params.append(w);
return m_client ? toQJS(client()->stateAt(toAddress(_a), toU256(_p), _block)) : ""; res["params"] = params;
} res["id"] = w;
batch.append(res);
QString QEthereum::codeAt(QString _a) const }
{
return m_client ? ::fromBinary(client()->codeAt(toAddress(_a))) : "";
}
QString QEthereum::codeAt(QString _a, int _block) const
{
return m_client ? ::fromBinary(client()->codeAt(toAddress(_a), _block)) : "";
}
double QEthereum::countAt(QString _a) const
{
return m_client ? (double)(uint64_t)client()->countAt(toAddress(_a)) : 0;
}
double QEthereum::countAt(QString _a, int _block) const return QString::fromUtf8(QJsonDocument(batch).toJson());
{
return m_client ? (double)(uint64_t)client()->countAt(toAddress(_a), _block) : 0;
} }
static dev::eth::MessageFilter toMessageFilter(QString _json) void QWebThree::poll()
{ {
dev::eth::MessageFilter filter; if (m_watches.size() > 0)
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("earliest"))
filter.withEarliest(f["earliest"].toInt());
if (f.contains("latest"))
filter.withLatest(f["latest"].toInt());
if (f.contains("max"))
filter.withMax(f["max"].toInt());
if (f.contains("skip"))
filter.withSkip(f["skip"].toInt());
if (f.contains("from"))
{
if (f["from"].isArray())
for (auto i: f["from"].toArray())
filter.from(toAddress(i.toString()));
else
filter.from(toAddress(f["from"].toString()));
}
if (f.contains("to"))
{ {
if (f["to"].isArray()) QString batch = toJsonRpcBatch(m_watches, "changed");
for (auto i: f["to"].toArray()) emit processData(batch, "changed");
filter.to(toAddress(i.toString()));
else
filter.to(toAddress(f["to"].toString()));
} }
if (f.contains("altered")) if (m_shhWatches.size() > 0)
{ {
if (f["altered"].isArray()) QString batch = toJsonRpcBatch(m_shhWatches, "shhChanged");
for (auto i: f["altered"].toArray()) emit processData(batch, "shhChanged");
if (i.isObject())
filter.altered(toAddress(i.toObject()["id"].toString()), toU256(i.toObject()["at"].toString()));
else
filter.altered(toAddress(i.toString()));
else
if (f["altered"].isObject())
filter.altered(toAddress(f["altered"].toObject()["id"].toString()), toU256(f["altered"].toObject()["at"].toString()));
else
filter.altered(toAddress(f["altered"].toString()));
} }
return filter;
} }
struct TransactionSkeleton void QWebThree::clearWatches()
{
Address from;
Address to;
u256 value;
bytes data;
u256 gas;
u256 gasPrice;
};
static TransactionSkeleton toTransaction(QString _json)
{ {
TransactionSkeleton ret; if (m_watches.size() > 0)
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("from"))
ret.from = toAddress(f["from"].toString());
if (f.contains("to"))
ret.to = toAddress(f["to"].toString());
if (f.contains("value"))
ret.value = toU256(f["value"].toString());
if (f.contains("gas"))
ret.gas = toU256(f["gas"].toString());
if (f.contains("gasPrice"))
ret.gasPrice = toU256(f["gasPrice"].toString());
if (f.contains("data") || f.contains("code") || f.contains("dataclose"))
{ {
if (f["data"].isString()) QString batch = toJsonRpcBatch(m_watches, "uninstallFilter");
ret.data = toBytes(f["data"].toString()); m_watches.clear();
else if (f["code"].isString()) emit processData(batch, "internal");
ret.data = toBytes(f["code"].toString());
else if (f["data"].isArray())
for (auto i: f["data"].toArray())
dev::operator +=(ret.data, asBytes(padded(i.toString(), 32)));
else if (f["code"].isArray())
for (auto i: f["code"].toArray())
dev::operator +=(ret.data, asBytes(padded(i.toString(), 32)));
else if (f["dataclose"].isArray())
for (auto i: f["dataclose"].toArray())
dev::operator +=(ret.data, toBytes(i.toString()));
} }
return ret; if (m_shhWatches.size() > 0)
}
static QString toJson(dev::eth::PastMessages const& _pms)
{
QJsonArray jsonArray;
for (dev::eth::PastMessage const& t: _pms)
{ {
QJsonObject v; QString batch = toJsonRpcBatch(m_shhWatches, "shhUninstallFilter");
v["input"] = ::fromBinary(t.input); m_shhWatches.clear();
v["output"] = ::fromBinary(t.output); emit processData(batch, "internal");
v["to"] = toQJS(t.to);
v["from"] = toQJS(t.from);
v["origin"] = toQJS(t.origin);
v["timestamp"] = (int)t.timestamp;
v["coinbase"] = toQJS(t.coinbase);
v["block"] = toQJS(t.block);
QJsonArray path;
for (int i: t.path)
path.append(i);
v["path"] = path;
v["number"] = (int)t.number;
jsonArray.append(v);
} }
return QString::fromUtf8(QJsonDocument(jsonArray).toJson());
} }
static QString toJson(dev::eth::BlockInfo const& _bi, dev::eth::BlockDetails const& _bd) void QWebThree::clientDieing()
{ {
QJsonObject v; clearWatches();
v["hash"] = toQJS(_bi.hash); this->disconnect();
v["parentHash"] = toQJS(_bi.parentHash);
v["sha3Uncles"] = toQJS(_bi.sha3Uncles);
v["miner"] = toQJS(_bi.coinbaseAddress);
v["stateRoot"] = toQJS(_bi.stateRoot);
v["transactionsRoot"] = toQJS(_bi.transactionsRoot);
v["difficulty"] = toQJS(_bi.difficulty);
v["number"] = (int)_bi.number;
v["minGasPrice"] = toQJS(_bi.minGasPrice);
v["gasLimit"] = (int)_bi.gasLimit;
v["gasUsed"] = (int)_bi.gasUsed;
v["timestamp"] = (int)_bi.timestamp;
v["extraData"] = ::fromBinary(_bi.extraData);
v["nonce"] = toQJS(_bi.nonce);
QJsonArray children;
for (auto c: _bd.children)
children.append(toQJS(c));
v["children"] = children;
v["totalDifficulty"] = toQJS(_bd.totalDifficulty);
v["bloom"] = toQJS(_bd.bloom);
return QString::fromUtf8(QJsonDocument(v).toJson());
}
static QString toJson(dev::eth::BlockInfo const& _bi)
{
QJsonObject v;
v["hash"] = toQJS(_bi.hash);
v["parentHash"] = toQJS(_bi.parentHash);
v["sha3Uncles"] = toQJS(_bi.sha3Uncles);
v["miner"] = toQJS(_bi.coinbaseAddress);
v["stateRoot"] = toQJS(_bi.stateRoot);
v["transactionsRoot"] = toQJS(_bi.transactionsRoot);
v["difficulty"] = toQJS(_bi.difficulty);
v["number"] = (int)_bi.number;
v["minGasPrice"] = toQJS(_bi.minGasPrice);
v["gasLimit"] = (int)_bi.gasLimit;
v["gasUsed"] = (int)_bi.gasUsed;
v["timestamp"] = (int)_bi.timestamp;
v["extraData"] = ::fromBinary(_bi.extraData);
v["nonce"] = toQJS(_bi.nonce);
return QString::fromUtf8(QJsonDocument(v).toJson());
}
static QString toJson(dev::eth::Transaction const& _bi)
{
QJsonObject v;
v["hash"] = toQJS(_bi.sha3());
v["input"] = ::fromBinary(_bi.data);
v["to"] = toQJS(_bi.receiveAddress);
v["from"] = toQJS(_bi.sender());
v["gas"] = (int)_bi.gas;
v["gasPrice"] = toQJS(_bi.gasPrice);
v["nonce"] = (int)_bi.nonce;
v["value"] = toQJS(_bi.value);
return QString::fromUtf8(QJsonDocument(v).toJson());
}
QString QEthereum::getUncle(QString _numberOrHash, int _i) const
{
auto n = toU256(_numberOrHash);
auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash);
return m_client ? toJson(m_client->uncle(h, _i)) : "";
}
QString QEthereum::getTransaction(QString _numberOrHash, int _i) const
{
auto n = toU256(_numberOrHash);
auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash);
return m_client ? toJson(m_client->transaction(h, _i)) : "";
}
QString QEthereum::getBlock(QString _numberOrHash) const
{
auto n = toU256(_numberOrHash);
auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash);
return m_client ? toJson(m_client->blockInfo(h), m_client->blockDetails(h)) : "";
}
QString QEthereum::getMessages(QString _json) const
{
return m_client ? toJson(m_client->messages(toMessageFilter(_json))) : "";
} }
bool QEthereum::isMining() const static QString formatInput(QJsonObject const& _object)
{ {
return m_client ? client()->isMining() : false; QJsonObject res;
res["jsonrpc"] = QString::fromStdString("2.0");
res["method"] = _object["call"];
res["params"] = _object["args"];
res["id"] = _object["_id"];
return QString::fromUtf8(QJsonDocument(res).toJson());
} }
bool QEthereum::isListening() const void QWebThree::postMessage(QString _json)
{ {
return /*m_client ? client()->haveNetwork() :*/ false; QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
}
void QEthereum::setMining(bool _l) QString method = f["call"].toString();
{ if (!method.compare("uninstallFilter") && f["args"].isArray() && f["args"].toArray().size())
if (m_client)
{ {
if (_l) int idToRemove = f["args"].toArray()[0].toInt();
client()->startMining(); m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end());
else
client()->stopMining();
} }
}
void QEthereum::setListening(bool) emit processData(formatInput(f), method);
{
if (!m_client)
return;
/* if (_l)
client()->startNetwork();
else
client()->stopNetwork();*/
} }
void QEthereum::setAccounts(QList<dev::KeyPair> const& _l) static QString formatOutput(QJsonObject const& _object)
{ {
m_accounts.clear(); QJsonObject res;
for (auto i: _l) res["_id"] = _object["id"];
m_accounts[i.address()] = i.secret(); res["data"] = _object["result"];
keysChanged(); return QString::fromUtf8(QJsonDocument(res).toJson());
} }
unsigned QEthereum::peerCount() const void QWebThree::onDataProcessed(QString _json, QString _addInfo)
{ {
return /*m_client ? (unsigned)client()->peerCount() :*/ 0; if (!_addInfo.compare("internal"))
} return;
QString QEthereum::doTransact(QString _json) if (!_addInfo.compare("changed"))
{
QString ret;
if (!m_client)
return ret;
TransactionSkeleton t = toTransaction(_json);
if (!t.from && m_accounts.size())
{ {
u256 b = 0; QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array();
for (auto a: m_accounts) for (int i = 0; i < resultsArray.size(); i++)
if (client()->balanceAt(a.first) > b)
t.from = a.first, b = client()->balanceAt(a.first);
}
if (!m_accounts.count(t.from))
return QString();
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
cwarn << "Silently signing transaction from address" << t.from.abridged() << ": User validation hook goes here.";
if (t.to)
// TODO: insert validification hook here.
client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice);
else
ret = toQJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice));
client()->flushTransactions();
return ret;
}
QString QEthereum::doCall(QString _json)
{
if (!m_client)
return QString();
TransactionSkeleton t = toTransaction(_json);
if (!t.from && m_accounts.size())
{ {
auto b = m_accounts.begin()->first; QJsonObject elem = resultsArray[i].toObject();
for (auto a: m_accounts) if (elem.contains("result") && elem["result"].toBool() == true)
if (client()->balanceAt(a.first) > client()->balanceAt(b))
b = a.first;
t.from = b;
}
if (!m_accounts.count(t.from))
return QString();
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
bytes out = client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice);
return asQString(out);
}
unsigned QEthereum::newWatch(QString _json)
{
if (!m_client)
return (unsigned)-1;
unsigned ret;
if (_json == "chain")
ret = m_client->installWatch(dev::eth::ChainChangedFilter);
else if (_json == "pending")
ret = m_client->installWatch(dev::eth::PendingChangedFilter);
else
ret = m_client->installWatch(toMessageFilter(_json));
m_watches.push_back(ret);
return ret;
}
QString QEthereum::watchMessages(unsigned _w)
{
if (!m_client)
return "";
return toJson(m_client->messages(_w));
}
void QEthereum::killWatch(unsigned _w)
{
if (!m_client)
return;
m_client->uninstallWatch(_w);
std::remove(m_watches.begin(), m_watches.end(), _w);
}
void QEthereum::poll()
{
if (!m_client)
return;
for (auto w: m_watches)
if (m_client->checkWatch(w))
emit watchChanged(w);
}
// TODO: repot and hook all these up.
QWhisper::QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c, QList<dev::KeyPair> _ids): QObject(_p), m_face(_c)
{
setIdentities(_ids);
}
QWhisper::~QWhisper()
{
}
// probably want a better way of doing this. somehow guarantee that the face() will always be available as long as this object is.
struct NoInterface: public Exception {};
std::shared_ptr<dev::shh::Interface> QWhisper::face() const
{
auto ret = m_face.lock();
if (!ret)
throw NoInterface();
return ret;
}
void QWhisper::faceDieing()
{
}
static shh::Message toMessage(QString _json)
{
shh::Message ret;
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("from"))
ret.setFrom(toPublic(f["from"].toString()));
if (f.contains("to"))
ret.setTo(toPublic(f["to"].toString()));
if (f.contains("payload"))
ret.setPayload(toBytes(f["payload"].toString()));
return ret;
}
static shh::Envelope toSealed(QString _json, shh::Message const& _m, Secret _from)
{
unsigned ttl = 50;
unsigned workToProve = 50;
shh::BuildTopic bt;
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("ttl"))
ttl = f["ttl"].toInt();
if (f.contains("workToProve"))
workToProve = f["workToProve"].toInt();
if (f.contains("topic"))
{ {
if (f["topic"].isString()) QJsonObject res;
bt.shift(asBytes(padded(f["topic"].toString(), 32))); res["_event"] = _addInfo;
else if (f["topic"].isArray()) res["_id"] = (int)m_watches[i]; // we can do that couse poll is synchronous
for (auto i: f["topic"].toArray()) response(QString::fromUtf8(QJsonDocument(res).toJson()));
bt.shift(asBytes(padded(i.toString(), 32)));
} }
return _m.seal(_from, bt, ttl, workToProve);
}
void QWhisper::doPost(QString _json)
{
shh::Message m = toMessage(_json);
Secret from;
if (m.from() && m_ids.count(m.from()))
{
cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here.";
// TODO: insert validification hook here.
from = m_ids[m.from()];
} }
return;
face()->inject(toSealed(_json, m, from));
}
void QWhisper::setIdentities(QList<dev::KeyPair> const& _l)
{
m_ids.clear();
for (auto i: _l)
m_ids[i.pub()] = i.secret();
emit idsChanged();
}
static pair<shh::TopicMask, Public> toWatch(QString _json)
{
shh::BuildTopicMask bt(shh::BuildTopicMask::Empty);
Public to;
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("to"))
to = toPublic(f["to"].toString());
if (f.contains("topic"))
{
if (f["topic"].isString())
bt.shift(asBytes(padded(f["topic"].toString(), 32)));
else if (f["topic"].isArray())
for (auto i: f["topic"].toArray())
if (i.isString())
bt.shift(asBytes(padded(i.toString(), 32)));
else
bt.shift();
} }
return make_pair(bt.toTopicMask(), to);
}
// _json contains
// topic: the topic as an array of components, some may be null.
// to: specifies the id to which the message is encrypted. null if broadcast.
unsigned QWhisper::newWatch(QString _json)
{
auto w = toWatch(_json);
auto ret = face()->installWatch(w.first);
m_watches.insert(make_pair(ret, w.second));
return ret;
}
void QWhisper::killWatch(unsigned _w)
{
face()->uninstallWatch(_w);
m_watches.erase(_w);
}
void QWhisper::clearWatches()
{
for (auto i: m_watches)
face()->uninstallWatch(i.first);
m_watches.clear();
}
static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m)
{
QJsonObject v;
v["hash"] = toQJS(_h);
v["expiry"] = (int)_e.expiry();
v["sent"] = (int)_e.sent();
v["ttl"] = (int)_e.ttl();
v["workProved"] = (int)_e.workProved();
v["topic"] = toQJS(_e.topic());
v["payload"] = toQJS(_m.payload());
v["from"] = toQJS(_m.from());
v["to"] = toQJS(_m.to());
return QString::fromUtf8(QJsonDocument(v).toJson());
}
QString QWhisper::watchMessages(unsigned _w) if (!_addInfo.compare("shhChanged"))
{
QString ret = "[";
auto wit = m_watches.find(_w);
if (wit == m_watches.end())
{ {
cwarn << "watchMessages called with invalid watch id" << _w; QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array();
return ""; for (int i = 0; i < resultsArray.size(); i++)
}
Public p = wit->second;
if (!p || m_ids.count(p))
for (h256 const& h: face()->watchMessages(_w))
{ {
auto e = face()->envelope(h); QJsonObject elem = resultsArray[i].toObject();
shh::Message m; if (elem.contains("result"))
if (p)
{ {
cwarn << "Silently decrypting message from identity" << p.abridged() << ": User validation hook goes here."; QJsonObject res;
m = e.open(m_ids[p]); res["_event"] = _addInfo;
res["_id"] = (int)m_shhWatches[i];
res["data"] = elem["result"].toArray();
response(QString::fromUtf8(QJsonDocument(res).toJson()));
}
} }
else
m = e.open();
ret.append((ret == "[" ? "" : ",") + toJson(h, e, m));
} }
return ret + "]"; QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
}
QString QWhisper::newIdentity() if ((!_addInfo.compare("newFilter") || !_addInfo.compare("newFilterString")) && f.contains("result"))
{ m_watches.push_back(f["result"].toInt());
return toQJS(makeIdentity()); if (!_addInfo.compare("shhNewFilter") && f.contains("result"))
} m_shhWatches.push_back(f["result"].toInt());
if (!_addInfo.compare("newIdentity") && f.contains("result"))
emit onNewId(f["result"].toString());
Public QWhisper::makeIdentity() response(formatOutput(f));
{
KeyPair kp = KeyPair::create();
emit newIdToAdd(toQJS(kp.sec()));
return kp.pub();
} }
QString QWhisper::newGroup(QString _me, QString _others) QWebThreeConnector::QWebThreeConnector()
{ {
(void)_me;
(void)_others;
return "";
} }
QString QWhisper::addToGroup(QString _group, QString _who) QWebThreeConnector::~QWebThreeConnector()
{ {
(void)_group; StopListening();
(void)_who;
return "";
} }
void QWhisper::poll() void QWebThreeConnector::setQWeb(QWebThree* _q)
{ {
for (auto const& w: m_watches) m_qweb = _q;
if (!w.second || m_ids.count(w.second)) if (m_isListening)
for (h256 const& h: face()->checkWatch(w.first))
{ {
auto e = face()->envelope(h); StopListening();
shh::Message m; StartListening();
if (w.second)
{
cwarn << "Silently decrypting message from identity" << w.second.abridged() << ": User validation hook goes here.";
m = e.open(m_ids[w.second]);
if (!m)
continue;
}
else
m = e.open();
emit watchChanged(w.first, toJson(h, e, m));
} }
} }
#include <libdevcrypto/FileSystem.h> bool QWebThreeConnector::StartListening()
QLDB::QLDB(QObject* _p): QObject(_p)
{ {
auto path = getDataDir() + "/.web3"; m_isListening = true;
boost::filesystem::create_directories(path); if (m_qweb)
ldb::Options o; {
o.create_if_missing = true; connect(m_qweb, SIGNAL(processData(QString, QString)), this, SLOT(onProcessData(QString, QString)));
ldb::DB::Open(o, path, &m_db); connect(this, SIGNAL(dataProcessed(QString, QString)), m_qweb, SLOT(onDataProcessed(QString, QString)));
} }
return true;
QLDB::~QLDB()
{
}
void QLDB::put(QString _p, QString _k, QString _v)
{
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes();
bytes v = toBytes(_v);
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
} }
QString QLDB::get(QString _p, QString _k) bool QWebThreeConnector::StopListening()
{ {
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); this->disconnect();
string ret; return true;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
return toQJS(dev::asBytes(ret));
} }
void QLDB::putString(QString _p, QString _k, QString _v) bool QWebThreeConnector::SendResponse(std::string const& _response, void* _addInfo)
{ {
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); emit dataProcessed(QString::fromStdString(_response), *(QString*)_addInfo);
string v = _v.toStdString(); return true;
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
} }
QString QLDB::getString(QString _p, QString _k) void QWebThreeConnector::onProcessData(QString const& _json, QString const& _addInfo)
{ {
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); OnRequest(_json.toStdString(), (void*)&_addInfo);
string ret;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
return QString::fromStdString(ret);
} }
// extra bits needed to link on VS // extra bits needed to link on VS

332
libqethereum/QEthereum.h

@ -15,344 +15,78 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file QEthereum.h /** @file QEthereum.h
* @author Gav Wood <i@gavwood.com> * @authors:
* Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
*/ */
#pragma once #pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QStringList> #include <QtCore/QString>
#include <QtCore/QList> #include <jsonrpc/rpc.h>
#include <libdevcore/CommonIO.h>
#include <libethcore/CommonEth.h>
namespace ldb = leveldb;
namespace dev {
namespace eth {
class Interface;
}
namespace shh {
class Interface;
}
}
class QJSEngine;
class QWebFrame;
class QEthereum;
inline dev::bytes asBytes(QString const& _s)
{
dev::bytes ret;
ret.reserve(_s.size());
for (QChar c: _s)
ret.push_back(c.cell());
return ret;
}
inline QString asQString(dev::bytes const& _s)
{
QString ret;
ret.reserve(_s.size());
for (auto c: _s)
ret.push_back(QChar(c, 0));
return ret;
}
dev::bytes toBytes(QString const& _s);
QString padded(QString const& _s, unsigned _l, unsigned _r);
QString padded(QString const& _s, unsigned _l);
QString unpadded(QString _s);
template <unsigned N> dev::FixedHash<N> toFixed(QString const& _s)
{
if (_s.startsWith("0x"))
// Hex
return dev::FixedHash<N>(_s.mid(2).toStdString());
else if (!_s.contains(QRegExp("[^0-9]")))
// Decimal
return (typename dev::FixedHash<N>::Arith)(_s.toStdString());
else
// Binary
return dev::FixedHash<N>(asBytes(padded(_s, N)));
}
template <unsigned N> inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> toInt(QString const& _s);
inline dev::Address toAddress(QString const& _s) { return toFixed<sizeof(dev::Address)>(_s); }
inline dev::Public toPublic(QString const& _s) { return toFixed<sizeof(dev::Public)>(_s); }
inline dev::Secret toSecret(QString const& _s) { return toFixed<sizeof(dev::Secret)>(_s); }
inline dev::u256 toU256(QString const& _s) { return toInt<32>(_s); }
template <unsigned S> QString toQJS(dev::FixedHash<S> const& _h) { return QString::fromStdString("0x" + toHex(_h.ref())); }
template <unsigned N> QString toQJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n) { return QString::fromStdString("0x" + dev::toHex(dev::toCompactBigEndian(_n))); }
inline QString toQJS(dev::bytes const& _n) { return "0x" + QString::fromStdString(dev::toHex(_n)); }
inline QString toBinary(QString const& _s)
{
return unpadded(asQString(toBytes(_s)));
}
inline QString toDecimal(QString const& _s)
{
return QString::fromStdString(dev::toString(toU256(_s)));
}
inline double fromFixed(QString const& _s)
{
return (double)toU256(_s) / (double)(dev::u256(1) << 128);
}
inline QString toFixed(double _s)
{
return toQJS(dev::u256(_s * (double)(dev::u256(1) << 128)));
}
inline QString fromBinary(dev::bytes _s, unsigned _padding = 32)
{
_s.resize(std::max<unsigned>(_s.size(), _padding));
return QString::fromStdString("0x" + dev::toHex(_s));
}
inline QString fromBinary(QString const& _s, unsigned _padding = 32)
{
return fromBinary(asBytes(_s), _padding);
}
class QDev: public QObject
{
Q_OBJECT
public:
QDev(QObject* _p): QObject(_p) {}
virtual ~QDev() {}
Q_INVOKABLE QString sha3(QString _s) const;
Q_INVOKABLE QString sha3(QString _s1, QString _s2) const;
Q_INVOKABLE QString sha3(QString _s1, QString _s2, QString _s3) const;
Q_INVOKABLE QString offset(QString _s, int _offset) const;
Q_INVOKABLE QString toAscii(QString _s) const { return ::toBinary(_s); }
Q_INVOKABLE QString fromAscii(QString _s) const { return ::fromBinary(_s, 32); }
Q_INVOKABLE QString fromAscii(QString _s, unsigned _padding) const { return ::fromBinary(_s, _padding); }
Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); }
Q_INVOKABLE double fromFixed(QString _s) const { return ::fromFixed(_s); }
Q_INVOKABLE QString toFixed(double _d) const { return ::toFixed(_d); }
};
class QEthereum: public QObject class QWebThree: public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
QEthereum(QObject* _p, dev::eth::Interface* _c, QList<dev::KeyPair> _accounts); QWebThree(QObject* _p);
virtual ~QEthereum(); virtual ~QWebThree();
dev::eth::Interface* client() const;
void setClient(dev::eth::Interface* _c) { m_client = _c; }
/// Call when the client() is going to be deleted to make this object useless but safe.
void clientDieing();
void setAccounts(QList<dev::KeyPair> const& _l);
Q_INVOKABLE QEthereum* self() { return this; }
Q_INVOKABLE QString lll(QString _s) const;
// [NEW API] - Use this instead.
Q_INVOKABLE QString/*dev::u256*/ balanceAt(QString/*dev::Address*/ _a, int _block) const;
Q_INVOKABLE double countAt(QString/*dev::Address*/ _a, int _block) const;
Q_INVOKABLE QString/*dev::u256*/ stateAt(QString/*dev::Address*/ _a, QString/*dev::u256*/ _p, int _block) const;
Q_INVOKABLE QString/*dev::u256*/ codeAt(QString/*dev::Address*/ _a, int _block) const;
Q_INVOKABLE QString/*dev::u256*/ balanceAt(QString/*dev::Address*/ _a) const; void poll();
Q_INVOKABLE double countAt(QString/*dev::Address*/ _a) const;
Q_INVOKABLE QString/*dev::u256*/ stateAt(QString/*dev::Address*/ _a, QString/*dev::u256*/ _p) const;
Q_INVOKABLE QString/*dev::u256*/ codeAt(QString/*dev::Address*/ _a) const;
Q_INVOKABLE QString/*json*/ getBlock(QString _numberOrHash/*unsigned if < number(), hash otherwise*/) const;
Q_INVOKABLE QString/*json*/ getTransaction(QString _numberOrHash/*unsigned if < number(), hash otherwise*/, int _index) const;
Q_INVOKABLE QString/*json*/ getUncle(QString _numberOrHash/*unsigned if < number(), hash otherwise*/, int _index) const;
Q_INVOKABLE QString/*json*/ getMessages(QString _attribs/*json*/) const;
Q_INVOKABLE QString doTransact(QString _json);
Q_INVOKABLE QString doCall(QString _json);
Q_INVOKABLE unsigned newWatch(QString _json);
Q_INVOKABLE QString watchMessages(unsigned _w);
Q_INVOKABLE void killWatch(unsigned _w);
void clearWatches(); void clearWatches();
void clientDieing();
bool isListening() const; Q_INVOKABLE void postMessage(QString _json);
bool isMining() const;
QString/*dev::Address*/ coinbase() const;
QString/*dev::u256*/ gasPrice() const { return toQJS(10 * dev::eth::szabo); }
QString/*dev::u256*/ number() const;
int getDefault() const;
QStringList/*list of dev::Address*/ accounts() const;
unsigned peerCount() const;
public slots: public slots:
void setCoinbase(QString/*dev::Address*/); void onDataProcessed(QString _json, QString _addInfo);
void setMining(bool _l);
void setListening(bool _l);
void setDefault(int _block);
/// Check to see if anything has changed, fire off signals if so.
/// @note Must be called in the QObject's thread.
void poll();
signals: signals:
void watchChanged(unsigned _w); void processData(QString _json, QString _addInfo);
void coinbaseChanged(); void response(QString _json);
void keysChanged(); void onNewId(QString _id);
void netChanged();
void miningChanged();
private: private:
Q_PROPERTY(QString number READ number NOTIFY watchChanged)
Q_PROPERTY(QString coinbase READ coinbase WRITE setCoinbase NOTIFY coinbaseChanged)
Q_PROPERTY(QString gasPrice READ gasPrice)
Q_PROPERTY(QStringList accounts READ accounts NOTIFY keysChanged)
Q_PROPERTY(bool mining READ isMining WRITE setMining NOTIFY netChanged)
Q_PROPERTY(bool listening READ isListening WRITE setListening NOTIFY netChanged)
Q_PROPERTY(unsigned peerCount READ peerCount NOTIFY miningChanged)
Q_PROPERTY(int defaultBlock READ getDefault WRITE setDefault)
dev::eth::Interface* m_client;
std::vector<unsigned> m_watches; std::vector<unsigned> m_watches;
std::map<dev::Address, dev::KeyPair> m_accounts; std::vector<unsigned> m_shhWatches;
}; };
class QWhisper: public QObject class QWebThreeConnector: public QObject, public jsonrpc::AbstractServerConnector
{ {
Q_OBJECT Q_OBJECT
public: public:
QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c, QList<dev::KeyPair> _ids); QWebThreeConnector();
virtual ~QWhisper(); virtual ~QWebThreeConnector();
std::shared_ptr<dev::shh::Interface> face() const;
void setFace(std::shared_ptr<dev::shh::Interface> const& _c) { m_face = _c; }
void setIdentities(QList<dev::KeyPair> const& _l);
/// Call when the face() is going to be deleted to make this object useless but safe.
void faceDieing();
Q_INVOKABLE QWhisper* self() { return this; }
/// Basic message send.
Q_INVOKABLE void doPost(QString _json);
Q_INVOKABLE QString newIdentity(); void setQWeb(QWebThree *_q);
Q_INVOKABLE bool haveIdentity(QString _id) { return m_ids.count(toPublic(_id)); }
Q_INVOKABLE QString newGroup(QString _id, QString _who); virtual bool StartListening();
Q_INVOKABLE QString addToGroup(QString _group, QString _who); virtual bool StopListening();
virtual bool SendResponse(std::string const& _response, void* _addInfo = NULL);
// Watches interface
Q_INVOKABLE unsigned newWatch(QString _json);
Q_INVOKABLE void killWatch(unsigned _w);
Q_INVOKABLE void clearWatches();
Q_INVOKABLE QString watchMessages(unsigned _w);
dev::Public makeIdentity();
std::map<dev::Public, dev::Secret> const& ids() const { return m_ids; }
public slots: public slots:
/// Check to see if anything has changed, fire off signals if so. void onProcessData(QString const& _json, QString const& _addInfo);
/// @note Must be called in the QObject's thread.
void poll();
signals: signals:
void watchChanged(unsigned _w, QString _envelopeJson); void dataProcessed(QString const& _json, QString const& _addInfo);
void idsChanged();
void newIdToAdd(QString _id);
private:
std::weak_ptr<dev::shh::Interface> m_face;
std::map<unsigned, dev::Public> m_watches;
std::map<dev::Public, dev::Secret> m_ids;
};
class QLDB: public QObject
{
Q_OBJECT
public:
QLDB(QObject* _p);
~QLDB();
Q_INVOKABLE void put(QString _name, QString _key, QString _value);
Q_INVOKABLE QString get(QString _name, QString _key);
Q_INVOKABLE void putString(QString _name, QString _key, QString _value);
Q_INVOKABLE QString getString(QString _name, QString _key);
private: private:
ldb::ReadOptions m_readOptions; QWebThree* m_qweb = nullptr;
ldb::WriteOptions m_writeOptions; bool m_isListening;
ldb::DB* m_db;
}; };
// TODO: add p2p object #define QETH_INSTALL_JS_NAMESPACE(_frame, _env, qweb) [_frame, _env, qweb]() \
#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh, _ldb) [_frame, _env, _web3, _eth, _shh, _ldb]() \
{ \ { \
_frame->disconnect(); \ _frame->disconnect(); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ _frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("web3", _web3, QWebFrame::ScriptOwnership); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \
if (_ldb) \ _frame->evaluateJavaScript(contentsOfQResource(":/js/main.js")); \
{ \ _frame->evaluateJavaScript(contentsOfQResource(":/js/qt.js")); \
_frame->addToJavaScriptWindowObject("_web3_dot_db", _ldb, QWebFrame::QtOwnership); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \
_frame->evaluateJavaScript("web3.db = _web3_dot_db"); \
} \
if (_eth) \
{ \
_frame->addToJavaScriptWindowObject("_web3_dot_eth", _eth, QWebFrame::ScriptOwnership); \
_frame->evaluateJavaScript("_web3_dot_eth.makeWatch = function(a) { var ww = _web3_dot_eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_eth.killWatch(this.w); }; ret.changed = function(f) { _web3_dot_eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_eth.watchMessages(this.w)) }; return ret; }"); \
_frame->evaluateJavaScript("_web3_dot_eth.watch = function(a) { return _web3_dot_eth.makeWatch(JSON.stringify(a)) }"); \
_frame->evaluateJavaScript("_web3_dot_eth.transact = function(a, f) { var r = _web3_dot_eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \
_frame->evaluateJavaScript("_web3_dot_eth.call = function(a, f) { var ret = _web3_dot_eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \
_frame->evaluateJavaScript("_web3_dot_eth.messages = function(a) { return JSON.parse(_web3_dot_eth.getMessages(JSON.stringify(a))); }"); \
_frame->evaluateJavaScript("_web3_dot_eth.block = function(a) { return JSON.parse(_web3_dot_eth.getBlock(a)); }"); \
_frame->evaluateJavaScript("_web3_dot_eth.transaction = function(a) { return JSON.parse(_web3_dot_eth.getTransaction(a)); }"); \
_frame->evaluateJavaScript("_web3_dot_eth.uncle = function(a) { return JSON.parse(_web3_dot_eth.getUncle(a)); }"); \
_frame->evaluateJavaScript("web3.eth = _web3_dot_eth"); \
} \
if (_shh) \
{ \
_frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \
_frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(this.w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(this.w)); for (var e in existing) f(existing[e]) }; return ret; }"); \
_frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \
_frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \
_frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \
} \
} }
template <unsigned N> inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> toInt(QString const& _s)
{
if (_s.startsWith("0x"))
return dev::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(dev::fromHex(_s.toStdString().substr(2)));
else if (!_s.contains(QRegExp("[^0-9]")))
// Hex or Decimal
return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s.toStdString());
else
// Binary
return dev::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(padded(_s, N)));
}

49
libserpent/opcodes.h

@ -1,3 +1,20 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ETHSERP_OPCODES #ifndef ETHSERP_OPCODES
#define ETHSERP_OPCODES #define ETHSERP_OPCODES
@ -7,7 +24,7 @@
#include <map> #include <map>
class Mapping { class Mapping {
public: public:
Mapping(std::string Op, int Opcode, int In, int Out) { Mapping(std::string Op, int Opcode, int In, int Out) {
op = Op; op = Op;
opcode = Opcode; opcode = Opcode;
@ -43,6 +60,7 @@ Mapping mapping[] = {
Mapping("BYTE", 0x13, 2, 1), Mapping("BYTE", 0x13, 2, 1),
Mapping("ADDMOD", 0x14, 3, 1), Mapping("ADDMOD", 0x14, 3, 1),
Mapping("MULMOD", 0x15, 3, 1), Mapping("MULMOD", 0x15, 3, 1),
Mapping("SIGNEXTEND", 0x16, 2, 1),
Mapping("SHA3", 0x20, 2, 1), Mapping("SHA3", 0x20, 2, 1),
Mapping("ADDRESS", 0x30, 0, 1), Mapping("ADDRESS", 0x30, 0, 1),
Mapping("BALANCE", 0x31, 1, 1), Mapping("BALANCE", 0x31, 1, 1),
@ -85,24 +103,25 @@ std::map<std::string, std::vector<int> > opcodes;
std::map<int, std::string> reverseOpcodes; std::map<int, std::string> reverseOpcodes;
// Fetches everything EXCEPT PUSH1..32 // Fetches everything EXCEPT PUSH1..32
std::pair<std::string, std::vector<int> > _opdata(std::string ops, int opi) { std::pair<std::string, std::vector<int> > _opdata(std::string ops, int opi)
if (!opcodes.size()) { {
if (!opcodes.size())
{
int i = 0; int i = 0;
while (mapping[i].op != "---END---") { while (mapping[i].op != "---END---")
{
Mapping mi = mapping[i]; Mapping mi = mapping[i];
opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out); opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out);
i++; i++;
} }
for (i = 1; i <= 16; i++) { for (i = 1; i <= 16; i++)
{
opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1); opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1);
opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1); opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1);
} }
for (std::map<std::string, std::vector<int> >::iterator it=opcodes.begin(); for (std::map<std::string, std::vector<int> >::iterator it=opcodes.begin(); it != opcodes.end(); it++)
it != opcodes.end();
it++) {
reverseOpcodes[(*it).second[0]] = (*it).first; reverseOpcodes[(*it).second[0]] = (*it).first;
} }
}
std::string op; std::string op;
std::vector<int> opdata; std::vector<int> opdata;
op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : ""; op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : "";
@ -110,19 +129,23 @@ std::pair<std::string, std::vector<int> > _opdata(std::string ops, int opi) {
return std::pair<std::string, std::vector<int> >(op, opdata); return std::pair<std::string, std::vector<int> >(op, opdata);
} }
int opcode(std::string op) { int opcode(std::string op)
{
return _opdata(op, -1).second[0]; return _opdata(op, -1).second[0];
} }
int opinputs(std::string op) { int opinputs(std::string op)
{
return _opdata(op, -1).second[1]; return _opdata(op, -1).second[1];
} }
int opoutputs(std::string op) { int opoutputs(std::string op)
{
return _opdata(op, -1).second[2]; return _opdata(op, -1).second[2];
} }
std::string op(int opcode) { std::string op(int opcode)
{
return _opdata("", opcode).first; return _opdata("", opcode).first;
} }

61
libsolidity/AST.cpp

@ -26,6 +26,8 @@
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
using namespace std;
namespace dev namespace dev
{ {
namespace solidity namespace solidity
@ -248,12 +250,12 @@ void Literal::accept(ASTVisitor& _visitor)
_visitor.endVisit(*this); _visitor.endVisit(*this);
} }
TypeError ASTNode::createTypeError(std::string const& _description) TypeError ASTNode::createTypeError(string const& _description)
{ {
return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
} }
void Statement::expectType(Expression& _expression, const Type& _expectedType) void Statement::expectType(Expression& _expression, Type const& _expectedType)
{ {
_expression.checkTypeRequirements(); _expression.checkTypeRequirements();
if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType))
@ -263,7 +265,7 @@ void Statement::expectType(Expression& _expression, const Type& _expectedType)
void Block::checkTypeRequirements() void Block::checkTypeRequirements()
{ {
for (std::shared_ptr<Statement> const& statement: m_statements) for (shared_ptr<Statement> const& statement: m_statements)
statement->checkTypeRequirements(); statement->checkTypeRequirements();
} }
@ -291,7 +293,7 @@ void Break::checkTypeRequirements()
void Return::checkTypeRequirements() void Return::checkTypeRequirements()
{ {
BOOST_ASSERT(m_returnParameters); assert(m_returnParameters);
if (m_returnParameters->getParameters().size() != 1) if (m_returnParameters->getParameters().size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
"than in returns declaration.")); "than in returns declaration."));
@ -328,7 +330,7 @@ void Assignment::checkTypeRequirements()
m_type = m_leftHandSide->getType(); m_type = m_leftHandSide->getType();
if (m_assigmentOperator != Token::ASSIGN) if (m_assigmentOperator != Token::ASSIGN)
{ {
// complex assignment // compound assignment
if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator)))
BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
} }
@ -339,7 +341,7 @@ void UnaryOperation::checkTypeRequirements()
// INC, DEC, NOT, BIT_NOT, DELETE // INC, DEC, NOT, BIT_NOT, DELETE
m_subExpression->checkTypeRequirements(); m_subExpression->checkTypeRequirements();
m_type = m_subExpression->getType(); m_type = m_subExpression->getType();
if (m_type->acceptsUnaryOperator(m_operator)) if (!m_type->acceptsUnaryOperator(m_operator))
BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type."));
} }
@ -354,10 +356,10 @@ void BinaryOperation::checkTypeRequirements()
else else
BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation."));
if (Token::isCompareOp(m_operator)) if (Token::isCompareOp(m_operator))
m_type = std::make_shared<BoolType>(); m_type = make_shared<BoolType>();
else else
{ {
BOOST_ASSERT(Token::isBinaryOp(m_operator)); assert(Token::isBinaryOp(m_operator));
m_type = m_commonType; m_type = m_commonType;
if (!m_commonType->acceptsBinaryOperator(m_operator)) if (!m_commonType->acceptsBinaryOperator(m_operator))
BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type."));
@ -369,12 +371,12 @@ void FunctionCall::checkTypeRequirements()
m_expression->checkTypeRequirements(); m_expression->checkTypeRequirements();
for (ASTPointer<Expression> const& argument: m_arguments) for (ASTPointer<Expression> const& argument: m_arguments)
argument->checkTypeRequirements(); argument->checkTypeRequirements();
Type const& expressionType = *m_expression->getType();
Type::Category const category = expressionType.getCategory(); Type const* expressionType = m_expression->getType().get();
if (category == Type::Category::TYPE) if (isTypeConversion())
{ {
TypeType const* type = dynamic_cast<TypeType const*>(&expressionType); TypeType const* type = dynamic_cast<TypeType const*>(expressionType);
BOOST_ASSERT(type); assert(type);
//@todo for structs, we have to check the number of arguments to be equal to the //@todo for structs, we have to check the number of arguments to be equal to the
// number of non-mapping members // number of non-mapping members
if (m_arguments.size() != 1) if (m_arguments.size() != 1)
@ -384,15 +386,15 @@ void FunctionCall::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
m_type = type->getActualType(); m_type = type->getActualType();
} }
else if (category == Type::Category::FUNCTION) else
{ {
//@todo would be nice to create a struct type from the arguments //@todo would be nice to create a struct type from the arguments
// and then ask if that is implicitly convertible to the struct represented by the // and then ask if that is implicitly convertible to the struct represented by the
// function parameters // function parameters
FunctionType const* function = dynamic_cast<FunctionType const*>(&expressionType); FunctionType const* function = dynamic_cast<FunctionType const*>(expressionType);
BOOST_ASSERT(function); assert(function);
FunctionDefinition const& fun = function->getFunction(); FunctionDefinition const& fun = function->getFunction();
std::vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters(); vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters();
if (parameters.size() != m_arguments.size()) if (parameters.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
@ -401,29 +403,32 @@ void FunctionCall::checkTypeRequirements()
// @todo actually the return type should be an anonymous struct, // @todo actually the return type should be an anonymous struct,
// but we change it to the type of the first return value until we have structs // but we change it to the type of the first return value until we have structs
if (fun.getReturnParameterList()->getParameters().empty()) if (fun.getReturnParameterList()->getParameters().empty())
m_type = std::make_shared<VoidType>(); m_type = make_shared<VoidType>();
else else
m_type = fun.getReturnParameterList()->getParameters().front()->getType(); m_type = fun.getReturnParameterList()->getParameters().front()->getType();
} }
else }
BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation."));
bool FunctionCall::isTypeConversion() const
{
return m_expression->getType()->getCategory() == Type::Category::TYPE;
} }
void MemberAccess::checkTypeRequirements() void MemberAccess::checkTypeRequirements()
{ {
BOOST_ASSERT(false); // not yet implemented assert(false); // not yet implemented
// m_type = ; // m_type = ;
} }
void IndexAccess::checkTypeRequirements() void IndexAccess::checkTypeRequirements()
{ {
BOOST_ASSERT(false); // not yet implemented assert(false); // not yet implemented
// m_type = ; // m_type = ;
} }
void Identifier::checkTypeRequirements() void Identifier::checkTypeRequirements()
{ {
BOOST_ASSERT(m_referencedDeclaration); assert(m_referencedDeclaration);
//@todo these dynamic casts here are not really nice... //@todo these dynamic casts here are not really nice...
// is i useful to have an AST visitor here? // is i useful to have an AST visitor here?
// or can this already be done in NameAndTypeResolver? // or can this already be done in NameAndTypeResolver?
@ -446,7 +451,7 @@ void Identifier::checkTypeRequirements()
if (structDef) if (structDef)
{ {
// note that we do not have a struct type here // note that we do not have a struct type here
m_type = std::make_shared<TypeType>(std::make_shared<StructType>(*structDef)); m_type = make_shared<TypeType>(make_shared<StructType>(*structDef));
return; return;
} }
FunctionDefinition* functionDef = dynamic_cast<FunctionDefinition*>(m_referencedDeclaration); FunctionDefinition* functionDef = dynamic_cast<FunctionDefinition*>(m_referencedDeclaration);
@ -455,21 +460,21 @@ void Identifier::checkTypeRequirements()
// a function reference is not a TypeType, because calling a TypeType converts to the type. // a function reference is not a TypeType, because calling a TypeType converts to the type.
// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
// conversion. // conversion.
m_type = std::make_shared<FunctionType>(*functionDef); m_type = make_shared<FunctionType>(*functionDef);
return; return;
} }
ContractDefinition* contractDef = dynamic_cast<ContractDefinition*>(m_referencedDeclaration); ContractDefinition* contractDef = dynamic_cast<ContractDefinition*>(m_referencedDeclaration);
if (contractDef) if (contractDef)
{ {
m_type = std::make_shared<TypeType>(std::make_shared<ContractType>(*contractDef)); m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef));
return; return;
} }
BOOST_ASSERT(false); // declaration reference of unknown/forbidden type assert(false); // declaration reference of unknown/forbidden type
} }
void ElementaryTypeNameExpression::checkTypeRequirements() void ElementaryTypeNameExpression::checkTypeRequirements()
{ {
m_type = std::make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken)); m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
} }
void Literal::checkTypeRequirements() void Literal::checkTypeRequirements()

163
libsolidity/AST.h

@ -40,6 +40,12 @@ namespace solidity
class ASTVisitor; class ASTVisitor;
/**
* The root (abstract) class of the AST inheritance tree.
* It is possible to traverse all direct and indirect children of an AST node by calling
* accept, providing an ASTVisitor.
*/
class ASTNode: private boost::noncopyable class ASTNode: private boost::noncopyable
{ {
public: public:
@ -55,28 +61,45 @@ public:
element->accept(_visitor); element->accept(_visitor);
} }
/// Returns the source code location of this node.
Location const& getLocation() const { return m_location; } Location const& getLocation() const { return m_location; }
/// Creates a @ref TypeError exception and decorates it with the location of the node and /// Creates a @ref TypeError exception and decorates it with the location of the node and
/// the given description /// the given description
TypeError createTypeError(std::string const& _description); TypeError createTypeError(std::string const& _description);
///@{
///@name equality operators
/// Equality relies on the fact that nodes cannot be copied.
bool operator==(ASTNode const& _other) const { return this == &_other; }
bool operator!=(ASTNode const& _other) const { return !operator==(_other); }
///@}
private: private:
Location m_location; Location m_location;
}; };
/**
* Abstract AST class for a declaration (contract, function, struct, variable).
*/
class Declaration: public ASTNode class Declaration: public ASTNode
{ {
public: public:
Declaration(Location const& _location, ASTPointer<ASTString> const& _name): Declaration(Location const& _location, ASTPointer<ASTString> const& _name):
ASTNode(_location), m_name(_name) {} ASTNode(_location), m_name(_name) {}
const ASTString& getName() const { return *m_name; } /// Returns the declared name.
ASTString const& getName() const { return *m_name; }
private: private:
ASTPointer<ASTString> m_name; ASTPointer<ASTString> m_name;
}; };
/**
* Definition of a contract. This is the only AST nodes where child nodes are not visited in
* document order. It first visits all struct declarations, then all variable declarations and
* finally all function declarations.
*/
class ContractDefinition: public Declaration class ContractDefinition: public Declaration
{ {
public: public:
@ -116,9 +139,11 @@ private:
std::vector<ASTPointer<VariableDeclaration>> m_members; std::vector<ASTPointer<VariableDeclaration>> m_members;
}; };
/// Used as function parameter list and return list /**
/// None of the parameters is allowed to contain mappings (not even recursively * Parameter list, used as function parameter list and return list.
/// inside structs) * None of the parameters is allowed to contain mappings (not even recursively
* inside structs), but (@todo) this is not yet enforced.
*/
class ParameterList: public ASTNode class ParameterList: public ASTNode
{ {
public: public:
@ -161,6 +186,10 @@ private:
ASTPointer<Block> m_body; ASTPointer<Block> m_body;
}; };
/**
* Declaration of a variable. This can be used in various places, e.g. in function parameter
* lists, struct definitions and even function bodys.
*/
class VariableDeclaration: public Declaration class VariableDeclaration: public Declaration
{ {
public: public:
@ -172,30 +201,38 @@ public:
bool isTypeGivenExplicitly() const { return bool(m_typeName); } bool isTypeGivenExplicitly() const { return bool(m_typeName); }
TypeName* getTypeName() const { return m_typeName.get(); } TypeName* getTypeName() const { return m_typeName.get(); }
//! Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
//! declared and there is no assignment to the variable that fixes the type. /// declared and there is no assignment to the variable that fixes the type.
std::shared_ptr<Type const> const& getType() const { return m_type; } std::shared_ptr<Type const> const& getType() const { return m_type; }
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; } void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
private: private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var") ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
std::shared_ptr<Type const> m_type; std::shared_ptr<Type const> m_type; ///< derived type, initially empty
}; };
/// types /// Types
/// @{ /// @{
/**
* Abstract base class of a type name, can be any built-in or user-defined type.
*/
class TypeName: public ASTNode class TypeName: public ASTNode
{ {
public: public:
explicit TypeName(Location const& _location): ASTNode(_location) {} explicit TypeName(Location const& _location): ASTNode(_location) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
/// Retrieve the element of the type hierarchy this node refers to. Can return an empty shared
/// pointer until the types have been resolved using the @ref NameAndTypeResolver.
virtual std::shared_ptr<Type> toType() = 0; virtual std::shared_ptr<Type> toType() = 0;
}; };
/// any pre-defined type that is not a mapping /**
* Any pre-defined type name represented by a single keyword, i.e. it excludes mappings,
* contracts, functions, etc.
*/
class ElementaryTypeName: public TypeName class ElementaryTypeName: public TypeName
{ {
public: public:
@ -204,12 +241,16 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual std::shared_ptr<Type> toType() override { return Type::fromElementaryTypeName(m_type); } virtual std::shared_ptr<Type> toType() override { return Type::fromElementaryTypeName(m_type); }
Token::Value getType() const { return m_type; } Token::Value getTypeName() const { return m_type; }
private: private:
Token::Value m_type; Token::Value m_type;
}; };
/**
* Name referring to a user-defined type (i.e. a struct).
* @todo some changes are necessary if this is also used to refer to contract types later
*/
class UserDefinedTypeName: public TypeName class UserDefinedTypeName: public TypeName
{ {
public: public:
@ -218,7 +259,7 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual std::shared_ptr<Type> toType() override { return Type::fromUserDefinedTypeName(*this); } virtual std::shared_ptr<Type> toType() override { return Type::fromUserDefinedTypeName(*this); }
const ASTString& getName() const { return *m_name; } ASTString const& getName() const { return *m_name; }
void setReferencedStruct(StructDefinition& _referencedStruct) { m_referencedStruct = &_referencedStruct; } void setReferencedStruct(StructDefinition& _referencedStruct) { m_referencedStruct = &_referencedStruct; }
StructDefinition const* getReferencedStruct() const { return m_referencedStruct; } StructDefinition const* getReferencedStruct() const { return m_referencedStruct; }
@ -228,6 +269,9 @@ private:
StructDefinition* m_referencedStruct; StructDefinition* m_referencedStruct;
}; };
/**
* A mapping type. Its source form is "mapping('keyType' => 'valueType')"
*/
class Mapping: public TypeName class Mapping: public TypeName
{ {
public: public:
@ -247,23 +291,30 @@ private:
/// Statements /// Statements
/// @{ /// @{
/**
* Abstract base class for statements.
*/
class Statement: public ASTNode class Statement: public ASTNode
{ {
public: public:
explicit Statement(Location const& _location): ASTNode(_location) {} explicit Statement(Location const& _location): ASTNode(_location) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
//! Check all type requirements, throws exception if some requirement is not met. /// Check all type requirements, throws exception if some requirement is not met.
//! For expressions, this also returns the inferred type of the expression. For other /// This includes checking that operators are applicable to their arguments but also that
//! statements, returns the empty pointer. /// the number of function call arguments matches the number of formal parameters and so forth.
virtual void checkTypeRequirements() = 0; virtual void checkTypeRequirements() = 0;
protected: protected:
//! Check that the inferred type for _expression is _expectedType or at least implicitly /// Helper function, check that the inferred type for @a _expression is @a _expectedType or at
//! convertible to _expectedType. If not, throw exception. /// least implicitly convertible to @a _expectedType. If not, throw exception.
void expectType(Expression& _expression, Type const& _expectedType); void expectType(Expression& _expression, Type const& _expectedType);
}; };
/**
* Brace-enclosed block containing zero or more statements.
*/
class Block: public Statement class Block: public Statement
{ {
public: public:
@ -277,6 +328,10 @@ private:
std::vector<ASTPointer<Statement>> m_statements; std::vector<ASTPointer<Statement>> m_statements;
}; };
/**
* If-statement with an optional "else" part. Note that "else if" is modeled by having a new
* if-statement as the false (else) body.
*/
class IfStatement: public Statement class IfStatement: public Statement
{ {
public: public:
@ -290,9 +345,13 @@ public:
private: private:
ASTPointer<Expression> m_condition; ASTPointer<Expression> m_condition;
ASTPointer<Statement> m_trueBody; ASTPointer<Statement> m_trueBody;
ASTPointer<Statement> m_falseBody; //< "else" part, optional ASTPointer<Statement> m_falseBody; ///< "else" part, optional
}; };
/**
* Statement in which a break statement is legal.
* @todo actually check this requirement.
*/
class BreakableStatement: public Statement class BreakableStatement: public Statement
{ {
public: public:
@ -341,11 +400,17 @@ public:
void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; }
private: private:
ASTPointer<Expression> m_expression; //< value to return, optional ASTPointer<Expression> m_expression; ///< value to return, optional
ParameterList* m_returnParameters; //< extracted from the function declaration /// Pointer to the parameter list of the function, filled by the @ref NameAndTypeResolver.
ParameterList* m_returnParameters;
}; };
/**
* Definition of a variable as a statement inside a function. It requires a type name (which can
* also be "var") but the actual assignment can be missing.
* Examples: var a = 2; uint256 a;
*/
class VariableDefinition: public Statement class VariableDefinition: public Statement
{ {
public: public:
@ -357,17 +422,22 @@ public:
private: private:
ASTPointer<VariableDeclaration> m_variable; ASTPointer<VariableDeclaration> m_variable;
ASTPointer<Expression> m_value; ///< can be missing ASTPointer<Expression> m_value; ///< the assigned value, can be missing
}; };
/**
* An expression, i.e. something that has a value (which can also be of type "void" in case
* of function calls).
*/
class Expression: public Statement class Expression: public Statement
{ {
public: public:
Expression(Location const& _location): Statement(_location) {} Expression(Location const& _location): Statement(_location) {}
std::shared_ptr<Type const> const& getType() const { return m_type; } std::shared_ptr<Type const> const& getType() const { return m_type; }
protected: protected:
//! Inferred type of the expression, only filled after a call to checkTypeRequirements(). /// Inferred type of the expression, only filled after a call to checkTypeRequirements().
std::shared_ptr<Type const> m_type; std::shared_ptr<Type const> m_type;
}; };
@ -376,6 +446,10 @@ protected:
/// Expressions /// Expressions
/// @{ /// @{
/**
* Assignment, can also be a compound assignment.
* Examples: (a = 7 + 8) or (a *= 2)
*/
class Assignment: public Expression class Assignment: public Expression
{ {
public: public:
@ -386,7 +460,9 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
Expression& getLeftHandSide() const { return *m_leftHandSide; }
Token::Value getAssignmentOperator() const { return m_assigmentOperator; } Token::Value getAssignmentOperator() const { return m_assigmentOperator; }
Expression& getRightHandSide() const { return *m_rightHandSide; }
private: private:
ASTPointer<Expression> m_leftHandSide; ASTPointer<Expression> m_leftHandSide;
@ -394,6 +470,10 @@ private:
ASTPointer<Expression> m_rightHandSide; ASTPointer<Expression> m_rightHandSide;
}; };
/**
* Operation involving a unary operator, pre- or postfix.
* Examples: ++i, delete x or !true
*/
class UnaryOperation: public Expression class UnaryOperation: public Expression
{ {
public: public:
@ -413,6 +493,10 @@ private:
bool m_isPrefix; bool m_isPrefix;
}; };
/**
* Operation involving a binary operator.
* Examples: 1 + 2, true && false or 1 <= 4
*/
class BinaryOperation: public Expression class BinaryOperation: public Expression
{ {
public: public:
@ -422,6 +506,8 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
Expression& getLeftExpression() const { return *m_left; }
Expression& getRightExpression() const { return *m_right; }
Token::Value getOperator() const { return m_operator; } Token::Value getOperator() const { return m_operator; }
private: private:
@ -432,7 +518,9 @@ private:
std::shared_ptr<Type const> m_commonType; std::shared_ptr<Type const> m_commonType;
}; };
/// Can be ordinary function call, type cast or struct construction. /**
* Can be ordinary function call, type cast or struct construction.
*/
class FunctionCall: public Expression class FunctionCall: public Expression
{ {
public: public:
@ -442,11 +530,18 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
/// Returns true if this is not an actual function call, but an explicit type conversion
/// or constructor call.
bool isTypeConversion() const;
private: private:
ASTPointer<Expression> m_expression; ASTPointer<Expression> m_expression;
std::vector<ASTPointer<Expression>> m_arguments; std::vector<ASTPointer<Expression>> m_arguments;
}; };
/**
* Access to a member of an object. Example: x.name
*/
class MemberAccess: public Expression class MemberAccess: public Expression
{ {
public: public:
@ -454,7 +549,7 @@ public:
ASTPointer<ASTString> const& _memberName): ASTPointer<ASTString> const& _memberName):
Expression(_location), m_expression(_expression), m_memberName(_memberName) {} Expression(_location), m_expression(_expression), m_memberName(_memberName) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
const ASTString& getMemberName() const { return *m_memberName; } ASTString const& getMemberName() const { return *m_memberName; }
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
private: private:
@ -462,6 +557,9 @@ private:
ASTPointer<ASTString> m_memberName; ASTPointer<ASTString> m_memberName;
}; };
/**
* Index access to an array. Example: a[2]
*/
class IndexAccess: public Expression class IndexAccess: public Expression
{ {
public: public:
@ -476,12 +574,19 @@ private:
ASTPointer<Expression> m_index; ASTPointer<Expression> m_index;
}; };
/**
* Primary expression, i.e. an expression that cannot be divided any further. Examples are literals
* or variable references.
*/
class PrimaryExpression: public Expression class PrimaryExpression: public Expression
{ {
public: public:
PrimaryExpression(Location const& _location): Expression(_location) {} PrimaryExpression(Location const& _location): Expression(_location) {}
}; };
/**
* An identifier, i.e. a reference to a declaration by name like a variable or function.
*/
class Identifier: public PrimaryExpression class Identifier: public PrimaryExpression
{ {
public: public:
@ -491,16 +596,22 @@ public:
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
ASTString const& getName() const { return *m_name; } ASTString const& getName() const { return *m_name; }
void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; }
Declaration* getReferencedDeclaration() { return m_referencedDeclaration; } Declaration* getReferencedDeclaration() { return m_referencedDeclaration; }
private: private:
ASTPointer<ASTString> m_name; ASTPointer<ASTString> m_name;
//! Declaration the name refers to. /// Declaration the name refers to.
Declaration* m_referencedDeclaration; Declaration* m_referencedDeclaration;
}; };
/**
* An elementary type name expression is used in expressions like "a = uint32(2)" to change the
* type of an expression explicitly. Here, "uint32" is the elementary type name expression and
* "uint32(2)" is a @ref FunctionCall.
*/
class ElementaryTypeNameExpression: public PrimaryExpression class ElementaryTypeNameExpression: public PrimaryExpression
{ {
public: public:
@ -515,6 +626,9 @@ private:
Token::Value m_typeToken; Token::Value m_typeToken;
}; };
/**
* A literal string or number. @see Type::literalToBigEndian is used to actually parse its value.
*/
class Literal: public PrimaryExpression class Literal: public PrimaryExpression
{ {
public: public:
@ -524,6 +638,7 @@ public:
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
Token::Value getToken() const { return m_token; } Token::Value getToken() const { return m_token; }
/// @returns the non-parsed value of the literal
ASTString const& getValue() const { return *m_value; } ASTString const& getValue() const { return *m_value; }
private: private:

30
libsolidity/ASTPrinter.cpp

@ -23,17 +23,19 @@
#include <libsolidity/ASTPrinter.h> #include <libsolidity/ASTPrinter.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
using namespace std;
namespace dev namespace dev
{ {
namespace solidity namespace solidity
{ {
ASTPrinter::ASTPrinter(ASTPointer<ASTNode> const& _ast, std::string const& _source): ASTPrinter::ASTPrinter(ASTPointer<ASTNode> const& _ast, string const& _source):
m_indentation(0), m_source(_source), m_ast(_ast) m_indentation(0), m_source(_source), m_ast(_ast)
{ {
} }
void ASTPrinter::print(std::ostream& _stream) void ASTPrinter::print(ostream& _stream)
{ {
m_ostream = &_stream; m_ostream = &_stream;
m_ast->accept(*this); m_ast->accept(*this);
@ -87,7 +89,7 @@ bool ASTPrinter::visit(TypeName& _node)
bool ASTPrinter::visit(ElementaryTypeName& _node) bool ASTPrinter::visit(ElementaryTypeName& _node)
{ {
writeLine(std::string("ElementaryTypeName ") + Token::toString(_node.getType())); writeLine(string("ElementaryTypeName ") + Token::toString(_node.getTypeName()));
printSourcePart(_node); printSourcePart(_node);
return goDeeper(); return goDeeper();
} }
@ -179,7 +181,7 @@ bool ASTPrinter::visit(Expression& _node)
bool ASTPrinter::visit(Assignment& _node) bool ASTPrinter::visit(Assignment& _node)
{ {
writeLine(std::string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); writeLine(string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator()));
printType(_node); printType(_node);
printSourcePart(_node); printSourcePart(_node);
return goDeeper(); return goDeeper();
@ -187,7 +189,7 @@ bool ASTPrinter::visit(Assignment& _node)
bool ASTPrinter::visit(UnaryOperation& _node) bool ASTPrinter::visit(UnaryOperation& _node)
{ {
writeLine(std::string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") +
") " + Token::toString(_node.getOperator())); ") " + Token::toString(_node.getOperator()));
printType(_node); printType(_node);
printSourcePart(_node); printSourcePart(_node);
@ -196,7 +198,7 @@ bool ASTPrinter::visit(UnaryOperation& _node)
bool ASTPrinter::visit(BinaryOperation& _node) bool ASTPrinter::visit(BinaryOperation& _node)
{ {
writeLine(std::string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator()));
printType(_node); printType(_node);
printSourcePart(_node); printSourcePart(_node);
return goDeeper(); return goDeeper();
@ -236,7 +238,7 @@ bool ASTPrinter::visit(PrimaryExpression& _node)
bool ASTPrinter::visit(Identifier& _node) bool ASTPrinter::visit(Identifier& _node)
{ {
writeLine(std::string("Identifier ") + _node.getName()); writeLine(string("Identifier ") + _node.getName());
printType(_node); printType(_node);
printSourcePart(_node); printSourcePart(_node);
return goDeeper(); return goDeeper();
@ -244,7 +246,7 @@ bool ASTPrinter::visit(Identifier& _node)
bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) bool ASTPrinter::visit(ElementaryTypeNameExpression& _node)
{ {
writeLine(std::string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken()));
printType(_node); printType(_node);
printSourcePart(_node); printSourcePart(_node);
return goDeeper(); return goDeeper();
@ -255,7 +257,7 @@ bool ASTPrinter::visit(Literal& _node)
char const* tokenString = Token::toString(_node.getToken()); char const* tokenString = Token::toString(_node.getToken());
if (!tokenString) if (!tokenString)
tokenString = "[no token]"; tokenString = "[no token]";
writeLine(std::string("Literal, token: ") + tokenString + " value: " + _node.getValue()); writeLine(string("Literal, token: ") + tokenString + " value: " + _node.getValue());
printType(_node); printType(_node);
printSourcePart(_node); printSourcePart(_node);
return goDeeper(); return goDeeper();
@ -417,7 +419,7 @@ void ASTPrinter::printSourcePart(ASTNode const& _node)
{ {
Location const& location(_node.getLocation()); Location const& location(_node.getLocation());
*m_ostream << getIndentation() << " Source: |" *m_ostream << getIndentation() << " Source: |"
<< m_source.substr(location.start, location.end - location.start) << "|" << std::endl; << m_source.substr(location.start, location.end - location.start) << "|" << endl;
} }
} }
@ -429,14 +431,14 @@ void ASTPrinter::printType(Expression const& _expression)
*m_ostream << getIndentation() << " Type unknown.\n"; *m_ostream << getIndentation() << " Type unknown.\n";
} }
std::string ASTPrinter::getIndentation() const string ASTPrinter::getIndentation() const
{ {
return std::string(m_indentation * 2, ' '); return string(m_indentation * 2, ' ');
} }
void ASTPrinter::writeLine(std::string const& _line) void ASTPrinter::writeLine(string const& _line)
{ {
*m_ostream << getIndentation() << _line << std::endl; *m_ostream << getIndentation() << _line << endl;
} }
} }

5
libsolidity/ASTPrinter.h

@ -30,12 +30,15 @@ namespace dev
namespace solidity namespace solidity
{ {
/**
* Pretty-printer for the abstract syntax tree (the "pretty" is arguable) for debugging purposes.
*/
class ASTPrinter: public ASTVisitor class ASTPrinter: public ASTVisitor
{ {
public: public:
/// Create a printer for the given abstract syntax tree. If the source is specified, /// Create a printer for the given abstract syntax tree. If the source is specified,
/// the corresponding parts of the source are printed with each node. /// the corresponding parts of the source are printed with each node.
ASTPrinter(ASTPointer<ASTNode> const& _ast, const std::string& _source = std::string()); ASTPrinter(ASTPointer<ASTNode> const& _ast, std::string const& _source = std::string());
/// Output the string representation of the AST to _stream. /// Output the string representation of the AST to _stream.
void print(std::ostream& _stream); void print(std::ostream& _stream);

12
libsolidity/ASTVisitor.h

@ -30,13 +30,17 @@ namespace dev
namespace solidity namespace solidity
{ {
/**
* Visitor interface for the abstract syntax tree. This class is tightly bound to the
* implementation of @ref ASTNode::accept and its overrides. After a call to
* @ref ASTNode::accept, the function visit for the appropriate parameter is called and then
* (if it returns true) this continues recursively for all child nodes in document order
* (there is an exception for contracts). After all child nodes have been visited, endVisit is
* called for the node.
*/
class ASTVisitor class ASTVisitor
{ {
public: public:
/// These functions are called after a call to ASTNode::accept,
/// first visit, then (if visit returns true) recursively for all
/// child nodes in document order (exception for contracts) and then
/// endVisit.
virtual bool visit(ASTNode&) { return true; } virtual bool visit(ASTNode&) { return true; }
virtual bool visit(ContractDefinition&) { return true; } virtual bool visit(ContractDefinition&) { return true; }
virtual bool visit(StructDefinition&) { return true; } virtual bool visit(StructDefinition&) { return true; }

6
libsolidity/BaseTypes.h

@ -29,8 +29,10 @@ namespace dev
namespace solidity namespace solidity
{ {
/// Representation of an interval of source positions. /**
/// The interval includes start and excludes end. * Representation of an interval of source positions.
* The interval includes start and excludes end.
*/
struct Location struct Location
{ {
Location(int _start, int _end): start(_start), end(_end) { } Location(int _start, int _end): start(_start), end(_end) { }

401
libsolidity/Compiler.cpp

@ -0,0 +1,401 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity AST to EVM bytecode compiler.
*/
#include <cassert>
#include <utility>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>
namespace dev {
namespace solidity {
void CompilerContext::setLabelPosition(uint32_t _label, uint32_t _position)
{
assert(m_labelPositions.find(_label) == m_labelPositions.end());
m_labelPositions[_label] = _position;
}
uint32_t CompilerContext::getLabelPosition(uint32_t _label) const
{
auto iter = m_labelPositions.find(_label);
assert(iter != m_labelPositions.end());
return iter->second;
}
void ExpressionCompiler::compile(Expression& _expression)
{
m_assemblyItems.clear();
_expression.accept(*this);
}
bytes ExpressionCompiler::getAssembledBytecode() const
{
bytes assembled;
assembled.reserve(m_assemblyItems.size());
// resolve label references
for (uint32_t pos = 0; pos < m_assemblyItems.size(); ++pos)
{
AssemblyItem const& item = m_assemblyItems[pos];
if (item.getType() == AssemblyItem::Type::LABEL)
m_context.setLabelPosition(item.getLabel(), pos + 1);
}
for (AssemblyItem const& item: m_assemblyItems)
if (item.getType() == AssemblyItem::Type::LABELREF)
assembled.push_back(m_context.getLabelPosition(item.getLabel()));
else
assembled.push_back(item.getData());
return assembled;
}
AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context,
Expression& _expression)
{
ExpressionCompiler compiler(_context);
compiler.compile(_expression);
return compiler.getAssemblyItems();
}
void ExpressionCompiler::endVisit(Assignment& _assignment)
{
Expression& rightHandSide = _assignment.getRightHandSide();
Token::Value op = _assignment.getAssignmentOperator();
if (op != Token::ASSIGN)
{
// compound assignment
// @todo retrieve lvalue value
rightHandSide.accept(*this);
Type const& resultType = *_assignment.getType();
cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType);
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType);
}
else
rightHandSide.accept(*this);
// @todo store value
}
void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
{
//@todo type checking and creating code for an operator should be in the same place:
// the operator should know how to convert itself and to which types it applies, so
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
// represents the operator
switch (_unaryOperation.getOperator())
{
case Token::NOT: // !
append(eth::Instruction::ISZERO);
break;
case Token::BIT_NOT: // ~
append(eth::Instruction::NOT);
break;
case Token::DELETE: // delete
// a -> a xor a (= 0).
// @todo this should also be an assignment
// @todo semantics change for complex types
append(eth::Instruction::DUP1);
append(eth::Instruction::XOR);
break;
case Token::INC: // ++ (pre- or postfix)
// @todo this should also be an assignment
if (_unaryOperation.isPrefixOperation())
{
append(eth::Instruction::PUSH1);
append(1);
append(eth::Instruction::ADD);
}
break;
case Token::DEC: // -- (pre- or postfix)
// @todo this should also be an assignment
if (_unaryOperation.isPrefixOperation())
{
append(eth::Instruction::PUSH1);
append(1);
append(eth::Instruction::SWAP1); //@todo avoid this
append(eth::Instruction::SUB);
}
break;
case Token::ADD: // +
// unary add, so basically no-op
break;
case Token::SUB: // -
// unary -x translates into "0-x"
append(eth::Instruction::PUSH1);
append(0);
append(eth::Instruction::SUB);
break;
default:
assert(false); // invalid operation
}
}
bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
{
Expression& leftExpression = _binaryOperation.getLeftExpression();
Expression& rightExpression = _binaryOperation.getRightExpression();
Type const& resultType = *_binaryOperation.getType();
Token::Value const op = _binaryOperation.getOperator();
if (op == Token::AND || op == Token::OR)
{
// special case: short-circuiting
appendAndOrOperatorCode(_binaryOperation);
}
else if (Token::isCompareOp(op))
{
leftExpression.accept(*this);
rightExpression.accept(*this);
// the types to compare have to be the same, but the resulting type is always bool
assert(*leftExpression.getType() == *rightExpression.getType());
appendCompareOperatorCode(op, *leftExpression.getType());
}
else
{
leftExpression.accept(*this);
cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType);
rightExpression.accept(*this);
cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType);
appendOrdinaryBinaryOperatorCode(op, resultType);
}
// do not visit the child nodes, we already did that explicitly
return false;
}
void ExpressionCompiler::endVisit(FunctionCall& _functionCall)
{
if (_functionCall.isTypeConversion())
{
//@todo binary representation for all supported types (bool and int) is the same, so no-op
// here for now.
}
else
{
//@todo
}
}
void ExpressionCompiler::endVisit(MemberAccess&)
{
}
void ExpressionCompiler::endVisit(IndexAccess&)
{
}
void ExpressionCompiler::endVisit(Identifier&)
{
}
void ExpressionCompiler::endVisit(Literal& _literal)
{
switch (_literal.getType()->getCategory())
{
case Type::Category::INTEGER:
case Type::Category::BOOL:
{
bytes value = _literal.getType()->literalToBigEndian(_literal);
assert(value.size() <= 32);
assert(!value.empty());
append(static_cast<byte>(eth::Instruction::PUSH1) + static_cast<byte>(value.size() - 1));
append(value);
break;
}
default:
assert(false); // @todo
}
}
void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType)
{
// If the type of one of the operands is extended, we need to remove all
// higher-order bits that we might have ignored in previous operations.
// @todo: store in the AST whether the operand might have "dirty" higher
// order bits
if (_typeOnStack == _targetType)
return;
if (_typeOnStack.getCategory() == Type::Category::INTEGER &&
_targetType.getCategory() == Type::Category::INTEGER)
{
//@todo
}
else
{
// If we get here, there is either an implementation missing to clean higher oder bits
// for non-integer types that are explicitly convertible or we got here in error.
assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType));
assert(false); // these types should not be convertible.
}
}
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation)
{
Token::Value const op = _binaryOperation.getOperator();
assert(op == Token::OR || op == Token::AND);
_binaryOperation.getLeftExpression().accept(*this);
append(eth::Instruction::DUP1);
if (op == Token::AND)
append(eth::Instruction::NOT);
uint32_t endLabel = appendConditionalJump();
_binaryOperation.getRightExpression().accept(*this);
appendLabel(endLabel);
}
void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type)
{
if (_operator == Token::EQ || _operator == Token::NE)
{
append(eth::Instruction::EQ);
if (_operator == Token::NE)
append(eth::Instruction::NOT);
}
else
{
IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
assert(type);
bool const isSigned = type->isSigned();
// note that EVM opcodes compare like "stack[0] < stack[1]",
// but our left value is at stack[1], so everyhing is reversed.
switch (_operator)
{
case Token::GTE:
append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
append(eth::Instruction::NOT);
break;
case Token::LTE:
append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
append(eth::Instruction::NOT);
break;
case Token::GT:
append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
break;
case Token::LT:
append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
break;
default:
assert(false);
}
}
}
void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type)
{
if (Token::isArithmeticOp(_operator))
appendArithmeticOperatorCode(_operator, _type);
else if (Token::isBitOp(_operator))
appendBitOperatorCode(_operator);
else if (Token::isShiftOp(_operator))
appendShiftOperatorCode(_operator);
else
assert(false); // unknown binary operator
}
void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type)
{
IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
assert(type);
bool const isSigned = type->isSigned();
switch (_operator)
{
case Token::ADD:
append(eth::Instruction::ADD);
break;
case Token::SUB:
append(eth::Instruction::SWAP1);
append(eth::Instruction::SUB);
break;
case Token::MUL:
append(eth::Instruction::MUL);
break;
case Token::DIV:
append(isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV);
break;
case Token::MOD:
append(isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
break;
default:
assert(false);
}
}
void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
{
switch (_operator)
{
case Token::BIT_OR:
append(eth::Instruction::OR);
break;
case Token::BIT_AND:
append(eth::Instruction::AND);
break;
case Token::BIT_XOR:
append(eth::Instruction::XOR);
break;
default:
assert(false);
}
}
void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
{
switch (_operator)
{
case Token::SHL:
assert(false); //@todo
break;
case Token::SAR:
assert(false); //@todo
break;
default:
assert(false);
}
}
uint32_t ExpressionCompiler::appendConditionalJump()
{
uint32_t label = m_context.dispenseNewLabel();
append(eth::Instruction::PUSH1);
appendLabelref(label);
append(eth::Instruction::JUMPI);
return label;
}
void ExpressionCompiler::append(bytes const& _data)
{
m_assemblyItems.reserve(m_assemblyItems.size() + _data.size());
for (byte b: _data)
append(b);
}
}
}

146
libsolidity/Compiler.h

@ -0,0 +1,146 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity AST to EVM bytecode compiler.
*/
#include <libevmface/Instruction.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/Types.h>
#include <libsolidity/Token.h>
namespace dev {
namespace solidity {
/**
* A single item of compiled code that can be assembled to a single byte value in the final
* bytecode. Its main purpose is to inject jump labels and label references into the opcode stream,
* which can be resolved in the final step.
*/
class AssemblyItem
{
public:
enum class Type
{
CODE, ///< m_data is opcode, m_label is empty.
DATA, ///< m_data is actual data, m_label is empty
LABEL, ///< m_data is JUMPDEST opcode, m_label is id of label
LABELREF ///< m_data is empty, m_label is id of label
};
explicit AssemblyItem(eth::Instruction _instruction) : m_type(Type::CODE), m_data(byte(_instruction)) {}
explicit AssemblyItem(byte _data): m_type(Type::DATA), m_data(_data) {}
/// Factory functions
static AssemblyItem labelRef(uint32_t _label) { return AssemblyItem(Type::LABELREF, 0, _label); }
static AssemblyItem label(uint32_t _label) { return AssemblyItem(Type::LABEL, byte(eth::Instruction::JUMPDEST), _label); }
Type getType() const { return m_type; }
byte getData() const { return m_data; }
uint32_t getLabel() const { return m_label; }
private:
AssemblyItem(Type _type, byte _data, uint32_t _label): m_type(_type), m_data(_data), m_label(_label) {}
Type m_type;
byte m_data; ///< data to be written to the bytecode stream (or filled by a label if this is a LABELREF)
uint32_t m_label; ///< the id of a label either referenced or defined by this item
};
using AssemblyItems = std::vector<AssemblyItem>;
/**
* Context to be shared by all units that compile the same contract. Its current usage only
* concerns dispensing unique jump label IDs and storing their actual positions in the bytecode
* stream.
*/
class CompilerContext
{
public:
CompilerContext(): m_nextLabel(0) {}
uint32_t dispenseNewLabel() { return m_nextLabel++; }
void setLabelPosition(uint32_t _label, uint32_t _position);
uint32_t getLabelPosition(uint32_t _label) const;
private:
uint32_t m_nextLabel;
std::map<uint32_t, uint32_t> m_labelPositions;
};
/**
* Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream
* of EVM instructions. It needs a compiler context that is the same for the whole compilation
* unit.
*/
class ExpressionCompiler: public ASTVisitor
{
public:
ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {}
/// Compile the given expression and (re-)populate the assembly item list.
void compile(Expression& _expression);
AssemblyItems const& getAssemblyItems() const { return m_assemblyItems; }
bytes getAssembledBytecode() const;
/// Compile the given expression and return the assembly items right away.
static AssemblyItems compileExpression(CompilerContext& _context, Expression& _expression);
private:
virtual void endVisit(Assignment& _assignment) override;
virtual void endVisit(UnaryOperation& _unaryOperation) override;
virtual bool visit(BinaryOperation& _binaryOperation) override;
virtual void endVisit(FunctionCall& _functionCall) override;
virtual void endVisit(MemberAccess& _memberAccess) override;
virtual void endVisit(IndexAccess& _indexAccess) override;
virtual void endVisit(Identifier& _identifier) override;
virtual void endVisit(Literal& _literal) override;
/// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type.
void cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType);
///@{
///@name Append code for various operator types
void appendAndOrOperatorCode(BinaryOperation& _binaryOperation);
void appendCompareOperatorCode(Token::Value _operator, Type const& _type);
void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type);
void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type);
void appendBitOperatorCode(Token::Value _operator);
void appendShiftOperatorCode(Token::Value _operator);
/// @}
/// Appends a JUMPI instruction to a new label and returns the label
uint32_t appendConditionalJump();
/// Append elements to the current instruction list.
void append(eth::Instruction const& _instruction) { m_assemblyItems.push_back(AssemblyItem(_instruction)); }
void append(byte _value) { m_assemblyItems.push_back(AssemblyItem(_value)); }
void append(bytes const& _data);
void appendLabelref(byte _label) { m_assemblyItems.push_back(AssemblyItem::labelRef(_label)); }
void appendLabel(byte _label) { m_assemblyItems.push_back(AssemblyItem::label(_label)); }
AssemblyItems m_assemblyItems;
CompilerContext& m_context;
};
}
}

21
libsolidity/NameAndTypeResolver.cpp

@ -20,11 +20,12 @@
* Parser part that determines the declarations corresponding to names and the types of expressions. * Parser part that determines the declarations corresponding to names and the types of expressions.
*/ */
#include <cassert>
#include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <boost/assert.hpp>
using namespace std;
namespace dev namespace dev
{ {
@ -68,7 +69,7 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name
} }
DeclarationRegistrationHelper::DeclarationRegistrationHelper(std::map<ASTNode*, Scope>& _scopes, DeclarationRegistrationHelper::DeclarationRegistrationHelper(map<ASTNode*, Scope>& _scopes,
ASTNode& _astRoot): ASTNode& _astRoot):
m_scopes(_scopes), m_currentScope(&m_scopes[nullptr]) m_scopes(_scopes), m_currentScope(&m_scopes[nullptr])
{ {
@ -120,22 +121,22 @@ void DeclarationRegistrationHelper::endVisit(VariableDeclaration&)
void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node)
{ {
std::map<ASTNode*, Scope>::iterator iter; map<ASTNode*, Scope>::iterator iter;
bool newlyAdded; bool newlyAdded;
std::tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope));
BOOST_ASSERT(newlyAdded); assert(newlyAdded);
m_currentScope = &iter->second; m_currentScope = &iter->second;
} }
void DeclarationRegistrationHelper::closeCurrentScope() void DeclarationRegistrationHelper::closeCurrentScope()
{ {
BOOST_ASSERT(m_currentScope); assert(m_currentScope);
m_currentScope = m_currentScope->getOuterScope(); m_currentScope = m_currentScope->getEnclosingScope();
} }
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
{ {
BOOST_ASSERT(m_currentScope); assert(m_currentScope);
if (!m_currentScope->registerDeclaration(_declaration)) if (!m_currentScope->registerDeclaration(_declaration))
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
<< errinfo_comment("Identifier already declared.")); << errinfo_comment("Identifier already declared."));
@ -162,7 +163,7 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable)
bool ReferencesResolver::visit(Return& _return) bool ReferencesResolver::visit(Return& _return)
{ {
BOOST_ASSERT(m_returnParameters); assert(m_returnParameters);
_return.setFunctionReturnParameters(*m_returnParameters); _return.setFunctionReturnParameters(*m_returnParameters);
return true; return true;
} }

23
libsolidity/NameAndTypeResolver.h

@ -33,8 +33,11 @@ namespace dev
namespace solidity namespace solidity
{ {
//! Resolves name references, resolves all types and checks that all operations are valid for the /**
//! inferred types. An exception is throw on the first error. * Resolves name references, types and checks types of all expressions.
* Specifically, it checks that all operations are valid for the inferred types.
* An exception is throw on the first error.
*/
class NameAndTypeResolver: private boost::noncopyable class NameAndTypeResolver: private boost::noncopyable
{ {
public: public:
@ -46,15 +49,17 @@ public:
private: private:
void reset(); void reset();
//! Maps nodes declaring a scope to scopes, i.e. ContractDefinition, FunctionDeclaration and /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition, FunctionDeclaration and
//! StructDefinition (@todo not yet implemented), where nullptr denotes the global scope. /// StructDefinition (@todo not yet implemented), where nullptr denotes the global scope.
std::map<ASTNode*, Scope> m_scopes; std::map<ASTNode*, Scope> m_scopes;
Scope* m_currentScope; Scope* m_currentScope;
}; };
//! Traverses the given AST upon construction and fills _scopes with all declarations inside the /**
//! AST. * Traverses the given AST upon construction and fills _scopes with all declarations inside the
* AST.
*/
class DeclarationRegistrationHelper: private ASTVisitor class DeclarationRegistrationHelper: private ASTVisitor
{ {
public: public:
@ -78,8 +83,10 @@ private:
Scope* m_currentScope; Scope* m_currentScope;
}; };
//! Resolves references to declarations (of variables and types) and also establishes the link /**
//! between a return statement and the return parameter list. * Resolves references to declarations (of variables and types) and also establishes the link
* between a return statement and the return parameter list.
*/
class ReferencesResolver: private ASTVisitor class ReferencesResolver: private ASTVisitor
{ {
public: public:

13
libsolidity/Parser.h

@ -44,8 +44,8 @@ private:
/// End position of the current token /// End position of the current token
int getEndPosition() const; int getEndPosition() const;
/// Parsing functions for the AST nodes ///@{
/// @{ ///@name Parsing functions for the AST nodes
ASTPointer<ContractDefinition> parseContractDefinition(); ASTPointer<ContractDefinition> parseContractDefinition();
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic); ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
ASTPointer<StructDefinition> parseStructDefinition(); ASTPointer<StructDefinition> parseStructDefinition();
@ -64,16 +64,17 @@ private:
ASTPointer<Expression> parseLeftHandSideExpression(); ASTPointer<Expression> parseLeftHandSideExpression();
ASTPointer<Expression> parsePrimaryExpression(); ASTPointer<Expression> parsePrimaryExpression();
std::vector<ASTPointer<Expression>> parseFunctionCallArguments(); std::vector<ASTPointer<Expression>> parseFunctionCallArguments();
/// @} ///@}
///@{
///@name Helper functions
/// Helper functions
/// @{
/// If current token value is not _value, throw exception otherwise advance token. /// If current token value is not _value, throw exception otherwise advance token.
void expectToken(Token::Value _value); void expectToken(Token::Value _value);
Token::Value expectAssignmentOperator(); Token::Value expectAssignmentOperator();
ASTPointer<ASTString> expectIdentifierToken(); ASTPointer<ASTString> expectIdentifierToken();
ASTPointer<ASTString> getLiteralAndAdvance(); ASTPointer<ASTString> getLiteralAndAdvance();
/// @} ///@}
/// Creates a @ref ParserError exception and annotates it with the current position and the /// Creates a @ref ParserError exception and annotates it with the current position and the
/// given @a _description. /// given @a _description.

43
libsolidity/Scanner.cpp

@ -50,11 +50,13 @@
* Solidity scanner. * Solidity scanner.
*/ */
#include <cassert>
#include <algorithm> #include <algorithm>
#include <tuple> #include <tuple>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
using namespace std;
namespace dev namespace dev
{ {
namespace solidity namespace solidity
@ -118,7 +120,7 @@ void Scanner::reset(CharStream const& _source)
bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength) bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength)
{ {
BOOST_ASSERT(_expectedLength <= 4); // prevent overflow assert(_expectedLength <= 4); // prevent overflow
char x = 0; char x = 0;
for (int i = 0; i < _expectedLength; i++) for (int i = 0; i < _expectedLength; i++)
{ {
@ -178,7 +180,7 @@ Token::Value Scanner::skipSingleLineComment()
Token::Value Scanner::skipMultiLineComment() Token::Value Scanner::skipMultiLineComment()
{ {
BOOST_ASSERT(m_char == '*'); assert(m_char == '*');
advance(); advance();
while (!isSourcePastEndOfInput()) while (!isSourcePastEndOfInput())
{ {
@ -471,7 +473,7 @@ void Scanner::scanDecimalDigits()
Token::Value Scanner::scanNumber(bool _periodSeen) Token::Value Scanner::scanNumber(bool _periodSeen)
{ {
BOOST_ASSERT(IsDecimalDigit(m_char)); // the first digit of the number or the fraction assert(IsDecimalDigit(m_char)); // the first digit of the number or the fraction
enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
LiteralScope literal(this); LiteralScope literal(this);
if (_periodSeen) if (_periodSeen)
@ -513,7 +515,7 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
// scan exponent, if any // scan exponent, if any
if (m_char == 'e' || m_char == 'E') if (m_char == 'e' || m_char == 'E')
{ {
BOOST_ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number assert(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
if (kind != DECIMAL) return Token::ILLEGAL; if (kind != DECIMAL) return Token::ILLEGAL;
// scan exponent // scan exponent
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
@ -607,9 +609,9 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
KEYWORD("while", Token::WHILE) \ KEYWORD("while", Token::WHILE) \
static Token::Value KeywordOrIdentifierToken(std::string const& input) static Token::Value KeywordOrIdentifierToken(string const& input)
{ {
BOOST_ASSERT(!input.empty()); assert(!input.empty());
int const kMinLength = 2; int const kMinLength = 2;
int const kMaxLength = 10; int const kMaxLength = 10;
if (input.size() < kMinLength || input.size() > kMaxLength) if (input.size() < kMinLength || input.size() > kMaxLength)
@ -637,7 +639,7 @@ case ch:
Token::Value Scanner::scanIdentifierOrKeyword() Token::Value Scanner::scanIdentifierOrKeyword()
{ {
BOOST_ASSERT(IsIdentifierStart(m_char)); assert(IsIdentifierStart(m_char));
LiteralScope literal(this); LiteralScope literal(this);
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
// Scan the rest of the identifier characters. // Scan the rest of the identifier characters.
@ -659,42 +661,41 @@ char CharStream::advanceAndGet()
char CharStream::rollback(size_t _amount) char CharStream::rollback(size_t _amount)
{ {
BOOST_ASSERT(m_pos >= _amount); assert(m_pos >= _amount);
m_pos -= _amount; m_pos -= _amount;
return get(); return get();
} }
std::string CharStream::getLineAtPosition(int _position) const string CharStream::getLineAtPosition(int _position) const
{ {
// if _position points to \n, it returns the line before the \n // if _position points to \n, it returns the line before the \n
using size_type = std::string::size_type; using size_type = string::size_type;
size_type searchStart = std::min<size_type>(m_source.size(), _position); size_type searchStart = min<size_type>(m_source.size(), _position);
if (searchStart > 0) if (searchStart > 0)
searchStart--; searchStart--;
size_type lineStart = m_source.rfind('\n', searchStart); size_type lineStart = m_source.rfind('\n', searchStart);
if (lineStart == std::string::npos) if (lineStart == string::npos)
lineStart = 0; lineStart = 0;
else else
lineStart++; lineStart++;
return m_source.substr(lineStart, return m_source.substr(lineStart, min(m_source.find('\n', lineStart),
std::min(m_source.find('\n', lineStart),
m_source.size()) - lineStart); m_source.size()) - lineStart);
} }
std::tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
{ {
using size_type = std::string::size_type; using size_type = string::size_type;
size_type searchPosition = std::min<size_type>(m_source.size(), _position); size_type searchPosition = min<size_type>(m_source.size(), _position);
int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n'); int lineNumber = count(m_source.begin(), m_source.begin() + searchPosition, '\n');
size_type lineStart; size_type lineStart;
if (searchPosition == 0) if (searchPosition == 0)
lineStart = 0; lineStart = 0;
else else
{ {
lineStart = m_source.rfind('\n', searchPosition - 1); lineStart = m_source.rfind('\n', searchPosition - 1);
lineStart = lineStart == std::string::npos ? 0 : lineStart + 1; lineStart = lineStart == string::npos ? 0 : lineStart + 1;
} }
return std::tuple<int, int>(lineNumber, searchPosition - lineStart); return tuple<int, int>(lineNumber, searchPosition - lineStart);
} }

40
libsolidity/Scanner.h

@ -52,8 +52,6 @@
#pragma once #pragma once
#include <boost/assert.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
@ -81,12 +79,13 @@ public:
char advanceAndGet(); char advanceAndGet();
char rollback(size_t _amount); char rollback(size_t _amount);
///@{
///@name Error printing helper functions
/// Functions that help pretty-printing parse errors /// Functions that help pretty-printing parse errors
/// Do only use in error cases, they are quite expensive. /// Do only use in error cases, they are quite expensive.
/// @{
std::string getLineAtPosition(int _position) const; std::string getLineAtPosition(int _position) const;
std::tuple<int, int> translatePositionToLineColumn(int _position) const; std::tuple<int, int> translatePositionToLineColumn(int _position) const;
/// @} ///@}
private: private:
std::string m_source; std::string m_source;
@ -119,29 +118,31 @@ public:
/// Returns the next token and advances input. /// Returns the next token and advances input.
Token::Value next(); Token::Value next();
/// Information about the current token ///@{
/// @{ ///@name Information about the current token
/// Returns the current token /// Returns the current token
Token::Value getCurrentToken() { return m_current_token.token; } Token::Value getCurrentToken() { return m_current_token.token; }
Location getCurrentLocation() const { return m_current_token.location; } Location getCurrentLocation() const { return m_current_token.location; }
const std::string& getCurrentLiteral() const { return m_current_token.literal; } std::string const& getCurrentLiteral() const { return m_current_token.literal; }
/// @} ///@}
///@{
///@name Information about the next token
/// Information about the next token
/// @{
/// Returns the next token without advancing input. /// Returns the next token without advancing input.
Token::Value peekNextToken() const { return m_next_token.token; } Token::Value peekNextToken() const { return m_next_token.token; }
Location peekLocation() const { return m_next_token.location; } Location peekLocation() const { return m_next_token.location; }
const std::string& peekLiteral() const { return m_next_token.literal; } std::string const& peekLiteral() const { return m_next_token.literal; }
/// @} ///@}
/// Functions that help pretty-printing parse errors. ///@{
///@name Error printing helper functions
/// Functions that help pretty-printing parse errors
/// Do only use in error cases, they are quite expensive. /// Do only use in error cases, they are quite expensive.
/// @{
std::string getLineAtPosition(int _position) const { return m_source.getLineAtPosition(_position); } std::string getLineAtPosition(int _position) const { return m_source.getLineAtPosition(_position); }
std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source.translatePositionToLineColumn(_position); } std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source.translatePositionToLineColumn(_position); }
/// @} ///@}
private: private:
// Used for the current and look-ahead token. // Used for the current and look-ahead token.
@ -152,13 +153,13 @@ private:
std::string literal; std::string literal;
}; };
/// Literal buffer support ///@{
/// @{ ///@name Literal buffer support
inline void startNewLiteral() { m_next_token.literal.clear(); } inline void startNewLiteral() { m_next_token.literal.clear(); }
inline void addLiteralChar(char c) { m_next_token.literal.push_back(c); } inline void addLiteralChar(char c) { m_next_token.literal.push_back(c); }
inline void dropLiteral() { m_next_token.literal.clear(); } inline void dropLiteral() { m_next_token.literal.clear(); }
inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); }
/// @} ///@}
bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); } bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); }
void rollback(int _amount) { m_char = m_source.rollback(_amount); } void rollback(int _amount) { m_char = m_source.rollback(_amount); }
@ -169,9 +170,10 @@ private:
bool scanHexNumber(char& o_scannedNumber, int _expectedLength); bool scanHexNumber(char& o_scannedNumber, int _expectedLength);
// Scans a single JavaScript token. /// Scans a single JavaScript token.
void scanToken(); void scanToken();
/// Skips all whitespace and @returns true if something was skipped.
bool skipWhitespace(); bool skipWhitespace();
Token::Value skipSingleLineComment(); Token::Value skipSingleLineComment();
Token::Value skipMultiLineComment(); Token::Value skipMultiLineComment();

4
libsolidity/Scope.cpp

@ -41,8 +41,8 @@ Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const
auto result = m_declarations.find(_name); auto result = m_declarations.find(_name);
if (result != m_declarations.end()) if (result != m_declarations.end())
return result->second; return result->second;
if (_recursive && m_outerScope) if (_recursive && m_enclosingScope)
return m_outerScope->resolveName(_name, true); return m_enclosingScope->resolveName(_name, true);
return nullptr; return nullptr;
} }

10
libsolidity/Scope.h

@ -32,18 +32,22 @@ namespace dev
namespace solidity namespace solidity
{ {
/**
* Container that stores mappings betwee names and declarations. It also contains a link to the
* enclosing scope.
*/
class Scope class Scope
{ {
public: public:
explicit Scope(Scope* _outerScope = nullptr): m_outerScope(_outerScope) {} explicit Scope(Scope* _enclosingScope = nullptr): m_enclosingScope(_enclosingScope) {}
/// Registers the declaration in the scope unless its name is already declared. Returns true iff /// Registers the declaration in the scope unless its name is already declared. Returns true iff
/// it was not yet declared. /// it was not yet declared.
bool registerDeclaration(Declaration& _declaration); bool registerDeclaration(Declaration& _declaration);
Declaration* resolveName(ASTString const& _name, bool _recursive = false) const; Declaration* resolveName(ASTString const& _name, bool _recursive = false) const;
Scope* getOuterScope() const { return m_outerScope; } Scope* getEnclosingScope() const { return m_enclosingScope; }
private: private:
Scope* m_outerScope; Scope* m_enclosingScope;
std::map<ASTString, Declaration*> m_declarations; std::map<ASTString, Declaration*> m_declarations;
}; };

36
libsolidity/SourceReferenceFormatter.cpp

@ -24,57 +24,59 @@
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
using namespace std;
namespace dev namespace dev
{ {
namespace solidity namespace solidity
{ {
void SourceReferenceFormatter::printSourceLocation(std::ostream& _stream, void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
Location const& _location, Location const& _location,
Scanner const& _scanner) Scanner const& _scanner)
{ {
int startLine; int startLine;
int startColumn; int startColumn;
std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start);
_stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; _stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n";
int endLine; int endLine;
int endColumn; int endColumn;
std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end);
if (startLine == endLine) if (startLine == endLine)
{ {
_stream << _scanner.getLineAtPosition(_location.start) << std::endl _stream << _scanner.getLineAtPosition(_location.start) << endl
<< std::string(startColumn, ' ') << "^"; << string(startColumn, ' ') << "^";
if (endColumn > startColumn + 2) if (endColumn > startColumn + 2)
_stream << std::string(endColumn - startColumn - 2, '-'); _stream << string(endColumn - startColumn - 2, '-');
if (endColumn > startColumn + 1) if (endColumn > startColumn + 1)
_stream << "^"; _stream << "^";
_stream << std::endl; _stream << endl;
} }
else else
_stream << _scanner.getLineAtPosition(_location.start) << std::endl _stream << _scanner.getLineAtPosition(_location.start) << endl
<< std::string(startColumn, ' ') << "^\n" << string(startColumn, ' ') << "^\n"
<< "Spanning multiple lines.\n"; << "Spanning multiple lines.\n";
} }
void SourceReferenceFormatter::printSourcePosition(std::ostream& _stream, void SourceReferenceFormatter::printSourcePosition(ostream& _stream,
int _position, int _position,
const Scanner& _scanner) const Scanner& _scanner)
{ {
int line; int line;
int column; int column;
std::tie(line, column) = _scanner.translatePositionToLineColumn(_position); tie(line, column) = _scanner.translatePositionToLineColumn(_position);
_stream << "at line " << (line + 1) << ", column " << (column + 1) << std::endl _stream << "at line " << (line + 1) << ", column " << (column + 1) << endl
<< _scanner.getLineAtPosition(_position) << std::endl << _scanner.getLineAtPosition(_position) << endl
<< std::string(column, ' ') << "^" << std::endl; << string(column, ' ') << "^" << endl;
} }
void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, void SourceReferenceFormatter::printExceptionInformation(ostream& _stream,
Exception const& _exception, Exception const& _exception,
std::string const& _name, string const& _name,
Scanner const& _scanner) Scanner const& _scanner)
{ {
_stream << _name; _stream << _name;
if (std::string const* description = boost::get_error_info<errinfo_comment>(_exception)) if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
_stream << ": " << *description; _stream << ": " << *description;
if (int const* position = boost::get_error_info<errinfo_sourcePosition>(_exception)) if (int const* position = boost::get_error_info<errinfo_sourcePosition>(_exception))

20
libsolidity/Token.h

@ -42,8 +42,7 @@
#pragma once #pragma once
#include <boost/assert.hpp> #include <cassert>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
@ -225,7 +224,7 @@ public:
// (e.g. "LT" for the token LT). // (e.g. "LT" for the token LT).
static char const* getName(Value tok) static char const* getName(Value tok)
{ {
BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned assert(tok < NUM_TOKENS); // tok is unsigned
return m_name[tok]; return m_name[tok];
} }
@ -236,6 +235,7 @@ public:
static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; } static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; }
static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; } static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; }
static bool isTruncatingBinaryOp(Value op) { return BIT_OR <= op && op <= SHR; } static bool isTruncatingBinaryOp(Value op) { return BIT_OR <= op && op <= SHR; }
static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; }
static bool isCompareOp(Value op) { return EQ <= op && op <= IN; } static bool isCompareOp(Value op) { return EQ <= op && op <= IN; }
static bool isOrderedRelationalCompareOp(Value op) static bool isOrderedRelationalCompareOp(Value op)
{ {
@ -251,7 +251,7 @@ public:
static Value negateCompareOp(Value op) static Value negateCompareOp(Value op)
{ {
BOOST_ASSERT(isArithmeticCompareOp(op)); assert(isArithmeticCompareOp(op));
switch (op) switch (op)
{ {
case EQ: case EQ:
@ -267,14 +267,14 @@ public:
case GTE: case GTE:
return LT; return LT;
default: default:
BOOST_ASSERT(false); // should not get here assert(false); // should not get here
return op; return op;
} }
} }
static Value reverseCompareOp(Value op) static Value reverseCompareOp(Value op)
{ {
BOOST_ASSERT(isArithmeticCompareOp(op)); assert(isArithmeticCompareOp(op));
switch (op) switch (op)
{ {
case EQ: case EQ:
@ -290,14 +290,14 @@ public:
case GTE: case GTE:
return LTE; return LTE;
default: default:
BOOST_ASSERT(false); // should not get here assert(false); // should not get here
return op; return op;
} }
} }
static Value AssignmentToBinaryOp(Value op) static Value AssignmentToBinaryOp(Value op)
{ {
BOOST_ASSERT(isAssignmentOp(op) && op != ASSIGN); assert(isAssignmentOp(op) && op != ASSIGN);
return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR)); return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR));
} }
@ -311,7 +311,7 @@ public:
// have a (unique) string (e.g. an IDENTIFIER). // have a (unique) string (e.g. an IDENTIFIER).
static char const* toString(Value tok) static char const* toString(Value tok)
{ {
BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. assert(tok < NUM_TOKENS); // tok is unsigned.
return m_string[tok]; return m_string[tok];
} }
@ -319,7 +319,7 @@ public:
// operators; returns 0 otherwise. // operators; returns 0 otherwise.
static int precedence(Value tok) static int precedence(Value tok)
{ {
BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. assert(tok < NUM_TOKENS); // tok is unsigned.
return m_precedence[tok]; return m_precedence[tok];
} }

92
libsolidity/Types.cpp

@ -20,7 +20,9 @@
* Solidity data types * Solidity data types
*/ */
#include <cassert>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libsolidity/Types.h> #include <libsolidity/Types.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
@ -50,7 +52,7 @@ std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
else if (_typeToken == Token::BOOL) else if (_typeToken == Token::BOOL)
return std::make_shared<BoolType>(); return std::make_shared<BoolType>();
else else
BOOST_ASSERT(false); // @todo add other tyes assert(false); // @todo add other tyes
return std::shared_ptr<Type>(); return std::shared_ptr<Type>();
} }
@ -61,7 +63,7 @@ std::shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _
std::shared_ptr<Type> Type::fromMapping(Mapping const&) std::shared_ptr<Type> Type::fromMapping(Mapping const&)
{ {
BOOST_ASSERT(false); //@todo not yet implemented assert(false); //@todo not yet implemented
return std::shared_ptr<Type>(); return std::shared_ptr<Type>();
} }
@ -92,12 +94,12 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
{ {
if (isAddress()) if (isAddress())
_bits = 160; _bits = 160;
BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); assert(_bits > 0 && _bits <= 256 && _bits % 8 == 0);
} }
bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (_convertTo.getCategory() != Category::INTEGER) if (_convertTo.getCategory() != getCategory())
return false; return false;
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo); IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
if (convertTo.m_bits < m_bits) if (convertTo.m_bits < m_bits)
@ -114,7 +116,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
return _convertTo.getCategory() == Category::INTEGER; return _convertTo.getCategory() == getCategory();
} }
bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const
@ -129,7 +131,24 @@ bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const
bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const
{ {
return _operator == Token::DELETE || (!isAddress() && _operator == Token::BIT_NOT); if (_operator == Token::DELETE)
return true;
if (isAddress())
return false;
if (_operator == Token::BIT_NOT)
return true;
if (isHash())
return false;
return _operator == Token::ADD || _operator == Token::SUB ||
_operator == Token::INC || _operator == Token::DEC;
}
bool IntegerType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
IntegerType const& other = dynamic_cast<IntegerType const&>(_other);
return other.m_bits == m_bits && other.m_modifier == m_modifier;
} }
std::string IntegerType::toString() const std::string IntegerType::toString() const
@ -140,11 +159,21 @@ std::string IntegerType::toString() const
return prefix + dev::toString(m_bits); return prefix + dev::toString(m_bits);
} }
bytes IntegerType::literalToBigEndian(Literal const& _literal) const
{
bigint value(_literal.getValue());
if (!isSigned() && value < 0)
return bytes(); // @todo this should already be caught by "smallestTypeforLiteral"
//@todo check that the number of bits is correct
//@todo does "toCompactBigEndian" work for signed numbers?
return toCompactBigEndian(value);
}
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
// conversion to integer is fine, but not to address // conversion to integer is fine, but not to address
// this is an example of explicit conversions being not transitive (though implicit should be) // this is an example of explicit conversions being not transitive (though implicit should be)
if (_convertTo.getCategory() == Category::INTEGER) if (_convertTo.getCategory() == getCategory())
{ {
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo); IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
if (!convertTo.isAddress()) if (!convertTo.isAddress())
@ -153,22 +182,55 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return isImplicitlyConvertibleTo(_convertTo); return isImplicitlyConvertibleTo(_convertTo);
} }
bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const bytes BoolType::literalToBigEndian(Literal const& _literal) const
{ {
if (_convertTo.getCategory() != Category::CONTRACT) if (_literal.getToken() == Token::TRUE_LITERAL)
return bytes(1, 1);
else if (_literal.getToken() == Token::FALSE_LITERAL)
return bytes(1, 0);
else
return NullBytes;
}
bool ContractType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false; return false;
ContractType const& convertTo = dynamic_cast<ContractType const&>(_convertTo); ContractType const& other = dynamic_cast<ContractType const&>(_other);
return &m_contract == &convertTo.m_contract; return other.m_contract == m_contract;
} }
bool StructType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool StructType::operator==(Type const& _other) const
{ {
if (_convertTo.getCategory() != Category::STRUCT) if (_other.getCategory() != getCategory())
return false; return false;
StructType const& convertTo = dynamic_cast<StructType const&>(_convertTo); StructType const& other = dynamic_cast<StructType const&>(_other);
return &m_struct == &convertTo.m_struct; return other.m_struct == m_struct;
} }
bool FunctionType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
return other.m_function == m_function;
}
bool MappingType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
MappingType const& other = dynamic_cast<MappingType const&>(_other);
return *other.m_keyType == *m_keyType && *other.m_valueType == *m_valueType;
}
bool TypeType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
TypeType const& other = dynamic_cast<TypeType const&>(_other);
return *getActualType() == *other.getActualType();
}
} }
} }

68
libsolidity/Types.h

@ -25,7 +25,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <boost/assert.hpp> #include <libdevcore/Common.h>
#include <libsolidity/ASTForward.h> #include <libsolidity/ASTForward.h>
#include <libsolidity/Token.h> #include <libsolidity/Token.h>
@ -36,6 +36,9 @@ namespace solidity
// @todo realMxN, string<N>, mapping // @todo realMxN, string<N>, mapping
/**
* Abstract base class that forms the root of the type hierarchy.
*/
class Type: private boost::noncopyable class Type: private boost::noncopyable
{ {
public: public:
@ -44,15 +47,19 @@ public:
INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE
}; };
//! factory functions that convert an AST TypeName to a Type. ///@{
///@name Factory functions
/// Factory functions that convert an AST @ref TypeName to a Type.
static std::shared_ptr<Type> fromElementaryTypeName(Token::Value _typeToken); static std::shared_ptr<Type> fromElementaryTypeName(Token::Value _typeToken);
static std::shared_ptr<Type> fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); static std::shared_ptr<Type> fromUserDefinedTypeName(UserDefinedTypeName const& _typeName);
static std::shared_ptr<Type> fromMapping(Mapping const& _typeName); static std::shared_ptr<Type> fromMapping(Mapping const& _typeName);
/// @}
/// Auto-detect the proper type for a literal
static std::shared_ptr<Type> forLiteral(Literal const& _literal); static std::shared_ptr<Type> forLiteral(Literal const& _literal);
virtual Category getCategory() const = 0; virtual Category getCategory() const = 0;
virtual bool isImplicitlyConvertibleTo(Type const&) const { return false; } virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
return isImplicitlyConvertibleTo(_convertTo); return isImplicitlyConvertibleTo(_convertTo);
@ -60,9 +67,16 @@ public:
virtual bool acceptsBinaryOperator(Token::Value) const { return false; } virtual bool acceptsBinaryOperator(Token::Value) const { return false; }
virtual bool acceptsUnaryOperator(Token::Value) const { return false; } virtual bool acceptsUnaryOperator(Token::Value) const { return false; }
virtual bool operator==(Type const& _other) const { return getCategory() == _other.getCategory(); }
virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); }
virtual std::string toString() const = 0; virtual std::string toString() const = 0;
virtual bytes literalToBigEndian(Literal const&) const { return NullBytes; }
}; };
/**
* Any kind of integer type including hash and address.
*/
class IntegerType: public Type class IntegerType: public Type
{ {
public: public:
@ -81,7 +95,10 @@ public:
virtual bool acceptsBinaryOperator(Token::Value _operator) const override; virtual bool acceptsBinaryOperator(Token::Value _operator) const override;
virtual bool acceptsUnaryOperator(Token::Value _operator) const override; virtual bool acceptsUnaryOperator(Token::Value _operator) const override;
virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override; virtual std::string toString() const override;
virtual bytes literalToBigEndian(Literal const& _literal) const override;
int getNumBits() const { return m_bits; } int getNumBits() const { return m_bits; }
bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; }
@ -93,14 +110,13 @@ private:
Modifier m_modifier; Modifier m_modifier;
}; };
/**
* The boolean type.
*/
class BoolType: public Type class BoolType: public Type
{ {
public: public:
virtual Category getCategory() const { return Category::BOOL; } virtual Category getCategory() const { return Category::BOOL; }
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override
{
return _convertTo.getCategory() == Category::BOOL;
}
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool acceptsBinaryOperator(Token::Value _operator) const override virtual bool acceptsBinaryOperator(Token::Value _operator) const override
{ {
@ -110,15 +126,21 @@ public:
{ {
return _operator == Token::NOT || _operator == Token::DELETE; return _operator == Token::NOT || _operator == Token::DELETE;
} }
virtual std::string toString() const override { return "bool"; } virtual std::string toString() const override { return "bool"; }
virtual bytes literalToBigEndian(Literal const& _literal) const override;
}; };
/**
* The type of a contract instance, there is one distinct type for each contract definition.
*/
class ContractType: public Type class ContractType: public Type
{ {
public: public:
virtual Category getCategory() const override { return Category::CONTRACT; } virtual Category getCategory() const override { return Category::CONTRACT; }
ContractType(ContractDefinition const& _contract): m_contract(_contract) {} ContractType(ContractDefinition const& _contract): m_contract(_contract) {}
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const;
virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override { return "contract{...}"; } virtual std::string toString() const override { return "contract{...}"; }
@ -126,17 +148,20 @@ private:
ContractDefinition const& m_contract; ContractDefinition const& m_contract;
}; };
/**
* The type of a struct instance, there is one distinct type per struct definition.
*/
class StructType: public Type class StructType: public Type
{ {
public: public:
virtual Category getCategory() const override { return Category::STRUCT; } virtual Category getCategory() const override { return Category::STRUCT; }
StructType(StructDefinition const& _struct): m_struct(_struct) {} StructType(StructDefinition const& _struct): m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const;
virtual bool acceptsUnaryOperator(Token::Value _operator) const override virtual bool acceptsUnaryOperator(Token::Value _operator) const override
{ {
return _operator == Token::DELETE; return _operator == Token::DELETE;
} }
virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override { return "struct{...}"; } virtual std::string toString() const override { return "struct{...}"; }
@ -144,6 +169,9 @@ private:
StructDefinition const& m_struct; StructDefinition const& m_struct;
}; };
/**
* The type of a function, there is one distinct type per function definition.
*/
class FunctionType: public Type class FunctionType: public Type
{ {
public: public:
@ -154,10 +182,15 @@ public:
virtual std::string toString() const override { return "function(...)returns(...)"; } virtual std::string toString() const override { return "function(...)returns(...)"; }
virtual bool operator==(Type const& _other) const override;
private: private:
FunctionDefinition const& m_function; FunctionDefinition const& m_function;
}; };
/**
* The type of a mapping, there is one distinct type per key/value type pair.
*/
class MappingType: public Type class MappingType: public Type
{ {
public: public:
@ -165,19 +198,30 @@ public:
MappingType() {} MappingType() {}
virtual std::string toString() const override { return "mapping(...=>...)"; } virtual std::string toString() const override { return "mapping(...=>...)"; }
virtual bool operator==(Type const& _other) const override;
private: private:
//@todo std::shared_ptr<Type const> m_keyType;
std::shared_ptr<Type const> m_valueType;
}; };
//@todo should be changed into "empty anonymous struct" /**
* The void type, can only be implicitly used as the type that is returned by functions without
* return parameters.
*/
class VoidType: public Type class VoidType: public Type
{ {
public: public:
virtual Category getCategory() const override { return Category::VOID; } virtual Category getCategory() const override { return Category::VOID; }
VoidType() {} VoidType() {}
virtual std::string toString() const override { return "void"; } virtual std::string toString() const override { return "void"; }
}; };
/**
* The type of a type reference. The type of "uint32" when used in "a = uint32(2)" is an example
* of a TypeType.
*/
class TypeType: public Type class TypeType: public Type
{ {
public: public:
@ -186,6 +230,8 @@ public:
std::shared_ptr<Type const> const& getActualType() const { return m_actualType; } std::shared_ptr<Type const> const& getActualType() const { return m_actualType; }
virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
private: private:

55
libweb3jsonrpc/CMakeLists.txt

@ -0,0 +1,55 @@
cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST)
include_directories(..)
link_directories(../libethcore)
link_directories(../libwebthree)
set(EXECUTABLE web3jsonrpc)
file(GLOB HEADERS "*.h")
if(ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp)
if(MINIUPNPC_LS)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS})
target_link_libraries(${EXECUTABLE} ${JSONRPC_LS})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
if(READLINE_LS)
target_link_libraries(${EXECUTABLE} ${READLINE_LS})
endif()
if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
target_link_libraries(${EXECUTABLE} boost_system-mt-s)
target_link_libraries(${EXECUTABLE} boost_filesystem-mt-s)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
target_link_libraries(${EXECUTABLE} gcc)
target_link_libraries(${EXECUTABLE} gdi32)
target_link_libraries(${EXECUTABLE} ws2_32)
target_link_libraries(${EXECUTABLE} mswsock)
target_link_libraries(${EXECUTABLE} shlwapi)
target_link_libraries(${EXECUTABLE} iphlpapi)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
else ()
target_link_libraries(${EXECUTABLE} boost_system)
target_link_libraries(${EXECUTABLE} boost_filesystem)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

42
libweb3jsonrpc/CorsHttpServer.cpp

@ -0,0 +1,42 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CorsHttpServer.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#include "CorsHttpServer.h"
namespace jsonrpc
{
bool CorsHttpServer::SendResponse(std::string const& _response, void* _addInfo)
{
struct mg_connection* conn = (struct mg_connection*) _addInfo;
if (mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"\r\n"
"%s",(int)_response.length(), _response.c_str()) > 0)
return true;
return false;
}
}

35
libweb3jsonrpc/CorsHttpServer.h

@ -0,0 +1,35 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CorsHttpServer.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#include <jsonrpc/connectors/httpserver.h>
namespace jsonrpc
{
class CorsHttpServer : public HttpServer
{
public:
using HttpServer::HttpServer;
bool virtual SendResponse(std::string const& _response, void* _addInfo = NULL);
};
}

657
libweb3jsonrpc/WebThreeStubServer.cpp

@ -0,0 +1,657 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file WebThreeStubServer.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#include "WebThreeStubServer.h"
#include <libevmface/Instruction.h>
#include <liblll/Compiler.h>
#include <libethereum/Client.h>
#include <libwebthree/WebThree.h>
#include <libdevcore/CommonJS.h>
#include <boost/filesystem.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libwhisper/Message.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
static Json::Value toJson(dev::eth::BlockInfo const& _bi)
{
Json::Value res;
res["hash"] = boost::lexical_cast<string>(_bi.hash);
res["parentHash"] = toJS(_bi.parentHash);
res["sha3Uncles"] = toJS(_bi.sha3Uncles);
res["miner"] = toJS(_bi.coinbaseAddress);
res["stateRoot"] = toJS(_bi.stateRoot);
res["transactionsRoot"] = toJS(_bi.transactionsRoot);
res["difficulty"] = toJS(_bi.difficulty);
res["number"] = (int)_bi.number;
res["minGasPrice"] = toJS(_bi.minGasPrice);
res["gasLimit"] = (int)_bi.gasLimit;
res["timestamp"] = (int)_bi.timestamp;
res["extraData"] = jsFromBinary(_bi.extraData);
res["nonce"] = toJS(_bi.nonce);
return res;
}
static Json::Value toJson(dev::eth::PastMessage const& _t)
{
Json::Value res;
res["input"] = jsFromBinary(_t.input);
res["output"] = jsFromBinary(_t.output);
res["to"] = toJS(_t.to);
res["from"] = toJS(_t.from);
res["value"] = jsToDecimal(toJS(_t.value));
res["origin"] = toJS(_t.origin);
res["timestamp"] = toJS(_t.timestamp);
res["coinbase"] = toJS(_t.coinbase);
res["block"] = toJS(_t.block);
Json::Value path;
for (int i: _t.path)
path.append(i);
res["path"] = path;
res["number"] = (int)_t.number;
return res;
}
static Json::Value toJson(dev::eth::PastMessages const& _pms)
{
Json::Value res;
for (dev::eth::PastMessage const& t: _pms)
res.append(toJson(t));
return res;
}
static Json::Value toJson(dev::eth::Transaction const& _t)
{
Json::Value res;
res["hash"] = toJS(_t.sha3());
res["input"] = jsFromBinary(_t.data);
res["to"] = toJS(_t.receiveAddress);
res["from"] = toJS(_t.sender());
res["gas"] = (int)_t.gas;
res["gasPrice"] = toJS(_t.gasPrice);
res["nonce"] = toJS(_t.nonce);
res["value"] = toJS(_t.value);
return res;
}
static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json)
{
dev::eth::MessageFilter filter;
if (!_json.isObject() || _json.empty())
return filter;
if (!_json["earliest"].empty())
filter.withEarliest(_json["earliest"].asInt());
if (!_json["latest"].empty())
filter.withLatest(_json["lastest"].asInt());
if (!_json["max"].empty())
filter.withMax(_json["max"].asInt());
if (!_json["skip"].empty())
filter.withSkip(_json["skip"].asInt());
if (!_json["from"].empty())
{
if (_json["from"].isArray())
for (auto i : _json["from"])
filter.from(jsToAddress(i.asString()));
else
filter.from(jsToAddress(_json["from"].asString()));
}
if (!_json["to"].empty())
{
if (_json["to"].isArray())
for (auto i : _json["to"])
filter.from(jsToAddress(i.asString()));
else
filter.from(jsToAddress(_json["to"].asString()));
}
if (!_json["altered"].empty())
{
if (_json["altered"].isArray())
for (auto i: _json["altered"])
if (i.isObject())
filter.altered(jsToAddress(i["id"].asString()), jsToU256(i["at"].asString()));
else
filter.altered((jsToAddress(i.asString())));
else if (_json["altered"].isObject())
filter.altered(jsToAddress(_json["altered"]["id"].asString()), jsToU256(_json["altered"]["at"].asString()));
else
filter.altered(jsToAddress(_json["altered"].asString()));
}
return filter;
}
static shh::Message toMessage(Json::Value const& _json)
{
shh::Message ret;
if (!_json["from"].empty())
ret.setFrom(jsToPublic(_json["from"].asString()));
if (!_json["to"].empty())
ret.setTo(jsToPublic(_json["to"].asString()));
if (!_json["payload"].empty())
ret.setPayload(asBytes(_json["payload"].asString()));
return ret;
}
static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from)
{
unsigned ttl = 50;
unsigned workToProve = 50;
shh::BuildTopic bt;
if (!_json["ttl"].empty())
ttl = _json["ttl"].asInt();
if (!_json["workToProve"].empty())
workToProve = _json["workToProve"].asInt();
if (!_json["topic"].empty())
{
if (_json["topic"].isString())
bt.shift(asBytes(jsPadded(_json["topic"].asString(), 32)));
else if (_json["topic"].isArray())
for (auto i: _json["topic"])
bt.shift(asBytes(jsPadded(i.asString(), 32)));
}
return _m.seal(_from, bt, ttl, workToProve);
}
static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json)
{
shh::BuildTopicMask bt(shh::BuildTopicMask::Empty);
Public to;
if (!_json["to"].empty())
to = jsToPublic(_json["to"].asString());
if (!_json["topic"].empty())
{
if (_json["topic"].isString())
bt.shift(asBytes(jsPadded(_json["topic"].asString(), 32)));
else if (_json["topic"].isArray())
for (auto i: _json["topic"])
{
if (i.isString())
bt.shift(asBytes(jsPadded(i.asString(), 32)));
else
bt.shift();
}
}
return make_pair(bt.toTopicMask(), to);
}
static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m)
{
Json::Value res;
res["hash"] = toJS(_h);
res["expiry"] = (int)_e.expiry();
res["sent"] = (int)_e.sent();
res["ttl"] = (int)_e.ttl();
res["workProved"] = (int)_e.workProved();
res["topic"] = toJS(_e.topic());
res["payload"] = asString(_m.payload());
res["from"] = toJS(_m.from());
res["to"] = toJS(_m.to());
return res;
}
WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts):
AbstractWebThreeStubServer(_conn),
m_web3(_web3)
{
setAccounts(_accounts);
auto path = getDataDir() + "/.web3";
boost::filesystem::create_directories(path);
ldb::Options o;
o.create_if_missing = true;
ldb::DB::Open(o, path, &m_db);
}
void WebThreeStubServer::setAccounts(std::vector<dev::KeyPair> const& _accounts)
{
m_accounts.clear();
for (auto i: _accounts)
m_accounts[i.address()] = i.secret();
}
void WebThreeStubServer::setIdentities(std::vector<dev::KeyPair> const& _ids)
{
m_ids.clear();
for (auto i: _ids)
m_ids[i.pub()] = i.secret();
}
dev::eth::Interface* WebThreeStubServer::client() const
{
return m_web3.ethereum();
}
std::shared_ptr<dev::shh::Interface> WebThreeStubServer::face() const
{
return m_web3.whisper();
}
std::string WebThreeStubServer::account()
{
if (!m_accounts.empty())
return toJS(m_accounts.begin()->first);
return "";
}
Json::Value WebThreeStubServer::accounts()
{
Json::Value ret(Json::arrayValue);
for (auto i: m_accounts)
ret.append(toJS(i.first));
return ret;
}
std::string WebThreeStubServer::addToGroup(std::string const& _group, std::string const& _who)
{
(void)_group;
(void)_who;
return "";
}
std::string WebThreeStubServer::balanceAt(string const& _address)
{
int block = 0;
return toJS(client()->balanceAt(jsToAddress(_address), block));
}
Json::Value WebThreeStubServer::blockByHash(std::string const& _hash)
{
if (!client())
return "";
return toJson(client()->blockInfo(jsToFixed<32>(_hash)));
}
Json::Value WebThreeStubServer::blockByNumber(int const& _number)
{
if (!client())
return "";
return toJson(client()->blockInfo(client()->hashFromNumber(_number)));
}
static TransactionSkeleton toTransaction(Json::Value const& _json)
{
TransactionSkeleton ret;
if (!_json.isObject() || _json.empty())
return ret;
if (!_json["from"].empty())
ret.from = jsToAddress(_json["from"].asString());
if (!_json["to"].empty())
ret.to = jsToAddress(_json["to"].asString());
if (!_json["value"].empty())
ret.value = jsToU256(_json["value"].asString());
if (!_json["gas"].empty())
ret.gas = jsToU256(_json["gas"].asString());
if (!_json["gasPrice"].empty())
ret.gasPrice = jsToU256(_json["gasPrice"].asString());
if (!_json["data"].empty() || _json["code"].empty() || _json["dataclose"].empty())
{
if (_json["data"].isString())
ret.data = jsToBytes(_json["data"].asString());
else if (_json["code"].isString())
ret.data = jsToBytes(_json["code"].asString());
else if (_json["data"].isArray())
for (auto i: _json["data"])
dev::operator +=(ret.data, asBytes(jsPadded(i.asString(), 32)));
else if (_json["code"].isArray())
for (auto i: _json["code"])
dev::operator +=(ret.data, asBytes(jsPadded(i.asString(), 32)));
else if (_json["dataclose"].isArray())
for (auto i: _json["dataclose"])
dev::operator +=(ret.data, jsToBytes(i.asString()));
}
return ret;
}
std::string WebThreeStubServer::call(Json::Value const& _json)
{
std::string ret;
if (!client())
return ret;
TransactionSkeleton t = toTransaction(_json);
if (!t.from && m_accounts.size())
{
auto b = m_accounts.begin()->first;
for (auto a: m_accounts)
if (client()->balanceAt(a.first) > client()->balanceAt(b))
b = a.first;
t.from = b;
}
if (!m_accounts.count(t.from))
return ret;
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
ret = toJS(client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice));
return ret;
}
bool WebThreeStubServer::changed(int const& _id)
{
if (!client())
return false;
return client()->checkWatch(_id);
}
std::string WebThreeStubServer::codeAt(string const& _address)
{
int block = 0;
return client() ? jsFromBinary(client()->codeAt(jsToAddress(_address), block)) : "";
}
std::string WebThreeStubServer::coinbase()
{
return client() ? toJS(client()->address()) : "";
}
double WebThreeStubServer::countAt(string const& _address)
{
int block = 0;
return client() ? (double)(uint64_t)client()->countAt(jsToAddress(_address), block) : 0;
}
int WebThreeStubServer::defaultBlock()
{
return client() ? client()->getDefault() : 0;
}
std::string WebThreeStubServer::gasPrice()
{
return toJS(10 * dev::eth::szabo);
}
std::string WebThreeStubServer::get(std::string const& _name, std::string const& _key)
{
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
string ret;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
return toJS(dev::asBytes(ret));
}
Json::Value WebThreeStubServer::getMessages(int const& _id)
{
if (!client())
return Json::Value();
return toJson(client()->messages(_id));
}
std::string WebThreeStubServer::getString(std::string const& _name, std::string const& _key)
{
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
string ret;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
return ret;
}
bool WebThreeStubServer::haveIdentity(std::string const& _id)
{
return m_ids.count(jsToPublic(_id)) > 0;
}
bool WebThreeStubServer::listening()
{
return m_web3.isNetworkStarted();
}
bool WebThreeStubServer::mining()
{
return client() ? client()->isMining() : false;
}
int WebThreeStubServer::newFilter(Json::Value const& _json)
{
unsigned ret = -1;
if (!client())
return ret;
ret = client()->installWatch(toMessageFilter(_json));
return ret;
}
int WebThreeStubServer::newFilterString(std::string const& _filter)
{
unsigned ret = -1;
if (!client())
return ret;
if (_filter.compare("chain") == 0)
ret = client()->installWatch(dev::eth::ChainChangedFilter);
else if (_filter.compare("pending") == 0)
ret = client()->installWatch(dev::eth::PendingChangedFilter);
return ret;
}
std::string WebThreeStubServer::newGroup(std::string const& _id, std::string const& _who)
{
(void)_id;
(void)_who;
return "";
}
std::string WebThreeStubServer::newIdentity()
{
KeyPair kp = KeyPair::create();
m_ids[kp.pub()] = kp.secret();
return toJS(kp.pub());
}
std::string WebThreeStubServer::compile(string const& _s)
{
return toJS(dev::eth::compileLLL(_s));
}
int WebThreeStubServer::number()
{
return client() ? client()->number() + 1 : 0;
}
int WebThreeStubServer::peerCount()
{
return m_web3.peerCount();
}
bool WebThreeStubServer::post(Json::Value const& _json)
{
shh::Message m = toMessage(_json);
Secret from;
if (m.from() && m_ids.count(m.from()))
{
cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here.";
// TODO: insert validification hook here.
from = m_ids[m.from()];
}
face()->inject(toSealed(_json, m, from));
return true;
}
bool WebThreeStubServer::put(std::string const& _name, std::string const& _key, std::string const& _value)
{
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
bytes v = jsToBytes(_value);
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
return true;
}
bool WebThreeStubServer::putString(std::string const& _name, std::string const& _key, std::string const& _value)
{
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
string v = _value;
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
return true;
}
bool WebThreeStubServer::setCoinbase(std::string const& _address)
{
if (!client())
return false;
client()->setAddress(jsToAddress(_address));
return true;
}
bool WebThreeStubServer::setDefaultBlock(int const& _block)
{
if (!client())
return false;
client()->setDefault(_block);
return true;
}
bool WebThreeStubServer::setListening(bool const& _listening)
{
if (_listening)
m_web3.startNetwork();
else
m_web3.stopNetwork();
return true;
}
bool WebThreeStubServer::setMining(bool const& _mining)
{
if (!client())
return false;
if (_mining)
client()->startMining();
else
client()->stopMining();
return true;
}
Json::Value WebThreeStubServer::shhChanged(int const& _id)
{
Json::Value ret(Json::arrayValue);
auto pub = m_shhWatches[_id];
if (!pub || m_ids.count(pub))
for (h256 const& h: face()->checkWatch(_id))
{
auto e = face()->envelope(h);
shh::Message m;
if (pub)
{
cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here.";
m = e.open(m_ids[pub]);
if (!m)
continue;
}
else
m = e.open();
ret.append(toJson(h,e,m));
}
return ret;
}
int WebThreeStubServer::shhNewFilter(Json::Value const& _json)
{
auto w = toWatch(_json);
auto ret = face()->installWatch(w.first);
m_shhWatches.insert(make_pair(ret, w.second));
return ret;
}
bool WebThreeStubServer::shhUninstallFilter(int const& _id)
{
face()->uninstallWatch(_id);
return true;
}
std::string WebThreeStubServer::stateAt(string const& _address, string const& _storage)
{
int block = 0;
return client() ? toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)) : "";
}
std::string WebThreeStubServer::transact(Json::Value const& _json)
{
std::string ret;
if (!client())
return ret;
TransactionSkeleton t = toTransaction(_json);
if (!t.from && m_accounts.size())
{
auto b = m_accounts.begin()->first;
for (auto a: m_accounts)
if (client()->balanceAt(a.first) > client()->balanceAt(b))
b = a.first;
t.from = b;
}
if (!m_accounts.count(t.from))
return ret;
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
cwarn << "Silently signing transaction from address" << t.from.abridged() << ": User validation hook goes here.";
if (t.to)
// TODO: from qethereum, insert validification hook here.
client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice);
else
ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice));
client()->flushTransactions();
return ret;
}
Json::Value WebThreeStubServer::transactionByHash(std::string const& _hash, int const& _i)
{
if (!client())
return "";
return toJson(client()->transaction(jsToFixed<32>(_hash), _i));
}
Json::Value WebThreeStubServer::transactionByNumber(int const& _number, int const& _i)
{
if (!client())
return "";
return toJson(client()->transaction(client()->hashFromNumber(_number), _i));
}
Json::Value WebThreeStubServer::uncleByHash(std::string const& _hash, int const& _i)
{
if (!client())
return "";
return toJson(client()->uncle(jsToFixed<32>(_hash), _i));
}
Json::Value WebThreeStubServer::uncleByNumber(int const& _number, int const& _i)
{
if (!client())
return "";
return toJson(client()->uncle(client()->hashFromNumber(_number), _i));
}
bool WebThreeStubServer::uninstallFilter(int const& _id)
{
if (!client())
return false;
client()->uninstallWatch(_id);
return true;
}

124
libweb3jsonrpc/WebThreeStubServer.h

@ -0,0 +1,124 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file WebThreeStubServer.h
* @authors:
* Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <iostream>
#include <jsonrpc/rpc.h>
#include <libdevcrypto/Common.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "abstractwebthreestubserver.h"
#pragma GCC diagnostic pop
namespace ldb = leveldb;
namespace dev
{
class WebThreeDirect;
class KeyPair;
namespace eth
{
class Interface;
}
namespace shh
{
class Interface;
}
}
/**
* @brief JSON-RPC api implementation
* @todo filters should work on unsigned instead of int
* unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1
*/
class WebThreeStubServer: public AbstractWebThreeStubServer
{
public:
WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
virtual std::string account();
virtual Json::Value accounts();
virtual std::string addToGroup(std::string const& _group, std::string const& _who);
virtual std::string balanceAt(std::string const& _address);
virtual Json::Value blockByHash(std::string const& _hash);
virtual Json::Value blockByNumber(int const& _number);
virtual std::string call(Json::Value const& _json);
virtual bool changed(int const& _id);
virtual std::string codeAt(std::string const& _address);
virtual std::string coinbase();
virtual std::string compile(std::string const& _s);
virtual double countAt(std::string const& _address);
virtual int defaultBlock();
virtual std::string gasPrice();
virtual std::string get(std::string const& _name, std::string const& _key);
virtual Json::Value getMessages(int const& _id);
virtual std::string getString(std::string const& _name, std::string const& _key);
virtual bool haveIdentity(std::string const& _id);
virtual bool listening();
virtual bool mining();
virtual int newFilter(Json::Value const& _json);
virtual int newFilterString(std::string const& _filter);
virtual std::string newGroup(std::string const& _id, std::string const& _who);
virtual std::string newIdentity();
virtual int number();
virtual int peerCount();
virtual bool post(Json::Value const& _json);
virtual bool put(std::string const& _name, std::string const& _key, std::string const& _value);
virtual bool putString(std::string const& _name, std::string const& _key, std::string const& _value);
virtual bool setCoinbase(std::string const& _address);
virtual bool setDefaultBlock(int const& _block);
virtual bool setListening(bool const& _listening);
virtual bool setMining(bool const& _mining);
virtual Json::Value shhChanged(int const& _id);
virtual int shhNewFilter(Json::Value const& _json);
virtual bool shhUninstallFilter(int const& _id);
virtual std::string stateAt(std::string const& _address, std::string const& _storage);
virtual std::string transact(Json::Value const& _json);
virtual Json::Value transactionByHash(std::string const& _hash, int const& _i);
virtual Json::Value transactionByNumber(int const& _number, int const& _i);
virtual Json::Value uncleByHash(std::string const& _hash, int const& _i);
virtual Json::Value uncleByNumber(int const& _number, int const& _i);
virtual bool uninstallFilter(int const& _id);
void setAccounts(std::vector<dev::KeyPair> const& _accounts);
void setIdentities(std::vector<dev::KeyPair> const& _ids);
std::map<dev::Public, dev::Secret> const& ids() const { return m_ids; }
private:
dev::eth::Interface* client() const;
std::shared_ptr<dev::shh::Interface> face() const;
dev::WebThreeDirect& m_web3;
std::map<dev::Address, dev::KeyPair> m_accounts;
ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions;
ldb::DB* m_db;
std::map<dev::Public, dev::Secret> m_ids;
std::map<unsigned, dev::Public> m_shhWatches;
};

323
libweb3jsonrpc/abstractwebthreestubserver.h

@ -0,0 +1,323 @@
/**
* THIS FILE IS GENERATED BY jsonrpcstub, DO NOT CHANGE IT!!!!!
*/
#ifndef _ABSTRACTWEBTHREESTUBSERVER_H_
#define _ABSTRACTWEBTHREESTUBSERVER_H_
#include <jsonrpc/rpc.h>
class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThreeStubServer>
{
public:
AbstractWebThreeStubServer(jsonrpc::AbstractServerConnector* conn) :
jsonrpc::AbstractServer<AbstractWebThreeStubServer>(conn)
{
this->bindAndAddMethod(new jsonrpc::Procedure("account", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::accountI);
this->bindAndAddMethod(new jsonrpc::Procedure("accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::accountsI);
this->bindAndAddMethod(new jsonrpc::Procedure("addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::addToGroupI);
this->bindAndAddMethod(new jsonrpc::Procedure("balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::balanceAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("blockByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::blockByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("blockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::blockByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::callI);
this->bindAndAddMethod(new jsonrpc::Procedure("changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::changedI);
this->bindAndAddMethod(new jsonrpc::Procedure("codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::codeAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::coinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("compile", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::compileI);
this->bindAndAddMethod(new jsonrpc::Procedure("countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::countAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("defaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::defaultBlockI);
this->bindAndAddMethod(new jsonrpc::Procedure("gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::gasPriceI);
this->bindAndAddMethod(new jsonrpc::Procedure("get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::getI);
this->bindAndAddMethod(new jsonrpc::Procedure("getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::getMessagesI);
this->bindAndAddMethod(new jsonrpc::Procedure("getString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::getStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("haveIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::haveIdentityI);
this->bindAndAddMethod(new jsonrpc::Procedure("listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::listeningI);
this->bindAndAddMethod(new jsonrpc::Procedure("mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::miningI);
this->bindAndAddMethod(new jsonrpc::Procedure("newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::newFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newFilterStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("newGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newGroupI);
this->bindAndAddMethod(new jsonrpc::Procedure("newIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newIdentityI);
this->bindAndAddMethod(new jsonrpc::Procedure("number", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::numberI);
this->bindAndAddMethod(new jsonrpc::Procedure("peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::peerCountI);
this->bindAndAddMethod(new jsonrpc::Procedure("post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::postI);
this->bindAndAddMethod(new jsonrpc::Procedure("put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::putI);
this->bindAndAddMethod(new jsonrpc::Procedure("putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::putStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::setCoinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::setDefaultBlockI);
this->bindAndAddMethod(new jsonrpc::Procedure("setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setListeningI);
this->bindAndAddMethod(new jsonrpc::Procedure("setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setMiningI);
this->bindAndAddMethod(new jsonrpc::Procedure("shhChanged", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhChangedI);
this->bindAndAddMethod(new jsonrpc::Procedure("shhNewFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shhNewFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("shhUninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhUninstallFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::stateAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::transactI);
this->bindAndAddMethod(new jsonrpc::Procedure("transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::transactionByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("transactionByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::transactionByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("uncleByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uncleByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("uncleByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uncleByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uninstallFilterI);
}
inline virtual void accountI(const Json::Value& request, Json::Value& response)
{
response = this->account();
}
inline virtual void accountsI(const Json::Value& request, Json::Value& response)
{
response = this->accounts();
}
inline virtual void addToGroupI(const Json::Value& request, Json::Value& response)
{
response = this->addToGroup(request[0u].asString(), request[1u].asString());
}
inline virtual void balanceAtI(const Json::Value& request, Json::Value& response)
{
response = this->balanceAt(request[0u].asString());
}
inline virtual void blockByHashI(const Json::Value& request, Json::Value& response)
{
response = this->blockByHash(request[0u].asString());
}
inline virtual void blockByNumberI(const Json::Value& request, Json::Value& response)
{
response = this->blockByNumber(request[0u].asInt());
}
inline virtual void callI(const Json::Value& request, Json::Value& response)
{
response = this->call(request[0u]);
}
inline virtual void changedI(const Json::Value& request, Json::Value& response)
{
response = this->changed(request[0u].asInt());
}
inline virtual void codeAtI(const Json::Value& request, Json::Value& response)
{
response = this->codeAt(request[0u].asString());
}
inline virtual void coinbaseI(const Json::Value& request, Json::Value& response)
{
response = this->coinbase();
}
inline virtual void compileI(const Json::Value& request, Json::Value& response)
{
response = this->compile(request[0u].asString());
}
inline virtual void countAtI(const Json::Value& request, Json::Value& response)
{
response = this->countAt(request[0u].asString());
}
inline virtual void defaultBlockI(const Json::Value& request, Json::Value& response)
{
response = this->defaultBlock();
}
inline virtual void gasPriceI(const Json::Value& request, Json::Value& response)
{
response = this->gasPrice();
}
inline virtual void getI(const Json::Value& request, Json::Value& response)
{
response = this->get(request[0u].asString(), request[1u].asString());
}
inline virtual void getMessagesI(const Json::Value& request, Json::Value& response)
{
response = this->getMessages(request[0u].asInt());
}
inline virtual void getStringI(const Json::Value& request, Json::Value& response)
{
response = this->getString(request[0u].asString(), request[1u].asString());
}
inline virtual void haveIdentityI(const Json::Value& request, Json::Value& response)
{
response = this->haveIdentity(request[0u].asString());
}
inline virtual void listeningI(const Json::Value& request, Json::Value& response)
{
response = this->listening();
}
inline virtual void miningI(const Json::Value& request, Json::Value& response)
{
response = this->mining();
}
inline virtual void newFilterI(const Json::Value& request, Json::Value& response)
{
response = this->newFilter(request[0u]);
}
inline virtual void newFilterStringI(const Json::Value& request, Json::Value& response)
{
response = this->newFilterString(request[0u].asString());
}
inline virtual void newGroupI(const Json::Value& request, Json::Value& response)
{
response = this->newGroup(request[0u].asString(), request[1u].asString());
}
inline virtual void newIdentityI(const Json::Value& request, Json::Value& response)
{
response = this->newIdentity();
}
inline virtual void numberI(const Json::Value& request, Json::Value& response)
{
response = this->number();
}
inline virtual void peerCountI(const Json::Value& request, Json::Value& response)
{
response = this->peerCount();
}
inline virtual void postI(const Json::Value& request, Json::Value& response)
{
response = this->post(request[0u]);
}
inline virtual void putI(const Json::Value& request, Json::Value& response)
{
response = this->put(request[0u].asString(), request[1u].asString(), request[2u].asString());
}
inline virtual void putStringI(const Json::Value& request, Json::Value& response)
{
response = this->putString(request[0u].asString(), request[1u].asString(), request[2u].asString());
}
inline virtual void setCoinbaseI(const Json::Value& request, Json::Value& response)
{
response = this->setCoinbase(request[0u].asString());
}
inline virtual void setDefaultBlockI(const Json::Value& request, Json::Value& response)
{
response = this->setDefaultBlock(request[0u].asInt());
}
inline virtual void setListeningI(const Json::Value& request, Json::Value& response)
{
response = this->setListening(request[0u].asBool());
}
inline virtual void setMiningI(const Json::Value& request, Json::Value& response)
{
response = this->setMining(request[0u].asBool());
}
inline virtual void shhChangedI(const Json::Value& request, Json::Value& response)
{
response = this->shhChanged(request[0u].asInt());
}
inline virtual void shhNewFilterI(const Json::Value& request, Json::Value& response)
{
response = this->shhNewFilter(request[0u]);
}
inline virtual void shhUninstallFilterI(const Json::Value& request, Json::Value& response)
{
response = this->shhUninstallFilter(request[0u].asInt());
}
inline virtual void stateAtI(const Json::Value& request, Json::Value& response)
{
response = this->stateAt(request[0u].asString(), request[1u].asString());
}
inline virtual void transactI(const Json::Value& request, Json::Value& response)
{
response = this->transact(request[0u]);
}
inline virtual void transactionByHashI(const Json::Value& request, Json::Value& response)
{
response = this->transactionByHash(request[0u].asString(), request[1u].asInt());
}
inline virtual void transactionByNumberI(const Json::Value& request, Json::Value& response)
{
response = this->transactionByNumber(request[0u].asInt(), request[1u].asInt());
}
inline virtual void uncleByHashI(const Json::Value& request, Json::Value& response)
{
response = this->uncleByHash(request[0u].asString(), request[1u].asInt());
}
inline virtual void uncleByNumberI(const Json::Value& request, Json::Value& response)
{
response = this->uncleByNumber(request[0u].asInt(), request[1u].asInt());
}
inline virtual void uninstallFilterI(const Json::Value& request, Json::Value& response)
{
response = this->uninstallFilter(request[0u].asInt());
}
virtual std::string account() = 0;
virtual Json::Value accounts() = 0;
virtual std::string addToGroup(const std::string& param1, const std::string& param2) = 0;
virtual std::string balanceAt(const std::string& param1) = 0;
virtual Json::Value blockByHash(const std::string& param1) = 0;
virtual Json::Value blockByNumber(const int& param1) = 0;
virtual std::string call(const Json::Value& param1) = 0;
virtual bool changed(const int& param1) = 0;
virtual std::string codeAt(const std::string& param1) = 0;
virtual std::string coinbase() = 0;
virtual std::string compile(const std::string& param1) = 0;
virtual double countAt(const std::string& param1) = 0;
virtual int defaultBlock() = 0;
virtual std::string gasPrice() = 0;
virtual std::string get(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value getMessages(const int& param1) = 0;
virtual std::string getString(const std::string& param1, const std::string& param2) = 0;
virtual bool haveIdentity(const std::string& param1) = 0;
virtual bool listening() = 0;
virtual bool mining() = 0;
virtual int newFilter(const Json::Value& param1) = 0;
virtual int newFilterString(const std::string& param1) = 0;
virtual std::string newGroup(const std::string& param1, const std::string& param2) = 0;
virtual std::string newIdentity() = 0;
virtual int number() = 0;
virtual int peerCount() = 0;
virtual bool post(const Json::Value& param1) = 0;
virtual bool put(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual bool putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual bool setCoinbase(const std::string& param1) = 0;
virtual bool setDefaultBlock(const int& param1) = 0;
virtual bool setListening(const bool& param1) = 0;
virtual bool setMining(const bool& param1) = 0;
virtual Json::Value shhChanged(const int& param1) = 0;
virtual int shhNewFilter(const Json::Value& param1) = 0;
virtual bool shhUninstallFilter(const int& param1) = 0;
virtual std::string stateAt(const std::string& param1, const std::string& param2) = 0;
virtual std::string transact(const Json::Value& param1) = 0;
virtual Json::Value transactionByHash(const std::string& param1, const int& param2) = 0;
virtual Json::Value transactionByNumber(const int& param1, const int& param2) = 0;
virtual Json::Value uncleByHash(const std::string& param1, const int& param2) = 0;
virtual Json::Value uncleByNumber(const int& param1, const int& param2) = 0;
virtual bool uninstallFilter(const int& param1) = 0;
};
#endif //_ABSTRACTWEBTHREESTUBSERVER_H_

55
libweb3jsonrpc/spec.json

@ -0,0 +1,55 @@
[
{ "method": "coinbase", "params": [], "order": [], "returns" : "" },
{ "method": "setCoinbase", "params": [""], "order": [], "returns" : true },
{ "method": "listening", "params": [], "order": [], "returns" : false },
{ "method": "setListening", "params": [false], "order" : [], "returns" : true },
{ "method": "mining", "params": [], "order": [], "returns" : false },
{ "method": "setMining", "params": [false], "order" : [], "returns" : true },
{ "method": "gasPrice", "params": [], "order": [], "returns" : "" },
{ "method": "account", "params": [], "order": [], "returns" : "" },
{ "method": "accounts", "params": [], "order": [], "returns" : [] },
{ "method": "peerCount", "params": [], "order": [], "returns" : 0 },
{ "method": "defaultBlock", "params": [], "order": [], "returns" : 0},
{ "method": "setDefaultBlock", "params": [0], "order": [], "returns" : true},
{ "method": "number", "params": [], "order": [], "returns" : 0},
{ "method": "balanceAt", "params": [""], "order": [], "returns" : ""},
{ "method": "stateAt", "params": ["", ""], "order": [], "returns": ""},
{ "method": "countAt", "params": [""], "order": [], "returns" : 0.0},
{ "method": "codeAt", "params": [""], "order": [], "returns": ""},
{ "method": "transact", "params": [{}], "order": [], "returns": ""},
{ "method": "call", "params": [{}], "order": [], "returns": ""},
{ "method": "blockByHash", "params": [""],"order": [], "returns": {}},
{ "method": "blockByNumber", "params": [0],"order": [], "returns": {}},
{ "method": "transactionByHash", "params": ["", 0], "order": [], "returns": {}},
{ "method": "transactionByNumber", "params": [0, 0], "order": [], "returns": {}},
{ "method": "uncleByHash", "params": ["", 0], "order": [], "returns": {}},
{ "method": "uncleByNumber", "params": [0, 0], "order": [], "returns": {}},
{ "method": "compile", "params": [""], "order": [], "returns": ""},
{ "method": "newFilter", "params": [{}], "order": [], "returns": 0},
{ "method": "newFilterString", "params": [""], "order": [], "returns": 0},
{ "method": "uninstallFilter", "params": [0], "order": [], "returns": true},
{ "method": "changed", "params": [0], "order": [], "returns": false},
{ "method": "getMessages", "params": [0], "order": [], "returns": []},
{ "method": "put", "params": ["", "", ""], "order": [], "returns": true},
{ "method": "get", "params": ["", ""], "order": [], "returns": ""},
{ "method": "putString", "params": ["", "", ""], "order": [], "returns": true},
{ "method": "getString", "params": ["", ""], "order": [], "returns": ""},
{ "method": "post", "params": [{}], "order": [], "returns": true},
{ "method": "newIdentity", "params": [], "order": [], "returns": ""},
{ "method": "haveIdentity", "params": [""], "order": [], "returns": false},
{ "method": "newGroup", "params": ["", ""], "order": [], "returns": ""},
{ "method": "addToGroup", "params": ["", ""], "order": [], "returns": ""},
{ "method": "shhNewFilter", "params": [{}], "order": [], "returns": 0},
{ "method": "shhUninstallFilter", "params": [0], "order": [], "returns": true},
{ "method": "shhChanged", "params": [0], "order": [], "returns": []}
]

3
libwebthree/WebThree.h

@ -119,6 +119,9 @@ public:
/// Stop the network subsystem. /// Stop the network subsystem.
void stopNetwork() { m_net.stop(); } void stopNetwork() { m_net.stop(); }
/// Is network working? there may not be any peers yet.
bool isNetworkStarted() { return m_net.isStarted(); }
private: private:
std::string m_clientVersion; ///< Our end-application client's name/version. std::string m_clientVersion; ///< Our end-application client's name/version.

4
neth/CMakeLists.txt

@ -5,8 +5,6 @@ aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(..)
include_directories(${LEVELDB_ID}) include_directories(${LEVELDB_ID})
link_directories(../libethcore)
link_directories(../libethereum)
set(EXECUTABLE neth) set(EXECUTABLE neth)
add_executable(${EXECUTABLE} ${SRC_LIST}) add_executable(${EXECUTABLE} ${SRC_LIST})
@ -21,7 +19,7 @@ endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS})
if(JSONRPC_LS) if(JSONRPC_LS)
target_link_libraries(${EXECUTABLE} ${JSONRPC_LS}) target_link_libraries(${EXECUTABLE} web3jsonrpc)
endif() endif()
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")

18
neth/main.cpp

@ -33,11 +33,9 @@
#include <libevmface/Instruction.h> #include <libevmface/Instruction.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#if ETH_JSONRPC #if ETH_JSONRPC
#include <eth/EthStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <eth/EthStubServer.cpp> #include <libweb3jsonrpc/abstractwebthreestubserver.h>
#include <eth/abstractethstubserver.h> #include <libdevcore/CommonJS.h>
#include <eth/CommonJS.h>
#include <eth/CommonJS.cpp>
#endif #endif
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include "BuildInfo.h" #include "BuildInfo.h"
@ -477,11 +475,11 @@ int main(int argc, char** argv)
c.startMining(); c.startMining();
#if ETH_JSONRPC #if ETH_JSONRPC
auto_ptr<EthStubServer> jsonrpcServer; auto_ptr<WebThreeStubServer> jsonrpcServer;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3)); jsonrpcServer = auto_ptr<WebThreeStubServer>(new WebThreeStubServer(new jsonrpc::HttpServer(jsonrpc), web3, {us}));
jsonrpcServer->setKeys({us}); jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
#endif #endif
@ -554,8 +552,8 @@ int main(int argc, char** argv)
{ {
if (jsonrpc < 0) if (jsonrpc < 0)
jsonrpc = 8080; jsonrpc = 8080;
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3)); jsonrpcServer = auto_ptr<WebThreeStubServer>(new WebThreeStubServer(new jsonrpc::HttpServer(jsonrpc), web3, {us}));
jsonrpcServer->setKeys({us}); jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
else if (cmd == "jsonstop") else if (cmd == "jsonstop")

43
solc/main.cpp

@ -31,6 +31,7 @@
#include <libsolidity/ASTPrinter.h> #include <libsolidity/ASTPrinter.h>
#include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
using namespace dev; using namespace dev;
@ -55,6 +56,37 @@ void version()
exit(0); exit(0);
} }
/**
* Helper class that extracts the first expression in an AST.
*/
class FirstExpressionExtractor: private ASTVisitor
{
public:
FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); }
Expression* getExpression() const { return m_expression; }
private:
virtual bool visit(Expression& _expression) override { return checkExpression(_expression); }
virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); }
virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); }
virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); }
virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); }
virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); }
virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); }
virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); }
virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); }
virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); }
virtual bool visit(Literal& _expression) override { return checkExpression(_expression); }
bool checkExpression(Expression& _expression)
{
if (m_expression == nullptr)
m_expression = &_expression;
return false;
}
private:
Expression* m_expression;
};
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
std::string infile; std::string infile;
@ -113,5 +145,16 @@ int main(int argc, char** argv)
std::cout << "Syntax tree for the contract:" << std::endl; std::cout << "Syntax tree for the contract:" << std::endl;
dev::solidity::ASTPrinter printer(ast, sourceCode); dev::solidity::ASTPrinter printer(ast, sourceCode);
printer.print(std::cout); printer.print(std::cout);
FirstExpressionExtractor extractor(*ast);
CompilerContext context;
ExpressionCompiler compiler(context);
compiler.compile(*extractor.getExpression());
bytes instructions = compiler.getAssembledBytecode();
// debug
std::cout << "Bytecode for the first expression: " << std::endl;
std::cout << eth::disassemble(instructions) << std::endl;
return 0; return 0;
} }

6
test/CMakeLists.txt

@ -4,8 +4,6 @@ aux_source_directory(. SRC_LIST)
list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp") list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp")
include_directories(..) include_directories(..)
link_directories(../libethcore)
link_directories(../libethereum)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
add_executable(testeth ${SRC_LIST} ${HEADERS}) add_executable(testeth ${SRC_LIST} ${HEADERS})
@ -17,6 +15,10 @@ target_link_libraries(testeth secp256k1)
target_link_libraries(testeth gmp) target_link_libraries(testeth gmp)
target_link_libraries(testeth solidity) target_link_libraries(testeth solidity)
target_link_libraries(testeth ${CRYPTOPP_LS}) target_link_libraries(testeth ${CRYPTOPP_LS})
target_link_libraries(testeth webthree)
if(JSONRPC_LS)
target_link_libraries(testeth web3jsonrpc)
endif()
target_link_libraries(createRandomTest ethereum) target_link_libraries(createRandomTest ethereum)
target_link_libraries(createRandomTest ethcore) target_link_libraries(createRandomTest ethcore)

250
test/jsonrpc.cpp

@ -0,0 +1,250 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file jsonrpc.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#if ETH_JSONRPC
#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libwebthree/WebThree.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/CorsHttpServer.h>
#include <jsonrpc/connectors/httpserver.h>
#include <jsonrpc/connectors/httpclient.h>
#include <set>
#include "JsonSpiritHeaders.h"
#include "TestHelper.h"
#include "webthreestubclient.h"
BOOST_AUTO_TEST_SUITE(jsonrpc)
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;
namespace jsonrpc_tests
{
string name = "Ethereum(++) tests";
string dbPath;
auto s = set<string>{"eth", "shh"};
dev::p2p::NetworkPreferences np(30303, std::string(), false);
dev::WebThreeDirect web3(name, dbPath, true, s, np);
unique_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<WebThreeStubClient> jsonrpcClient;
struct JsonrpcFixture {
JsonrpcFixture()
{
cnote << "setup jsonrpc";
web3.setIdealPeerCount(5);
web3.ethereum()->setForceMining(true);
jsonrpcServer = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(new jsonrpc::CorsHttpServer(8080), web3, {}));
jsonrpcServer->setIdentities({});
jsonrpcServer->StartListening();
jsonrpcClient = unique_ptr<WebThreeStubClient>(new WebThreeStubClient(new jsonrpc::HttpClient("http://localhost:8080")));
}
~JsonrpcFixture()
{
cnote << "teardown jsonrpc";
}
};
BOOST_GLOBAL_FIXTURE(JsonrpcFixture)
BOOST_AUTO_TEST_CASE(jsonrpc_defaultBlock)
{
cnote << "Testing jsonrpc defaultBlock...";
int defaultBlock = jsonrpcClient->defaultBlock();
BOOST_CHECK_EQUAL(defaultBlock, web3.ethereum()->getDefault());
}
BOOST_AUTO_TEST_CASE(jsonrpc_gasPrice)
{
cnote << "Testing jsonrpc gasPrice...";
string gasPrice = jsonrpcClient->gasPrice();
BOOST_CHECK_EQUAL(gasPrice, toJS(10 * dev::eth::szabo));
}
BOOST_AUTO_TEST_CASE(jsonrpc_isListening)
{
cnote << "Testing jsonrpc isListening...";
web3.startNetwork();
bool listeningOn = jsonrpcClient->listening();
BOOST_CHECK_EQUAL(listeningOn, web3.isNetworkStarted());
web3.stopNetwork();
bool listeningOff = jsonrpcClient->listening();
BOOST_CHECK_EQUAL(listeningOff, web3.isNetworkStarted());
}
BOOST_AUTO_TEST_CASE(jsonrpc_isMining)
{
cnote << "Testing jsonrpc isMining...";
web3.ethereum()->startMining();
bool miningOn = jsonrpcClient->mining();
BOOST_CHECK_EQUAL(miningOn, web3.ethereum()->isMining());
web3.ethereum()->stopMining();
bool miningOff = jsonrpcClient->mining();
BOOST_CHECK_EQUAL(miningOff, web3.ethereum()->isMining());
}
BOOST_AUTO_TEST_CASE(jsonrpc_accounts)
{
cnote << "Testing jsonrpc accounts...";
std::vector <dev::KeyPair> keys = {KeyPair::create(), KeyPair::create()};
jsonrpcServer->setAccounts(keys);
Json::Value k = jsonrpcClient->accounts();
jsonrpcServer->setAccounts({});
BOOST_CHECK_EQUAL(k.isArray(), true);
BOOST_CHECK_EQUAL(k.size(), keys.size());
for (auto &i:k)
{
auto it = std::find_if(keys.begin(), keys.end(), [i](dev::KeyPair const& keyPair)
{
return jsToAddress(i.asString()) == keyPair.address();
});
BOOST_CHECK_EQUAL(it != keys.end(), true);
}
}
BOOST_AUTO_TEST_CASE(jsonrpc_number)
{
cnote << "Testing jsonrpc number2...";
int number = jsonrpcClient->number();
BOOST_CHECK_EQUAL(number, web3.ethereum()->number() + 1);
dev::eth::mine(*(web3.ethereum()), 1);
int numberAfter = jsonrpcClient->number();
BOOST_CHECK_EQUAL(number + 1, numberAfter);
BOOST_CHECK_EQUAL(numberAfter, web3.ethereum()->number() + 1);
}
BOOST_AUTO_TEST_CASE(jsonrpc_peerCount)
{
cnote << "Testing jsonrpc peerCount...";
int peerCount = jsonrpcClient->peerCount();
BOOST_CHECK_EQUAL(web3.peerCount(), peerCount);
}
BOOST_AUTO_TEST_CASE(jsonrpc_setListening)
{
cnote << "Testing jsonrpc setListening...";
jsonrpcClient->setListening(true);
BOOST_CHECK_EQUAL(web3.isNetworkStarted(), true);
jsonrpcClient->setListening(false);
BOOST_CHECK_EQUAL(web3.isNetworkStarted(), false);
}
BOOST_AUTO_TEST_CASE(jsonrpc_setMining)
{
cnote << "Testing jsonrpc setMining...";
jsonrpcClient->setMining(true);
BOOST_CHECK_EQUAL(web3.ethereum()->isMining(), true);
jsonrpcClient->setMining(false);
BOOST_CHECK_EQUAL(web3.ethereum()->isMining(), false);
}
BOOST_AUTO_TEST_CASE(jsonrpc_stateAt)
{
cnote << "Testing jsonrpc stateAt...";
dev::KeyPair key = KeyPair::create();
auto address = key.address();
string stateAt = jsonrpcClient->stateAt(toJS(address), "0");
BOOST_CHECK_EQUAL(toJS(web3.ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt);
}
BOOST_AUTO_TEST_CASE(jsonrpc_transact)
{
cnote << "Testing jsonrpc transact...";
string coinbase = jsonrpcClient->coinbase();
BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3.ethereum()->address());
dev::KeyPair key = KeyPair::create();
auto address = key.address();
auto receiver = KeyPair::create();
web3.ethereum()->setAddress(address);
coinbase = jsonrpcClient->coinbase();
BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3.ethereum()->address());
BOOST_CHECK_EQUAL(jsToAddress(coinbase), address);
jsonrpcServer->setAccounts({key});
auto balance = web3.ethereum()->balanceAt(address, 0);
string balanceString = jsonrpcClient->balanceAt(toJS(address));
double countAt = jsonrpcClient->countAt(toJS(address));
BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3.ethereum()->countAt(address));
BOOST_CHECK_EQUAL(countAt, 0);
BOOST_CHECK_EQUAL(toJS(balance), balanceString);
BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "0");
dev::eth::mine(*(web3.ethereum()), 1);
balance = web3.ethereum()->balanceAt(address, 0);
balanceString = jsonrpcClient->balanceAt(toJS(address));
BOOST_CHECK_EQUAL(toJS(balance), balanceString);
BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "1500000000000000000");
auto txAmount = balance / 2u;
auto gasPrice = 10 * dev::eth::szabo;
auto gas = dev::eth::c_txGas;
Json::Value t;
t["from"] = toJS(address);
t["value"] = jsToDecimal(toJS(txAmount));
t["to"] = toJS(receiver.address());
t["data"] = toJS(bytes());
t["gas"] = toJS(gas);
t["gasPrice"] = toJS(gasPrice);
jsonrpcClient->transact(t);
jsonrpcServer->setAccounts({});
dev::eth::mine(*(web3.ethereum()), 1);
countAt = jsonrpcClient->countAt(toJS(address));
auto balance2 = web3.ethereum()->balanceAt(receiver.address());
string balanceString2 = jsonrpcClient->balanceAt(toJS(receiver.address()));
BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3.ethereum()->countAt(address));
BOOST_CHECK_EQUAL(countAt, 1);
BOOST_CHECK_EQUAL(toJS(balance2), balanceString2);
BOOST_CHECK_EQUAL(jsToDecimal(balanceString2), "750000000000000000");
BOOST_CHECK_EQUAL(txAmount, balance2);
}
}
BOOST_AUTO_TEST_SUITE_END()
#endif

229
test/solidityCompiler.cpp

@ -0,0 +1,229 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Unit tests for the name and type resolution of the solidity parser.
*/
#include <string>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>
#include <boost/test/unit_test.hpp>
namespace dev
{
namespace solidity
{
namespace test
{
namespace
{
/**
* Helper class that extracts the first expression in an AST.
*/
class FirstExpressionExtractor: private ASTVisitor
{
public:
FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); }
Expression* getExpression() const { return m_expression; }
private:
virtual bool visit(Expression& _expression) override { return checkExpression(_expression); }
virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); }
virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); }
virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); }
virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); }
virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); }
virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); }
virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); }
virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); }
virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); }
virtual bool visit(Literal& _expression) override { return checkExpression(_expression); }
bool checkExpression(Expression& _expression)
{
if (m_expression == nullptr)
m_expression = &_expression;
return false;
}
private:
Expression* m_expression;
};
bytes compileFirstExpression(std::string const& _sourceCode)
{
Parser parser;
ASTPointer<ContractDefinition> contract;
BOOST_REQUIRE_NO_THROW(contract = parser.parse(std::make_shared<Scanner>(CharStream(_sourceCode))));
NameAndTypeResolver resolver;
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
FirstExpressionExtractor extractor(*contract);
BOOST_REQUIRE(extractor.getExpression() != nullptr);
CompilerContext context;
ExpressionCompiler compiler(context);
compiler.compile(*extractor.getExpression());
bytes instructions = compiler.getAssembledBytecode();
// debug
//std::cout << eth::disassemble(instructions) << std::endl;
return instructions;
}
} // end anonymous namespace
BOOST_AUTO_TEST_SUITE(SolidityExpressionCompiler)
BOOST_AUTO_TEST_CASE(literal_true)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = true; }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(literal_false)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = false; }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x0});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_literal)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = 0x12345678901234567890; }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90,
0x12, 0x34, 0x56, 0x78, 0x90});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(comparison)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = (0x10aa < 0x11aa) != true; }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa,
byte(eth::Instruction::PUSH2), 0x11, 0xaa,
byte(eth::Instruction::GT),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::EQ),
byte(eth::Instruction::NOT)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(short_circuiting)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = (10 + 8 >= 4 || 2 != 9) != true; }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0xa,
byte(eth::Instruction::PUSH1), 0x8,
byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::GT),
byte(eth::Instruction::NOT), // after this we have 10 + 8 >= 4
byte(eth::Instruction::DUP1),
byte(eth::Instruction::PUSH1), 0x14,
byte(eth::Instruction::JUMPI), // short-circuit if it is true
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x9,
byte(eth::Instruction::EQ),
byte(eth::Instruction::NOT), // after this we have 2 != 9
byte(eth::Instruction::JUMPDEST),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::EQ),
byte(eth::Instruction::NOT)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(arithmetics)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x3,
byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::PUSH1), 0x5,
byte(eth::Instruction::PUSH1), 0x6,
byte(eth::Instruction::PUSH1), 0x7,
byte(eth::Instruction::PUSH1), 0x8,
byte(eth::Instruction::PUSH1), 0x9,
byte(eth::Instruction::XOR),
byte(eth::Instruction::AND),
byte(eth::Instruction::OR),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB),
byte(eth::Instruction::ADD),
byte(eth::Instruction::MOD),
byte(eth::Instruction::DIV),
byte(eth::Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(unary_operators)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = !(~+-(--(++1++)--) == 2); }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB),
byte(eth::Instruction::PUSH1), 0x0,
byte(eth::Instruction::SUB),
byte(eth::Instruction::NOT),
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_SUITE_END()
}
}
} // end namespaces

2
test/solidityNameAndTypeResolution.cpp

@ -38,7 +38,7 @@ namespace test
namespace namespace
{ {
void parseTextAndResolveNames(const std::string& _source) void parseTextAndResolveNames(std::string const& _source)
{ {
Parser parser; Parser parser;
ASTPointer<ContractDefinition> contract = parser.parse( ASTPointer<ContractDefinition> contract = parser.parse(

2
test/solidityParser.cpp

@ -37,7 +37,7 @@ namespace test
namespace namespace
{ {
ASTPointer<ASTNode> parseText(const std::string& _source) ASTPointer<ASTNode> parseText(std::string const& _source)
{ {
Parser parser; Parser parser;
return parser.parse(std::make_shared<Scanner>(CharStream(_source))); return parser.parse(std::make_shared<Scanner>(CharStream(_source)));

587
test/webthreestubclient.h

@ -0,0 +1,587 @@
/**
* THIS FILE IS GENERATED BY jsonrpcstub, DO NOT CHANGE IT!!!!!
*/
#ifndef _WEBTHREESTUBCLIENT_H_
#define _WEBTHREESTUBCLIENT_H_
#include <jsonrpc/rpc.h>
class WebThreeStubClient
{
public:
WebThreeStubClient(jsonrpc::AbstractClientConnector* conn)
{
this->client = new jsonrpc::Client(conn);
}
~WebThreeStubClient()
{
delete this->client;
}
std::string account() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("account",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value accounts() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("accounts",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string addToGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("addToGroup",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string balanceAt(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("balanceAt",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value blockByHash(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("blockByHash",p);
if (result.isObject())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value blockByNumber(const int& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("blockByNumber",p);
if (result.isObject())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string call(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("call",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool changed(const int& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("changed",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("codeAt",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string coinbase() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("coinbase",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string compile(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("compile",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
double countAt(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("countAt",p);
if (result.isDouble())
return result.asDouble();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
int defaultBlock() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("defaultBlock",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string gasPrice() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("gasPrice",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string get(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("get",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value getMessages(const int& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("getMessages",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string getString(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("getString",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool haveIdentity(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("haveIdentity",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool listening() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("listening",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool mining() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("mining",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
int newFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("newFilter",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
int newFilterString(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("newFilterString",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string newGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("newGroup",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string newIdentity() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("newIdentity",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
int number() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("number",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
int peerCount() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->client->CallMethod("peerCount",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool post(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("post",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
p.append(param3);
Json::Value result = this->client->CallMethod("put",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool putString(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
p.append(param3);
Json::Value result = this->client->CallMethod("putString",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool setCoinbase(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("setCoinbase",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool setDefaultBlock(const int& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("setDefaultBlock",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool setListening(const bool& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("setListening",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool setMining(const bool& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("setMining",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value shhChanged(const int& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("shhChanged",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
int shhNewFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("shhNewFilter",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool shhUninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("shhUninstallFilter",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string stateAt(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("stateAt",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string transact(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("transact",p);
if (result.isString())
return result.asString();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value transactionByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("transactionByHash",p);
if (result.isObject())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value transactionByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("transactionByNumber",p);
if (result.isObject())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value uncleByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("uncleByHash",p);
if (result.isObject())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value uncleByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->client->CallMethod("uncleByNumber",p);
if (result.isObject())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool uninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->client->CallMethod("uninstallFilter",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
private:
jsonrpc::Client* client;
};
#endif //_WEBTHREESTUBCLIENT_H_

2
third/CMakeLists.txt

@ -53,7 +53,7 @@ else ()
endif () endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore web3jsonrpc jsqrc)
if (APPLE) if (APPLE)
# First have qt5 install plugins and frameworks # First have qt5 install plugins and frameworks

48
third/MainWin.cpp

@ -39,6 +39,7 @@
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include "BuildInfo.h" #include "BuildInfo.h"
#include "MainWin.h" #include "MainWin.h"
#include "ui_Main.h" #include "ui_Main.h"
@ -72,6 +73,20 @@ static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
return QString(); return QString();
} }
static std::vector<dev::KeyPair> keysAsVector(QList<dev::KeyPair> const& keys)
{
auto list = keys.toStdList();
return {std::begin(list), std::end(list)};
}
static QString contentsOfQResource(std::string const& res)
{
QFile file(QString::fromStdString(res));
if (!file.open(QFile::ReadOnly))
return "";
QTextStream in(&file);
return in.readAll();
}
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
@ -102,28 +117,25 @@ Main::Main(QWidget *parent) :
m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"})); m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"}));
m_web3->connect(Host::pocHost()); m_web3->connect(Host::pocHost());
m_ldb = new QLDB(this); m_server = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(&m_qwebConnector, *web3(), keysAsVector(m_myKeys)));
m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening();
connect(ui->webView, &QWebView::loadStarted, [this]() connect(ui->webView, &QWebView::loadStarted, [this]()
{ {
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this); m_qweb = new QWebThree(this);
m_ethereum = new QEthereum(this, ethereum(), m_myKeys); auto qweb = m_qweb;
m_whisper = new QWhisper(this, whisper(), owned()); m_qwebConnector.setQWeb(qweb);
QWebFrame* f = ui->webView->page()->mainFrame(); QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qdev = m_dev; connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qweb));
auto qeth = m_ethereum;
auto qshh = m_whisper;
auto qldb = m_ldb;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb));
}); });
connect(ui->webView, &QWebView::loadFinished, [=]() connect(ui->webView, &QWebView::loadFinished, [=]()
{ {
m_ethereum->poll(); m_qweb->poll();
m_whisper->poll();
}); });
connect(ui->webView, &QWebView::titleChanged, [=]() connect(ui->webView, &QWebView::titleChanged, [=]()
@ -151,8 +163,7 @@ Main::~Main()
{ {
// Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor) // Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor)
// *after* the client is dead. // *after* the client is dead.
m_ethereum->clientDieing(); m_qweb->clientDieing();
writeSettings(); writeSettings();
} }
@ -524,10 +535,8 @@ void Main::timerEvent(QTimerEvent*)
else else
interval += 100; interval += 100;
if (m_ethereum) if (m_qweb)
m_ethereum->poll(); m_qweb->poll();
if (m_whisper)
m_whisper->poll();
for (auto const& i: m_handlers) for (auto const& i: m_handlers)
if (ethereum()->checkWatch(i.first)) if (ethereum()->checkWatch(i.first))
@ -546,8 +555,9 @@ void Main::ourAccountsRowsMoved()
myKeys.push_back(i); myKeys.push_back(i);
} }
m_myKeys = myKeys; m_myKeys = myKeys;
if (m_ethereum)
m_ethereum->setAccounts(myKeys); if (m_server.get())
m_server->setAccounts(keysAsVector(myKeys));
} }
void Main::on_ourAccounts_doubleClicked() void Main::on_ourAccounts_doubleClicked()

10
third/MainWin.h

@ -48,6 +48,7 @@ class WhisperHost;
} }
class QQuickView; class QQuickView;
class WebThreeStubServer;
class Main : public QMainWindow class Main : public QMainWindow
{ {
@ -61,7 +62,7 @@ public:
dev::eth::Client* ethereum() const; dev::eth::Client* ethereum() const;
std::shared_ptr<dev::shh::WhisperHost> whisper() const; std::shared_ptr<dev::shh::WhisperHost> whisper() const;
QList<dev::KeyPair> owned() const { return m_myKeys + m_myIdentities; } QList<dev::KeyPair> owned() const { return m_myKeys + m_myIdentities;}
public slots: public slots:
void note(QString _entry); void note(QString _entry);
@ -133,8 +134,7 @@ private:
QNetworkAccessManager m_webCtrl; QNetworkAccessManager m_webCtrl;
QDev* m_dev = nullptr; std::unique_ptr<WebThreeStubServer> m_server;
QEthereum* m_ethereum = nullptr; QWebThreeConnector m_qwebConnector;
QWhisper* m_whisper = nullptr; QWebThree* m_qweb = nullptr;
QLDB* m_ldb = nullptr;
}; };

1
third/main.cpp

@ -4,6 +4,7 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
Q_INIT_RESOURCE(js);
Main w; Main w;
w.show(); w.show();

4
windows/LibEthereum.vcxproj

@ -103,8 +103,8 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="..\libethcore\_libethcore.cpp" /> <ClCompile Include="..\libethcore\_libethcore.cpp" />
<ClCompile Include="..\libethereum\Account.cpp" />
<ClCompile Include="..\libethereum\AccountDiff.cpp" /> <ClCompile Include="..\libethereum\AccountDiff.cpp" />
<ClCompile Include="..\libethereum\AddressState.cpp" />
<ClCompile Include="..\libethereum\BlockChain.cpp" /> <ClCompile Include="..\libethereum\BlockChain.cpp" />
<ClCompile Include="..\libethereum\BlockDetails.cpp" /> <ClCompile Include="..\libethereum\BlockDetails.cpp" />
<ClCompile Include="..\libethereum\BlockQueue.cpp" /> <ClCompile Include="..\libethereum\BlockQueue.cpp" />
@ -318,8 +318,8 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude> </ClInclude>
<ClInclude Include="..\libethereum\Account.h" />
<ClInclude Include="..\libethereum\AccountDiff.h" /> <ClInclude Include="..\libethereum\AccountDiff.h" />
<ClInclude Include="..\libethereum\AddressState.h" />
<ClInclude Include="..\libethereum\All.h" /> <ClInclude Include="..\libethereum\All.h" />
<ClInclude Include="..\libethereum\BlockChain.h" /> <ClInclude Include="..\libethereum\BlockChain.h" />
<ClInclude Include="..\libethereum\BlockDetails.h" /> <ClInclude Include="..\libethereum\BlockDetails.h" />

12
windows/LibEthereum.vcxproj.filters

@ -4,9 +4,6 @@
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
<Filter>Windows</Filter> <Filter>Windows</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\libethereum\AddressState.cpp">
<Filter>libethereum</Filter>
</ClCompile>
<ClCompile Include="..\libethereum\BlockChain.cpp"> <ClCompile Include="..\libethereum\BlockChain.cpp">
<Filter>libethereum</Filter> <Filter>libethereum</Filter>
</ClCompile> </ClCompile>
@ -202,14 +199,14 @@
<ClCompile Include="..\libdevcrypto\SHA3MAC.cpp"> <ClCompile Include="..\libdevcrypto\SHA3MAC.cpp">
<Filter>libdevcrypto</Filter> <Filter>libdevcrypto</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\libethereum\Account.cpp">
<Filter>libethereum</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h"> <ClInclude Include="stdafx.h">
<Filter>Windows</Filter> <Filter>Windows</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libethereum\AddressState.h">
<Filter>libethereum</Filter>
</ClInclude>
<ClInclude Include="..\libethereum\BlockChain.h"> <ClInclude Include="..\libethereum\BlockChain.h">
<Filter>libethereum</Filter> <Filter>libethereum</Filter>
</ClInclude> </ClInclude>
@ -435,6 +432,9 @@
<ClInclude Include="..\libdevcrypto\SHA3MAC.h"> <ClInclude Include="..\libdevcrypto\SHA3MAC.h">
<Filter>libdevcrypto</Filter> <Filter>libdevcrypto</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libethereum\Account.h">
<Filter>libethereum</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Windows"> <Filter Include="Windows">

Loading…
Cancel
Save