Browse Source

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

cl-refactor
CJentzsch 10 years ago
parent
commit
96b0c46035
  1. 7
      CMakeLists.txt
  2. 4
      CodingStandards.txt
  3. 3
      alethzero/CMakeLists.txt
  4. 4
      alethzero/MainWin.cpp
  5. 30
      alethzero/OurWebThreeStubServer.cpp
  6. 16
      alethzero/OurWebThreeStubServer.h
  7. 2
      evmjit/libevmjit/Utils.h
  8. 9
      libdevcore/CommonData.h
  9. 2
      libethcore/BlockInfo.cpp
  10. 2
      libethcore/CommonEth.cpp
  11. 28
      libethcore/ProofOfWork.h
  12. 135
      libethereum/Client.cpp
  13. 57
      libethereum/Client.h
  14. 5
      libethereum/Interface.h
  15. 2
      libethereum/LogFilter.cpp
  16. 8
      libethereum/LogFilter.h
  17. 12
      libethereum/Miner.cpp
  18. 28
      libethereum/Miner.h
  19. 18
      libethereum/State.cpp
  20. 4
      libethereum/State.h
  21. 31
      libjsqrc/ethereumjs/dist/ethereum.js
  22. 4
      libjsqrc/ethereumjs/dist/ethereum.js.map
  23. 2
      libjsqrc/ethereumjs/dist/ethereum.min.js
  24. 31
      libjsqrc/ethereumjs/lib/providermanager.js
  25. 1
      libjsqrc/js.qrc
  26. 35
      libnatspec/CMakeLists.txt
  27. 59
      libnatspec/NatspecExpressionEvaluator.cpp
  28. 49
      libnatspec/NatspecExpressionEvaluator.h
  29. 69
      libnatspec/natspec.js
  30. 5
      libnatspec/natspec.qrc
  31. 2
      libsolidity/AST.cpp
  32. 19
      libsolidity/AST.h
  33. 47
      libsolidity/ExpressionCompiler.cpp
  34. 12
      libsolidity/Parser.cpp
  35. 6
      libsolidity/Token.h
  36. 57
      libsolidity/Types.cpp
  37. 3
      libsolidity/Types.h
  38. 12
      libweb3jsonrpc/WebThreeStubServer.h
  39. 20
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  40. 3
      libweb3jsonrpc/WebThreeStubServerBase.h
  41. 12
      libweb3jsonrpc/abstractwebthreestubserver.h
  42. 4
      libweb3jsonrpc/spec.json
  43. 2
      mix/AppContext.cpp
  44. 45
      mix/AssemblyDebuggerControl.cpp
  45. 48
      mix/AssemblyDebuggerControl.h
  46. 2
      mix/CMakeLists.txt
  47. 13
      mix/ClientModel.cpp
  48. 10
      mix/ClientModel.h
  49. 8
      mix/CodeEditorExtensionManager.cpp
  50. 7
      mix/ContractCallDataEncoder.cpp
  51. 118
      mix/MixClient.cpp
  52. 9
      mix/MixClient.h
  53. 48
      mix/StateListView.cpp
  54. 45
      mix/StateListView.h
  55. 37
      mix/qml/DebugInfoList.qml
  56. 304
      mix/qml/Debugger.qml
  57. 243
      mix/qml/FilesSection.qml
  58. 71
      mix/qml/MainContent.qml
  59. 241
      mix/qml/ProjectList.qml
  60. 1
      mix/qml/ProjectModel.qml
  61. 58
      mix/qml/StateList.qml
  62. 10
      mix/qml/StateListModel.qml
  63. 29
      mix/qml/Style.qml
  64. 70
      mix/qml/TransactionLog.qml
  65. 3
      mix/qml/WebPreview.qml
  66. BIN
      mix/qml/fonts/SourceSansPro-Black.ttf
  67. BIN
      mix/qml/fonts/SourceSansPro-BlackIt.ttf
  68. BIN
      mix/qml/fonts/SourceSansPro-Bold.ttf
  69. BIN
      mix/qml/fonts/SourceSansPro-BoldIt.ttf
  70. BIN
      mix/qml/fonts/SourceSansPro-ExtraLight.ttf
  71. BIN
      mix/qml/fonts/SourceSansPro-ExtraLightIt.ttf
  72. BIN
      mix/qml/fonts/SourceSansPro-It.ttf
  73. BIN
      mix/qml/fonts/SourceSansPro-Light.ttf
  74. BIN
      mix/qml/fonts/SourceSansPro-LightIt.ttf
  75. BIN
      mix/qml/fonts/SourceSansPro-Regular.ttf
  76. BIN
      mix/qml/fonts/SourceSansPro-Semibold.ttf
  77. BIN
      mix/qml/fonts/SourceSansPro-SemiboldIt.ttf
  78. BIN
      mix/qml/fonts/SourceSerifPro-Bold.ttf
  79. BIN
      mix/qml/fonts/SourceSerifPro-Regular.ttf
  80. BIN
      mix/qml/fonts/SourceSerifPro-Semibold.ttf
  81. BIN
      mix/qml/img/closedtriangleindicator_filesproject.png
  82. BIN
      mix/qml/img/opentriangleindicator_filesproject.png
  83. BIN
      mix/qml/img/projecticon.png
  84. 7
      mix/qml/js/Debugger.js
  85. 12
      mix/qml/js/ProjectModel.js
  86. 36
      mix/qml/main.qml
  87. 1
      mix/qml/qmldir
  88. 21
      mix/res.qrc
  89. 13
      pysol/MANIFEST.in
  90. 0
      pysol/README.md
  91. 115
      pysol/pysolidity.cpp
  92. 41
      pysol/setup.py
  93. 2
      sc/CMakeLists.txt
  94. 1
      test/CMakeLists.txt
  95. 18
      test/SolidityEndToEndTest.cpp
  96. 70
      test/SolidityExpressionCompiler.cpp
  97. 28
      test/SolidityNameAndTypeResolution.cpp
  98. 32
      test/SolidityParser.cpp
  99. 9
      test/SolidityScanner.cpp
  100. 112
      test/natspec.cpp

7
CMakeLists.txt

@ -131,11 +131,15 @@ endif()
add_subdirectory(libdevcore)
add_subdirectory(libevmcore)
add_subdirectory(liblll)
add_subdirectory(libserpent)
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
add_subdirectory(libserpent)
endif ()
add_subdirectory(libsolidity)
add_subdirectory(lllc)
add_subdirectory(solc)
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
add_subdirectory(sc)
endif()
if (JSONRPC)
add_subdirectory(libweb3jsonrpc)
@ -164,6 +168,7 @@ endif ()
if (NOT HEADLESS)
add_subdirectory(libnatspec)
add_subdirectory(libjsqrc)
add_subdirectory(libqwebthree)
add_subdirectory(alethzero)

4
CodingStandards.txt

@ -93,7 +93,7 @@ b. Only one per line.
c. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)).
d. Favour declarations close to use; don't habitually declare at top of scope ala C.
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.
f. If a func tion 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".
@ -128,7 +128,7 @@ d. Use override, final and const judiciously.
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).
f. For a method 'foo'
f. For a property 'foo'
- Member: m_foo;
- Getter: foo() [ also: for booleans, isFoo() ];
- Setter: setFoo();

3
alethzero/CMakeLists.txt

@ -40,13 +40,16 @@ target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} secp256k1)
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
target_link_libraries(${EXECUTABLE} serpent)
endif()
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} solidity)
target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} natspec)
# eth_install_executable is defined in cmake/EthExecutableHelper.cmake
eth_install_executable(${EXECUTABLE})

4
alethzero/MainWin.cpp

@ -30,8 +30,10 @@
#include <QtCore/QtCore>
#include <boost/algorithm/string.hpp>
#include <test/JsonSpiritHeaders.h>
#ifndef _MSC_VER
#include <libserpent/funcs.h>
#include <libserpent/util.h>
#endif
#include <libdevcrypto/FileSystem.h>
#include <libethcore/CommonJS.h>
#include <liblll/Compiler.h>
@ -1719,6 +1721,7 @@ void Main::on_data_textChanged()
solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>";
}
}
#ifndef _MSC_VER
else if (sourceIsSerpent(src))
{
try
@ -1732,6 +1735,7 @@ void Main::on_data_textChanged()
errors.push_back("Serpent " + err);
}
}
#endif
else
{
m_data = compileLLL(src, m_enableOptimizer, &errors);

30
alethzero/OurWebThreeStubServer.cpp

@ -24,6 +24,7 @@
#include <QMessageBox>
#include <QAbstractButton>
#include <libwebthree/WebThree.h>
#include <libnatspec/NatspecExpressionEvaluator.h>
#include "MainWin.h"
@ -84,36 +85,9 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
return showAuthenticationPopup("Unverified Pending Transaction",
"An undocumented transaction is about to be executed.");
QNatspecExpressionEvaluator evaluator(this, m_main);
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);
}
QNatspecExpressionEvaluator::QNatspecExpressionEvaluator(OurWebThreeStubServer* _server, Main* _main)
: m_server(_server), m_main(_main)
{}
QNatspecExpressionEvaluator::~QNatspecExpressionEvaluator()
{}
QString QNatspecExpressionEvaluator::evalExpression(QString const& _expression) const
{
// load natspec.js only when we need it for natspec evaluation
m_main->evalRaw(contentsOfQResource(":/js/natspec.js"));
QVariant result = m_main->evalRaw("evaluateExpression('" + _expression + "')");
if (result.type() == QVariant::Invalid)
{
cerr << "Could not evaluate natspec expression: \"" << _expression.toStdString() << "\"" << endl;
// return the expression unevaluated
return _expression;
}
return result.toString();
}

16
alethzero/OurWebThreeStubServer.h

@ -47,19 +47,3 @@ private:
dev::WebThreeDirect* m_web3;
Main* m_main;
};
class QNatspecExpressionEvaluator: public QObject
{
Q_OBJECT
public:
QNatspecExpressionEvaluator(OurWebThreeStubServer* _server, Main* _main);
virtual ~QNatspecExpressionEvaluator();
QString evalExpression(QString const& _expression) const;
private:
OurWebThreeStubServer* m_server;
Main* m_main;
};

2
evmjit/libevmjit/Utils.h

@ -1,5 +1,7 @@
#pragma once
#include <iostream>
#include "Common.h"
namespace dev

9
libdevcore/CommonData.h

@ -246,4 +246,13 @@ inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b)
/// Make normal string from fixed-length string.
std::string toString(string32 const& _s);
template<class T, class U>
std::vector<T> keysOf(std::map<T, U> const& _m)
{
std::vector<T> ret;
for (auto const& i: _m)
ret.push_back(i.first);
return ret;
}
}

2
libethcore/BlockInfo.cpp

@ -208,7 +208,7 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
if (parentHash != _parent.hash)
BOOST_THROW_EXCEPTION(InvalidParentHash());
if (timestamp < _parent.timestamp)
if (timestamp <= _parent.timestamp)
BOOST_THROW_EXCEPTION(InvalidTimestamp());
if (number != _parent.number + 1)

2
libethcore/CommonEth.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 52;
const unsigned c_protocolVersion = 53;
const unsigned c_databaseVersion = 5;
static const vector<pair<u256, string>> g_units =

28
libethcore/ProofOfWork.h

@ -51,7 +51,7 @@ class ProofOfWorkEngine: public Evaluator
public:
static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)Evaluator::eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; }
inline MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
inline std::pair<MineInfo, h256> mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
protected:
h256 m_last;
@ -79,14 +79,14 @@ using SHA3ProofOfWork = ProofOfWorkEngine<SHA3Evaluator>;
using ProofOfWork = SHA3ProofOfWork;
template <class Evaluator>
MineInfo ProofOfWorkEngine<Evaluator>::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
std::pair<MineInfo, h256> ProofOfWorkEngine<Evaluator>::mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
{
MineInfo ret;
std::pair<MineInfo, h256> ret;
static std::mt19937_64 s_eng((time(0) + (unsigned)m_last));
u256 s = (m_last = h256::random(s_eng));
bigint d = (bigint(1) << 256) / _difficulty;
ret.requirement = log2((double)d);
ret.first.requirement = log2((double)d);
// 2^ 0 32 64 128 256
// [--------*-------------------------]
@ -95,20 +95,26 @@ MineInfo ProofOfWorkEngine<Evaluator>::mine(h256& o_solution, h256 const& _root,
auto startTime = std::chrono::steady_clock::now();
if (!_turbo)
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, ret.hashes++)
double best = 1e99; // high enough to be effectively infinity :)
h256 solution;
unsigned h = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++)
{
o_solution = (h256)s;
auto e = (bigint)(u256)Evaluator::eval(_root, o_solution);
ret.best = std::min<double>(ret.best, log2((double)e));
solution = (h256)s;
auto e = (bigint)(u256)Evaluator::eval(_root, solution);
best = std::min<double>(best, log2((double)e));
if (e <= d)
{
ret.completed = true;
ret.first.completed = true;
break;
}
}
ret.first.hashes = h;
ret.first.best = best;
ret.second = solution;
if (ret.completed)
assert(verify(_root, o_solution, _difficulty));
if (ret.first.completed)
assert(verify(_root, solution, _difficulty));
return ret;
}

135
libethereum/Client.cpp

