Browse Source

Merge branch 'develop' into jsonrpcstub

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
0e17aa2519
  1. 1
      CMakeLists.txt
  2. 1
      alethzero/CMakeLists.txt
  3. 30
      alethzero/OurWebThreeStubServer.cpp
  4. 16
      alethzero/OurWebThreeStubServer.h
  5. 28
      libethcore/ProofOfWork.h
  6. 103
      libethereum/Client.cpp
  7. 50
      libethereum/Client.h
  8. 5
      libethereum/Interface.h
  9. 12
      libethereum/Miner.cpp
  10. 28
      libethereum/Miner.h
  11. 18
      libethereum/State.cpp
  12. 4
      libethereum/State.h
  13. 1
      libjsqrc/js.qrc
  14. 35
      libnatspec/CMakeLists.txt
  15. 59
      libnatspec/NatspecExpressionEvaluator.cpp
  16. 49
      libnatspec/NatspecExpressionEvaluator.h
  17. 69
      libnatspec/natspec.js
  18. 5
      libnatspec/natspec.qrc
  19. 11
      libsolidity/AST.cpp
  20. 3
      libsolidity/AST.h
  21. 47
      libsolidity/ExpressionCompiler.cpp
  22. 16
      libsolidity/Parser.cpp
  23. 71
      libsolidity/Types.cpp
  24. 3
      libsolidity/Types.h
  25. 12
      libweb3jsonrpc/WebThreeStubServer.h
  26. 14
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  27. 3
      libweb3jsonrpc/WebThreeStubServerBase.h
  28. 12
      libweb3jsonrpc/abstractwebthreestubserver.h
  29. 4
      libweb3jsonrpc/spec.json
  30. 2
      mix/AppContext.cpp
  31. 45
      mix/AssemblyDebuggerControl.cpp
  32. 48
      mix/AssemblyDebuggerControl.h
  33. 1
      mix/ClientModel.h
  34. 8
      mix/CodeEditorExtensionManager.cpp
  35. 7
      mix/ContractCallDataEncoder.cpp
  36. 1
      mix/MixClient.cpp
  37. 2
      mix/MixClient.h
  38. 48
      mix/StateListView.cpp
  39. 45
      mix/StateListView.h
  40. 13
      mix/qml/DebugInfoList.qml
  41. 54
      mix/qml/Debugger.qml
  42. 243
      mix/qml/FilesSection.qml
  43. 71
      mix/qml/MainContent.qml
  44. 241
      mix/qml/ProjectList.qml
  45. 1
      mix/qml/ProjectModel.qml
  46. 58
      mix/qml/StateList.qml
  47. 10
      mix/qml/StateListModel.qml
  48. 29
      mix/qml/Style.qml
  49. 70
      mix/qml/TransactionLog.qml
  50. BIN
      mix/qml/fonts/SourceSansPro-Black.ttf
  51. BIN
      mix/qml/fonts/SourceSansPro-BlackIt.ttf
  52. BIN
      mix/qml/fonts/SourceSansPro-Bold.ttf
  53. BIN
      mix/qml/fonts/SourceSansPro-BoldIt.ttf
  54. BIN
      mix/qml/fonts/SourceSansPro-ExtraLight.ttf
  55. BIN
      mix/qml/fonts/SourceSansPro-ExtraLightIt.ttf
  56. BIN
      mix/qml/fonts/SourceSansPro-It.ttf
  57. BIN
      mix/qml/fonts/SourceSansPro-Light.ttf
  58. BIN
      mix/qml/fonts/SourceSansPro-LightIt.ttf
  59. BIN
      mix/qml/fonts/SourceSansPro-Regular.ttf
  60. BIN
      mix/qml/fonts/SourceSansPro-Semibold.ttf
  61. BIN
      mix/qml/fonts/SourceSansPro-SemiboldIt.ttf
  62. BIN
      mix/qml/fonts/SourceSerifPro-Bold.ttf
  63. BIN
      mix/qml/fonts/SourceSerifPro-Regular.ttf
  64. BIN
      mix/qml/fonts/SourceSerifPro-Semibold.ttf
  65. BIN
      mix/qml/img/closedtriangleindicator_filesproject.png
  66. BIN
      mix/qml/img/opentriangleindicator_filesproject.png
  67. BIN
      mix/qml/img/projecticon.png
  68. 11
      mix/qml/js/ProjectModel.js
  69. 34
      mix/qml/main.qml
  70. 1
      mix/qml/qmldir
  71. 21
      mix/res.qrc
  72. 1
      test/CMakeLists.txt
  73. 18
      test/SolidityEndToEndTest.cpp
  74. 22
      test/SolidityNameAndTypeResolution.cpp
  75. 13
      test/SolidityParser.cpp
  76. 112
      test/natspec.cpp
  77. 30
      test/stRefundTestFiller.json
  78. 70
      test/stSystemOperationsTestFiller.json
  79. 64
      test/stTransactionTestFiller.json
  80. 84
      test/vmSha3TestFiller.json

