Browse Source

Merge branch 'develop' of https://github.com/ethereum/cpp-ethereum into develop

cl-refactor
winsvega 10 years ago
parent
commit
15daf080da
  1. 1
      CMakeLists.txt
  2. 50
      CodingStandards.txt
  3. 12
      alethzero/CMakeLists.txt
  4. 59
      alethzero/Context.cpp
  5. 68
      alethzero/Context.h
  6. 380
      alethzero/Debugger.cpp
  7. 103
      alethzero/Debugger.h
  8. 300
      alethzero/Debugger.ui
  9. 528
      alethzero/Main.ui
  10. 700
      alethzero/MainWin.cpp
  11. 184
      alethzero/MainWin.h
  12. 13
      alethzero/NatspecHandler.cpp
  13. 5
      alethzero/NatspecHandler.h
  14. 71
      alethzero/OurWebThreeStubServer.cpp
  15. 4
      alethzero/OurWebThreeStubServer.h
  16. 336
      alethzero/Transact.cpp
  17. 82
      alethzero/Transact.h
  18. 244
      alethzero/Transact.ui
  19. 3
      cmake/EthCompilerSettings.cmake
  20. 4
      cmake/EthDependencies.cmake
  21. 47
      cmake/FindMHD.cmake
  22. 2
      eth/CMakeLists.txt
  23. 2
      evmjit/libevmjit/Arith256.cpp
  24. 2
      exp/CMakeLists.txt
  25. 8
      extdep/CMakeLists.txt
  26. 2
      libdevcore/CMakeLists.txt
  27. 2
      libdevcore/RLP.cpp
  28. 5
      libdevcore/vector_ref.h
  29. 2
      libdevcrypto/CMakeLists.txt
  30. 6
      libethcore/BlockInfo.cpp
  31. 2
      libethcore/CMakeLists.txt
  32. 10
      libethcore/CommonEth.cpp
  33. 33
      libethcore/CommonEth.h
  34. 13
      libethcore/CommonJS.cpp
  35. 3
      libethcore/CommonJS.h
  36. 1
      libethcore/Exceptions.h
  37. 4
      libethereum/BlockChain.h
  38. 2
      libethereum/CMakeLists.txt
  39. 14
      libethereum/Client.cpp
  40. 2
      libethereum/Client.h
  41. 6
      libethereum/Executive.cpp
  42. 5
      libethereum/Executive.h
  43. 2
      libethereum/Interface.h
  44. 7
      libethereum/State.cpp
  45. 2
      libethereum/State.h
  46. 3
      libethereumx/CMakeLists.txt
  47. 2
      libevm/CMakeLists.txt
  48. 2
      libevmcore/CMakeLists.txt
  49. 4
      libjsqrc/setup.js
  50. 2
      liblll/CMakeLists.txt
  51. 2
      libnatspec/CMakeLists.txt
  52. 2
      libp2p/CMakeLists.txt
  53. 2
      libp2p/Host.cpp
  54. 8
      libp2p/NodeTable.h
  55. 6
      libp2p/Session.cpp
  56. 41
      libqwebthree/CMakeLists.txt
  57. 107
      libqwebthree/QWebThree.cpp
  58. 89
      libqwebthree/QWebThree.h
  59. 2
      libserpent/CMakeLists.txt
  60. 55
      libsolidity/AST.cpp
  61. 60
      libsolidity/AST.h
  62. 2
      libsolidity/ASTForward.h
  63. 15
      libsolidity/ASTJsonConverter.cpp
  64. 22
      libsolidity/ASTPrinter.cpp
  65. 4
      libsolidity/ASTPrinter.h
  66. 8
      libsolidity/ASTVisitor.h
  67. 28
      libsolidity/AST_accept.h
  68. 4
      libsolidity/CMakeLists.txt
  69. 49
      libsolidity/Compiler.cpp
  70. 6
      libsolidity/Compiler.h
  71. 5
      libsolidity/CompilerStack.cpp
  72. 1
      libsolidity/CompilerStack.h
  73. 103
      libsolidity/CompilerUtils.cpp
  74. 14
      libsolidity/CompilerUtils.h
  75. 13
      libsolidity/DeclarationContainer.cpp
  76. 6
      libsolidity/DeclarationContainer.h
  77. 219
      libsolidity/ExpressionCompiler.cpp
  78. 33
      libsolidity/ExpressionCompiler.h
  79. 9
      libsolidity/InterfaceHandler.cpp
  80. 28
      libsolidity/NameAndTypeResolver.cpp
  81. 3
      libsolidity/NameAndTypeResolver.h
  82. 39
      libsolidity/Parser.cpp
  83. 2
      libsolidity/Parser.h
  84. 6
      libsolidity/Token.h
  85. 70
      libsolidity/Types.cpp
  86. 40
      libsolidity/Types.h
  87. 5
      libsolidity/grammar.txt
  88. 5
      libweb3jsonrpc/CMakeLists.txt
  89. 71
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  90. 31
      libweb3jsonrpc/WebThreeStubServerBase.h
  91. 176
      libweb3jsonrpc/abstractwebthreestubserver.h
  92. 7
      libweb3jsonrpc/spec.json
  93. 2
      libwebthree/CMakeLists.txt
  94. 2
      libwhisper/CMakeLists.txt
  95. 4
      lllc/CMakeLists.txt
  96. 7
      mix/CMakeLists.txt
  97. 70
      mix/ClientModel.cpp
  98. 21
      mix/ClientModel.h
  99. 2
      mix/CodeHighlighter.cpp
  100. 201
      mix/CodeModel.cpp

1
CMakeLists.txt

@ -181,7 +181,6 @@ if (NOT HEADLESS)
add_subdirectory(libnatspec)
add_subdirectory(libjsqrc)
add_subdirectory(libqwebthree)
add_subdirectory(alethzero)
add_subdirectory(third)
add_subdirectory(mix)

50
CodingStandards.txt

@ -1,8 +1,11 @@
0. Formatting
GOLDEN RULE: Never *ever* use spaces for formatting.
a. Use tabs for indentation!
- tab stops are every 4 characters.
- One indentation level -> exactly one byte (i.e. a tab character) in the source file.
- Never use spaces to line up sequential lines: If you have run-on lines, indent as you would for a block.
b. Line widths:
- Don't worry about having lines of code > 80-char wide.
- Lines of comments should be formatted according to ease of viewing, but simplicity is to be prefered over beauty.
@ -17,10 +20,22 @@ j. Braces, when used, always have their own lines and are at same indentation le
(WRONG)
if( a==b[ i ] ) { printf ("Hello\n"); }
foo->bar(someLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName);
(RIGHT)
if (a == b[i])
printf("Hello\n"); // NOTE spaces used instead of tab here for clarify - first byte should be '\t'.
printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'.
foo->bar(
someLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName
);
@ -57,6 +72,8 @@ e. Split complex macro on multiple lines with '\'.
3. Capitalization;
GOLDEN RULE: Preprocessor: ALL_CAPS; C++: camelCase.
a. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions.
b. The following entities' first alpha is upper case:
- Type names.
@ -65,6 +82,7 @@ b. The following entities' first alpha is upper case:
- static const variables that form an external API.
c. All preprocessor symbols (macros, macro argments) in full uppercase with underscore word separation.
All other entities' first alpha is lower case.
@ -96,12 +114,18 @@ e. Always pass non-trivial parameters with a const& suffix.
f. If a function returns multiple values, use std::tuple (std::pair acceptable). Prefer not using */& arguments, except where efficiency requires.
g. Never use a macro where adequate non-preprocessor C++ can be written.
h. Prefer "using NewType = OldType" to "typedef OldType NewType".
i. Make use of auto whenever type is clear or unimportant:
- Always avoid doubly-stating the type.
- Use to avoid vast and unimportant type declarations.
(WRONG)
const double d = 0;
int i, j;
char *s;
float meanAndSigma(std::vector<float> _v, float* _sigma);
Derived* x(dynamic_cast<Derived*>(base));
for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {}
(CORRECT)
double const d = 0;
@ -109,12 +133,14 @@ int i;
int j;
char* s;
std::tuple<float, float> meanAndSigma(std::vector<float> const& _v);
auto x = dynamic_cast<Derived*>(base);
for (auto i = x.begin(); i != x.end(); ++i) {}
7. Structs & classes
a. Structs to be used when all members public and no virtual functions.
- In this case, members should be named naturally and not prefixed with 'm_'
b. Classes to be used in all other circumstances.
@ -124,7 +150,7 @@ b. Classes to be used in all other circumstances.
a. One member per line only.
b. Private, non-static, non-const fields prefixed with m_.
c. Avoid public fields, except in structs.
d. Use override, final and const judiciously.
d. Use override, final and const as much as possible.
e. No implementations with the class declaration, except:
- template or force-inline method (though prefer implementation at bottom of header file).
- one-line implementation (in which case include it in same line as declaration).
@ -147,14 +173,18 @@ c. Avoid unpronouncable names;
- If you need to shorten a name favour a pronouncable slice of the original to a scatterred set of consonants.
- e.g. Manager shortens to Man rather than Mgr.
d. Avoid prefixes of initials (e.g. DON'T use IMyInterface, CMyImplementation)
e. A dictionary and thesaurus are your friends.
e. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments.
- A dictionary and thesaurus are your friends.
- Spell correctly.
- Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments.
- Think carefully about the class's purpose.
- Imagine it as an isolated component to try to decontextualise it when considering its name.
- Don't be trapped into naming it (purely) in terms of its implementation.
10. Type-definitions
a. Prefer using to typedef. e.g. using ints = std::vector<int>; rather than typedef std::vector<int> ints;
a. Prefer 'using' to 'typedef'. e.g. using ints = std::vector<int>; rather than typedef std::vector<int> ints;
b. Generally avoid shortening a standard form that already includes all important information:
- e.g. stick to shared_ptr<X> rather than shortening to ptr<X>.
c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently.
@ -162,9 +192,17 @@ c. Where there are exceptions to this (due to excessive use and clear meaning),
d. In general expressions should be roughly as important/semantically meaningful as the space they occupy.
11. Commenting
a. Comments should be doxygen-compilable, using @notation rather than \notation.
b. Document the interface, not the implementation.
- Documentation should be able to remain completely unchanged, even if the method is reimplemented.
- Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports).
- Be careful to scrutinise documentation that extends only to intended purpose and usage.
- Reject documentation that is simply an English transaction of the implementation.
12. Include Headers

12
alethzero/CMakeLists.txt

@ -10,11 +10,13 @@ endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${JSONCPP_INCLUDE_DIRS})
include_directories(..)
qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui)
file(GLOB HEADERS "*.h")
@ -27,15 +29,17 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
ICON alethzero
UI_RESOURCES alethzero.icns Main.ui
UI_RESOURCES alethzero.icns Main.ui Debugger.ui Transact.ui
WIN_RESOURCES alethzero.rc
)
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Widgets)
target_link_libraries(${EXECUTABLE} Qt5::WebKit)
target_link_libraries(${EXECUTABLE} Qt5::WebKitWidgets)
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} qwebthree)
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} ethcore)

59
alethzero/Context.cpp