@ -126,7 +126,7 @@ void Client::killChain()
m_tq.clear();
m_bq.clear();
m_miners.clear();
m_localMiners.clear();
m_preMine = State();
m_postMine = State();
@ -167,8 +167,8 @@ void Client::clearPending()
}
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
@ -223,13 +223,17 @@ void Client::uninstallWatch(unsigned _i)
auto fit = m_filters.find(id);
if (fit != m_filters.end())
if (!--fit->second.refCount)
{
cwatch << "*X*" << fit->first << ":" << fit->second.filter;
m_filters.erase(fit);
}
}
void Client::noteChanged(h256Set const& _filters)
{
Guard l(m_filterLock);
cnote << "noteChanged(" << _filters << ")";
if (_filters.size())
cnote << "noteChanged(" << _filters << ")";
// accrue all changes left in each filter into the watches.
for (auto& i: m_watches)
if (_filters.count(i.second.id))
@ -250,8 +254,11 @@ LocalisedLogEntries Client::peekWatch(unsigned _watchId) const
Guard l(m_filterLock);
try {
return m_watches.at(_watchId).changes;
auto& w = m_watches.at(_watchId);
w.lastPoll = chrono::system_clock::now();
return w.changes;
} catch (...) {}
return LocalisedLogEntries();
}
@ -261,7 +268,9 @@ LocalisedLogEntries Client::checkWatch(unsigned _watchId)
LocalisedLogEntries ret;
try {
std::swap(ret, m_watches.at(_watchId).changes);
auto& w = m_watches.at(_watchId);
std::swap(ret, w.changes);
w.lastPoll = chrono::system_clock::now();
} catch (...) {}
return ret;
@ -311,8 +320,8 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
void Client::setForceMining(bool _enable)
{
m_forceMining = _enable;
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
@ -321,19 +330,19 @@ void Client::setMiningThreads(unsigned _threads)
stopMining();
auto t = _threads ? _threads : thread::hardware_concurrency();
WriteGuard l(x_miners);
m_miners.clear();
m_miners.resize(t);
WriteGuard l(x_localMiners);
m_localMiners.clear();
m_localMiners.resize(t);
unsigned i = 0;
for (auto& m: m_miners)
for (auto& m: m_localMiners)
m.setup(this, i++);
}
MineProgress Client::miningProgress() const
{
MineProgress ret;
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
ret.combine(m.miningProgress());
return ret;
}
@ -342,13 +351,13 @@ std::list<MineInfo> Client::miningHistory()
{
std::list<MineInfo> ret;
ReadGuard l(x_miners);
if (m_miners.empty())
ReadGuard l(x_localMiners);
if (m_localMiners.empty())
return ret;
ret = m_miners[0].miningHistory();
for (unsigned i = 1; i < m_miners.size(); ++i)
ret = m_localMiners[0].miningHistory();
for (unsigned i = 1; i < m_localMiners.size(); ++i)
{
auto l = m_miners[i].miningHistory();
auto l = m_localMiners[i].miningHistory();
auto ri = ret.begin();
auto li = l.begin();
for (; ri != ret.end() && li != l.end(); ++ri, ++li)
@ -465,6 +474,22 @@ void Client::inject(bytesConstRef _rlp)
m_tq.attemptImport(_rlp);
}
pair<h256, u256> Client::getWork()
{
Guard l(x_remoteMiner);
{
ReadGuard l(x_stateDB);
m_remoteMiner.update(m_postMine, m_bc);
}
return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty());
}
bool Client::submitNonce(h256 const&_nonce)
{
Guard l(x_remoteMiner);
return m_remoteMiner.submitWork(_nonce);
}
void Client::doWork()
{
// TODO: Use condition variable rather than polling.
@ -472,27 +497,34 @@ void Client::doWork()
cworkin << "WORK";
h256Set changeds;
auto maintainMiner = [&](Miner& m)
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
if (m.isComplete())
if (m.isComplete())
{
cwork << "CHAIN <== postSTATE";
h256s hs;
{
cwork << "CHAIN <== postSTATE";
h256s hs;
{
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto h: hs)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
//changeds.insert(PendingChangedFilter); // if we mined the new block, then we've probably reset the pending transactions.
}
for (auto& m: m_miners)
m.noteStateChange();
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto const& h: hs)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
}
for (auto& m: m_localMiners)
m.noteStateChange();
}
};
{
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
maintainMiner(m);
}
{
Guard l(x_remoteMiner);
maintainMiner(m_remoteMiner);
}
// Synchronise state to block chain.
@ -502,7 +534,7 @@ void Client::doWork()
// if there are no checkpoints before our fork) reverting to the genesis block and replaying
// all blocks.
// Resynchronise state with block chain & trans
bool rsm = false;
bool resyncStateNeeded = false;
{
WriteGuard l(x_stateDB);
cwork << "BQ ==> CHAIN ==> STATE";
@ -525,7 +557,7 @@ void Client::doWork()
if (isMining())
cnote << "New block on chain: Restarting mining operation.";
m_postMine = m_preMine;
rsm = true;
resyncStateNeeded = true;
changeds.insert(PendingChangedFilter);
// TODO: Move transactions pending from m_postMine back to transaction queue.
}
@ -541,13 +573,13 @@ void Client::doWork()
if (isMining())
cnote << "Additional transaction ready: Restarting mining operation.";
rsm = true;
resyncStateNeeded = true;
}
}
if (rsm)
if (resyncStateNeeded)
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
ReadGuard l(x_localMiners);
for (auto& m: m_localMiners)
m.noteStateChange();
}
@ -556,6 +588,23 @@ void Client::doWork()
cworkout << "WORK";
this_thread::sleep_for(chrono::milliseconds(100));
if (chrono::system_clock::now() - m_lastGarbageCollection > chrono::seconds(5))
{
// garbage collect on watches
vector<unsigned> toUninstall;
{
Guard l(m_filterLock);
for (auto key: keysOf(m_watches))
if (chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20))
{
toUninstall.push_back(key);
cnote << "GC: Uninstall" << key << "(" << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)";
}
}
for (auto i: toUninstall)
uninstallWatch(i);
m_lastGarbageCollection = chrono::system_clock::now();
}
}
unsigned Client::numberOf(int _n) const

57
libethereum/Client.h

@ -89,11 +89,12 @@ static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0);
struct ClientWatch
{
ClientWatch() {}
explicit ClientWatch(h256 _id): id(_id) {}
ClientWatch(): lastPoll(std::chrono::system_clock::now()) {}
explicit ClientWatch(h256 _id): id(_id), lastPoll(std::chrono::system_clock::now()) {}
h256 id;
LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange };
mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now();
};
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; };
@ -134,6 +135,28 @@ template <class T> T abiOut(bytes const& _data)
return ABIDeserialiser<T>::deserialise(o);
}
class RemoteMiner: public Miner
{
public:
RemoteMiner() {}
void update(State const& _provisional, BlockChain const& _bc) { m_state = _provisional; m_state.commitToMine(_bc); }
h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); }
u256 const& difficulty() const { return m_state.info().difficulty; }
bool submitWork(h256 const& _nonce) { return (m_isComplete = m_state.completeMine(_nonce)); }
virtual bool isComplete() const override { return m_isComplete; }
virtual bytes const& blockData() const { return m_state.blockData(); }
virtual void noteStateChange() override {}
private:
bool m_isComplete = false;
State m_state;
};
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@ -252,20 +275,26 @@ public:
/// Stops mining and sets the number of mining threads (0 for automatic).
virtual void setMiningThreads(unsigned _threads = 0);
/// Get the effective number of mining threads.
virtual unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
virtual unsigned miningThreads() const { ReadGuard l(x_localMiners); return m_localMiners.size(); }
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
virtual void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
virtual void startMining() { startWorking(); ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.start(); }
/// Stop mining.
/// NOT thread-safe
virtual void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
virtual void stopMining() { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.stop(); }
/// Are we mining now?
virtual bool isMining() { ReadGuard l(x_miners); return m_miners.size() && m_miners[0].isRunning(); }
virtual bool isMining() { ReadGuard l(x_localMiners); return m_localMiners.size() && m_localMiners[0].isRunning(); }
/// Check the progress of the mining.
virtual MineProgress miningProgress() const;
/// Get and clear the mining history.
std::list<MineInfo> miningHistory();
/// Update to the latest transactions and get hash of the current block to be mined minus the
/// nonce (the 'work hash') and the difficulty to be met.
virtual std::pair<h256, u256> getWork() override;
/// Submit the nonce for the proof-of-work.
virtual bool submitNonce(h256 const&_nonce) override;
// Debug stuff:
DownloadMan const* downloadMan() const;
@ -294,6 +323,7 @@ private:
/// Do some work. Handles blockchain maintenance and mining.
virtual void doWork();
/// Called when Worker is exiting.
virtual void doneWorking();
/// Overrides for being a mining host.
@ -308,26 +338,31 @@ private:
State asOf(unsigned _h) const;
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
CanonBlockChain m_bc; ///< Maintains block database.
CanonBlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector<Miner> m_miners;
mutable SharedMutex x_miners;
mutable Mutex x_remoteMiner; ///< The remote miner lock.
RemoteMiner m_remoteMiner; ///< The remote miner.
std::vector<LocalMiner> m_localMiners; ///< The in-process miners.
mutable SharedMutex x_localMiners; ///< The in-process miners lock.
bool m_paranoia = false; ///< Should we be paranoid about our state?
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending?
mutable std::mutex m_filterLock;
mutable Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
mutable std::chrono::system_clock::time_point m_lastGarbageCollection;
};
}

5
libethereum/Interface.h

@ -149,6 +149,11 @@ public:
/// Are we mining now?
virtual bool isMining() = 0;
/// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual std::pair<h256, u256> getWork() = 0;
/// Submit the nonce for the proof-of-work.
virtual bool submitNonce(h256 const&) = 0;
/// Check the progress of the mining.
virtual MineProgress miningProgress() const = 0;

2
libethereum/LogFilter.cpp

@ -27,7 +27,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
std::ostream& dev::operator<<(std::ostream& _out, LogFilter const& _s)
std::ostream& dev::eth::operator<<(std::ostream& _out, LogFilter const& _s)
{
// TODO
_out << "(@" << _s.m_addresses << "#" << _s.m_topics << ">" << _s.m_earliest << "-" << _s.m_latest << "< +" << _s.m_skip << "^" << _s.m_max << ")";

8
libethereum/LogFilter.h

@ -34,12 +34,12 @@ namespace eth
class LogFilter;
}
/// Simple stream output for the StateDiff.
std::ostream& operator<<(std::ostream& _out, dev::eth::LogFilter const& _s);
namespace eth
{
/// Simple stream output for the StateDiff.
std::ostream& operator<<(std::ostream& _out, dev::eth::LogFilter const& _s);
class State;
class LogFilter
@ -65,7 +65,7 @@ public:
LogFilter withEarliest(int _e) { m_earliest = _e; return *this; }
LogFilter withLatest(int _e) { m_latest = _e; return *this; }
friend std::ostream& dev::operator<<(std::ostream& _out, dev::eth::LogFilter const& _s);
friend std::ostream& dev::eth::operator<<(std::ostream& _out, dev::eth::LogFilter const& _s);
private:
AddressSet m_addresses;

12
libethereum/Miner.cpp

@ -15,8 +15,8 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Miner.cpp
* @author Alex Leverington <nessence@gmail.com>
* @author Gav Wood <i@gavwood.com>
* @author Giacomo Tazzari
* @date 2014
*/
@ -28,19 +28,21 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
Miner::Miner(MinerHost* _host, unsigned _id):
Miner::~Miner() {}
LocalMiner::LocalMiner(MinerHost* _host, unsigned _id):
Worker("miner-" + toString(_id)),
m_host(_host)
{
}
void Miner::setup(MinerHost* _host, unsigned _id)
void LocalMiner::setup(MinerHost* _host, unsigned _id)
{
m_host = _host;
setName("miner-" + toString(_id));
}
void Miner::doWork()
void LocalMiner::doWork()
{
// Do some mining.
if (m_miningStatus != Waiting && m_miningStatus != Mined)
@ -63,7 +65,7 @@ void Miner::doWork()
if (m_miningStatus == Mining)
{
// Mine for a while.
// Mine for a while.
MineInfo mineInfo = m_mineState.mine(100, m_host->turbo());
{

28
libethereum/Miner.h

@ -63,6 +63,16 @@ public:
virtual bool force() const = 0; ///< @returns true iff the Miner should mine regardless of the number of transactions.
};
class Miner
{
public:
virtual ~Miner();
virtual void noteStateChange() = 0;
virtual bool isComplete() const = 0;
virtual bytes const& blockData() const = 0;
};
/**
* @brief Implements Miner.
* To begin mining, use start() & stop(). noteStateChange() can be used to reset the mining and set up the
@ -75,23 +85,23 @@ public:
* @threadsafe
* @todo Signal Miner to restart once with condition variables.
*/
class Miner: Worker
class LocalMiner: public Miner, Worker
{
public:
/// Null constructor.
Miner(): m_host(nullptr) {}
LocalMiner(): m_host(nullptr) {}
/// Constructor.
Miner(MinerHost* _host, unsigned _id = 0);
LocalMiner(MinerHost* _host, unsigned _id = 0);
/// Move-constructor.
Miner(Miner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); }
LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); }
/// Move-assignment.
Miner& operator=(Miner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; }
LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; }
/// Destructor. Stops miner.
~Miner() { stop(); }
~LocalMiner() { stop(); }
/// Setup its basics.
void setup(MinerHost* _host, unsigned _id = 0);
@ -103,16 +113,16 @@ public:
void stop() { stopWorking(); }
/// Call to notify Miner of a state change.
void noteStateChange() { m_miningStatus = Preparing; }
virtual void noteStateChange() override { m_miningStatus = Preparing; }
/// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force().
bool isRunning() { return isWorking(); }
/// @returns true if mining is complete.
bool isComplete() const { return m_miningStatus == Mined; }
virtual bool isComplete() const override { return m_miningStatus == Mined; }
/// @returns the internal State object.
bytes const& blockData() { return m_mineState.blockData(); }
virtual bytes const& blockData() const override { return m_mineState.blockData(); }
/// Check the progress of the mining.
MineProgress miningProgress() const { Guard l(x_mineInfo); return m_mineProgress; }

18
libethereum/State.cpp