1
CMakeLists.txt

@ -168,6 +168,7 @@ endif ()
if (NOT HEADLESS)
add_subdirectory(libnatspec)
add_subdirectory(libjsqrc)
add_subdirectory(libqwebthree)
add_subdirectory(alethzero)

1
alethzero/CMakeLists.txt

@ -49,6 +49,7 @@ 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})

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;
};

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;
}

103
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();
}
@ -320,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();
}
@ -330,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;
}
@ -351,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)
@ -474,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.
@ -481,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.
@ -511,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";
@ -534,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.
}
@ -550,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();
}

50
libethereum/Client.h

@ -135,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.
*/
@ -253,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;
@ -295,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.
@ -309,24 +338,27 @@ 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;

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;

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.

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>

11
libsolidity/AST.cpp

@ -596,17 +596,6 @@ void ElementaryTypeNameExpression::checkTypeRequirements()
m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
}
Literal::Literal(Location const& _location, Token::Value _token,
ASTPointer<ASTString> const& _value,
Token::Value _sub):
PrimaryExpression(_location), m_token(_token), m_value(_value)
{
if (Token::isEtherSubdenomination(_sub))
m_subDenomination = static_cast<Literal::SubDenomination>(_sub);
else
m_subDenomination = Literal::SubDenomination::None;
}
void Literal::checkTypeRequirements()
{
m_type = Type::forLiteral(*this);

3
libsolidity/AST.h

@ -1127,7 +1127,8 @@ public:
};
Literal(Location const& _location, Token::Value _token,
ASTPointer<ASTString> const& _value,
Token::Value _sub = Token::ILLEGAL);
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;

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,

16
libsolidity/Parser.cpp

@ -684,7 +684,6 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
ASTNodeFactory nodeFactory(*this);
Token::Value token = m_scanner->getCurrentToken();
ASTPointer<Expression> expression;
Token::Value nextToken = Token::ILLEGAL;
switch (token)
{
case Token::TRUE_LITERAL:
@ -692,12 +691,19 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
break;
case Token::NUMBER:
nextToken = m_scanner->peekNextToken();
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(), nextToken);
if (Token::isEtherSubdenomination(nextToken))
m_scanner->next();
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
break;
case Token::IDENTIFIER:
nodeFactory.markEndPosition();

71
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
@ -326,7 +342,7 @@ string IntegerConstantType::toString() const
return "int_const " + m_value.str();
}
u256 IntegerConstantType::literalValue(Literal const* _literal) const
u256 IntegerConstantType::literalValue(Literal const*) const
{
u256 value;
// we ignore the literal and hope that the type was correctly determined
@ -338,26 +354,6 @@ u256 IntegerConstantType::literalValue(Literal const* _literal) const
else
value = s2u(s256(m_value));
if (_literal)
{
Literal::SubDenomination sub =_literal->getSubDenomination();
switch(sub)
{
case Literal::SubDenomination::Wei:
case Literal::SubDenomination::None:
break;
case Literal::SubDenomination::Szabo:
value *= u256(1000000000000);
break;
case Literal::SubDenomination::Finney:
value *= u256(1000000000000000);
break;
case Literal::SubDenomination::Ether:
value *= u256(1000000000000000000);
break;
}
}
return value;
}
@ -647,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;

14
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -428,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;

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;
};
}
}

1
mix/ClientModel.h

@ -26,6 +26,7 @@
#include <atomic>
#include <map>
#include <QString>
#include <QVariantMap>
#include "MachineStates.h"
namespace dev

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;

1
mix/MixClient.cpp

@ -205,7 +205,6 @@ void MixClient::mine()
m_state.completeMine();
bc().import(m_state.blockData(), m_stateDB);
m_state.sync(bc());
//m_state.cleanup(true);
m_startState = m_state;
m_executions.emplace_back(std::move(m_pendingExecutions));
h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter };

2
mix/MixClient.h

@ -86,6 +86,8 @@ 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);

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;
};
}
}

13
mix/qml/DebugInfoList.qml