@ -0,0 +1,59 @@
/*
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 Debugger.h
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#include "Context.h"
#include <QComboBox>
#include <libethcore/CommonEth.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
NatSpecFace::~NatSpecFace()
{
}
Context::~Context()
{
}
void initUnits(QComboBox* _b)
{
for (auto n = (unsigned)units().size(); n-- != 0; )
_b->addItem(QString::fromStdString(units()[n].second), n);
}
vector<KeyPair> keysAsVector(QList<KeyPair> const& keys)
{
auto list = keys.toStdList();
return {begin(list), end(list)};
}
bool sourceIsSolidity(string const& _source)
{
// TODO: Improve this heuristic
return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol");
}
bool sourceIsSerpent(string const& _source)
{
// TODO: Improve this heuristic
return (_source.substr(0, 5) == "//ser");
}

68
alethzero/Context.h

@ -0,0 +1,68 @@
/*
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 Debugger.h
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#pragma once
#include <string>
#include <vector>
#include <QString>
#include <QList>
#include <libethcore/CommonEth.h>
class QComboBox;
namespace dev { namespace eth { struct StateDiff; } }
#define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "
#define Div(S) "<div style=\"" S "\">"
#define Span(S) "<span style=\"" S "\">"
void initUnits(QComboBox* _b);
std::vector<dev::KeyPair> keysAsVector(QList<dev::KeyPair> const& _keys);
bool sourceIsSolidity(std::string const& _source);
bool sourceIsSerpent(std::string const& _source);
class NatSpecFace
{
public:
virtual ~NatSpecFace();
virtual void add(dev::h256 const& _contractHash, std::string const& _doc) = 0;
virtual std::string retrieve(dev::h256 const& _contractHash) const = 0;
virtual std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData) = 0;
virtual std::string getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionDacta) = 0;
};
class Context
{
public:
virtual ~Context();
virtual QString pretty(dev::Address _a) const = 0;
virtual QString prettyU256(dev::u256 _n) const = 0;
virtual QString render(dev::Address _a) const = 0;
virtual dev::Address fromString(QString const& _a) const = 0;
virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0;
};

380
alethzero/Debugger.cpp

@ -0,0 +1,380 @@
/*
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 Debugger.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#include "Debugger.h"
#include <fstream>
#include <QFileDialog>
#include <libevm/VM.h>
#include <libethereum/ExtVM.h>
#include <libethereum/Executive.h>
#include "ui_Debugger.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
Debugger::Debugger(Context* _c, QWidget* _parent):
QDialog(_parent),
ui(new Ui::Debugger),
m_context(_c)
{
ui->setupUi(this);
}
Debugger::~Debugger()
{
delete ui;
}
void Debugger::init()
{
if (m_session.history.size())
{
alterDebugStateGroup(true);
ui->debugCode->setEnabled(false);
ui->debugTimeline->setMinimum(0);
ui->debugTimeline->setMaximum(m_session.history.size());
ui->debugTimeline->setValue(0);
}
}
void Debugger::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction)
{
finished();
if (m_session.populate(_executive, _transaction))
init();
update();
}
bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction)
{
try {
if (_executive.setup(_transaction))
return false;
}
catch (...)
{
// Invalid transaction
return false;
}
vector<WorldState const*> levels;
bytes lastExtCode;
bytesConstRef lastData;
h256 lastHash;
h256 lastDataHash;
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, VM* voidVM, ExtVMFace const* voidExt)
{
VM& vm = *voidVM;
ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
if (ext.code != lastExtCode)
{
lastExtCode = ext.code;
lastHash = sha3(lastExtCode);
if (!codes.count(lastHash))
codes[lastHash] = ext.code;
}
if (ext.data != lastData)
{
lastData = ext.data;
lastDataHash = sha3(lastData);
if (!codes.count(lastDataHash))
codes[lastDataHash] = ext.data.toBytes();
}
if (levels.size() < ext.depth)
levels.push_back(&history.back());
else
levels.resize(ext.depth);
history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
_executive.go(onOp);
_executive.finalize();
return true;
}
void Debugger::finished()
{
m_session = DebugSession();
ui->callStack->clear();
ui->debugCode->clear();
ui->debugStack->clear();
ui->debugMemory->setHtml("");
ui->debugStorage->setHtml("");
ui->debugStateInfo->setText("");
alterDebugStateGroup(false);
}
void Debugger::update()
{
if (m_session.history.size())
{
WorldState const& nws = m_session.history[min((int)m_session.history.size() - 1, ui->debugTimeline->value())];
WorldState const& ws = ui->callStack->currentRow() > 0 ? *nws.levels[nws.levels.size() - ui->callStack->currentRow()] : nws;
if (ui->debugTimeline->value() >= m_session.history.size())
{
if (ws.gasCost > ws.gas)
ui->debugMemory->setHtml("<h3>OUT-OF-GAS</h3>");
else if (ws.inst == Instruction::RETURN && ws.stack.size() >= 2)
{
unsigned from = (unsigned)ws.stack.back();
unsigned size = (unsigned)ws.stack[ws.stack.size() - 2];
unsigned o = 0;
bytes out(size, 0);
for (; o < size && from + o < ws.memory.size(); ++o)
out[o] = ws.memory[from + o];
ui->debugMemory->setHtml("<h3>RETURN</h3>" + QString::fromStdString(dev::memDump(out, 16, true)));
}
else if (ws.inst == Instruction::STOP)
ui->debugMemory->setHtml("<h3>STOP</h3>");
else if (ws.inst == Instruction::SUICIDE && ws.stack.size() >= 1)
ui->debugMemory->setHtml("<h3>SUICIDE</h3>0x" + QString::fromStdString(toString(right160(ws.stack.back()))));
else
ui->debugMemory->setHtml("<h3>EXCEPTION</h3>");
ostringstream ss;
ss << dec << "EXIT | GAS: " << dec << max<dev::bigint>(0, (dev::bigint)ws.gas - ws.gasCost);
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
ui->debugStorage->setHtml("");
ui->debugCallData->setHtml("");
m_session.currentData = h256();
ui->callStack->clear();
m_session.currentLevels.clear();
ui->debugCode->clear();
m_session.currentCode = h256();
ui->debugStack->setHtml("");
}
else
{
if (m_session.currentLevels != nws.levels || !ui->callStack->count())
{
m_session.currentLevels = nws.levels;
ui->callStack->clear();
for (unsigned i = 0; i <= nws.levels.size(); ++i)
{
WorldState const& s = i ? *nws.levels[nws.levels.size() - i] : nws;
ostringstream out;
out << s.cur.abridged();
if (i)
out << " " << instructionInfo(s.inst).name << " @0x" << hex << s.curPC;
ui->callStack->addItem(QString::fromStdString(out.str()));
}
}
if (ws.code != m_session.currentCode)
{
m_session.currentCode = ws.code;
bytes const& code = m_session.codes[ws.code];
QListWidget* dc = ui->debugCode;
dc->clear();
m_session.pcWarp.clear();
for (unsigned i = 0; i <= code.size(); ++i)
{
byte b = i < code.size() ? code[i] : 0;
try
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
ostringstream out;
out << hex << setw(4) << setfill('0') << i;
m_session.pcWarp[i] = dc->count();
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = b - (byte)Instruction::PUSH1 + 1;
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&code[i + 1], bc)));
i += bc;
}
dc->addItem(QString::fromStdString(out.str()) + " " + s);
}
catch (...)
{
cerr << "Unhandled exception!" << endl << boost::current_exception_diagnostic_information();
break; // probably hit data segment
}
}
}
if (ws.callData != m_session.currentData)
{
m_session.currentData = ws.callData;
if (ws.callData)
{
assert(m_session.codes.count(ws.callData));
ui->debugCallData->setHtml(QString::fromStdString(dev::memDump(m_session.codes[ws.callData], 16, true)));
}
else
ui->debugCallData->setHtml("");
}
QString stack;
for (auto i: ws.stack)
stack.prepend("<div>" + m_context->prettyU256(i) + "</div>");
ui->debugStack->setHtml(stack);
ui->debugMemory->setHtml(QString::fromStdString(dev::memDump(ws.memory, 16, true)));
assert(m_session.codes.count(ws.code));
if (m_session.codes[ws.code].size() >= (unsigned)ws.curPC)
{
int l = m_session.pcWarp[(unsigned)ws.curPC];
ui->debugCode->setCurrentRow(max(0, l - 5));
ui->debugCode->setCurrentRow(min(ui->debugCode->count() - 1, l + 5));
ui->debugCode->setCurrentRow(l);
}
else
cwarn << "PC (" << (unsigned)ws.curPC << ") is after code range (" << m_session.codes[ws.code].size() << ")";
ostringstream ss;
ss << dec << "STEP: " << ws.steps << " | PC: 0x" << hex << ws.curPC << " : " << instructionInfo(ws.inst).name << " | ADDMEM: " << dec << ws.newMemSize << " words | COST: " << dec << ws.gasCost << " | GAS: " << dec << ws.gas;
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
stringstream s;
for (auto const& i: ws.storage)
s << "@" << m_context->prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << m_context->prettyU256(i.second).toStdString() << "<br/>";
ui->debugStorage->setHtml(QString::fromStdString(s.str()));
}
}
}
void Debugger::on_callStack_currentItemChanged()
{
update();
}
void Debugger::alterDebugStateGroup(bool _enable) const
{
ui->stepOver->setEnabled(_enable);
ui->stepInto->setEnabled(_enable);
ui->stepOut->setEnabled(_enable);
ui->backOver->setEnabled(_enable);
ui->backInto->setEnabled(_enable);
ui->backOut->setEnabled(_enable);
ui->dump->setEnabled(_enable);
ui->dumpStorage->setEnabled(_enable);
ui->dumpPretty->setEnabled(_enable);
}
void Debugger::on_debugTimeline_valueChanged()
{
update();
}
void Debugger::on_stepOver_clicked()
{
if (ui->debugTimeline->value() < m_session.history.size()) {
auto l = m_session.history[ui->debugTimeline->value()].levels.size();
if ((ui->debugTimeline->value() + 1) < m_session.history.size() && m_session.history[ui->debugTimeline->value() + 1].levels.size() > l)
{
on_stepInto_clicked();
if (m_session.history[ui->debugTimeline->value()].levels.size() > l)
on_stepOut_clicked();
}
else
on_stepInto_clicked();
}
}
void Debugger::on_stepInto_clicked()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() + 1);
ui->callStack->setCurrentRow(0);
}
void Debugger::on_stepOut_clicked()
{
if (ui->debugTimeline->value() < m_session.history.size())
{
auto ls = m_session.history[ui->debugTimeline->value()].levels.size();
auto l = ui->debugTimeline->value();
for (; l < m_session.history.size() && m_session.history[l].levels.size() >= ls; ++l) {}
ui->debugTimeline->setValue(l);
ui->callStack->setCurrentRow(0);
}
}
void Debugger::on_backInto_clicked()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() - 1);
ui->callStack->setCurrentRow(0);
}
void Debugger::on_backOver_clicked()
{
auto l = m_session.history[ui->debugTimeline->value()].levels.size();
if (ui->debugTimeline->value() > 0 && m_session.history[ui->debugTimeline->value() - 1].levels.size() > l)
{
on_backInto_clicked();
if (m_session.history[ui->debugTimeline->value()].levels.size() > l)
on_backOut_clicked();
}
else
on_backInto_clicked();
}
void Debugger::on_backOut_clicked()
{
if (ui->debugTimeline->value() > 0 && m_session.history.size() > 0)
{
auto ls = m_session.history[min(ui->debugTimeline->value(), m_session.history.size() - 1)].levels.size();
int l = ui->debugTimeline->value();
for (; l > 0 && m_session.history[l].levels.size() >= ls; --l) {}
ui->debugTimeline->setValue(l);
ui->callStack->setCurrentRow(0);
}
}
void Debugger::on_dump_clicked()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_session.history)
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl;
}
void Debugger::on_dumpPretty_clicked()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_session.history)
{
f << endl << " STACK" << endl;
for (auto i: ws.stack)
f << (h256)i << endl;
f << " MEMORY" << endl << dev::memDump(ws.memory);
f << " STORAGE" << endl;
for (auto const& i: ws.storage)
f << showbase << hex << i.first << ": " << i.second << endl;
f << dec << ws.levels.size() << " | " << ws.cur << " | #" << ws.steps << " | " << hex << setw(4) << setfill('0') << ws.curPC << " : " << instructionInfo(ws.inst).name << " | " << dec << ws.gas << " | -" << dec << ws.gasCost << " | " << ws.newMemSize << "x32";
}
}
void Debugger::on_dumpStorage_clicked()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_session.history)
{
if (ws.inst == Instruction::STOP || ws.inst == Instruction::RETURN || ws.inst == Instruction::SUICIDE)
for (auto i: ws.storage)
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl;
}
}

103
alethzero/Debugger.h

@ -0,0 +1,103 @@
/*
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 Debugger.h
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#pragma once
#include <libdevcore/RLP.h>
#include <libethcore/CommonEth.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <QDialog>
#include <QMap>
#include <QList>
#include "Context.h"
namespace Ui { class Debugger; }
struct WorldState
{
uint64_t steps;
dev::Address cur;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::h256 code;
dev::h256 callData;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<WorldState const*> levels;
};
struct DebugSession
{
DebugSession() {}
bool populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction);
dev::h256 currentCode;
dev::h256 currentData;
std::vector<WorldState const*> currentLevels;
QMap<unsigned, unsigned> pcWarp;
QList<WorldState> history;
std::map<dev::u256, dev::bytes> codes;
};
class Debugger: public QDialog
{
Q_OBJECT
public:
explicit Debugger(Context* _context, QWidget* _parent = 0);
~Debugger();
void populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction);
protected slots:
void on_callStack_currentItemChanged();
void on_debugTimeline_valueChanged();
void on_stepOver_clicked();
void on_stepInto_clicked();
void on_stepOut_clicked();
void on_backOver_clicked();
void on_backInto_clicked();
void on_backOut_clicked();
void on_dump_clicked();
void on_dumpPretty_clicked();
void on_dumpStorage_clicked();
void on_close_clicked() { close(); }
private:
void init();
void update();
void finished();
void alterDebugStateGroup(bool _enable) const;
Ui::Debugger* ui;
DebugSession m_session;
Context* m_context;
};

300
alethzero/Debugger.ui

@ -0,0 +1,300 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Debugger</class>
<widget class="QDialog" name="Debugger">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>989</width>
<height>690</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="stepOver">
<property name="text">
<string>Step Over</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="stepInto">
<property name="text">
<string>Step Into</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="stepOut">
<property name="text">
<string>Step Out</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="backOver">
<property name="text">
<string>Back Over</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="backInto">
<property name="text">
<string>Back Into</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="backOut">
<property name="text">
<string>Back Out</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QSplitter" name="splitter_42">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QListWidget" name="debugCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QListWidget" name="callStack">
<property name="font">
<font>
<family>Ubuntu Mono</family>
</font>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</widget>
<widget class="QSplitter" name="splitter_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTextEdit" name="debugStack">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QTextEdit" name="debugMemory">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QTextEdit" name="debugStorage">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QTextEdit" name="debugCallData">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="QLabel" name="debugStateInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="debugTimeline">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="dump">
<property name="text">
<string>Dump</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="dumpStorage">
<property name="text">
<string>Dump Storage</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="dumpPretty">
<property name="text">
<string>Dump Pretty</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>577</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

528
alethzero/Main.ui

@ -117,7 +117,7 @@
<x>0</x>
<y>0</y>
<width>1617</width>
<height>25</height>
<height>24</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@ -140,11 +140,12 @@
</widget>
<widget class="QMenu" name="menu_Tools">
<property name="title">
<string>T&amp;ools</string>
<string>&amp;Tools</string>
</property>
<addaction name="mine"/>
<addaction name="separator"/>
<addaction name="create"/>
<addaction name="newTransaction"/>
<addaction name="newAccount"/>
<addaction name="importKey"/>
<addaction name="importKeyFile"/>
<addaction name="exportKey"/>
@ -160,18 +161,14 @@
</widget>
<widget class="QMenu" name="menu_Debug">
<property name="title">
<string>Deb&amp;ug</string>
<string>&amp;Special</string>
</property>
<addaction name="debugDumpState"/>
<addaction name="debugDumpStatePre"/>
<addaction name="separator"/>
<addaction name="paranoia"/>
<addaction name="clearPending"/>
<addaction name="killBlockchain"/>
<addaction name="inject"/>
<addaction name="forceMining"/>
<addaction name="turboMining"/>
<addaction name="enableOptimizer"/>
<addaction name="separator"/>
<addaction name="usePrivate"/>
<addaction name="jitvm"/>
@ -185,42 +182,28 @@
<addaction name="separator"/>
<addaction name="preview"/>
</widget>
<widget class="QMenu" name="menuDebugger">
<property name="title">
<string>D&amp;ebugger</string>
</property>
<widget class="QMenu" name="menu_Dump_Trace">
<property name="title">
<string>&amp;Dump Trace</string>
</property>
<addaction name="dumpTrace"/>
<addaction name="dumpTraceStorage"/>
<addaction name="dumpTracePretty"/>
</widget>
<addaction name="debugCurrent"/>
<addaction name="menu_Dump_Trace"/>
<addaction name="separator"/>
<addaction name="debugStep"/>
<addaction name="debugStepInto"/>
<addaction name="debugStepOut"/>
<addaction name="debugStepBack"/>
<addaction name="debugStepBackInto"/>
<addaction name="debugStepBackOut"/>
</widget>
<widget class="QMenu" name="menuWhispe">
<property name="title">
<string>&amp;Whisper</string>
</property>
<addaction name="newIdentity"/>
</widget>
<widget class="QMenu" name="menuDebug">
<property name="title">
<string>&amp;Debug</string>
</property>
<addaction name="debugCurrent"/>
<addaction name="debugDumpState"/>
<addaction name="debugDumpStatePre"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_View"/>
<addaction name="menu_Network"/>
<addaction name="menu_Tools"/>
<addaction name="menuDebugger"/>
<addaction name="menuWhispe"/>
<addaction name="menu_Debug"/>
<addaction name="menuDebug"/>
<addaction name="menu_Help"/>
<addaction name="menu_Debug"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="dockWidget_2">
@ -533,237 +516,11 @@
<bool>false</bool>
</attribute>
<addaction name="go"/>
<addaction name="newTransaction"/>
<addaction name="preview"/>
<addaction name="mine"/>
<addaction name="refresh"/>
</widget>
<widget class="QDockWidget" name="dockWidget_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>510</width>
<height>386</height>
</size>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Transact</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_5">
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Data</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="5" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Gas</string>
</property>
<property name="buddy">
<cstring>gas</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;To</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="gas">
<property name="suffix">
<string> gas</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>10000</number>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="gasPrice">
<property name="prefix">
<string>@ </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="calculatedName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label5_2">
<property name="text">
<string>&amp;Amount</string>
</property>
<property name="buddy">
<cstring>value</cstring>
</property>
</widget>
</item>
<item row="4" column="1" colspan="3">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="destination">
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>(Create Contract)</string>
</property>
</item>
</widget>
</item>
<item row="6" column="3">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Execute</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="total">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QPushButton" name="debug">
<property name="text">
<string>De&amp;bug</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_7">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
@ -987,171 +744,6 @@
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_9">
<property name="floating">
<bool>false</bool>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Debugger</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="debugPanel">
<property name="enabled">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitter_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QSplitter" name="splitter_42">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QListWidget" name="debugCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QListWidget" name="callStack">
<property name="font">
<font>
<family>Ubuntu Mono</family>
</font>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</widget>
<widget class="QSplitter" name="splitter_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTextEdit" name="debugStack">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QTextEdit" name="debugMemory">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QTextEdit" name="debugStorage">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QTextEdit" name="debugCallData">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="QLabel" name="debugStateInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="debugTimeline">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_10">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
@ -1566,9 +1158,6 @@ font-size: 14pt</string>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="3" column="1" colspan="4">
@ -1621,9 +1210,6 @@ font-size: 14pt</string>
<property name="text">
<string>TTL</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
@ -1637,9 +1223,6 @@ font-size: 14pt</string>
<property name="text">
<string>From</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
@ -1653,9 +1236,6 @@ font-size: 14pt</string>
<property name="text">
<string>To</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="4">
@ -1686,9 +1266,6 @@ font-size: 14pt</string>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
@ -1715,9 +1292,6 @@ font-size: 14pt</string>
<property name="text">
<string>Work to Prove</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
</layout>
@ -1776,7 +1350,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>Use &amp;UPnP</string>
<string>&amp;Use UPnP</string>
</property>
</action>
<action name="connect">
@ -1800,9 +1374,9 @@ font-size: 14pt</string>
<string>&amp;Mine</string>
</property>
</action>
<action name="create">
<action name="newAccount">
<property name="text">
<string>&amp;New Address</string>
<string>&amp;New Address...</string>
</property>
</action>
<action name="about">
@ -1834,7 +1408,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>Mining &amp;Paranoia</string>
<string>&amp;Mining Paranoia</string>
</property>
</action>
<action name="killBlockchain">
@ -1862,7 +1436,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>Show Ancient &amp;Blocks</string>
<string>&amp;Show Ancient Blocks</string>
</property>
</action>
<action name="showAllAccounts">
@ -1870,7 +1444,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>Show Anonymous &amp;Accounts</string>
<string>Show &amp;Anonymous Accounts</string>
</property>
</action>
<action name="usePast">
@ -1970,7 +1544,7 @@ font-size: 14pt</string>
<bool>false</bool>
</property>
<property name="text">
<string>Debu&amp;g Current Transaction</string>
<string>&amp;Debug Current Transaction</string>
</property>
</action>
<action name="debugDumpState">
@ -1978,7 +1552,7 @@ font-size: 14pt</string>
<bool>false</bool>
</property>
<property name="text">
<string>D&amp;ump Current Transaction State (post)</string>
<string>Dump &amp;Current Transaction State (post)</string>
</property>
</action>
<action name="debugDumpStatePre">
@ -1986,7 +1560,7 @@ font-size: 14pt</string>
<bool>false</bool>
</property>
<property name="text">
<string>D&amp;ump Current Transaction State (pre)</string>
<string>Dump Current &amp;Transaction State (pre)</string>
</property>
</action>
<action name="dumpTracePretty">
@ -2007,7 +1581,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Use Private Chain...</string>
<string>Use &amp;Private Chain...</string>
</property>
</action>
<action name="enableOptimizer">
@ -2015,7 +1589,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Enable LLL &amp;Optimizer</string>
<string>&amp;Enable LLL Optimizer</string>
</property>
</action>
<action name="turboMining">
@ -2023,7 +1597,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>Reserved Debug 1</string>
<string>&amp;Reserved Debug 1</string>
</property>
</action>
<action name="localNetworking">
@ -2031,7 +1605,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>Enable Local Addresses</string>
<string>&amp;Enable Local Addresses</string>
</property>
</action>
<action name="importKeyFile">
@ -2044,7 +1618,7 @@ font-size: 14pt</string>
</action>
<action name="go">
<property name="text">
<string>Go!</string>
<string>&amp;Go!</string>
</property>
</action>
<action name="newIdentity">
@ -2054,7 +1628,7 @@ font-size: 14pt</string>
</action>
<action name="clearPending">
<property name="text">
<string>Clear Pe&amp;nd&amp;ing</string>
<string>&amp;Clear Pending</string>
</property>
</action>
<action name="jitvm">
@ -2073,6 +1647,11 @@ font-size: 14pt</string>
<string>&amp;Kill Account</string>
</property>
</action>
<action name="newTransaction">
<property name="text">
<string>New &amp;Transaction...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
@ -2095,27 +1674,30 @@ font-size: 14pt</string>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>destination</tabstop>
<tabstop>calculatedName</tabstop>
<tabstop>value</tabstop>
<tabstop>valueUnits</tabstop>
<tabstop>gas</tabstop>
<tabstop>gasPrice</tabstop>
<tabstop>gasPriceUnits</tabstop>
<tabstop>data</tabstop>
<tabstop>send</tabstop>
<tabstop>idealPeers</tabstop>
<tabstop>port</tabstop>
<tabstop>clientName</tabstop>
<tabstop>shhTo</tabstop>
<tabstop>shhFrom</tabstop>
<tabstop>shhTtl</tabstop>
<tabstop>shhTopic</tabstop>
<tabstop>shhWork</tabstop>
<tabstop>shhData</tabstop>
<tabstop>log</tabstop>
<tabstop>post</tabstop>
<tabstop>verbosity</tabstop>
<tabstop>jsConsole</tabstop>
<tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop>
<tabstop>webView</tabstop>
<tabstop>idealPeers</tabstop>
<tabstop>forceAddress</tabstop>
<tabstop>port</tabstop>
<tabstop>clientName</tabstop>
<tabstop>transactionQueue</tabstop>
<tabstop>pendingInfo</tabstop>
<tabstop>blockChainFilter</tabstop>
<tabstop>nameReg</tabstop>
<tabstop>debugCode</tabstop>
<tabstop>debugStack</tabstop>
<tabstop>debugMemory</tabstop>
<tabstop>debugStorage</tabstop>
<tabstop>nodes</tabstop>
<tabstop>whispers</tabstop>
<tabstop>jsInput</tabstop>
</tabstops>
<resources/>
<connections/>

700
alethzero/MainWin.cpp

@ -50,11 +50,14 @@
#include <libethereum/EthereumHost.h>
#include <libethereum/DownloadMan.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include "MainWin.h"
#include "DownloadView.h"
#include "MiningView.h"
#include "BuildInfo.h"
#include "OurWebThreeStubServer.h"
#include "Transact.h"
#include "Debugger.h"
#include "ui_Main.h"
using namespace std;
using namespace dev;
@ -62,17 +65,6 @@ using namespace dev::p2p;
using namespace dev::eth;
namespace js = json_spirit;
#define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "
#define Div(S) "<div style=\"" S "\">"
#define Span(S) "<span style=\"" S "\">"
static void initUnits(QComboBox* _b)
{
for (auto n = (unsigned)units().size(); n-- != 0; )
_b->addItem(QString::fromStdString(units()[n].second), n);
}
QString Main::fromRaw(h256 _n, unsigned* _inc)
{
if (_n)
@ -98,12 +90,6 @@ QString Main::fromRaw(h256 _n, unsigned* _inc)
return QString();
}
static vector<KeyPair> keysAsVector(QList<KeyPair> const& keys)
{
auto list = keys.toStdList();
return {begin(list), end(list)};
}
QString contentsOfQResource(string const& res)
{
QFile file(QString::fromStdString(res));
@ -119,7 +105,8 @@ Address c_newConfig = Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
Main::Main(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Main)
ui(new Ui::Main),
m_transact(this, this)
{
setWindowFlags(Qt::Window);
ui->setupUi(this);
@ -148,12 +135,6 @@ Main::Main(QWidget *parent) :
ui->configDock->close();
on_verbosity_valueChanged();
initUnits(ui->gasPriceUnits);
initUnits(ui->valueUnits);
ui->valueUnits->setCurrentIndex(6);
ui->gasPriceUnits->setCurrentIndex(4);
ui->gasPrice->setValue(10);
on_destination_currentTextChanged();
statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount);
@ -167,25 +148,26 @@ Main::Main(QWidget *parent) :
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"}, p2p::NetworkPreferences(), network));
m_qwebConnector.reset(new QWebThreeConnector());
m_server.reset(new OurWebThreeStubServer(*m_qwebConnector, *web3(), keysAsVector(m_myKeys), this));
m_httpConnector.reset(new jsonrpc::HttpServer(8080));
m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), keysAsVector(m_myKeys), this));
connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString)));
m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening();
connect(ui->webView, &QWebView::loadStarted, [this]()
{
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_qweb = new QWebThree(this);
auto qweb = m_qweb;
m_qwebConnector->setQWeb(qweb);
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qweb));
connect(m_qweb, SIGNAL(onNewId(QString)), this, SLOT(addNewId(QString)));
connect(f, &QWebFrame::javaScriptWindowObjectCleared, [f, this]()
{
f->disconnect();
f->addToJavaScriptWindowObject("env", this, QWebFrame::QtOwnership);
f->evaluateJavaScript(contentsOfQResource(":/js/bignumber.min.js"));
f->evaluateJavaScript(contentsOfQResource(":/js/webthree.js"));
f->evaluateJavaScript(contentsOfQResource(":/js/setup.js"));
});
});
connect(ui->webView, &QWebView::loadFinished, [=]()
@ -216,7 +198,6 @@ Main::~Main()
writeSettings();
// Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor)
// *after* the client is dead.
m_qweb->clientDieing();
g_logPost = simpleDebugOut;
}
@ -372,12 +353,6 @@ void Main::on_forceMining_triggered()
ethereum()->setForceMining(ui->forceMining->isChecked());
}
void Main::on_enableOptimizer_triggered()
{
m_enableOptimizer = ui->enableOptimizer->isChecked();
on_data_textChanged();
}
QString Main::contents(QString _s)
{
return QString::fromStdString(dev::asString(dev::contents(_s.toStdString())));
@ -411,6 +386,12 @@ void Main::load(QString _s)
}*/
}
void Main::on_newTransaction_triggered()
{
m_transact.setEnvironment(m_myKeys, ethereum(), &m_natSpecDB);
m_transact.exec();
}
void Main::on_loadJS_triggered()
{
QString f = QFileDialog::getOpenFileName(this, "Load Javascript", QString(), "Javascript (*.js);;All files (*)");
@ -672,7 +653,6 @@ void Main::writeSettings()
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("showAll", ui->showAll->isChecked());
s.setValue("showAllAccounts", ui->showAllAccounts->isChecked());
s.setValue("enableOptimizer", m_enableOptimizer);
s.setValue("clientName", ui->clientName->text());
s.setValue("idealPeers", ui->idealPeers->value());
s.setValue("port", ui->port->value());
@ -742,8 +722,6 @@ void Main::readSettings(bool _skipGeometry)
ui->paranoia->setChecked(s.value("paranoia", false).toBool());
ui->showAll->setChecked(s.value("showAll", false).toBool());
ui->showAllAccounts->setChecked(s.value("showAllAccounts", false).toBool());
m_enableOptimizer = s.value("enableOptimizer", true).toBool();
ui->enableOptimizer->setChecked(m_enableOptimizer);
ui->clientName->setText(s.value("clientName", "").toString());
if (ui->clientName->text().isEmpty())
ui->clientName->setText(QInputDialog::getText(nullptr, "Enter identity", "Enter a name that will identify you on the peer network"));
@ -990,7 +968,6 @@ void Main::refreshNetwork()
void Main::refreshAll()
{
refreshDestination();
refreshBlockChain();
refreshBlockCount();
refreshPending();
@ -1041,20 +1018,6 @@ void Main::refreshAccounts()
}
}
void Main::refreshDestination()
{
cwatch << "refreshDestination()";
QString s;
for (auto i: ethereum()->addresses())
if ((s = pretty(i)).size())
// A namereg address
if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1)
ui->destination->addItem(s);
for (int i = 0; i < ui->destination->count(); ++i)
if (ui->destination->itemText(i) != "(Create Contract)" && !fromString(ui->destination->itemText(i)))
ui->destination->removeItem(i--);
}
void Main::refreshBlockCount()
{
cwatch << "refreshBlockCount()";
@ -1477,13 +1440,12 @@ void Main::on_debugCurrent_triggered()
if (!item->data(Qt::UserRole + 1).isNull())
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
m_executiveState = ethereum()->state(txi + 1, h);
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = m_executiveState.pending()[txi];
m_executiveState = m_executiveState.fromPending(txi);
auto r = t.rlp();
populateDebugger(&r);
m_currentExecution.reset();
bytes t = ethereum()->blockChain().transaction(h, txi);
State s(ethereum()->state(txi, h));
Executive e(s, ethereum()->blockChain(), 0);
Debugger dw(this, this);
dw.populate(e, Transaction(t, CheckSignature::Sender));
dw.exec();
}
}
}
@ -1514,49 +1476,6 @@ void Main::on_debugDumpStatePre_triggered()
on_debugDumpState_triggered(0);
}
void Main::populateDebugger(dev::bytesConstRef _r)
{
bool done = m_currentExecution->setup(_r);
if (!done)
{
debugFinished();
vector<WorldState const*> levels;
m_codes.clear();
bytes lastExtCode;
bytesConstRef lastData;
h256 lastHash;
h256 lastDataHash;
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, VM* voidVM, ExtVMFace const* voidExt)
{
VM& vm = *voidVM;
ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
if (ext.code != lastExtCode)
{
lastExtCode = ext.code;
lastHash = sha3(lastExtCode);
if (!m_codes.count(lastHash))
m_codes[lastHash] = ext.code;
}
if (ext.data != lastData)
{
lastData = ext.data;
lastDataHash = sha3(lastData);
if (!m_codes.count(lastDataHash))
m_codes[lastDataHash] = ext.data.toBytes();
}
if (levels.size() < ext.depth)
levels.push_back(&m_history.back());
else
levels.resize(ext.depth);
m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
m_currentExecution->go(onOp);
m_currentExecution->finalize();
initDebugger();
updateDebugger();
}
}
void Main::on_contracts_currentItemChanged()
{
ui->contractInfo->clear();
@ -1572,7 +1491,7 @@ void Main::on_contracts_currentItemChanged()
auto storage = ethereum()->storageAt(address);
for (auto const& i: storage)
s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>";
s << "<h4>Body Code</h4>" << disassemble(ethereum()->codeAt(address));
s << "<h4>Body Code (" << sha3(ethereum()->codeAt(address)).abridged() << ")</h4>" << disassemble(ethereum()->codeAt(address));
s << Div(Mono) << toHex(ethereum()->codeAt(address)) << "</div>";
ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
}
@ -1616,19 +1535,6 @@ void Main::on_contracts_doubleClicked()
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
void Main::on_destination_currentTextChanged()
{
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)")
if (Address a = fromString(ui->destination->currentText()))
ui->calculatedName->setText(render(a));
else
ui->calculatedName->setText("Unknown Address");
else
ui->calculatedName->setText("Create Contract");
on_data_textChanged();
// updateFee();
}
static shh::FullTopic topicFromText(QString _s)
{
shh::BuildTopic ret;
@ -1683,134 +1589,6 @@ static shh::FullTopic topicFromText(QString _s)
return ret;
}
bool Main::sourceIsSolidity(string const& _source)
{
// TODO: Improve this heuristic
return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol");
}
static bool sourceIsSerpent(string const& _source)
{
// TODO: Improve this heuristic
return (_source.substr(0, 5) == "//ser");
}
string const Main::getFunctionHashes(dev::solidity::CompilerStack const &_compiler,
string const& _contractName)
{
string ret = "";
auto const& contract = _compiler.getContractDefinition(_contractName);
auto interfaceFunctions = contract.getInterfaceFunctions();
for (auto const& it: interfaceFunctions)
{
ret += it.first.abridged();
ret += " :";
ret += it.second->getDeclaration().getName() + "\n";
}
return ret;
}
void Main::on_data_textChanged()
{
m_pcWarp.clear();
if (isCreation())
{
string src = ui->data->toPlainText().toStdString();
vector<string> errors;
QString lll;
QString solidity;
if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0)
{
m_data = fromHex(src);
}
else if (sourceIsSolidity(src))
{
dev::solidity::CompilerStack compiler;
try
{
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, m_enableOptimizer);
solidity = "<h4>Solidity</h4>";
solidity += "<pre>var " + QString::fromStdString(compiler.getContractNames().front()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");</pre>";
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "</pre>";
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "</pre>";
}
catch (dev::Exception const& exception)
{
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>";
}
catch (...)
{
solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>";
}
}
#ifndef _MSC_VER
else if (sourceIsSerpent(src))
{
try
{
m_data = dev::asBytes(::compile(src));
for (auto& i: errors)
i = "(LLL " + i + ")";
}
catch (string err)
{
errors.push_back("Serpent " + err);
}
}
#endif
else
{
m_data = compileLLL(src, m_enableOptimizer, &errors);
if (errors.empty())
{
auto asmcode = compileLLLToAsm(src, false);
lll = "<h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>";
if (m_enableOptimizer)
{
asmcode = compileLLLToAsm(src, true);
lll = "<h4>Opt</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>" + lll;
}
}
}
QString errs;
if (errors.size())
{
errs = "<h4>Errors</h4>";
for (auto const& i: errors)
errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>");
}
ui->code->setHtml(errs + lll + solidity + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "<h4>Hex</h4>" Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>");
ui->gas->setMinimum((qint64)Client::txGas(m_data, 0));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
m_data = parseData(ui->data->toPlainText().toStdString());
ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true)));
if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size())
{
ui->gas->setMinimum((qint64)Client::txGas(m_data, 1));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
if (ui->gas->isEnabled())
m_backupGas = ui->gas->value();
ui->gas->setValue((qint64)Client::txGas(m_data));
ui->gas->setEnabled(false);
}
}
updateFee();
}
void Main::on_clearPending_triggered()
{
writeSettings();
@ -1835,54 +1613,6 @@ void Main::on_killBlockchain_triggered()
refreshAll();
}
bool Main::isCreation() const
{
return ui->destination->currentText().isEmpty() || ui->destination->currentText() == "(Create Contract)";
}
u256 Main::fee() const
{
return ui->gas->value() * gasPrice();
}
u256 Main::value() const
{
if (ui->valueUnits->currentIndex() == -1)
return 0;
return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
}
u256 Main::gasPrice() const
{
if (ui->gasPriceUnits->currentIndex() == -1)
return 0;
return ui->gasPrice->value() * units()[units().size() - 1 - ui->gasPriceUnits->currentIndex()].first;
}
u256 Main::total() const
{
return value() + fee();
}
void Main::updateFee()
{
ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str()));
auto totalReq = total();
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false;
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
ok = true;
break;
}
ui->send->setEnabled(ok);
QPalette p = ui->total->palette();
p.setColor(QPalette::WindowText, QColor(ok ? 0x00 : 0x80, 0x00, 0x00));
ui->total->setPalette(p);
}
void Main::on_net_triggered()
{
ui->port->setEnabled(!ui->net->isChecked());
@ -1944,79 +1674,12 @@ void Main::on_mine_triggered()
ethereum()->stopMining();
}
void Main::on_send_clicked()
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address(), 0) >= totalReq)
{
debugFinished();
Secret s = i.secret();
if (isCreation())
{
// If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB
ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice());
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
try
{
dev::solidity::CompilerStack compiler;
m_data = compiler.compile(src, m_enableOptimizer);
for (string& s: compiler.getContractNames())
{
h256 contractHash = compiler.getContractCodeHash(s);
m_natspecDB.add(contractHash,
compiler.getMetadata(s, dev::solidity::DocumentationType::NatspecUser));
}
}
catch (...)
{
statusBar()->showMessage("Couldn't compile Solidity Contract.");
}
}
else
ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
return;
}
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
}
void Main::keysChanged()
{
onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
}
void Main::on_debug_clicked()
{
debugFinished();
try
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
Secret s = i.secret();
m_executiveState = ethereum()->postState();
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s);
auto r = t.rlp();
populateDebugger(&r);
m_currentExecution.reset();
return;
}
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
}
catch (dev::Exception const& _e)
{
statusBar()->showMessage("Error running transaction: " + QString::fromStdString(diagnostic_information(_e)));
// this output is aimed at developers, reconsider using _e.what for more user friendly output.
}
}
bool beginsWith(Address _a, bytes const& _b)
{
for (unsigned i = 0; i < min<unsigned>(20, _b.size()); ++i)
@ -2025,7 +1688,7 @@ bool beginsWith(Address _a, bytes const& _b)
return true;
}
void Main::on_create_triggered()
void Main::on_newAccount_triggered()
{
bool ok = true;
enum { NoVanity = 0, FirstTwo, FirstTwoNextTwo, FirstThree, FirstFour, StringMatch };
@ -2093,111 +1756,6 @@ void Main::on_killAccount_triggered()
}
}
void Main::on_debugStep_triggered()
{
if (ui->debugTimeline->value() < m_history.size()) {
auto l = m_history[ui->debugTimeline->value()].levels.size();
if ((ui->debugTimeline->value() + 1) < m_history.size() && m_history[ui->debugTimeline->value() + 1].levels.size() > l)
{
on_debugStepInto_triggered();
if (m_history[ui->debugTimeline->value()].levels.size() > l)
on_debugStepOut_triggered();
}
else
on_debugStepInto_triggered();
}
}
void Main::on_debugStepInto_triggered()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() + 1);
ui->callStack->setCurrentRow(0);
}
void Main::on_debugStepOut_triggered()
{
if (ui->debugTimeline->value() < m_history.size())
{
auto ls = m_history[ui->debugTimeline->value()].levels.size();
auto l = ui->debugTimeline->value();
for (; l < m_history.size() && m_history[l].levels.size() >= ls; ++l) {}
ui->debugTimeline->setValue(l);
ui->callStack->setCurrentRow(0);
}
}
void Main::on_debugStepBackInto_triggered()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() - 1);
ui->callStack->setCurrentRow(0);
}
void Main::on_debugStepBack_triggered()
{
auto l = m_history[ui->debugTimeline->value()].levels.size();
if (ui->debugTimeline->value() > 0 && m_history[ui->debugTimeline->value() - 1].levels.size() > l)
{
on_debugStepBackInto_triggered();
if (m_history[ui->debugTimeline->value()].levels.size() > l)
on_debugStepBackOut_triggered();
}
else
on_debugStepBackInto_triggered();
}
void Main::on_debugStepBackOut_triggered()
{
if (ui->debugTimeline->value() > 0 && m_history.size() > 0)
{
auto ls = m_history[min(ui->debugTimeline->value(), m_history.size() - 1)].levels.size();
int l = ui->debugTimeline->value();
for (; l > 0 && m_history[l].levels.size() >= ls; --l) {}
ui->debugTimeline->setValue(l);
ui->callStack->setCurrentRow(0);
}
}
void Main::on_dumpTrace_triggered()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_history)
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl;
}
void Main::on_dumpTracePretty_triggered()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_history)
{
f << endl << " STACK" << endl;
for (auto i: ws.stack)
f << (h256)i << endl;
f << " MEMORY" << endl << dev::memDump(ws.memory);
f << " STORAGE" << endl;
for (auto const& i: ws.storage)
f << showbase << hex << i.first << ": " << i.second << endl;
f << dec << ws.levels.size() << " | " << ws.cur << " | #" << ws.steps << " | " << hex << setw(4) << setfill('0') << ws.curPC << " : " << instructionInfo(ws.inst).name << " | " << dec << ws.gas << " | -" << dec << ws.gasCost << " | " << ws.newMemSize << "x32";
}
}
void Main::on_dumpTraceStorage_triggered()
{
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace");
ofstream f(fn.toStdString());
if (f.is_open())
for (WorldState const& ws: m_history)
{
if (ws.inst == Instruction::STOP || ws.inst == Instruction::RETURN || ws.inst == Instruction::SUICIDE)
for (auto i: ws.storage)
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl;
}
}
void Main::on_go_triggered()
{
if (!ui->net->isChecked())
@ -2208,60 +1766,6 @@ void Main::on_go_triggered()
web3()->connect(Host::pocHost());
}
void Main::on_callStack_currentItemChanged()
{
updateDebugger();
}
void Main::alterDebugStateGroup(bool _enable) const
{
ui->debugStep->setEnabled(_enable);
ui->debugStepInto->setEnabled(_enable);
ui->debugStepOut->setEnabled(_enable);
ui->debugStepBackInto->setEnabled(_enable);
ui->debugStepBackOut->setEnabled(_enable);
ui->dumpTrace->setEnabled(_enable);
ui->dumpTraceStorage->setEnabled(_enable);
ui->dumpTracePretty->setEnabled(_enable);
ui->debugStepBack->setEnabled(_enable);
ui->debugPanel->setEnabled(_enable);
}
void Main::debugFinished()
{
m_codes.clear();
m_pcWarp.clear();
m_history.clear();
m_lastLevels.clear();
m_lastCode = h256();
ui->callStack->clear();
ui->debugCode->clear();
ui->debugStack->clear();
ui->debugMemory->setHtml("");
ui->debugStorage->setHtml("");
ui->debugStateInfo->setText("");
alterDebugStateGroup(false);
// ui->send->setEnabled(true);
}
void Main::initDebugger()
{
// ui->send->setEnabled(false);
if (m_history.size())
{
alterDebugStateGroup(true);
ui->debugCode->setEnabled(false);
ui->debugTimeline->setMinimum(0);
ui->debugTimeline->setMaximum(m_history.size());
ui->debugTimeline->setValue(0);
}
}
void Main::on_debugTimeline_valueChanged()
{
updateDebugger();
}
QString Main::prettyU256(dev::u256 _n) const
{
unsigned inc = 0;
@ -2289,136 +1793,6 @@ QString Main::prettyU256(dev::u256 _n) const
return QString::fromStdString(s.str());
}
void Main::updateDebugger()
{
if (m_history.size())
{
WorldState const& nws = m_history[min((int)m_history.size() - 1, ui->debugTimeline->value())];
WorldState const& ws = ui->callStack->currentRow() > 0 ? *nws.levels[nws.levels.size() - ui->callStack->currentRow()] : nws;
if (ui->debugTimeline->value() >= m_history.size())
{
if (ws.gasCost > ws.gas)
ui->debugMemory->setHtml("<h3>OUT-OF-GAS</h3>");
else if (ws.inst == Instruction::RETURN && ws.stack.size() >= 2)
{
unsigned from = (unsigned)ws.stack.back();
unsigned size = (unsigned)ws.stack[ws.stack.size() - 2];
unsigned o = 0;
bytes out(size, 0);
for (; o < size && from + o < ws.memory.size(); ++o)
out[o] = ws.memory[from + o];
ui->debugMemory->setHtml("<h3>RETURN</h3>" + QString::fromStdString(dev::memDump(out, 16, true)));
}
else if (ws.inst == Instruction::STOP)
ui->debugMemory->setHtml("<h3>STOP</h3>");
else if (ws.inst == Instruction::SUICIDE && ws.stack.size() >= 1)
ui->debugMemory->setHtml("<h3>SUICIDE</h3>0x" + QString::fromStdString(toString(right160(ws.stack.back()))));
else
ui->debugMemory->setHtml("<h3>EXCEPTION</h3>");
ostringstream ss;
ss << dec << "EXIT | GAS: " << dec << max<dev::bigint>(0, (dev::bigint)ws.gas - ws.gasCost);
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
ui->debugStorage->setHtml("");
ui->debugCallData->setHtml("");
m_lastData = h256();
ui->callStack->clear();
m_lastLevels.clear();
ui->debugCode->clear();
m_lastCode = h256();
ui->debugStack->setHtml("");
}
else
{
if (m_lastLevels != nws.levels || !ui->callStack->count())
{
m_lastLevels = nws.levels;
ui->callStack->clear();
for (unsigned i = 0; i <= nws.levels.size(); ++i)
{
WorldState const& s = i ? *nws.levels[nws.levels.size() - i] : nws;
ostringstream out;
out << s.cur.abridged();
if (i)
out << " " << instructionInfo(s.inst).name << " @0x" << hex << s.curPC;
ui->callStack->addItem(QString::fromStdString(out.str()));
}
}
if (ws.code != m_lastCode)
{
bytes const& code = m_codes[ws.code];
QListWidget* dc = ui->debugCode;
dc->clear();
m_pcWarp.clear();
for (unsigned i = 0; i <= code.size(); ++i)
{
byte b = i < code.size() ? code[i] : 0;
try
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
ostringstream out;
out << hex << setw(4) << setfill('0') << i;
m_pcWarp[i] = dc->count();
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = b - (byte)Instruction::PUSH1 + 1;
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&code[i + 1], bc)));
i += bc;
}
dc->addItem(QString::fromStdString(out.str()) + " " + s);
}
catch (...)
{
cerr << "Unhandled exception!" << endl <<
boost::current_exception_diagnostic_information();
break; // probably hit data segment
}
}
m_lastCode = ws.code;
}
if (ws.callData != m_lastData)
{
m_lastData = ws.callData;
if (ws.callData)
{
assert(m_codes.count(ws.callData));
ui->debugCallData->setHtml(QString::fromStdString(dev::memDump(m_codes[ws.callData], 16, true)));
}
else
ui->debugCallData->setHtml("");
}
QString stack;
for (auto i: ws.stack)
stack.prepend("<div>" + prettyU256(i) + "</div>");
ui->debugStack->setHtml(stack);
ui->debugMemory->setHtml(QString::fromStdString(dev::memDump(ws.memory, 16, true)));
assert(m_codes.count(ws.code));
if (m_codes[ws.code].size() >= (unsigned)ws.curPC)
{
int l = m_pcWarp[(unsigned)ws.curPC];
ui->debugCode->setCurrentRow(max(0, l - 5));
ui->debugCode->setCurrentRow(min(ui->debugCode->count() - 1, l + 5));
ui->debugCode->setCurrentRow(l);
}
else
cwarn << "PC (" << (unsigned)ws.curPC << ") is after code range (" << m_codes[ws.code].size() << ")";
ostringstream ss;
ss << dec << "STEP: " << ws.steps << " | PC: 0x" << hex << ws.curPC << " : " << instructionInfo(ws.inst).name << " | ADDMEM: " << dec << ws.newMemSize << " words | COST: " << dec << ws.gasCost << " | GAS: " << dec << ws.gas;
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
stringstream s;
for (auto const& i: ws.storage)
s << "@" << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << prettyU256(i.second).toStdString() << "<br/>";
ui->debugStorage->setHtml(QString::fromStdString(s.str()));
}
}
}
void Main::on_post_clicked()
{
shh::Message m;
@ -2431,14 +1805,16 @@ void Main::on_post_clicked()
whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value()));
}
string Main::lookupNatSpec(dev::h256 const& _contractHash) const
{
return m_natspecDB.retrieve(_contractHash);
}
string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData)
int Main::authenticate(QString _title, QString _text)
{
return m_natspecDB.getUserNotice(_contractHash, _transactionData);
QMessageBox userInput(this);
userInput.setText(_title);
userInput.setInformativeText(_text);
userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
userInput.button(QMessageBox::Ok)->setText("Allow");
userInput.button(QMessageBox::Cancel)->setText("Reject");
userInput.setDefaultButton(QMessageBox::Cancel);
return userInput.exec();
}
void Main::refreshWhispers()