@ -774,19 +774,31 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo)
// Update difficulty according to timestamp.
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
MineInfo ret;
// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
auto ret = m_pow.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHash(WithoutNonce), m_currentBlock.difficulty, _msTimeout, true, _turbo);
tie(ret, m_currentBlock.nonce) = m_pow.mine(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.difficulty, _msTimeout, true, _turbo);
if (!ret.completed)
m_currentBytes.clear();
else
{
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.nonce, m_currentBlock.difficulty);
}
return ret;
}
bool State::completeMine(h256 const& _nonce)
{
if (!m_pow.verify(m_currentBlock.headerHash(WithoutNonce), _nonce, m_currentBlock.difficulty))
return false;
m_currentBlock.nonce = _nonce;
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.nonce, m_currentBlock.difficulty);
completeMine();
return true;
}
void State::completeMine()
{
cdebug << "Completing mine!";

4
libethereum/State.h

@ -113,6 +113,10 @@ public:
/// This may be called multiple times and without issue.
void commitToMine(BlockChain const& _bc);
/// Pass in a solution to the proof-of-work.
/// @returns true iff the given nonce is a proof-of-work for this State's block.
bool completeMine(h256 const& _nonce);
/// Attempt to find valid nonce for block that this state represents.
/// This function is thread-safe. You can safely have other interactions with this object while it is happening.
/// @param _msTimeout Timeout before return in milliseconds.

31
libjsqrc/ethereumjs/dist/ethereum.js

@ -1043,33 +1043,16 @@ var ProviderManager = function() {
var self = this;
var poll = function () {
if (self.provider) {
var pollsBatch = self.polls.map(function (data) {
return data.data;
});
var payload = jsonrpc.toBatchPayload(pollsBatch);
var results = self.provider.send(payload);
self.polls.forEach(function (data, index) {
var result = results[index];
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return;
}
result = result.result;
// dont call the callback if result is not an array, or empty one
if (!(result instanceof Array) || result.length === 0) {
return;
}
self.polls.forEach(function (data) {
var result = self.send(data.data);
data.callback(result);
if (!(result instanceof Array) || result.length === 0) {
return;
}
});
data.callback(result);
});
}
setTimeout(poll, 1000);
};
poll();

4
libjsqrc/ethereumjs/dist/ethereum.js.map

File diff suppressed because one or more lines are too long

2
libjsqrc/ethereumjs/dist/ethereum.min.js

File diff suppressed because one or more lines are too long

31
libjsqrc/ethereumjs/lib/providermanager.js

@ -42,33 +42,16 @@ var ProviderManager = function() {
var self = this;
var poll = function () {
if (self.provider) {
var pollsBatch = self.polls.map(function (data) {
return data.data;
});
self.polls.forEach(function (data) {
var result = self.send(data.data);
var payload = jsonrpc.toBatchPayload(pollsBatch);
var results = self.provider.send(payload);
if (!(result instanceof Array) || result.length === 0) {
return;
}
self.polls.forEach(function (data, index) {
var result = results[index];
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return;
}
data.callback(result);
});
result = result.result;
// dont call the callback if result is not an array, or empty one
if (!(result instanceof Array) || result.length === 0) {
return;
}
data.callback(result);
});
}
setTimeout(poll, 1000);
};
poll();

1
libjsqrc/js.qrc

@ -3,6 +3,5 @@
<file>bignumber.min.js</file>
<file>setup.js</file>
<file alias="webthree.js">ethereumjs/dist/ethereum.js</file>
<file>natspec.js</file>
</qresource>
</RCC>

35
libnatspec/CMakeLists.txt

@ -0,0 +1,35 @@
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_AUTOMOC OFF)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(..)
set(EXECUTABLE natspec)
file(GLOB HEADERS "*.h")
qt5_add_resources(NATSPECQRC natspec.qrc)
if (ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS} ${NATSPECQRC})
else()
add_library(${EXECUTABLE} SHARED ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS} ${NATSPECQRC})
endif()
target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Qml)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

59
libnatspec/NatspecExpressionEvaluator.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 NatspecExpressionEvaluator.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
#include "NatspecExpressionEvaluator.h"
using namespace std;
using namespace dev;
static QString contentsOfQResource(string const& _res)
{
QFile file(QString::fromStdString(_res));
if (!file.open(QFile::ReadOnly))
BOOST_THROW_EXCEPTION(FileError());
QTextStream in(&file);
return in.readAll();
}
NatspecExpressionEvaluator::NatspecExpressionEvaluator(QString const& _abi, QString const& _method, QString const& _params)
{
Q_INIT_RESOURCE(natspec);
QJSValue result = m_engine.evaluate(contentsOfQResource(":/natspec/natspec.js"));
if (result.isError())
BOOST_THROW_EXCEPTION(FileError());
m_engine.evaluate("globals.abi = " + _abi);
m_engine.evaluate("globals.method = " + _method);
m_engine.evaluate("globals.params = " + _params);
}
QString NatspecExpressionEvaluator::evalExpression(QString const& _expression)
{
QJSValue result = m_engine.evaluate("evaluateExpression(\"" + _expression + "\")");
if (result.isError())
{
cerr << "Could not evaluate expression: \"" << _expression.toStdString() << "\"" << endl;
return _expression;
}
return result.toString();
}

49
libnatspec/NatspecExpressionEvaluator.h

@ -0,0 +1,49 @@
/*
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 NatspecExpressionEvaluator.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <QtCore/QObject>
#include <QtCore/QtCore>
#include <QtQml/QJSEngine>
/**
* Should be used to evaluate natspec expression.
* @see test/natspec.cpp for natspec expression examples
*/
class NatspecExpressionEvaluator
{
public:
/// Construct natspec expression evaluator
/// @params abi - contract's abi in json format, passed as string
/// @params method - name of the contract's method for which we evaluate the natspec.
/// If we want to use raw string, it should be passed with quotation marks eg. "\"helloWorld\""
/// If we pass string "helloWorld", the value of the object with name "helloWorld" will be used
/// @params params - array of method input params, passed as string, objects in array should be
/// javascript valid objects
NatspecExpressionEvaluator(QString const& _abi = "[]", QString const& _method = "", QString const& _params = "[]");
/// Should be called to evaluate natspec expression
/// @params expression - natspec expression
/// @returns evaluated natspec expression if it was valid, otherwise original expression
QString evalExpression(QString const& _expression);
private:
QJSEngine m_engine;
};

69
libjsqrc/natspec.js → libnatspec/natspec.js

@ -2,13 +2,19 @@
/**
* This plugin exposes 'evaluateExpression' method which should be used
* to evaluate natspec description
* It should be reloaded each time we want to evaluate set of expressions
* Just because of security reasons
* TODO: make use of sync api (once it's finished) and remove unnecessary
* code from 'getContractMethods'
* TODO: unify method signature creation with abi.js (and make a separate method from it)
*/
/// Object which should be used by NatspecExpressionEvaluator
/// abi - abi of the contract that will be used
/// method - name of the method that is called
/// params - input params of the method that will be called
var globals = {
abi: [],
method: "",
params: []
};
/// Helper method
/// Should be called to copy values from object to global context
var copyToContext = function (obj, context) {
var keys = Object.keys(obj);
@ -17,32 +23,38 @@ var copyToContext = function (obj, context) {
});
}
/// Helper method
/// Should be called to get method with given name from the abi
/// @param contract's abi
/// @param name of the method that we are looking for
var getMethodWithName = function(abi, name) {
for (var i = 0; i < abi.length; i++) {
if (abi[i].name === name) {
return abi[i];
}
}
//console.warn('could not find method with name: ' + name);
return undefined;
};
/// Function called to get all contract's storage values
/// @returns hashmap with contract properties which are used
/// TODO: check if this function will be used
var getContractProperties = function (address, abi) {
return {};
};
/// Function called to get all contract's methods
/// @returns hashmap with used contract's methods
/// TODO: check if this function will be used
var getContractMethods = function (address, abi) {
return web3.eth.contract(address, abi);
};
var getMethodWithName = function(abi, name) {
for (var i = 0; i < abi.length; i++) {
if (abi[i].name === name) {
return abi[i];
}
}
console.warn('could not find method with name: ' + name);
return undefined;
//return web3.eth.contract(address, abi); // commented out web3 usage
return {};
};
/// Function called to get all contract method input variables
/// @returns hashmap with all contract's method input variables
var getContractInputParams = function (abi, methodName, params) {
var method = getMethodWithName(abi, methodName);
var getMethodInputParams = function (method, params) {
return method.inputs.reduce(function (acc, current, index) {
acc[current.name] = params[index];
return acc;
@ -55,18 +67,15 @@ var getContractInputParams = function (abi, methodName, params) {
var evaluateExpression = function (expression) {
var self = this;
var abi = web3._currentContractAbi;
var address = web3._currentContractAddress;
var methodName = web3._currentContractMethodName;
var params = web3._currentContractMethodParams;
var storage = getContractProperties(address, abi);
var methods = getContractMethods(address, abi);
var inputParams = getContractInputParams(abi, methodName, params);
copyToContext(storage, self);
copyToContext(methods, self);
copyToContext(inputParams, self);
//var storage = getContractProperties(address, abi);
//var methods = getContractMethods(address, abi);
var method = getMethodWithName(globals.abi, globals.method);
if (method) {
var input = getMethodInputParams(method, globals.params);
copyToContext(input, self);
}
// TODO: test if it is safe
var evaluatedExpression = "";

5
libnatspec/natspec.qrc

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/natspec">
<file>natspec.js</file>
</qresource>
</RCC>

2
libsolidity/AST.cpp

@ -383,6 +383,8 @@ void VariableDefinition::checkTypeRequirements()
BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString()));
type = intType;
}
else if (type->getCategory() == Type::Category::VOID)
BOOST_THROW_EXCEPTION(m_variable->createTypeError("var cannot be void type"));
m_variable->setType(type);
}
}

19
libsolidity/AST.h

@ -1112,13 +1112,23 @@ private:
};
/**
* A literal string or number. @see Type::literalToBigEndian is used to actually parse its value.
* A literal string or number. @see ExpressionCompiler::endVisit() is used to actually parse its value.
*/
class Literal: public PrimaryExpression
{
public:
Literal(Location const& _location, Token::Value _token, ASTPointer<ASTString> const& _value):
PrimaryExpression(_location), m_token(_token), m_value(_value) {}
enum class SubDenomination
{
None = Token::ILLEGAL,
Wei = Token::SubWei,
Szabo = Token::SubSzabo,
Finney = Token::SubFinney,
Ether = Token::SubEther
};
Literal(Location const& _location, Token::Value _token,
ASTPointer<ASTString> const& _value,
SubDenomination _sub = SubDenomination::None):
PrimaryExpression(_location), m_token(_token), m_value(_value), m_subDenomination(_sub) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
@ -1127,9 +1137,12 @@ public:
/// @returns the non-parsed value of the literal
ASTString const& getValue() const { return *m_value; }
SubDenomination getSubDenomination() const { return m_subDenomination; }
private:
Token::Value m_token;
ASTPointer<ASTString> m_value;
SubDenomination m_subDenomination;
};
/// @}

47
libsolidity/ExpressionCompiler.cpp

@ -867,19 +867,17 @@ unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedT
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{
FunctionType thisType(_varDecl);
solAssert(thisType.getReturnParameterTypes().size() == 1, "");
TypePointer const& resultType = thisType.getReturnParameterTypes().front();
unsigned sizeOnStack;
FunctionType accessorType(_varDecl);
unsigned length = 0;
TypePointers const& params = thisType.getParameterTypes();
TypePointers const& params = accessorType.getParameterTypes();
// move arguments to memory
for (TypePointer const& param: boost::adaptors::reverse(params))
length += appendTypeConversionAndMoveToMemory(*param, *param, Location(), length);
// retrieve the position of the mapping
// retrieve the position of the variable
m_context << m_context.getStorageLocationOfVariable(_varDecl);
TypePointer returnType = _varDecl.getType();
for (TypePointer const& param: params)
{
@ -888,13 +886,40 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
unsigned argLen = CompilerUtils::getPaddedSize(param->getCalldataEncodedSize());
length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
returnType = dynamic_cast<MappingType const&>(*returnType).getValueType();
}
m_currentLValue = LValue(m_context, LValue::STORAGE, *resultType);
m_currentLValue.retrieveValue(resultType, Location(), true);
sizeOnStack = resultType->getSizeOnStack();
solAssert(sizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP;
unsigned retSizeOnStack = 0;
solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");
if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
{
auto const& names = accessorType.getReturnParameterNames();
auto const& types = accessorType.getReturnParameterTypes();
// struct
for (size_t i = 0; i < names.size(); ++i)
{
m_context << eth::Instruction::DUP1
<< structType->getStorageOffsetOfMember(names[i])
<< eth::Instruction::ADD;
m_currentLValue = LValue(m_context, LValue::STORAGE, *types[i]);
m_currentLValue.retrieveValue(types[i], 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();
}
m_context << eth::Instruction::POP;
}
else
{
// simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
m_currentLValue = LValue(m_context, LValue::STORAGE, *returnType);
m_currentLValue.retrieveValue(returnType, 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,

12
libsolidity/Parser.cpp

@ -180,7 +180,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
{
Declaration::Visibility visibility;
Declaration::Visibility visibility = Declaration::Visibility::DEFAULT;
if (_token == Token::PUBLIC)
visibility = Declaration::Visibility::PUBLIC;
else if (_token == Token::PROTECTED)
@ -691,6 +691,16 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
break;
case Token::NUMBER:
if (Token::isEtherSubdenomination(m_scanner->peekNextToken()))
{
ASTPointer<ASTString> literal = getLiteralAndAdvance();
nodeFactory.markEndPosition();
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(m_scanner->getCurrentToken());
m_scanner->next();
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
break;
}
// fall-through
case Token::STRING_LITERAL:
nodeFactory.markEndPosition();
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());

6
libsolidity/Token.h

@ -174,6 +174,11 @@ namespace solidity
K(WHILE, "while", 0) \
\
\
/* Ether subdenominations */ \
K(SubWei, "wei", 0) \
K(SubSzabo, "szabo", 0) \
K(SubFinney, "finney", 0) \
K(SubEther, "ether", 0) \
/* type keywords, keep them in this order, keep int as first keyword
* the implementation in Types.cpp has to be synced to this here
* TODO more to be added */ \
@ -378,6 +383,7 @@ public:
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 isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; }
// Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or NULL if the token doesn't

57
libsolidity/Types.cpp

@ -91,7 +91,7 @@ shared_ptr<Type const> Type::forLiteral(Literal const& _literal)
case Token::FALSE_LITERAL:
return make_shared<BoolType>();
case Token::NUMBER:
return IntegerConstantType::fromLiteral(_literal.getValue());
return make_shared<IntegerConstantType>(_literal);
case Token::STRING_LITERAL:
//@todo put larger strings into dynamic strings
return StaticStringType::smallestTypeForLiteral(_literal.getValue());
@ -216,9 +216,25 @@ const MemberList IntegerType::AddressMemberList =
strings{}, FunctionType::Location::BARE)},
{"send", make_shared<FunctionType>(strings{"uint"}, strings{}, FunctionType::Location::SEND)}});
shared_ptr<IntegerConstantType const> IntegerConstantType::fromLiteral(string const& _literal)
IntegerConstantType::IntegerConstantType(Literal const& _literal)
{
return make_shared<IntegerConstantType>(bigint(_literal));
m_value = bigint(_literal.getValue());
switch (_literal.getSubDenomination())
{
case Literal::SubDenomination::Wei:
case Literal::SubDenomination::None:
break;
case Literal::SubDenomination::Szabo:
m_value *= bigint("1000000000000");
break;
case Literal::SubDenomination::Finney:
m_value *= bigint("1000000000000000");
break;
case Literal::SubDenomination::Ether:
m_value *= bigint("1000000000000000000");
break;
}
}
bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) const
@ -328,13 +344,17 @@ string IntegerConstantType::toString() const
u256 IntegerConstantType::literalValue(Literal const*) const
{
u256 value;
// we ignore the literal and hope that the type was correctly determined
solAssert(m_value <= u256(-1), "Integer constant too large.");
solAssert(m_value >= -(bigint(1) << 255), "Integer constant too small.");
if (m_value >= 0)
return u256(m_value);
value = u256(m_value);
else
return s2u(s256(m_value));
value = s2u(s256(m_value));
return value;
}
shared_ptr<IntegerType const> IntegerConstantType::getIntegerType() const
@ -623,22 +643,31 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
{
TypePointers params;
vector<string> paramNames;
TypePointers retParams;
vector<string> retParamNames;
TypePointer varDeclType = _varDecl.getType();
auto mappingType = dynamic_cast<MappingType const*>(varDeclType.get());
auto returnType = varDeclType;
auto returnType = _varDecl.getType();
while (mappingType != nullptr)
while (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
{
params.push_back(mappingType->getKeyType());
paramNames.push_back("");
returnType = mappingType->getValueType();
mappingType = dynamic_cast<MappingType const*>(mappingType->getValueType().get());
}
retParams.push_back(returnType);
retParamNames.push_back("");
TypePointers retParams;
vector<string> retParamNames;
if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
{
for (pair<string, TypePointer> const& member: structType->getMembers())
if (member.second->canLiveOutsideStorage())
{
retParamNames.push_back(member.first);
retParams.push_back(member.second);
}
}
else
{
retParams.push_back(returnType);
retParamNames.push_back("");
}
swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames);

3
libsolidity/Types.h

@ -197,8 +197,7 @@ class IntegerConstantType: public Type
public:
virtual Category getCategory() const override { return Category::INTEGER_CONSTANT; }
static std::shared_ptr<IntegerConstantType const> fromLiteral(std::string const& _literal);
explicit IntegerConstantType(Literal const& _literal);
explicit IntegerConstantType(bigint _value): m_value(_value) {}
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;

12
libweb3jsonrpc/WebThreeStubServer.h

@ -44,13 +44,13 @@ public:
WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
private:
dev::eth::Interface* client() override;
std::shared_ptr<dev::shh::Interface> face() override;
dev::WebThreeNetworkFace* network() override;
dev::WebThreeStubDatabaseFace* db() override;
virtual dev::eth::Interface* client() override;
virtual std::shared_ptr<dev::shh::Interface> face() override;
virtual dev::WebThreeNetworkFace* network() override;
virtual dev::WebThreeStubDatabaseFace* db() override;
std::string get(std::string const& _name, std::string const& _key) override;
void put(std::string const& _name, std::string const& _key, std::string const& _value) override;
virtual std::string get(std::string const& _name, std::string const& _key) override;
virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) override;
private:
dev::WebThreeDirect& m_web3;

