Browse Source

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

cl-refactor
CJentzsch 10 years ago
parent
commit
7c442af36b
  1. 2
      README.md
  2. 1
      alethzero/CMakeLists.txt
  3. 139
      alethzero/DappHost.cpp
  4. 58
      alethzero/DappHost.h
  5. 203
      alethzero/DappLoader.cpp
  6. 94
      alethzero/DappLoader.h
  7. 71
      alethzero/MainWin.cpp
  8. 14
      alethzero/MainWin.h
  9. 4
      alethzero/Transact.cpp
  10. 28
      alethzero/WebPage.cpp
  11. 40
      alethzero/WebPage.h
  12. 3
      libdevcore/StructuredLogger.cpp
  13. 11
      libdevcore/StructuredLogger.h
  14. 16
      libethereum/State.cpp
  15. 2
      libethereum/State.h
  16. 22
      libevmcore/Assembly.cpp
  17. 15
      libevmcore/Assembly.h
  18. 20
      libnatspec/NatspecExpressionEvaluator.cpp
  19. 9
      libnatspec/NatspecExpressionEvaluator.h
  20. 102
      libnatspec/natspec.js
  21. 2
      libnatspec/natspec.qrc
  22. 3
      libnatspec/natspecjs/.gitignore
  23. 8
      libnatspec/natspecjs/.travis.yml
  24. 47
      libnatspec/natspecjs/README.md
  25. 3570
      libnatspec/natspecjs/dist/natspec.js
  26. 1
      libnatspec/natspecjs/dist/natspec.js.map
  27. 2
      libnatspec/natspecjs/dist/natspec.min.js
  28. 13
      libnatspec/natspecjs/example/example.html
  29. 186
      libnatspec/natspecjs/natspec.js
  30. 24
      libnatspec/natspecjs/package.json
  31. 149
      libnatspec/natspecjs/test/test.js
  32. 3
      libsolidity/Compiler.cpp
  33. 4
      libsolidity/Compiler.h
  34. 7
      libsolidity/CompilerContext.cpp
  35. 4
      libsolidity/CompilerContext.h
  36. 5
      libsolidity/ExpressionCompiler.cpp
  37. 2
      libsolidity/Parser.h
  38. 3
      mix/AppContext.cpp
  39. 9
      mix/CodeEditorExtensionManager.cpp
  40. 2
      mix/CodeEditorExtensionManager.h
  41. 2
      mix/CodeModel.h
  42. 2
      mix/FileIo.cpp
  43. 156
      mix/SortFilterProxyModel.cpp
  44. 97
      mix/SortFilterProxyModel.h
  45. 302
      mix/qml/LogsPane.qml
  46. 29
      mix/qml/LogsPaneStyle.qml
  47. 32
      mix/qml/MainContent.qml
  48. 10
      mix/qml/ProjectModel.qml
  49. 5
      mix/qml/StateListModel.qml
  50. 170
      mix/qml/StatusPane.qml
  51. 7
      mix/qml/WebPreview.qml
  52. BIN
      mix/qml/img/broom.png
  53. BIN
      mix/qml/img/copy.png
  54. 21
      mix/qml/js/ProjectModel.js
  55. 1
      mix/qml/qmldir
  56. 4
      mix/res.qrc
  57. 32
      pullSubtree.sh
  58. 9
      solc/CommandLineInterface.cpp
  59. 1
      solc/docker_emscripten/Dockerfile
  60. 41
      test/TestHelper.cpp
  61. 8
      test/TestHelper.h
  62. 18
      test/bcUncleTestFiller.json
  63. 14
      test/blockchain.cpp
  64. 19
      test/natspec.cpp
  65. 89
      test/stRefundTestFiller.json
  66. 4
      test/stTransactionTestFiller.json
  67. 64
      test/vm.cpp
  68. 32
      test/vmArithmeticTestFiller.json
  69. 225
      test/vmIOandFlowOperationsTestFiller.json

2
README.md

@ -1,5 +1,7 @@
## Ethereum C++ Client. ## Ethereum C++ Client.
[![Join the chat at https://gitter.im/ethereum/cpp-ethereum](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/cpp-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
By Gav Wood et al, 2013, 2014, 2015. By Gav Wood et al, 2013, 2014, 2015.
| Linux | OSX | Windows | Linux | OSX | Windows

1
alethzero/CMakeLists.txt

@ -56,6 +56,7 @@ target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} jsqrc) target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} natspec) target_link_libraries(${EXECUTABLE} natspec)
target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES})
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")) if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} serpent)

139
alethzero/DappHost.cpp