184
alethzero/MainWin.h

@ -34,10 +34,10 @@
#include <libethcore/CommonEth.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libqwebthree/QWebThree.h>
#include <libwebthree/WebThree.h>
#include <libsolidity/CompilerStack.h>
#include "Context.h"
#include "Transact.h"
#include "NatspecHandler.h"
namespace Ui {
@ -49,31 +49,18 @@ class Client;
class State;
}}
namespace jsonrpc {
class HttpServer;
}
class QQuickView;
class OurWebThreeStubServer;
struct WorldState
{
uint64_t steps;
dev::Address cur;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::h256 code;
dev::h256 callData;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<WorldState const*> levels;
};
using WatchHandler = std::function<void(dev::eth::LocalisedLogEntries const&)>;
QString contentsOfQResource(std::string const& res);
class Main : public QMainWindow
class Main: public QMainWindow, public Context
{
Q_OBJECT
@ -85,12 +72,19 @@ public:
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
std::string lookupNatSpec(dev::h256 const& _contractHash) const;
std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData);
NatSpecFace* natSpec() { return &m_natSpecDB; }
QVariant evalRaw(QString const& _js);
QString pretty(dev::Address _a) const override;
QString prettyU256(dev::u256 _n) const override;
QString render(dev::Address _a) const override;
dev::Address fromString(QString const& _a) const override;
std::string renderDiff(dev::eth::StateDiff const& _d) const override;
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
QVariant evalRaw(QString const& _js);
dev::u256 gasPrice() const { return 10 * dev::eth::szabo; }
public slots:
void load(QString _file);
@ -99,75 +93,80 @@ public slots:
void warn(QString _entry);
QString contents(QString _file);
int authenticate(QString _title, QString _text);
void onKeysChanged();
private slots:
void eval(QString const& _js);
// Application
void on_about_triggered();
void on_quit_triggered() { close(); }
// Network
void on_go_triggered();
void on_net_triggered();
void on_connect_triggered();
void on_idealPeers_valueChanged();
// Mining
void on_mine_triggered();
void on_send_clicked();
void on_create_triggered();
// View
void on_refresh_triggered();
void on_showAll_triggered() { refreshBlockChain(); }
void on_showAllAccounts_triggered() { refreshAccounts(); }
void on_preview_triggered();
// Account management
void on_newAccount_triggered();
void on_killAccount_triggered();
void on_net_triggered();
void on_verbosity_valueChanged();
void on_ourAccounts_doubleClicked();
void on_importKey_triggered();
void on_importKeyFile_triggered();
void on_exportKey_triggered();
// Tools
void on_newTransaction_triggered();
void on_loadJS_triggered();
// Stuff concerning the blocks/transactions/accounts panels
void ourAccountsRowsMoved();
void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked();
void on_destination_currentTextChanged();
void on_data_textChanged();
void on_idealPeers_valueChanged();
void on_value_valueChanged() { updateFee(); }
void on_gas_valueChanged() { updateFee(); }
void on_valueUnits_currentIndexChanged() { updateFee(); }
void on_gasPriceUnits_currentIndexChanged() { updateFee(); }
void on_gasPrice_valueChanged() { updateFee(); }
void on_log_doubleClicked();
void on_blocks_currentItemChanged();
void on_contracts_doubleClicked();
void on_contracts_currentItemChanged();
void on_transactionQueue_currentItemChanged();
void on_about_triggered();
void on_paranoia_triggered();
void on_nameReg_textChanged();
void on_preview_triggered();
void on_quit_triggered() { close(); }
void on_blockChainFilter_textChanged();
void on_blocks_currentItemChanged();
// Logging
void on_log_doubleClicked();
void on_verbosity_valueChanged();
// Misc
void on_urlEdit_returnPressed();
void on_debugStep_triggered();
void on_debugStepBack_triggered();
void on_debug_clicked();
void on_debugTimeline_valueChanged();
void on_jsInput_returnPressed();
void on_nameReg_textChanged();
// Special (debug) stuff
void on_paranoia_triggered();
void on_killBlockchain_triggered();
void on_clearPending_triggered();
void on_importKey_triggered();
void on_exportKey_triggered();
void on_inject_triggered();
void on_showAll_triggered() { refreshBlockChain(); }
void on_showAllAccounts_triggered() { refreshAccounts(); }
void on_loadJS_triggered();
void on_blockChainFilter_textChanged();
void on_forceMining_triggered();
void on_dumpTrace_triggered();
void on_dumpTraceStorage_triggered();
void on_dumpTracePretty_triggered();
void on_debugStepInto_triggered();
void on_debugStepOut_triggered();
void on_debugStepBackOut_triggered();
void on_debugStepBackInto_triggered();
void on_callStack_currentItemChanged();
void on_usePrivate_triggered();
void on_turboMining_triggered();
void on_jitvm_triggered();
// Debugger
void on_debugCurrent_triggered();
void on_debugDumpState_triggered(int _add = 1);
void on_debugDumpStatePre_triggered();
void on_refresh_triggered();
void on_usePrivate_triggered();
void on_enableOptimizer_triggered();
void on_turboMining_triggered();
void on_go_triggered();
void on_importKeyFile_triggered();
void on_post_clicked();
// Whisper
void on_newIdentity_triggered();
void on_jitvm_triggered();
void on_post_clicked();
void refreshWhisper();
void refreshBlockChain();
@ -179,33 +178,14 @@ signals:
private:
dev::p2p::NetworkPreferences netPrefs() const;
QString pretty(dev::Address _a) const;
QString prettyU256(dev::u256 _n) const;
QString lookup(QString const& _n) const;
dev::Address getNameReg() const;
dev::Address getCurrencies() const;
void populateDebugger(dev::bytesConstRef r);
void initDebugger();
void updateDebugger();
void debugFinished();
QString render(dev::Address _a) const;
dev::Address fromString(QString const& _a) const;
std::string renderDiff(dev::eth::StateDiff const& _d) const;
void alterDebugStateGroup(bool _enable) const;
void updateFee();
void readSettings(bool _skipGeometry = false);
void writeSettings();
bool isCreation() const;
dev::u256 fee() const;
dev::u256 total() const;
dev::u256 value() const;
dev::u256 gasPrice() const;
unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f);
unsigned installWatch(dev::h256 _tf, WatchHandler const& _f);
void uninstallWatch(unsigned _w);
@ -232,16 +212,9 @@ private:
void refreshAll();
void refreshPending();
void refreshAccounts();
void refreshDestination();
void refreshBlockCount();
void refreshBalances();
/// Attempts to infer that @c _source contains Solidity code
bool sourceIsSolidity(std::string const& _source);
/// @eturns all method hashes of a Solidity contract in a string
std::string const getFunctionHashes(dev::solidity::CompilerStack const &_compiler,
std::string const& _contractName = "");
std::unique_ptr<Ui::Main> ui;
std::unique_ptr<dev::WebThreeDirect> m_webThree;
@ -256,22 +229,8 @@ private:
QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities;
QString m_privateChain;
dev::bytes m_data;
dev::Address m_nameReg;
unsigned m_backupGas;
dev::eth::State m_executiveState;
std::unique_ptr<dev::eth::Executive> m_currentExecution;
dev::h256 m_lastCode;
dev::h256 m_lastData;
std::vector<WorldState const*> m_lastLevels;
QMap<unsigned, unsigned> m_pcWarp;
QList<WorldState> m_history;
std::map<dev::u256, dev::bytes> m_codes; // and pcWarps
bool m_enableOptimizer = true;
QNetworkAccessManager m_webCtrl;
QList<QPair<QString, QString>> m_consoleHistory;
@ -279,10 +238,11 @@ private:
QString m_logHistory;
bool m_logChanged = true;
std::unique_ptr<QWebThreeConnector> m_qwebConnector;
std::unique_ptr<jsonrpc::HttpServer> m_httpConnector;
std::unique_ptr<OurWebThreeStubServer> m_server;
QWebThree* m_qweb = nullptr;
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr);
NatspecHandler m_natspecDB;
NatspecHandler m_natSpecDB;
Transact m_transact;
};

13
alethzero/NatspecHandler.cpp

@ -50,16 +50,15 @@ NatspecHandler::~NatspecHandler()
void NatspecHandler::add(dev::h256 const& _contractHash, string const& _doc)
{
bytes k = _contractHash.asBytes();
string v = _doc;
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
m_db->Put(m_writeOptions, _contractHash.ref(), _doc);
cdebug << "Registering NatSpec: " << _contractHash.abridged() << _doc;
}
string NatspecHandler::retrieve(dev::h256 const& _contractHash) const
{
bytes k = _contractHash.asBytes();
string ret;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
m_db->Get(m_readOptions, _contractHash.ref(), &ret);
cdebug << "Looking up NatSpec: " << _contractHash.abridged() << ret;
return ret;
}
@ -69,8 +68,8 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran
Json::Value userNotice;
string retStr;
m_reader.parse(json, natspec);
bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4);
FixedHash<4> transactionFunctionHash(transactionFunctionPart);
FixedHash<4> transactionFunctionHash((bytesConstRef(&_transactionData).cropped(0, 4).toBytes()));
Json::Value methods = natspec["methods"];
for (Json::ValueIterator it = methods.begin(); it != methods.end(); ++it)

5
alethzero/NatspecHandler.h

@ -28,10 +28,11 @@
#pragma warning(pop)
#include <json/json.h>
#include <libdevcore/FixedHash.h>
#include "Context.h"
namespace ldb = leveldb;
class NatspecHandler
class NatspecHandler: public NatSpecFace
{
public:
NatspecHandler();
@ -40,7 +41,7 @@ class NatspecHandler
/// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation
void add(dev::h256 const& _contractHash, std::string const& _doc);
/// Retrieves the natspec documentation as a string given a contract code hash
std::string retrieve(dev::h256 const& _contractHash) const;
std::string retrieve(dev::h256 const& _contractHash) const override;
/// Given a json natspec string and the transaction data return the user notice
std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData);

71
alethzero/OurWebThreeStubServer.cpp

@ -46,48 +46,71 @@ string OurWebThreeStubServer::shh_newIdentity()
bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const
{
QMessageBox userInput;
userInput.setText(QString::fromStdString(_title));
userInput.setInformativeText(QString::fromStdString(_text + "\n Do you wish to allow this?"));
userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
userInput.button(QMessageBox::Ok)->setText("Allow");
userInput.button(QMessageBox::Cancel)->setText("Reject");
userInput.setDefaultButton(QMessageBox::Cancel);
return userInput.exec() == QMessageBox::Ok;
int button;
QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text)));
return button == QMessageBox::Ok;
}
void OurWebThreeStubServer::showBasicValueTransferNotice(u256 _value) const
bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t) const
{
QMessageBox notice;
notice.setText("Basic Value Transfer Transaction");
notice.setInformativeText(QString::fromStdString("Value is " + toString(_value)));
notice.setStandardButtons(QMessageBox::Ok);
notice.exec();
return showAuthenticationPopup("Contract Creation Transaction", "ÐApp is attemping to create a contract; to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>.");
}
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t) const
{
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>.");
}
bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) const
{
return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!",
"ÐApp is attempting to call into an unknown contract at address " +
m_main->pretty(_t.to).toStdString() +
".\n\nCall involves sending " +
formatBalance(_t.value) + " to the recipient, with additional network fees of up to " +
formatBalance(_t.gas * _t.gasPrice) +
"However, this also does other stuff which we don't understand, and does so in your name.\n\n" +
"WARNING: This is probably going to cost you at least " +
formatBalance(_t.value + _t.gas * _t.gasPrice) +
", however this doesn't include any side-effects, which could be of far greater importance.\n\n" +
"REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!");
}
bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
{
if (_t.creation)
{
// recipient has no code - nothing special about this transaction, show basic value transfer info
return showCreationNotice(_t);
}
h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to);
if (contractCodeHash == EmptySHA3)
// contract creation
return true;
if (false) //TODO: When is is just a value transfer?
{
// recipient has no code - nothing special about this transaction, show basic value transfer info
showBasicValueTransferNotice(_t.value);
return true;
return showSendNotice(_t);
}
string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data);
string userNotice = m_main->natSpec()->getUserNotice(contractCodeHash, _t.data);
if (userNotice.empty())
return showAuthenticationPopup("Unverified Pending Transaction",
"An undocumented transaction is about to be executed.");
return showUnknownCallNotice(_t);
NatspecExpressionEvaluator evaluator;
userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString();
// otherwise it's a transaction to a contract for which we have the natspec
return showAuthenticationPopup("Pending Transaction", userNotice);
return showAuthenticationPopup("Contract Transaction",
"ÐApp attempting to conduct contract interaction with " +
m_main->pretty(_t.to).toStdString() +
": <b>" + userNotice + "</b>.\n\n" +
(_t.value > 0 ?
"In addition, ÐApp is attempting to send " +
formatBalance(_t.value) + " to said recipient, with additional network fees of up to " +
formatBalance(_t.gas * _t.gasPrice) + " = <b>" +
formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>."
:
"Additional network fees are at most" +
formatBalance(_t.gas * _t.gasPrice) + ".")
);
}

4
alethzero/OurWebThreeStubServer.h

@ -42,7 +42,9 @@ signals:
private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const;
void showBasicValueTransferNotice(dev::u256 _value) const;
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t) const;
bool showSendNotice(dev::eth::TransactionSkeleton const& _t) const;
bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t) const;
dev::WebThreeDirect* m_web3;
Main* m_main;