20
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -31,7 +31,9 @@
#include <libethcore/CommonJS.h>
#include <libwhisper/Message.h>
#include <libwhisper/WhisperHost.h>
#ifndef _MSC_VER
#include <libserpent/funcs.h>
#endif
#include "WebThreeStubServerBase.h"
using namespace std;
@ -426,6 +428,20 @@ int WebThreeStubServerBase::eth_newFilterString(std::string const& _filter)
return ret;
}
Json::Value WebThreeStubServerBase::eth_getWork()
{
Json::Value ret(Json::arrayValue);
auto r = client()->getWork();
ret.append(toJS(r.first));
ret.append(toJS(r.second));
return ret;
}
bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce)
{
return client()->submitNonce(jsToFixed<32>(_nonce));
}
std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who)
{
(void)_id;
@ -446,7 +462,9 @@ Json::Value WebThreeStubServerBase::eth_compilers()
Json::Value ret(Json::arrayValue);
ret.append("lll");
ret.append("solidity");
#ifndef _MSC_VER
ret.append("serpent");
#endif
return ret;
}
@ -462,6 +480,7 @@ std::string WebThreeStubServerBase::eth_lll(std::string const& _code)
std::string WebThreeStubServerBase::eth_serpent(std::string const& _code)
{
string res;
#ifndef _MSC_VER
try
{
res = toJS(dev::asBytes(::compile(_code)));
@ -474,6 +493,7 @@ std::string WebThreeStubServerBase::eth_serpent(std::string const& _code)
{
cwarn << "Uncought serpent compilation exception";
}
#endif
return res;
}

3
libweb3jsonrpc/WebThreeStubServerBase.h

@ -103,6 +103,9 @@ public:
virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i);
virtual bool eth_uninstallFilter(int const& _id);
virtual Json::Value eth_getWork();
virtual bool eth_submitWork(std::string const& _nonce);
virtual std::string db_get(std::string const& _name, std::string const& _key);
virtual std::string db_getString(std::string const& _name, std::string const& _key);
virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value);

12
libweb3jsonrpc/abstractwebthreestubserver.h

@ -49,6 +49,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
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);
@ -211,6 +213,14 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
response = this->eth_logs(request[0u]);
}
inline virtual void eth_getWorkI(const Json::Value &request, Json::Value &response)
{
response = this->eth_getWork();
}
inline virtual void eth_submitWorkI(const Json::Value &request, Json::Value &response)
{
response = this->eth_submitWork(request[0u].asString());
}
inline virtual void db_putI(const Json::Value &request, Json::Value &response)
{
response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString());
@ -296,6 +306,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual Json::Value eth_changed(const int& param1) = 0;
virtual Json::Value eth_filterLogs(const 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;
virtual bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual std::string db_get(const std::string& param1, const std::string& param2) = 0;
virtual bool db_putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0;

4
libweb3jsonrpc/spec.json

@ -36,7 +36,6 @@
{ "name": "eth_solidity", "params": [""], "order": [], "returns": ""},
{ "name": "eth_serpent", "params": [""], "order": [], "returns": ""},
{ "name": "eth_newFilter", "params": [{}], "order": [], "returns": 0},
{ "name": "eth_newFilterString", "params": [""], "order": [], "returns": 0},
{ "name": "eth_uninstallFilter", "params": [0], "order": [], "returns": true},
@ -44,6 +43,9 @@
{ "name": "eth_filterLogs", "params": [0], "order": [], "returns": []},
{ "name": "eth_logs", "params": [{}], "order": [], "returns": []},
{ "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": [""], "order": [], "returns": true},
{ "name": "db_put", "params": ["", "", ""], "order": [], "returns": true},
{ "name": "db_get", "params": ["", ""], "order": [], "returns": ""},
{ "name": "db_putString", "params": ["", "", ""], "order": [], "returns": true},

2
mix/AppContext.cpp

@ -84,7 +84,7 @@ void AppContext::load()
qmlRegisterType<CodeEditorExtensionManager>("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager");
qmlRegisterType<HttpServer>("HttpServer", 1, 0, "HttpServer");
m_applicationEngine->load(QUrl("qrc:/qml/main.qml"));
QWindow *window = qobject_cast<QWindow *>(m_applicationEngine->rootObjects().at(0));
QWindow *window = qobject_cast<QWindow*>(m_applicationEngine->rootObjects().at(0));
window->setIcon(QIcon(":/res/mix_256x256x32.png"));
appLoaded();
}

45
mix/AssemblyDebuggerControl.cpp

@ -1,45 +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 AssemblyDebuggerControl.cpp
* @author Yann yann@ethdev.com
* @date 2014
* display opcode debugging.
*/
#include <QDebug>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include "ClientModel.h"
#include "AssemblyDebuggerControl.h"
using namespace dev::mix;
AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context):
Extension(_context, ExtensionDisplayBehavior::RightView)
{
}
QString AssemblyDebuggerControl::contentUrl() const
{
return QStringLiteral("qrc:/qml/Debugger.qml");
}
QString AssemblyDebuggerControl::title() const
{
return QApplication::tr("Debugger");
}
void AssemblyDebuggerControl::start() const
{
}

48
mix/AssemblyDebuggerControl.h

@ -1,48 +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 AssemblyDebuggerControl.h
* @author Yann yann@ethdev.com
* @date 2014
* Extension which display debugging steps in assembly code.
*/
#pragma once
#include <atomic>
#include "Extension.h"
namespace dev
{
namespace mix
{
class AppContext;
/**
* @brief Extension which display transaction creation or transaction call debugging.
*/
class AssemblyDebuggerControl: public Extension
{
Q_OBJECT
public:
AssemblyDebuggerControl(AppContext* _context);
~AssemblyDebuggerControl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
};
}
}

2
mix/CMakeLists.txt

@ -46,7 +46,9 @@ target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} secp256k1)
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
target_link_libraries(${EXECUTABLE} serpent)
endif()
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} solidity)
target_link_libraries(${EXECUTABLE} evmcore)

13
mix/ClientModel.cpp

@ -113,24 +113,27 @@ QString ClientModel::apiCall(QString const& _message)
void ClientModel::mine()
{
if (m_running)
if (m_running || m_mining)
BOOST_THROW_EXCEPTION(ExecutionStateException());
m_running = true;
emit runStarted();
emit runStateChanged();
m_mining = true;
emit miningStarted();
emit miningStateChanged();
QtConcurrent::run([=]()
{
try
{
m_client->mine();
newBlock();
m_mining = false;
emit miningComplete();
}
catch (...)
{
m_mining = false;
std::cerr << boost::current_exception_diagnostic_information();
emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information()));
}
m_running = false;
emit miningStateChanged();
});
}

10
mix/ClientModel.h

@ -26,6 +26,7 @@
#include <atomic>
#include <map>
#include <QString>
#include <QVariantMap>
#include "MachineStates.h"
namespace dev
@ -114,6 +115,8 @@ public:
~ClientModel();
/// @returns true if currently executing contract code
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)
/// ethereum.js RPC request entry point
@ -144,6 +147,12 @@ signals:
void runStarted();
/// Transaction execution completed successfully
void runComplete();
/// Mining has started
void miningStarted();
/// Mined a new block
void miningComplete();
/// Mining stopped or started
void miningStateChanged();
/// Transaction execution completed with error
/// @param _message Error message
void runFailed(QString const& _message);
@ -174,6 +183,7 @@ private:
AppContext* m_context;
std::atomic<bool> m_running;
std::atomic<bool> m_mining;
std::unique_ptr<MixClient> m_client;
std::unique_ptr<RpcConnector> m_rpcConnector;
std::unique_ptr<Web3Server> m_web3Server;

8
mix/CodeEditorExtensionManager.cpp

@ -26,8 +26,6 @@
#include <QQmlComponent>
#include <QQuickTextDocument>
#include "StatusPane.h"
#include "AssemblyDebuggerControl.h"
#include "StateListView.h"
#include "AppContext.h"
#include "MixApplication.h"
#include "CodeModel.h"
@ -56,13 +54,9 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
void CodeEditorExtensionManager::initExtensions()
{
std::shared_ptr<StatusPane> output = std::make_shared<StatusPane>(m_appContext);
std::shared_ptr<AssemblyDebuggerControl> debug = std::make_shared<AssemblyDebuggerControl>(m_appContext);
std::shared_ptr<StateListView> stateList = std::make_shared<StateListView>(m_appContext);
QObject::connect(m_appContext->codeModel(), &CodeModel::compilationComplete, this, &CodeEditorExtensionManager::applyCodeHighlight);
initExtension(output);
initExtension(debug);
initExtension(stateList);
}
void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext)
@ -94,10 +88,10 @@ void CodeEditorExtensionManager::applyCodeHighlight()
void CodeEditorExtensionManager::setRightView(QQuickItem* _rightView)
{
m_rightView = _rightView;
initExtensions(); //TODO: move this to a proper place
}
void CodeEditorExtensionManager::setHeaderView(QQuickItem* _headerView)
{
m_headerView = _headerView;
initExtensions(); //TODO: move this to a proper place
}

7
mix/ContractCallDataEncoder.cpp