@ -0,0 +1,139 @@
/*
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 DappHost.cpp
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#include "DappHost.h"
#include <QUrl>
#include <microhttpd.h>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h>
using namespace dev;
DappHost::DappHost(int _port, int _threads):
m_port(_port), m_threads(_threads), m_running(false), m_daemon(nullptr)
{
startListening();
}
DappHost::~DappHost()
{
stopListening();
}
void DappHost::startListening()
{
if(!this->m_running)
{
this->m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, this->m_port, nullptr, nullptr, &DappHost::callback, this, MHD_OPTION_THREAD_POOL_SIZE, this->m_threads, MHD_OPTION_END);
if (this->m_daemon != nullptr)
this->m_running = true;
}
}
void DappHost::stopListening()
{
if(this->m_running)
{
MHD_stop_daemon(this->m_daemon);
this->m_running = false;
}
}
void DappHost::sendOptionsResponse(MHD_Connection* _connection)
{
MHD_Response *result = MHD_create_response_from_data(0, NULL, 0, 1);
MHD_add_response_header(result, "Allow", "GET, OPTIONS");
MHD_add_response_header(result, "Access-Control-Allow-Headers", "origin, content-type, accept");
MHD_add_response_header(result, "DAV", "1");
MHD_queue_response(_connection, MHD_HTTP_OK, result);
MHD_destroy_response(result);
}
void DappHost::sendNotAllowedResponse(MHD_Connection* _connection)
{
MHD_Response *result = MHD_create_response_from_data(0, NULL, 0, 1);
MHD_add_response_header(result, "Allow", "GET, OPTIONS");
MHD_queue_response(_connection, MHD_HTTP_METHOD_NOT_ALLOWED, result);
MHD_destroy_response(result);
}
void DappHost::sendResponse(std::string const& _url, MHD_Connection* _connection)
{
QUrl requestUrl(QString::fromStdString(_url));
QString path = requestUrl.path().toLower();
if (path.isEmpty())
path = "/";
bytesConstRef response;
unsigned code = MHD_HTTP_NOT_FOUND;
std::string contentType;
while (!path.isEmpty())
{
auto iter = m_entriesByPath.find(path);
if (iter != m_entriesByPath.end())
{
ManifestEntry const* entry = iter->second;
auto contentIter = m_dapp.content.find(entry->hash);
if (contentIter == m_dapp.content.end())
break;
response = bytesConstRef(contentIter->second.data(), contentIter->second.size());
code = entry->httpStatus != 0 ? entry->httpStatus : MHD_HTTP_OK;
contentType = entry->contentType;
break;
}
path.truncate(path.length() - 1);
path = path.mid(0, path.lastIndexOf('/'));
}
MHD_Response *result = MHD_create_response_from_data(response.size(), const_cast<byte*>(response.data()), 0, 1);
if (!contentType.empty())
MHD_add_response_header(result, "Content-Type", contentType.c_str());
MHD_queue_response(_connection, code, result);
MHD_destroy_response(result);
}
int DappHost::callback(void* _cls, MHD_Connection* _connection, char const* _url, char const* _method, char const* _version, char const* _uploadData, size_t* _uploadDataSize, void** _conCls)
{
(void)_version;
(void)_uploadData;
(void)_uploadDataSize;
(void)_conCls;
DappHost* host = static_cast<DappHost*>(_cls);
if (std::string("GET") == _method)
host->sendResponse(std::string(_url), _connection);
else if (std::string("OPTIONS") == _method)
host->sendOptionsResponse(_connection);
else
host->sendNotAllowedResponse(_connection);
return MHD_YES;
}
QUrl DappHost::hostDapp(Dapp&& _dapp)
{
m_dapp = std::move(_dapp);
m_entriesByPath.clear();
for (ManifestEntry const& entry: m_dapp.manifest.entries)
m_entriesByPath[QString::fromStdString(entry.path)] = &entry;
return QUrl(QString("http://localhost:%1/").arg(m_port));
}

58
alethzero/DappHost.h

@ -0,0 +1,58 @@
/*
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 DappHost.h
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#pragma once
#include <map>
#include <QUrl>
#include <QString>
#include "DappLoader.h"
struct MHD_Daemon;
struct MHD_Connection;
/// DApp web server. Servers web content, resolves paths by hashes
class DappHost
{
public:
/// @param _port Network pork to listen for incoming connections
/// @param _threads Max number of threads to process requests
DappHost(int _port, int _threads = 10);
virtual ~DappHost();
/// Load and host a dapp. Previsous dapp in discarded. Synchronous
QUrl hostDapp(Dapp&& _dapp);
private:
void startListening();
void stopListening();
void sendOptionsResponse(MHD_Connection* _connection);
void sendNotAllowedResponse(MHD_Connection* _connection);
void sendResponse(std::string const& _url, MHD_Connection* _connection);
static int callback(void* _cls, MHD_Connection* _connection, char const* _url, char const* _method, char const* _version, char const* _uploadData, size_t* _uploadDataSize, void** _conCls);
int m_port;
int m_threads;
bool m_running;
MHD_Daemon* m_daemon;
Dapp m_dapp;
std::map<QString, ManifestEntry const*> m_entriesByPath;
};

203
alethzero/DappLoader.cpp

@ -0,0 +1,203 @@
/*
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 DappLoader.cpp
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#include <algorithm>
#include <json/json.h>
#include <QUrl>
#include <QStringList>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h>
#include <libethcore/CommonJS.h>
#include <libethereum/Client.h>
#include <libwebthree/WebThree.h>
#include "DappLoader.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::crypto;
Address c_registrar = Address("0000000000000000000000000000000000000a28");
Address c_urlHint = Address("0000000000000000000000000000000000000a29");
QString contentsOfQResource(std::string const& res);
DappLoader::DappLoader(QObject* _parent, WebThreeDirect* _web3):
QObject(_parent), m_web3(_web3)
{
connect(&m_net, &QNetworkAccessManager::finished, this, &DappLoader::downloadComplete);
}
DappLocation DappLoader::resolveAppUri(QString const& _uri)
{
QUrl url(_uri);
if (!url.scheme().isEmpty() && url.scheme() != "eth")
throw dev::Exception(); //TODO:
QStringList parts = url.host().split('.', QString::SkipEmptyParts);
QStringList domainParts;
std::reverse(parts.begin(), parts.end());
parts.append(url.path().split('/', QString::SkipEmptyParts));
Address address = c_registrar;
Address lastAddress;
int partIndex = 0;
h256 contentHash;
while (address && partIndex < parts.length())
{
lastAddress = address;
string32 name = { 0 };
QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("addr(string32)", name)));
domainParts.append(parts[partIndex]);
if (!address)
{
//we have the address of the last part, try to get content hash
contentHash = abiOut<h256>(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)));
if (!contentHash)
throw dev::Exception() << errinfo_comment("Can't resolve address");
}
++partIndex;
}
string32 contentUrl = abiOut<string32>(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)));
QString domain = domainParts.join('/');
parts.erase(parts.begin(), parts.begin() + partIndex);
QString path = parts.join('/');
QString contentUrlString = QString::fromUtf8(std::string(contentUrl.data(), contentUrl.size()).c_str());
if (!contentUrlString.startsWith("http://") || !contentUrlString.startsWith("https://"))
contentUrlString = "http://" + contentUrlString;
return DappLocation { domain, path, contentUrlString, contentHash };
}
void DappLoader::downloadComplete(QNetworkReply* _reply)
{
try
{
//try to interpret as rlp
QByteArray data = _reply->readAll();
_reply->deleteLater();
h256 expected = m_uriHashes[_reply->request().url()];
bytes package(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
Secp256k1 dec;
dec.decrypt(expected, package);
h256 got = sha3(package);
if (got != expected)
{
//try base64
data = QByteArray::fromBase64(data);
package = bytes(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
dec.decrypt(expected, package);
got = sha3(package);
if (got != expected)
throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
}
RLP rlp(package);
loadDapp(rlp);
}
catch (...)
{
qWarning() << tr("Error downloading DApp: ") << boost::current_exception_diagnostic_information().c_str();
emit dappError();
}
}
void DappLoader::loadDapp(RLP const& _rlp)
{
Dapp dapp;
unsigned len = _rlp.itemCountStrict();
dapp.manifest = loadManifest(_rlp[0].toString());
for (unsigned c = 1; c < len; ++c)
{
bytesConstRef content = _rlp[c].toBytesConstRef();
h256 hash = sha3(content);
auto entry = std::find_if(dapp.manifest.entries.cbegin(), dapp.manifest.entries.cend(), [=](ManifestEntry const& _e) { return _e.hash == hash; });
if (entry != dapp.manifest.entries.cend())
{
if (entry->path == "/deployment.js")
{
//inject web3 code
QString code;
code += contentsOfQResource(":/js/bignumber.min.js");
code += "\n";
code += contentsOfQResource(":/js/webthree.js");
code += "\n";
code += contentsOfQResource(":/js/setup.js");
code += "\n";
QByteArray res = code.toLatin1();
bytes b(res.data(), res.data() + res.size());
b.insert(b.end(), content.begin(), content.end());
dapp.content[hash] = b;
}
else
dapp.content[hash] = content.toBytes();
}
else
throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
}
emit dappReady(dapp);
}
Manifest DappLoader::loadManifest(std::string const& _manifest)
{
/// https://github.com/ethereum/go-ethereum/wiki/URL-Scheme
Manifest manifest;
Json::Reader jsonReader;
Json::Value root;
jsonReader.parse(_manifest, root, false);
Json::Value entries = root["entries"];
for (Json::ValueIterator it = entries.begin(); it != entries.end(); ++it)
{
Json::Value const& entryValue = *it;
std::string path = entryValue["path"].asString();
if (path.size() == 0 || path[0] != '/')
path = "/" + path;
std::string contentType = entryValue["contentType"].asString();
std::string strHash = entryValue["hash"].asString();
if (strHash.length() == 64)
strHash = "0x" + strHash;
h256 hash = jsToFixed<32>(strHash);
unsigned httpStatus = entryValue["status"].asInt();
manifest.entries.push_back(ManifestEntry{ path, hash, contentType, httpStatus });
}
return manifest;
}
void DappLoader::loadDapp(QString const& _uri)
{
DappLocation location = resolveAppUri(_uri);
QUrl uri(location.contentUri);
QNetworkRequest request(uri);
m_uriHashes[uri] = location.contentHash;
m_net.get(request);
}

94
alethzero/DappLoader.h

@ -0,0 +1,94 @@
/*
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 DappLoader.h
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#pragma once
#include <map>
#include <string>
#include <vector>
#include <QObject>
#include <QString>
#include <QUrl>
#include <QNetworkAccessManager>
#include <libdevcore/FixedHash.h>
namespace dev
{
class WebThreeDirect;
class RLP;
}
struct ManifestEntry
{
std::string path;
dev::h256 hash;
std::string contentType;
unsigned httpStatus;
};
struct Manifest
{
std::vector<ManifestEntry> entries;
};
struct Dapp
{
Manifest manifest;
std::map<dev::h256, dev::bytes> content;
};
struct DappLocation
{
QString canonDomain;
QString path;
QString contentUri;
dev::h256 contentHash;
};
///Downloads, unpacks and prepares DApps for hosting
class DappLoader: public QObject
{
Q_OBJECT
public:
DappLoader(QObject* _parent, dev::WebThreeDirect* _web3);
///Load a new DApp. Resolves a name with a name reg contract. Asynchronous. dappReady is emitted once everything is read, dappError othervise
///@param _uri Eth name path
void loadDapp(QString const& _uri);
signals:
void dappReady(Dapp& _dapp);
void dappError();
private slots:
void downloadComplete(QNetworkReply* _reply);
private:
dev::WebThreeDirect* web3() const { return m_web3; }
DappLocation resolveAppUri(QString const& _uri);
void loadDapp(dev::RLP const& _rlp);
Manifest loadManifest(std::string const& _manifest);
dev::WebThreeDirect* m_web3;
QNetworkAccessManager m_net;
std::map<QUrl, dev::h256> m_uriHashes;
};

71
alethzero/MainWin.cpp

@ -19,7 +19,6 @@
* @date 2014 * @date 2014
*/ */
#define QWEBENGINEINSPECTOR 1
#include <fstream> #include <fstream>
// Make sure boost/asio.hpp is included before windows.h. // Make sure boost/asio.hpp is included before windows.h.
@ -68,6 +67,9 @@
#include "OurWebThreeStubServer.h" #include "OurWebThreeStubServer.h"
#include "Transact.h" #include "Transact.h"
#include "Debugger.h" #include "Debugger.h"
#include "DappLoader.h"
#include "DappHost.h"
#include "WebPage.h"
#include "ui_Main.h" #include "ui_Main.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -116,7 +118,9 @@ Address c_newConfig = Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
Main::Main(QWidget *parent) : Main::Main(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::Main), ui(new Ui::Main),
m_transact(this, this) m_transact(this, this),
m_dappLoader(nullptr),
m_webPage(nullptr)
{ {
QtWebEngine::initialize(); QtWebEngine::initialize();
setWindowFlags(Qt::Window); setWindowFlags(Qt::Window);
@ -166,10 +170,12 @@ Main::Main(QWidget *parent) :
m_server->setIdentities(keysAsVector(owned())); m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening(); m_server->StartListening();
WebPage* webPage= new WebPage(this);
m_webPage = webPage;
connect(webPage, &WebPage::consoleMessage, [this](QString const& _msg) { Main::addConsoleMessage(_msg, QString()); });
ui->webView->setPage(m_webPage);
connect(ui->webView, &QWebEngineView::loadFinished, [this]() connect(ui->webView, &QWebEngineView::loadFinished, [this]()
{ {
// f->disconnect();
// f->addToJavaScriptWindowObject("env", this, QWebFrame::QtOwnership);
auto f = ui->webView->page(); auto f = ui->webView->page();
f->runJavaScript(contentsOfQResource(":/js/bignumber.min.js")); f->runJavaScript(contentsOfQResource(":/js/bignumber.min.js"));
f->runJavaScript(contentsOfQResource(":/js/webthree.js")); f->runJavaScript(contentsOfQResource(":/js/webthree.js"));
@ -181,6 +187,9 @@ Main::Main(QWidget *parent) :
ui->tabWidget->setTabText(0, ui->webView->title()); ui->tabWidget->setTabText(0, ui->webView->title());
}); });
m_dappHost.reset(new DappHost(8081));
m_dappLoader = new DappLoader(this, web3());
connect(m_dappLoader, &DappLoader::dappReady, this, &Main::dappLoaded);
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector(); // QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page); // inspector->setPage(page);
@ -425,13 +434,7 @@ void Main::eval(QString const& _js)
s = "<span style=\"color: #840\">" + jsonEv.toString().toHtmlEscaped() + "</span>"; s = "<span style=\"color: #840\">" + jsonEv.toString().toHtmlEscaped() + "</span>";
else else
s = "<span style=\"color: #888\">unknown type</span>"; s = "<span style=\"color: #888\">unknown type</span>";
m_consoleHistory.push_back(qMakePair(_js, s)); addConsoleMessage(_js, s);
s = "<html><body style=\"margin: 0;\">" Div(Mono "position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%");
for (auto const& i: m_consoleHistory)
s += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>"
"<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>";
s += "</div></body></html>";
ui->jsConsole->setHtml(s);
}; };
ui->webView->page()->runJavaScript("JSON.stringify(___RET)", f2); ui->webView->page()->runJavaScript("JSON.stringify(___RET)", f2);
}; };
@ -439,6 +442,17 @@ void Main::eval(QString const& _js)
ui->webView->page()->runJavaScript(c, f); ui->webView->page()->runJavaScript(c, f);
} }
void Main::addConsoleMessage(QString const& _js, QString const& _s)
{
m_consoleHistory.push_back(qMakePair(_js, _s));
QString r = "<html><body style=\"margin: 0;\">" Div(Mono "position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%");
for (auto const& i: m_consoleHistory)
r += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>"
"<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>";
r += "</div></body></html>";
ui->jsConsole->setHtml(r);
}
static Public stringToPublic(QString const& _a) static Public stringToPublic(QString const& _a)
{ {
string sn = _a.toStdString(); string sn = _a.toStdString();
@ -780,15 +794,28 @@ void Main::on_jitvm_triggered()
void Main::on_urlEdit_returnPressed() void Main::on_urlEdit_returnPressed()
{ {
QString s = ui->urlEdit->text(); QString s = ui->urlEdit->text();
QRegExp r("([a-z]+://)?([^/]*)(.*)"); QUrl url(s);
if (r.exactMatch(s)) if (url.scheme().isEmpty() || url.scheme() == "eth")
if (r.cap(2).isEmpty()) {
s = (r.cap(1).isEmpty() ? "file://" : r.cap(1)) + r.cap(3); try
{
//try do resolve dapp url
m_dappLoader->loadDapp(s);
}
catch (...)
{
qWarning() << boost::current_exception_diagnostic_information().c_str();
}
}
if (url.scheme().isEmpty())
if (url.path().indexOf('/') < url.path().indexOf('.'))
url.setScheme("file");
else else
s = (r.cap(1).isEmpty() ? "http://" : r.cap(1)) + lookup(r.cap(2)) + r.cap(3); url.setScheme("http");
else{} else {}
qDebug() << s; qDebug() << url.toString();
ui->webView->setUrl(s); ui->webView->page()->setUrl(url);
} }
void Main::on_nameReg_textChanged() void Main::on_nameReg_textChanged()
@ -1835,3 +1862,9 @@ void Main::refreshWhispers()
ui->whispers->addItem(item); ui->whispers->addItem(item);
} }
} }
void Main::dappLoaded(Dapp& _dapp)
{
QUrl url = m_dappHost->hostDapp(std::move(_dapp));
ui->webView->page()->setUrl(url);
}

14
alethzero/MainWin.h

@ -54,8 +54,11 @@ namespace jsonrpc {
class HttpServer; class HttpServer;
} }
class QQuickView; class QWebEnginePage;
class OurWebThreeStubServer; class OurWebThreeStubServer;
class DappLoader;
class DappHost;
struct Dapp;
using WatchHandler = std::function<void(dev::eth::LocalisedLogEntries const&)>; using WatchHandler = std::function<void(dev::eth::LocalisedLogEntries const&)>;
@ -99,6 +102,7 @@ public slots:
private slots: private slots:
void eval(QString const& _js); void eval(QString const& _js);
void addConsoleMessage(QString const& _js, QString const& _s);
// Application // Application
void on_about_triggered(); void on_about_triggered();
@ -172,6 +176,9 @@ private slots:
void refreshBlockChain(); void refreshBlockChain();
void addNewId(QString _ids); void addNewId(QString _ids);
// Dapps
void dappLoaded(Dapp& _dapp); //qt does not support rvalue refs for signals
signals: signals:
void poll(); void poll();
@ -234,8 +241,6 @@ private:
QString m_privateChain; QString m_privateChain;
dev::Address m_nameReg; dev::Address m_nameReg;
QNetworkAccessManager m_webCtrl;
QList<QPair<QString, QString>> m_consoleHistory; QList<QPair<QString, QString>> m_consoleHistory;
QMutex m_logLock; QMutex m_logLock;
QString m_logHistory; QString m_logHistory;
@ -248,4 +253,7 @@ private:
NatspecHandler m_natSpecDB; NatspecHandler m_natSpecDB;
Transact m_transact; Transact m_transact;
std::unique_ptr<DappHost> m_dappHost;
DappLoader* m_dappLoader;
QWebEnginePage* m_webPage;
}; };

4
alethzero/Transact.cpp