336
alethzero/Transact.cpp

@ -0,0 +1,336 @@
/*
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 Transact.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#include "Transact.h"
#include <fstream>
#include <QFileDialog>
#include <QMessageBox>
#include <liblll/Compiler.h>
#include <liblll/CodeFragment.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/AST.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h>
#include <libethereum/Utility.h>
#ifndef _MSC_VER
#include <libserpent/funcs.h>
#include <libserpent/util.h>
#endif
#include "Debugger.h"
#include "ui_Transact.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
Transact::Transact(Context* _c, QWidget* _parent):
QDialog(_parent),
ui(new Ui::Transact),
m_context(_c)
{
ui->setupUi(this);
initUnits(ui->gasPriceUnits);
initUnits(ui->valueUnits);
ui->valueUnits->setCurrentIndex(6);
ui->gasPriceUnits->setCurrentIndex(4);
ui->gasPrice->setValue(10);
on_destination_currentTextChanged();
}
Transact::~Transact()
{
delete ui;
}
void Transact::setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB)
{
m_myKeys = _myKeys;
m_ethereum = _eth;
m_natSpecDB = _natSpecDB;
}
bool Transact::isCreation() const
{
return ui->destination->currentText().isEmpty() || ui->destination->currentText() == "(Create Contract)";
}
u256 Transact::fee() const
{
return ui->gas->value() * gasPrice();
}
u256 Transact::value() const
{
if (ui->valueUnits->currentIndex() == -1)
return 0;
return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
}
u256 Transact::gasPrice() const
{
if (ui->gasPriceUnits->currentIndex() == -1)
return 0;
return ui->gasPrice->value() * units()[units().size() - 1 - ui->gasPriceUnits->currentIndex()].first;
}
u256 Transact::total() const
{
return value() + fee();
}
void Transact::updateDestination()
{
cwatch << "updateDestination()";
QString s;
for (auto i: ethereum()->addresses())
if ((s = m_context->pretty(i)).size())
// A namereg address
if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1)
ui->destination->addItem(s);
for (int i = 0; i < ui->destination->count(); ++i)
if (ui->destination->itemText(i) != "(Create Contract)" && !m_context->fromString(ui->destination->itemText(i)))
ui->destination->removeItem(i--);
}
void Transact::updateFee()
{
ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str()));
auto totalReq = total();
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false;
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
ok = true;
break;
}
ui->send->setEnabled(ok);
QPalette p = ui->total->palette();
p.setColor(QPalette::WindowText, QColor(ok ? 0x00 : 0x80, 0x00, 0x00));
ui->total->setPalette(p);
}
string Transact::getFunctionHashes(dev::solidity::CompilerStack const& _compiler, string const& _contractName)
{
string ret = "";
auto const& contract = _compiler.getContractDefinition(_contractName);
auto interfaceFunctions = contract.getInterfaceFunctions();
for (auto const& it: interfaceFunctions)
{
ret += it.first.abridged();
ret += " :";
ret += it.second->getDeclaration().getName() + "\n";
}
return ret;
}
void Transact::on_destination_currentTextChanged()
{
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)")
if (Address a = m_context->fromString(ui->destination->currentText()))
ui->calculatedName->setText(m_context->render(a));
else
ui->calculatedName->setText("Unknown Address");
else
ui->calculatedName->setText("Create Contract");
rejigData();
// updateFee();
}
void Transact::rejigData()
{
if (isCreation())
{
string src = ui->data->toPlainText().toStdString();
vector<string> errors;
QString lll;
QString solidity;
if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0)
{
m_data = fromHex(src);
}
else if (sourceIsSolidity(src))
{
dev::solidity::CompilerStack compiler;
try
{
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, ui->optimize->isChecked());
solidity = "<h4>Solidity</h4>";
solidity += "<pre>var " + QString::fromStdString(compiler.defaultContractName()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");</pre>";
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "</pre>";
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "</pre>";
}
catch (dev::Exception const& exception)
{
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>";
}
catch (...)
{
solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>";
}
}
#ifndef _MSC_VER
else if (sourceIsSerpent(src))
{
try
{
m_data = dev::asBytes(::compile(src));
for (auto& i: errors)
i = "(LLL " + i + ")";
}
catch (string err)
{
errors.push_back("Serpent " + err);
}
}
#endif
else
{
m_data = compileLLL(src, ui->optimize->isChecked(), &errors);
if (errors.empty())
{
auto asmcode = compileLLLToAsm(src, false);
lll = "<h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>";
if (ui->optimize->isChecked())
{
asmcode = compileLLLToAsm(src, true);
lll = "<h4>Opt</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>" + lll;
}
}
}
QString errs;
if (errors.size())
{
errs = "<h4>Errors</h4>";
for (auto const& i: errors)
errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>");
}
ui->code->setHtml(errs + lll + solidity + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "<h4>Hex</h4>" Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>");
ui->gas->setMinimum((qint64)Interface::txGas(m_data, 0));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
m_data = parseData(ui->data->toPlainText().toStdString());
auto to = m_context->fromString(ui->destination->currentText());
QString natspec;
if (ethereum()->codeAt(to, 0).size())
{
string userNotice = m_natSpecDB->getUserNotice(ethereum()->postState().codeHash(to), m_data);
if (userNotice.empty())
natspec = "Destination contract unknown.";
else
{
NatspecExpressionEvaluator evaluator;
natspec = evaluator.evalExpression(QString::fromStdString(userNotice));
}
ui->gas->setMinimum((qint64)Interface::txGas(m_data, 1));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
natspec += "Destination not a contract.";
if (ui->gas->isEnabled())
m_backupGas = ui->gas->value();
ui->gas->setValue((qint64)Interface::txGas(m_data));
ui->gas->setEnabled(false);
}
ui->code->setHtml("<h3>NatSpec</h3>" + natspec + "<h3>Dump</h3>" + QString::fromStdString(dev::memDump(m_data, 8, true)) + "<h3>Hex</h3>" + Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>");
}
updateFee();
}
void Transact::on_send_clicked()
{
u256 totalReq = value() + fee();
for (auto const& i: m_myKeys)
if (ethereum()->balanceAt(i.address(), 0) >= totalReq)
{
Secret s = i.secret();
if (isCreation())
{
// If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB
ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice());
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
try
{
dev::solidity::CompilerStack compiler;
m_data = compiler.compile(src, ui->optimize->isChecked());
for (string const& s: compiler.getContractNames())
{
h256 contractHash = compiler.getContractCodeHash(s);
m_natSpecDB->add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NatspecUser));
}
}
catch (...)
{
}
close();
return;
}
else
ethereum()->transact(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
return;
}
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
}
void Transact::on_debug_clicked()
{
try
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
State st(ethereum()->postState());
Secret s = i.secret();
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()), m_data, st.transactionsFrom(dev::toAddress(s)), s);
Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t);
dw.exec();
return;
}
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
}
catch (dev::Exception const& _e)
{
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction. Low-level error: " + QString::fromStdString(diagnostic_information(_e)));
// this output is aimed at developers, reconsider using _e.what for more user friendly output.
}
}

82
alethzero/Transact.h

@ -0,0 +1,82 @@
/*
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 Transact.h
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#pragma once
#include <libdevcore/RLP.h>
#include <libethcore/CommonEth.h>
#include <libethereum/Transaction.h>
#include <QDialog>
#include <QMap>
#include <QList>
#include "Context.h"
namespace Ui { class Transact; }
namespace dev { namespace eth { class Client; } }
namespace dev { namespace solidity { class CompilerStack; } }
class Transact: public QDialog
{
Q_OBJECT
public:
explicit Transact(Context* _context, QWidget* _parent = 0);
~Transact();
void setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB);
private slots:
void on_destination_currentTextChanged();
void on_value_valueChanged() { updateFee(); }
void on_gas_valueChanged() { updateFee(); }
void on_valueUnits_currentIndexChanged() { updateFee(); }
void on_gasPriceUnits_currentIndexChanged() { updateFee(); }
void on_gasPrice_valueChanged() { updateFee(); }
void on_data_textChanged() { rejigData(); }
void on_optimize_clicked() { rejigData(); }
void on_send_clicked();
void on_debug_clicked();
void on_cancel_clicked() { close(); }
private:
dev::eth::Client* ethereum() { return m_ethereum; }
void rejigData();
void updateDestination();
void updateFee();
bool isCreation() const;
dev::u256 fee() const;
dev::u256 total() const;
dev::u256 value() const;
dev::u256 gasPrice() const;
std::string getFunctionHashes(dev::solidity::CompilerStack const& _compiler, std::string const& _contractName = std::string());
Ui::Transact* ui;
unsigned m_backupGas;
dev::bytes m_data;
QList<dev::KeyPair> m_myKeys;
dev::eth::Client* m_ethereum;
Context* m_context;
NatSpecFace* m_natSpecDB;
};

244
alethzero/Transact.ui

@ -0,0 +1,244 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Transact</class>
<widget class="QDialog" name="Transact">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>543</width>
<height>695</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label5_2">
<property name="text">
<string>&amp;Amount</string>
</property>
<property name="buddy">
<cstring>value</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="calculatedName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item row="5" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="4" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;To</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="7" column="2">
<widget class="QPushButton" name="debug">
<property name="text">
<string>&amp;Debug</string>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Execute</string>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Gas</string>
</property>
<property name="buddy">
<cstring>gas</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="gas">
<property name="suffix">
<string> gas</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>10000</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="gasPrice">
<property name="prefix">
<string>@ </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QCheckBox" name="optimize">
<property name="text">
<string>&amp;Optimise</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>D&amp;ata</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="destination">
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>(Create Contract)</string>
</property>
</item>
</widget>
</item>
<item row="6" column="0" colspan="4">
<widget class="QLabel" name="total">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QPushButton" name="cancel">
<property name="text">
<string>&amp;Cancel</string>
</property>
<property name="shortcut">
<string>Esc</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

3
cmake/EthCompilerSettings.cmake

@ -27,13 +27,14 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# enable parallel compilation
# specify Exception Handling Model in msvc
# disable unknown pragma warning (4068)
# disable unsafe function warning (4996)
# disable decorated name length exceeded, name was truncated (4503)
# disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests)
# declare Windows XP requirement
add_compile_options(/EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501)
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501)
# disable empty object file warning
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification

4
cmake/EthDependencies.cmake

@ -59,6 +59,10 @@ if (JSONRPC)
message (" - json-rpc-cpp lib : ${JSON_RPC_CPP_LIBRARIES}")
add_definitions(-DETH_JSONRPC)
find_package(MHD)
message(" - microhttpd header: ${MHD_INCLUDE_DIRS}")
message(" - microhttpd lib : ${MHD_LIBRARIES}")
endif() #JSONRPC
# TODO readline package does not yet check for correct version number

47
cmake/FindMHD.cmake

@ -0,0 +1,47 @@
# Find microhttpd
#
# Find the microhttpd includes and library
#
# if you need to add a custom library search path, do it via via CMAKE_PREFIX_PATH
#
# This module defines
# MHD_INCLUDE_DIRS, where to find header, etc.
# MHD_LIBRARIES, the libraries needed to use jsoncpp.
# MHD_FOUND, If false, do not try to use jsoncpp.
find_path(
MHD_INCLUDE_DIR
NAMES microhttpd.h
DOC "microhttpd include dir"
)
find_library(
MHD_LIBRARY
NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll
DOC "microhttpd library"
)
set(MHD_INCLUDE_DIRS ${MHD_INCLUDE_DIR})
set(MHD_LIBRARIES ${MHD_LIBRARY})
# debug library on windows
# same naming convention as in QT (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
# official MHD project actually uses _d suffix
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
MHD_LIBRARY_DEBUG
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d
DOC "mhd debug library"
)
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(mhd DEFAULT_MSG
MHD_INCLUDE_DIR MHD_LIBRARY)
mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY)

2
eth/CMakeLists.txt

@ -3,9 +3,9 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE eth)

2
evmjit/libevmjit/Arith256.cpp

@ -416,7 +416,7 @@ namespace
explicit operator uint128()
{
uint128 r = lo;
r |= ((uint128) mid) << 64;
r = (r + ((uint128) mid)) << 64;
return r;
}

2
exp/CMakeLists.txt

@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE exp)

8
extdep/CMakeLists.txt

@ -35,14 +35,18 @@ if (ETH_COMPILE)
include(compile/boost.cmake)
else()
eth_download(jsoncpp)
eth_download(json-rpc-cpp OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/json-rpc-cpp_osx.sh)
eth_download(microhttpd)
eth_download(json-rpc-cpp
VERSION 4.2
OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/json-rpc-cpp_osx.sh
)
if (APPLE)
eth_download(snappy OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/snappy_osx.sh)
endif()
eth_download(leveldb OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/leveldb_osx.sh)
eth_download(qt)
eth_download(qt VERSION 5.4)
eth_download(cryptopp)
eth_download(boost)
eth_download(curl)

2
libdevcore/CMakeLists.txt

@ -12,8 +12,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE devcore)

2
libdevcore/RLP.cpp

@ -177,7 +177,7 @@ void RLPStream::noteAppended(unsigned _itemCount)
while (m_listStack.size())
{
if (m_listStack.back().first < _itemCount)
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large"));
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount));
m_listStack.back().first -= _itemCount;
if (m_listStack.back().first)
break;

5
libdevcore/vector_ref.h

@ -1,7 +1,8 @@
#pragma once
#include <type_traits>
#include <cstring>
#include <cassert>
#include <type_traits>
#include <vector>
#include <string>
@ -18,7 +19,7 @@ public:
vector_ref(): m_data(nullptr), m_count(0) {}
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
vector_ref(std::string* _data): m_data((_T*)_data->data()), m_count(_data->size() / sizeof(_T)) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type _data): m_data((_T*)_data->data()), m_count(_data->size() / sizeof(_T)) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {}
#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_

2
libdevcrypto/CMakeLists.txt

@ -9,10 +9,10 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE devcrypto)

6
libethcore/BlockInfo.cpp

@ -134,7 +134,7 @@ void BlockInfo::populate(bytesConstRef _block, bool _checkNonce)
RLP header = root[0];
if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data()));
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data()) << errinfo_comment("block header needs to be a list"));
populateFromHeader(header, _checkNonce);
if (!root[1].isList())
@ -157,8 +157,8 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
{
bytes k = rlp(i);
t.insert(&k, tr.data());
u256 gp = tr[1].toInt<u256>();
mgp = min(mgp, gp);
u256 gasprice = tr[1].toInt<u256>();
mgp = min(mgp, gasprice); // the minimum gas price is not used for anything //TODO delete?
++i;
}
if (transactionsRoot != t.root())

2
libethcore/CMakeLists.txt

@ -9,8 +9,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE ethcore)

10
libethcore/CommonEth.cpp

@ -35,16 +35,6 @@ namespace eth
const unsigned c_protocolVersion = 53;
const unsigned c_databaseVersion = 5;
template <size_t n> u256 exp10()
{
return exp10<n - 1>() * u256(10);
}
template <> u256 exp10<0>()
{
return u256(1);
}
vector<pair<u256, string>> const& units()
{
static const vector<pair<u256, string>> s_units =

33
libethcore/CommonEth.h

@ -47,26 +47,21 @@ std::vector<std::pair<u256, std::string>> const& units();
/// The log bloom's size (512 bit).
using LogBloom = h512;
template <size_t n> inline u256 exp10()
{
return exp10<n - 1>() * u256(10);
}
template <> inline u256 exp10<0>()
{
return u256(1);
}
// The various denominations; here for ease of use where needed within code.
/*static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Vether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Dether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Nether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Yether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Zether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Eether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Pether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Tether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Gether = (u256(1000000000) * 1000000000) * 1000000000;
static const u256 Mether = (u256(1000000000) * 1000000000) * 1000000;
static const u256 grand = (u256(1000000000) * 1000000000) * 1000;*/
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
/*static const u256 Gwei = u256(1000000000);
static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);*/
static const u256 wei = u256(1);
static const u256 ether = exp10<18>();
static const u256 finney = exp10<15>();
static const u256 szabo = exp10<12>();
static const u256 wei = exp10<0>();
}
}

13
libethcore/CommonJS.cpp

@ -97,7 +97,7 @@ std::string fromRaw(h256 _n, unsigned* _inc)
return "";
}
std::string prettyU256(u256 _n)
std::string prettyU256(u256 _n, bool _abridged)
{
unsigned inc = 0;
std::string raw;
@ -110,11 +110,16 @@ std::string prettyU256(u256 _n)
{
Address a = right160(_n);
std::string n = a.abridged();
std::string n;
if (_abridged)
n = a.abridged();
else
n = toHex(a.ref());
if (n.empty())
s << "0x" << a;
s << "0";
else
s << n << "(0x" << a.abridged() << ")";
s << _n << "(0x" << n << ")";
}
else if ((raw = fromRaw((h256)_n, &inc)).size())
return "\"" + raw + "\"" + (inc ? " + " + std::to_string(inc) : "");

3
libethcore/CommonJS.h

@ -59,7 +59,7 @@ bytes unpadded(bytes _s);
/// Remove all 0 byte on the head of @a _s.
bytes unpadLeft(bytes _s);
/// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256.
std::string prettyU256(u256 _n);
std::string prettyU256(u256 _n, bool _abridged = true);
/// Convert h256 into user-readable string (by directly using std::string constructor).
std::string fromRaw(h256 _n, unsigned* _inc = nullptr);
/// Convert string to Address (h160), returns empty address if (_a.size != 40).
@ -144,6 +144,7 @@ inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev:
struct TransactionSkeleton
{
bool creation = false;
Address from;
Address to;
u256 value;

1
libethcore/Exceptions.h

@ -51,6 +51,7 @@ struct UncleTooOld: virtual dev::Exception {};
class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; };
struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {};
struct InvalidGasUsed: virtual dev::Exception {};
class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; };
struct InvalidTransaction: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {};

4
libethereum/BlockChain.h

@ -112,6 +112,10 @@ public:
bytes block(h256 _hash) const;
bytes block() const { return block(currentHash()); }
/// Get a block's transaction (RLP format) for the given block hash (or the most recent mined if none given) & index. Thread-safe.
bytes transaction(h256 _hash, unsigned _i) const { bytes b = block(_hash); return RLP(b)[1][_i].data().toBytes(); }
bytes transaction(unsigned _i) const { return transaction(currentHash(), _i); }
/// Get a number for the given hash (or the most recent mined if none given). Thread-safe.
unsigned number(h256 _hash) const { return details(_hash).number; }
unsigned number() const { return number(currentHash()); }

2
libethereum/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE ethereum)

14
libethereum/Client.cpp

@ -714,6 +714,20 @@ BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
return BlockInfo();
}
unsigned Client::transactionCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[1].itemCount();
}
unsigned Client::uncleCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[2].itemCount();
}
LocalisedLogEntries Client::logs(LogFilter const& _f) const
{
LocalisedLogEntries ret;

2
libethereum/Client.h

@ -229,6 +229,8 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); }
virtual Transaction transaction(h256 _blockHash, unsigned _i) const;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const;
virtual unsigned transactionCount(h256 _blockHash) const;
virtual unsigned uncleCount(h256 _blockHash) const;
/// Differences between transactions.
using Interface::diff;

6
libethereum/Executive.cpp

@ -54,6 +54,12 @@ bool Executive::setup(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.
m_t = Transaction(_rlp, CheckSignature::Sender);
return setup();
}
bool Executive::setup()
{
// Entry point for a user-executed transaction.
// Avoid invalid transactions.
auto nonceReq = m_s.transactionsFrom(m_t.sender());

5
libethereum/Executive.h

@ -62,6 +62,9 @@ public:
/// Set up the executive for evaluating a transaction. You must call finalize() following this.
/// @returns true iff go() must be called (and thus a VM execution in required).
bool setup(bytesConstRef _transaction);
/// Set up the executive for evaluating a transaction. You must call finalize() following this.
/// @returns true iff go() must be called (and thus a VM execution in required).
bool setup(Transaction const& _transaction) { m_t = _transaction; return setup(); }
/// Finalise a transaction previously set up with setup().
/// @warning Only valid after setup(), and possibly go().
void finalize();
@ -101,6 +104,8 @@ public:
bool excepted() const { return m_excepted; }
private:
bool setup();
State& m_s; ///< The state to which this operation/transaction is applied.
LastHashes m_lastHashes;
std::shared_ptr<ExtVM> m_ext; ///< The VM externality object for the VM execution or null if no VM is required.

2
libethereum/Interface.h

@ -103,6 +103,8 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0;
virtual unsigned transactionCount(h256 _blockHash) const = 0;
virtual unsigned uncleCount(h256 _blockHash) const = 0;
// [EXTRA API]:

7
libethereum/State.cpp

@ -600,6 +600,13 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
BOOST_THROW_EXCEPTION(InvalidStateRoot());
}
if (m_currentBlock.gasUsed != gasUsed())
{
// Rollback the trie.
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
}
return tdIncrease;
}

2
libethereum/State.h

@ -132,7 +132,7 @@ public:
* commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* // unlock
* MineInfo info;
* for (info.complete = false; !info.complete; info = mine()) {}
* for (info.completed = false; !info.completed; info = mine()) {}
* }
* // lock
* completeMine();

3
libethereumx/CMakeLists.txt

@ -4,7 +4,8 @@ set(CMAKE_AUTOMOC OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ..)
set(EXECUTABLE ethereumx)

2
libevm/CMakeLists.txt

@ -13,8 +13,8 @@ aux_source_directory(. SRC_LIST)
# we may not use it in libevm, but one of our dependecies is including boost in header file
# and windows is failing to build without that
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE evm)

2
libevmcore/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE evmcore)

4
libjsqrc/setup.js

@ -20,8 +20,6 @@
* @date 2014
*/
navigator.qt = _web3;
var web3 = require('web3');
web3.setProvider(new web3.providers.QtSyncProvider());
web3.setProvider(new web3.providers.HttpSyncProvider());

2
liblll/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE lll)

2
libnatspec/CMakeLists.txt

@ -13,7 +13,7 @@ set(CMAKE_AUTOMOC OFF)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ..)
set(EXECUTABLE natspec)

2
libp2p/CMakeLists.txt

@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
# we may not use it in libp2p, but one of our dependecies is including leveldb in header file
# and windows is failing to build without that
include_directories(${LEVELDB_INCLUDE_DIRS})
@ -18,7 +19,6 @@ include_directories(${LEVELDB_INCLUDE_DIRS})
if (MINIUPNPC_FOUND)
include_directories(${MINIUPNPC_INCLUDE_DIRS})
endif()
include_directories(..)
set(EXECUTABLE p2p)

2
libp2p/Host.cpp

@ -54,7 +54,7 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, byte
m_ioService(2),
m_tcp4Acceptor(m_ioService),
m_alias(networkAlias(_restoreNetwork)),
m_lastPing(chrono::time_point<chrono::steady_clock>::min())
m_lastPing(chrono::steady_clock::time_point::min())
{
for (auto address: m_ifAddresses)
if (address.is_v4())

8
libp2p/NodeTable.h

@ -163,15 +163,15 @@ public:
std::list<NodeEntry> snapshot() const;
/// Returns true if node id is in node table.
bool haveNode(NodeId const& _id) { Guard l(x_nodes); return m_nodes.count(_id); }
bool haveNode(NodeId const& _id) { Guard l(x_nodes); return m_nodes.count(_id) > 0; }
/// Returns the Node to the corresponding node id or the empty Node if that id is not found.
Node node(NodeId const& _id);
#ifndef BOOST_AUTO_TEST_SUITE
private:
#else
#if defined(BOOST_AUTO_TEST_SUITE) || defined(_MSC_VER) // MSVC includes access specifier in symbol name
protected:
#else
private:
#endif
/// Constants for Kademlia, derived from address space.

6
libp2p/Session.cpp

@ -40,10 +40,10 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr<Peer> const&
m_server(_s),
m_socket(std::move(_socket)),
m_peer(_n),
m_info({NodeId(), "?", m_socket.remote_endpoint().address().to_string(), 0, std::chrono::steady_clock::duration(0), CapDescSet(), 0, map<string, string>()}),
m_ping(chrono::time_point<chrono::steady_clock>::max())
m_info({NodeId(), "?", m_socket.remote_endpoint().address().to_string(), 0, chrono::steady_clock::duration(0), CapDescSet(), 0, map<string, string>()}),
m_ping(chrono::steady_clock::time_point::max())
{
m_lastReceived = m_connect = std::chrono::steady_clock::now();
m_lastReceived = m_connect = chrono::steady_clock::now();
}
Session::~Session()

41
libqwebthree/CMakeLists.txt

@ -1,41 +0,0 @@
cmake_policy(SET CMP0015 NEW)
# let cmake autolink dependencies on windows
cmake_policy(SET CMP0020 NEW)
# this policy was introduced in cmake 3.0
# remove if, once 3.0 will be used on unix
if (${CMAKE_MAJOR_VERSION} GREATER 2)
# old policy do not use MACOSX_RPATH
cmake_policy(SET CMP0042 OLD)
cmake_policy(SET CMP0043 OLD)
endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE qwebthree)
file(GLOB HEADERS "*.h")
if(ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Gui)
target_link_libraries(${EXECUTABLE} Qt5::WebKit)
target_link_libraries(${EXECUTABLE} Qt5::WebKitWidgets)
target_link_libraries(${EXECUTABLE} Qt5::Widgets)
target_link_libraries(${EXECUTABLE} Qt5::Network)
target_link_libraries(${EXECUTABLE} Qt5::Quick)
target_link_libraries(${EXECUTABLE} Qt5::Qml)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES})
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} secp256k1)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