@ -9,7 +9,7 @@ ColumnLayout {
property variant listModel;
property bool collapsible;
property bool enableSelection;
property real storedHeight;
property real storedHeight: 0;
property Component itemDelegate
signal rowActivated(int index)
spacing: 0
@ -104,6 +104,17 @@ ColumnLayout {
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

54
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;
@ -62,6 +64,7 @@ Rectangle {
property alias storageHeightSettings: storageRect.height
property alias memoryDumpHeightSettings: memoryRect.height
property alias callDataHeightSettings: callDataRect.height
property alias transactionLogVisible: transactionLog.visible
}
Rectangle
@ -113,45 +116,41 @@ Rectangle {
}
}
ScrollView {
SplitView {
id: debugScrollArea
anchors.fill: parent
orientation: Qt.Vertical
handleDelegate: Rectangle {
height: machineStates.sideMargin
color: "transparent"
}
SplitView
TransactionLog {
id: transactionLog
Layout.fillWidth: true
Layout.minimumHeight: 60
height: 250
}
ScrollView
{
property int sideMargin: 10
id: machineStates
anchors.top: parent.top
anchors.topMargin: 15
anchors.left: parent.left;
anchors.leftMargin: machineStates.sideMargin
width: debugScrollArea.width - machineStates.sideMargin * 2 - 20;
orientation: Qt.Vertical
handleDelegate: Rectangle {
height: machineStates.sideMargin
color: "transparent"
}
Layout.fillWidth: true
Layout.fillHeight: true
function updateHeight() {
machineStates.height = transactionLog.childrenRect.height + buttonRow.childrenRect.height + assemblyCodeRow.childrenRect.height +
statesLayout.height = buttonRow.childrenRect.height + assemblyCodeRow.childrenRect.height +
callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height + 120;
}
Component.onCompleted: updateHeight();
TransactionLog {
id: transactionLog
Layout.fillWidth: true
Layout.minimumHeight: 60
height: 250
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
id: statesLayout
anchors.top: parent.top
anchors.topMargin: 15
anchors.left: parent.left;
anchors.leftMargin: machineStates.sideMargin
width: debugScrollArea.width - machineStates.sideMargin * 2 - 20;
spacing: machineStates.sideMargin
Rectangle {
@ -550,7 +549,6 @@ Rectangle {
}
}
}
}
Rectangle

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"

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

11
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);
@ -173,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);
@ -225,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");
}

34
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 }
}
@ -91,6 +95,17 @@ ApplicationWindow {
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 {
target: projectModel.stateListModel
@ -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>

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"

22
test/SolidityNameAndTypeResolution.cpp

@ -910,6 +910,28 @@ BOOST_AUTO_TEST_CASE(disallow_declaration_of_void_type)
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()
}

13
test/SolidityParser.cpp

@ -679,6 +679,19 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
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()
}

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()

30
test/stRefundTestFiller.json

@ -303,6 +303,34 @@
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
}
},
"RefundOverflow" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "400",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "5789604461865809771178549250434395392663499233282028201972879200395656482016",
"gasPrice" : "20",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : ""
}
}
}

70
test/stSystemOperationsTestFiller.json

@ -33,6 +33,76 @@
}
},
"testRandomTest": {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentGasLimit" : "1000000",
"currentNumber" : "300",
"currentTimestamp" : "2",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x424443444243434383f0155af055",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "10000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"value" : "100000"
}
},
"createWithInvalidOpcode": {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentGasLimit" : "1000000",
"currentNumber" : "300",
"currentTimestamp" : "2",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x444242424245434253f0",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"createNameRegistratorOOG_MemExpansionInsufficientBalance": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

64
test/stTransactionTestFiller.json

@ -169,7 +169,7 @@
},
"pre" :
{
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000",
"code" : "",
"nonce" : "0",
@ -189,6 +189,68 @@
}
},
"TransactionFromCoinbaseHittingBlockGasLimit" : {
"env" : {
"currentCoinbase" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1100",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "1100",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
}
},
"TransactionFromCoinbaseHittingBlockGasLimit1" : {
"env" : {
"currentCoinbase" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1100",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "1101",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
}
},
"ContractStoreClearsSuccess" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",

84
test/vmSha3TestFiller.json

@ -193,5 +193,89 @@
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"sha3_bigSize": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0,
"code" : "{ [[ 0 ]] (SHA3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x10000000000"
}
},
"sha3_bigOffset": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0,
"code" : "{ [[ 0 ]] (SHA3 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 2)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x10000000000"
}
},
"sha3_bigOffset2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0,
"code" : "{ [[ 0 ]] (SHA3 0x1000000 2)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
}
}

Loading…
Cancel
Save