@ -175,7 +175,7 @@ void Transact::rejigData()
m_data = fromHex(src); m_data = fromHex(src);
else if (sourceIsSolidity(src)) else if (sourceIsSolidity(src))
{ {
dev::solidity::CompilerStack compiler; dev::solidity::CompilerStack compiler(true);
try try
{ {
// compiler.addSources(dev::solidity::StandardSources); // compiler.addSources(dev::solidity::StandardSources);
@ -287,7 +287,7 @@ void Transact::on_send_clicked()
if (sourceIsSolidity(src)) if (sourceIsSolidity(src))
try try
{ {
dev::solidity::CompilerStack compiler; dev::solidity::CompilerStack compiler(true);
m_data = compiler.compile(src, ui->optimize->isChecked()); m_data = compiler.compile(src, ui->optimize->isChecked());
for (string const& s: compiler.getContractNames()) for (string const& s: compiler.getContractNames())
{ {

28
alethzero/WebPage.cpp

@ -0,0 +1,28 @@
/*
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 WebPage.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com>
* @date 2015
*/
#include "WebPage.h"
void WebPage::javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _level, const QString& _message, int _lineNumber, const QString& _sourceID)
{
QString prefix = _level == QWebEnginePage::ErrorMessageLevel ? "error" : _level == QWebEnginePage::WarningMessageLevel ? "warning" : "";
emit consoleMessage(QString("%1(%2:%3):%4").arg(prefix).arg(_sourceID).arg(_lineNumber).arg(_message));
}

40
alethzero/WebPage.h

@ -0,0 +1,40 @@
/*
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 WebPage.h
* @author Arkadiy Paronyan arkadiy@ethdev.com>
* @date 2015
*/
#pragma once
#include <QString>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" //QtWebEngineWidgets/qwebenginecertificateerror.h:78:348: error: extra ';'
#include <QtWebEngineWidgets/QWebEnginePage>
#pragma GCC diagnostic pop
class WebPage: public QWebEnginePage
{
Q_OBJECT
public:
WebPage(QObject* _parent): QWebEnginePage(_parent) { }
signals:
void consoleMessage(QString const& _msg);
protected:
void javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _level, const QString& _message, int _lineNumber, const QString& _sourceID) override;
};

3
libdevcore/StructuredLogger.cpp

@ -22,11 +22,12 @@
*/ */
#include "StructuredLogger.h" #include "StructuredLogger.h"
#include <ctime> #include <ctime>
#include <boost/asio/ip/tcp.hpp>
#include <json/json.h> #include <json/json.h>
#include "Guards.h" #include "Guards.h"
namespace ba = boost::asio;
using namespace std; using namespace std;
namespace dev namespace dev

11
libdevcore/StructuredLogger.h

@ -27,9 +27,10 @@
#include <string> #include <string>
#include <chrono> #include <chrono>
#include <libp2p/Network.h>
namespace Json { class Value; } namespace Json { class Value; }
namespace boost { namespace asio { namespace ip { template<class T>class basic_endpoint; class tcp; }}}
namespace bi = boost::asio::ip;
namespace dev namespace dev
{ {
@ -61,12 +62,16 @@ public:
static void stopping(std::string const& _clientImpl, const char* _ethVersion); static void stopping(std::string const& _clientImpl, const char* _ethVersion);
static void p2pConnected( static void p2pConnected(
std::string const& _id, std::string const& _id,
bi::tcp::endpoint const& _addr, bi::basic_endpoint<bi::tcp> const& _addr,
std::chrono::system_clock::time_point const& _ts, std::chrono::system_clock::time_point const& _ts,
std::string const& _remoteVersion, std::string const& _remoteVersion,
unsigned int _numConnections unsigned int _numConnections
); );
static void p2pDisconnected(std::string const& _id, bi::tcp::endpoint const& _addr, unsigned int _numConnections); static void p2pDisconnected(
std::string const& _id,
bi::basic_endpoint<bi::tcp> const& _addr,
unsigned int _numConnections
);
static void minedNewBlock( static void minedNewBlock(
std::string const& _hash, std::string const& _hash,
std::string const& _blockNumber, std::string const& _blockNumber,

16
libethereum/State.cpp

@ -555,7 +555,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
BOOST_THROW_EXCEPTION(TooManyUncles()); BOOST_THROW_EXCEPTION(TooManyUncles());
set<Nonce> nonces = { m_currentBlock.nonce }; set<Nonce> nonces = { m_currentBlock.nonce };
Addresses rewarded; vector<BlockInfo> rewarded;
set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
for (auto const& i: rlp[2]) for (auto const& i: rlp[2])
@ -574,7 +574,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
nonces.insert(uncle.nonce); nonces.insert(uncle.nonce);
tdIncrease += uncle.difficulty; tdIncrease += uncle.difficulty;
rewarded.push_back(uncle.coinbaseAddress); rewarded.push_back(uncle);
} }
applyRewards(rewarded); applyRewards(rewarded);
@ -696,7 +696,7 @@ void State::commitToMine(BlockChain const& _bc)
m_lastTx = m_db; m_lastTx = m_db;
Addresses uncleAddresses; vector<BlockInfo> uncleBlockHeaders;
RLPStream unclesData; RLPStream unclesData;
unsigned unclesCount = 0; unsigned unclesCount = 0;
@ -716,7 +716,7 @@ void State::commitToMine(BlockChain const& _bc)
BlockInfo ubi(_bc.block(u)); BlockInfo ubi(_bc.block(u));
ubi.streamRLP(unclesData, WithNonce); ubi.streamRLP(unclesData, WithNonce);
++unclesCount; ++unclesCount;
uncleAddresses.push_back(ubi.coinbaseAddress); uncleBlockHeaders.push_back(ubi);
if (unclesCount == 2) if (unclesCount == 2)
break; break;
} }
@ -760,7 +760,7 @@ void State::commitToMine(BlockChain const& _bc)
m_currentBlock.sha3Uncles = sha3(m_currentUncles); m_currentBlock.sha3Uncles = sha3(m_currentUncles);
// Apply rewards last of all. // Apply rewards last of all.
applyRewards(uncleAddresses); applyRewards(uncleBlockHeaders);
// Commit any and all changes to the trie that are in the cache, then update the state root accordingly. // Commit any and all changes to the trie that are in the cache, then update the state root accordingly.
commit(); commit();
@ -1148,12 +1148,12 @@ State State::fromPending(unsigned _i) const
return ret; return ret;
} }
void State::applyRewards(Addresses const& _uncleAddresses) void State::applyRewards(vector<BlockInfo> const& _uncleBlockHeaders)
{ {
u256 r = m_blockReward; u256 r = m_blockReward;
for (auto const& i: _uncleAddresses) for (auto const& i: _uncleBlockHeaders)
{ {
addBalance(i, m_blockReward * 15 / 16); addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8);
r += m_blockReward / 32; r += m_blockReward / 32;
} }
addBalance(m_currentBlock.coinbaseAddress, r); addBalance(m_currentBlock.coinbaseAddress, r);

2
libethereum/State.h

@ -314,7 +314,7 @@ private:
u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true); u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true);
/// Finalise the block, applying the earned rewards. /// Finalise the block, applying the earned rewards.
void applyRewards(Addresses const& _uncleAddresses); void applyRewards(std::vector<BlockInfo> const& _uncleBlockHeaders);
/// @returns gas used by transactions thus far executed. /// @returns gas used by transactions thus far executed.
u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; } u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; }

22
libevmcore/Assembly.cpp

@ -77,6 +77,20 @@ int AssemblyItem::deposit() const
return 0; return 0;
} }
string AssemblyItem::getJumpTypeAsString() const
{
switch (m_jumpType)
{
case JumpType::IntoFunction:
return "[in]";
case JumpType::OutOfFunction:
return "[out]";
case JumpType::Ordinary:
default:
return "";
}
}
unsigned Assembly::bytesRequired() const unsigned Assembly::bytesRequired() const
{ {
for (unsigned br = 1;; ++br) for (unsigned br = 1;; ++br)
@ -196,7 +210,7 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc
return move(cut); return move(cut);
} }
ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
{ {
_out << _prefix << ".code:" << endl; _out << _prefix << ".code:" << endl;
for (AssemblyItem const& i: m_items) for (AssemblyItem const& i: m_items)
@ -205,7 +219,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con
switch (i.m_type) switch (i.m_type)
{ {
case Operation: case Operation:
_out << " " << instructionInfo((Instruction)(byte)i.m_data).name; _out << " " << instructionInfo((Instruction)(byte)i.m_data).name << "\t" << i.getJumpTypeAsString();
break; break;
case Push: case Push:
_out << " PUSH " << i.m_data; _out << " PUSH " << i.m_data;
@ -240,7 +254,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con
default: default:
BOOST_THROW_EXCEPTION(InvalidOpcode()); BOOST_THROW_EXCEPTION(InvalidOpcode());
} }
_out << string("\t\t") << getLocationFromSources(_sourceCodes, i.getLocation()) << endl; _out << "\t\t" << getLocationFromSources(_sourceCodes, i.getLocation()) << endl;
} }
if (!m_data.empty() || !m_subs.empty()) if (!m_data.empty() || !m_subs.empty())
@ -252,7 +266,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con
for (size_t i = 0; i < m_subs.size(); ++i) for (size_t i = 0; i < m_subs.size(); ++i)
{ {
_out << _prefix << " " << hex << i << ": " << endl; _out << _prefix << " " << hex << i << ": " << endl;
m_subs[i].streamRLP(_out, _prefix + " ", _sourceCodes); m_subs[i].stream(_out, _prefix + " ", _sourceCodes);
} }
} }
return _out; return _out;

15
libevmcore/Assembly.h

@ -42,6 +42,8 @@ class AssemblyItem
friend class Assembly; friend class Assembly;
public: public:
enum class JumpType { Ordinary, IntoFunction, OutOfFunction };
AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} AssemblyItem(u256 _push): m_type(Push), m_data(_push) {}
AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {}
AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {}
@ -58,13 +60,18 @@ public:
int deposit() const; int deposit() const;
bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); } bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); }
void setLocation(SourceLocation const& _location) { m_location = _location;} void setLocation(SourceLocation const& _location) { m_location = _location; }
SourceLocation const& getLocation() const { return m_location; } SourceLocation const& getLocation() const { return m_location; }
void setJumpType(JumpType _jumpType) { m_jumpType = _jumpType; }
JumpType getJumpType() const { return m_jumpType; }
std::string getJumpTypeAsString() const;
private: private:
AssemblyItemType m_type; AssemblyItemType m_type;
u256 m_data; u256 m_data;
SourceLocation m_location; SourceLocation m_location;
JumpType m_jumpType;
}; };
using AssemblyItems = std::vector<AssemblyItem>; using AssemblyItems = std::vector<AssemblyItem>;
@ -114,7 +121,7 @@ public:
void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); }
void injectStart(AssemblyItem const& _i); void injectStart(AssemblyItem const& _i);
std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); } std::string out() const { std::stringstream ret; stream(ret); return ret.str(); }
int deposit() const { return m_deposit; } int deposit() const { return m_deposit; }
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
@ -124,7 +131,7 @@ public:
bytes assemble() const; bytes assemble() const;
Assembly& optimise(bool _enable); Assembly& optimise(bool _enable);
std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const; std::ostream& stream(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const;
protected: protected:
std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const;
@ -146,7 +153,7 @@ protected:
inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a)
{ {
_a.streamRLP(_out); _a.stream(_out);
return _out; return _out;
} }

20
libnatspec/NatspecExpressionEvaluator.cpp

@ -35,25 +35,23 @@ static QString contentsOfQResource(string const& _res)
return in.readAll(); return in.readAll();
} }
NatspecExpressionEvaluator::NatspecExpressionEvaluator(QString const& _abi, QString const& _method, QString const& _params) NatspecExpressionEvaluator::NatspecExpressionEvaluator(QString const& _abi, QString const& _transaction, QString const& _method)
: m_abi(_abi), m_transaction(_transaction), m_method(_method)
{ {
Q_INIT_RESOURCE(natspec); Q_INIT_RESOURCE(natspec);
QJSValue result = m_engine.evaluate(contentsOfQResource(":/natspec/natspec.js")); QJSValue result = m_engine.evaluate(contentsOfQResource(":/natspec/natspec.js"));
if (result.isError()) if (result.isError())
BOOST_THROW_EXCEPTION(FileError()); BOOST_THROW_EXCEPTION(FileError());
m_engine.evaluate("globals.abi = " + _abi); m_engine.evaluate("var natspec = require('natspec')");
m_engine.evaluate("globals.method = " + _method);
m_engine.evaluate("globals.params = " + _params);
} }
QString NatspecExpressionEvaluator::evalExpression(QString const& _expression) QString NatspecExpressionEvaluator::evalExpression(QString const& _expression)
{ {
QJSValue result = m_engine.evaluate("evaluateExpression(\"" + _expression + "\")"); QString call = "";
if (result.isError()) if (!m_abi.isEmpty() && !m_transaction.isEmpty() && !m_method.isEmpty())
{ call = ", {abi:" + m_abi + ", transaction:" + m_transaction + ", method: '" + m_method + "' }";
cerr << "Could not evaluate expression: \"" << _expression.toStdString() << "\"" << endl;
return _expression; QJSValue result = m_engine.evaluate("natspec.evaluateExpressionSafe(\"" + _expression + "\"" + call + ")");
}
return result.toString(); return result.toString();
} }

9
libnatspec/NatspecExpressionEvaluator.h

@ -34,12 +34,10 @@ class NatspecExpressionEvaluator
public: public:
/// Construct natspec expression evaluator /// Construct natspec expression evaluator
/// @params abi - contract's abi in json format, passed as string /// @params abi - contract's abi in json format, passed as string
/// @params transaction - json object containing transaction data
/// @params method - name of the contract's method for which we evaluate the natspec. /// @params method - name of the contract's method for which we evaluate the natspec.
/// If we want to use raw string, it should be passed with quotation marks eg. "\"helloWorld\""
/// If we pass string "helloWorld", the value of the object with name "helloWorld" will be used
/// @params params - array of method input params, passed as string, objects in array should be
/// javascript valid objects /// javascript valid objects
NatspecExpressionEvaluator(QString const& _abi = "[]", QString const& _method = "", QString const& _params = "[]"); NatspecExpressionEvaluator(QString const& _abi = "[]", QString const& _transaction = "{}", QString const& _method = "");
/// Should be called to evaluate natspec expression /// Should be called to evaluate natspec expression
/// @params expression - natspec expression /// @params expression - natspec expression
@ -48,4 +46,7 @@ public:
private: private:
QJSEngine m_engine; QJSEngine m_engine;
QString m_abi;
QString m_transaction;
QString m_method;
}; };

102
libnatspec/natspec.js