107
libqwebthree/QWebThree.cpp

@ -1,107 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file QWebThree.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#include <QtCore/QtCore>
#include "QWebThree.h"
using namespace std;
QWebThree::QWebThree(QObject* _p): QObject(_p)
{
moveToThread(_p->thread());
}
QWebThree::~QWebThree()
{
clientDieing();
}
void QWebThree::clientDieing()
{
this->disconnect();
}
QString QWebThree::callMethod(QString _json)
{
emit processData(_json, ""); // it's synchronous
return m_response;
}
void QWebThree::onDataProcessed(QString _json, QString)
{
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
syncResponse(QString::fromUtf8(QJsonDocument(f).toJson()));
}
void QWebThree::syncResponse(QString _json)
{
m_response = _json;
}
QWebThreeConnector::QWebThreeConnector()
{
}
QWebThreeConnector::~QWebThreeConnector()
{
StopListening();
}
void QWebThreeConnector::setQWeb(QWebThree* _q)
{
m_qweb = _q;
if (m_isListening)
{
StopListening();
StartListening();
}
}
bool QWebThreeConnector::StartListening()
{
m_isListening = true;
if (m_qweb)
{
connect(m_qweb, SIGNAL(processData(QString, QString)), this, SLOT(onProcessData(QString, QString)));
connect(this, SIGNAL(dataProcessed(QString, QString)), m_qweb, SLOT(onDataProcessed(QString, QString)));
}
return true;
}
bool QWebThreeConnector::StopListening()
{
this->disconnect();
return true;
}
bool QWebThreeConnector::SendResponse(std::string const& _response, void* _addInfo)
{
emit dataProcessed(QString::fromStdString(_response), *(QString*)_addInfo);
return true;
}
void QWebThreeConnector::onProcessData(QString const& _json, QString const& _addInfo)
{
OnRequest(_json.toStdString(), (void*)&_addInfo);
}

89
libqwebthree/QWebThree.h

@ -1,89 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file QWebThree.h
* @authors:
* Gav Wood <i@gavwood.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#pragma once
#include <QtCore/QObject>
#include <QtCore/QString>
#include <jsonrpccpp/server.h>
class QWebThree: public QObject
{
Q_OBJECT
public:
QWebThree(QObject* _p);
virtual ~QWebThree();
void clientDieing();
Q_INVOKABLE QString callMethod(QString _json);
void syncResponse(QString _json);
public slots:
void onDataProcessed(QString _json, QString _addInfo);
signals:
void processData(QString _json, QString _addInfo);
void response(QString _json);
void onNewId(QString _id);
private:
QString m_response;
};
class QWebThreeConnector: public QObject, public jsonrpc::AbstractServerConnector
{
Q_OBJECT
public:
QWebThreeConnector();
virtual ~QWebThreeConnector();
void setQWeb(QWebThree *_q);
virtual bool StartListening();
virtual bool StopListening();
virtual bool SendResponse(std::string const& _response, void* _addInfo = NULL);
public slots:
void onProcessData(QString const& _json, QString const& _addInfo);
signals:
void dataProcessed(QString const& _json, QString const& _addInfo);
private:
QWebThree* m_qweb = nullptr;
bool m_isListening;
};
#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, qweb) [_frame, _env, qweb]() \
{ \
_frame->disconnect(); \
_frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/bignumber.min.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/webthree.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \
}

2
libserpent/CMakeLists.txt

@ -11,7 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ..)
set(EXECUTABLE serpent)

55
libsolidity/AST.cpp

@ -206,6 +206,13 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn
return *m_interfaceFunctionList;
}
TypePointer EnumValue::getType(ContractDefinition const*) const
{
EnumDefinition const* parentDef = dynamic_cast<EnumDefinition const*>(getScope());
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
return make_shared<EnumType>(*parentDef);
}
void InheritanceSpecifier::checkTypeRequirements()
{
m_baseName->checkTypeRequirements();
@ -255,6 +262,11 @@ void StructDefinition::checkRecursion() const
}
}
TypePointer EnumDefinition::getType(ContractDefinition const*) const
{
return make_shared<TypeType>(make_shared<EnumType>(*this));
}
TypePointer FunctionDefinition::getType(ContractDefinition const*) const
{
return make_shared<FunctionType>(*this);
@ -262,6 +274,15 @@ TypePointer FunctionDefinition::getType(ContractDefinition const*) const
void FunctionDefinition::checkTypeRequirements()
{
// change all byte arrays parameters to point to calldata
if (getVisibility() == Visibility::External)
for (ASTPointer<VariableDeclaration> const& var: getParameters())
{
auto const& type = var->getType();
solAssert(!!type, "");
if (auto const* byteArrayType = dynamic_cast<ByteArrayType const*>(type.get()))
var->setType(byteArrayType->copyForLocation(ByteArrayType::Location::CallData));
}
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
@ -276,12 +297,23 @@ string FunctionDefinition::getCanonicalSignature() const
return FunctionType(*this).getCanonicalSignature(getName());
}
Declaration::LValueType VariableDeclaration::getLValueType() const
bool VariableDeclaration::isLValue() const
{
if (dynamic_cast<FunctionDefinition const*>(getScope()) || dynamic_cast<ModifierDefinition const*>(getScope()))
return Declaration::LValueType::Local;
else
return Declaration::LValueType::Storage;
if (auto const* function = dynamic_cast<FunctionDefinition const*>(getScope()))
if (function->getVisibility() == Declaration::Visibility::External && isFunctionParameter())
return false;
return true;
}
bool VariableDeclaration::isFunctionParameter() const
{
auto const* function = dynamic_cast<FunctionDefinition const*>(getScope());
if (!function)
return false;
for (auto const& variable: function->getParameters())
if (variable.get() == this)
return true;
return false;
}
TypePointer ModifierDefinition::getType(ContractDefinition const*) const
@ -402,10 +434,8 @@ void Assignment::checkTypeRequirements()
{
m_leftHandSide->checkTypeRequirements();
m_leftHandSide->requireLValue();
//@todo later, assignments to structs might be possible, but not to mappings
if (m_leftHandSide->getType()->getCategory() != Type::Category::ByteArray &&
!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue())
BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue."));
if (m_leftHandSide->getType()->getCategory() == Type::Category::Mapping)
BOOST_THROW_EXCEPTION(createTypeError("Mappings cannot be assigned to."));
m_type = m_leftHandSide->getType();
if (m_assigmentOperator == Token::Assign)
m_rightHandSide->expectType(*m_type);
@ -576,8 +606,7 @@ void MemberAccess::checkTypeRequirements()
if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
"visible in " + type.toString()));
//@todo later, this will not always be STORAGE
m_lvalue = type.getCategory() == Type::Category::Struct ? Declaration::LValueType::Storage : Declaration::LValueType::None;
m_isLValue = (type.getCategory() == Type::Category::Struct);
}
void IndexAccess::checkTypeRequirements()
@ -589,14 +618,14 @@ void IndexAccess::checkTypeRequirements()
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
m_index->expectType(*type.getKeyType());
m_type = type.getValueType();
m_lvalue = Declaration::LValueType::Storage;
m_isLValue = true;
}
void Identifier::checkTypeRequirements()
{
solAssert(m_referencedDeclaration, "Identifier not resolved.");
m_lvalue = m_referencedDeclaration->getLValueType();
m_isLValue = m_referencedDeclaration->isLValue();
m_type = m_referencedDeclaration->getType(m_currentContract);
if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined."));

60
libsolidity/AST.h

@ -132,8 +132,8 @@ private:
class Declaration: public ASTNode
{
public:
enum class LValueType { None, Local, Storage };
enum class Visibility { Default, Public, Protected, Private };
/// Visibility ordered from restricted to unrestricted.
enum class Visibility { Default, Private, Protected, Public, External };
Declaration(Location const& _location, ASTPointer<ASTString> const& _name,
Visibility _visibility = Visibility::Default):
@ -142,7 +142,9 @@ public:
/// @returns the declared name.
ASTString const& getName() const { return *m_name; }
Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; }
bool isPublic() const { return getVisibility() == Visibility::Public; }
bool isPublic() const { return getVisibility() >= Visibility::Public; }
bool isVisibleInContract() const { return getVisibility() != Visibility::External; }
bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Protected; }
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step.
@ -153,8 +155,7 @@ public:
/// The current contract has to be given since this context can change the type, especially of
/// contract types.
virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0;
/// @returns the lvalue type of expressions referencing this declaration
virtual LValueType getLValueType() const { return LValueType::None; }
virtual bool isLValue() const { return false; }
protected:
virtual Visibility getDefaultVisibility() const { return Visibility::Public; }
@ -209,6 +210,7 @@ public:
ASTPointer<ASTString> const& _documentation,
std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts,
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
std::vector<ASTPointer<EnumDefinition>> const& _definedEnums,
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
@ -216,6 +218,7 @@ public:
Declaration(_location, _name), Documented(_documentation),
m_baseContracts(_baseContracts),
m_definedStructs(_definedStructs),
m_definedEnums(_definedEnums),
m_stateVariables(_stateVariables),
m_definedFunctions(_definedFunctions),
m_functionModifiers(_functionModifiers),
@ -227,6 +230,7 @@ public:
std::vector<ASTPointer<InheritanceSpecifier>> const& getBaseContracts() const { return m_baseContracts; }
std::vector<ASTPointer<StructDefinition>> const& getDefinedStructs() const { return m_definedStructs; }
std::vector<ASTPointer<EnumDefinition>> const& getDefinedEnums() const { return m_definedEnums; }
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<ModifierDefinition>> const& getFunctionModifiers() const { return m_functionModifiers; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
@ -260,6 +264,7 @@ private:
std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<EnumDefinition>> m_definedEnums;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
@ -315,6 +320,39 @@ private:
std::vector<ASTPointer<VariableDeclaration>> m_members;
};
class EnumDefinition: public Declaration
{
public:
EnumDefinition(Location const& _location,
ASTPointer<ASTString> const& _name,
std::vector<ASTPointer<EnumValue>> const& _members):
Declaration(_location, _name), m_members(_members) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<EnumValue>> const& getMembers() const { return m_members; }
virtual TypePointer getType(ContractDefinition const*) const override;
private:
std::vector<ASTPointer<EnumValue>> m_members;
};
/**
* Declaration of an Enum Value
*/
class EnumValue: public Declaration
{
public:
EnumValue(Location const& _location,
ASTPointer<ASTString> const& _name):
Declaration(_location, _name) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
TypePointer getType(ContractDefinition const* = nullptr) const;
};
/**
* Parameter list, used as function parameter list and return list.
* None of the parameters is allowed to contain mappings (not even recursively
@ -408,8 +446,9 @@ public:
TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; }
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
virtual LValueType getLValueType() const override;
virtual bool isLValue() const override;
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isFunctionParameter() const;
bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; }
@ -847,8 +886,7 @@ public:
virtual void checkTypeRequirements() = 0;
std::shared_ptr<Type const> const& getType() const { return m_type; }
bool isLValue() const { return m_lvalue != Declaration::LValueType::None; }
bool isLocalLValue() const { return m_lvalue == Declaration::LValueType::Local; }
bool isLValue() const { return m_isLValue; }
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it
/// is implicitly convertible to @a _expectedType. If not, throw exception.
@ -863,9 +901,9 @@ public:
protected:
//! Inferred type of the expression, only filled after a call to checkTypeRequirements().
std::shared_ptr<Type const> m_type;
//! If this expression is an lvalue (i.e. something that can be assigned to) and is stored
//! locally or in storage. This is set during calls to @a checkTypeRequirements()
Declaration::LValueType m_lvalue = Declaration::LValueType::None;
//! If this expression is an lvalue (i.e. something that can be assigned to).
//! This is set during calls to @a checkTypeRequirements()
bool m_isLValue = false;
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
bool m_lvalueRequested = false;
};

2
libsolidity/ASTForward.h

@ -40,6 +40,8 @@ class Declaration;
class ContractDefinition;
class InheritanceSpecifier;
class StructDefinition;
class EnumDefinition;
class EnumValue;
class ParameterList;
class FunctionDefinition;
class VariableDeclaration;

15
libsolidity/ASTJsonConverter.cpp

@ -118,11 +118,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
bool ASTJsonConverter::visit(VariableDeclaration const& _node)
{
bool isLocalVariable = (_node.getLValueType() == VariableDeclaration::LValueType::Local);
addJsonNode("VariableDeclaration",
{ make_pair("name", _node.getName()),
make_pair("local", boost::lexical_cast<std::string>(isLocalVariable))},
true);
addJsonNode("VariableDeclaration", { make_pair("name", _node.getName()) }, true);
return true;
}
@ -216,11 +212,12 @@ bool ASTJsonConverter::visit(ExpressionStatement const&)
bool ASTJsonConverter::visit(Expression const& _node)
{
addJsonNode("Expression",
addJsonNode(
"Expression",
{ make_pair("type", getType(_node)),
make_pair("lvalue", boost::lexical_cast<std::string>(_node.isLValue())),
make_pair("local_lvalue", boost::lexical_cast<std::string>(_node.isLocalLValue())) },
true);
make_pair("lvalue", boost::lexical_cast<std::string>(_node.isLValue())) },
true
);
return true;
}

22
libsolidity/ASTPrinter.cpp

@ -71,6 +71,18 @@ bool ASTPrinter::visit(StructDefinition const& _node)
return goDeeper();
}
bool ASTPrinter::visit(EnumDefinition const& _node)
{
writeLine("EnumDefinition \"" + _node.getName() + "\"");
return goDeeper();
}
bool ASTPrinter::visit(EnumValue const& _node)
{
writeLine("EnumValue \"" + _node.getName() + "\"");
return goDeeper();
}
bool ASTPrinter::visit(ParameterList const& _node)
{
writeLine("ParameterList");
@ -347,6 +359,16 @@ void ASTPrinter::endVisit(StructDefinition const&)
m_indentation--;
}
void ASTPrinter::endVisit(EnumDefinition const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(EnumValue const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(ParameterList const&)
{
m_indentation--;

4
libsolidity/ASTPrinter.h

@ -46,6 +46,8 @@ public:
bool visit(ContractDefinition const& _node) override;
bool visit(InheritanceSpecifier const& _node) override;
bool visit(StructDefinition const& _node) override;
bool visit(EnumDefinition const& _node) override;
bool visit(EnumValue const& _node) override;
bool visit(ParameterList const& _node) override;
bool visit(FunctionDefinition const& _node) override;
bool visit(VariableDeclaration const& _node) override;
@ -85,6 +87,8 @@ public:
void endVisit(ContractDefinition const&) override;
void endVisit(InheritanceSpecifier const&) override;
void endVisit(StructDefinition const&) override;
void endVisit(EnumDefinition const&) override;
void endVisit(EnumValue const&) override;
void endVisit(ParameterList const&) override;
void endVisit(FunctionDefinition const&) override;
void endVisit(VariableDeclaration const&) override;

8
libsolidity/ASTVisitor.h

@ -47,6 +47,8 @@ public:
virtual bool visit(ContractDefinition&) { return true; }
virtual bool visit(InheritanceSpecifier&) { return true; }
virtual bool visit(StructDefinition&) { return true; }
virtual bool visit(EnumDefinition&) { return true; }
virtual bool visit(EnumValue&) { return true; }
virtual bool visit(ParameterList&) { return true; }
virtual bool visit(FunctionDefinition&) { return true; }
virtual bool visit(VariableDeclaration&) { return true; }
@ -88,6 +90,8 @@ public:
virtual void endVisit(ContractDefinition&) { }
virtual void endVisit(InheritanceSpecifier&) { }
virtual void endVisit(StructDefinition&) { }
virtual void endVisit(EnumDefinition&) { }
virtual void endVisit(EnumValue&) { }
virtual void endVisit(ParameterList&) { }
virtual void endVisit(FunctionDefinition&) { }
virtual void endVisit(VariableDeclaration&) { }
@ -133,6 +137,8 @@ public:
virtual bool visit(ContractDefinition const&) { return true; }
virtual bool visit(InheritanceSpecifier const&) { return true; }
virtual bool visit(StructDefinition const&) { return true; }
virtual bool visit(EnumDefinition const&) { return true; }
virtual bool visit(EnumValue const&) { return true; }
virtual bool visit(ParameterList const&) { return true; }
virtual bool visit(FunctionDefinition const&) { return true; }
virtual bool visit(VariableDeclaration const&) { return true; }
@ -174,6 +180,8 @@ public:
virtual void endVisit(ContractDefinition const&) { }
virtual void endVisit(InheritanceSpecifier const&) { }
virtual void endVisit(StructDefinition const&) { }
virtual void endVisit(EnumDefinition const&) { }
virtual void endVisit(EnumValue const&) { }
virtual void endVisit(ParameterList const&) { }
virtual void endVisit(FunctionDefinition const&) { }
virtual void endVisit(VariableDeclaration const&) { }

28
libsolidity/AST_accept.h

@ -63,6 +63,7 @@ void ContractDefinition::accept(ASTVisitor& _visitor)
{
listAccept(m_baseContracts, _visitor);
listAccept(m_definedStructs, _visitor);
listAccept(m_definedEnums, _visitor);
listAccept(m_stateVariables, _visitor);
listAccept(m_events, _visitor);
listAccept(m_functionModifiers, _visitor);
@ -77,6 +78,7 @@ void ContractDefinition::accept(ASTConstVisitor& _visitor) const
{
listAccept(m_baseContracts, _visitor);
listAccept(m_definedStructs, _visitor);
listAccept(m_definedEnums, _visitor);
listAccept(m_stateVariables, _visitor);
listAccept(m_events, _visitor);
listAccept(m_functionModifiers, _visitor);
@ -105,6 +107,32 @@ void InheritanceSpecifier::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
void EnumDefinition::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
listAccept(m_members, _visitor);
_visitor.endVisit(*this);
}
void EnumDefinition::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
listAccept(m_members, _visitor);
_visitor.endVisit(*this);
}
void EnumValue::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void EnumValue::accept(ASTConstVisitor& _visitor) const
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void StructDefinition::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))

4
libsolidity/CMakeLists.txt

@ -11,9 +11,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSONCPP_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE solidity)

49
libsolidity/Compiler.cpp

@ -147,7 +147,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
// retrieve the function signature hash from the calldata
if (!interfaceFunctions.empty())
CompilerUtils(m_context).loadFromMemory(0, 4, false, true);
CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true);
// stack now is: 1 0 <funhash>
for (auto const& it: interfaceFunctions)
@ -178,23 +178,46 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
}
}
unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory)
void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory)
{
// We do not check the calldata size, everything is zero-padded.
unsigned dataOffset = CompilerUtils::dataStartOffset; // the 4 bytes of the function hash signature
//@todo this can be done more efficiently, saving some CALLDATALOAD calls
unsigned offset(CompilerUtils::dataStartOffset);
bool const c_padToWords = true;
unsigned dynamicParameterCount = 0;
for (TypePointer const& type: _typeParameters)
if (type->isDynamicallySized())
dynamicParameterCount++;
offset += dynamicParameterCount * 32;
unsigned currentDynamicParameter = 0;
for (TypePointer const& type: _typeParameters)
if (type->isDynamicallySized())
{
unsigned const c_numBytes = type->getCalldataEncodedSize();
if (c_numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_comment("Type " + type->toString() + " not yet supported."));
bool const c_leftAligned = type->getCategory() == Type::Category::String;
bool const c_padToWords = true;
dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned,
!_fromMemory, c_padToWords);
// value on stack: [calldata_offset] (only if we are already in dynamic mode)
if (currentDynamicParameter == 0)
// switch from static to dynamic
m_context << u256(offset);
// retrieve length
CompilerUtils(m_context).loadFromMemory(
CompilerUtils::dataStartOffset + currentDynamicParameter * 32,
IntegerType(256), !_fromMemory, c_padToWords);
// stack: offset length
// add 32-byte padding to copy of length
m_context << u256(32) << eth::Instruction::DUP1 << u256(31)
<< eth::Instruction::DUP4 << eth::Instruction::ADD
<< eth::Instruction::DIV << eth::Instruction::MUL;
// stack: offset length padded_length
m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
currentDynamicParameter++;
// stack: offset length next_calldata_offset
}
return dataOffset;
else if (currentDynamicParameter == 0)
// we can still use static load
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, c_padToWords);
else
CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, c_padToWords);
if (dynamicParameterCount > 0)
m_context << eth::Instruction::POP;
}
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)

6
libsolidity/Compiler.h

@ -20,6 +20,8 @@
* Solidity AST to EVM bytecode compiler.
*/
#pragma once
#include <ostream>
#include <functional>
#include <libsolidity/ASTVisitor.h>
@ -52,8 +54,8 @@ private:
void appendConstructorCall(FunctionDefinition const& _constructor);
void appendFunctionSelector(ContractDefinition const& _contract);
/// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers.
/// From memory if @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
unsigned appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
/// From memory if @a _fromMemory is true, otherwise from call data.
void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
void appendReturnValuePacker(TypePointers const& _typeParameters);
void registerStateVariables(ContractDefinition const& _contract);

5
libsolidity/CompilerStack.cpp