@ -51,6 +51,8 @@ void ContractCallDataEncoder::push(bytes const& _b)
QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const& _returnParameters, bytes _value)
{
bytesConstRef value(&_value);
bytes rawParam(32);
QList<QVariableDefinition*> r;
for (int k = 0; k <_returnParameters.length(); k++)
{
@ -69,11 +71,10 @@ QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDecla
else
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found"));
bytes rawParam(_value.begin(), _value.begin() + 32);
value.populate(&rawParam);
def->decodeValue(rawParam);
r.push_back(def);
if (_value.size() > 32)
_value = bytes(_value.begin() + 32, _value.end());
value = value.cropped(32);
qDebug() << "decoded return value : " << dec->type() << " " << def->value();
}
return r;

118
mix/MixClient.cpp

@ -27,6 +27,7 @@
#include <libethereum/Transaction.h>
#include <libethereum/Executive.h>
#include <libethereum/ExtVM.h>
#include <libethereum/BlockChain.h>
#include <libevm/VM.h>
#include "Exceptions.h"
@ -34,15 +35,37 @@
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
namespace dev
{
namespace mix
{
const Secret c_userAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const u256 c_mixGenesisDifficulty = (u256) 1 << 4;
class MixBlockChain: public dev::eth::BlockChain
{
public:
MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, true)
{
}
static bytes createGenesisBlock(h256 _stateRoot)
{
RLPStream block(3);
block.appendList(14)
<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << std::string() << sha3(bytes(1, 42));
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
};
MixClient::MixClient(std::string const& _dbPath):
m_userAccount(c_userAccountSecret), m_bc(_dbPath, true), m_dbPath(_dbPath), m_minigThreads(0)
m_userAccount(c_userAccountSecret), m_dbPath(_dbPath), m_minigThreads(0)
{
//TODO: put this into genesis block somehow
//resetState(10000000 * ether);
resetState(10000000 * ether);
}
MixClient::~MixClient()
@ -51,21 +74,24 @@ MixClient::~MixClient()
void MixClient::resetState(u256 _balance)
{
(void) _balance;
{
WriteGuard l(x_state);
Guard fl(m_filterLock);
m_filters.clear();
m_watches.clear();
m_bc.reopen(m_dbPath, true);
m_state = eth::State();
m_stateDB = OverlayDB();
m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::CanonGenesis);
m_state.sync(m_bc);
m_startState = m_state;
m_pendingExecutions.clear();
}
mine();
WriteGuard l(x_state);
Guard fl(m_filterLock);
m_filters.clear();
m_watches.clear();
m_stateDB = OverlayDB();
TrieDB<Address, MemoryDB> accountState(&m_stateDB);
accountState.init();
std::map<Address, Account> genesisState = { std::make_pair(KeyPair(c_userAccountSecret).address(), Account(_balance, Account::NormalCreation)) };
dev::eth::commit(genesisState, static_cast<MemoryDB&>(m_stateDB), accountState);
h256 stateRoot = accountState.root();
m_bc.reset();
m_bc.reset(new MixBlockChain(m_dbPath, stateRoot));
m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Empty);
m_state.sync(bc());
m_startState = m_state;
m_pendingExecutions.clear();
m_executions.clear();
}
void MixClient::executeTransaction(Transaction const& _t, State& _state)
@ -74,9 +100,9 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
// do debugging run first
LastHashes lastHashes(256);
lastHashes[0] = m_bc.numberHash(m_bc.number());
lastHashes[0] = bc().numberHash(bc().number());
for (unsigned i = 1; i < 256; ++i)
lastHashes[i] = lastHashes[i - 1] ? m_bc.details(lastHashes[i - 1]).parent : h256();
lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256();
State execState = _state;
Executive execution(execState, lastHashes, 0);
@ -155,7 +181,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
h256Set changed;
Guard l(m_filterLock);
for (std::pair<h256 const, eth::InstalledFilter>& i: m_filters)
if ((unsigned)i.second.filter.latest() > m_bc.number())
if ((unsigned)i.second.filter.latest() > bc().number())
{
// acceptable number.
auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1));
@ -163,7 +189,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
{
// filter catches them
for (LogEntry const& l: m)
i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1));
i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1));
changed.insert(i.first);
}
}
@ -174,12 +200,11 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
void MixClient::mine()
{
WriteGuard l(x_state);
m_state.commitToMine(m_bc);
m_state.commitToMine(bc());
while (!m_state.mine(100, true).completed) {}
m_state.completeMine();
m_bc.import(m_state.blockData(), m_stateDB);
m_state.sync(m_bc);
//m_state.cleanup(true);
bc().import(m_state.blockData(), m_stateDB);
m_state.sync(bc());
m_startState = m_state;
m_executions.emplace_back(std::move(m_pendingExecutions));
h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter };
@ -188,9 +213,9 @@ void MixClient::mine()
ExecutionResult const& MixClient::execution(unsigned _block, unsigned _transaction) const
{
if (_block == m_bc.number() + 1)
if (_block == bc().number() + 1)
return m_pendingExecutions.at(_transaction);
return m_executions.at(_block).at(_transaction);
return m_executions.at(_block - 1).at(_transaction);
}
ExecutionResult const& MixClient::lastExecution() const
@ -213,14 +238,13 @@ State MixClient::asOf(int _block) const
else if (_block == -1)
return m_startState;
else
return State(m_stateDB, m_bc, m_bc.numberHash(_block));
return State(m_stateDB, bc(), bc().numberHash(_block));
}
void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret));
_gasPrice = 0; //TODO: remove after fixing setBalance
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
executeTransaction(t, m_state);
}
@ -229,7 +253,6 @@ Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init,
{
WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret));
_gasPrice = 0; //TODO: remove after fixing setBalance
eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
executeTransaction(t, m_state);
Address address = right160(sha3(rlpList(t.sender(), t.nonce())));
@ -301,12 +324,12 @@ eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const
eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const
{
LocalisedLogEntries ret;
unsigned lastBlock = m_bc.number();
unsigned lastBlock = bc().number();
unsigned block = std::min<unsigned>(lastBlock, (unsigned)_f.latest());
unsigned end = std::min(lastBlock, std::min(block, (unsigned)_f.earliest()));
unsigned skip = _f.skip();
// Pending transactions
if (block > m_bc.number())
if (block > bc().number())
{
ReadGuard l(x_state);
for (unsigned i = 0; i < m_state.pending().size(); ++i)
@ -318,15 +341,15 @@ eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const
ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block));
skip -= std::min(skip, static_cast<unsigned>(logEntries.size()));
}
block = m_bc.number();
block = bc().number();
}
// The rest
auto h = m_bc.numberHash(block);
auto h = bc().numberHash(block);
for (; ret.size() != block && block != end; block--)
{
if (_f.matches(m_bc.info(h).logBloom))
for (TransactionReceipt receipt: m_bc.receipts(h).receipts)
if (_f.matches(bc().info(h).logBloom))
for (TransactionReceipt receipt: bc().receipts(h).receipts)
if (_f.matches(receipt.bloom()))
{
LogEntries logEntries = _f.matches(receipt);
@ -334,7 +357,7 @@ eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const
ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block));
skip -= std::min(skip, static_cast<unsigned>(logEntries.size()));
}
h = m_bc.details(h).parent;
h = bc().details(h).parent;
}
return ret;
}
@ -416,22 +439,22 @@ LocalisedLogEntries MixClient::checkWatch(unsigned _watchId)
h256 MixClient::hashFromNumber(unsigned _number) const
{
return m_bc.numberHash(_number);
return bc().numberHash(_number);
}
eth::BlockInfo MixClient::blockInfo(h256 _hash) const
{
return BlockInfo(m_bc.block(_hash));
return BlockInfo(bc().block(_hash));
}
eth::BlockDetails MixClient::blockDetails(h256 _hash) const
{
return m_bc.details(_hash);
return bc().details(_hash);
}
eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[1].itemCount())
return Transaction(b[1][_i].data(), CheckSignature::Range);
@ -441,7 +464,7 @@ eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const
eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
@ -451,7 +474,7 @@ eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const
unsigned MixClient::number() const
{
return m_bc.number();
return bc().number();
}
eth::Transactions MixClient::pending() const
@ -461,7 +484,7 @@ eth::Transactions MixClient::pending() const
eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const
{
State st(m_stateDB, m_bc, _block);
State st(m_stateDB, bc(), _block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
@ -526,3 +549,6 @@ eth::MineProgress MixClient::miningProgress() const
{
return eth::MineProgress();
}
}
}

9
mix/MixClient.h

@ -27,7 +27,6 @@
#include <string>
#include <libethereum/Interface.h>
#include <libethereum/Client.h>
#include <libethereum/CanonBlockChain.h>
#include "MachineStates.h"
namespace dev
@ -35,6 +34,8 @@ namespace dev
namespace mix
{
class MixBlockChain;
class MixClient: public dev::eth::Interface
{
public:
@ -85,17 +86,21 @@ public:
void stopMining() override;
bool isMining() override;
eth::MineProgress miningProgress() const override;
std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); }
bool submitNonce(h256 const&) override { return false; }
private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state);
void noteChanged(h256Set const& _filters);
dev::eth::State asOf(int _block) const;
MixBlockChain& bc() { return *m_bc; }
MixBlockChain const& bc() const { return *m_bc; }
KeyPair m_userAccount;
eth::State m_state;
eth::State m_startState;
OverlayDB m_stateDB;
eth::CanonBlockChain m_bc;
std::auto_ptr<MixBlockChain> m_bc;
mutable boost::shared_mutex x_state;
mutable std::mutex m_filterLock;
std::map<h256, dev::eth::InstalledFilter> m_filters;

48
mix/StateListView.cpp

@ -1,48 +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 StateListView.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QQuickItem>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include "StateListView.h"
using namespace dev::mix;
StateListView::StateListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightView)
{
}
QString StateListView::contentUrl() const
{
return QStringLiteral("qrc:/qml/StateList.qml");
}
QString StateListView::title() const
{
return QApplication::tr("States");
}
void StateListView::start() const
{
}

45
mix/StateListView.h

@ -1,45 +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 StateListView.h
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <memory>
#include <QTextDocument>
#include "Extension.h"
namespace dev
{
namespace mix
{
/// State list control
class StateListView: public Extension
{
Q_OBJECT
public:
StateListView(AppContext* _context);
void start() const override;
QString title() const override;
QString contentUrl() const override;
};
}
}

37
mix/qml/DebugInfoList.qml

@ -4,14 +4,19 @@ import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.1
ColumnLayout {
id: root
property string title
property variant listModel;
property bool collapsible;
property bool enableSelection;
property real storedHeight: 0;
property Component itemDelegate
signal rowActivated(int index)
spacing: 0
function collapse()
{
storedHeight = childrenRect.height;
storageContainer.state = "collapsed";
}
@ -32,7 +37,9 @@ ColumnLayout {
Image {
source: "qrc:/qml/img/opentriangleindicator.png"
width: 15
height: 15
sourceSize.width: 15
sourceSize.height: 15
id: storageImgArrow
}
@ -53,16 +60,20 @@ ColumnLayout {
if (storageContainer.state == "collapsed")
{
storageContainer.state = "";
storageContainer.parent.parent.height = storageContainer.parent.parent.Layout.maximumHeight;
storageContainer.parent.parent.height = storedHeight;
}
else
{
storedHeight = root.childrenRect.height;
storageContainer.state = "collapsed";
}
}
}
}
}
Rectangle
{
id: storageContainer
border.width: 3
border.color: "#deddd9"
Layout.fillWidth: true
@ -80,18 +91,34 @@ ColumnLayout {
}
}
]
id: storageContainer
ListView {
TableView {
clip: true;
alternatingRowColors: false
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: 3
anchors.leftMargin: 3
width: parent.width - 3
height: parent.height - 6
id: storageList
model: listModel
delegate: itemDelegate
selectionMode: enableSelection ? SelectionMode.SingleSelection : SelectionMode.NoSelection
headerDelegate: null
itemDelegate: root.itemDelegate
onHeightChanged: {
if (height <= 0 && collapsible) {
if (storedHeight <= 0)
storedHeight = 200;
storageContainer.state = "collapsed";
}
else if (height > 0 && storageContainer.state == "collapsed") {
//TODO: fix increasing size
//storageContainer.state = "";
}
}
TableViewColumn {
role: "modelData"
width: parent.width
}
}
}
}

304
mix/qml/Debugger.qml