@ -1,102 +0,0 @@
/**
* This plugin exposes 'evaluateExpression' method which should be used
* to evaluate natspec description
*/
/// Object which should be used by NatspecExpressionEvaluator
/// abi - abi of the contract that will be used
/// method - name of the method that is called
/// params - input params of the method that will be called
var globals = {
abi: [],
method: "",
params: []
};
/// Helper method
/// Should be called to copy values from object to global context
var copyToContext = function (obj, context) {
var keys = Object.keys(obj);
keys.forEach(function (key) {
context[key] = obj[key];
});
}
/// Helper method
/// Should be called to get method with given name from the abi
/// @param contract's abi
/// @param name of the method that we are looking for
var getMethodWithName = function(abi, name) {
for (var i = 0; i < abi.length; i++) {
if (abi[i].name === name) {
return abi[i];
}
}
//console.warn('could not find method with name: ' + name);
return undefined;
};
/// Function called to get all contract's storage values
/// @returns hashmap with contract properties which are used
/// TODO: check if this function will be used
var getContractProperties = function (address, abi) {
return {};
};
/// Function called to get all contract's methods
/// @returns hashmap with used contract's methods
/// TODO: check if this function will be used
var getContractMethods = function (address, abi) {
//return web3.eth.contract(address, abi); // commented out web3 usage
return {};
};
/// Function called to get all contract method input variables
/// @returns hashmap with all contract's method input variables
var getMethodInputParams = function (method, params) {
return method.inputs.reduce(function (acc, current, index) {
acc[current.name] = params[index];
return acc;
}, {});
};
/// Should be called to evaluate single expression
/// Is internally using javascript's 'eval' method
/// Should be checked if it is safe
var evaluateExpression = function (expression) {
var self = this;
//var storage = getContractProperties(address, abi);
//var methods = getContractMethods(address, abi);
var method = getMethodWithName(globals.abi, globals.method);
if (method) {
var input = getMethodInputParams(method, globals.params);
copyToContext(input, self);
}
// TODO: test if it is safe
var evaluatedExpression = "";
// match everything in `` quotes
var pattern = /\`(?:\\.|[^`\\])*\`/gim
var match;
var lastIndex = 0;
while ((match = pattern.exec(expression)) !== null) {
var startIndex = pattern.lastIndex - match[0].length;
var toEval = match[0].slice(1, match[0].length - 1);
evaluatedExpression += expression.slice(lastIndex, startIndex);
evaluatedExpression += eval(toEval).toString();
lastIndex = pattern.lastIndex;
}
evaluatedExpression += expression.slice(lastIndex);
return evaluatedExpression;
};

2
libnatspec/natspec.qrc

@ -1,5 +1,5 @@
<RCC> <RCC>
<qresource prefix="/natspec"> <qresource prefix="/natspec">
<file>natspec.js</file> <file alias="natspec.js">natspecjs/dist/natspec.min.js</file>
</qresource> </qresource>
</RCC> </RCC>

3
libnatspec/natspecjs/.gitignore

@ -0,0 +1,3 @@
# VIM stuff
*.swp
node_modules/

8
libnatspec/natspecjs/.travis.yml

@ -0,0 +1,8 @@
language: node_js
node_js:
- "0.11"
- "0.10"
before_script:
- npm install
after_script:
- npm run-script test-coveralls

47
libnatspec/natspecjs/README.md

@ -0,0 +1,47 @@
# natspec.js
Javascript Library used to evaluate natspec expressions
[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url]
[travis-image]: https://travis-ci.org/ethereum/natspec.js.svg
[travis-url]: https://travis-ci.org/ethereum/natspec.js
[coveralls-image]: https://coveralls.io/repos/ethereum/natspec.js/badge.svg?branch=master
[coveralls-url]: https://coveralls.io/r/ethereum/natspec.js?branch=master
## Usage
It exposes global object `natspec` with method `evaluateExpression`.
```javascript
var natspec = require('natspec');
var natspecExpression = "Will multiply `a` by 7 and return `a * 7`.";
var call = {
method: 'multiply',
abi: abi,
transaction: transaction
};
var evaluatedExpression = natspec.evaluateExpression(natspecExpression, call);
console.log(evaluatedExpression); // "Will multiply 4 by 7 and return 28."
```
More examples are available [here](https://github.com/ethereum/natspec.js/blob/master/test/test.js).
## Building
```bash
npm run-script build
```
## Testing (mocha)
```bash
npm test
```
## Wiki
* [Ethereum Natural Specification Format](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format)
* [Natspec Example](https://github.com/ethereum/wiki/wiki/Natspec-Example)

3570
libnatspec/natspecjs/dist/natspec.js

File diff suppressed because it is too large

1
libnatspec/natspecjs/dist/natspec.js.map

File diff suppressed because one or more lines are too long

2
libnatspec/natspecjs/dist/natspec.min.js

File diff suppressed because one or more lines are too long

13
libnatspec/natspecjs/example/example.html

@ -0,0 +1,13 @@
<!doctype>
<html>
<head>
<script type="text/javascript" src="../dist/natspec.js"></script>
<script type="text/javascript">
var natspec = require('natspec');
</script>
</head>
<body>
</body>
</html>

186
libnatspec/natspecjs/natspec.js

@ -0,0 +1,186 @@
/*
This file is part of natspec.js.
natspec.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
natspec.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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with natspec.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file natspec.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var abi = require('./node_modules/ethereum.js/lib/abi.js');
/**
* This object should be used to evaluate natspec expression
* It has one method evaluateExpression which shoul be used
*/
var natspec = (function () {
/**
* Helper method
* Should be called to copy values from object to global context
*
* @method copyToContext
* @param {Object} object from which we want to copy properties
* @param {Object} object to which we copy
*/
var copyToContext = function (obj, context) {
Object.keys(obj).forEach(function (key) {
context[key] = obj[key];
});
}
/**
* Should be used to generate codes, which will be evaluated
*
* @method generateCode
* @param {Object} object from which code will be generated
* @return {String} javascript code which is used to initalized variables
*/
var generateCode = function (obj) {
return Object.keys(obj).reduce(function (acc, key) {
return acc + "var " + key + " = context['" + key + "'];\n";
}, "");
};
/**
* Helper method
* Should be called to get method with given name from the abi
*
* @method getMethodWithName
* @param {Array} contract's abi
* @param {String} name of the method that we are looking for
* @return {Object} abi for method with name
*/
var getMethodWithName = function(abi, name) {
return abi.filter(function (method) {
return method.name === name;
})[0];
};
/**
* Should be used to get all contract method input variables
*
* @method getMethodInputParams
* @param {Object} abi for certain method
* @param {Object} transaction object
* @return {Object} object with all contract's method input variables
*/
var getMethodInputParams = function (method, transaction) {
// do it with output formatter (cause we have to decode)
var params = abi.formatOutput(method.inputs, '0x' + transaction.params[0].data.slice(10));
return method.inputs.reduce(function (acc, current, index) {
acc[current.name] = params[index];
return acc;
}, {});
};
/**
* Should be called when we want to evaluate natspec expression
* Replaces all natspec 'subexpressions' with evaluated value
*
* @method mapExpressionToEvaluate
* @param {String} expression to evaluate
* @param {Function} callback which is called to evaluate te expression
* @return {String} evaluated expression
*/
var mapExpressionsToEvaluate = function (expression, cb) {
var evaluatedExpression = "";
// match everything in `` quotes
var pattern = /\`(?:\\.|[^`\\])*\`/gim
var match;
var lastIndex = 0;
try {
while ((match = pattern.exec(expression)) !== null) {
var startIndex = pattern.lastIndex - match[0].length;
var toEval = match[0].slice(1, match[0].length - 1);
evaluatedExpression += expression.slice(lastIndex, startIndex);
var evaluatedPart = cb(toEval);
evaluatedExpression += evaluatedPart;
lastIndex = pattern.lastIndex;
}
evaluatedExpression += expression.slice(lastIndex);
}
catch (err) {
throw new Error("Natspec evaluation failed, wrong input params");
}
return evaluatedExpression;
};
/**
* Should be called to evaluate single expression
* Is internally using javascript's 'eval' method
*
* @method evaluateExpression
* @param {String} expression which should be evaluated
* @param {Object} [call] object containing contract abi, transaction, called method
* @return {String} evaluated expression
* @throws exception if method is not found or we are trying to evaluate input params that does not exists
*/
var evaluateExpression = function (expression, call) {
//var self = this;
var context = {};
if (!!call) {
try {
var method = getMethodWithName(call.abi, call.method);
var params = getMethodInputParams(method, call.transaction);
copyToContext(params, context);
}
catch (err) {
throw new Error("Natspec evaluation failed, method does not exist");
}
}
var code = generateCode(context);
var evaluatedExpression = mapExpressionsToEvaluate(expression, function (toEval) {
var fn = new Function("context", code + "return " + toEval + ";");
return fn(context).toString();
});
return evaluatedExpression;
};
/**
* Safe version of evaluateExpression
* Instead of throwing an exception it returns it as a string
*
* @method evaluateExpressionSafe
* @param {String} expression which should be evaluated
* @param {Object} [call] object containing contract abi, transaction, called method
* @return {String} evaluated expression
*/
var evaluateExpressionSafe = function (expression, call) {
try {
return evaluateExpression(expression, call);
}
catch (err) {
return err.message;
}
};
return {
evaluateExpression: evaluateExpression,
evaluateExpressionSafe: evaluateExpressionSafe
};
})();
module.exports = natspec;

24
libnatspec/natspecjs/package.json

@ -0,0 +1,24 @@
{
"name": "natspec.js",
"version": "0.0.1",
"description": "Javascript Library used to evaluate natspec expressions",
"main": "natspec.js",
"scripts": {
"build": "cd dist && browserify -r ../natspec.js:natspec -i crypto -o natspec.js && uglifyjs natspec.js --source-map natspec.js.map -c -m -o natspec.min.js",
"test": "mocha",
"test-coveralls": "istanbul cover _mocha -- -R spec && cat coverage/lcov.info | coveralls --verbose"
},
"author": "",
"dependencies": {
"ethereum.js": "ethereum/ethereum.js#master"
},
"devDependencies": {
"browserify": "^9.0.3",
"chai": "^2.1.0",
"coveralls": "^2.11.2",
"istanbul": "^0.3.6",
"mocha": "^2.1.0",
"uglify-js": "^2.4.16"
},
"license": "LGPL-3.0"
}

149
libnatspec/natspecjs/test/test.js

@ -0,0 +1,149 @@
var chai = require('chai');
var natspec = require('../natspec.js');
var assert = chai.assert;
describe('natspec', function () {
it('should evaluate simple expression', function () {
// given
var expression = "`x = 1` + `y = 2` will be equal `x + y`";
// when
var result = natspec.evaluateExpression(expression);
var result2 = natspec.evaluateExpressionSafe(expression);
// then
assert.equal(result, "1 + 2 will be equal 3");
assert.equal(result2, "1 + 2 will be equal 3");
});
it('should evalute expression using input params', function () {
//given
var expression = "Will multiply `a` by 7 and return `a * 7`.";
var method = 'multiply';
var abi = [{
"name": "multiply",
"constant": false,
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}],
"outputs": [{
"name": "d",
"type": "uint256"
}]
}];
var transaction = {
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x8521742d3f456bd237e312d6e30724960f72517a",
"data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a"
}],
"id": 6
};
var call = {
method: method,
abi: abi,
transaction: transaction
};
// when
var result = natspec.evaluateExpression(expression, call);
var result2 = natspec.evaluateExpressionSafe(expression, call);
// then
assert.equal(result, "Will multiply 122 by 7 and return 854.");
assert.equal(result2, "Will multiply 122 by 7 and return 854.");
});
it('should evalute expression using input params', function () {
//given
var expression = "Will multiply `a` by 7 and return `a * 7`.";
var method = 'multiply';
var abi = [{
"name": "multiply",
"constant": false,
"type": "function",
"inputs": [{
"name": "b",
"type": "uint256"
}],
"outputs": [{
"name": "d",
"type": "uint256"
}]
}];
var transaction = {
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x8521742d3f456bd237e312d6e30724960f72517a",
"data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a"
}],
"id": 6
};
var call = {
method: method,
abi: abi,
transaction: transaction
};
// when
var exceptionThrow = function () { natspec.evaluateExpression(expression, call);}
var result = natspec.evaluateExpressionSafe(expression, call);
// then
assert.equal(result, "Natspec evaluation failed, wrong input params");
assert.throws(exceptionThrow, "Natspec evaluation failed, wrong input params");
});
it('should evalute expression using input params', function () {
//given
var expression = "Will multiply `a` by 7 and return `a * 7`.";
var method = 'multiply2';
var abi = [{
"name": "multiply",
"constant": false,
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}],
"outputs": [{
"name": "d",
"type": "uint256"
}]
}];
var transaction = {
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x8521742d3f456bd237e312d6e30724960f72517a",
"data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a"
}],
"id": 6
};
var call = {
method: method,
abi: abi,
transaction: transaction
};
// when
var exceptionThrow = function () { natspec.evaluateExpression(expression, call);}
var result = natspec.evaluateExpressionSafe(expression, call);
// then
assert.equal(result, "Natspec evaluation failed, method does not exist");
assert.throws(exceptionThrow, "Natspec evaluation failed, method does not exist");
});
});

3
libsolidity/Compiler.cpp

@ -378,8 +378,9 @@ bool Compiler::visit(FunctionDefinition const& _function)
m_context.removeVariable(*localVariable); m_context.removeVariable(*localVariable);
m_context.adjustStackOffset(-(int)c_returnValuesSize); m_context.adjustStackOffset(-(int)c_returnValuesSize);
if (!_function.isConstructor()) if (!_function.isConstructor())
m_context << eth::Instruction::JUMP; m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
return false; return false;
} }

4
libsolidity/Compiler.h

@ -94,8 +94,8 @@ private:
std::vector<eth::AssemblyItem> m_continueTags; ///< tag to jump to for a "continue" statement std::vector<eth::AssemblyItem> m_continueTags; ///< tag to jump to for a "continue" statement
eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement
unsigned m_modifierDepth = 0; unsigned m_modifierDepth = 0;
FunctionDefinition const* m_currentFunction; FunctionDefinition const* m_currentFunction = nullptr;
unsigned m_stackCleanupForReturn; ///< this number of stack elements need to be removed before jump to m_returnTag unsigned m_stackCleanupForReturn = 0; ///< this number of stack elements need to be removed before jump to m_returnTag
// arguments for base constructors, filled in derived-to-base order // arguments for base constructors, filled in derived-to-base order
std::map<FunctionDefinition const*, std::vector<ASTPointer<Expression>> const*> m_baseArguments; std::map<FunctionDefinition const*, std::vector<ASTPointer<Expression>> const*> m_baseArguments;
}; };

7
libsolidity/CompilerContext.cpp

@ -177,6 +177,13 @@ u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declarati
return it->second; return it->second;
} }
CompilerContext& CompilerContext::appendJump(eth::AssemblyItem::JumpType _jumpType)
{
eth::AssemblyItem item(eth::Instruction::JUMP);
item.setJumpType(_jumpType);
return *this << item;
}
void CompilerContext::resetVisitedNodes(ASTNode const* _node) void CompilerContext::resetVisitedNodes(ASTNode const* _node)
{ {
stack<ASTNode const*> newStack; stack<ASTNode const*> newStack;

4
libsolidity/CompilerContext.h

@ -91,7 +91,7 @@ public:
/// Appends a JUMP to a new tag and @returns the tag /// Appends a JUMP to a new tag and @returns the tag
eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); } eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); }
/// Appends a JUMP to a tag already on the stack /// Appends a JUMP to a tag already on the stack
CompilerContext& appendJump() { return *this << eth::Instruction::JUMP; } CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary);
/// Appends a JUMP to a specific tag /// Appends a JUMP to a specific tag
CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; }
/// Appends pushing of a new tag and @returns the new tag. /// Appends pushing of a new tag and @returns the new tag.
@ -120,7 +120,7 @@ public:
eth::Assembly const& getAssembly() const { return m_asm; } eth::Assembly const& getAssembly() const { return m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings /// @arg _sourceCodes is the map of input files to source code strings
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.streamRLP(_stream, "", _sourceCodes); } void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.stream(_stream, "", _sourceCodes); }
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }

5
libsolidity/ExpressionCompiler.cpp

@ -108,7 +108,8 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
retSizeOnStack = returnType->getSizeOnStack(); retSizeOnStack = returnType->getSizeOnStack();
} }
solAssert(retSizeOnStack <= 15, "Stack too deep."); solAssert(retSizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP; m_context << eth::dupInstruction(retSizeOnStack + 1);
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
} }
void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
@ -405,7 +406,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
} }
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
m_context.appendJump(); m_context.appendJump(eth::AssemblyItem::JumpType::IntoFunction);
m_context << returnLabel; m_context << returnLabel;
unsigned returnParametersSize = CompilerUtils::getSizeOnStack(function.getReturnParameterTypes()); unsigned returnParametersSize = CompilerUtils::getSizeOnStack(function.getReturnParameterTypes());

2
libsolidity/Parser.h

@ -34,6 +34,8 @@ class Scanner;
class Parser class Parser
{ {
public: public:
Parser() {}
ASTPointer<SourceUnit> parse(std::shared_ptr<Scanner> const& _scanner); ASTPointer<SourceUnit> parse(std::shared_ptr<Scanner> const& _scanner);
std::shared_ptr<std::string const> const& getSourceName() const; std::shared_ptr<std::string const> const& getSourceName() const;

3
mix/AppContext.cpp

@ -37,6 +37,7 @@
#include "QVariableDefinition.h" #include "QVariableDefinition.h"
#include "HttpServer.h" #include "HttpServer.h"
#include "AppContext.h" #include "AppContext.h"
#include "SortFilterProxyModel.h"
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
@ -74,6 +75,7 @@ void AppContext::load()
qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType"); qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration"); qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration");
qmlRegisterType<RecordLogEntry>("org.ethereum.qml.RecordLogEntry", 1, 0, "RecordLogEntry"); qmlRegisterType<RecordLogEntry>("org.ethereum.qml.RecordLogEntry", 1, 0, "RecordLogEntry");
qmlRegisterType<SortFilterProxyModel>("org.ethereum.qml.SortFilterProxyModel", 1, 0, "SortFilterProxyModel");
QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml")); QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml"));
QObject* projectModel = projectModelComponent.create(); QObject* projectModel = projectModelComponent.create();
if (projectModelComponent.isError()) if (projectModelComponent.isError())
@ -86,6 +88,7 @@ void AppContext::load()
m_applicationEngine->rootContext()->setContextProperty("projectModel", projectModel); m_applicationEngine->rootContext()->setContextProperty("projectModel", projectModel);
qmlRegisterType<CodeEditorExtensionManager>("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); qmlRegisterType<CodeEditorExtensionManager>("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager");
qmlRegisterType<HttpServer>("HttpServer", 1, 0, "HttpServer"); qmlRegisterType<HttpServer>("HttpServer", 1, 0, "HttpServer");
m_applicationEngine->load(QUrl("qrc:/qml/main.qml")); m_applicationEngine->load(QUrl("qrc:/qml/main.qml"));
QWindow *window = qobject_cast<QWindow*>(m_applicationEngine->rootObjects().at(0)); QWindow *window = qobject_cast<QWindow*>(m_applicationEngine->rootObjects().at(0));
window->setIcon(QIcon(":/res/mix_256x256x32.png")); window->setIcon(QIcon(":/res/mix_256x256x32.png"));

9
mix/CodeEditorExtensionManager.cpp

@ -51,14 +51,6 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
return; return;
} }
void CodeEditorExtensionManager::initExtensions()
{
std::shared_ptr<StatusPane> output = std::make_shared<StatusPane>(m_appContext);
QObject::connect(m_appContext->codeModel(), &CodeModel::compilationComplete, this, &CodeEditorExtensionManager::applyCodeHighlight);
initExtension(output);
}
void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext) void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext)
{ {
if (!_ext->contentUrl().isEmpty()) if (!_ext->contentUrl().isEmpty())
@ -93,5 +85,4 @@ void CodeEditorExtensionManager::setRightView(QQuickItem* _rightView)
void CodeEditorExtensionManager::setHeaderView(QQuickItem* _headerView) void CodeEditorExtensionManager::setHeaderView(QQuickItem* _headerView)
{ {
m_headerView = _headerView; m_headerView = _headerView;
initExtensions(); //TODO: move this to a proper place
} }

2
mix/CodeEditorExtensionManager.h

@ -49,8 +49,6 @@ class CodeEditorExtensionManager: public QObject
public: public:
CodeEditorExtensionManager(); CodeEditorExtensionManager();
~CodeEditorExtensionManager(); ~CodeEditorExtensionManager();
/// Initialize all extensions.
void initExtensions();
/// Initialize extension. /// Initialize extension.
void initExtension(std::shared_ptr<Extension>); void initExtension(std::shared_ptr<Extension>);
/// Set current tab view /// Set current tab view

2
mix/CodeModel.h

@ -164,6 +164,8 @@ public:
/// Find a contract by document id /// Find a contract by document id
/// @returns CompiledContract object or null if not found /// @returns CompiledContract object or null if not found
Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const; Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const;
/// Reset code model
Q_INVOKABLE void reset() { reset(QVariantMap()); }
signals: signals:
/// Emited on compilation state change /// Emited on compilation state change

2
mix/FileIo.cpp

@ -158,6 +158,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
} }
rlpStr.appendList(k); rlpStr.appendList(k);
manifest["entries"] = entries;
std::stringstream jsonStr; std::stringstream jsonStr;
jsonStr << manifest; jsonStr << manifest;
QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8(); QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8();
@ -166,7 +167,6 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
for (unsigned int k = 0; k < files.size(); k++) for (unsigned int k = 0; k < files.size(); k++)
rlpStr.append(files.at(k)); rlpStr.append(files.at(k));
manifest["entries"] = entries;
bytes dapp = rlpStr.out(); bytes dapp = rlpStr.out();
dev::h256 dappHash = dev::sha3(dapp); dev::h256 dappHash = dev::sha3(dapp);
//encrypt //encrypt

156
mix/SortFilterProxyModel.cpp

@ -0,0 +1,156 @@
/*
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 Yann <yann@ethdev.com>
* @date 2015
* Proxy used to filter a QML TableView.
*/
#include "SortFilterProxyModel.h"
#include <QtDebug>
#include <QtQml>
using namespace dev::mix;
SortFilterProxyModel::SortFilterProxyModel(QObject* _parent) : QSortFilterProxyModel(_parent)
{
connect(this, &SortFilterProxyModel::rowsInserted, this, &SortFilterProxyModel::countChanged);
connect(this, &SortFilterProxyModel::rowsRemoved, this, &SortFilterProxyModel::countChanged);
}
int SortFilterProxyModel::count() const
{
return rowCount();
}
QObject* SortFilterProxyModel::source() const
{
return sourceModel();
}
void SortFilterProxyModel::setSource(QObject* _source)
{
setSourceModel(qobject_cast<QAbstractItemModel*>(_source));
}
QByteArray SortFilterProxyModel::sortRole() const
{
return roleNames().value(QSortFilterProxyModel::sortRole());
}
void SortFilterProxyModel::setSortRole(QByteArray const& _role)
{
QSortFilterProxyModel::setSortRole(roleKey(_role));
}
void SortFilterProxyModel::setSortOrder(Qt::SortOrder _order)
{
QSortFilterProxyModel::sort(0, _order);
}
QString SortFilterProxyModel::filterString() const
{
return filterRegExp().pattern();
}
void SortFilterProxyModel::setFilterString(QString const& _filter)
{
setFilterRegExp(QRegExp(_filter, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax())));
}
SortFilterProxyModel::FilterSyntax SortFilterProxyModel::filterSyntax() const
{
return static_cast<FilterSyntax>(filterRegExp().patternSyntax());
}
void SortFilterProxyModel::setFilterSyntax(SortFilterProxyModel::FilterSyntax _syntax)
{
setFilterRegExp(QRegExp(filterString(), filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(_syntax)));
}
QJSValue SortFilterProxyModel::get(int _idx) const
{
QJSEngine *engine = qmlEngine(this);
QJSValue value = engine->newObject();
if (_idx >= 0 && _idx < count())
{
QHash<int, QByteArray> roles = roleNames();
QHashIterator<int, QByteArray> it(roles);
while (it.hasNext())
{
it.next();
value.setProperty(QString::fromUtf8(it.value()), data(index(_idx, 0), it.key()).toString());
}
}
return value;
}
int SortFilterProxyModel::roleKey(QByteArray const& _role) const
{
QHash<int, QByteArray> roles = roleNames();
QHashIterator<int, QByteArray> it(roles);
while (it.hasNext())
{
it.next();
if (it.value() == _role)
return it.key();
}
return -1;
}
QHash<int, QByteArray> SortFilterProxyModel::roleNames() const
{
if (QAbstractItemModel* source = sourceModel())
return source->roleNames();
return QHash<int, QByteArray>();
}
bool SortFilterProxyModel::filterAcceptsRow(int _sourceRow, QModelIndex const& _sourceParent) const
{
QAbstractItemModel* model = sourceModel();
QModelIndex sourceIndex = model->index(_sourceRow, 0, _sourceParent);
if (!sourceIndex.isValid())
return true;
QString keyType = model->data(sourceIndex, roleKey(type.toUtf8())).toString();
QString keyContent = model->data(sourceIndex, roleKey(content.toUtf8())).toString();
return keyType.contains(m_filterType) && keyContent.contains(m_filterContent);
}
void SortFilterProxyModel::setFilterType(QString const& _type)
{
m_filterType = QRegExp(_type, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax()));
setFilterRegExp(_type);
}
QString SortFilterProxyModel::filterType() const
{
return m_filterType.pattern();
}
void SortFilterProxyModel::setFilterContent(QString const& _content)
{
m_filterContent = QRegExp(_content, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax()));
setFilterRegExp(_content);
}
QString SortFilterProxyModel::filterContent() const
{
return m_filterContent.pattern();
}

97
mix/SortFilterProxyModel.h

@ -0,0 +1,97 @@
/*
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 Yann <yann@ethdev.com>
* @date 2015
* Proxy used to filter a QML TableView.
*/
#pragma once
#include <QtCore/qsortfilterproxymodel.h>
#include <QtQml/qjsvalue.h>
namespace dev
{
namespace mix
{
class SortFilterProxyModel: public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QObject* source READ source WRITE setSource)
Q_PROPERTY(QByteArray sortRole READ sortRole WRITE setSortRole)
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder)
Q_PROPERTY(QString filterContent READ filterContent WRITE setFilterContent)
Q_PROPERTY(QString filterType READ filterType WRITE setFilterType)
Q_PROPERTY(QString filterString READ filterString WRITE setFilterString)
Q_PROPERTY(FilterSyntax filterSyntax READ filterSyntax WRITE setFilterSyntax)
Q_ENUMS(FilterSyntax)
public:
explicit SortFilterProxyModel(QObject* _parent = 0);
QObject* source() const;
void setSource(QObject* _source);
QByteArray sortRole() const;
void setSortRole(QByteArray const& _role);
void setSortOrder(Qt::SortOrder _order);
QString filterContent() const;
void setFilterContent(QString const& _content);
QString filterType() const;
void setFilterType(QString const& _type);
QString filterString() const;
void setFilterString(QString const& _filter);
enum FilterSyntax {
RegExp,
Wildcard,
FixedString
};
FilterSyntax filterSyntax() const;
void setFilterSyntax(FilterSyntax _syntax);
int count() const;
Q_INVOKABLE QJSValue get(int _index) const;
signals:
void countChanged();
protected:
int roleKey(QByteArray const& _role) const;
QHash<int, QByteArray> roleNames() const;
bool filterAcceptsRow(int _sourceRow, QModelIndex const& _sourceParent) const;
private:
QRegExp m_filterType;
QRegExp m_filterContent;
const QString type = "type";
const QString content = "content";
};
}
}

302
mix/qml/LogsPane.qml

@ -0,0 +1,302 @@
import QtQuick 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.3
import org.ethereum.qml.SortFilterProxyModel 1.0
import "."
Rectangle
{
function push(_level, _type, _content)
{
_content = _content.replace(/\n/g, " ")
logsModel.insert(0, { "type": _type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss dd.MM.yyyy"), "content": _content, "level": _level });
}
anchors.fill: parent
radius: 5
color: LogsPaneStyle.generic.layout.backgroundColor
border.color: LogsPaneStyle.generic.layout.borderColor
border.width: LogsPaneStyle.generic.layout.borderWidth
ColumnLayout {
z: 2
height: parent.height
width: parent.width
spacing: 0
Row
{
id: rowAction
Layout.preferredHeight: LogsPaneStyle.generic.layout.headerHeight
height: LogsPaneStyle.generic.layout.headerHeight
anchors.leftMargin: LogsPaneStyle.generic.layout.leftMargin
anchors.left: parent.left
spacing: LogsPaneStyle.generic.layout.headerButtonSpacing
Button
{
height: LogsPaneStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter
action: clearAction
iconSource: "qrc:/qml/img/broom.png"
}
Action {
id: clearAction
enabled: logsModel.count > 0
tooltip: qsTr("Clear")
onTriggered: {
logsModel.clear()
}
}
Button
{
height: LogsPaneStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter
action: copytoClipBoardAction
iconSource: "qrc:/qml/img/copy.png"
}
Action {
id: copytoClipBoardAction
enabled: logsModel.count > 0
tooltip: qsTr("Copy to Clipboard")
onTriggered: {
var content = "";
for (var k = 0; k < logsModel.count; k++)
{
var log = logsModel.get(k);
content += log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content + "\n";
}
appContext.toClipboard(content);
}
}
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: 1;
height: parent.height - 10
color : "#808080"
}
ToolButton {
id: javascriptButton
checkable: true
height: LogsPaneStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter
checked: true
onCheckedChanged: {
proxyModel.toogleFilter("javascript")
}
tooltip: qsTr("JavaScript")
style:
ButtonStyle {
label:
Item {
DefaultLabel {
font.family: LogsPaneStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3)
color: LogsPaneStyle.generic.layout.logLabelColor
anchors.centerIn: parent
text: qsTr("JavaScript")
}
}
}
}
ToolButton {
id: runButton
checkable: true
height: LogsPaneStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter
checked: true
onCheckedChanged: {
proxyModel.toogleFilter("run")
}
tooltip: qsTr("Run")
style:
ButtonStyle {
label:
Item {
DefaultLabel {
font.family: LogsPaneStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3)
color: LogsPaneStyle.generic.layout.logLabelColor
anchors.centerIn: parent
text: qsTr("Run")
}
}
}
}
ToolButton {
id: stateButton
checkable: true
height: LogsPaneStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter
checked: true
onCheckedChanged: {
proxyModel.toogleFilter("state")
}
tooltip: qsTr("State")
style:
ButtonStyle {
label:
Item {
DefaultLabel {
font.family: LogsPaneStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3)
color: "#5391d8"
anchors.centerIn: parent
text: qsTr("State")
}
}
}
}
ToolButton {
id: compilationButton
checkable: true
height: LogsPaneStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter
checked: false
onCheckedChanged: {
proxyModel.toogleFilter("compilation")
}
tooltip: qsTr("Compilation")
style:
ButtonStyle {
label:
Item {
DefaultLabel {
font.family: LogsPaneStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3)
color: "#5391d8"
anchors.centerIn: parent
text: qsTr("Compilation")
}
}
}
}
DefaultTextField
{
id: searchBox
height: LogsPaneStyle.generic.layout.headerButtonHeight
anchors.verticalCenter: parent.verticalCenter
width: LogsPaneStyle.generic.layout.headerInputWidth
font.family: LogsPaneStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-3)
font.italic: true
onTextChanged: {
proxyModel.search(text);
}
}
}
ListModel {
id: logsModel
}
TableView {
id: logsTable
clip: true
Layout.fillWidth: true
Layout.preferredHeight: parent.height - rowAction.height
headerVisible : false
onDoubleClicked:
{
var log = logsModel.get((logsTable.currentRow));
if (log)
appContext.toClipboard(log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content);
}
model: SortFilterProxyModel {
id: proxyModel
source: logsModel
property var roles: ["-", "javascript", "run", "state"]
Component.onCompleted: {
filterType = regEx(proxyModel.roles);
}
function search(_value)
{
filterContent = _value;
}
function toogleFilter(_value)
{
var count = roles.length;
for (var i in roles)
{
if (roles[i] === _value)
{
roles.splice(i, 1);
break;
}
}
if (count === roles.length)
roles.push(_value);
filterType = regEx(proxyModel.roles);
}
function regEx(_value)
{
return "(?:" + roles.join('|') + ")";
}
filterType: "(?:javascript|run|state)"
filterContent: ""
filterSyntax: SortFilterProxyModel.RegExp
filterCaseSensitivity: Qt.CaseInsensitive
}
TableViewColumn
{
role: "date"
title: qsTr("date")
width: LogsPaneStyle.generic.layout.dateWidth
delegate: itemDelegate
}
TableViewColumn
{
role: "type"
title: qsTr("type")
width: LogsPaneStyle.generic.layout.typeWidth
delegate: itemDelegate
}
TableViewColumn
{
role: "content"
title: qsTr("content")
width: LogsPaneStyle.generic.layout.contentWidth
delegate: itemDelegate
}
rowDelegate: Item {
Rectangle {
width: logsTable.width - 4
height: 17
color: styleData.alternate ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor
}
}
}
Component {
id: itemDelegate
DefaultLabel {
text: styleData.value;
font.family: LogsPaneStyle.generic.layout.logLabelFont
font.pointSize: Style.absoluteSize(-1)
color: {
if (proxyModel.get(styleData.row).level === "error")
return "red";
else if (proxyModel.get(styleData.row).level === "warning")
return "orange";
else
return "#808080";
}
}
}
}
}

29
mix/qml/LogsPaneStyle.qml

@ -0,0 +1,29 @@
pragma Singleton
import QtQuick 2.0
QtObject {
function absoluteSize(rel)
{
return systemPointSize + rel;
}
property QtObject generic: QtObject {
property QtObject layout: QtObject {
property string backgroundColor: "#f7f7f7"
property string borderColor: "#5391d8"
property int borderWidth: 1
property int headerHeight: 35
property int headerButtonSpacing: 5
property int leftMargin: 10
property int headerButtonHeight: 30
property string logLabelColor: "#5391d8"
property string logLabelFont: "sans serif"
property int headerInputWidth: 200
property int dateWidth: 150
property int typeWidth: 80
property int contentWidth: 700
property string logAlternateColor: "#f0f0f0"
}
}
}

32
mix/qml/MainContent.qml

@ -35,8 +35,8 @@ Rectangle {
onCompilationComplete: { onCompilationComplete: {
if (firstCompile) { if (firstCompile) {
firstCompile = false; firstCompile = false;
if (runOnProjectLoad) if (runOnProjectLoad)
startQuickDebugging(); startQuickDebugging();
} }
} }
} }
@ -102,7 +102,6 @@ Rectangle {
} }
CodeEditorExtensionManager { CodeEditorExtensionManager {
headerView: headerPaneTabs;
} }
Settings { Settings {
@ -116,6 +115,7 @@ Rectangle {
ColumnLayout ColumnLayout
{ {
id: mainColumn
anchors.fill: parent anchors.fill: parent
spacing: 0 spacing: 0
Rectangle { Rectangle {
@ -133,21 +133,15 @@ Rectangle {
} }
id: headerPaneContainer id: headerPaneContainer
anchors.fill: parent anchors.fill: parent
TabView { StatusPane
id: headerPaneTabs {
tabsVisible: false
antialiasing: true
anchors.fill: parent anchors.fill: parent
style: TabViewStyle { webPreview: webPreview
frameOverlap: 1
tab: Rectangle {}
frame: Rectangle { color: "transparent" }
}
} }
} }
} }
Rectangle{ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
height: 1 height: 1
color: "#8c8c8c" color: "#8c8c8c"
@ -168,9 +162,9 @@ Rectangle {
{ {
anchors.fill: parent anchors.fill: parent
handleDelegate: Rectangle { handleDelegate: Rectangle {
width: 1 width: 1
height: 1 height: 1
color: "#8c8c8c" color: "#8c8c8c"
} }
orientation: Qt.Horizontal orientation: Qt.Horizontal
@ -180,16 +174,18 @@ Rectangle {
Layout.minimumWidth: 250 Layout.minimumWidth: 250
Layout.fillHeight: true Layout.fillHeight: true
} }
Rectangle { Rectangle {
id: contentView id: contentView
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
SplitView { SplitView {
handleDelegate: Rectangle { handleDelegate: Rectangle {
width: 1 width: 1
height: 1 height: 1
color: "#8c8c8c" color: "#8c8c8c"
} }
id: codeWebSplitter id: codeWebSplitter
anchors.fill: parent anchors.fill: parent
orientation: Qt.Vertical orientation: Qt.Vertical

10
mix/qml/ProjectModel.qml

@ -64,7 +64,7 @@ Item {
Connections { Connections {
target: appContext target: appContext
onAppLoaded: { onAppLoaded: {
if (projectSettings.lastProjectPath) if (projectSettings.lastProjectPath && projectSettings.lastProjectPath !== "")
projectModel.loadProject(projectSettings.lastProjectPath) projectModel.loadProject(projectSettings.lastProjectPath)
} }
} }
@ -130,6 +130,14 @@ Item {
id: projectStateListModel id: projectStateListModel
} }
Connections
{
target: projectModel
onProjectClosed: {
projectSettings.lastProjectPath = "";
}
}
Settings { Settings {
id: projectSettings id: projectSettings
property string lastProjectPath; property string lastProjectPath;

5
mix/qml/StateListModel.qml

@ -134,6 +134,7 @@ Item {
onProjectClosed: { onProjectClosed: {
stateListModel.clear(); stateListModel.clear();
stateList = []; stateList = [];
codeModel.reset();
} }
onProjectLoading: stateListModel.loadStatesFromProject(projectData); onProjectLoading: stateListModel.loadStatesFromProject(projectData);
onProjectSaving: { onProjectSaving: {
@ -148,6 +149,7 @@ Item {
state.title = qsTr("Default"); state.title = qsTr("Default");
projectData.states = [ state ]; projectData.states = [ state ];
projectData.defaultStateIndex = 0; projectData.defaultStateIndex = 0;
stateListModel.loadStatesFromProject(projectData);
} }
} }
@ -264,6 +266,7 @@ Item {
defaultStateIndex--; defaultStateIndex--;
save(); save();
} }
function save() { function save() {
@ -284,6 +287,8 @@ Item {
else else
defaultStateIndex = 0; defaultStateIndex = 0;
var items = projectData.states; var items = projectData.states;
stateListModel.clear();
stateList = [];
for(var i = 0; i < items.length; i++) { for(var i = 0; i < items.length; i++) {
var item = fromPlainStateItem(items[i]); var item = fromPlainStateItem(items[i]);
stateListModel.append(item); stateListModel.append(item);

170
mix/qml/StatusPane.qml

@ -8,6 +8,7 @@ import "."
Rectangle { Rectangle {
id: statusHeader id: statusHeader
objectName: "statusPane" objectName: "statusPane"
property variant webPreview
function updateStatus(message) function updateStatus(message)
{ {
@ -15,7 +16,6 @@ Rectangle {
{ {
status.state = ""; status.state = "";
status.text = qsTr("Compile successfully."); status.text = qsTr("Compile successfully.");
logslink.visible = false;
debugImg.state = "active"; debugImg.state = "active";
} }
else else
@ -23,39 +23,76 @@ Rectangle {
status.state = "error"; status.state = "error";
var errorInfo = ErrorLocationFormater.extractErrorInfo(message, true); var errorInfo = ErrorLocationFormater.extractErrorInfo(message, true);
status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail; status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail;
logslink.visible = true;
debugImg.state = ""; debugImg.state = "";
errorMessage(status.text, "Compilation");
} }
debugRunActionIcon.enabled = codeModel.hasContract; debugRunActionIcon.enabled = codeModel.hasContract;
} }
function infoMessage(text) function infoMessage(text, type)
{ {
status.state = ""; status.state = "";
status.text = text status.text = text
logslink.visible = false; logPane.push("info", type, text);
} }
function errorMessage(text) function warningMessage(text, type)
{
status.state = "warning";
status.text = text
logPane.push("warning", type, text);
}
function errorMessage(text, type)
{ {
status.state = "error"; status.state = "error";
status.text = text status.text = text
logslink.visible = false; logPane.push("error", type, text);
}
Connections {
target: webPreview
onJavaScriptMessage:
{
if (_level === 0)
infoMessage(_content, "JavaScript")
else
{
var message = _sourceId.substring(_sourceId.lastIndexOf("/") + 1) + " - " + qsTr("line") + " " + _lineNb + " - " + _content;
if (_level === 1)
warningMessage(message, "JavaScript")
else
errorMessage(message, "JavaScript")
}
}
} }
Connections { Connections {
target:clientModel target:clientModel
onRunStarted: infoMessage(qsTr("Running transactions...")); onRunStarted: infoMessage(qsTr("Running transactions..."), "Run");
onRunFailed: errorMessage(qsTr("Error running transactions: " + _message)); onRunFailed: errorMessage(format(_message), "Run");
onRunComplete: infoMessage(qsTr("Run complete")); onRunComplete: infoMessage(qsTr("Run complete"), "Run");
onNewBlock: infoMessage(qsTr("New block created")); onNewBlock: infoMessage(qsTr("New block created"), "State");
function format(_message)
{
var formatted = _message.match(/(?:<dev::eth::)(.+)(?:>)/);
if (formatted.length > 1)
formatted = formatted[1] + ": ";
else
return _message;
var exceptionInfos = _message.match(/(?:tag_)(.+)/g);
for (var k in exceptionInfos)
formatted += " " + exceptionInfos[k].replace("*]", "").replace("tag_", "").replace("=", "");
return formatted;
}
} }
Connections { Connections {
target:projectModel target:projectModel
onDeploymentStarted: infoMessage(qsTr("Running deployment...")); onDeploymentStarted: infoMessage(qsTr("Running deployment..."), "Deployment");
onDeploymentError: errorMessage(error); onDeploymentError: errorMessage(error, "Deployment");
onDeploymentComplete: infoMessage(qsTr("Deployment complete")); onDeploymentComplete: infoMessage(qsTr("Deployment complete"), "Deployment");
onDeploymentStepChanged: infoMessage(message); onDeploymentStepChanged: infoMessage(message, "Deployment");
} }
Connections { Connections {
target: codeModel target: codeModel
@ -74,6 +111,24 @@ Rectangle {
width: 500 width: 500
height: 30 height: 30
color: "#fcfbfc" color: "#fcfbfc"
states: [
State {
name: "logsOpened"
PropertyChanges {
target: statusContainer
border.color: "#5391d8"
border.width: 1
}
},
State {
name: "logsClosed"
PropertyChanges {
target: statusContainer
border.color: "#5391d8"
border.width: 0
}
}
]
Text { Text {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -98,6 +153,17 @@ Rectangle {
target: statusContainer target: statusContainer
color: "#fffcd5" color: "#fffcd5"
} }
},
State {
name: "warning"
PropertyChanges {
target: status
color: "orange"
}
PropertyChanges {
target: statusContainer
color: "#fffcd5"
}
} }
] ]
onTextChanged: onTextChanged:
@ -127,30 +193,73 @@ Rectangle {
color: "transparent" color: "transparent"
} }
} }
MouseArea {
anchors.fill: parent
onClicked: {
logsContainer.toggle();
}
}
} }
Action { Action {
id: toolTipInfo id: toolTipInfo
tooltip: "" tooltip: ""
} }
}
Button Rectangle
{ {
id: logslink function toggle()
anchors.left: statusContainer.right {
anchors.leftMargin: 9 if (logsContainer.state === "opened")
visible: false {
anchors.verticalCenter: parent.verticalCenter statusContainer.state = "logsClosed";
action: displayLogAction logsContainer.state = "closed"
iconSource: "qrc:/qml/img/search_filled.png" }
} else
{
statusContainer.state = "logsOpened";
logsContainer.state = "opened";
logsContainer.focus = true;
forceActiveFocus();
}
}
Action { id: logsContainer
id: displayLogAction width: 1000
tooltip: qsTr("Display Log") height: 0
onTriggered: { anchors.topMargin: 10
mainContent.displayCompilationErrorIfAny(); anchors.top: statusContainer.bottom
anchors.horizontalCenter: parent.horizontalCenter
visible: false
radius: 5
Component.onCompleted:
{
var top = logsContainer;
while (top.parent)
top = top.parent
var coordinates = logsContainer.mapToItem(top, 0, 0)
logsContainer.parent = top;
logsContainer.x = coordinates.x
logsContainer.y = coordinates.y
}
LogsPane
{
id: logPane
}
states: [
State {
name: "opened";
PropertyChanges { target: logsContainer; height: 500; visible: true }
},
State {
name: "closed";
PropertyChanges { target: logsContainer; height: 0; visible: false }
}
]
transitions: Transition {
NumberAnimation { properties: "height"; easing.type: Easing.InOutQuad; duration: 200 }
NumberAnimation { properties: "visible"; easing.type: Easing.InOutQuad; duration: 200 }
}
} }
} }
@ -168,7 +277,6 @@ Rectangle {
{ {
color: "transparent" color: "transparent"
anchors.fill: parent anchors.fill: parent
Button Button
{ {
anchors.right: parent.right anchors.right: parent.right

7
mix/qml/WebPreview.qml

@ -12,6 +12,7 @@ Item {
id: webPreview id: webPreview
property string pendingPageUrl: "" property string pendingPageUrl: ""
property bool initialized: false property bool initialized: false
signal javaScriptMessage(var _level, string _sourceId, var _lineNb, string _content)
function setPreviewUrl(url) { function setPreviewUrl(url) {
if (!initialized) if (!initialized)
@ -198,7 +199,6 @@ Item {
{ {
setPreviewUrl(text); setPreviewUrl(text);
} }
focus: true focus: true
} }
@ -216,7 +216,9 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 21 width: 21
height: 21 height: 21
focus: true
} }
CheckBox { CheckBox {
id: autoReloadOnSave id: autoReloadOnSave
checked: true checked: true
@ -227,6 +229,7 @@ Item {
text: qsTr("Auto reload on save") text: qsTr("Auto reload on save")
} }
} }
focus: true
} }
} }
} }
@ -240,7 +243,7 @@ Item {
id: webView id: webView
experimental.settings.localContentCanAccessRemoteUrls: true experimental.settings.localContentCanAccessRemoteUrls: true
onJavaScriptConsoleMessage: { onJavaScriptConsoleMessage: {
console.log(sourceID + ":" + lineNumber + ":" + message); webPreview.javaScriptMessage(level, sourceID, lineNumber, message);
} }
onLoadingChanged: { onLoadingChanged: {
if (!loading) { if (!loading) {

BIN
mix/qml/img/broom.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

BIN
mix/qml/img/copy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

21
mix/qml/js/ProjectModel.js

@ -105,7 +105,6 @@ function loadProject(path) {
contractSources[doc.documentId] = fileIo.readFile(doc.path); contractSources[doc.documentId] = fileIo.readFile(doc.path);
} }
codeModel.reset(contractSources); codeModel.reset(contractSources);
} }
function addFile(fileName) { function addFile(fileName) {
@ -377,8 +376,6 @@ function finalizeDeployment(deploymentId, addresses) {
else else
insertAt += 6; insertAt += 6;
html = html.substr(0, insertAt) + html = html.substr(0, insertAt) +
"<script src=\"bignumber.min.js\"></script>" +
"<script src=\"ethereum.js\"></script>" +
"<script src=\"deployment.js\"></script>" + "<script src=\"deployment.js\"></script>" +
html.substr(insertAt); html.substr(insertAt);
fileIo.writeFile(deploymentDir + doc.fileName, html); fileIo.writeFile(deploymentDir + doc.fileName, html);
@ -388,9 +385,8 @@ function finalizeDeployment(deploymentId, addresses) {
} }
//write deployment js //write deployment js
var deploymentJs = var deploymentJs =
"// Autogenerated by Mix\n" + "// Autogenerated by Mix\n" +
"web3 = require(\"web3\");\n" + "contracts = {};\n";
"contracts = {};\n";
for (var c in codeModel.contracts) { for (var c in codeModel.contracts) {
var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]";
deploymentJs += contractAccessor + " = {\n" + deploymentJs += contractAccessor + " = {\n" +
@ -400,9 +396,6 @@ function finalizeDeployment(deploymentId, addresses) {
contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n";
} }
fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs);
//copy scripts
fileIo.copyFile("qrc:///js/bignumber.min.js", deploymentDir + "bignumber.min.js");
fileIo.copyFile("qrc:///js/webthree.js", deploymentDir + "ethereum.js");
deploymentAddresses = addresses; deploymentAddresses = addresses;
saveProject(); saveProject();
@ -435,7 +428,7 @@ function checkEthPath(dappUrl, callBack)
//register() //register()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_call", method: "eth_call",
params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ], params: [ { "gas": 150000, "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
@ -472,7 +465,7 @@ function checkRegistration(dappUrl, addr, callBack)
//getOwner() //getOwner()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_call", method: "eth_call",
params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ], params: [ { "gas" : 2000, "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
@ -537,7 +530,7 @@ function checkRegistration(dappUrl, addr, callBack)
//setRegister() //setRegister()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ], params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
@ -570,7 +563,7 @@ function registerContentHash(registrar, callBack)
//setContent() //setContent()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ], params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
@ -587,7 +580,7 @@ function registerToUrlHint()
//urlHint => suggestUrl //urlHint => suggestUrl
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", method: "eth_transact",
params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 2000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 30000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });

1
mix/qml/qmldir

@ -5,3 +5,4 @@ singleton DebuggerPaneStyle 1.0 DebuggerPaneStyle.qml
singleton StateStyle 1.0 StateStyle.qml singleton StateStyle 1.0 StateStyle.qml
singleton StatusPaneStyle 1.0 StatusPaneStyle.qml singleton StatusPaneStyle 1.0 StatusPaneStyle.qml
singleton WebPreviewStyle 1.0 WebPreviewStyle.qml singleton WebPreviewStyle 1.0 WebPreviewStyle.qml
singleton LogsPaneStyle 1.0 LogsPaneStyle.qml

4
mix/res.qrc

@ -111,5 +111,9 @@
<file>qml/img/exit.png</file> <file>qml/img/exit.png</file>
<file>qml/img/run.png</file> <file>qml/img/run.png</file>
<file>qml/img/note.png</file> <file>qml/img/note.png</file>
<file>qml/LogsPane.qml</file>
<file>qml/img/copy.png</file>
<file>qml/img/broom.png</file>
<file>qml/LogsPaneStyle.qml</file>
</qresource> </qresource>
</RCC> </RCC>

32
pullSubtree.sh

@ -0,0 +1,32 @@
# usage
# ./pullsubtree [repository branch] [repository2 branch2]
#
# example
# ./pullSubtree evmjit master
# ./pullSubtree ethereumjs develop
# ./pullSubtree evmjit master ethereumjs master
evmjit_repo="https://github.com/ethereum/evmjit"
evmjit_location="evmjit"
ethereumjs_repo="https://github.com/ethereum/ethereum.js"
ethereumjs_location="libjsqrc/ethereumjs"
natspecjs_repo="https://github.com/ethereum/natspec.js"
natspecjs_location="libnatspec/natspecjs"
while [ "$1" != "" ]; do
case $1 in
evmjit | ethereumjs | natspecjs )
REPO="${1}_repo"
REPO=${!REPO}
LOCATION="${1}_location"
LOCATION=${!LOCATION}
shift
BRANCH=$1
git subtree pull --prefix=${LOCATION} ${REPO} ${BRANCH} --squash
;;
esac
shift
done

9
solc/CommandLineInterface.cpp

@ -272,7 +272,7 @@ bool CommandLineInterface::processInput()
while (!cin.eof()) while (!cin.eof())
{ {
getline(cin, s); getline(cin, s);
m_sourceCodes["<stdin>"].append(s); m_sourceCodes["<stdin>"].append(s + '\n');
} }
} }
else else
@ -345,18 +345,11 @@ bool CommandLineInterface::processInput()
void CommandLineInterface::handleAst(string const& _argStr) void CommandLineInterface::handleAst(string const& _argStr)
{ {
string title; string title;
string suffix;
if (_argStr == g_argAstStr) if (_argStr == g_argAstStr)
{
title = "Syntax trees:"; title = "Syntax trees:";
suffix = ".ast";
}
else if (_argStr == g_argAstJson) else if (_argStr == g_argAstJson)
{
title = "JSON AST:"; title = "JSON AST:";
suffix = ".json";
}
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal argStr for AST")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal argStr for AST"));

1
solc/docker_emscripten/Dockerfile

@ -10,6 +10,7 @@ RUN apt-get install -qy automake libtool yasm scons
RUN useradd -ms /bin/bash user RUN useradd -ms /bin/bash user
USER user USER user
ENV HOME /home/user
WORKDIR /home/user WORKDIR /home/user
# Emscripten SDK # Emscripten SDK

41
test/TestHelper.cpp

@ -181,46 +181,35 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost)
m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries());
// export post state // export post state
json_spirit::mObject postState;
for (auto const& a: _statePost.addresses())
{
json_spirit::mObject o;
o["balance"] = toString(_statePost.balance(a.first));
o["nonce"] = toString(_statePost.transactionsFrom(a.first));
{
json_spirit::mObject store;
for (auto const& s: _statePost.storage(a.first))
store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second));
o["storage"] = store;
}
o["code"] = "0x" + toHex(_statePost.code(a.first));
postState[toString(a.first)] = o;
}
m_TestObject["post"] = json_spirit::mValue(postState);
m_TestObject["post"] = fillJsonWithState(_statePost);
m_TestObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes()); m_TestObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes());
// export pre state // export pre state
json_spirit::mObject preState; m_TestObject["pre"] = fillJsonWithState(m_statePre);
}
json_spirit::mObject fillJsonWithState(State _state)
{
// export pre state
json_spirit::mObject oState;
for (auto const& a: m_statePre.addresses()) for (auto const& a: _state.addresses())
{ {
json_spirit::mObject o; json_spirit::mObject o;
o["balance"] = toString(m_statePre.balance(a.first)); o["balance"] = toString(_state.balance(a.first));
o["nonce"] = toString(m_statePre.transactionsFrom(a.first)); o["nonce"] = toString(_state.transactionsFrom(a.first));
{ {
json_spirit::mObject store; json_spirit::mObject store;
for (auto const& s: m_statePre.storage(a.first)) for (auto const& s: _state.storage(a.first))
store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second)); store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second));
o["storage"] = store; o["storage"] = store;
} }
o["code"] = "0x" + toHex(m_statePre.code(a.first)); o["code"] = "0x" + toHex(_state.code(a.first));
preState[toString(a.first)] = o; oState[toString(a.first)] = o;
} }
m_TestObject["pre"] = json_spirit::mValue(preState); return oState;
} }
u256 toInt(json_spirit::mValue const& _v) u256 toInt(json_spirit::mValue const& _v)

8
test/TestHelper.h

@ -117,6 +117,13 @@ private:
json_spirit::mObject& m_TestObject; json_spirit::mObject& m_TestObject;
}; };
class ZeroGasPricer: public eth::GasPricer
{
protected:
u256 ask(eth::State const&) const override { return 0; }
u256 bid(eth::TransactionPriority = eth::TransactionPriority::Medium) const override { return 0; }
};
// helping functions // helping functions
u256 toInt(json_spirit::mValue const& _v); u256 toInt(json_spirit::mValue const& _v);
byte toByte(json_spirit::mValue const& _v); byte toByte(json_spirit::mValue const& _v);
@ -136,6 +143,7 @@ void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::m
RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj); RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj);
void processCommandLineOptions(); void processCommandLineOptions();
eth::LastHashes lastHashes(u256 _currentBlockNumber); eth::LastHashes lastHashes(u256 _currentBlockNumber);
json_spirit::mObject fillJsonWithState(eth::State _state);
template<typename mapType> template<typename mapType>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)

18
test/bcUncleTestFiller.json

@ -265,23 +265,7 @@
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
}, },
{ {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "sameAsPreviousSibling" : "1"
"coinbase" : "0000000000000000000000000000000000000000",
"difficulty" : "131072",
"extraData" : "0x",
"gasLimit" : "99902343",
"gasUsed" : "0",
"hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04",
"mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770",
"nonce" : "18a524c1790fa83b",
"number" : "2",
"parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"seedHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd",
"timestamp" : "0x54c98c82",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
} }
] ]
} }

14
test/blockchain.cpp

@ -52,6 +52,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
ImportTest importer(o["pre"].get_obj()); ImportTest importer(o["pre"].get_obj());
State state(Address(), OverlayDB(), BaseState::Empty); State state(Address(), OverlayDB(), BaseState::Empty);
importer.importState(o["pre"].get_obj(), state); importer.importState(o["pre"].get_obj(), state);
o["pre"] = fillJsonWithState(state);
state.commit(); state.commit();
if (_fillin) if (_fillin)
@ -87,7 +88,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// get txs // get txs
TransactionQueue txs; TransactionQueue txs;
TrivialGasPricer gp; ZeroGasPricer gp;
BOOST_REQUIRE(blObj.count("transactions")); BOOST_REQUIRE(blObj.count("transactions"));
for (auto const& txObj: blObj["transactions"].get_array()) for (auto const& txObj: blObj["transactions"].get_array())
{ {
@ -101,10 +102,18 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BlockQueue uncleBlockQueue; BlockQueue uncleBlockQueue;
mArray aUncleList; mArray aUncleList;
vector<BlockInfo> vBiUncles; vector<BlockInfo> vBiUncles;
mObject uncleHeaderObj_pre;
for (auto const& uHObj: blObj["uncleHeaders"].get_array()) for (auto const& uHObj: blObj["uncleHeaders"].get_array())
{ {
mObject uncleHeaderObj = uHObj.get_obj(); mObject uncleHeaderObj = uHObj.get_obj();
if (uncleHeaderObj.count("sameAsPreviousSibling"))
{
writeBlockHeaderToJson(uncleHeaderObj_pre, vBiUncles[vBiUncles.size()-1]);
aUncleList.push_back(uncleHeaderObj_pre);
vBiUncles.push_back(vBiUncles[vBiUncles.size()-1]);
continue;
}
BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj);
// make uncle header valid // make uncle header valid
@ -123,6 +132,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
cnote << "import uncle in blockQueue"; cnote << "import uncle in blockQueue";
RLPStream uncle = createFullBlockFromHeader(uncleBlockFromFields); RLPStream uncle = createFullBlockFromHeader(uncleBlockFromFields);
uncleBlockQueue.import(&uncle.out(), bc); uncleBlockQueue.import(&uncle.out(), bc);
uncleHeaderObj_pre = uncleHeaderObj;
} }
blObj["uncleHeaders"] = aUncleList; blObj["uncleHeaders"] = aUncleList;
@ -579,6 +590,7 @@ void updatePoW(BlockInfo& _bi)
ret = pow.mine(_bi, 10000, true, true); // tie(ret, blockFromFields.nonce) ret = pow.mine(_bi, 10000, true, true); // tie(ret, blockFromFields.nonce)
Ethash::assignResult(ret.second, _bi); Ethash::assignResult(ret.second, _bi);
} }
_bi.hash = _bi.headerHash(WithNonce);
} }
void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi) void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi)

19
test/natspec.cpp

@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(natspec_eval_function_exists)
// given // given
NatspecExpressionEvaluator e; NatspecExpressionEvaluator e;
// when // when
string result = e.evalExpression("`typeof evaluateExpression`").toStdString(); string result = e.evalExpression("`typeof natspec.evaluateExpression`").toStdString();
// then // then
BOOST_CHECK_EQUAL(result, "function"); BOOST_CHECK_EQUAL(result, "function");
} }
@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(natspec_js_eval_input_params)
// given // given
char const* abi = R"([ char const* abi = R"([
{ {
"name": "f", "name": "multiply",
"constant": false, "constant": false,
"type": "function", "type": "function",
"inputs": [ "inputs": [
@ -94,7 +94,18 @@ BOOST_AUTO_TEST_CASE(natspec_js_eval_input_params)
] ]
} }
])"; ])";
NatspecExpressionEvaluator e(abi, "'f'", "[4]");
char const* transaction = R"({
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x8521742d3f456bd237e312d6e30724960f72517a",
"data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000004"
}],
"id": 6
})";
NatspecExpressionEvaluator e(abi, transaction , "multiply");
// when // when
string result = e.evalExpression("Will multiply `a` by 7 and return `a * 7`.").toStdString(); string result = e.evalExpression("Will multiply `a` by 7 and return `a * 7`.").toStdString();
// then // then
@ -108,7 +119,7 @@ BOOST_AUTO_TEST_CASE(natspec_js_eval_error)
// when // when
string result = e.evalExpression("`test(`").toStdString(); string result = e.evalExpression("`test(`").toStdString();
// then // then
BOOST_CHECK_EQUAL(result, "`test(`"); BOOST_CHECK_EQUAL(result, "Natspec evaluation failed, wrong input params");
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

89
test/stRefundTestFiller.json

@ -304,6 +304,95 @@
"data" : "" "data" : ""
} }
}, },
"refund_CallToSuicide" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (CALL 500 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : {
"0x01" : "0x01"
}
},
"aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (SUICIDE 0x095e7baea6a6c7c4c2dfeb977efac326af552d87) }",
"storage" : {
"0x01" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund_CallToSuicideTwice" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (CALL 500 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 ) (CALL 500 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : {
"0x01" : "0x01"
}
},
"aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (SUICIDE 0x095e7baea6a6c7c4c2dfeb977efac326af552d87) }",
"storage" : {
"0x01" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund_CallA" : { "refund_CallA" : {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

4
test/stTransactionTestFiller.json

@ -709,7 +709,7 @@
"pre" : "pre" :
{ {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000", "balance" : "180000",
"code" : "", "code" : "",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
@ -737,7 +737,7 @@
"transaction" : "transaction" :
{ {
"data" : "", "data" : "",
"gasLimit" : "50000", "gasLimit" : "150000",
"gasPrice" : "1", "gasPrice" : "1",
"nonce" : "", "nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",

64
test/vm.cpp

@ -533,33 +533,43 @@ BOOST_AUTO_TEST_CASE(vmPerformanceTest)
} }
} }
//BOOST_AUTO_TEST_CASE(vmInputLimitsTest1) BOOST_AUTO_TEST_CASE(vmInputLimitsTest1)
//{ {
// for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
// { {
// string arg = boost::unit_test::framework::master_test_suite().argv[i]; string arg = boost::unit_test::framework::master_test_suite().argv[i];
// if (arg == "--inputlimits" || arg == "--all") if (arg == "--inputlimits" || arg == "--all")
// { {
// auto start = chrono::steady_clock::now(); auto start = chrono::steady_clock::now();
// dev::test::executeTests("vmInputLimitsTest1", "/VMTests", dev::test::doVMTests); dev::test::executeTests("vmInputLimits1", "/VMTests", dev::test::doVMTests);
// auto end = chrono::steady_clock::now(); auto end = chrono::steady_clock::now();
// auto duration(chrono::duration_cast<chrono::milliseconds>(end - start)); auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
// cnote << "test duration: " << duration.count() << " milliseconds.\n"; cnote << "test duration: " << duration.count() << " milliseconds.\n";
// } }
// } }
//} }
//BOOST_AUTO_TEST_CASE(vmInputLimitsTest2) BOOST_AUTO_TEST_CASE(vmInputLimitsTest2)
//{ {
// for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
// { {
// string arg = boost::unit_test::framework::master_test_suite().argv[i]; string arg = boost::unit_test::framework::master_test_suite().argv[i];
// if (arg == "--inputlimits" || arg == "--all") if (arg == "--inputlimits" || arg == "--all")
// dev::test::executeTests("vmInputLimitsTest2", "/VMTests", dev::test::doVMTests); dev::test::executeTests("vmInputLimits2", "/VMTests", dev::test::doVMTests);
// } }
//} }
BOOST_AUTO_TEST_CASE(vmInputLimitsLightTest)
{
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--inputlimits" || arg == "--all")
dev::test::executeTests("vmInputLimitsLight", "/VMTests", dev::test::doVMTests);
}
}
BOOST_AUTO_TEST_CASE(vmRandom) BOOST_AUTO_TEST_CASE(vmRandom)
{ {

32
test/vmArithmeticTestFiller.json

@ -976,8 +976,36 @@
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000", "value" : "1000000000000000000",
"data" : "", "data" : "",
"gasPrice" : "100000000000000", "gasPrice" : "1",
"gas" : "10000" "gas" : "1000000"
}
},
"sdiv_dejavu": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ asm PUSH1 0x05 PUSH1 0x09 PUSH1 0x00 SUB SDIV DUP PUSH1 0 SSTORE }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "10000000"
} }
}, },

225
test/vmIOandFlowOperationsTestFiller.json

@ -283,7 +283,7 @@
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0", "currentNumber" : "0",
"currentGasLimit" : "1000000", "currentGasLimit" : "8390000000",
"currentDifficulty" : "256", "currentDifficulty" : "256",
"currentTimestamp" : "1", "currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -306,6 +306,229 @@
"gas" : "100000" "gas" : "100000"
} }
}, },
"mstore8MemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x60f1630fffffff53",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000"
}
},
"mloadMemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x630fffffff51",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000"
}
},
"mstoreMemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x60f1630fffffff52",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000000"
}
},
"log1MemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x60ff60ff630fffffffa1",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000000"
}
},
"extcodecopyMemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x60ff60ff630fffffff630fffffff3c",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000000"
}
},
"codecopyMemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x60ff60ff630fffffff630fffffff39",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000000"
}
},
"calldatacopyMemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x60ff60ff630fffffff630fffffff37",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000000"
}
},
"sha3MemExp": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "8390000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "100000000000000000000000",
"nonce" : "0",
"code" : "0x60ff630fffffff20",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "1",
"gas" : "8390000000"
}
},
"mstore8WordToBigError": { "mstore8WordToBigError": {
"env" : { "env" : {

Loading…
Cancel
Save