@ -333,6 +333,11 @@ void CompilerStack::resolveImports()
swap(m_sourceOrder, sourceOrder);
}
std::string CompilerStack::defaultContractName() const
{
return getContract("").contract->getName();
}
CompilerStack::Contract const& CompilerStack::getContract(string const& _contractName) const
{
if (m_contracts.empty())

1
libsolidity/CompilerStack.h

@ -73,6 +73,7 @@ public:
void parse(std::string const& _sourceCode);
/// Returns a list of the contract names in the sources.
std::vector<std::string> getContractNames() const;
std::string defaultContractName() const;
/// Compiles the source units that were previously added and parsed.
void compile(bool _optimize = false);

103
libsolidity/CompilerUtils.cpp

@ -33,35 +33,26 @@ namespace solidity
const unsigned int CompilerUtils::dataStartOffset = 4;
unsigned CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned,
unsigned CompilerUtils::loadFromMemory(unsigned _offset, Type const& _type,
bool _fromCalldata, bool _padToWordBoundaries)
{
if (_bytes == 0)
{
m_context << u256(0);
return 0;
}
eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD;
solAssert(_bytes <= 32, "Memory load of more than 32 bytes requested.");
if (_bytes == 32 || _padToWordBoundaries)
{
m_context << u256(_offset) << load;
return 32;
}
else
{
// load data and add leading or trailing zeros by dividing/multiplying depending on alignment
u256 shiftFactor = u256(1) << ((32 - _bytes) * 8);
m_context << shiftFactor;
if (_leftAligned)
solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically load dynamic type.");
m_context << u256(_offset);
return loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
}
void CompilerUtils::loadFromMemoryDynamic(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
solAssert(_type.getCategory() != Type::Category::ByteArray, "Byte arrays not yet implemented.");
m_context << eth::Instruction::DUP1;
m_context << u256(_offset) << load << eth::Instruction::DIV;
if (_leftAligned)
m_context << eth::Instruction::MUL;
return _bytes;
}
unsigned numBytes = loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
// update memory counter
for (unsigned i = 0; i < _type.getSizeOnStack(); ++i)
m_context << eth::swapInstruction(1 + i);
m_context << u256(numBytes) << eth::Instruction::ADD;
}
unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries)
{
solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically store dynamic type.");
@ -76,8 +67,19 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
if (_type.getCategory() == Type::Category::ByteArray)
{
auto const& type = dynamic_cast<ByteArrayType const&>(_type);
solAssert(type.getLocation() == ByteArrayType::Location::Storage, "Non-storage byte arrays not yet implemented.");
if (type.getLocation() == ByteArrayType::Location::CallData)
{
// stack: target source_offset source_len
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5
// stack: target source_offset source_len source_len source_offset target
<< eth::Instruction::CALLDATACOPY
<< eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP;
}
else
{
solAssert(type.getLocation() == ByteArrayType::Location::Storage, "Memory byte arrays not yet implemented.");
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// stack here: memory_offset storage_offset length_bytes
// jump to end if length is zero
@ -106,11 +108,13 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
m_context.appendConditionalJumpTo(loopStart);
m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP;
}
}
else
{
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
if (numBytes > 0)
{
solAssert(_type.getSizeOnStack() == 1, "Memory store of types with stack size != 1 not implemented.");
m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
m_context << u256(numBytes) << eth::Instruction::ADD;
}
@ -170,29 +174,32 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
{
case ByteArrayType::Location::CallData:
{
// @todo this does not take length into account. It also assumes that after "CALLDATALENGTH" we only have zeros.
// This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
// stack here: target_ref target_length_words
// stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic();
// compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack here: target_ref target_data_end target_data_ref
// stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes)
m_context << eth::Instruction::CALLDATASIZE;
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP5 << eth::Instruction::SSTORE;
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
<< eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// store start offset
m_context << u256(0);
// stack now: target_ref target_data_end target_data_ref calldata_offset
m_context << eth::Instruction::DUP5;
// stack now: source_offset source_len target_ref target_data_end target_data_ref calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart
// copy from calldata and store
@ -203,16 +210,18 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
// increment calldata_offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATASIZE << eth::Instruction::GT;
<< eth::Instruction::DUP1 << eth::Instruction::DUP6 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP;
m_context << copyLoopEnd;
// now clear leftover bytes of the old value
// stack now: target_ref target_data_end target_data_ref
// stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop();
// stack now: source_offset source_len target_ref target_data_end
m_context << eth::Instruction::POP;
m_context << eth::Instruction::POP << eth::Instruction::SWAP2
<< eth::Instruction::POP << eth::Instruction::POP;
break;
}
case ByteArrayType::Location::Storage:
@ -280,6 +289,30 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
}
}
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
unsigned _encodedSize = _type.getCalldataEncodedSize();
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
bool leftAligned = _type.getCategory() == Type::Category::String;
if (numBytes == 0)
m_context << eth::Instruction::POP << u256(0);
else
{
solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
m_context << (_fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD);
if (numBytes != 32)
{
// add leading or trailing zeros by dividing/multiplying depending on alignment
u256 shiftFactor = u256(1) << ((32 - numBytes) * 8);
m_context << shiftFactor << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (leftAligned)
m_context << shiftFactor << eth::Instruction::MUL;
}
}
return numBytes;
}
void CompilerUtils::clearByteArray(ByteArrayType const& _type) const
{
solAssert(_type.getLocation() == ByteArrayType::Location::Storage, "");

14
libsolidity/CompilerUtils.h

@ -37,14 +37,16 @@ public:
/// Loads data from memory to the stack.
/// @param _offset offset in memory (or calldata)
/// @param _bytes number of bytes to load
/// @param _leftAligned if true, store left aligned on stack (otherwise right aligned)
/// @param _type data type to load
/// @param _fromCalldata if true, load from calldata, not from memory
/// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries
/// @returns the number of bytes consumed in memory (can be different from _bytes if
/// _padToWordBoundaries is true)
unsigned loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false,
/// @returns the number of bytes consumed in memory.
unsigned loadFromMemory(unsigned _offset, Type const& _type = IntegerType(256),
bool _fromCalldata = false, bool _padToWordBoundaries = false);
/// Dynamic version of @see loadFromMemory, expects the memory offset on the stack.
/// Stack pre: memory_offset
/// Stack post: value... (memory_offset+length)
void loadFromMemoryDynamic(Type const& _type, bool _fromCalldata = false, bool _padToWordBoundaries = true);
/// Stores data from stack in memory.
/// @param _offset offset in memory
/// @param _type type of the data on the stack
@ -93,6 +95,8 @@ public:
private:
/// Prepares the given type for storing in memory by shifting it if necessary.
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
/// Loads type from memory assuming memory offset is on stack top.
unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries);
/// Appends a loop that clears a sequence of storage slots (excluding end).
/// Stack pre: end_ref start_ref
/// Stack post: end_ref

13
libsolidity/DeclarationContainer.cpp

@ -28,14 +28,19 @@ namespace dev
namespace solidity
{
bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _update)
bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update)
{
if (_declaration.getName().empty())
ASTString const& name(_declaration.getName());
if (name.empty())
return true;
if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end())
if (!_update && (m_declarations.count(name) || m_invisibleDeclarations.count(name)))
return false;
m_declarations[_declaration.getName()] = &_declaration;
if (_invisible)
m_invisibleDeclarations.insert(name);
else
m_declarations[name] = &_declaration;
return true;
}

6
libsolidity/DeclarationContainer.h

@ -23,6 +23,7 @@
#pragma once
#include <map>
#include <set>
#include <boost/noncopyable.hpp>
#include <libsolidity/ASTForward.h>
@ -43,8 +44,10 @@ public:
DeclarationContainer const* _enclosingContainer = nullptr):
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
/// Registers the declaration in the scope unless its name is already declared or the name is empty.
/// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName
/// @param _update if true, replaces a potential declaration that is already present
/// @returns false if the name was already declared.
bool registerDeclaration(Declaration const& _declaration, bool _update = false);
bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false);
Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const;
Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
std::map<ASTString, Declaration const*> const& getDeclarations() const { return m_declarations; }
@ -53,6 +56,7 @@ private:
Declaration const* m_enclosingDeclaration;
DeclarationContainer const* m_enclosingContainer;
std::map<ASTString, Declaration const*> m_declarations;
std::set<ASTString> m_invisibleDeclarations;
};
}

219
libsolidity/ExpressionCompiler.cpp

@ -70,12 +70,12 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
solAssert(_assignment.getType()->isValueType(), "Compound operators not implemented for non-value types.");
if (m_currentLValue.storesReferenceOnStack())
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
m_currentLValue.retrieveValue(_assignment.getType(), _assignment.getLocation(), true);
m_currentLValue.retrieveValue(_assignment.getLocation(), true);
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
if (m_currentLValue.storesReferenceOnStack())
m_context << eth::Instruction::SWAP1;
}
m_currentLValue.storeValue(_assignment, *_assignment.getRightHandSide().getType());
m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation());
m_currentLValue.reset();
return false;
@ -105,13 +105,13 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
break;
case Token::Delete: // delete
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
m_currentLValue.setToZero(_unaryOperation, *_unaryOperation.getSubExpression().getType());
m_currentLValue.setToZero(_unaryOperation.getLocation());
m_currentLValue.reset();
break;
case Token::Inc: // ++ (pre- or postfix)
case Token::Dec: // -- (pre- or postfix)
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
m_currentLValue.retrieveValue(_unaryOperation.getType(), _unaryOperation.getLocation());
m_currentLValue.retrieveValue(_unaryOperation.getLocation());
if (!_unaryOperation.isPrefixOperation())
{
if (m_currentLValue.storesReferenceOnStack())
@ -128,7 +128,8 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
// Stack for postfix: *ref [ref] (*ref)+-1
if (m_currentLValue.storesReferenceOnStack())
m_context << eth::Instruction::SWAP1;
m_currentLValue.storeValue(_unaryOperation, *_unaryOperation.getType(), !_unaryOperation.isPrefixOperation());
m_currentLValue.storeValue(*_unaryOperation.getType(), _unaryOperation.getLocation(),
!_unaryOperation.isPrefixOperation());
m_currentLValue.reset();
break;
case Token::Add: // +
@ -474,9 +475,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
else if (member == "gasprice")
m_context << eth::Instruction::GASPRICE;
else if (member == "data")
{
// nothing to store on the stack
}
m_context << u256(0) << eth::Instruction::CALLDATASIZE;
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member."));
break;
@ -484,31 +483,54 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD;
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *_memberAccess.getType());
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _memberAccess.getType());
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
break;
}
case Type::Category::Enum:
{
EnumType const& type = dynamic_cast<EnumType const&>(*_memberAccess.getExpression().getType());
m_context << type.getMemberValue(_memberAccess.getMemberName());
break;
}
case Type::Category::TypeType:
{
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.getExpression().getType());
if (type.getMembers().getMemberType(member))
if (!type.getMembers().getMemberType(member))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to " + type.toString()));
if (auto contractType = dynamic_cast<ContractType const*>(type.getActualType().get()))
{
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*type.getActualType())
.getContractDefinition();
ContractDefinition const& contract = contractType->getContractDefinition();
for (ASTPointer<FunctionDefinition> const& function: contract.getDefinedFunctions())
if (function->getName() == member)
{
m_context << m_context.getFunctionEntryLabel(*function).pushTag();
return;
}
solAssert(false, "Function not found in member access.");
}
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to " + type.toString()));
else if (auto enumType = dynamic_cast<EnumType const*>(type.getActualType().get()))
m_context << enumType->getMemberValue(_memberAccess.getMemberName());
break;
}
case Type::Category::ByteArray:
{
solAssert(member == "length", "Illegal bytearray member.");
auto const& type = dynamic_cast<ByteArrayType const&>(*_memberAccess.getExpression().getType());
switch (type.getLocation())
{
case ByteArrayType::Location::CallData:
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
break;
case ByteArrayType::Location::Storage:
m_context << eth::Instruction::SLOAD;
break;
default:
solAssert(false, "Unsupported byte array location.");
break;
}
break;
}
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type."));
@ -530,7 +552,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
appendTypeMoveToMemory(IntegerType(256));
m_context << u256(0) << eth::Instruction::SHA3;
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *_indexAccess.getType());
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
return false;
@ -561,6 +583,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
{
// no-op
}
else if (dynamic_cast<EnumDefinition const*>(declaration))
{
// no-op
}
else
{
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context."));
@ -744,6 +770,9 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
}
}
}
else if (stackTypeCategory == Type::Category::Enum)
solAssert(targetTypeCategory == Type::Category::Integer ||
targetTypeCategory == Type::Category::Enum, "");
else if (stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::Contract ||
stackTypeCategory == Type::Category::IntegerConstant)
{
@ -757,6 +786,9 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
solAssert(typeOnStack.getNumBits() == targetStringType.getNumBytes() * 8, "The size should be the same.");
m_context << (u256(1) << (256 - typeOnStack.getNumBits())) << eth::Instruction::MUL;
}
else if (targetTypeCategory == Type::Category::Enum)
// just clean
appendTypeConversion(_typeOnStack, *_typeOnStack.getRealType(), true);
else
{
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
@ -864,11 +896,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
m_context << eth::Instruction::POP;
m_context << eth::Instruction::POP; // pop contract address
if (retSize > 0)
{
bool const c_leftAligned = firstType->getCategory() == Type::Category::String;
CompilerUtils(m_context).loadFromMemory(0, retSize, c_leftAligned, false, true);
}
if (firstType)
CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true);
}
void ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expression const>> const& _arguments,
@ -939,8 +968,8 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context << eth::Instruction::DUP1
<< structType->getStorageOffsetOfMember(names[i])
<< eth::Instruction::ADD;
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *types[i]);
m_currentLValue.retrieveValue(types[i], Location(), true);
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, types[i]);
m_currentLValue.retrieveValue(Location(), true);
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
m_context << eth::Instruction::SWAP1;
retSizeOnStack += types[i]->getSizeOnStack();
@ -951,27 +980,51 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{
// simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *returnType);
m_currentLValue.retrieveValue(returnType, Location(), true);
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, returnType);
m_currentLValue.retrieveValue(Location(), true);
retSizeOnStack = returnType->getSizeOnStack();
}
solAssert(retSizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP;
}
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,
unsigned _baseStackOffset):
m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset)
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type,
TypePointer const& _dataType, unsigned _baseStackOffset):
m_context(&_compilerContext), m_type(_type), m_dataType(_dataType),
m_baseStackOffset(_baseStackOffset)
{
//@todo change the type cast for arrays
solAssert(_dataType.getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " +_dataType.toString() + " should fit in unsigned");
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(),
"The storage size of " + m_dataType->toString() + " should fit in unsigned");
if (m_type == LValueType::Storage)
m_size = unsigned(_dataType.getStorageSize());
m_size = unsigned(m_dataType->getStorageSize());
else
m_size = unsigned(m_dataType->getSizeOnStack());
}
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
{
if (m_context->isLocalVariable(&_declaration))
{
m_type = LValueType::Stack;
m_dataType = _identifier.getType();
m_size = m_dataType->getSizeOnStack();
m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration);
}
else if (m_context->isStateVariable(&_declaration))
{
*m_context << m_context->getStorageLocationOfVariable(_declaration);
m_type = LValueType::Storage;
m_dataType = _identifier.getType();
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(),
"The storage size of " + m_dataType->toString() + " should fit in an unsigned");
m_size = unsigned(m_dataType->getStorageSize()); }
else
m_size = unsigned(_dataType.getSizeOnStack());
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())
<< errinfo_comment("Identifier type not supported or identifier not found."));
}
void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Location const& _location, bool _remove) const
void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const
{
switch (m_type)
{
@ -986,10 +1039,10 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio
break;
}
case LValueType::Storage:
retrieveValueFromStorage(_type, _remove);
retrieveValueFromStorage(_remove);
break;
case LValueType::Memory:
if (!_type->isValueType())
if (!m_dataType->isValueType())
break; // no distinction between value and reference for non-value types
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Location type not yet implemented."));
@ -1001,9 +1054,9 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio
}
}
void ExpressionCompiler::LValue::retrieveValueFromStorage(TypePointer const& _type, bool _remove) const
void ExpressionCompiler::LValue::retrieveValueFromStorage(bool _remove) const
{
if (!_type->isValueType())
if (!m_dataType->isValueType())
return; // no distinction between value and reference for non-value types
if (!_remove)
*m_context << eth::Instruction::DUP1;
@ -1020,7 +1073,7 @@ void ExpressionCompiler::LValue::retrieveValueFromStorage(TypePointer const& _ty
}
}
void ExpressionCompiler::LValue::storeValue(Expression const& _expression, Type const& _sourceType, bool _move) const
void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location const& _location, bool _move) const
{
switch (m_type)
{
@ -1028,23 +1081,23 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, Type
{
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1;
if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Stack too deep."));
else if (stackDiff > 0)
for (unsigned i = 0; i < m_size; ++i)
*m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP;
if (!_move)
retrieveValue(_expression.getType(), _expression.getLocation());
retrieveValue(_location);
break;
}
case LValueType::Storage:
// stack layout: value value ... value target_ref
if (_expression.getType()->isValueType())
if (m_dataType->isValueType())
{
if (!_move) // copy values
{
if (m_size + 1 > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Stack too deep."));
for (unsigned i = 0; i < m_size; ++i)
*m_context << eth::dupInstruction(m_size + 1) << eth::Instruction::SWAP1;
@ -1064,36 +1117,60 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, Type
}
else
{
solAssert(!_move, "Move assign for non-value types not implemented.");
solAssert(_sourceType.getCategory() == _expression.getType()->getCategory(), "");
if (_expression.getType()->getCategory() == Type::Category::ByteArray)
solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "");
if (m_dataType->getCategory() == Type::Category::ByteArray)
CompilerUtils(*m_context).copyByteArrayToStorage(
dynamic_cast<ByteArrayType const&>(*_expression.getType()),
dynamic_cast<ByteArrayType const&>(*m_dataType),
dynamic_cast<ByteArrayType const&>(_sourceType));
else if (_expression.getType()->getCategory() == Type::Category::Struct)
{
//@todo
solAssert(false, "Struct copy not yet implemented.");
else if (m_dataType->getCategory() == Type::Category::Struct)
{
// stack layout: source_ref target_ref
auto const& structType = dynamic_cast<StructType const&>(*m_dataType);
solAssert(structType == _sourceType, "Struct assignment with conversion.");
for (auto const& member: structType.getMembers())
{
// assign each member that is not a mapping
TypePointer const& memberType = member.second;
if (memberType->getCategory() == Type::Category::Mapping)
continue;
*m_context << structType.getStorageOffsetOfMember(member.first)
<< eth::Instruction::DUP3 << eth::Instruction::DUP2
<< eth::Instruction::ADD;
LValue rightHandSide(*m_context, LValueType::Storage, memberType);
rightHandSide.retrieveValue(_location, true);
// stack: source_ref target_ref offset source_value...
*m_context << eth::dupInstruction(2 + memberType->getSizeOnStack())
<< eth::dupInstruction(2 + memberType->getSizeOnStack())
<< eth::Instruction::ADD;
LValue memberLValue(*m_context, LValueType::Storage, memberType);
memberLValue.storeValue(*memberType, _location, true);
*m_context << eth::Instruction::POP;
}
if (_move)
*m_context << eth::Instruction::POP;
else
*m_context << eth::Instruction::SWAP1;
*m_context << eth::Instruction::POP;
}
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Invalid non-value type for assignment."));
}
break;
case LValueType::Memory:
if (!_expression.getType()->isValueType())
if (!m_dataType->isValueType())
break; // no distinction between value and reference for non-value types
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Location type not yet implemented."));
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Unsupported location type."));
break;
}
}
void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type const& _type) const
void ExpressionCompiler::LValue::setToZero(Location const& _location) const
{
switch (m_type)
{
@ -1101,7 +1178,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type c
{
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset));
if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Stack too deep."));
solAssert(stackDiff >= m_size - 1, "");
for (unsigned i = 0; i < m_size; ++i)
@ -1110,8 +1187,8 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type c
break;
}
case LValueType::Storage:
if (_type.getCategory() == Type::Category::ByteArray)
CompilerUtils(*m_context).clearByteArray(dynamic_cast<ByteArrayType const&>(_type));
if (m_dataType->getCategory() == Type::Category::ByteArray)
CompilerUtils(*m_context).clearByteArray(dynamic_cast<ByteArrayType const&>(*m_dataType));
else
{
if (m_size == 0)
@ -1125,11 +1202,11 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type c
}
break;
case LValueType::Memory:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Location type not yet implemented."));
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Unsupported location type."));
break;
}
@ -1139,36 +1216,10 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co
{
if (!_expression.lvalueRequested())
{
retrieveValue(_expression.getType(), _expression.getLocation(), true);
retrieveValue(_expression.getLocation(), true);
reset();
}
}
void ExpressionCompiler::LValue::fromStateVariable(Declaration const& _varDecl, TypePointer const& _type)
{
m_type = LValueType::Storage;
solAssert(_type->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _type->toString() + " should fit in an unsigned");
*m_context << m_context->getStorageLocationOfVariable(_varDecl);
m_size = unsigned(_type->getStorageSize());
}
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
{
if (m_context->isLocalVariable(&_declaration))
{
m_type = LValueType::Stack;
m_size = _identifier.getType()->getSizeOnStack();
m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration);
}
else if (m_context->isStateVariable(&_declaration))
{
fromStateVariable(_declaration, _identifier.getType());
}
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())
<< errinfo_comment("Identifier type not supported or identifier not found."));
}
}
}

33
libsolidity/ExpressionCompiler.h

@ -22,8 +22,10 @@
*/
#include <functional>
#include <memory>
#include <boost/noncopyable.hpp>
#include <libdevcore/Common.h>
#include <libsolidity/BaseTypes.h>
#include <libsolidity/ASTVisitor.h>
namespace dev {
@ -37,6 +39,7 @@ namespace solidity {
class CompilerContext;
class Type;
class IntegerType;
class ByteArrayType;
class StaticStringType;
/**
@ -119,14 +122,13 @@ private:
enum class LValueType { None, Stack, Memory, Storage };
explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); }
LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset = 0);
LValue(CompilerContext& _compilerContext, LValueType _type,
std::shared_ptr<Type const> const& _dataType, unsigned _baseStackOffset = 0);
/// Set type according to the declaration and retrieve the reference.
/// @a _expression is the current expression
void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration);
/// Convenience function to set type for a state variable and retrieve the reference
void fromStateVariable(Declaration const& _varDecl, TypePointer const& _type);
void reset() { m_type = LValueType::None; m_baseStackOffset = 0; m_size = 0; }
void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; }
bool isValid() const { return m_type != LValueType::None; }
bool isInOnStack() const { return m_type == LValueType::Stack; }
@ -138,30 +140,29 @@ private:
/// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true,
/// also removes the reference from the stack (note that is does not reset the type to @a NONE).
/// @a _type is the type of the current expression and @ _location its location, used for error reporting.
/// @a _location can be a nullptr for expressions that don't have an actual ASTNode equivalent
void retrieveValue(TypePointer const& _type, Location const& _location, bool _remove = false) const;
/// Stores a value (from the stack directly beneath the reference, which is assumed to
/// be on the top of the stack, if any) in the lvalue and removes the reference.
/// Also removes the stored value from the stack if @a _move is
/// true. @a _expression is the current expression, used for error reporting.
/// @a _sourceType is the type of the expression that is assigned.
void storeValue(Expression const& _expression, Type const& _sourceType, bool _move = false) const;
/// @a _location source location of the current expression, used for error reporting.
void retrieveValue(Location const& _location, bool _remove = false) const;
/// Moves a value from the stack to the lvalue. Removes the value if @a _move is true.
/// @a _location is the source location of the expression that caused this operation.
/// Stack pre: [lvalue_ref] value
/// Stack post if !_move: value_of(lvalue_ref)
void storeValue(Type const& _sourceType, Location const& _location = Location(), bool _move = false) const;
/// Stores zero in the lvalue.
/// @a _expression is the current expression, used for error reporting.
void setToZero(Expression const& _expression, Type const& _type) const;
/// @a _location is the source location of the requested operation
void setToZero(Location const& _location = Location()) const;
/// Convenience function to convert the stored reference to a value and reset type to NONE if
/// the reference was not requested by @a _expression.
void retrieveValueIfLValueNotRequested(Expression const& _expression);
private:
/// Convenience function to retrieve Value from Storage. Specific version of @ref retrieveValue
void retrieveValueFromStorage(TypePointer const& _type, bool _remove = false) const;
void retrieveValueFromStorage(bool _remove = false) const;
/// Copies from a byte array to a byte array in storage, both references on the stack.
void copyByteArrayToStorage(ByteArrayType const& _targetType, ByteArrayType const& _sourceType) const;
CompilerContext* m_context;
LValueType m_type = LValueType::None;
std::shared_ptr<Type const> m_dataType;
/// If m_type is STACK, this is base stack offset (@see
/// CompilerContext::getBaseStackOffsetOfVariable) of a local variable.
unsigned m_baseStackOffset = 0;

9
libsolidity/InterfaceHandler.cpp

@ -108,16 +108,7 @@ unique_ptr<string> InterfaceHandler::getABISolidityInterface(ContractDefinition
ret.pop_back();
ret += "{}";
}
for (auto const& it: _contractDef.getInterfaceEvents())
{
std::string params;
for (auto const& p: it->getParameters())
params += (params.empty() ? "(" : ",") + p->getType()->toString() + (p->isIndexed() ? " indexed " : " ") + p->getName();
if (!params.empty())
params += ")";
ret += "event " + it->getName() + params + ";";
}
return unique_ptr<string>(new string(ret + "}"));
}

28
libsolidity/NameAndTypeResolver.cpp

@ -58,6 +58,8 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
ReferencesResolver resolver(*structDef, *this, &_contract, nullptr);
for (ASTPointer<EnumDefinition> const& enumDef: _contract.getDefinedEnums())
ReferencesResolver resolver(*enumDef, *this, &_contract, nullptr);
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
ReferencesResolver resolver(*variable, *this, &_contract, nullptr);
for (ASTPointer<EventDefinition> const& event: _contract.getEvents())
@ -84,7 +86,7 @@ void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract)
void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
{
m_scopes[nullptr].registerDeclaration(_declaration, true);
m_scopes[nullptr].registerDeclaration(_declaration, false, true);
solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope.");
}
@ -108,8 +110,9 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base)
for (auto const& nameAndDeclaration: iterator->second.getDeclarations())
{
Declaration const* declaration = nameAndDeclaration.second;
// Import if it was declared in the base and is not the constructor
if (declaration->getScope() == &_base && declaration->getName() != _base.getName())
// Import if it was declared in the base, is not the constructor and is visible in derived classes
if (declaration->getScope() == &_base && declaration->getName() != _base.getName() &&
declaration->isVisibleInDerivedContracts())
m_currentScope->registerDeclaration(*declaration);
}
}
@ -221,6 +224,23 @@ void DeclarationRegistrationHelper::endVisit(StructDefinition&)
closeCurrentScope();
}
bool DeclarationRegistrationHelper::visit(EnumDefinition& _enum)
{
registerDeclaration(_enum, true);
return true;
}
void DeclarationRegistrationHelper::endVisit(EnumDefinition&)
{
closeCurrentScope();
}
bool DeclarationRegistrationHelper::visit(EnumValue& _value)
{
registerDeclaration(_value, false);
return true;
}
bool DeclarationRegistrationHelper::visit(FunctionDefinition& _function)
{
registerDeclaration(_function, true);
@ -289,7 +309,7 @@ void DeclarationRegistrationHelper::closeCurrentScope()
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
{
if (!m_scopes[m_currentScope].registerDeclaration(_declaration))
if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract()))
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
<< errinfo_comment("Identifier already declared."));
//@todo the exception should also contain the location of the first declaration

3
libsolidity/NameAndTypeResolver.h

@ -98,6 +98,9 @@ private:
void endVisit(ContractDefinition& _contract) override;
bool visit(StructDefinition& _struct) override;
void endVisit(StructDefinition& _struct) override;
bool visit(EnumDefinition& _enum) override;
void endVisit(EnumDefinition& _enum) override;
bool visit(EnumValue& _value) override;
bool visit(FunctionDefinition& _function) override;
void endVisit(FunctionDefinition& _function) override;
bool visit(ModifierDefinition& _modifier) override;

39
libsolidity/Parser.cpp

@ -119,6 +119,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
ASTPointer<ASTString> name = expectIdentifierToken();
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
vector<ASTPointer<StructDefinition>> structs;
vector<ASTPointer<EnumDefinition>> enums;
vector<ASTPointer<VariableDeclaration>> stateVariables;
vector<ASTPointer<FunctionDefinition>> functions;
vector<ASTPointer<ModifierDefinition>> modifiers;
@ -140,6 +141,8 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
functions.push_back(parseFunctionDefinition(name.get()));
else if (currentToken == Token::Struct)
structs.push_back(parseStructDefinition());
else if (currentToken == Token::Enum)
enums.push_back(parseEnumDefinition());
else if (currentToken == Token::Identifier || currentToken == Token::Mapping ||
Token::isElementaryTypeName(currentToken))
{
@ -157,7 +160,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
}
nodeFactory.markEndPosition();
expectToken(Token::RBrace);
return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs,
return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs, enums,
stateVariables, functions, modifiers, events);
}
@ -187,6 +190,8 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
visibility = Declaration::Visibility::Protected;
else if (_token == Token::Private)
visibility = Declaration::Visibility::Private;
else if (_token == Token::External)
visibility = Declaration::Visibility::External;
else
solAssert(false, "Invalid visibility specifier.");
m_scanner->next();
@ -263,6 +268,36 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
return nodeFactory.createNode<StructDefinition>(name, members);
}
ASTPointer<EnumValue> Parser::parseEnumValue()
{
ASTNodeFactory nodeFactory(*this);
nodeFactory.markEndPosition();
return nodeFactory.createNode<EnumValue>(expectIdentifierToken());
}
ASTPointer<EnumDefinition> Parser::parseEnumDefinition()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::Enum);
ASTPointer<ASTString> name = expectIdentifierToken();
vector<ASTPointer<EnumValue>> members;
expectToken(Token::LBrace);
while (m_scanner->getCurrentToken() != Token::RBrace)
{
members.push_back(parseEnumValue());
if (m_scanner->getCurrentToken() == Token::RBrace)
break;
expectToken(Token::Comma);
if (m_scanner->getCurrentToken() != Token::Identifier)
BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ','"));
}
nodeFactory.markEndPosition();
expectToken(Token::RBrace);
return nodeFactory.createNode<EnumDefinition>(name, members);
}
ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOptions const& _options)
{
ASTNodeFactory nodeFactory(*this);
@ -273,7 +308,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOp
ASTPointer<ASTString> identifier;
Token::Value token = m_scanner->getCurrentToken();
Declaration::Visibility visibility(Declaration::Visibility::Default);
if (_options.isStateVariable && Token::isVisibilitySpecifier(token))
if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token))
visibility = parseVisibilitySpecifier(token);
if (_options.allowIndexed && token == Token::Indexed)
{

2
libsolidity/Parser.h

@ -61,6 +61,8 @@ private:
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<EnumDefinition> parseEnumDefinition();
ASTPointer<EnumValue> parseEnumValue();
ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions());
ASTPointer<ModifierDefinition> parseModifierDefinition();
ASTPointer<EventDefinition> parseEventDefinition();

6
libsolidity/Token.h

@ -150,6 +150,7 @@ namespace solidity
K(Do, "do", 0) \
K(Else, "else", 0) \
K(Event, "event", 0) \
K(External, "external", 0) \
K(Is, "is", 0) \
K(Indexed, "indexed", 0) \
K(For, "for", 0) \
@ -168,7 +169,7 @@ namespace solidity
K(Switch, "switch", 0) \
K(Var, "var", 0) \
K(While, "while", 0) \
\
K(Enum, "enum", 0) \
\
/* Ether subdenominations */ \
K(SubWei, "wei", 0) \
@ -378,7 +379,8 @@ public:
static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; }
static bool isCountOp(Value op) { return op == Inc || op == Dec; }
static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); }
static bool isVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; }
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; }
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; }
// Returns a string corresponding to the JS token string