@ -9,8 +9,10 @@ import "js/ErrorLocationFormater.js" as ErrorLocationFormater
Rectangle {
id: debugPanel
property alias transactionLog : transactionLog
objectName: "debugPanel"
anchors.fill: parent;
color: "#ededed"
clip: true
@ -22,7 +24,7 @@ Rectangle {
function update(data, giveFocus)
{
if (statusPane.result.successful)
if (statusPane && statusPane.result.successful)
{
Debugger.init(data);
debugScrollArea.visible = true;
@ -55,6 +57,16 @@ Rectangle {
onCompilationComplete: update(null, false);
}
Settings {
id: splitSettings
property alias transactionLogHeight: transactionLog.height
property alias callStackHeight: callStackRect.height
property alias storageHeightSettings: storageRect.height
property alias memoryDumpHeightSettings: memoryRect.height
property alias callDataHeightSettings: callDataRect.height
property alias transactionLogVisible: transactionLog.visible
}
Rectangle
{
visible: false;
@ -104,49 +116,56 @@ Rectangle {
}
}
Flickable {
property int firstColumnWidth: 180
property int secondColumnWidth: 250
SplitView {
id: debugScrollArea
flickableDirection: Flickable.VerticalFlick
anchors.fill: parent
contentHeight: 4000
contentWidth: parent.width
Rectangle
{
orientation: Qt.Vertical
handleDelegate: Rectangle {
height: machineStates.sideMargin
color: "transparent"
anchors.fill: parent
ColumnLayout
{
property int sideMargin: 10
id: machineStates
}
TransactionLog {
id: transactionLog
Layout.fillWidth: true
Layout.minimumHeight: 60
height: 250
}
ScrollView
{
property int sideMargin: 10
id: machineStates
Layout.fillWidth: true
Layout.fillHeight: true
function updateHeight() {
statesLayout.height = buttonRow.childrenRect.height + assemblyCodeRow.childrenRect.height +
callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height + 120;
}
Component.onCompleted: updateHeight();
ColumnLayout {
id: statesLayout
anchors.top: parent.top
anchors.topMargin: 15
anchors.left: parent.left;
anchors.leftMargin: machineStates.sideMargin
anchors.right: parent.right;
anchors.rightMargin: machineStates.sideMargin
anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
TransactionLog {
Layout.fillWidth: true
height: 250
}
width: debugScrollArea.width - machineStates.sideMargin * 2 - 20;
spacing: machineStates.sideMargin
RowLayout {
Rectangle {
// step button + slider
id: buttonRow
spacing: machineStates.sideMargin
height: 27
Layout.fillWidth: true
color: "transparent"
Rectangle
{
height: parent.height
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
color: "transparent"
width: debugScrollArea.firstColumnWidth
width: stateListContainer.width
RowLayout {
anchors.horizontalCenter: parent.horizontalCenter
id: jumpButtons
@ -226,9 +245,11 @@ Rectangle {
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: debugInfoContainer.width
color: "transparent"
Layout.fillWidth: true
height: parent.height
Slider {
id: statesSlider
anchors.fill: parent
@ -255,83 +276,99 @@ Rectangle {
}
}
RowLayout {
Rectangle {
// Assembly code
id: assemblyCodeRow
Layout.fillWidth: true
height: 405
implicitHeight: 405
spacing: machineStates.sideMargin
color: "transparent"
Rectangle
{
id: stateListContainer
width: debugScrollArea.firstColumnWidth
anchors.top : parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: parent.width * 0.4
height: parent.height
border.width: 3
border.color: "#deddd9"
color: "white"
anchors.top: parent.top
ListView {
TableView {
id: statesList
anchors.fill: parent
anchors.leftMargin: 3
anchors.rightMargin: 3
anchors.topMargin: 3
anchors.bottomMargin: 3
clip: true
id: statesList
delegate: renderDelegate
highlight: highlightBar
//highlightFollowsCurrentItem: false
headerDelegate: null
itemDelegate: renderDelegate
model: ListModel {}
TableViewColumn {
role: "line"
width: parent.width - 10
}
}
Component {
id: highlightBar
Rectangle {
radius: 4
height: statesList.currentItem.height
width: statesList.currentItem.width;
anchors.fill: parent
y: statesList.currentItem.y
color: "#4A90E2"
//Behavior on y {
// PropertyAnimation { properties: "y"; easing.type: Easing.InOutQuad; duration: 50}
//}
}
}
Component {
id: renderDelegate
RowLayout {
id: wrapperItem
height: 20
width: parent.width
spacing: 5
Text {
anchors.left: parent.left
anchors.leftMargin: 10
width: 15
color: "#b2b3ae"
text: line.split(' ')[0]
font.family: "monospace"
font.pointSize: 9
id: id
wrapMode: Text.NoWrap
Item {
Rectangle {
radius: 4
anchors.fill: parent
color: "#4A90E2"
visible: styleData.selected;
}
Text {
wrapMode: Text.NoWrap
color: parent.ListView.isCurrentItem ? "white" : "black"
font.family: "monospace"
text: line.replace(line.split(' ')[0], '')
anchors.left: id.right
font.pointSize: 9
RowLayout {
id: wrapperItem
anchors.fill: parent
spacing: 5
Text {
anchors.left: parent.left
anchors.leftMargin: 10
width: 15
color: "#b2b3ae"
text: styleData.value.split(' ')[0]
font.family: "monospace"
font.pointSize: 9
wrapMode: Text.NoWrap
id: id
}
Text {
anchors.left: id.right;
wrapMode: Text.NoWrap
color: styleData.selected ? "white" : "black"
font.family: "monospace"
text: styleData.value.replace(styleData.value.split(' ')[0], '')
font.pointSize: 9
}
}
}
}
}
Rectangle {
Layout.fillWidth: true
id: debugInfoContainer
width: parent.width * 0.6 - machineStates.sideMargin
anchors.top : parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
height: parent.height //- 2 * stateListContainer.border.width
color: "transparent"
ColumnLayout
@ -372,7 +409,7 @@ Rectangle {
title : qsTr("Stack")
itemDelegate: Item {
id: renderedItem
height: 25
//height: 25
width: parent.width
RowLayout
{
@ -391,7 +428,7 @@ Rectangle {
anchors.leftMargin: 5
font.family: "monospace"
color: "#4a4a4a"
text: model.index;
text: styleData.row;
font.pointSize: 9
}
}
@ -402,7 +439,6 @@ Rectangle {
Layout.fillWidth: true
Layout.minimumWidth: 15
Layout.preferredWidth: 15
Layout.maximumWidth: 60
Layout.minimumHeight: parent.height
Text {
anchors.left: parent.left
@ -410,7 +446,7 @@ Rectangle {
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: modelData
text: styleData.value
font.pointSize: 9
}
}
@ -434,42 +470,95 @@ Rectangle {
id: splitInfoList
Layout.fillHeight: true
Layout.fillWidth: true
Settings {
id: splitSettings
property alias storageHeightSettings: storageRect.height
property alias memoryDumpHeightSettings: memoryRect.height
property alias callDataHeightSettings: callDataRect.height
}
orientation: Qt.Vertical
width: debugPanel.width - 2 * machineStates.sideMargin
Rectangle
{
id: callStackRect;
color: "transparent"
height: 120
width: parent.width
Layout.minimumHeight: 120
Layout.maximumHeight: 400
CallStack {
anchors.fill: parent
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList
{
id: callStack
onFrameActivated: Debugger.displayFrame(index);
collapsible: true
anchors.fill: parent
title : qsTr("Call Stack")
enableSelection: true
onRowActivated: Debugger.displayFrame(index);
itemDelegate:
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#4A90E2"
visible: styleData.selected;
}
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: 30
Layout.maximumWidth: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.row;
font.pointSize: 9
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width - 30
Layout.maximumWidth: parent.width - 30
Text {
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.Wrap
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value;
elide: Text.ElideRight
font.pointSize: 9
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
}
}
Rectangle
{
id: storageRect
color: "transparent"
width: parent.width
Layout.minimumHeight: 25
Layout.maximumHeight: 223
height: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList
{
id: storage
@ -478,29 +567,24 @@ Rectangle {
title : qsTr("Storage")
itemDelegate:
Item {
height: 27
width: parent.width;
anchors.fill: parent
RowLayout
{
id: row
width: parent.width
height: 26
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.preferredWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Layout.minimumHeight: parent.height
Layout.maximumHeight: parent.height
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: modelData.split('\t')[0];
text: styleData.value.split('\t')[0];
font.pointSize: 9
width: parent.width - 5
elide: Text.ElideRight
@ -511,10 +595,7 @@ Rectangle {
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.preferredWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Layout.minimumHeight: parent.height
Layout.maximumHeight: parent.height
Text {
anchors.leftMargin: 5
width: parent.width - 5
@ -523,7 +604,7 @@ Rectangle {
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: modelData.split('\t')[1];
text: styleData.value.split('\t')[1];
elide: Text.ElideRight
font.pointSize: 9
}
@ -545,10 +626,10 @@ Rectangle {
{
id: memoryRect;
color: "transparent"
height: 25
width: parent.width
Layout.minimumHeight: 25
Layout.maximumHeight: 223
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList {
id: memoryDump
anchors.fill: parent
@ -567,10 +648,10 @@ Rectangle {
{
id: callDataRect
color: "transparent"
height: 25
width: parent.width
Layout.minimumHeight: 25
Layout.maximumHeight: 223
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList {
id: callDataDump
anchors.fill: parent
@ -586,8 +667,9 @@ Rectangle {
}
Rectangle
{
id: bottomRect;
width: parent.width
Layout.minimumHeight: 25
Layout.minimumHeight: 20
color: "transparent"
}
}

243
mix/qml/FilesSection.qml

@ -0,0 +1,243 @@
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.3
import "."
ColumnLayout {
id: wrapperItem
signal documentSelected(string doc, string groupName)
property alias model: filesList.model
property string sectionName;
property variant selManager;
Layout.fillWidth: true
Layout.minimumHeight: hiddenHeightTopLevel()
height: hiddenHeightTopLevel()
Layout.maximumHeight: hiddenHeightTopLevel()
spacing: 0
function hiddenHeightTopLevel()
{
return section.state === "hidden" ? Style.documentsList.height : Style.documentsList.fileNameHeight * model.count + Style.documentsList.height;
}
function hiddenHeightRepeater()
{
return section.state === "hidden" ? 0 : Style.documentsList.fileNameHeight * wrapperItem.model.count;
}
function hiddenHeightElement()
{
return section.state === "hidden" ? 0 : Style.documentsList.fileNameHeight;
}
function getDocumentIndex(documentId)
{
for (var i = 0; i < model.count; i++)
if (model.get(i).documentId === documentId)
return i;
return -1;
}
function removeDocument(documentId)
{
var i = getDocumentIndex(documentId);
if (i !== -1)
model.remove(i);
}
FontLoader
{
id: fileNameFont
source: "qrc:/qml/fonts/SourceSansPro-Regular.ttf"
}
RowLayout
{
anchors.top: parent.top
id: rowCol
width: parent.width
height: Style.documentsList.height
Image {
source: "qrc:/qml/img/opentriangleindicator_filesproject.png"
width: 15
sourceSize.width: 15
id: imgArrow
anchors.right: section.left
anchors.rightMargin: 5
anchors.top: parent.top
anchors.topMargin: 8
}
Text
{
id: section
text: sectionName
anchors.left: parent.left
anchors.leftMargin: Style.general.leftMargin
color: Style.documentsList.sectionColor
font.family: fileNameFont.name
font.pointSize: Style.documentsList.fontSize
font.weight: Font.Bold
font.letterSpacing: 1
states: [
State {
name: "hidden"
PropertyChanges { target: filesList; visible: false; }
PropertyChanges { target: rowCol; Layout.minimumHeight: Style.documentsList.height; Layout.maximumHeight: Style.documentsList.height; height: Style.documentsList.height; }
PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" }
}
]
}
MouseArea {
id: titleMouseArea
anchors.fill: parent
hoverEnabled: true
z: 2
onClicked: {
if (section.state === "hidden")
section.state = "";
else
section.state = "hidden";
}
}
}
ColumnLayout {
height: wrapperItem.hiddenHeightRepeater()
Layout.minimumHeight: wrapperItem.hiddenHeightRepeater()
Layout.preferredHeight: wrapperItem.hiddenHeightRepeater()
Layout.maximumHeight: wrapperItem.hiddenHeightRepeater()
width: parent.width
visible: section.state !== "hidden"
spacing: 0
Repeater
{
id: filesList
visible: section.state !== "hidden"
Rectangle
{
visible: section.state !== "hidden"
id: rootItem
Layout.fillWidth: true
Layout.minimumHeight: wrapperItem.hiddenHeightElement()
Layout.preferredHeight: wrapperItem.hiddenHeightElement()
Layout.maximumHeight: wrapperItem.hiddenHeightElement()
height: wrapperItem.hiddenHeightElement()
color: isSelected ? Style.documentsList.highlightColor : Style.documentsList.background
property bool isSelected
property bool renameMode
Text {
id: nameText
height: parent.height
visible: !renameMode
color: rootItem.isSelected ? Style.documentsList.selectedColor : Style.documentsList.color
text: name;
font.family: fileNameFont.name
font.pointSize: Style.documentsList.fontSize
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
anchors.left: parent.left
anchors.leftMargin: Style.general.leftMargin + 2
width: parent.width
Connections
{
target: selManager
onSelected: {
if (groupName != sectionName)
rootItem.isSelected = false;
else if (doc === documentId)
rootItem.isSelected = true;
else
rootItem.isSelected = false;
}
}
}
TextInput {
id: textInput
text: nameText.text
visible: renameMode
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Style.general.leftMargin
MouseArea {
id: textMouseArea
anchors.fill: parent
hoverEnabled: true
z: 2
onClicked: {
textInput.forceActiveFocus();
}
}
onVisibleChanged: {
if (visible) {
selectAll();
forceActiveFocus();
}
}
onAccepted: close(true);
onCursorVisibleChanged: {
if (!cursorVisible)
close(false);
}
onFocusChanged: {
if (!focus)
close(false);
}
function close(accept) {
rootItem.renameMode = false;
if (accept)
{
var i = getDocumentIndex(documentId);
projectModel.renameDocument(documentId, textInput.text);
wrapperItem.model.set(i, projectModel.getDocument(documentId));
}
}
}
MouseArea {
id: mouseArea
z: 1
hoverEnabled: false
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked:{
if (mouse.button === Qt.RightButton && !isContract)
contextMenu.popup();
else if (mouse.button === Qt.LeftButton)
{
rootItem.isSelected = true;
projectModel.openDocument(documentId);
documentSelected(documentId, groupName);
}
}
}
Menu {
id: contextMenu
MenuItem {
text: qsTr("Rename")
onTriggered: {
rootItem.renameMode = true;
}
}
MenuItem {
text: qsTr("Delete")
onTriggered: {
projectModel.removeDocument(documentId);
wrapperItem.removeDocument(documentId);
}
}
}
}
}
}
}

71
mix/qml/MainContent.qml

@ -7,9 +7,9 @@ import Qt.labs.settings 1.0
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
import "js/TransactionHelper.js" as TransactionHelper
import "."
Rectangle {
objectName: "mainContent"
signal keyPressed(variant event)
focus: true
@ -21,11 +21,12 @@ Rectangle {
anchors.fill: parent
id: root
property alias rightViewVisible : rightView.visible
property alias webViewVisible : webPreview.visible
property alias projectViewVisible : projectList.visible
property alias runOnProjectLoad : mainSettings.runOnProjectLoad
property bool webViewHorizontal : codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally
property alias rightViewVisible: rightView.visible
property alias webViewVisible: webPreview.visible
property alias projectViewVisible: projectList.visible
property alias runOnProjectLoad: mainSettings.runOnProjectLoad
property alias rightPane: rightView
property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally
property bool firstCompile: true
Connections {
@ -76,7 +77,6 @@ Rectangle {
CodeEditorExtensionManager {
headerView: headerPaneTabs;
rightView: rightPaneTabs;
}
Settings {
@ -121,6 +121,12 @@ Rectangle {
}
}
Rectangle{
Layout.fillWidth: true
height: 1
color: "#8c8c8c"
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: root.height - headerView.height;
@ -136,16 +142,16 @@ Rectangle {
{
anchors.fill: parent
handleDelegate: Rectangle {
width: 4
height: 4
color: "#cccccc"
width: 1
height: 1
color: "#8c8c8c"
}
orientation: Qt.Horizontal
ProjectList {
id: projectList
width: 200
Layout.minimumWidth: 180
width: 350
Layout.minimumWidth: 250
Layout.fillHeight: true
}
Rectangle {
@ -154,9 +160,9 @@ Rectangle {
Layout.fillWidth: true
SplitView {
handleDelegate: Rectangle {
width: 4
height: 4
color: "#cccccc"
width: 1
height: 1
color: "#8c8c8c"
}
id: codeWebSplitter
anchors.fill: parent
@ -178,46 +184,13 @@ Rectangle {
}
}
Rectangle {
Debugger {
visible: false;
id: rightView;
Layout.fillHeight: true
Keys.onEscapePressed: visible = false
height: parent.height;
width: 515
Layout.minimumWidth: 515
anchors.right: parent.right
Rectangle {
anchors.fill: parent;
id: rightPaneView
TabView {
id: rightPaneTabs
tabsVisible: true
antialiasing: true
anchors.fill: parent
style: TabViewStyle {
frameOverlap: 1
tabBar:
Rectangle {
color: "#ededed"
id: background
}
tab: Rectangle {
color: "#ededed"
implicitWidth: 80
implicitHeight: 20
radius: 2
Text {
anchors.centerIn: parent
text: styleData.title
color: styleData.selected ? "#7da4cd" : "#202020"
}
}
frame: Rectangle {
}
}
}
}
}
}
}

241
mix/qml/ProjectList.qml

@ -2,138 +2,151 @@ import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.3
import Qt.labs.settings 1.0
import "."
Item {
property bool renameMode: false;
ColumnLayout {
anchors.fill: parent
Text {
Layout.fillWidth: true
color: "blue"
text: projectModel.projectTitle
horizontalAlignment: Text.AlignHCenter
visible: !projectModel.isEmpty;
id: filesCol
spacing: 0
FontLoader
{
id: srcSansProLight
source: "qrc:/qml/fonts/SourceSansPro-Regular.ttf"
}
ListView {
id: projectList
Layout.fillWidth: true
Layout.fillHeight: true
model: projectModel.listModel
Rectangle
{
color: Style.title.background
height: Style.title.height
Layout.fillWidth: true
Image {
id: projectIcon
source: "qrc:/qml/img/projecticon.png"
sourceSize.height: 30
anchors.right: projectTitle.left
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 6
}
delegate: renderDelegate
highlight: Rectangle {
color: "lightsteelblue";
Text
{
id: projectTitle
color: Style.title.color
text: projectModel.projectTitle
anchors.verticalCenter: parent.verticalCenter
visible: !projectModel.isEmpty;
anchors.left: parent.left
anchors.leftMargin: Style.general.leftMargin
font.family: srcSansProLight.name
font.pointSize: Style.title.pointSize
font.weight: Font.Light
}
highlightFollowsCurrentItem: true
focus: true
clip: true
onCurrentIndexChanged: {
if (currentIndex >= 0 && currentIndex < projectModel.listModel.count)
projectModel.openDocument(projectModel.listModel.get(currentIndex).documentId);
Text
{
text: "-"
anchors.right: parent.right
anchors.rightMargin: 15
font.family: srcSansProLight.name
font.pointSize: Style.title.pointSize
anchors.verticalCenter: parent.verticalCenter
}
}
Menu {
id: contextMenu
MenuItem {
text: qsTr("Rename")
onTriggered: {
renameMode = true;
}
}
MenuItem {
text: qsTr("Delete")
onTriggered: {
projectModel.removeDocument(projectList.model.get(projectList.currentIndex).documentId);
}
}
Rectangle
{
Layout.fillWidth: true
height: 10
color: Style.documentsList.background
}
}
Component {
id: renderDelegate
Item {
id: wrapperItem
height: 20
width: parent.width
RowLayout {
anchors.fill: parent
visible: !(index === projectList.currentIndex) || !renameMode
Text {
id: nameText
Layout.fillWidth: true
Layout.fillHeight: true
text: name
font.pointSize: 12
verticalAlignment: Text.AlignBottom
}
}
TextInput {
id: textInput
text: nameText.text
visible: (index === projectList.currentIndex) && renameMode
MouseArea {
id: textMouseArea
anchors.fill: parent
hoverEnabled: true
z:2
onClicked: {
textInput.forceActiveFocus();
}
}
onVisibleChanged: {
if (visible) {
selectAll();
forceActiveFocus();
}
}
onAccepted: close(true);
onCursorVisibleChanged: {
if (!cursorVisible)
close(false);
}
onFocusChanged: {
if (!focus)
close(false);
}
function close(accept) {
renameMode = false;
if (accept)
projectModel.renameDocument(projectList.model.get(projectList.currentIndex).documentId, textInput.text);
}
}
MouseArea {
id: mouseArea
z: 1
hoverEnabled: false
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked:{
projectList.currentIndex = index;
if (mouse.button === Qt.RightButton && !projectList.model.get(index).isContract)
contextMenu.popup();
}
}
}
}
Connections {
target: projectModel
onProjectLoaded: {
projectList.currentIndex = 0;
if (projectList.currentIndex >= 0 && projectList.currentIndex < projectModel.listModel.count)
projectModel.openDocument(projectModel.listModel.get(projectList.currentIndex).documentId);
Rectangle
{
Layout.fillWidth: true
Layout.fillHeight: true
color: Style.documentsList.background
}
onProjectClosed: {
projectList.currentIndex = -1;
}
onDocumentOpened: {
if (projectList.currentItem.documentId !== document.documentId)
projectList.currentIndex = projectModel.getDocumentIndex(document.documentId);
ColumnLayout
{
anchors.top: parent.top
width: parent.width
spacing: 0
Repeater {
model: ["Contracts", "Javascript", "HTML", "Styles", "Images", "Misc"]
signal selected(string doc, string groupName)
id: sectionRepeater
FilesSection
{
sectionName: modelData
model: sectionModel
selManager: sectionRepeater
onDocumentSelected: {
selManager.selected(doc, groupName);
}
ListModel
{
id: sectionModel
}
Connections {
target: codeModel
onCompilationComplete: {
if (modelData === "Contracts")
{
var ctr = projectModel.listModel.get(0);
if (codeModel.code.contract.name !== ctr.name)
{
ctr.name = codeModel.code.contract.name;
projectModel.listModel.set(0, ctr);
sectionModel.set(0, ctr);
}
}
}
}
Connections {
id: projectModelConnection
target: projectModel
function addDocToSubModel()
{
for (var k = 0; k < projectModel.listModel.count; k++)
{
var item = projectModel.listModel.get(k);
if (item.groupName === modelData)
sectionModel.append(item);
}
}
onProjectLoaded: {
addDocToSubModel();
if (modelData === "Contracts")
{
var selItem = projectModel.listModel.get(0);
projectModel.openDocument(selItem.documentId);
sectionRepeater.selected(selItem.documentId, modelData);
}
}
onDocumentAdded:
{
var newDoc = projectModel.getDocument(documentId);
if (newDoc.groupName === modelData)
sectionModel.append(newDoc);
}
}
}
}
}
}
}
}

1
mix/qml/ProjectModel.qml

@ -41,6 +41,7 @@ Item {
function addExistingFile() { ProjectModelCode.addExistingFile(); }
function newHtmlFile() { ProjectModelCode.newHtmlFile(); }
function newJsFile() { ProjectModelCode.newJsFile(); }
function newCssFile() { ProjectModelCode.newCssFile(); }
//function newContract() { ProjectModelCode.newContract(); }
function openDocument(documentId) { ProjectModelCode.openDocument(documentId); }
function openNextDocument() { ProjectModelCode.openNextDocument(); }

58
mix/qml/StateList.qml

@ -3,60 +3,66 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
Rectangle {
color: "#ededed"
Window {
id: stateListContainer
focus: true
anchors.topMargin: 10
anchors.left: parent.left
height: parent.height
width: parent.width
modality: Qt.WindowModal
ListView {
id: list
anchors.top: parent.top
height: parent.height
width: parent.width
model: projectModel.stateListModel
delegate: renderDelegate
}
width: 640
height: 480
Button {
anchors.bottom: parent.bottom
action: addStateAction
visible: false
ColumnLayout
{
anchors.fill: parent
TableView {
id: list
Layout.fillHeight: true
Layout.fillWidth: true
model: projectModel.stateListModel
itemDelegate: renderDelegate
headerDelegate: null
TableViewColumn {
role: "title"
title: qsTr("State")
width: list.width
}
}
Button {
anchors.bottom: parent.bottom
action: addStateAction
}
}
Component {
id: renderDelegate
Item {
id: wrapperItem
height: 20
width: parent.width
RowLayout {
anchors.fill: parent
Text {
Layout.fillWidth: true
Layout.fillHeight: true
text: title
text: styleData.value
font.pointSize: 12
verticalAlignment: Text.AlignBottom
}
ToolButton {
text: qsTr("Edit");
Layout.fillHeight: true
onClicked: list.model.editState(index);
onClicked: list.model.editState(styleData.row);
}
ToolButton {
visible: list.model.count - 1 != index
visible: list.model.defaultStateIndex !== styleData.row
text: qsTr("Delete");
Layout.fillHeight: true
onClicked: list.model.deleteState(index);
onClicked: list.model.deleteState(styleData.row);
}
ToolButton {
text: qsTr("Run");
Layout.fillHeight: true
onClicked: list.model.runState(index);
onClicked: list.model.runState(styleData.row);
}
}
}

10
mix/qml/StateListModel.qml

@ -8,7 +8,6 @@ import "js/QEtherHelper.js" as QEtherHelper
Item {
property int defaultStateIndex: 0
property alias model: stateListModel
property var stateList: []
@ -111,7 +110,7 @@ Item {
for(var i = 0; i < stateListModel.count; i++) {
projectData.states.push(toPlainStateItem(stateList[i]));
}
projectData.defaultStateIndex = defaultStateIndex;
projectData.defaultStateIndex = stateListModel.defaultStateIndex;
}
onNewProject: {
var state = toPlainStateItem(stateListModel.createDefaultState());
@ -127,12 +126,12 @@ Item {
var item = stateDialog.getItem();
if (stateDialog.stateIndex < stateListModel.count) {
if (stateDialog.isDefault)
defaultStateIndex = stateIndex;
stateListModel.defaultStateIndex = stateIndex;
stateList[stateDialog.stateIndex] = item;
stateListModel.set(stateDialog.stateIndex, item);
} else {
if (stateDialog.isDefault)
defaultStateIndex = 0;
stateListModel.defaultStateIndex = 0;
stateList.push(item);
stateListModel.append(item);
}
@ -149,8 +148,10 @@ Item {
ListModel {
id: stateListModel
property int defaultStateIndex: 0
signal defaultStateChanged;
signal stateListModelReady;
signal stateRun(int index)
function defaultTransactionItem() {
return {
@ -205,6 +206,7 @@ Item {
function runState(index) {
var item = stateList[index];
clientModel.setupState(item);
stateRun(index);
}
function deleteState(index) {

29
mix/qml/Style.qml

@ -0,0 +1,29 @@
pragma Singleton
import QtQuick 2.0
/*
* Project Files
*/
QtObject {
property QtObject general: QtObject {
property int leftMargin: 45
}
property QtObject title: QtObject {
property string color: "#808080"
property string background: "#f0f0f0"
property int height: 70
property int pointSize: 18
}
property QtObject documentsList: QtObject {
property string background: "#f7f7f7"
property string color: "#4d4d4d"
property string sectionColor: "#808080"
property string selectedColor: "white"
property string highlightColor: "#4a90e2"
property int height: 32
property int fileNameHeight: 45
property int fontSize: 15
}
}

70
mix/qml/TransactionLog.qml

@ -5,13 +5,69 @@ import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
Item {
Action {
id: addStateAction
text: "Add State"
shortcut: "Ctrl+Alt+T"
enabled: codeModel.hasContract && !clientModel.running;
onTriggered: projectModel.stateListModel.addState();
}
Action {
id: editStateAction
text: "Edit State"
shortcut: "Ctrl+Alt+T"
enabled: codeModel.hasContract && !clientModel.running && statesCombo.currentIndex >= 0 && projectModel.stateListModel.count > 0;
onTriggered: projectModel.stateListModel.editState(statesCombo.currentIndex);
}
ColumnLayout {
anchors.fill: parent
CheckBox {
id: recording
text: qsTr("Record transactions");
checked: true
Layout.fillWidth: true
RowLayout {
ComboBox {
id: statesCombo
model: projectModel.stateListModel
width: 150
editable: false
textRole: "title"
onActivated: {
model.runState(index);
}
Connections {
target: projectModel.stateListModel
onStateRun: {
if (statesCombo.currentIndex !== index)
statesCombo.currentIndex = index;
}
}
}
Button
{
anchors.rightMargin: 9
anchors.verticalCenter: parent.verticalCenter
action: editStateAction
}
Button
{
anchors.rightMargin: 9
anchors.verticalCenter: parent.verticalCenter
action: addStateAction
}
Button
{
anchors.rightMargin: 9
anchors.verticalCenter: parent.verticalCenter
action: mineAction
}
CheckBox {
id: recording
text: qsTr("Record transactions");
checked: true
Layout.fillWidth: true
}
}
TableView {
Layout.fillWidth: true
@ -31,7 +87,7 @@ Item {
TableViewColumn {
role: "contract"
title: qsTr("Contract")
width: 120
width: 100
}
TableViewColumn {
role: "function"
@ -41,7 +97,7 @@ Item {
TableViewColumn {
role: "value"
title: qsTr("Value")
width: 120
width: 60
}
TableViewColumn {
role: "address"

3
mix/qml/WebPreview.qml

@ -114,7 +114,8 @@ Item {
onClientConnected: {
//filter polling spam
//TODO: do it properly
var log = _request.content.indexOf("eth_changed") < 0;
//var log = _request.content.indexOf("eth_changed") < 0;
var log = true;
if (log)
console.log(_request.content);
var response = clientModel.apiCall(_request.content);

BIN
mix/qml/fonts/SourceSansPro-Black.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-BlackIt.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-Bold.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-BoldIt.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-ExtraLight.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-ExtraLightIt.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-It.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-Light.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-LightIt.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-Regular.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-Semibold.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSansPro-SemiboldIt.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSerifPro-Bold.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSerifPro-Regular.ttf

Binary file not shown.

BIN
mix/qml/fonts/SourceSerifPro-Semibold.ttf

Binary file not shown.

BIN
mix/qml/img/closedtriangleindicator_filesproject.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

BIN
mix/qml/img/opentriangleindicator_filesproject.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

BIN
mix/qml/img/projecticon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

7
mix/qml/js/Debugger.js

@ -107,7 +107,7 @@ function select(stateIndex)
callStackData.push(address);
}
callStackData.push(debugData.states[0].address);
callStack.model = callStackData;
callStack.listModel = callStackData;
}
function codeStr(stateIndex)
@ -118,8 +118,9 @@ function codeStr(stateIndex)
function highlightSelection(index)
{
statesList.currentIndex = index;
statesList.positionViewAtIndex(index, ListView.Center);
statesList.positionViewAtRow(index, ListView.Center);
statesList.selection.clear();
statesList.selection.select(index);
}
function completeCtxInformation(state)

12
mix/qml/js/ProjectModel.js

@ -88,7 +88,9 @@ function addFile(fileName) {
var isHtml = extension === ".html";
var isCss = extension === ".css";
var isJs = extension === ".js";
var isImg = extension === ".png" || extension === ".gif" || extension === ".jpg" || extension === ".svg";
var syntaxMode = isContract ? "solidity" : isJs ? "javascript" : isHtml ? "htmlmixed" : isCss ? "css" : "";
var groupName = isContract ? "Contracts" : isJs ? "Javascript" : isHtml ? "HTML" : isCss ? "Styles" : isImg ? "Images" : "Misc";
var docData = {
contract: false,
path: p,
@ -99,6 +101,7 @@ function addFile(fileName) {
isText: isContract || isHtml || isCss || isJs,
isContract: isContract,
isHtml: isHtml,
groupName: groupName
};
projectListModel.append(docData);
@ -153,6 +156,7 @@ function doCloseProject() {
console.log("closing project");
projectListModel.clear();
projectPath = "";
currentDocumentId = "";
projectClosed();
}
@ -172,8 +176,8 @@ function doCreateProject(title, path) {
files: [ contractsFile, indexFile ]
};
//TODO: copy from template
fileIo.writeFile(dirPath + indexFile, "<html>\n<head>\n<script>\nvar web3 = parent.web3;\nvar theContract = parent.contract;\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>");
fileIo.writeFile(dirPath + contractsFile, "contract Contract {\n}\n");
fileIo.writeFile(dirPath + indexFile, "<html>\n<head>\n<script>\nvar web3 = parent.web3;\nvar theContract = parent.contract;\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>");
fileIo.writeFile(dirPath + contractsFile, "contract Contract {\n}\n");
newProject(projectData);
var json = JSON.stringify(projectData, null, "\t");
fileIo.writeFile(projectFile, json);
@ -224,6 +228,10 @@ function newHtmlFile() {
createAndAddFile("page", "html", "<html>\n</html>");
}
function newCssFile() {
createAndAddFile("style", "css", "body {\n}\n");
}
function newJsFile() {
createAndAddFile("script", "js", "function foo() {\n}\n");
}

36
mix/qml/main.qml

@ -15,7 +15,7 @@ ApplicationWindow {
height: 800
minimumWidth: 400
minimumHeight: 300
title: qsTr("mix")
title: qsTr("Mix")
menuBar: MenuBar {
Menu {
@ -28,6 +28,7 @@ ApplicationWindow {
MenuItem { action: addExistingFileAction }
MenuItem { action: addNewJsFileAction }
MenuItem { action: addNewHtmlFileAction }
MenuItem { action: addNewCssFileAction }
MenuSeparator {}
//MenuItem { action: addNewContractAction }
MenuItem { action: closeProjectAction }
@ -39,6 +40,8 @@ ApplicationWindow {
MenuItem { action: debugRunAction }
MenuItem { action: mineAction }
MenuSeparator {}
MenuItem { action: editStatesAction }
MenuSeparator {}
MenuItem { action: toggleRunOnLoadAction }
}
Menu {
@ -48,6 +51,7 @@ ApplicationWindow {
MenuSeparator {}
MenuItem { action: toggleProjectNavigatorAction }
MenuItem { action: showHideRightPanelAction }
MenuItem { action: toggleTransactionLogAction }
MenuItem { action: toggleWebPreviewAction }
MenuItem { action: toggleWebPreviewOrientationAction }
}
@ -88,7 +92,18 @@ ApplicationWindow {
text: qsTr("Mine")
shortcut: "Ctrl+M"
onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running
enabled: codeModel.hasContract && !clientModel.running &&!clientModel.mining
}
StateList {
id: stateList
}
Action {
id: editStatesAction
text: qsTr("Edit States")
shortcut: "Ctrl+Alt+E"
onTriggered: stateList.show();
}
Connections {
@ -120,6 +135,15 @@ ApplicationWindow {
onTriggered: mainContent.toggleWebPreview();
}
Action {
id: toggleTransactionLogAction
text: qsTr("Show States and Transactions")
shortcut: "Alt+1"
checkable: true
checked: mainContent.rightPane.transactionLog.visible
onTriggered: mainContent.rightPane.transactionLog.visible = !mainContent.rightPane.transactionLog.visible
}
Action {
id: toggleProjectNavigatorAction
text: qsTr("Show Project Navigator")
@ -188,6 +212,14 @@ ApplicationWindow {
onTriggered: projectModel.newHtmlFile();
}
Action {
id: addNewCssFileAction
text: qsTr("New CSS File")
shortcut: "Ctrl+Alt+S"
enabled: !projectModel.isEmpty
onTriggered: projectModel.newCssFile();
}
Action {
id: addNewContractAction
text: qsTr("New Contract")

1
mix/qml/qmldir

@ -0,0 +1 @@
singleton Style 1.0 Style.qml

21
mix/res.qrc

@ -63,5 +63,26 @@
<file>res/mix_256x256x32.png</file>
<file>qml/CallStack.qml</file>
<file>qml/QVariableDeclaration.qml</file>
<file>qml/Style.qml</file>
<file>qml/qmldir</file>
<file>qml/FilesSection.qml</file>
<file>qml/fonts/SourceSansPro-Black.ttf</file>
<file>qml/fonts/SourceSansPro-BlackIt.ttf</file>
<file>qml/fonts/SourceSansPro-Bold.ttf</file>
<file>qml/fonts/SourceSansPro-BoldIt.ttf</file>
<file>qml/fonts/SourceSansPro-ExtraLight.ttf</file>
<file>qml/fonts/SourceSansPro-ExtraLightIt.ttf</file>
<file>qml/fonts/SourceSansPro-It.ttf</file>
<file>qml/fonts/SourceSansPro-Light.ttf</file>
<file>qml/fonts/SourceSansPro-LightIt.ttf</file>
<file>qml/fonts/SourceSansPro-Regular.ttf</file>
<file>qml/fonts/SourceSansPro-Semibold.ttf</file>
<file>qml/fonts/SourceSansPro-SemiboldIt.ttf</file>
<file>qml/fonts/SourceSerifPro-Bold.ttf</file>
<file>qml/fonts/SourceSerifPro-Regular.ttf</file>
<file>qml/fonts/SourceSerifPro-Semibold.ttf</file>
<file>qml/img/closedtriangleindicator_filesproject.png</file>
<file>qml/img/opentriangleindicator_filesproject.png</file>
<file>qml/img/projecticon.png</file>
</qresource>
</RCC>

13
pysol/MANIFEST.in

@ -0,0 +1,13 @@
include pysol/*.cpp
include *.py
include libdevcore/*cpp
include libdevcore/*h
include libdevcrypto/*cpp
include libdevcrypto/*h
include libethcore/*cpp
include libethcore/*h
include libsolidity/*cpp
include libsolidity/*h
include libevmcore/*cpp
include libevmcore/*h
include pysol/README.md

0
pysol/README.md

115
pysol/pysolidity.cpp

@ -0,0 +1,115 @@
#include <Python.h>
#include "structmember.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include "../libdevcore/CommonData.h"
#include <libsolidity/Compiler.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/CompilerUtils.h>
#include <libsolidity/SourceReferenceFormatter.h>
std::string compile(std::string src) {
dev::solidity::CompilerStack compiler;
try
{
std::vector<uint8_t> m_data = compiler.compile(src, false);
return std::string(m_data.begin(), m_data.end());
}
catch (dev::Exception const& exception)
{
std::ostringstream error;
dev::solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
std::string e = error.str();
throw(e);
}
}
std::string mk_full_signature(std::string src) {
dev::solidity::CompilerStack compiler;
try
{
compiler.compile(src);
return compiler.getInterface("");
}
catch (dev::Exception const& exception)
{
std::ostringstream error;
dev::solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
std::string e = error.str();
throw(e);
}
}
std::string bob(std::string src) { return src + src; }
#define PYMETHOD(name, FROM, method, TO) \
static PyObject * name(PyObject *, PyObject *args) { \
try { \
FROM(med) \
return TO(method(med)); \
} \
catch (std::string e) { \
PyErr_SetString(PyExc_Exception, e.c_str()); \
return NULL; \
} \
}
#define FROMSTR(v) \
const char *command; \
int len; \
if (!PyArg_ParseTuple(args, "s#", &command, &len)) \
return NULL; \
std::string v = std::string(command, len); \
// Convert string into python wrapper form
PyObject* pyifyString(std::string s) {
return Py_BuildValue("s#", s.c_str(), s.length());
}
// Convert integer into python wrapper form
PyObject* pyifyInteger(unsigned int i) {
return Py_BuildValue("i", i);
}
// Convert pyobject int into normal form
int cppifyInt(PyObject* o) {
int out;
if (!PyArg_Parse(o, "i", &out))
throw("Argument should be integer");
return out;
}
// Convert pyobject string into normal form
std::string cppifyString(PyObject* o) {
const char *command;
if (!PyArg_Parse(o, "s", &command))
throw("Argument should be string");
return std::string(command);
}
int fh(std::string i) {
return dev::fromHex(i[0]);
}
PYMETHOD(ps_compile, FROMSTR, compile, pyifyString)
PYMETHOD(ps_mk_full_signature, FROMSTR, mk_full_signature, pyifyString)
static PyMethodDef PyextMethods[] = {
{"compile", ps_compile, METH_VARARGS,
"Compile code."},
{"mk_full_signature", ps_mk_full_signature, METH_VARARGS,
"Get the signature of a piece of code."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC initsolidity(void)
{
Py_InitModule( "solidity", PyextMethods );
}

41
pysol/setup.py

@ -0,0 +1,41 @@
import os
os.chdir('..')
from setuptools import setup, Extension
from distutils.sysconfig import get_config_vars
(opt,) = get_config_vars('OPT')
os.environ['OPT'] = " ".join(
flag for flag in opt.split() if flag != '-Wstrict-prototypes'
)
setup(
# Name of this package
name="ethereum-solidity",
# Package version
version='1.8.0',
description='Solidity compiler python wrapper',
maintainer='Vitalik Buterin',
maintainer_email='v@buterin.com',
license='WTFPL',
url='http://www.ethereum.org/',
# Describes how to build the actual extension module from C source files.
ext_modules=[
Extension(
'solidity', # Python name of the module
sources= ['libdevcore/Common.cpp', 'libdevcore/CommonData.cpp', 'libdevcore/CommonIO.cpp', 'libdevcore/FixedHash.cpp', 'libdevcore/Guards.cpp', 'libdevcore/Log.cpp', 'libdevcore/RangeMask.cpp', 'libdevcore/RLP.cpp', 'libdevcore/Worker.cpp', 'libdevcrypto/AES.cpp', 'libdevcrypto/Common.cpp', 'libdevcrypto/CryptoPP.cpp', 'libdevcrypto/ECDHE.cpp', 'libdevcrypto/FileSystem.cpp', 'libdevcrypto/MemoryDB.cpp', 'libdevcrypto/OverlayDB.cpp', 'libdevcrypto/SHA3.cpp', 'libdevcrypto/TrieCommon.cpp', 'libdevcrypto/TrieDB.cpp', 'libethcore/CommonEth.cpp', 'libethcore/CommonJS.cpp', 'libethcore/Exceptions.cpp', 'libsolidity/AST.cpp', 'libsolidity/ASTJsonConverter.cpp', 'libsolidity/ASTPrinter.cpp', 'libsolidity/CompilerContext.cpp', 'libsolidity/Compiler.cpp', 'libsolidity/CompilerStack.cpp', 'libsolidity/CompilerUtils.cpp', 'libsolidity/DeclarationContainer.cpp', 'libsolidity/ExpressionCompiler.cpp', 'libsolidity/GlobalContext.cpp', 'libsolidity/InterfaceHandler.cpp', 'libsolidity/NameAndTypeResolver.cpp', 'libsolidity/Parser.cpp', 'libsolidity/Scanner.cpp', 'libsolidity/SourceReferenceFormatter.cpp', 'libsolidity/Token.cpp', 'libsolidity/Types.cpp', 'libevmcore/Assembly.cpp', 'libevmcore/Instruction.cpp', 'pysol/pysolidity.cpp'],
libraries=['boost_python', 'boost_filesystem', 'boost_chrono', 'boost_thread', 'cryptopp', 'leveldb', 'jsoncpp'],
include_dirs=['/usr/include/boost', '..', '../..', '.'],
extra_compile_args=['--std=c++11', '-Wno-unknown-pragmas']
)],
py_modules=[
],
scripts=[
],
entry_points={
}
),

2
sc/CMakeLists.txt

@ -8,7 +8,9 @@ set(EXECUTABLE sc)
add_executable(${EXECUTABLE} ${SRC_LIST})
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
target_link_libraries(${EXECUTABLE} serpent)
endif()
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)

1
test/CMakeLists.txt

@ -22,6 +22,7 @@ target_link_libraries(testeth ethcore)
target_link_libraries(testeth secp256k1)
target_link_libraries(testeth solidity)
target_link_libraries(testeth webthree)
target_link_libraries(testeth natspec)
if (JSONRPC)
target_link_libraries(testeth web3jsonrpc)

18
test/SolidityEndToEndTest.cpp

@ -959,6 +959,24 @@ BOOST_AUTO_TEST_CASE(complex_accessors)
BOOST_CHECK(callContractFunction("to_multiple_map(uint256,uint256)", 42, 23) == encodeArgs(31));
}
BOOST_AUTO_TEST_CASE(struct_accessor)
{
char const* sourceCode = R"(
contract test {
struct Data { uint a; uint8 b; mapping(uint => uint) c; bool d; }
mapping(uint => Data) public data;
function test() {
data[7].a = 1;
data[7].b = 2;
data[7].c[0] = 3;
data[7].d = true;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("data(uint256)", 7) == encodeArgs(1, 2, true));
}
BOOST_AUTO_TEST_CASE(balance)
{
char const* sourceCode = "contract test {\n"

70
test/SolidityExpressionCompiler.cpp

@ -91,7 +91,15 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
{
Parser parser;
ASTPointer<SourceUnit> sourceUnit;
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
try
{
sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)));
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing source code failed with: \n") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
vector<Declaration const*> declarations;
declarations.reserve(_globalDeclarations.size() + 1);
@ -177,6 +185,66 @@ BOOST_AUTO_TEST_CASE(int_literal)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 wei;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 szabo;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_finney_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 finney;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(int_with_ether_ether_subdenomination)
{
char const* sourceCode = R"(
contract test {
function test ()
{
var x = 1 ether;
}
})";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(comparison)
{
char const* sourceCode = "contract test {\n"

28
test/SolidityNameAndTypeResolution.cpp

@ -904,6 +904,34 @@ BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args)
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(disallow_declaration_of_void_type)
{
char const* sourceCode = "contract c { function f() { var x = f(); } }";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units)
{
char const* sourceCodeFine = R"(
contract c {
function c ()
{
a = 115792089237316195423570985008687907853269984665640564039458;
}
uint256 a;
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCodeFine));
char const* sourceCode = R"(
contract c {
function c ()
{
a = 115792089237316195423570985008687907853269984665640564039458 ether;
}
uint256 a;
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_SUITE_END()
}

32
test/SolidityParser.cpp

@ -660,6 +660,38 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
{
char const* text = R"(
contract c {
function c ()
{
a = 1 wei;
b = 2 szabo;
c = 3 finney;
b = 4 ether;
}
uint256 a;
uint256 b;
uint256 c;
uint256 d;
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
}
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expressions)
{
char const* text = R"(
contract c {
function c ()
{
a = 1 wei * 100 wei + 7 szabo - 3;
}
uint256 a;
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
}
BOOST_AUTO_TEST_SUITE_END()
}

9
test/SolidityScanner.cpp

@ -255,6 +255,15 @@ BOOST_AUTO_TEST_CASE(comments_mixed_in_sequence)
BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "documentation comment ");
}
BOOST_AUTO_TEST_CASE(ether_subdenominations)
{
Scanner scanner(CharStream("wei szabo finney ether"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::SubWei);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubSzabo);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubFinney);
BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther);
}
BOOST_AUTO_TEST_SUITE_END()
}

112
test/natspec.cpp

@ -0,0 +1,112 @@
/*
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 natspec.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libnatspec/NatspecExpressionEvaluator.h>
using namespace std;
BOOST_AUTO_TEST_SUITE(natspec)
BOOST_AUTO_TEST_CASE(natspec_eval_function_exists)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`typeof evaluateExpression`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "function");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`1 + 2`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "3");
}
BOOST_AUTO_TEST_CASE(natspec_create_custom_function)
{
// given
NatspecExpressionEvaluator e;
// when
auto x = e.evalExpression("`test = function (x) { return x + 'ok'; }`"); // ommit var, make it global
string result = e.evalExpression("`test(5)`").toStdString();
string result2 = e.evalExpression("`typeof test`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "5ok");
BOOST_CHECK_EQUAL(result2, "function");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval_separated_expressions)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`x = 1` + `y = 2` will be equal `x + y`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "1 + 2 will be equal 3");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval_input_params)
{
// given
char const* abi = R"([
{
"name": "f",
"constant": false,
"type": "function",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
NatspecExpressionEvaluator e(abi, "'f'", "[4]");
// when
string result = e.evalExpression("Will multiply `a` by 7 and return `a * 7`.").toStdString();
// then
BOOST_CHECK_EQUAL(result, "Will multiply 4 by 7 and return 28.");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval_error)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`test(`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "`test(`");
}
BOOST_AUTO_TEST_SUITE_END()

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

Loading…
Cancel
Save