70
libsolidity/Types.cpp

@ -74,6 +74,8 @@ TypePointer Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
Declaration const* declaration = _typeName.getReferencedDeclaration();
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
return make_shared<StructType>(*structDef);
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
return make_shared<EnumType>(*enumDef);
else if (FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(declaration))
return make_shared<FunctionType>(*function);
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
@ -154,7 +156,9 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
StaticStringType const& convertTo = dynamic_cast<StaticStringType const&>(_convertTo);
return isHash() && (m_bits == convertTo.getNumBytes() * 8);
}
return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::Contract;
return _convertTo.getCategory() == getCategory() ||
_convertTo.getCategory() == Category::Contract ||
_convertTo.getCategory() == Category::Enum;
}
TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
@ -536,12 +540,19 @@ bool ByteArrayType::operator==(Type const& _other) const
unsigned ByteArrayType::getSizeOnStack() const
{
if (m_location == Location::CallData)
return 0;
// offset, length (stack top)
return 2;
else
// offset
return 1;
}
const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared<IntegerType >(256)}});
shared_ptr<ByteArrayType> ByteArrayType::copyForLocation(ByteArrayType::Location _location) const
{
return make_shared<ByteArrayType>(_location);
}
const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared<IntegerType>(256)}});
bool ContractType::operator==(Type const& _other) const
{
@ -568,7 +579,8 @@ MemberList const& ContractType::getMembers() const
{
for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions())
if (!function->isConstructor() && !function->getName().empty())
if (!function->isConstructor() && !function->getName().empty() &&
function->isVisibleInDerivedContracts())
members.insert(make_pair(function->getName(), make_shared<FunctionType>(*function, true)));
}
else
@ -653,7 +665,7 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const
{
//@todo cache member offset?
u256 offset;
for (ASTPointer<VariableDeclaration> variable: m_struct.getMembers())
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
{
if (variable->getName() == _name)
return offset;
@ -662,6 +674,41 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested."));
}
TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
{
return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer();
}
bool EnumType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
EnumType const& other = dynamic_cast<EnumType const&>(_other);
return other.m_enum == m_enum;
}
string EnumType::toString() const
{
return string("enum ") + m_enum.getName();
}
bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::Integer;
}
unsigned int EnumType::getMemberValue(ASTString const& _member) const
{
unsigned int index = 0;
for (ASTPointer<EnumValue> const& decl: m_enum.getMembers())
{
if (decl->getName() == _member)
return index;
++index;
}
BOOST_THROW_EXCEPTION(m_enum.createTypeError("Requested unknown enum value ." + _member));
}
FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
m_location(_isInternal ? Location::Internal : Location::External),
m_isConstant(_function.isDeclaredConst()),
@ -730,7 +777,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
}
FunctionType::FunctionType(const EventDefinition& _event):
m_location(Location::Event), m_declaration(&_event)
m_location(Location::Event), m_isConstant(true), m_declaration(&_event)
{
TypePointers params;
vector<string> paramNames;
@ -918,12 +965,19 @@ MemberList const& TypeType::getMembers() const
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).getContractDefinition();
vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts();
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
// We are accessing the type of a base contract, so add all public and private
// We are accessing the type of a base contract, so add all public and protected
// functions. Note that this does not add inherited functions on purpose.
for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions())
if (!f->isConstructor() && !f->getName().empty())
if (!f->isConstructor() && !f->getName().empty() && f->isVisibleInDerivedContracts())
members[f->getName()] = make_shared<FunctionType>(*f);
}
else if (m_actualType->getCategory() == Category::Enum)
{
EnumDefinition const& enumDef = dynamic_cast<EnumType const&>(*m_actualType).getEnumDefinition();
auto enumType = make_shared<EnumType>(enumDef);
for (ASTPointer<EnumValue> const& enumValue: enumDef.getMembers())
members.insert(make_pair(enumValue->getName(), enumType));
}
m_members.reset(new MemberList(members));
}
return *m_members;

40
libsolidity/Types.h

@ -76,10 +76,9 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this<Type
public:
enum class Category
{
Integer, IntegerConstant, Bool, Real, String,
ByteArray, Mapping,
Contract, Struct, Function,
Void, TypeType, Modifier, Magic
Integer, IntegerConstant, Bool, Real, ByteArray,
String, Contract, Struct, Function, Enum,
Mapping, Void, TypeType, Modifier, Magic
};
///@{
@ -123,6 +122,8 @@ public:
/// is not a simple big-endian encoding or the type cannot be stored in calldata.
/// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes.
virtual unsigned getCalldataEncodedSize() const { return 0; }
/// @returns true if the type is dynamically encoded in calldata
virtual bool isDynamicallySized() const { return false; }
/// @returns number of bytes required to hold this value in storage.
/// For dynamically "allocated" types, it returns the size of the statically allocated head,
virtual u256 getStorageSize() const { return 1; }
@ -290,12 +291,17 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override;
virtual bool isDynamicallySized() const { return true; }
virtual unsigned getSizeOnStack() const override;
virtual std::string toString() const override { return "bytes"; }
virtual MemberList const& getMembers() const override { return s_byteArrayMemberList; }
Location getLocation() const { return m_location; }
/// @returns a copy of this type with location changed to @a _location
/// @todo this might move as far up as Type later
std::shared_ptr<ByteArrayType> copyForLocation(Location _location) const;
private:
Location m_location;
static const MemberList s_byteArrayMemberList;
@ -368,6 +374,32 @@ private:
mutable std::unique_ptr<MemberList> m_members;
};
/**
* The type of an enum instance, there is one distinct type per enum definition.
*/
class EnumType: public Type
{
public:
virtual Category getCategory() const override { return Category::Enum; }
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned getSizeOnStack() const override { return 1; }
virtual std::string toString() const override;
virtual bool isValueType() const override { return true; }
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
EnumDefinition const& getEnumDefinition() const { return m_enum; }
/// @returns the value that the string has in the Enum
unsigned int getMemberValue(ASTString const& _member) const;
private:
EnumDefinition const& m_enum;
/// List of member types, will be lazy-initialized because of recursive references.
mutable std::unique_ptr<MemberList> m_members;
};
/**
* The type of a function, identified by its (return) parameter types.
* @todo the return parameters should also have names, i.e. return parameters should be a struct

5
libsolidity/grammar.txt

@ -1,7 +1,7 @@
ContractDefinition = 'contract' Identifier
( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )?
'{' ContractPart* '}'
ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition
ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition | EnumDefinition
InheritanceSpecifier = Identifier ( '(' Expression ( ',' Expression )* ')' )?
StructDefinition = 'struct' Identifier '{'
@ -11,6 +11,9 @@ ModifierDefinition = 'modifier' Identifier ParameterList? Block
FunctionDefinition = 'function' Identifier ParameterList
( Identifier | 'constant' | 'public' | 'protected' | 'private' )*
( 'returns' ParameterList )? Block
EnumValue = Identifier
EnumDefinition = 'enum' '{' EnumValue (',' EnumValue)* '}'
ParameterList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')'
// semantic restriction: mappings and structs (recursively) containing mappings
// are not allowed in argument lists

5
libweb3jsonrpc/CMakeLists.txt

@ -9,9 +9,11 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${MHD_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE web3jsonrpc)
@ -26,6 +28,7 @@ endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES})
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)

71
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -264,7 +264,7 @@ Json::Value WebThreeStubServerBase::eth_blockByHash(std::string const& _hash)
return toJson(client()->blockInfo(jsToFixed<32>(_hash)));
}
Json::Value WebThreeStubServerBase::eth_blockByNumber(int const& _number)
Json::Value WebThreeStubServerBase::eth_blockByNumber(int _number)
{
return toJson(client()->blockInfo(client()->hashFromNumber(_number)));
}
@ -279,6 +279,8 @@ static TransactionSkeleton toTransaction(Json::Value const& _json)
ret.from = jsToAddress(_json["from"].asString());
if (_json["to"].isString())
ret.to = jsToAddress(_json["to"].asString());
else
ret.creation = true;
if (!_json["value"].empty())
{
if (_json["value"].isString())
@ -342,7 +344,7 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json)
return ret;
}
Json::Value WebThreeStubServerBase::eth_changed(int const& _id)
Json::Value WebThreeStubServerBase::eth_changed(int _id)
{
auto entries = client()->checkWatch(_id);
if (entries.size())
@ -365,6 +367,26 @@ double WebThreeStubServerBase::eth_countAt(string const& _address)
return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault());
}
double WebThreeStubServerBase::eth_transactionCountByHash(std::string const& _hash)
{
return client()->transactionCount(jsToFixed<32>(_hash));
}
double WebThreeStubServerBase::eth_transactionCountByNumber(int _number)
{
return client()->transactionCount(client()->hashFromNumber(_number));
}
double WebThreeStubServerBase::eth_uncleCountByHash(std::string const& _hash)
{
return client()->transactionCount(jsToFixed<32>(_hash));
}
double WebThreeStubServerBase::eth_uncleCountByNumber(int _number)
{
return client()->transactionCount(client()->hashFromNumber(_number));
}
int WebThreeStubServerBase::eth_defaultBlock()
{
return client()->getDefault();
@ -381,7 +403,7 @@ std::string WebThreeStubServerBase::db_get(std::string const& _name, std::string
return toJS(dev::asBytes(ret));
}
Json::Value WebThreeStubServerBase::eth_filterLogs(int const& _id)
Json::Value WebThreeStubServerBase::eth_filterLogs(int _id)
{
return toJson(client()->logs(_id));
}
@ -563,13 +585,13 @@ bool WebThreeStubServerBase::eth_setCoinbase(std::string const& _address)
return true;
}
bool WebThreeStubServerBase::eth_setDefaultBlock(int const& _block)
bool WebThreeStubServerBase::eth_setDefaultBlock(int _block)
{
client()->setDefault(_block);
return true;
}
bool WebThreeStubServerBase::eth_setListening(bool const& _listening)
bool WebThreeStubServerBase::eth_setListening(bool _listening)
{
if (_listening)
network()->startNetwork();
@ -578,7 +600,7 @@ bool WebThreeStubServerBase::eth_setListening(bool const& _listening)
return true;
}
bool WebThreeStubServerBase::eth_setMining(bool const& _mining)
bool WebThreeStubServerBase::eth_setMining(bool _mining)
{
if (_mining)
client()->startMining();
@ -587,7 +609,7 @@ bool WebThreeStubServerBase::eth_setMining(bool const& _mining)
return true;
}
Json::Value WebThreeStubServerBase::shh_changed(int const& _id)
Json::Value WebThreeStubServerBase::shh_changed(int _id)
{
Json::Value ret(Json::arrayValue);
auto pub = m_shhWatches[_id];
@ -611,6 +633,29 @@ Json::Value WebThreeStubServerBase::shh_changed(int const& _id)
return ret;
}
Json::Value WebThreeStubServerBase::shh_getMessages(int _id)
{
Json::Value ret(Json::arrayValue);
auto pub = m_shhWatches[_id];
if (!pub || m_ids.count(pub))
for (h256 const& h: face()->watchMessages(_id))
{
auto e = face()->envelope(h);
shh::Message m;
if (pub)
{
cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here.";
m = e.open(face()->fullTopic(_id), m_ids[pub]);
}
else
m = e.open(face()->fullTopic(_id));
if (!m)
continue;
ret.append(toJson(h, e, m));
}
return ret;
}
int WebThreeStubServerBase::shh_newFilter(Json::Value const& _json)
{
auto w = toWatch(_json);
@ -619,7 +664,7 @@ int WebThreeStubServerBase::shh_newFilter(Json::Value const& _json)
return ret;
}
bool WebThreeStubServerBase::shh_uninstallFilter(int const& _id)
bool WebThreeStubServerBase::shh_uninstallFilter(int _id)
{
face()->uninstallWatch(_id);
return true;
@ -671,27 +716,27 @@ bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t)
return true;
}
Json::Value WebThreeStubServerBase::eth_transactionByHash(std::string const& _hash, int const& _i)
Json::Value WebThreeStubServerBase::eth_transactionByHash(std::string const& _hash, int _i)
{
return toJson(client()->transaction(jsToFixed<32>(_hash), _i));
}
Json::Value WebThreeStubServerBase::eth_transactionByNumber(int const& _number, int const& _i)
Json::Value WebThreeStubServerBase::eth_transactionByNumber(int _number, int _i)
{
return toJson(client()->transaction(client()->hashFromNumber(_number), _i));
}
Json::Value WebThreeStubServerBase::eth_uncleByHash(std::string const& _hash, int const& _i)
Json::Value WebThreeStubServerBase::eth_uncleByHash(std::string const& _hash, int _i)
{
return toJson(client()->uncle(jsToFixed<32>(_hash), _i));
}
Json::Value WebThreeStubServerBase::eth_uncleByNumber(int const& _number, int const& _i)
Json::Value WebThreeStubServerBase::eth_uncleByNumber(int _number, int _i)
{
return toJson(client()->uncle(client()->hashFromNumber(_number), _i));
}
bool WebThreeStubServerBase::eth_uninstallFilter(int const& _id)
bool WebThreeStubServerBase::eth_uninstallFilter(int _id)
{
client()->uninstallWatch(_id);
return true;

31
libweb3jsonrpc/WebThreeStubServerBase.h

@ -69,16 +69,20 @@ public:
virtual Json::Value eth_accounts();
virtual std::string eth_balanceAt(std::string const& _address);
virtual Json::Value eth_blockByHash(std::string const& _hash);
virtual Json::Value eth_blockByNumber(int const& _number);
virtual Json::Value eth_blockByNumber(int _number);
virtual std::string eth_call(Json::Value const& _json);
virtual Json::Value eth_changed(int const& _id);
virtual Json::Value eth_changed(int _id);
virtual std::string eth_codeAt(std::string const& _address);
virtual std::string eth_coinbase();
virtual Json::Value eth_compilers();
virtual double eth_countAt(std::string const& _address);
virtual double eth_transactionCountByHash(std::string const& _hash);
virtual double eth_transactionCountByNumber(int _number);
virtual double eth_uncleCountByHash(std::string const& _hash);
virtual double eth_uncleCountByNumber(int _number);
virtual int eth_defaultBlock();
virtual std::string eth_gasPrice();
virtual Json::Value eth_filterLogs(int const& _id);
virtual Json::Value eth_filterLogs(int _id);
virtual bool eth_flush();
virtual Json::Value eth_logs(Json::Value const& _json);
virtual bool eth_listening();
@ -88,20 +92,20 @@ public:
virtual int eth_number();
virtual int eth_peerCount();
virtual bool eth_setCoinbase(std::string const& _address);
virtual bool eth_setDefaultBlock(int const& _block);
virtual bool eth_setListening(bool const& _listening);
virtual bool eth_setDefaultBlock(int _block);
virtual bool eth_setListening(bool _listening);
virtual std::string eth_lll(std::string const& _s);
virtual std::string eth_serpent(std::string const& _s);
virtual bool eth_setMining(bool const& _mining);
virtual bool eth_setMining(bool _mining);
virtual std::string eth_solidity(std::string const& _code);
virtual std::string eth_stateAt(std::string const& _address, std::string const& _storage);
virtual Json::Value eth_storageAt(std::string const& _address);
virtual std::string eth_transact(Json::Value const& _json);
virtual Json::Value eth_transactionByHash(std::string const& _hash, int const& _i);
virtual Json::Value eth_transactionByNumber(int const& _number, int const& _i);
virtual Json::Value eth_uncleByHash(std::string const& _hash, int const& _i);
virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i);
virtual bool eth_uninstallFilter(int const& _id);
virtual Json::Value eth_transactionByHash(std::string const& _hash, int _i);
virtual Json::Value eth_transactionByNumber(int _number, int _i);
virtual Json::Value eth_uncleByHash(std::string const& _hash, int _i);
virtual Json::Value eth_uncleByNumber(int _number, int _i);
virtual bool eth_uninstallFilter(int _id);
virtual Json::Value eth_getWork();
virtual bool eth_submitWork(std::string const& _nonce);
@ -112,13 +116,14 @@ public:
virtual bool db_putString(std::string const& _name, std::string const& _key, std::string const& _value);
virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who);
virtual Json::Value shh_changed(int const& _id);
virtual Json::Value shh_changed(int _id);
virtual Json::Value shh_getMessages(int _id);
virtual bool shh_haveIdentity(std::string const& _id);
virtual int shh_newFilter(Json::Value const& _json);
virtual std::string shh_newGroup(std::string const& _id, std::string const& _who);
virtual std::string shh_newIdentity();
virtual bool shh_post(Json::Value const& _json);
virtual bool shh_uninstallFilter(int const& _id);
virtual bool shh_uninstallFilter(int _id);
void setAccounts(std::vector<dev::KeyPair> const& _accounts);
void setIdentities(std::vector<dev::KeyPair> const& _ids);

176
libweb3jsonrpc/abstractwebthreestubserver.h

@ -10,59 +10,64 @@
class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThreeStubServer>
{
public:
AbstractWebThreeStubServer(jsonrpc::AbstractServerConnector &conn) : jsonrpc::AbstractServer<AbstractWebThreeStubServer>(conn)
{
this->bindAndAddMethod(new jsonrpc::Procedure("web3_sha3", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::web3_sha3I);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_setCoinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_listeningI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setListeningI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_miningI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setMiningI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_gasPriceI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_accountsI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_peerCountI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_defaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_defaultBlockI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_setDefaultBlockI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_number", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_numberI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_balanceAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_stateAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_storageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_storageAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_countAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_codeAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_transactI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_callI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_flush", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_flushI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_blockByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_blockByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_blockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_blockByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_transactionByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_uncleByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_uncleByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_compilers", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_compilersI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_lll", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_lllI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_solidity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_solidityI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_serpent", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_serpentI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newFilterStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_filterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_filterLogsI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI);
this->bindAndAddMethod(new jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI);
this->bindAndAddMethod(new jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI);
this->bindAndAddMethod(new jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("db_getString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_postI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_newIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newIdentityI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_haveIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_haveIdentityI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_newGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newGroupI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_addToGroupI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_newFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI);
AbstractWebThreeStubServer(jsonrpc::AbstractServerConnector &conn, jsonrpc::serverVersion_t type = jsonrpc::JSONRPC_SERVER_V2) : jsonrpc::AbstractServer<AbstractWebThreeStubServer>(conn, type)
{
this->bindAndAddMethod(jsonrpc::Procedure("web3_sha3", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::web3_sha3I);
this->bindAndAddMethod(jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_setCoinbaseI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_listeningI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setListeningI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_miningI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setMiningI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_gasPriceI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_accountsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_peerCountI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_defaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_defaultBlockI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_setDefaultBlockI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_number", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_numberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_balanceAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_stateAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_storageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_storageAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_countAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_transactionCountByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionCountByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_uncleCountByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleCountByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_codeAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_transactI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_callI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_flush", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_flushI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_blockByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_blockByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_blockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_blockByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_compilers", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_compilersI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_lll", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_lllI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_solidity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_solidityI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_serpent", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_serpentI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newFilterStringI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_filterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_filterLogsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI);
this->bindAndAddMethod(jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI);
this->bindAndAddMethod(jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI);
this->bindAndAddMethod(jsonrpc::Procedure("db_getString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getStringI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_postI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_newIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newIdentityI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_haveIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_haveIdentityI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_newGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newGroupI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_addToGroupI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_newFilterI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_getMessagesI);
}
inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response)
@ -71,6 +76,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_coinbaseI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_coinbase();
}
inline virtual void eth_setCoinbaseI(const Json::Value &request, Json::Value &response)
@ -79,6 +85,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_listeningI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_listening();
}
inline virtual void eth_setListeningI(const Json::Value &request, Json::Value &response)
@ -87,6 +94,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_miningI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_mining();
}
inline virtual void eth_setMiningI(const Json::Value &request, Json::Value &response)
@ -95,18 +103,22 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_gasPriceI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_gasPrice();
}
inline virtual void eth_accountsI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_accounts();
}
inline virtual void eth_peerCountI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_peerCount();
}
inline virtual void eth_defaultBlockI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_defaultBlock();
}
inline virtual void eth_setDefaultBlockI(const Json::Value &request, Json::Value &response)
@ -115,6 +127,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_numberI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_number();
}
inline virtual void eth_balanceAtI(const Json::Value &request, Json::Value &response)
@ -133,6 +146,22 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
response = this->eth_countAt(request[0u].asString());
}
inline virtual void eth_transactionCountByHashI(const Json::Value &request, Json::Value &response)
{
response = this->eth_transactionCountByHash(request[0u].asString());
}
inline virtual void eth_transactionCountByNumberI(const Json::Value &request, Json::Value &response)
{
response = this->eth_transactionCountByNumber(request[0u].asInt());
}
inline virtual void eth_uncleCountByHashI(const Json::Value &request, Json::Value &response)
{
response = this->eth_uncleCountByHash(request[0u].asString());
}
inline virtual void eth_uncleCountByNumberI(const Json::Value &request, Json::Value &response)
{
response = this->eth_uncleCountByNumber(request[0u].asInt());
}
inline virtual void eth_codeAtI(const Json::Value &request, Json::Value &response)
{
response = this->eth_codeAt(request[0u].asString());
@ -147,6 +176,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_flushI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_flush();
}
inline virtual void eth_blockByHashI(const Json::Value &request, Json::Value &response)
@ -175,6 +205,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_compilersI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_compilers();
}
inline virtual void eth_lllI(const Json::Value &request, Json::Value &response)
@ -215,6 +246,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_getWorkI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_getWork();
}
inline virtual void eth_submitWorkI(const Json::Value &request, Json::Value &response)
@ -243,6 +275,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void shh_newIdentityI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->shh_newIdentity();
}
inline virtual void shh_haveIdentityI(const Json::Value &request, Json::Value &response)
@ -269,42 +302,50 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
response = this->shh_changed(request[0u].asInt());
}
inline virtual void shh_getMessagesI(const Json::Value &request, Json::Value &response)
{
response = this->shh_getMessages(request[0u].asInt());
}
virtual std::string web3_sha3(const std::string& param1) = 0;
virtual std::string eth_coinbase() = 0;
virtual bool eth_setCoinbase(const std::string& param1) = 0;
virtual bool eth_listening() = 0;
virtual bool eth_setListening(const bool& param1) = 0;
virtual bool eth_setListening(bool param1) = 0;
virtual bool eth_mining() = 0;
virtual bool eth_setMining(const bool& param1) = 0;
virtual bool eth_setMining(bool param1) = 0;
virtual std::string eth_gasPrice() = 0;
virtual Json::Value eth_accounts() = 0;
virtual int eth_peerCount() = 0;
virtual int eth_defaultBlock() = 0;
virtual bool eth_setDefaultBlock(const int& param1) = 0;
virtual bool eth_setDefaultBlock(int param1) = 0;
virtual int eth_number() = 0;
virtual std::string eth_balanceAt(const std::string& param1) = 0;
virtual std::string eth_stateAt(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value eth_storageAt(const std::string& param1) = 0;
virtual double eth_countAt(const std::string& param1) = 0;
virtual double eth_transactionCountByHash(const std::string& param1) = 0;
virtual double eth_transactionCountByNumber(int param1) = 0;
virtual double eth_uncleCountByHash(const std::string& param1) = 0;
virtual double eth_uncleCountByNumber(int param1) = 0;
virtual std::string eth_codeAt(const std::string& param1) = 0;
virtual std::string eth_transact(const Json::Value& param1) = 0;
virtual std::string eth_call(const Json::Value& param1) = 0;
virtual bool eth_flush() = 0;
virtual Json::Value eth_blockByHash(const std::string& param1) = 0;
virtual Json::Value eth_blockByNumber(const int& param1) = 0;
virtual Json::Value eth_transactionByHash(const std::string& param1, const int& param2) = 0;
virtual Json::Value eth_transactionByNumber(const int& param1, const int& param2) = 0;
virtual Json::Value eth_uncleByHash(const std::string& param1, const int& param2) = 0;
virtual Json::Value eth_uncleByNumber(const int& param1, const int& param2) = 0;
virtual Json::Value eth_blockByNumber(int param1) = 0;
virtual Json::Value eth_transactionByHash(const std::string& param1, int param2) = 0;
virtual Json::Value eth_transactionByNumber(int param1, int param2) = 0;
virtual Json::Value eth_uncleByHash(const std::string& param1, int param2) = 0;
virtual Json::Value eth_uncleByNumber(int param1, int param2) = 0;
virtual Json::Value eth_compilers() = 0;
virtual std::string eth_lll(const std::string& param1) = 0;
virtual std::string eth_solidity(const std::string& param1) = 0;
virtual std::string eth_serpent(const std::string& param1) = 0;
virtual int eth_newFilter(const Json::Value& param1) = 0;
virtual int eth_newFilterString(const std::string& param1) = 0;
virtual bool eth_uninstallFilter(const int& param1) = 0;
virtual Json::Value eth_changed(const int& param1) = 0;
virtual Json::Value eth_filterLogs(const int& param1) = 0;
virtual bool eth_uninstallFilter(int param1) = 0;
virtual Json::Value eth_changed(int param1) = 0;
virtual Json::Value eth_filterLogs(int param1) = 0;
virtual Json::Value eth_logs(const Json::Value& param1) = 0;
virtual Json::Value eth_getWork() = 0;
virtual bool eth_submitWork(const std::string& param1) = 0;
@ -318,8 +359,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual std::string shh_newGroup(const std::string& param1, const std::string& param2) = 0;
virtual std::string shh_addToGroup(const std::string& param1, const std::string& param2) = 0;
virtual int shh_newFilter(const Json::Value& param1) = 0;
virtual bool shh_uninstallFilter(const int& param1) = 0;
virtual Json::Value shh_changed(const int& param1) = 0;
virtual bool shh_uninstallFilter(int param1) = 0;
virtual Json::Value shh_changed(int param1) = 0;
virtual Json::Value shh_getMessages(int param1) = 0;
};
#endif //JSONRPC_CPP_ABSTRACTWEBTHREESTUBSERVER_H_
#endif //JSONRPC_CPP_STUB_ABSTRACTWEBTHREESTUBSERVER_H_

7
libweb3jsonrpc/spec.json

@ -18,6 +18,10 @@
{ "name": "eth_stateAt", "params": ["", ""], "order": [], "returns": ""},
{ "name": "eth_storageAt", "params": [""], "order": [], "returns": {}},
{ "name": "eth_countAt", "params": [""], "order": [], "returns" : 0.0},
{ "name": "eth_transactionCountByHash", "params": [""], "order": [], "returns" : 0.0},
{ "name": "eth_transactionCountByNumber", "params": [0], "order": [], "returns" : 0.0},
{ "name": "eth_uncleCountByHash", "params": [""], "order": [], "returns" : 0.0},
{ "name": "eth_uncleCountByNumber", "params": [0], "order": [], "returns" : 0.0},
{ "name": "eth_codeAt", "params": [""], "order": [], "returns": ""},
{ "name": "eth_transact", "params": [{}], "order": [], "returns": ""},
@ -59,6 +63,7 @@
{ "name": "shh_newFilter", "params": [{}], "order": [], "returns": 0},
{ "name": "shh_uninstallFilter", "params": [0], "order": [], "returns": true},
{ "name": "shh_changed", "params": [0], "order": [], "returns": []}
{ "name": "shh_changed", "params": [0], "order": [], "returns": []},
{ "name": "shh_getMessages", "params": [0], "order": [], "returns": []}
]

2
libwebthree/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE webthree)

2
libwhisper/CMakeLists.txt

@ -11,7 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
set(EXECUTABLE whisper)

4
lllc/CMakeLists.txt

@ -3,9 +3,9 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSONCPP_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE lllc)

7
mix/CMakeLists.txt

@ -10,8 +10,9 @@ endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(${JSONCPP_INCLUDE_DIRS})
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
find_package (Qt5WebEngine QUIET)
qt5_add_resources(UI_RESOURCES res.qrc)
@ -70,4 +71,4 @@ eth_install_executable(${EXECUTABLE}
#add qml asnd stdc files to project tree in Qt creator
file(GLOB_RECURSE QMLFILES "qml/*.*")
file(GLOB_RECURSE SOLFILES "stdc/*.*")
add_custom_target(dummy SOURCES ${QMLFILES} ${SOLFILES})
add_custom_target(mix_qml SOURCES ${QMLFILES} ${SOLFILES})

70
mix/ClientModel.cpp

@ -65,7 +65,7 @@ private:
ClientModel::ClientModel(AppContext* _context):
m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address())
m_context(_context), m_running(false), m_rpcConnector(new RpcConnector())
{
qRegisterMetaType<QBigInt*>("QBigInt*");
qRegisterMetaType<QIntType*>("QIntType*");
@ -136,9 +136,12 @@ void ClientModel::mine()
});
}
QString ClientModel::contractAddress() const
QVariantMap ClientModel::contractAddresses() const
{
return QString::fromStdString(dev::toJS(m_contractAddress));
QVariantMap res;
for (auto const& c: m_contractAddresses)
res.insert(c.first, QString::fromStdString(dev::toJS(c.second)));
return res;
}
void ClientModel::debugDeployment()
@ -155,8 +158,8 @@ void ClientModel::setupState(QVariantMap _state)
for (auto const& t: transactions)
{
QVariantMap transaction = t.toMap();
QString contractId = transaction.value("contractId").toString();
QString functionId = transaction.value("functionId").toString();
u256 gas = boost::get<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue());
u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
u256 gasPrice = (qvariant_cast<QEther*>(transaction.value("gasPrice")))->toU256Wei();
@ -164,7 +167,9 @@ void ClientModel::setupState(QVariantMap _state)
bool isStdContract = (transaction.value("stdContract").toBool());
if (isStdContract)
{
TransactionSettings transactionSettings(functionId, transaction.value("url").toString());
if (contractId.isEmpty()) //TODO: This is to support old project files, remove later
contractId = functionId;
TransactionSettings transactionSettings(contractId, transaction.value("url").toString());
transactionSettings.gasPrice = 10000000000000;
transactionSettings.gas = 125000;
transactionSettings.value = 0;
@ -172,8 +177,10 @@ void ClientModel::setupState(QVariantMap _state)
}
else
{
if (contractId.isEmpty() && m_context->codeModel()->hasContract()) //TODO: This is to support old project files, remove later
contractId = m_context->codeModel()->contracts().keys()[0];
QVariantList qParams = transaction.value("qType").toList();
TransactionSettings transactionSettings(functionId, value, gas, gasPrice);
TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice);
for (QVariant const& variant: qParams)
{
@ -181,7 +188,7 @@ void ClientModel::setupState(QVariantMap _state)
transactionSettings.parameterValues.push_back(param);
}
if (transaction.value("executeConstructor").toBool())
if (contractId == functionId || functionId == "Constructor")
transactionSettings.functionId.clear();
transactionSequence.push_back(transactionSettings);
@ -194,8 +201,6 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
{
if (m_running)
BOOST_THROW_EXCEPTION(ExecutionStateException());
CompilationResult* compilerRes = m_context->codeModel()->code();
std::shared_ptr<QContractDefinition> contractDef = compilerRes->sharedContract();
m_running = true;
emit runStarted();
@ -206,25 +211,26 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
{
try
{
bytes contractCode = compilerRes->bytes();
m_client->resetState(_balance);
onStateReset();
for (TransactionSettings const& transaction: _sequence)
{
ContractCallDataEncoder encoder;
QFunctionDefinition const* f = nullptr;
if (!transaction.stdContractUrl.isEmpty())
{
//std contract
dev::bytes const& stdContractCode = m_context->codeModel()->getStdContractCode(transaction.functionId, transaction.stdContractUrl);
dev::bytes const& stdContractCode = m_context->codeModel()->getStdContractCode(transaction.contractId, transaction.stdContractUrl);
Address address = deployContract(stdContractCode, transaction);
m_stdContractAddresses[transaction.functionId] = address;
m_stdContractNames[address] = transaction.functionId;
m_stdContractAddresses[transaction.contractId] = address;
m_stdContractNames[address] = transaction.contractId;
}
else
{
//encode data
f = nullptr;
CompiledContract const& compilerRes = m_context->codeModel()->contract(transaction.contractId);
QFunctionDefinition const* f = nullptr;
bytes contractCode = compilerRes.bytes();
std::shared_ptr<QContractDefinition> contractDef = compilerRes.sharedContract();
if (transaction.functionId.isEmpty())
f = contractDef->constructor();
else
@ -240,24 +246,31 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
encoder.encode(f);
for (int p = 0; p < transaction.parameterValues.size(); p++)
{
if (f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type())
BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(f->parametersList().at(p)->type().toStdString()));
if (f->parametersList().size() <= p || f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type())
BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(transaction.functionId.toStdString()));
encoder.push(transaction.parameterValues.at(p)->encodeValue());
}
if (transaction.functionId.isEmpty())
if (transaction.functionId.isEmpty() || transaction.functionId == transaction.contractId)
{
bytes param = encoder.encodedData();
contractCode.insert(contractCode.end(), param.begin(), param.end());
Address newAddress = deployContract(contractCode, transaction);
if (newAddress != m_contractAddress)
auto contractAddressIter = m_contractAddresses.find(transaction.contractId);
if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second)
{
m_contractAddress = newAddress;
contractAddressChanged();
m_contractAddresses[transaction.contractId] = newAddress;
m_contractNames[newAddress] = transaction.contractId;
contractAddressesChanged();
}
}
else
callContract(m_contractAddress, encoder.encodedData(), transaction);
{
auto contractAddressIter = m_contractAddresses.find(transaction.contractId);
if (contractAddressIter == m_contractAddresses.end())
BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Contract not deployed: " + transaction.contractId.toStdString()));
callContract(contractAddressIter->second, encoder.encodedData(), transaction);
}
}
onNewTransaction();
}
@ -338,7 +351,8 @@ void ClientModel::callContract(Address const& _contract, bytes const& _data, Tra
void ClientModel::onStateReset()
{
m_contractAddress = dev::Address();
m_contractAddresses.clear();
m_contractNames.clear();
m_stdContractAddresses.clear();
m_stdContractNames.clear();
emit stateCleared();
@ -389,14 +403,16 @@ void ClientModel::onNewTransaction()
if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress));
if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress))
Address contractAddress = tr.address != 0 ? tr.address : tr.contractAddress;
auto contractAddressIter = m_contractNames.find(contractAddress);
if (contractAddressIter != m_contractNames.end())
{
auto compilerRes = m_context->codeModel()->code();
QContractDefinition* def = compilerRes->contract();
CompiledContract const& compilerRes = m_context->codeModel()->contract(contractAddressIter->second);
const QContractDefinition* def = compilerRes.contract();
contract = def->name();
if (abi)
{
QFunctionDefinition* funcDef = def->getFunction(functionHash);
QFunctionDefinition const* funcDef = def->getFunction(functionHash);
if (funcDef)
{
function = funcDef->name();

21
mix/ClientModel.h

@ -46,13 +46,13 @@ class QVariableDefinition;
struct TransactionSettings
{
TransactionSettings() {}
TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
TransactionSettings(u256 _value, u256 _gas, u256 _gasPrice):
value(_value), gas(_gas), gasPrice(_gasPrice) {}
TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl):
functionId(_stdContractName), stdContractUrl(_stdContractUrl) {}
contractId(_stdContractName), stdContractUrl(_stdContractUrl) {}
/// Contract name
QString contractId;
/// Contract function name
QString functionId;
/// Transaction value
@ -121,8 +121,8 @@ public:
Q_PROPERTY(bool running MEMBER m_running NOTIFY runStateChanged)
/// @returns true if currently mining
Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged)
/// @returns address of the last executed contract
Q_PROPERTY(QString contractAddress READ contractAddress NOTIFY contractAddressChanged)
/// @returns deployed contracts addresses
Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged)
/// ethereum.js RPC request entry point
/// @param _message RPC request in Json format
/// @returns RPC response in Json format
@ -161,7 +161,7 @@ signals:
/// @param _message Error message
void runFailed(QString const& _message);
/// Contract address changed
void contractAddressChanged();
void contractAddressesChanged();
/// Execution state changed
void newBlock();
/// Execution state changed
@ -177,7 +177,7 @@ signals:
void stateCleared();
private:
QString contractAddress() const;
QVariantMap contractAddresses() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
@ -191,7 +191,8 @@ private:
std::unique_ptr<MixClient> m_client;
std::unique_ptr<RpcConnector> m_rpcConnector;
std::unique_ptr<Web3Server> m_web3Server;
Address m_contractAddress;
std::map<QString, Address> m_contractAddresses;
std::map<Address, QString> m_contractNames;
std::map<QString, Address> m_stdContractAddresses;
std::map<Address, QString> m_stdContractNames;
};

2
mix/CodeHighlighter.cpp

@ -119,7 +119,7 @@ void CodeHighlighter::processComments(std::string const& _source)
//add single line comment
int start = i;
i += 2;
while (_source[i] != '\n' && i < size)
while (i < size && _source[i] != '\n')
++i;
m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start));
}

201
mix/CodeModel.cpp

@ -21,6 +21,7 @@
*/
#include <sstream>
#include <memory>
#include <QDebug>
#include <QApplication>
#include <QtQml>
@ -38,51 +39,31 @@
using namespace dev::mix;
void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content)
const std::set<std::string> c_predefinedContracts =
{ "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" };
void BackgroundWorker::queueCodeChange(int _jobId)
{
m_model->runCompilationJob(_jobId, _content);
m_model->runCompilationJob(_jobId);
}
CompilationResult::CompilationResult():
QObject(nullptr),
m_successful(false),
m_codeHash(qHash(QString())),
m_contract(new QContractDefinition()),
m_contractInterface("[]"),
m_codeHighlighter(new CodeHighlighter())
{}
CompilationResult::CompilationResult(const dev::solidity::CompilerStack& _compiler):
CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler, QString const& _contractName, QString const& _source):
QObject(nullptr),
m_successful(true),
m_codeHash(qHash(QString()))
m_sourceHash(qHash(_source))
{
if (!_compiler.getContractNames().empty())
{
auto const& contractDefinition = _compiler.getContractDefinition(std::string());
auto const& contractDefinition = _compiler.getContractDefinition(_contractName.toStdString());
m_contract.reset(new QContractDefinition(&contractDefinition));
m_bytes = _compiler.getBytecode();
QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership);
m_bytes = _compiler.getBytecode(_contractName.toStdString());
dev::solidity::InterfaceHandler interfaceHandler;
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
if (m_contractInterface.isEmpty())
m_contractInterface = "[]";
}
else
m_contract.reset(new QContractDefinition());
if (contractDefinition.getLocation().sourceName.get())
m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName);
}
CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage):
QObject(nullptr),
m_successful(false),
m_codeHash(qHash(QString())),
m_contract(_prev.m_contract),
m_compilerMessage(_compilerMessage),
m_bytes(_prev.m_bytes),
m_contractInterface(_prev.m_contractInterface),
m_codeHighlighter(_prev.m_codeHighlighter)
{}
QString CompilationResult::codeHex() const
QString CompiledContract::codeHex() const
{
return QString::fromStdString(toJS(m_bytes));
}
@ -90,27 +71,26 @@ QString CompilationResult::codeHex() const
CodeModel::CodeModel(QObject* _parent):
QObject(_parent),
m_compiling(false),
m_result(new CompilationResult()),
m_codeHighlighterSettings(new CodeHighlighterSettings()),
m_backgroundWorker(this),
m_backgroundJobId(0)
{
m_backgroundThread.start();
m_backgroundWorker.moveToThread(&m_backgroundThread);
connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection);
connect(this, &CodeModel::compilationCompleteInternal, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection);
qRegisterMetaType<CompilationResult*>("CompilationResult*");
qRegisterMetaType<CompiledContract*>("CompiledContract*");
qRegisterMetaType<QContractDefinition*>("QContractDefinition*");
qRegisterMetaType<QFunctionDefinition*>("QFunctionDefinition*");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
qmlRegisterType<QFunctionDefinition>("org.ethereum.qml", 1, 0, "QFunctionDefinition");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml", 1, 0, "QVariableDeclaration");
m_backgroundThread.start();
}
CodeModel::~CodeModel()
{
stop();
disconnect(this);
releaseContracts();
}
void CodeModel::stop()
@ -120,80 +100,133 @@ void CodeModel::stop()
m_backgroundThread.wait();
}
void CodeModel::registerCodeChange(QString const& _code)
void CodeModel::reset(QVariantMap const& _documents)
{
///@todo: cancel bg job
Guard l(x_contractMap);
releaseContracts();
Guard pl(x_pendingContracts);
m_pendingContracts.clear();
for (QVariantMap::const_iterator d = _documents.cbegin(); d != _documents.cend(); ++d)
m_pendingContracts[d.key()] = d.value().toString();
// launch the background thread
uint hash = qHash(_code);
if (m_result->m_codeHash == hash)
m_compiling = true;
emit stateChanged();
emit scheduleCompilationJob(++m_backgroundJobId);
}
void CodeModel::registerCodeChange(QString const& _documentId, QString const& _code)
{
{
Guard l(x_contractMap);
CompiledContract* contract = m_contractMap.value(_documentId);
if (contract != nullptr && contract->m_sourceHash == qHash(_code))
return;
m_backgroundJobId++;
Guard pl(x_pendingContracts);
m_pendingContracts[_documentId] = _code;
}
// launch the background thread
m_compiling = true;
emit stateChanged();
emit scheduleCompilationJob(m_backgroundJobId, _code);
emit scheduleCompilationJob(++m_backgroundJobId);
}
void CodeModel::runCompilationJob(int _jobId, QString const& _code)
QVariantMap CodeModel::contracts() const
{
if (_jobId != m_backgroundJobId)
return; //obsolete job
QVariantMap result;
Guard l(x_contractMap);
for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); ++c)
result.insert(c.key(), QVariant::fromValue(c.value()));
return result;
}
solidity::CompilerStack cs(true);
std::unique_ptr<CompilationResult> result;
CompiledContract* CodeModel::contractByDocumentId(QString _documentId) const
{
Guard l(x_contractMap);
for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); ++c)
if (c.value()->m_documentId == _documentId)
return c.value();
return nullptr;
}
std::string source = _code.toStdString();
// run syntax highlighting first
// @todo combine this with compilation step
auto codeHighlighter = std::make_shared<CodeHighlighter>();
codeHighlighter->processSource(source);
CompiledContract const& CodeModel::contract(QString _name) const
{
Guard l(x_contractMap);
CompiledContract* res = m_contractMap.value(_name);
if (res == nullptr)
BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Contract not found: " + _name.toStdString()));
return *res;
}
cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})");
void CodeModel::releaseContracts()
{
for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); ++c)
c.value()->deleteLater();
m_contractMap.clear();
}
// run compilation
void CodeModel::runCompilationJob(int _jobId)
{
if (_jobId != m_backgroundJobId)
return; //obsolete job
ContractMap result;
solidity::CompilerStack cs(true);
try
{
cs.addSource("", source);
cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})");
{
Guard l(x_pendingContracts);
for (auto const& c: m_pendingContracts)
cs.addSource(c.first.toStdString(), c.second.toStdString());
}
cs.compile(false);
codeHighlighter->processAST(cs.getAST());
result.reset(new CompilationResult(cs));
qDebug() << QString(QApplication::tr("compilation succeeded"));
{
Guard pl(x_pendingContracts);
Guard l(x_contractMap);
for (std::string n: cs.getContractNames())
{
if (c_predefinedContracts.count(n) != 0)
continue;
QString name = QString::fromStdString(n);
auto sourceIter = m_pendingContracts.find(name);
QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString();
CompiledContract* contract = new CompiledContract(cs, name, source);
QQmlEngine::setObjectOwnership(contract, QQmlEngine::CppOwnership);
result[name] = contract;
CompiledContract* prevContract = m_contractMap.value(name);
if (prevContract != nullptr && prevContract->contractInterface() != result[name]->contractInterface())
emit contractInterfaceChanged(name);
}
releaseContracts();
m_contractMap.swap(result);
emit codeChanged();
emit compilationComplete();
}
}
catch (dev::Exception const& _exception)
{
std::ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs);
result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str())));
codeHighlighter->processError(_exception);
qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage());
solidity::Location const* location = boost::get_error_info<solidity::errinfo_sourceLocation>(_exception);
QString message = QString::fromStdString(error.str());
CompiledContract* contract = nullptr;
if (location && location->sourceName.get() && (contract = contractByDocumentId(QString::fromStdString(*location->sourceName))))
message = message.replace(QString::fromStdString(*location->sourceName), contract->contract()->name()); //substitute the location to match our contract names
compilationError(message);
}
result->m_codeHighlighter = codeHighlighter;
result->m_codeHash = qHash(_code);
emit compilationCompleteInternal(result.release());
}
void CodeModel::onCompilationComplete(CompilationResult* _newResult)
{
m_compiling = false;
bool contractChanged = m_result->contractInterface() != _newResult->contractInterface();
m_result.reset(_newResult);
emit compilationComplete();
emit stateChanged();
if (m_result->successful())
{
emit codeChanged();
if (contractChanged)
emit contractInterfaceChanged();
}
}
bool CodeModel::hasContract() const
{
return m_result->successful();
}
void CodeModel::updateFormatting(QTextDocument* _document)
{
m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings);
Guard l(x_contractMap);
return m_contractMap.size() != 0;
}
dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, const QString& _url)

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

Loading…
Cancel
Save