Browse Source

Merge branch 'develop' into p2p-udp-nodetable

cl-refactor
subtly 10 years ago
parent
commit
6658d5be5f
  1. 2
      .gitignore
  2. 68
      alethzero/MainWin.cpp
  3. 15
      docker/Dockerfile
  4. 14
      eth/main.cpp
  5. 2
      evmjit
  6. 4
      exp/main.cpp
  7. 3
      libdevcore/Common.h
  8. 180
      libdevcore/CommonData.cpp
  9. 3
      libdevcore/CommonData.h
  10. 15
      libdevcore/CommonJS.cpp
  11. 8
      libdevcore/CommonJS.h
  12. 1
      libdevcore/vector_ref.h
  13. 2
      libethcore/CommonEth.cpp
  14. 2
      libethereum/BlockChain.cpp
  15. 4
      libethereum/BlockChain.h
  16. 29
      libethereum/Client.cpp
  17. 34
      libethereum/Client.h
  18. 14
      libethereum/Executive.cpp
  19. 9
      libethereum/Executive.h
  20. 4
      libethereum/ExtVM.cpp
  21. 4
      libethereum/ExtVM.h
  22. 8
      libethereum/Precompiled.cpp
  23. 82
      libethereum/State.cpp
  24. 14
      libethereum/State.h
  25. 16
      libethereum/TransactionReceipt.cpp
  26. 2
      libethereum/TransactionReceipt.h
  27. 3
      libevm/ExtVMFace.cpp
  28. 10
      libevm/ExtVMFace.h
  29. 30
      libevm/VM.h
  30. 4
      libevmcore/Instruction.cpp
  31. 2
      libevmcore/Instruction.h
  32. 2
      libp2p/Session.cpp
  33. 2
      libserpent/opcodes.cpp
  34. 6
      libsolidity/ExpressionCompiler.cpp
  35. 2
      libsolidity/SourceReferenceFormatter.h
  36. 24
      mix/AppContext.cpp
  37. 30
      mix/AppContext.h
  38. 171
      mix/AssemblyDebuggerControl.cpp
  39. 84
      mix/AssemblyDebuggerControl.h
  40. 103
      mix/AssemblyDebuggerCtrl.cpp
  41. 70
      mix/AssemblyDebuggerCtrl.h
  42. 69
      mix/AssemblyDebuggerModel.cpp
  43. 14
      mix/AssemblyDebuggerModel.h
  44. 30
      mix/CodeEditorExtensionManager.cpp
  45. 17
      mix/CodeEditorExtensionManager.h
  46. 30
      mix/ConstantCompilationControl.cpp
  47. 15
      mix/ConstantCompilationControl.h
  48. 3
      mix/ConstantCompilationModel.cpp
  49. 10
      mix/ConstantCompilationModel.h
  50. 131
      mix/ContractCallDataEncoder.cpp
  51. 64
      mix/ContractCallDataEncoder.h
  52. 19
      mix/DebuggingStateWrapper.cpp
  53. 74
      mix/DebuggingStateWrapper.h
  54. 5
      mix/Extension.cpp
  55. 11
      mix/Extension.h
  56. 9
      mix/KeyEventManager.h
  57. 1
      mix/MixApplication.h
  58. 30
      mix/QBasicNodeDefinition.h
  59. 48
      mix/QContractDefinition.cpp
  60. 53
      mix/QContractDefinition.h
  61. 37
      mix/QFunctionDefinition.cpp
  62. 58
      mix/QFunctionDefinition.h
  63. 49
      mix/QVariableDeclaration.h
  64. 55
      mix/QVariableDefinition.cpp
  65. 72
      mix/QVariableDefinition.h
  66. 40
      mix/TransactionBuilder.cpp
  67. 221
      mix/TransactionListModel.cpp
  68. 168
      mix/TransactionListModel.h
  69. 56
      mix/TransactionListView.cpp
  70. 54
      mix/TransactionListView.h
  71. 2
      mix/qml.qrc
  72. 5
      mix/qml/AlertMessageDialog.qml
  73. 8
      mix/qml/BasicContent.qml
  74. 1
      mix/qml/BasicMessage.qml
  75. 70
      mix/qml/Debugger.qml
  76. 105
      mix/qml/MainContent.qml
  77. 7
      mix/qml/ModalDialog.qml
  78. 219
      mix/qml/TransactionDialog.qml
  79. 89
      mix/qml/TransactionList.qml
  80. 10
      mix/qml/js/Debugger.js
  81. 6
      mix/qml/main.qml
  82. 2
      test/solidityExecutionFramework.h
  83. 205
      test/stInitCodeTestFiller.json
  84. 106
      test/stSystemOperationsTestFiller.json
  85. 137
      test/stTransactionTestFiller.json
  86. 2
      test/state.cpp
  87. 2
      test/stateOriginal.cpp
  88. 2
      test/vm.cpp
  89. 2392
      test/vmArithmeticTestFiller.json

2
.gitignore

@ -64,3 +64,5 @@ profile
DerivedData
project.pbxproj
evmjit

68
alethzero/MainWin.cpp

@ -106,6 +106,8 @@ static QString contentsOfQResource(std::string const& res)
}
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
Address c_newConfig = Address("d5f9d8d94886e70b06e474c3fb14fd43e2f23970");
Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1");
Main::Main(QWidget *parent) :
QMainWindow(parent),
@ -448,8 +450,29 @@ static Public stringToPublic(QString const& _a)
return Public();
}
static Address g_newNameReg;
QString Main::pretty(dev::Address _a) const
{
static std::map<Address, QString> s_memos;
if (!s_memos.count(_a))
{
if (!g_newNameReg)
g_newNameReg = abiOut<Address>(ethereum()->call(c_newConfig, abiIn(1, (u256)1)));
if (g_newNameReg)
{
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn(2, _a)))));
s_memos[_a] = s;
if (s.size())
return s;
}
}
else
if (s_memos[_a].size())
return s_memos[_a];
h256 n;
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
@ -469,19 +492,47 @@ QString Main::render(dev::Address _a) const
return QString::fromStdString(_a.abridged());
}
Address Main::fromString(QString const& _a) const
string32 fromString(std::string const& _s)
{
string32 ret;
for (unsigned i = 0; i < 32 && i <= _s.size(); ++i)
ret[i] = i < _s.size() ? _s[i] : 0;
return ret;
}
Address Main::fromString(QString const& _n) const
{
if (_a == "(Create Contract)")
if (_n == "(Create Contract)")
return Address();
string sn = _a.toStdString();
static std::map<QString, Address> s_memos;
if (!s_memos.count(_n))
{
if (!g_newNameReg)
g_newNameReg = abiOut<Address>(ethereum()->call(c_newConfig, abiIn(1, (u256)1)));
if (g_newNameReg)
{
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn(0, ::fromString(_n.toStdString()))));
s_memos[_n] = a;
if (a)
return a;
}
}
else
if (s_memos[_n])
return s_memos[_n];
string sn = _n.toStdString();
if (sn.size() > 32)
sn.resize(32);
h256 n;
memcpy(n.data(), sn.data(), sn.size());
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size())
if (_n.size())
{
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a);
@ -489,8 +540,9 @@ Address Main::fromString(QString const& _a) const
if (h256 a = ethereum()->stateAt(m_nameReg, n))
return right160(a);
}
if (_a.size() == 40)
return Address(fromHex(_a.toStdString()));
if (_n.size() == 40)
return Address(fromHex(_n.toStdString()));
else
return Address();
}
@ -1350,7 +1402,7 @@ void Main::on_debugCurrent_triggered()
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
m_executiveState = ethereum()->state(txi + 1, h);
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, 0));
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = m_executiveState.pending()[txi];
m_executiveState = m_executiveState.fromPending(txi);
auto r = t.rlp();
@ -1803,7 +1855,7 @@ void Main::on_debug_clicked()
{
Secret s = i.secret();
m_executiveState = ethereum()->postState();
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, 0));
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s);

15
docker/Dockerfile

@ -7,6 +7,7 @@ RUN apt-get upgrade -y
# Ethereum dependencies
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 )
RUN apt-get install -qy libncurses5-dev
@ -14,15 +15,11 @@ RUN apt-get install -qy libncurses5-dev
# Qt-based GUI
# RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev
# Cryptopp
RUN git clone --depth=1 https://github.com/mmoss/cryptopp.git
RUN cd cryptopp && scons --shared --prefix=/usr
# JSONRPC (version 0.2.1, see https://github.com/ethereum/cpp-ethereum/issues/453 )
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
RUN git clone --depth=1 --branch=0.2.1 https://github.com/cinemast/libjson-rpc-cpp.git
RUN mkdir -p libjson-rpc-cpp/build
RUN cd libjson-rpc-cpp/build && cmake .. && make && make install
# Ethereum PPA
RUN apt-get install -qy software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum
RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev
# Build Ethereum (HEADLESS)
RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum

14
eth/main.cpp

@ -89,6 +89,7 @@ void interactiveHelp()
<< " importConfig <path> Import the config (.RLP) from the path provided." <<endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl
<< " dumpreceipt <block> <index> Dumps a transation receipt." << endl
<< " exit Exits the application." << endl;
}
@ -606,6 +607,17 @@ int main(int argc, char** argv)
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
}
else if (c && cmd == "dumpreceipt")
{
unsigned block;
unsigned index;
iss >> block >> index;
dev::eth::TransactionReceipt r = c->blockChain().receipts(c->blockChain().numberHash(block)).receipts[index];
auto rb = r.rlp();
cout << "RLP: " << RLP(rb) << endl;
cout << "Hex: " << toHex(rb) << endl;
cout << r << endl;
}
else if (c && cmd == "dumptrace")
{
unsigned block;
@ -619,7 +631,7 @@ int main(int argc, char** argv)
dev::eth::State state =c->state(index + 1,c->blockChain().numberHash(block));
if (index < state.pending().size())
{
Executive e(state, 0);
Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();

2
evmjit

@ -1 +1 @@
Subproject commit 1b490244bf4864b96448d56a7cd20f3d5b0a0b9b
Subproject commit 3df5a125fa0baa579528abce80402118cad803fd

4
exp/main.cpp

@ -21,13 +21,13 @@
*/
#include <functional>
#include <libethereum/AccountDiff.h>
#include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h>
#include <libdevcore/CommonIO.h>
#include <libp2p/All.h>
#include <libdevcore/RangeMask.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/All.h>
#include <liblll/All.h>
@ -91,7 +91,7 @@ int main()
Transaction t(0, 10000, 10000, c, bytes(), 0, u.secret());
cnote << "Transaction: " << t;
cnote << s.balance(c);
s.execute(t.rlp());
s.execute(LastHashes(), t.rlp());
cnote << "State after transaction: " << s;
cnote << before.diff(s);
}

3
libdevcore/Common.h

@ -80,6 +80,9 @@ using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>;
// Fixed-length string types.
using string32 = std::array<char, 32>;
// Null/Invalid values for convenience.
static const u256 Invalid256 = ~(u256)0;
static const bytes NullBytes;

180
libdevcore/CommonData.cpp

@ -123,180 +123,10 @@ bytes dev::asNibbles(std::string const& _s)
return ret;
}
#if 0
/* Following code is copyright 2012-2014 Luke Dashjr
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details.
*/
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#include <cstring>
static const int8_t b58digits_map[] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
{
size_t binsz = *binszp;
const unsigned char *b58u = (void*)b58;
unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
unsigned zerocount = 0;
if (!b58sz)
b58sz = strlen(b58);
memset(outi, 0, outisz * sizeof(*outi));
// Leading zeros, just count
for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i)
++zerocount;
for ( ; i < b58sz; ++i)
{
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits_map[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
}
for (; j < outisz; ++j)
{
*(binu++) = (outi[j] >> 0x18) & 0xff;
*(binu++) = (outi[j] >> 0x10) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff;
*(binu++) = (outi[j] >> 0) & 0xff;
}
// Count canonical base58 byte count
binu = bin;
for (i = 0; i < binsz; ++i)
{
if (binu[i])
break;
--*binszp;
}
*binszp += zerocount;
return true;
}
static
bool my_dblsha256(void *hash, const void *data, size_t datasz)
std::string dev::toString(string32 const& _s)
{
uint8_t buf[0x20];
return b58_sha256_impl(buf, data, datasz) && b58_sha256_impl(hash, buf, sizeof(buf));
}
int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz)
{
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4)
return -4;
if (!my_dblsha256(buf, bin, binsz - 4))
return -2;
if (memcmp(&binc[binsz - 4], buf, 4))
return -1;
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
{} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1')
return -3;
return binc[0];
}
static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
const uint8_t *bin = data;
int carry;
size_t i, j, high, zcount = 0;
size_t size;
while (zcount < binsz && !bin[zcount])
++zcount;
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t buf[size];
memset(buf, 0, size);
for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
{
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
{
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
}
}
for (j = 0; j < size && !buf[j]; ++j);
if (*b58sz <= zcount + size - j)
{
*b58sz = zcount + size - j + 1;
return false;
}
if (zcount)
memset(b58, '1', zcount);
for (i = zcount; j < size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
return true;
std::string ret;
for (unsigned i = 0; i < 32 && _s[i]; ++i)
ret.push_back(_s[i]);
return ret;
}
#endif

3
libdevcore/CommonData.h

@ -236,4 +236,7 @@ inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b)
return ret += _b;
}
/// Make normal string from fixed-length string.
std::string toString(string32 const& _s);
}

15
libdevcore/CommonJS.cpp

@ -42,8 +42,6 @@ bytes padded(bytes _b, unsigned _l)
{
while (_b.size() < _l)
_b.insert(_b.begin(), 0);
while (_b.size() < _l)
_b.push_back(0);
return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
}
@ -54,15 +52,23 @@ bytes unpadded(bytes _b)
return _b;
}
std::string unpadLeft(std::string _b)
{
auto p = _b.find_first_not_of('0');
if (p == std::string::npos)
return "0";
return _b.substr(p, _b.length() - 1);
}
std::string prettyU256(u256 _n)
{
unsigned inc = 0;
std::string raw;
std::ostringstream s;
if (!(_n >> 64))
s << " " << (uint64_t)_n << " (0x" << (uint64_t)_n << ")";
s << " " << (uint64_t)_n << " (0x" << std::hex << (uint64_t)_n << ")";
else if (!~(_n >> 64))
s << " " << (int64_t)_n << " (0x" << (int64_t)_n << ")";
s << " " << (int64_t)_n << " (0x" << std::hex << (int64_t)_n << ")";
else if ((_n >> 160) == 0)
{
Address a = right160(_n);
@ -113,5 +119,4 @@ Address fromString(std::string const& _sn)
return Address();
}
}

8
libdevcore/CommonJS.h

@ -46,11 +46,19 @@ inline std::string toJS(dev::bytes const& _n)
return "0x" + dev::toHex(_n);
}
/// Convert string to byte array. Input parameters can be hex or dec. Returns empty array if invalid input e.g neither dec or hex.
bytes jsToBytes(std::string const& _s);
/// Add '0' on the head of _b until _l.
bytes padded(bytes _b, unsigned _l);
/// Removing all trailing '0'. Returns empty array if input contains only '0' char.
bytes unpadded(bytes _s);
/// Remove all '0' on the head of _s. Returns 0 if _s contains only '0'.
std::string unpadLeft(std::string _s);
/// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256.
std::string prettyU256(u256 _n);
/// Convert h256 into user-readable string (by directly using std::string constructor).
std::string fromRaw(h256 _n, unsigned* _inc = nullptr);
/// Convert string to Address (h160), returns empty address if (_a.size != 40).
Address fromString(std::string const& _a);
template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)

1
libdevcore/vector_ref.h

@ -41,6 +41,7 @@ public:
void retarget(_T const* _d, size_t _s) { m_data = _d; m_count = _s; }
void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); }
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
_T* begin() { return m_data; }
_T* end() { return m_data + m_count; }

2
libethcore/CommonEth.cpp

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

2
libethereum/BlockChain.cpp

@ -71,7 +71,7 @@ std::map<Address, Account> const& dev::eth::genesisState()
return s_ret;
}
BlockInfo* BlockChain::s_genesis = nullptr;
std::unique_ptr<BlockInfo> BlockChain::s_genesis;
boost::shared_mutex BlockChain::x_genesis;
ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub)

4
libethereum/BlockChain.h

@ -132,7 +132,7 @@ public:
h256Set allUnclesFrom(h256 _parent) const;
/// @returns the genesis block header.
static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); (s_genesis = new BlockInfo)->populate(&gb); } return *s_genesis; }
static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); s_genesis.reset(new BlockInfo); s_genesis->populate(&gb); } return *s_genesis; }
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
@ -211,7 +211,7 @@ private:
/// Static genesis info and its lock.
static boost::shared_mutex x_genesis;
static BlockInfo* s_genesis;
static std::unique_ptr<BlockInfo> s_genesis;
};
std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);

29
libethereum/Client.cpp

@ -27,6 +27,7 @@
#include <libdevcore/Log.h>
#include <libp2p/Host.h>
#include "Defaults.h"
#include "Executive.h"
#include "EthereumHost.h"
using namespace std;
using namespace dev;
@ -343,7 +344,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
n = temp.transactionsFrom(toAddress(_secret));
}
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
u256 gasUsed = temp.execute(t.rlp(), &out, false);
u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false);
(void)gasUsed; // TODO: do something with gasused which it returns.
}
catch (...)
@ -353,6 +354,30 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
return out;
}
bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice)
{
try
{
State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
{
ReadGuard l(x_stateDB);
temp = m_postMine;
}
Executive e(temp, LastHashes(), 0);
if (!e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address()))
{
e.go();
return e.out().toBytes();
}
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
return bytes();
}
Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
startWorking();
@ -442,7 +467,7 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ";
h512s newPendingBlooms = m_postMine.sync(m_tq);
h512s newPendingBlooms = m_postMine.sync(m_bc, m_tq);
if (newPendingBlooms.size())
{
for (auto i: newPendingBlooms)

34
libethereum/Client.h

@ -25,6 +25,8 @@
#include <mutex>
#include <list>
#include <atomic>
#include <string>
#include <array>
#include <boost/utility.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
@ -105,6 +107,35 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-"
#define cworkin dev::LogOutputStream<dev::eth::WorkInChannel, true>()
#define cworkout dev::LogOutputStream<dev::eth::WorkOutChannel, true>()
template <class T> struct ABISerialiser {};
template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { return _t.asBytes(); } };
template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } };
template <> struct ABISerialiser<u160> { static bytes serialise(u160 const& _t) { return h160(_t).asBytes(); } };
template <> struct ABISerialiser<string32> { static bytes serialise(string32 const& _t) { return bytesConstRef((byte const*)_t.data(), 32).toBytes(); } };
inline bytes abiInAux() { return {}; }
template <class T, class ... U> bytes abiInAux(T const& _t, U const& ... _u)
{
return ABISerialiser<T>::serialise(_t) + abiInAux(_u ...);
}
template <class ... T> bytes abiIn(byte _id, T const& ... _t)
{
return bytes(1, _id) + abiInAux(_t ...);
}
template <class T> struct ABIDeserialiser {};
template <unsigned N> struct ABIDeserialiser<FixedHash<N>> { static FixedHash<N> deserialise(bytesConstRef& io_t) { FixedHash<N> ret; io_t.cropped(0, N).populate(ret.ref()); return ret; } };
template <> struct ABIDeserialiser<u256> { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian<u256>(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } };
template <> struct ABIDeserialiser<u160> { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian<u160>(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } };
template <> struct ABIDeserialiser<string32> { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref<char>(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } };
template <class T> T abiOut(bytes const& _data)
{
bytesConstRef o(&_data);
return ABIDeserialiser<T>::deserialise(o);
}
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@ -135,6 +166,9 @@ public:
/// Makes the given call. Nothing is recorded into the state.
virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
/// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH.
virtual bytes call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether);
// Informational stuff
// [NEW API]

14
libethereum/Executive.cpp

@ -1,16 +1,13 @@
/*
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/>.
*/
@ -29,12 +26,19 @@
#include "State.h"
#include "ExtVM.h"
#include "Precompiled.h"
#include "BlockChain.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
#define ETH_VMTRACE 1
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
m_s(_s),
m_lastHashes(_s.getLastHashes(_bc)),
m_depth(_level)
{}
u256 Executive::gasUsed() const
{
return m_t.gas() - m_endGas;
@ -123,7 +127,7 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen
{
m_vm = VMFactory::create(_gas);
bytes const& c = m_s.code(_codeAddress);
m_ext = make_shared<ExtVM>(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth);
}
else
m_endGas = _gas;
@ -143,7 +147,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init.
m_vm = VMFactory::create(_gas);
m_ext = make_shared<ExtVM>(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
return _init.empty();
}

9
libethereum/Executive.h

@ -1,16 +1,13 @@
/*
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/>.
*/
@ -34,6 +31,7 @@ namespace eth
{
class State;
class BlockChain;
class ExtVM;
struct Manifest;
@ -52,7 +50,9 @@ class Executive
{
public:
/// Basic constructor.
Executive(State& _s, unsigned _level): m_s(_s), m_depth(_level) {}
Executive(State& _s, LastHashes const& _lh, unsigned _level): m_s(_s), m_lastHashes(_lh), m_depth(_level) {}
/// Basic constructor.
Executive(State& _s, BlockChain const& _bc, unsigned _level);
/// Basic destructor.
~Executive() = default;
@ -102,6 +102,7 @@ public:
private:
State& m_s; ///< The state to which this operation/transaction is applied.
LastHashes m_lastHashes;
std::shared_ptr<ExtVM> m_ext; ///< The VM externality object for the VM execution or null if no VM is required.
std::unique_ptr<VMFace> m_vm; ///< The VM object or null if no VM is required.
bytes m_precompiledOut; ///< Used for the output when there is no VM for a contract (i.e. precompiled).

4
libethereum/ExtVM.cpp

@ -28,7 +28,7 @@ using namespace dev::eth;
bool ExtVM::call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp, Address _myAddressOverride, Address _codeAddressOverride)
{
Executive e(m_s, depth + 1);
Executive e(m_s, lastHashes, depth + 1);
if (!e.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, io_gas, origin))
{
e.go(_onOp);
@ -45,7 +45,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
Executive e(m_s, depth + 1);
Executive e(m_s, lastHashes, depth + 1);
if (!e.create(myAddress, _endowment, gasPrice, io_gas, _code, origin))
{
e.go(_onOp);

4
libethereum/ExtVM.h

@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache)
ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache)
{
m_s.ensureCached(_myAddress, true, true);
}

8
libethereum/Precompiled.cpp

@ -75,11 +75,17 @@ static bytes ripemd160Code(bytesConstRef _in)
return ret;
}
static bytes identityCode(bytesConstRef _in)
{
return _in.toBytes();
}
static const std::map<unsigned, PrecompiledAddress> c_precompiled =
{
{ 1, { [](bytesConstRef) -> bigint { return (bigint)500; }, ecrecoverCode }},
{ 2, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, sha256Code }},
{ 3, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, ripemd160Code }}
{ 3, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, ripemd160Code }},
{ 4, { [](bytesConstRef i) -> bigint { return (bigint)1 + (i.size() + 31) / 32 * 1; }, identityCode }}
};
std::map<unsigned, PrecompiledAddress> const& dev::eth::precompiled()

82
libethereum/State.cpp

@ -114,7 +114,7 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
m_ourAddress = bi.coinbaseAddress;
sync(_bc, bi.parentHash, bip);
enact(&b);
enact(&b, _bc);
}
State::State(State const& _s):
@ -319,7 +319,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{
auto b = _bc.block(*it);
enact(&b);
enact(&b, _bc);
cleanup(true);
}
}
@ -348,7 +348,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
sync(_bc, _bi.parentHash);
resetCurrent();
m_previousBlock = biParent;
return enact(_block, &_bc);
return enact(_block, _bc);
}
map<Address, u256> State::addresses() const
@ -412,12 +412,14 @@ bool State::cull(TransactionQueue& _tq) const
return ret;
}
h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
// TRANSACTIONS
h512s ret;
auto ts = _tq.transactions();
auto lh = getLastHashes(_bc);
for (int goodTxs = 1; goodTxs;)
{
goodTxs = 0;
@ -429,7 +431,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
uncommitToMine();
// boost::timer t;
execute(i.second);
execute(lh, i.second);
ret.push_back(m_receipts.back().bloom());
_tq.noteGood(i);
++goodTxs;
@ -467,7 +469,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
return ret;
}
u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
{
// m_currentBlock is assumed to be prepopulated and reset.
@ -496,6 +498,8 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
LastHashes lh = getLastHashes(_bc);
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
for (auto const& tr: RLP(_block)[1])
@ -504,26 +508,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
k << i;
transactionsTrie.insert(&k.out(), tr.data());
// cnote << m_state.root() << m_state;
// cnote << *this;
execute(tr.data());
execute(lh, tr.data());
RLPStream receiptrlp;
m_receipts.back().streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
/*
if (tr[1].toHash<h256>() != m_state.root())
{
// Invalid state root
cnote << m_state.root() << "\n" << m_state;
cnote << *this;
cnote << "INVALID: " << tr[1].toHash<h256>();
BOOST_THROW_EXCEPTION(InvalidTransactionStateRoot());
}
if (tr[2].toInt<u256>() != gasUsed())
BOOST_THROW_EXCEPTION(InvalidTransactionGasUsed());
*/
++i;
}
@ -535,7 +524,20 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
if (receiptsTrie.root() != m_currentBlock.receiptsRoot)
{
cwarn << "Bad receipts state root!";
cwarn << "Bad receipts state root.";
cwarn << "Block:" << toHex(_block);
cwarn << "Block RLP:" << RLP(_block);
cwarn << "Want: " << receiptsTrie.root() << ", got: " << m_currentBlock.receiptsRoot;
for (unsigned j = 0; j < i; ++j)
{
RLPStream k;
k << j;
auto b = asBytes(receiptsTrie.at(&k.out()));
cwarn << j << ": ";
cwarn << "RLP: " << RLP(b);
cwarn << "Hex: " << toHex(b);
cwarn << TransactionReceipt(&b);
}
BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
}
@ -551,7 +553,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
// Check uncles & apply their rewards to state.
set<h256> nonces = { m_currentBlock.nonce };
Addresses rewarded;
set<h256> knownUncles = _bc ? _bc->allUnclesFrom(m_currentBlock.parentHash) : set<h256>();
set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
for (auto const& i: RLP(_block)[2])
{
if (knownUncles.count(sha3(i.data())))
@ -560,13 +562,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
BlockInfo uncle = BlockInfo::fromHeader(i.data());
if (nonces.count(uncle.nonce))
BOOST_THROW_EXCEPTION(DuplicateUncleNonce());
if (_bc)
{
BlockInfo uncleParent(_bc->block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6)
BOOST_THROW_EXCEPTION(UncleTooOld());
uncle.verifyParent(uncleParent);
}
BlockInfo uncleParent(_bc.block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
BOOST_THROW_EXCEPTION(UncleTooOld());
uncle.verifyParent(uncleParent);
nonces.insert(uncle.nonce);
tdIncrease += uncle.difficulty;
@ -648,7 +648,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
cnote << "PARANOIA root:" << s.rootHash();
// s.m_currentBlock.populate(&block.out(), false);
// s.m_currentBlock.verifyInternals(&block.out());
s.enact(&block.out(), &_bc, false); // don't check nonce for this since we haven't mined it yet.
s.enact(&block.out(), _bc, false); // don't check nonce for this since we haven't mined it yet.
s.cleanup(false);
return true;
}
@ -993,9 +993,21 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
LastHashes State::getLastHashes(BlockChain const& _bc) const
{
LastHashes ret;
ret.resize(256);
if (c_protocolVersion > 49)
{
unsigned n = (unsigned)m_previousBlock.number;
for (unsigned i = 0; i < 256; ++i)
ret[i] = _bc.numberHash(std::max<unsigned>(n, i) - i);
}
return ret;
}
u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, bool _commit)
{
#ifndef ETH_RELEASE
commit(); // get an updated hash
@ -1008,7 +1020,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
auto h = rootHash();
#endif
Executive e(*this, 0);
Executive e(*this, _lh, 0);
e.setup(_rlp);
u256 startGasUsed = gasUsed();

14
libethereum/State.h

@ -143,14 +143,18 @@ public:
/// @returns a list of bloom filters one for each transaction placed from the queue into the state.
/// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue
/// changed and the pointer is non-null
h512s sync(TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
h512s sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
/// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const;
LastHashes getLastHashes(BlockChain const& _bc) const;
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
u256 execute(bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(&_rlp, o_output, _commit); }
u256 execute(bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), &_rlp, o_output, _commit); }
u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), _rlp, o_output, _commit); }
u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); }
u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }
@ -268,9 +272,9 @@ private:
/// Retrieve all information about a given address into a cache.
void ensureCached(std::map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const;
/// Execute the given block, assuming it corresponds to m_currentBlock. If _bc is passed, it will be used to check the uncles.
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
u256 enact(bytesConstRef _block, BlockChain const* _bc = nullptr, bool _checkNonce = true);
u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true);
/// Finalise the block, applying the earned rewards.
void applyRewards(Addresses const& _uncleAddresses);

16
libethereum/TransactionReceipt.cpp

@ -49,3 +49,19 @@ void TransactionReceipt::streamRLP(RLPStream& _s) const
for (LogEntry const& l: m_log)
l.streamRLP(_s);
}
std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionReceipt const& _r)
{
_out << "Root: " << _r.stateRoot() << std::endl;
_out << "Gas used: " << _r.gasUsed() << std::endl;
_out << "Logs: " << _r.log().size() << " entries:" << std::endl;
for (LogEntry const& i: _r.log())
{
_out << "Address " << i.address << ". Topics:" << std::endl;
for (auto const& j: i.topics)
_out << " " << j << std::endl;
_out << " Data: " << toHex(i.data) << std::endl;
}
_out << "Bloom: " << _r.bloom() << std::endl;
return _out;
}

2
libethereum/TransactionReceipt.h

@ -57,5 +57,7 @@ private:
using TransactionReceipts = std::vector<TransactionReceipt>;
std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r);
}
}

3
libevm/ExtVMFace.cpp

@ -25,7 +25,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth):
ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth):
myAddress(_myAddress),
caller(_caller),
origin(_origin),
@ -33,6 +33,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256
gasPrice(_gasPrice),
data(_data),
code(_code),
lastHashes(_lh),
previousBlock(_previousBlock),
currentBlock(_currentBlock),
depth(_depth)

10
libevm/ExtVMFace.h

@ -93,6 +93,8 @@ struct SubState
class ExtVMFace;
class VM;
using LastHashes = std::vector<h256>;
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, VM*, ExtVMFace const*)>;
/**
@ -105,7 +107,7 @@ public:
ExtVMFace() = default;
/// Full constructor.
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth);
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth);
virtual ~ExtVMFace() = default;
@ -145,6 +147,9 @@ public:
/// Revert any changes made (by any of the other calls).
virtual void revert() {}
/// Hash of a block if within the last 256 blocks, or h256() otherwise.
h256 prevhash(u256 _number) { return _number < currentBlock.number && _number > (std::max<u256>(257, currentBlock.number) - 257) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } // TODO: CHECK!!!
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; }
@ -155,7 +160,8 @@ public:
u256 gasPrice; ///< Price of gas (that we already paid).
bytesConstRef data; ///< Current input data.
bytes code; ///< Current code that is executing.
BlockInfo previousBlock; ///< The previous block's information.
LastHashes lastHashes; ///< Most recent 256 blocks' hashes.
BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE
BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth = 0; ///< Depth of the present call.

30
libevm/VM.h

@ -83,29 +83,9 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; };
if (m_jumpDests.empty())
{
std::set<u256> implicit;
for (unsigned i = 0; i < _ext.code.size(); ++i)
if (_ext.code[i] == (byte)Instruction::JUMPDEST)
m_jumpDests.insert(i);
else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32)
{
int in = _ext.code[i] - (unsigned)Instruction::PUSH1 + 1;
u256 p = 0;
for (i++; in--; i++)
p = (p << 8) | _ext.getCode(i);
if ((_ext.getCode(i) == (byte)Instruction::JUMP || _ext.getCode(i) == (byte)Instruction::JUMPI) && !(_ext.getCode(p) == (byte)Instruction::JUMP || _ext.getCode(p) == (byte)Instruction::JUMPI))
if (p >= _ext.code.size())
m_jumpDests.insert(p);
else
implicit.insert(p);
else {}
i--;
}
for (unsigned i = 0; i < _ext.code.size(); i += instructionInfo((Instruction)_ext.getCode(i)).additional + 1)
if (implicit.count(i))
m_jumpDests.insert(i);
}
u256 nextPC = m_curPC + 1;
auto osteps = _steps;
@ -198,7 +178,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
require(1);
runGas = c_balanceGas;
break;
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
@ -240,6 +219,10 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
break;
}
case Instruction::BLOCKHASH:
require(1);
break;
case Instruction::PC:
case Instruction::MSIZE:
case Instruction::GAS:
@ -251,7 +234,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
case Instruction::CALLDATASIZE:
case Instruction::CODESIZE:
case Instruction::GASPRICE:
case Instruction::PREVHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
@ -580,8 +562,8 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
case Instruction::GASPRICE:
m_stack.push_back(_ext.gasPrice);
break;
case Instruction::PREVHASH:
m_stack.push_back(_ext.previousBlock.hash);
case Instruction::BLOCKHASH:
m_stack.back() = (u256)_ext.prevhash(m_stack.back());
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);

4
libevmcore/Instruction.cpp

@ -67,7 +67,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "GASPRICE", Instruction::GASPRICE },
{ "EXTCODESIZE", Instruction::EXTCODESIZE },
{ "EXTCODECOPY", Instruction::EXTCODECOPY },
{ "PREVHASH", Instruction::PREVHASH },
{ "BLOCKHASH", Instruction::BLOCKHASH },
{ "COINBASE", Instruction::COINBASE },
{ "TIMESTAMP", Instruction::TIMESTAMP },
{ "NUMBER", Instruction::NUMBER },
@ -200,7 +200,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false } },
{ Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false } },
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true } },
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1, false } },
{ Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false } },
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1, false } },

2
libevmcore/Instruction.h

@ -73,7 +73,7 @@ enum class Instruction: uint8_t
EXTCODESIZE, ///< get external code size (from another contract)
EXTCODECOPY, ///< copy external code (from another contract)
PREVHASH = 0x40, ///< get hash of most recent complete block
BLOCKHASH = 0x40, ///< get hash of most recent complete block
COINBASE, ///< get the block's coinbase address
TIMESTAMP, ///< get the block's timestamp
NUMBER, ///< get the block's number

2
libp2p/Session.cpp

@ -195,7 +195,7 @@ bool Session::interpret(RLP const& _r)
// "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments"
stringstream capslog;
for (auto cap: caps)
capslog << "(" << hex << cap.first << "," << hex << cap.second << ")";
capslog << "(" << cap.first << "," << dec << cap.second << ")";
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort;

2
libserpent/opcodes.cpp

@ -44,7 +44,7 @@ Mapping mapping[] = {
Mapping("GASPRICE", 0x3a, 0, 1),
Mapping("EXTCODESIZE", 0x3b, 1, 1),
Mapping("EXTCODECOPY", 0x3c, 4, 0),
Mapping("PREVHASH", 0x40, 0, 1),
Mapping("BLOCKHASH", 0x40, 1, 1),
Mapping("COINBASE", 0x41, 0, 1),
Mapping("TIMESTAMP", 0x42, 0, 1),
Mapping("NUMBER", 0x43, 0, 1),

6
libsolidity/ExpressionCompiler.cpp

@ -344,9 +344,9 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
m_context << eth::Instruction::COINBASE;
else if (member == "timestamp")
m_context << eth::Instruction::TIMESTAMP;
else if (member == "prevhash")
m_context << eth::Instruction::PREVHASH;
else if (member == "difficulty")
/* else if (member == "blockhash")
m_context << eth::Instruction::BLOCKHASH;
*/ else if (member == "difficulty")
m_context << eth::Instruction::DIFFICULTY;
else if (member == "number")
m_context << eth::Instruction::NUMBER;

2
libsolidity/SourceReferenceFormatter.h

@ -28,7 +28,7 @@
namespace dev
{
class Exception; // forward
struct Exception; // forward
namespace solidity
{

24
mix/AppContext.cpp

@ -26,12 +26,15 @@
#include <QMessageBox>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include "libdevcrypto/FileSystem.h"
#include <libwebthree/WebThree.h>
#include <libdevcrypto/FileSystem.h>
#include <libsolidity/CompilerStack.h>
#include "KeyEventManager.h"
#include "AppContext.h"
using namespace dev;
using namespace dev::mix;
using namespace dev::eth;
using namespace dev::solidity;
using namespace dev::mix;
AppContext* AppContext::Instance = nullptr;
@ -40,6 +43,7 @@ AppContext::AppContext(QQmlApplicationEngine* _engine)
m_applicationEngine = std::unique_ptr<QQmlApplicationEngine>(_engine);
m_keyEventManager = std::unique_ptr<KeyEventManager>(new KeyEventManager());
m_webThree = std::unique_ptr<dev::WebThreeDirect>(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"}));
m_compiler = std::unique_ptr<CompilerStack>(new CompilerStack()); //TODO : to move in a codel model structure.
}
QQmlApplicationEngine* AppContext::appEngine()
@ -47,11 +51,6 @@ QQmlApplicationEngine* AppContext::appEngine()
return m_applicationEngine.get();
}
dev::eth::Client* AppContext::getEthereumClient()
{
return m_webThree->ethereum();
}
void AppContext::initKeyEventManager(QObject* _res)
{
QObject* mainContent = _res->findChild<QObject*>("mainContent", Qt::FindChildrenRecursively);
@ -66,6 +65,11 @@ KeyEventManager* AppContext::getKeyEventManager()
return m_keyEventManager.get();
}
CompilerStack* AppContext::compiler()
{
return m_compiler.get();
}
void AppContext::setApplicationContext(QQmlApplicationEngine* _engine)
{
if (Instance == nullptr)
@ -74,9 +78,9 @@ void AppContext::setApplicationContext(QQmlApplicationEngine* _engine)
void AppContext::displayMessageDialog(QString _title, QString _message)
{
QObject* dialogWin = m_applicationEngine.get()->rootObjects().at(0)->findChild<QObject*>("alertMessageDialog", Qt::FindChildrenRecursively);
QObject* dialogWinComponent = m_applicationEngine.get()->rootObjects().at(0)->findChild<QObject*>("alertMessageDialogContent", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
// TODO : move to a UI dedicated layer.
QObject* dialogWin = m_applicationEngine->rootObjects().at(0)->findChild<QObject*>("alertMessageDialog", Qt::FindChildrenRecursively);
QObject* dialogWinComponent = m_applicationEngine->rootObjects().at(0)->findChild<QObject*>("alertMessageDialogContent", Qt::FindChildrenRecursively);
dialogWinComponent->setProperty("source", QString("qrc:/qml/BasicMessage.qml"));
dialogWin->setProperty("title", _title);
dialogWin->setProperty("width", "250");

30
mix/AppContext.h

@ -27,28 +27,48 @@
#pragma once
#include <memory>
#include <QQmlApplicationEngine>
#include "libwebthree/WebThree.h"
#include <libsolidity/CompilerStack.h>
#include <libwebthree/WebThree.h>
#include "KeyEventManager.h"
namespace dev
{
class WebThreeDirect;
namespace solidity
{
class CompilerStack;
}
}
namespace dev
{
namespace mix
{
/**
* @brief Provides access to application scope variable.
*/
class AppContext: public QObject
{
Q_OBJECT
public:
AppContext(QQmlApplicationEngine* _engine);
~AppContext() {}
/// Get the current QQmlApplicationEngine instance.
static AppContext* getInstance() { return Instance; }
/// Renew QQMLApplicationEngine with a new instance.
static void setApplicationContext(QQmlApplicationEngine* _engine);
/// Get the current QQMLApplicationEngine instance.
QQmlApplicationEngine* appEngine();
dev::eth::Client* getEthereumClient();
/// Initialize KeyEventManager (used to handle key pressed event).
void initKeyEventManager(QObject* _obj);
/// Get the current KeyEventManager instance.
KeyEventManager* getKeyEventManager();
/// Get the current Compiler instance (used to parse and compile contract code).
dev::solidity::CompilerStack* compiler();
/// Display an alert message.
void displayMessageDialog(QString _title, QString _message);
private:
@ -56,12 +76,14 @@ private:
std::unique_ptr<QQmlApplicationEngine> m_applicationEngine;
std::unique_ptr<dev::WebThreeDirect> m_webThree;
std::unique_ptr<KeyEventManager> m_keyEventManager;
std::unique_ptr<solidity::CompilerStack> m_compiler;
public slots:
/// Delete the current instance when application quit.
void quitApplication() { delete Instance; }
/// Initialize components after the loading of the main QML view.
void resourceLoaded(QObject* _obj, QUrl _url) { Q_UNUSED(_url); initKeyEventManager(_obj); }
};
}
}

171
mix/AssemblyDebuggerControl.cpp

@ -0,0 +1,171 @@
/*
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 <QtConcurrent/QtConcurrent>
#include <QDebug>
#include <QVariableDefinition.h>
#include <QQmlContext>
#include <QModelIndex>
#include <libdevcore/CommonJS.h>
#include <libethereum/Transaction.h>
#include "AssemblyDebuggerModel.h"
#include "AssemblyDebuggerControl.h"
#include "KeyEventManager.h"
#include "AppContext.h"
#include "DebuggingStateWrapper.h"
#include "TransactionListModel.h"
#include "QContractDefinition.h"
#include "QVariableDeclaration.h"
#include "ContractCallDataEncoder.h"
using namespace dev::eth;
using namespace dev::mix;
AssemblyDebuggerControl::AssemblyDebuggerControl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::ModalDialog)
{
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*");
qRegisterMetaType<QList<QVariableDefinition*>>("QList<QVariableDefinition*>");
qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
qRegisterMetaType<AssemblyDebuggerData>("AssemblyDebuggerData");
qRegisterMetaType<DebuggingStatusResult>("DebuggingStatusResult");
connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList<QVariableDefinition*>, QList<QObject*>, AssemblyDebuggerData)),
this, SLOT(updateGUI(bool, DebuggingStatusResult, QList<QVariableDefinition*>, QList<QObject*>, AssemblyDebuggerData)), Qt::QueuedConnection);
m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
m_compilation = std::unique_ptr<ConstantCompilationModel>(new ConstantCompilationModel);
m_doc = _doc;
}
QString AssemblyDebuggerControl::contentUrl() const
{
return QStringLiteral("qrc:/qml/Debugger.qml");
}
QString AssemblyDebuggerControl::title() const
{
return QApplication::tr("debugger");
}
void AssemblyDebuggerControl::start() const
{
//start to listen on F5
m_ctx->getKeyEventManager()->registerEvent(this, SLOT(keyPressed(int)));
}
void AssemblyDebuggerControl::keyPressed(int _key)
{
if (_key == Qt::Key_F5)
{
QtConcurrent::run([this]()
{
deployContract(m_doc->toPlainText());
});
}
else if (_key == Qt::Key_F6)
{
m_modelDebugger->resetState();
AppContext::getInstance()->displayMessageDialog(QApplication::tr("State status"), QApplication::tr("State reseted ... need to redeploy contract"));
}
}
void AssemblyDebuggerControl::callContract(TransactionSettings _tr, dev::Address _contract)
{
CompilerResult compilerRes = m_compilation->compile(m_doc->toPlainText());
if (!compilerRes.success)
AppContext::getInstance()->displayMessageDialog("debugger","compilation failed");
else
{
ContractCallDataEncoder c;
std::shared_ptr<QContractDefinition> contractDef = QContractDefinition::Contract(m_doc->toPlainText());
QFunctionDefinition* f = nullptr;
for (int k = 0; k < contractDef->functions().size(); k++)
{
if (contractDef->functions().at(k)->name() == _tr.functionId)
{
f = (QFunctionDefinition*)contractDef->functions().at(k);
break;
}
}
if (!f)
AppContext::getInstance()->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("function not found. Please redeploy this contract."));
else
{
c.encode(f->index());
for (int k = 0; k < f->parameters().size(); k++)
{
QVariableDeclaration* var = (QVariableDeclaration*)f->parameters().at(k);
c.encode(var, _tr.parameterValues[var->name()]);
}
DebuggingContent debuggingContent = m_modelDebugger->callContract(_contract, c.encodedData(), _tr);
debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue);
finalizeExecution(debuggingContent);
}
}
}
void AssemblyDebuggerControl::deployContract(QString _source)
{
CompilerResult compilerRes = m_compilation->compile(_source);
if (!compilerRes.success)
emit dataAvailable(false, DebuggingStatusResult::Compilationfailed);
else
{
m_previousDebugResult = m_modelDebugger->deployContract(compilerRes.bytes);
finalizeExecution(m_previousDebugResult);
}
}
void AssemblyDebuggerControl::finalizeExecution(DebuggingContent _debuggingContent)
{
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < _debuggingContent.machineStates.size(); i++)
{
QPointer<DebuggingStateWrapper> s(new DebuggingStateWrapper(_debuggingContent.executionCode, _debuggingContent.executionData.toBytes()));
s->setState(_debuggingContent.machineStates.at(i));
wStates.append(s);
}
AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(_debuggingContent.executionCode);
emit dataAvailable(true, DebuggingStatusResult::Ok, _debuggingContent.returnParameters, wStates, code);
}
void AssemblyDebuggerControl::updateGUI(bool _success, DebuggingStatusResult const& _reason, QList<QVariableDefinition*> const& _returnParam, QList<QObject*> const& _wStates, AssemblyDebuggerData const& _code)
{
Q_UNUSED(_reason);
if (_success)
{
m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates));
m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code)));
m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code)));
m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam)));
this->addContentOn(this);
}
else
m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("compilation failed"));
}
void AssemblyDebuggerControl::runTransaction(TransactionSettings const& _tr)
{
QtConcurrent::run([this, _tr]()
{
callContract(_tr, m_previousDebugResult.contractAddress);
});
}

84
mix/AssemblyDebuggerControl.h

@ -0,0 +1,84 @@
/*
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 <QKeySequence>
#include <QTextDocument>
#include "Extension.h"
#include "ConstantCompilationModel.h"
#include "TransactionListModel.h"
#include "AssemblyDebuggerModel.h"
#include "AppContext.h"
using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>;
enum DebuggingStatusResult
{
Ok,
Compilationfailed
};
Q_DECLARE_METATYPE(AssemblyDebuggerData)
Q_DECLARE_METATYPE(DebuggingStatusResult)
Q_DECLARE_METATYPE(dev::mix::DebuggingContent)
namespace dev
{
namespace mix
{
/**
* @brief Extension which display transaction creation or transaction call debugging. handle: F5 to deploy contract, F6 to reset state.
*/
class AssemblyDebuggerControl: public Extension
{
Q_OBJECT
public:
AssemblyDebuggerControl(QTextDocument* _doc);
~AssemblyDebuggerControl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
private:
void deployContract(QString _source);
void callContract(TransactionSettings _tr, Address _contract);
void finalizeExecution(DebuggingContent _content);
std::unique_ptr<AssemblyDebuggerModel> m_modelDebugger;
std::unique_ptr<ConstantCompilationModel> m_compilation;
DebuggingContent m_previousDebugResult; //TODO: to be replaced in a more consistent struct. Used for now to keep the contract address in case of future transaction call.
QTextDocument* m_doc;
public slots:
/// Handle key pressed. F5 deploy contract - F6 reset state.
void keyPressed(int);
/// Update UI with machine states result. Display a modal dialog.
void updateGUI(bool _success, DebuggingStatusResult const& _reason, QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData());
/// Run the given transaction.
void runTransaction(TransactionSettings const& _tr);
signals:
/// Emited when machine states are available.
void dataAvailable(bool _success, DebuggingStatusResult const& _reason, QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData());
};
}
}

103
mix/AssemblyDebuggerCtrl.cpp

@ -1,103 +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 AssemblyDebuggerCtrl.h
* @author Yann yann@ethdev.com
* @date 2014
* display opcode debugging.
*/
#include <QtConcurrent/QtConcurrent>
#include <QDebug>
#include <QQmlContext>
#include <QModelIndex>
#include "libethereum/Transaction.h"
#include "AssemblyDebuggerModel.h"
#include "AssemblyDebuggerCtrl.h"
#include "TransactionBuilder.h"
#include "KeyEventManager.h"
#include "AppContext.h"
#include "DebuggingStateWrapper.h"
using namespace dev::mix;
AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::ModalDialog)
{
qRegisterMetaType<AssemblyDebuggerData>();
qRegisterMetaType<DebuggingStatusResult>();
connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList<QObject*>, AssemblyDebuggerData)),
this, SLOT(updateGUI(bool, DebuggingStatusResult, QList<QObject*>, AssemblyDebuggerData)), Qt::QueuedConnection);
m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
m_doc = _doc;
}
QString AssemblyDebuggerCtrl::contentUrl() const
{
return QStringLiteral("qrc:/qml/Debugger.qml");
}
QString AssemblyDebuggerCtrl::title() const
{
return QApplication::tr("debugger");
}
void AssemblyDebuggerCtrl::start() const
{
//start to listen on F5
m_ctx->getKeyEventManager()->registerEvent(this, SLOT(keyPressed(int)));
}
void AssemblyDebuggerCtrl::keyPressed(int _key)
{
if (_key == Qt::Key_F5)
{
QString code = m_doc->toPlainText();
QtConcurrent::run([this, code]()
{
if (!m_modelDebugger->compile(m_doc->toPlainText()))
{
emit dataAvailable(false, DebuggingStatusResult::Compilationfailed);
return;
}
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
DebuggingContent debuggingContent = m_modelDebugger->getContractInitiationDebugStates(amount, gasPrice, gas, m_doc->toPlainText());
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.states.size(); i++)
{
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes(), this);
s->setState(debuggingContent.states.at(i));
wStates.append(s);
}
AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode, this);
emit dataAvailable(true, DebuggingStatusResult::Ok, wStates, code);
});
}
}
void AssemblyDebuggerCtrl::updateGUI(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates, AssemblyDebuggerData _code)
{
Q_UNUSED(reason);
if (success)
{
m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates));
m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code)));
m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code)));
this->addContentOn(this);
}
else
m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("compilation failed"));
}

70
mix/AssemblyDebuggerCtrl.h

@ -1,70 +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 AssemblyDebuggerCtrl.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QKeySequence>
#include "QTextDocument"
#include "Extension.h"
#include "ConstantCompilationModel.h"
#include "AssemblyDebuggerModel.h"
#include "AppContext.h"
using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>;
enum DebuggingStatusResult
{
Ok,
Compilationfailed
};
Q_DECLARE_METATYPE(AssemblyDebuggerData)
Q_DECLARE_METATYPE(DebuggingStatusResult)
namespace dev
{
namespace mix
{
class AssemblyDebuggerCtrl: public Extension
{
Q_OBJECT
public:
AssemblyDebuggerCtrl(QTextDocument*);
~AssemblyDebuggerCtrl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
private:
std::unique_ptr<AssemblyDebuggerModel> m_modelDebugger;
QTextDocument* m_doc;
public slots:
void keyPressed(int);
void updateGUI(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates = QList<QObject*>(), AssemblyDebuggerData _code = AssemblyDebuggerData());
signals:
void dataAvailable(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates = QList<QObject*>(), AssemblyDebuggerData _code = AssemblyDebuggerData());
};
}
}

69
mix/AssemblyDebuggerModel.cpp

@ -11,7 +11,7 @@
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 AssemblyDebuggerModel.h
/** @file AssemblyDebuggerModel.cpp
* @author Yann yann@ethdev.com
* @date 2014
* used as a model to debug contract assembly code.
@ -24,7 +24,7 @@
#include <libethereum/Transaction.h>
#include <libethereum/ExtVM.h>
#include "AppContext.h"
#include "TransactionBuilder.h"
#include "TransactionListModel.h"
#include "AssemblyDebuggerModel.h"
#include "ConstantCompilationModel.h"
#include "DebuggingStateWrapper.h"
@ -38,15 +38,14 @@ AssemblyDebuggerModel::AssemblyDebuggerModel():
m_baseState(Address(), m_overlayDB, BaseState::Empty)
{
m_baseState.addBalance(m_userAccount.address(), 10000000 * ether);
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, 0));
m_executiveState = m_baseState;
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, LastHashes(), 0));
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::bytesConstRef _rawTransaction)
DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction)
{
// Reset the state back to our clean premine.
m_executiveState = m_baseState;
QList<DebuggingState> states;
QList<DebuggingState> machineStates;
m_currentExecution.reset(new Executive(m_executiveState, LastHashes(), 0));
m_currentExecution->setup(_rawTransaction);
std::vector<DebuggingState const*> levels;
bytes code;
@ -65,21 +64,21 @@ DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::by
}
if (levels.size() < ext.depth)
levels.push_back(&states.back());
levels.push_back(&machineStates.back());
else
levels.resize(ext.depth);
states.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
machineStates.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
m_currentExecution->go(onOp);
cdebug << states.size();
m_currentExecution->finalize(onOp);
m_executiveState.completeMine();
DebuggingContent d;
d.states = states;
d.returnValue = m_currentExecution->out().toVector();
d.machineStates = machineStates;
d.executionCode = code;
d.executionData = data;
d.contentAvailable = true;
@ -87,34 +86,32 @@ DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::by
return d;
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(
dev::u256 _value,
dev::u256 _gasPrice,
dev::u256 _gas,
QString _code
)
DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code)
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(_code);
if (!res.success)
{
DebuggingContent r;
r.contentAvailable = false;
r.message = QApplication::tr("compilation failed");
return r;
}
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
Transaction _tr(amount, gasPrice, min(gas, m_baseState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
bytes b = _tr.rlp();
dev::bytesConstRef bytesRef = &b;
DebuggingContent d = executeTransaction(bytesRef);
h256 th = sha3(rlpList(_tr.sender(), _tr.nonce()));
d.contractAddress = right160(th);
return d;
}
TransactionBuilder trBuild;
Transaction tr = trBuild.getCreationTransaction(_value, _gasPrice, min(_gas, m_baseState.gasLimitRemaining()), res.bytes,
m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)
{
Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_baseState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
bytes b = tr.rlp();
dev::bytesConstRef bytesRef = &b;
return getContractInitiationDebugStates(bytesRef);
DebuggingContent d = executeTransaction(bytesRef);
d.contractAddress = tr.receiveAddress();
return d;
}
bool AssemblyDebuggerModel::compile(QString _code)
void AssemblyDebuggerModel::resetState()
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(_code);
return res.success;
// Reset the state back to our clean premine.
m_executiveState = m_baseState;
}

14
mix/AssemblyDebuggerModel.h

@ -14,7 +14,7 @@
/** @file AssemblyDebuggerModel.h
* @author Yann yann@ethdev.com
* @date 2014
* serves as a model to debug contract assembly code.
* Used as a model to debug contract assembly code.
*/
#pragma once
@ -26,6 +26,7 @@
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include "DebuggingStateWrapper.h"
#include "TransactionListModel.h"
namespace dev
{
@ -39,9 +40,12 @@ class AssemblyDebuggerModel
{
public:
AssemblyDebuggerModel();
DebuggingContent getContractInitiationDebugStates(u256, u256, u256, QString);
DebuggingContent getContractInitiationDebugStates(bytesConstRef);
bool compile(QString);
/// Call function in a already deployed contract.
DebuggingContent callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
/// Deploy the contract described by _code.
DebuggingContent deployContract(bytes const& _code);
/// Reset state to the base state.
void resetState();
private:
KeyPair m_userAccount;
@ -49,8 +53,8 @@ private:
eth::State m_baseState;
eth::State m_executiveState;
std::unique_ptr<eth::Executive> m_currentExecution;
DebuggingContent executeTransaction(dev::bytesConstRef const& _rawTransaction);
};
}
}

30
mix/CodeEditorExtensionManager.cpp

@ -26,8 +26,9 @@
#include <QQmlComponent>
#include <QQuickTextDocument>
#include <libevm/VM.h>
#include "ConstantCompilationCtrl.h"
#include "AssemblyDebuggerCtrl.h"
#include "ConstantCompilationControl.h"
#include "AssemblyDebuggerControl.h"
#include "TransactionListView.h"
#include "AppContext.h"
#include "CodeEditorExtensionManager.h"
using namespace dev::mix;
@ -48,7 +49,17 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
{
QQuickTextDocument* qqdoc = doc.value<QQuickTextDocument*>();
if (qqdoc)
{
m_doc = qqdoc->textDocument();
auto args = QApplication::arguments();
if (args.length() > 1)
{
QString path = args[1];
QFile file(path);
if (file.exists() && file.open(QFile::ReadOnly))
m_doc->setPlainText(file.readAll());
}
}
}
}
catch (...)
@ -59,8 +70,12 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
void CodeEditorExtensionManager::initExtensions()
{
initExtension(std::make_shared<ConstantCompilationCtrl>(m_doc));
initExtension(std::make_shared<AssemblyDebuggerCtrl>(m_doc));
initExtension(std::make_shared<ConstantCompilationControl>(m_doc));
std::shared_ptr<AssemblyDebuggerControl> debug = std::make_shared<AssemblyDebuggerControl>(m_doc);
std::shared_ptr<TransactionListView> tr = std::make_shared<TransactionListView>(m_doc);
QObject::connect(tr->model(), &TransactionListModel::transactionStarted, debug.get(), &AssemblyDebuggerControl::runTransaction);
initExtension(debug);
initExtension(tr);
}
void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext)
@ -71,6 +86,8 @@ void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext)
{
if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::Tab)
_ext->addTabOn(m_tabView);
else if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::RightTab)
_ext->addTabOn(m_rightTabView);
}
catch (...)
{
@ -88,6 +105,11 @@ void CodeEditorExtensionManager::setEditor(QQuickItem* _editor)
this->initExtensions();
}
void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView)
{
m_rightTabView = _tabView;
}
void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView)
{
m_tabView = _tabView;

17
mix/CodeEditorExtensionManager.h

@ -22,40 +22,49 @@
#pragma once
#include "memory"
#include <QQuickItem>
#include <QTextDocument>
#include <QVector>
#include "ConstantCompilationCtrl.h"
#include "ConstantCompilationControl.h"
namespace dev
{
namespace mix
{
/**
* @brief Init and provides connection between extensions.
*/
class CodeEditorExtensionManager: public QObject
{
Q_OBJECT
Q_PROPERTY(QQuickItem* editor MEMBER m_editor WRITE setEditor)
Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView)
Q_PROPERTY(QQuickItem* rightTabView MEMBER m_rightTabView WRITE setRightTabView)
public:
CodeEditorExtensionManager() {}
~CodeEditorExtensionManager();
/// Initialize all extensions.
void initExtensions();
/// Initialize extension.
void initExtension(std::shared_ptr<Extension>);
/// Set current text editor.
void setEditor(QQuickItem*);
/// Set current tab view
void setTabView(QQuickItem*);
/// Set current right tab view.
void setRightTabView(QQuickItem*);
private:
QQuickItem* m_editor;
QVector<std::shared_ptr<Extension>> m_features;
QQuickItem* m_tabView;
QQuickItem* m_rightTabView;
QTextDocument* m_doc;
void loadEditor(QQuickItem*);
void loadEditor(QQuickItem* _editor);
};
}
}

30
mix/ConstantCompilationCtrl.cpp → mix/ConstantCompilationControl.cpp

@ -14,56 +14,58 @@
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 ConstantCompilationCtrl.cpp
/** @file ConstantCompilationControl.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QQmlContext>
#include <QQuickItem>
#include <QtCore/QFileInfo>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtCore/QtCore>
#include <QDebug>
#include "ConstantCompilationCtrl.h"
#include "ConstantCompilationControl.h"
#include "ConstantCompilationModel.h"
#include "QContractDefinition.h"
using namespace dev::mix;
ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::Tab)
ConstantCompilationControl::ConstantCompilationControl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::Tab)
{
m_editor = _doc;
m_compilationModel = std::unique_ptr<ConstantCompilationModel>(new ConstantCompilationModel());
}
QString ConstantCompilationCtrl::contentUrl() const
QString ConstantCompilationControl::contentUrl() const
{
return QStringLiteral("qrc:/qml/BasicContent.qml");
}
QString ConstantCompilationCtrl::title() const
QString ConstantCompilationControl::title() const
{
return QApplication::tr("compiler");
}
void ConstantCompilationCtrl::start() const
void ConstantCompilationControl::start() const
{
connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile()));
}
void ConstantCompilationCtrl::compile()
void ConstantCompilationControl::compile()
{
QString codeContent = m_editor->toPlainText().replace("\n", "");
if (codeContent.isEmpty())
{
resetOutPut();
return;
else
{
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText().replace("\t", " "));
writeOutPut(res);
}
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText().replace("\t", " "));
writeOutPut(res);
}
void ConstantCompilationCtrl::resetOutPut()
void ConstantCompilationControl::resetOutPut()
{
QObject* status = m_view->findChild<QObject*>("status", Qt::FindChildrenRecursively);
QObject* content = m_view->findChild<QObject*>("content", Qt::FindChildrenRecursively);
@ -71,7 +73,7 @@ void ConstantCompilationCtrl::resetOutPut()
content->setProperty("text", "");
}
void ConstantCompilationCtrl::writeOutPut(CompilerResult const& _res)
void ConstantCompilationControl::writeOutPut(CompilerResult const& _res)
{
QObject* status = m_view->findChild<QObject*>("status", Qt::FindChildrenRecursively);
QObject* content = m_view->findChild<QObject*>("content", Qt::FindChildrenRecursively);
@ -80,13 +82,11 @@ void ConstantCompilationCtrl::writeOutPut(CompilerResult const& _res)
status->setProperty("text", "succeeded");
status->setProperty("color", "green");
content->setProperty("text", _res.hexCode);
qDebug() << QString(QApplication::tr("compile succeeded") + " " + _res.hexCode);
}
else
{
status->setProperty("text", "failure");
status->setProperty("color", "red");
content->setProperty("text", _res.comment);
qDebug() << QString(QApplication::tr("compile failed") + " " + _res.comment);
}
}

15
mix/ConstantCompilationCtrl.h → mix/ConstantCompilationControl.h

@ -11,7 +11,7 @@
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 ConstantCompilationCtrl.h
/** @file ConstantCompilationControl.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
@ -28,13 +28,16 @@ namespace dev
namespace mix
{
class ConstantCompilationCtrl: public Extension
/**
* @brief Extension which display assembly code of the contract being edited.
*/
class ConstantCompilationControl: public Extension
{
Q_OBJECT
public:
ConstantCompilationCtrl(QTextDocument*);
~ConstantCompilationCtrl() {}
ConstantCompilationControl(QTextDocument* _doc);
~ConstantCompilationControl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
@ -42,13 +45,13 @@ public:
private:
QTextDocument* m_editor;
std::unique_ptr<ConstantCompilationModel> m_compilationModel;
void writeOutPut(CompilerResult const&);
void writeOutPut(CompilerResult const& _res);
void resetOutPut();
public slots:
/// Compile text editor content.
void compile();
};
}
}

3
mix/ConstantCompilationModel.cpp

@ -24,13 +24,16 @@
#include <QObject>
#include <libevm/VM.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libsolidity/NameAndTypeResolver.h>
#include "ConstantCompilationModel.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
using namespace dev::solidity;
CompilerResult ConstantCompilationModel::compile(QString _code)
{

10
mix/ConstantCompilationModel.h

@ -22,14 +22,18 @@
#pragma once
#include <libevm/VM.h>
#include <QObject>
#include <libevm/VM.h>
#include <libsolidity/AST.h>
namespace dev
{
namespace mix
{
/**
* @brief Provides compiler result information.
*/
struct CompilerResult
{
QString hexCode;
@ -38,12 +42,16 @@ struct CompilerResult
bool success;
};
/**
* @brief Compile source code using the solidity library.
*/
class ConstantCompilationModel
{
public:
ConstantCompilationModel() {}
~ConstantCompilationModel() {}
/// Compile code.
CompilerResult compile(QString _code);
};

131
mix/ContractCallDataEncoder.cpp

@ -0,0 +1,131 @@
/*
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 ContractCallDataEncoder.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QDebug>
#include <QMap>
#include <QStringList>
#include <libdevcore/CommonJS.h>
#include <libsolidity/AST.h>
#include "QVariableDeclaration.h"
#include "QVariableDefinition.h"
#include "ContractCallDataEncoder.h"
using namespace dev;
using namespace dev::solidity;
using namespace dev::mix;
bytes ContractCallDataEncoder::encodedData()
{
return m_encodedData;
}
void ContractCallDataEncoder::encode(int _functionIndex)
{
bytes i = jsToBytes(std::to_string(_functionIndex));
m_encodedData.insert(m_encodedData.end(), i.begin(), i.end());
}
void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, bool _value)
{
return encode(_dec, QString(formatBool(_value)));
}
void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, QString _value)
{
int padding = this->padding(_dec->type());
bytes data = padded(jsToBytes(_value.toStdString()), padding);
m_encodedData.insert(m_encodedData.end(), data.begin(), data.end());
}
void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, u256 _value)
{
int padding = this->padding(_dec->type());
std::ostringstream s;
s << std::hex << "0x" << _value;
bytes data = padded(jsToBytes(s.str()), padding);
m_encodedData.insert(m_encodedData.end(), data.begin(), data.end());
encodedData();
}
QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> _returnParameters, bytes _value)
{
QList<QVariableDefinition*> r;
std::string returnValue = toJS(_value);
returnValue = returnValue.substr(2, returnValue.length() - 1);
for (int k = 0; k <_returnParameters.length(); k++)
{
QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k);
int padding = this->padding(dec->type());
std::string rawParam = returnValue.substr(0, padding * 2);
r.append(new QVariableDefinition(dec, convertToReadable(unpadLeft(rawParam), dec)));
returnValue = returnValue.substr(rawParam.length(), returnValue.length() - 1);
}
return r;
}
int ContractCallDataEncoder::padding(QString type)
{
// TODO : to be improved (load types automatically from solidity library).
if (type.indexOf("uint") != -1)
return integerPadding(type.remove("uint").toInt());
else if (type.indexOf("int") != -1)
return integerPadding(type.remove("int").toInt());
else if (type.indexOf("bool") != -1)
return 1;
else if ((type.indexOf("address") != -1))
return 20;
else
return 0;
}
int ContractCallDataEncoder::integerPadding(int bitValue)
{
return bitValue / 8;
}
QString ContractCallDataEncoder::formatBool(bool _value)
{
return (_value ? "1" : "0");
}
QString ContractCallDataEncoder::convertToReadable(std::string _v, QVariableDeclaration* _dec)
{
if (_dec->type().indexOf("int") != -1)
return convertToInt(_v);
else if (_dec->type().indexOf("bool") != -1)
return convertToBool(_v);
else
return QString::fromStdString(_v);
}
QString ContractCallDataEncoder::convertToBool(std::string _v)
{
return _v == "1" ? "true" : "false";
}
QString ContractCallDataEncoder::convertToInt(std::string _v)
{
//TO DO to be improve to manage all int, uint size (128, 256, ...) in ethereum QML types task #612.
int x = std::stol(_v, nullptr, 16);
std::stringstream ss;
ss << std::dec << x;
return QString::fromStdString(ss.str());
}

64
mix/ContractCallDataEncoder.h

@ -0,0 +1,64 @@
/*
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 ContractCallDataEncoder.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include "QVariableDeclaration.h"
#include "QVariableDefinition.h"
namespace dev
{
namespace mix
{
/**
* @brief Encode/Decode data to be sent to a transaction or to be displayed in a view.
*/
class ContractCallDataEncoder
{
public:
ContractCallDataEncoder() {}
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration* _dec, QString _value);
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration* _dec, u256 _value);
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration* _dec, bool _value);
/// Encode index of the function to call.
void encode(int _functionIndex);
/// Decode variable in order to be sent to QML view.
QList<QVariableDefinition*> decode(QList<QVariableDeclaration*> _dec, bytes _value);
/// Get all encoded data encoded by encode function.
bytes encodedData();
private:
int padding(QString _type);
bytes m_encodedData;
static QString convertToReadable(std::string _v, QVariableDeclaration* _dec);
static QString convertToBool(std::string _v);
static QString convertToInt(std::string _v);
static int integerPadding(int _bitValue);
static QString formatBool(bool _value);
};
}
}

19
mix/DebuggingStateWrapper.cpp

@ -22,17 +22,18 @@
#include <QApplication>
#include <QDebug>
#include "libevmcore/Instruction.h"
#include "libdevcore/CommonJS.h"
#include "libdevcrypto/Common.h"
#include "libevmcore/Instruction.h"
#include "libdevcore/Common.h"
#include <QPointer>
#include <libevmcore/Instruction.h>
#include <libdevcore/CommonJS.h>
#include <libdevcrypto/Common.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/Common.h>
#include "DebuggingStateWrapper.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCode(const bytes& _code, QObject* _objUsedAsParent)
std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCode(const bytes& _code)
{
QList<QObject*> codeStr;
QMap<int, int> codeMapping;
@ -52,7 +53,7 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc)));
i += bc;
}
HumanReadableCode* humanCode = new HumanReadableCode(QString::fromStdString(out.str()) + " " + s, line, _objUsedAsParent);
QPointer<HumanReadableCode> humanCode(new HumanReadableCode(QString::fromStdString(out.str()) + " " + s, line));
codeStr.append(humanCode);
}
catch (...)
@ -62,7 +63,7 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
break; // probably hit data segment
}
}
return std::make_tuple(codeStr, new QQMLMap(codeMapping, _objUsedAsParent));
return std::make_tuple(codeStr, QPointer<QQMLMap>(new QQMLMap(codeMapping)));
}
QString DebuggingStateWrapper::gasLeft()
@ -99,7 +100,7 @@ QString DebuggingStateWrapper::debugStorage()
{
std::stringstream s;
for (auto const& i: m_state.storage)
s << "@" << prettyU256(i.first) << "&nbsp;&nbsp;&nbsp;&nbsp;" << prettyU256(i.second);
s << "@" << prettyU256(i.first) << " " << prettyU256(i.second);
return QString::fromStdString(s.str());
}

74
mix/DebuggingStateWrapper.h

@ -23,15 +23,20 @@
#pragma once
#include <QStringList>
#include "libethereum/State.h"
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
#include <QMap>
#include <libdevcore/Common.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include "QVariableDefinition.h"
namespace dev
{
namespace mix
{
/**
* @brief Store information about a machine state.
*/
struct DebuggingState
{
uint64_t steps;
@ -47,13 +52,19 @@ struct DebuggingState
std::vector<DebuggingState const*> levels;
};
/**
* @brief Store information about a machine states.
*/
struct DebuggingContent
{
QList<DebuggingState> states;
QList<DebuggingState> machineStates;
bytes executionCode;
bytesConstRef executionData;
Address contractAddress;
bool contentAvailable;
QString message;
bytes returnValue;
QList<QVariableDefinition*> returnParameters;
};
/**
@ -62,12 +73,14 @@ struct DebuggingContent
class HumanReadableCode: public QObject
{
Q_OBJECT
Q_PROPERTY(QString line READ line)
Q_PROPERTY(int processIndex READ processIndex)
Q_PROPERTY(QString line READ line CONSTANT)
Q_PROPERTY(int processIndex READ processIndex CONSTANT)
public:
HumanReadableCode(QString _line, int _processIndex, QObject* _parent): QObject(_parent), m_line(_line), m_processIndex(_processIndex) {}
HumanReadableCode(QString _line, int _processIndex): QObject(), m_line(_line), m_processIndex(_processIndex) {}
/// Get the assembly code line.
QString line() { return m_line; }
/// Get corresponding index.
int processIndex() { return m_processIndex; }
private:
@ -84,7 +97,8 @@ class QQMLMap: public QObject
Q_OBJECT
public:
QQMLMap(QMap<int, int> _map, QObject* _parent): QObject(_parent), m_map(_map) { }
QQMLMap(QMap<int, int> _map): QObject(), m_map(_map) { }
/// Get the value associated with _key store in n_map.
Q_INVOKABLE int getValue(int _key) { return m_map.value(_key); }
private:
@ -97,36 +111,51 @@ private:
class DebuggingStateWrapper: public QObject
{
Q_OBJECT
Q_PROPERTY(int step READ step)
Q_PROPERTY(int curPC READ curPC)
Q_PROPERTY(QString gasCost READ gasCost)
Q_PROPERTY(QString gas READ gas)
Q_PROPERTY(QString gasLeft READ gasLeft)
Q_PROPERTY(QString debugStack READ debugStack)
Q_PROPERTY(QString debugStorage READ debugStorage)
Q_PROPERTY(QString debugMemory READ debugMemory)
Q_PROPERTY(QString debugCallData READ debugCallData)
Q_PROPERTY(QString headerInfo READ headerInfo)
Q_PROPERTY(QString endOfDebug READ endOfDebug)
Q_PROPERTY(QStringList levels READ levels)
Q_PROPERTY(int step READ step CONSTANT)
Q_PROPERTY(int curPC READ curPC CONSTANT)
Q_PROPERTY(QString gasCost READ gasCost CONSTANT)
Q_PROPERTY(QString gas READ gas CONSTANT)
Q_PROPERTY(QString gasLeft READ gasLeft CONSTANT)
Q_PROPERTY(QString debugStack READ debugStack CONSTANT)
Q_PROPERTY(QString debugStorage READ debugStorage CONSTANT)
Q_PROPERTY(QString debugMemory READ debugMemory CONSTANT)
Q_PROPERTY(QString debugCallData READ debugCallData CONSTANT)
Q_PROPERTY(QString headerInfo READ headerInfo CONSTANT)
Q_PROPERTY(QString endOfDebug READ endOfDebug CONSTANT)
Q_PROPERTY(QStringList levels READ levels CONSTANT)
public:
DebuggingStateWrapper(bytes _code, bytes _data, QObject* _parent): QObject(_parent), m_code(_code), m_data(_data) {}
DebuggingStateWrapper(bytes _code, bytes _data): QObject(), m_code(_code), m_data(_data) {}
/// Get the step of this machine states.
int step() { return (int)m_state.steps; }
/// Get the proccessed code index.
int curPC() { return (int)m_state.curPC; }
/// Get gas left.
QString gasLeft();
/// Get gas cost.
QString gasCost();
/// Get gas used.
QString gas();
/// Get stack.
QString debugStack();
/// Get storage.
QString debugStorage();
/// Get memory.
QString debugMemory();
/// Get call data.
QString debugCallData();
/// Get info to be displayed in the header.
QString headerInfo();
/// get end of debug information.
QString endOfDebug();
/// Get all previous steps.
QStringList levels();
/// Get the current processed machine state.
DebuggingState state() { return m_state; }
/// Set the current processed machine state.
void setState(DebuggingState _state) { m_state = _state; }
static std::tuple<QList<QObject*>, QQMLMap*> getHumanReadableCode(bytes const& _code, QObject* _objUsedAsParent);
/// Convert all machine state in human readable code.
static std::tuple<QList<QObject*>, QQMLMap*> getHumanReadableCode(bytes const& _code);
private:
DebuggingState m_state;
@ -135,5 +164,4 @@ private:
};
}
}

5
mix/Extension.cpp

@ -20,6 +20,7 @@
#include <QMessageBox>
#include <QDebug>
#include <libevm/VM.h>
#include <libwebthree/WebThree.h>
#include "Extension.h"
#include "AppContext.h"
using namespace dev;
@ -65,10 +66,10 @@ void Extension::addContentOn(QObject* _view)
Q_UNUSED(_view);
if (m_displayBehavior == ExtensionDisplayBehavior::ModalDialog)
{
QQmlComponent* component = new QQmlComponent(AppContext::getInstance()->appEngine(), QUrl(contentUrl()), _view);
QObject* dialogWin = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("dialog", Qt::FindChildrenRecursively);
QObject* dialogWinComponent = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("modalDialogContent", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
dialogWinComponent->setProperty("source", contentUrl());
dialogWinComponent->setProperty("sourceComponent", QVariant::fromValue(component));
dialogWin->setProperty("title", title());
QMetaObject::invokeMethod(dialogWin, "open");
}

11
mix/Extension.h

@ -31,6 +31,7 @@ namespace mix
enum ExtensionDisplayBehavior
{
Tab,
RightTab,
ModalDialog
};
@ -42,12 +43,19 @@ class Extension: public QObject
public:
Extension();
Extension(ExtensionDisplayBehavior _displayBehavior);
/// Return the QML url of the view to display.
virtual QString contentUrl() const { return ""; }
/// Return the title of this extension.
virtual QString title() const { return ""; }
/// Initialize extension.
virtual void start() const {}
void addContentOn(QObject* _tabView);
/// Add the view define in contentUrl() in the _view QObject.
void addContentOn(QObject* _view);
/// Add the view define in contentUrl() in the _view QObject (_view has to be a tab).
void addTabOn(QObject* _view);
/// Modify the display behavior of this extension.
void setDisplayBehavior(ExtensionDisplayBehavior _displayBehavior) { m_displayBehavior = _displayBehavior; }
/// Get the display behavior of thi extension.
ExtensionDisplayBehavior getDisplayBehavior() { return m_displayBehavior; }
protected:
@ -61,5 +69,4 @@ private:
};
}
}

9
mix/KeyEventManager.h

@ -17,12 +17,13 @@
/** @file KeyEventManager.h
* @author Yann yann@ethdev.com
* @date 2014
* use as an event handler for all classes which need keyboard interactions
* Used as an event handler for all classes which need keyboard interactions
*/
#pragma once
#include <QObject>
#include <QVariant>
class KeyEventManager: public QObject
{
@ -30,13 +31,17 @@ class KeyEventManager: public QObject
public:
KeyEventManager() {}
/// Allows _receiver to handle key pressed event.
void registerEvent(const QObject* _receiver, const char* _slot);
/// Unregister _receiver.
void unRegisterEvent(QObject* _receiver);
signals:
void onKeyPressed(int);
/// Emited when a key is pressed.
void onKeyPressed(int _event);
public slots:
/// Called when a key is pressed.
void keyPressed(QVariant _event);
};

1
mix/MixApplication.h

@ -41,5 +41,4 @@ public:
};
}
}

30
mix/TransactionBuilder.h → mix/QBasicNodeDefinition.h

@ -1,43 +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 TransactionBuilder.h
/** @file QBasicNodeDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QString>
#include "libdevcore/Common.h"
#include "libethereum/Transaction.h"
#include <QObject>
#include <libsolidity/AST.h>
namespace dev
{
namespace mix
{
class TransactionBuilder
class QBasicNodeDefinition: public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name CONSTANT)
public:
TransactionBuilder() {}
dev::eth::Transaction getBasicTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
QString address, bytes _data, dev::u256 _nonce, Secret _secret) const;
dev::eth::Transaction getCreationTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
dev::bytes _data, dev::u256 _nonce, Secret _secret) const;
QBasicNodeDefinition(): QObject() {}
~QBasicNodeDefinition() {}
QBasicNodeDefinition(solidity::Declaration const* _d): QObject(), m_name(QString::fromStdString(_d->getName())) {}
/// Get the name of the node.
QString name() const { return m_name; }
private:
QString m_name;
};
}
}

48
mix/QContractDefinition.cpp

@ -0,0 +1,48 @@
/*
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 QContractDefinition.cpp
* @author Yann yann@ethdev.com
* @date 2014
*/
#include <QObject>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/AST.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/NameAndTypeResolver.h>
#include "AppContext.h"
#include "QContractDefinition.h"
using namespace dev::solidity;
using namespace dev::mix;
std::shared_ptr<QContractDefinition> QContractDefinition::Contract(QString _source)
{
CompilerStack* comp = AppContext::getInstance()->compiler();
comp->addSource("contract", _source.toStdString());
comp->parse();
ContractDefinition const* def = &comp->getContractDefinition(comp->getContractNames().front());
return std::make_shared<QContractDefinition>(def);
}
void QContractDefinition::initQFunctions()
{
std::vector<FunctionDefinition const*> functions = m_contract->getInterfaceFunctions();
for (unsigned i = 0; i < functions.size(); i++)
m_functions.append(new QFunctionDefinition(functions.at(i), i));
}

53
mix/QContractDefinition.h

@ -0,0 +1,53 @@
/*
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 QContractDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#pragma once
#include <QObject>
#include <libsolidity/AST.h>
#include "QFunctionDefinition.h"
#include "QBasicNodeDefinition.h"
namespace dev
{
namespace mix
{
class QContractDefinition: public QBasicNodeDefinition
{
Q_OBJECT
Q_PROPERTY(QList<QFunctionDefinition*> functions READ functions)
public:
QContractDefinition(solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_contract), m_contract(_contract) { initQFunctions(); }
/// Get all the functions of the contract.
QList<QFunctionDefinition*> functions() const { return m_functions; }
/// Get the description (functions, parameters, return parameters, ...) of the contract describes by _code.
static std::shared_ptr<QContractDefinition> Contract(QString _code);
private:
solidity::ContractDefinition const* m_contract;
QList<QFunctionDefinition*> m_functions;
void initQFunctions();
};
}
}

37
mix/QFunctionDefinition.cpp

@ -0,0 +1,37 @@
/*
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 QFunctionDefinition.cpp
* @author Yann yann@ethdev.com
* @date 2014
*/
#include <libsolidity/AST.h>
#include "QVariableDeclaration.h"
#include "QFunctionDefinition.h"
using namespace dev::solidity;
using namespace dev::mix;
void QFunctionDefinition::initQParameters()
{
std::vector<std::shared_ptr<VariableDeclaration>> parameters = m_functions->getParameterList().getParameters();
for (unsigned i = 0; i < parameters.size(); i++)
m_parameters.append(new QVariableDeclaration(parameters.at(i).get()));
std::vector<std::shared_ptr<VariableDeclaration>> returnParameters = m_functions->getReturnParameters();
for (unsigned i = 0; i < returnParameters.size(); i++)
m_returnParameters.append(new QVariableDeclaration(returnParameters.at(i).get()));
}

58
mix/QFunctionDefinition.h

@ -0,0 +1,58 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file QFunctionDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#pragma once
#include <QObject>
#include <libsolidity/AST.h>
#include <QVariableDeclaration.h>
#include "QBasicNodeDefinition.h"
namespace dev
{
namespace mix
{
class QFunctionDefinition: public QBasicNodeDefinition
{
Q_OBJECT
Q_PROPERTY(QList<QVariableDeclaration*> parameters READ parameters)
Q_PROPERTY(int index READ index)
public:
QFunctionDefinition(solidity::FunctionDefinition const* _f, int _index): QBasicNodeDefinition(_f), m_index(_index), m_functions(_f) { initQParameters(); }
/// Get all input parameters of this function.
QList<QVariableDeclaration*> parameters() const { return m_parameters; }
/// Get all return parameters of this function.
QList<QVariableDeclaration*> returnParameters() const { return m_returnParameters; }
/// Get the index of this function on the contract ABI.
int index() const { return m_index; }
private:
int m_index;
solidity::FunctionDefinition const* m_functions;
QList<QVariableDeclaration*> m_parameters;
QList<QVariableDeclaration*> m_returnParameters;
void initQParameters();
};
}
}

49
mix/QVariableDeclaration.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 QVariableDeclaration.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#include <libsolidity/AST.h>
#include "QBasicNodeDefinition.h"
#pragma once
namespace dev
{
namespace mix
{
class QVariableDeclaration: public QBasicNodeDefinition
{
Q_OBJECT
Q_PROPERTY(QString type READ type CONSTANT)
public:
QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_variable(_v) {}
/// Get the type of this variable.
QString type() const { return QString::fromStdString(m_variable->getType()->toString()); }
private:
solidity::VariableDeclaration const* m_variable;
};
}
}
Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*)

55
mix/QVariableDefinition.cpp

@ -0,0 +1,55 @@
/*
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 QVariableDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#include "QVariableDefinition.h"
using namespace dev::mix;
int QVariableDefinitionList::rowCount(const QModelIndex& _parent) const
{
Q_UNUSED(_parent);
return m_def.size();
}
QVariant QVariableDefinitionList::data(const QModelIndex& _index, int _role) const
{
if (_role != Qt::DisplayRole)
return QVariant();
int i = _index.row();
if (i < 0 || i >= m_def.size())
return QVariant(QVariant::Invalid);
return QVariant::fromValue(m_def.at(i));
}
QHash<int, QByteArray> QVariableDefinitionList::roleNames() const
{
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "variable";
return roles;
}
QVariableDefinition* QVariableDefinitionList::val(int _idx)
{
if (_idx < 0 || _idx >= m_def.size())
return nullptr;
return m_def.at(_idx);
}

72
mix/QVariableDefinition.h

@ -0,0 +1,72 @@
/*
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 QVariableDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#pragma once
#include <QAbstractListModel>
#include "QVariableDeclaration.h"
namespace dev
{
namespace mix
{
class QVariableDefinition: public QObject
{
Q_OBJECT
Q_PROPERTY(QString value READ value CONSTANT)
Q_PROPERTY(QVariableDeclaration* declaration READ declaration CONSTANT)
public:
QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(), m_value(_value), m_dec(_def) {}
/// Return the associated declaration of this variable definition.
QVariableDeclaration* declaration() const { return m_dec; }
/// Return the variable value.
QString value() const { return m_value; }
private:
QString m_value;
QVariableDeclaration* m_dec;
};
class QVariableDefinitionList: public QAbstractListModel
{
Q_OBJECT
public:
QVariableDefinitionList(QList<QVariableDefinition*> _def): m_def(_def) {}
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
/// Return the variable definition at index _idx.
QVariableDefinition* val(int _idx);
/// Return the list of variables.
QList<QVariableDefinition*> def() { return m_def; }
private:
QList<QVariableDefinition*> m_def;
};
}
}
Q_DECLARE_METATYPE(dev::mix::QVariableDefinition*)

40
mix/TransactionBuilder.cpp

@ -1,40 +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 TransactionBuilder.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include "libethereum/Executive.h"
#include "libdevcore/CommonJS.h"
#include "libdevcore/Common.h"
#include "AppContext.h"
#include "TransactionBuilder.h"
using namespace dev::mix;
using namespace dev::eth;
using namespace dev;
Transaction TransactionBuilder::getCreationTransaction(u256 _value, u256 _gasPrice, u256 _gas,
bytes _data, u256 _nonce, Secret _secret) const
{
return Transaction(_value, _gasPrice, _gas, _data, _nonce, _secret);
}
Transaction TransactionBuilder::getBasicTransaction(u256 _value, u256 _gasPrice, u256 _gas,
QString _address, bytes _data, u256 _nonce, Secret _secret) const
{
return Transaction(_value, _gasPrice, _gas, dev::fromString(_address.toStdString()), _data, _nonce, _secret);
}

221
mix/TransactionListModel.cpp

@ -0,0 +1,221 @@
/*
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 TransactionListModel.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QObject>
#include <QQmlEngine>
#include <QTextDocument>
#include <QAbstractListModel>
#include <libdevcore/CommonJS.h>
#include "TransactionListModel.h"
#include "QContractDefinition.h"
#include "QFunctionDefinition.h"
#include "QVariableDeclaration.h"
namespace dev
{
namespace mix
{
/// @todo Move this to QML
u256 fromQString(QString const& _s)
{
return dev::jsToU256(_s.toStdString());
}
/// @todo Move this to QML
QString toQString(u256 _value)
{
std::ostringstream s;
s << _value;
return QString::fromStdString(s.str());
}
TransactionListItem::TransactionListItem(int _index, TransactionSettings const& _t, QObject* _parent):
QObject(_parent), m_index(_index), m_title(_t.title), m_functionId(_t.functionId), m_value(toQString(_t.value)),
m_gas(toQString(_t.gas)), m_gasPrice(toQString(_t.gasPrice))
{}
TransactionListModel::TransactionListModel(QObject* _parent, QTextDocument* _document):
QAbstractListModel(_parent), m_document(_document)
{
qRegisterMetaType<TransactionListItem*>("TransactionListItem*");
}
QHash<int, QByteArray> TransactionListModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[TitleRole] = "title";
roles[IdRole] = "transactionIndex";
return roles;
}
int TransactionListModel::rowCount(QModelIndex const& _parent) const
{
Q_UNUSED(_parent);
return m_transactions.size();
}
QVariant TransactionListModel::data(QModelIndex const& _index, int _role) const
{
if (_index.row() < 0 || _index.row() >= (int)m_transactions.size())
return QVariant();
auto const& transaction = m_transactions.at(_index.row());
switch (_role)
{
case TitleRole:
return QVariant(transaction.title);
case IdRole:
return QVariant(_index.row());
default:
return QVariant();
}
}
///@todo: get parameters from code model
QList<TransactionParameterItem*> buildParameters(QTextDocument* _document, TransactionSettings const& _transaction, QString const& _functionId)
{
QList<TransactionParameterItem*> params;
try
{
std::shared_ptr<QContractDefinition> contract = QContractDefinition::Contract(_document->toPlainText());
auto functions = contract->functions();
for (auto f : functions)
{
if (f->name() != _functionId)
continue;
auto parameters = f->parameters();
//build a list of parameters for a function. If the function is selected as current, add parameter values as well
for (auto p : parameters)
{
QString paramValue;
if (f->name() == _transaction.functionId)
{
auto paramValueIter = _transaction.parameterValues.find(p->name());
if (paramValueIter != _transaction.parameterValues.cend())
paramValue = toQString(paramValueIter->second);
}
TransactionParameterItem* item = new TransactionParameterItem(p->name(), p->type(), paramValue);
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
params.append(item);
}
}
}
catch (boost::exception const&)
{
//TODO:
}
return params;
}
///@todo: get fnctions from code model
QList<QString> TransactionListModel::getFunctions()
{
QList<QString> functionNames;
try
{
QString code = m_document->toPlainText();
std::shared_ptr<QContractDefinition> contract(QContractDefinition::Contract(code));
auto functions = contract->functions();
for (auto f : functions)
{
functionNames.append(f->name());
}
}
catch (boost::exception const&)
{
}
return functionNames;
}
QVariantList TransactionListModel::getParameters(int _index, QString const& _functionId)
{
TransactionSettings const& transaction = (_index >= 0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : TransactionSettings();
auto plist = buildParameters(m_document, transaction, _functionId);
QVariantList vl;
for (QObject* p : plist)
vl.append(QVariant::fromValue(p));
return vl;
}
TransactionListItem* TransactionListModel::getItem(int _index)
{
TransactionSettings const& transaction = (_index >= 0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : TransactionSettings();
TransactionListItem* item = new TransactionListItem(_index, transaction, nullptr);
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
return item;
}
void TransactionListModel::edit(QObject* _data)
{
//these properties come from TransactionDialog QML object
///@todo change the model to a qml component
int index = _data->property("transactionIndex").toInt();
QString title = _data->property("transactionTitle").toString();
QString gas = _data->property("gas").toString();
QString gasPrice = _data->property("gasPrice").toString();
QString value = _data->property("transactionValue").toString();
QString functionId = _data->property("functionId").toString();
QAbstractListModel* paramsModel = qvariant_cast<QAbstractListModel*>(_data->property("transactionParams"));
TransactionSettings transaction(title, functionId, fromQString(value), fromQString(gas), fromQString(gasPrice));
int paramCount = paramsModel->rowCount(QModelIndex());
for (int p = 0; p < paramCount; ++p)
{
QString paramName = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole).toString();
QString paramValue = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole + 2).toString();
if (!paramValue.isEmpty() && !paramName.isEmpty())
transaction.parameterValues[paramName] = fromQString(paramValue);
}
if (index >= 0 && index < (int)m_transactions.size())
{
beginRemoveRows(QModelIndex(), index, index);
m_transactions.erase(m_transactions.begin() + index);
endRemoveRows();
}
else
index = rowCount(QModelIndex());
beginInsertRows(QModelIndex(), index, index);
m_transactions.push_back(transaction);
emit countChanged();
endInsertRows();
}
int TransactionListModel::getCount() const
{
return rowCount(QModelIndex());
}
void TransactionListModel::runTransaction(int _index)
{
TransactionSettings tr = m_transactions.at(_index);
emit transactionStarted(tr);
}
}
}

168
mix/TransactionListModel.h

@ -0,0 +1,168 @@
/*
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 TransactionListView.h
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QObject>
#include <QVariant>
#include <QAbstractListModel>
#include <QHash>
#include <QByteArray>
#include <libdevcore/Common.h>
#include <libethcore/CommonEth.h>
class QTextDocument;
namespace dev
{
namespace mix
{
/// Backend transaction config class
struct TransactionSettings
{
TransactionSettings():
value(0), gas(10000), gasPrice(10 * dev::eth::szabo) {}
TransactionSettings(QString const& _title, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
title(_title), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
/// User specified transaction title
QString title;
/// Contract function name
QString functionId;
/// Transaction value
u256 value;
/// Gas
u256 gas;
/// Gas price
u256 gasPrice;
/// Mapping from contract function parameter name to value
std::map<QString, u256> parameterValues;
};
/// QML transaction parameter class
class TransactionParameterItem: public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString type READ type CONSTANT)
Q_PROPERTY(QString value READ value CONSTANT)
public:
TransactionParameterItem(QString const& _name, QString const& _type, QString const& _value):
m_name(_name), m_type(_type), m_value(_value) {}
/// Parameter name, set by contract definition
QString name() { return m_name; }
/// Parameter type, set by contract definition
QString type() { return m_type; }
/// Parameter value, set by user
QString value() { return m_value; }
private:
QString m_name;
QString m_type;
QString m_value;
};
class TransactionListItem: public QObject
{
Q_OBJECT
Q_PROPERTY(int index READ index CONSTANT)
Q_PROPERTY(QString title READ title CONSTANT)
Q_PROPERTY(QString functionId READ functionId CONSTANT)
Q_PROPERTY(QString gas READ gas CONSTANT)
Q_PROPERTY(QString gasPrice READ gasPrice CONSTANT)
Q_PROPERTY(QString value READ value CONSTANT)
public:
TransactionListItem(int _index, TransactionSettings const& _t, QObject* _parent);
/// User specified transaction title
QString title() { return m_title; }
/// Gas
QString gas() { return m_gas; }
/// Gas cost
QString gasPrice() { return m_gasPrice; }
/// Transaction value
QString value() { return m_value; }
/// Contract function name
QString functionId() { return m_functionId; }
/// Index of this transaction in the transactions list
int index() { return m_index; }
private:
int m_index;
QString m_title;
QString m_functionId;
QString m_value;
QString m_gas;
QString m_gasPrice;
};
/// QML model for a list of transactions
class TransactionListModel: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ getCount() NOTIFY countChanged())
enum Roles
{
TitleRole = Qt::DisplayRole,
IdRole = Qt::UserRole + 1
};
public:
TransactionListModel(QObject* _parent, QTextDocument* _document);
~TransactionListModel() {}
QHash<int, QByteArray> roleNames() const override;
int rowCount(QModelIndex const& _parent) const override;
QVariant data(QModelIndex const& _index, int _role) const override;
int getCount() const;
/// Apply changes from transaction dialog. Argument is a dialog model as defined in TransactionDialog.qml
/// @todo Change that to transaction item
Q_INVOKABLE void edit(QObject* _data);
/// @returns transaction item for a give index
Q_INVOKABLE TransactionListItem* getItem(int _index);
/// @returns a list of functions for current contract
Q_INVOKABLE QList<QString> getFunctions();
/// @returns function parameters along with parameter values if set. @see TransactionParameterItem
Q_INVOKABLE QVariantList getParameters(int _id, QString const& _functionId);
/// Launch transaction execution UI handler
Q_INVOKABLE void runTransaction(int _index);
signals:
/// Transaction count has changed
void countChanged();
/// Transaction has been launched
void transactionStarted(dev::mix::TransactionSettings);
private:
std::vector<TransactionSettings> m_transactions;
QTextDocument* m_document;
};
}
}

56
mix/TransactionListView.cpp

@ -0,0 +1,56 @@
/*
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 TransactionListView.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QQuickItem>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include "TransactionListView.h"
#include "TransactionListModel.h"
using namespace dev::mix;
TransactionListView::TransactionListView(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::RightTab)
{
m_editor = _doc;
m_model.reset(new TransactionListModel(this, _doc));
m_appEngine->rootContext()->setContextProperty("transactionListModel", m_model.get());
}
TransactionListView::~TransactionListView()
{
//implementation is in cpp file so that all types deleted are complete
}
QString TransactionListView::contentUrl() const
{
return QStringLiteral("qrc:/qml/TransactionList.qml");
}
QString TransactionListView::title() const
{
return QApplication::tr("Transactions");
}
void TransactionListView::start() const
{
}

54
mix/TransactionListView.h

@ -0,0 +1,54 @@
/*
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 TransactionListView.h
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QTextDocument>
#include "Extension.h"
namespace dev
{
namespace mix
{
class TransactionListModel;
/// Transactions list control
/// @todo This should be moved into state as a sequence
class TransactionListView: public Extension
{
Q_OBJECT
public:
TransactionListView(QTextDocument*);
~TransactionListView();
void start() const override;
QString title() const override;
QString contentUrl() const override;
/// @returns the underlying model
TransactionListModel* model() const { return m_model.get(); }
private:
QTextDocument* m_editor;
std::unique_ptr<TransactionListModel> m_model;
};
}
}

2
mix/qml.qrc

@ -7,6 +7,8 @@
<file>qml/Debugger.qml</file>
<file>qml/js/Debugger.js</file>
<file>qml/BasicMessage.qml</file>
<file>qml/TransactionDialog.qml</file>
<file>qml/TransactionList.qml</file>
<file>qml/ModalDialog.qml</file>
<file>qml/AlertMessageDialog.qml</file>
</qresource>

5
mix/qml/AlertMessageDialog.qml

@ -22,6 +22,9 @@ Window
}
function close()
{
visible = false
visible = false;
alertMessageDialogContent.source = "";
alertMessageDialogContent.sourceComponent = undefined;
alertMessageDialog.destroy();
}
}

8
mix/qml/BasicContent.qml

@ -7,13 +7,13 @@ Rectangle {
height: parent.height
color: "lightgray"
Text {
font.pointSize: 7
font.pointSize: 9
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 3
anchors.leftMargin: 3
height: 9
font.family: "Sego UI light"
font.family: "Monospace"
objectName: "status"
id: status
}
@ -23,8 +23,8 @@ Rectangle {
anchors.leftMargin: 10
anchors.top: status.bottom
anchors.topMargin: 3
font.pointSize: 7
font.family: "Sego UI light"
font.pointSize: 9
font.family: "Monospace"
height: parent.height * 0.8
width: parent.width - 20
wrapMode: Text.Wrap

1
mix/qml/BasicMessage.qml

@ -16,6 +16,7 @@ Rectangle {
objectName: "messageContent"
id: messageTxt
text: ""
wrapMode: "Wrap"
}
}

70
mix/qml/Debugger.qml

@ -8,18 +8,54 @@ import "js/Debugger.js" as Debugger
Rectangle {
anchors.fill: parent;
color: "lightgrey"
Component.onCompleted: Debugger.init();
Rectangle {
color: "transparent"
id: headerInfo
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
height: 30
height: 60
anchors.top: parent.top
Label {
anchors.centerIn: parent
font.family: "Verdana"
font.pointSize: 9
font.italic: true
id: headerInfoLabel
Column {
width: parent.width
height: parent.height
Rectangle {
color: "transparent"
width: parent.width
height: 30
Label {
anchors.centerIn: parent
font.family: "Verdana"
font.pointSize: 9
font.italic: true
id: headerInfoLabel
}
}
Rectangle {
color: "transparent"
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
height: 30
ListView {
orientation: ListView.Horizontal
anchors.centerIn: parent;
width: parent.width
id: headerReturnList
delegate: renderDelegateReturnValues
}
Component {
id: renderDelegateReturnValues
Item {
id: wrapperItem
width: 80
Text {
anchors.centerIn: parent
text: variable.declaration.name + " = " + variable.value
font.pointSize: 9
}
}
}
}
}
}
@ -37,7 +73,7 @@ Rectangle {
anchors.topMargin: 10
anchors.top: headerInfo.bottom
anchors.left: parent.left
height: parent.height - 30
height: parent.height - 70
width: parent.width * 0.5
ListView {
@ -46,7 +82,6 @@ Rectangle {
width: 200
anchors.horizontalCenter: parent.horizontalCenter
id: statesList
Component.onCompleted: Debugger.init();
model: humanReadableExecutionCode
delegate: renderDelegate
highlight: highlightBar
@ -94,7 +129,7 @@ Rectangle {
font.letterSpacing: 2
width: parent.width
height: 15
text: "callstack"
text: qsTr("callstack")
}
ListView {
@ -140,7 +175,7 @@ Rectangle {
width: parent.width
height: 15
anchors.top : parent.top
text: "debug stack"
text: qsTr("debug stack")
}
TextArea {
anchors.bottom: parent.bottom
@ -148,7 +183,7 @@ Rectangle {
font.family: "Verdana"
font.pointSize: 8
height: parent.height - 15
id:debugStackTxt
id: debugStackTxt
readOnly: true;
}
}
@ -166,7 +201,7 @@ Rectangle {
width: parent.width
height: 15
anchors.top : parent.top
text: "debug memory"
text: qsTr("debug memory")
}
TextArea {
anchors.bottom: parent.bottom
@ -192,7 +227,7 @@ Rectangle {
width: parent.width
height: 15
anchors.top : parent.top
text: "debug storage"
text: qsTr("debug storage")
}
TextArea {
anchors.bottom: parent.bottom
@ -200,7 +235,7 @@ Rectangle {
font.family: "Verdana"
font.pointSize: 8
height: parent.height - 15
id:debugStorageTxt
id: debugStorageTxt
readOnly: true;
}
}
@ -218,12 +253,15 @@ Rectangle {
width: parent.width
height: 15
anchors.top : parent.top
text: "debug calldata"
text: qsTr("debug calldata")
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
height: parent.height - 15
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
id: debugCallDataTxt
readOnly: true;
}

105
mix/qml/MainContent.qml

@ -16,47 +16,66 @@ Rectangle {
anchors.fill: parent
height: parent.height
width: parent.width;
id:root
SplitView {
anchors.fill: parent
orientation: Qt.Vertical
Rectangle {
anchors.top: parent.top
id: contentView
width: parent.width
height: parent.height * 0.7
TextArea {
id: codeEditor
height: parent.height
font.family: "Verdana"
font.pointSize: 9
width: parent.width
anchors.centerIn: parent
tabChangesFocus: false
Keys.onPressed: {
if (event.key === Qt.Key_Tab) {
codeEditor.insert(codeEditor.cursorPosition, "\t");
event.accepted = true;
}
}
}
}
Rectangle {
anchors.bottom: parent.bottom
id: contextualView
width: parent.width
Layout.minimumHeight: 20
height: parent.height * 0.3
TabView {
id: contextualTabs
antialiasing: true
anchors.fill: parent
style: TabStyle {}
}
}
CodeEditorExtensionManager {
tabView: contextualTabs
editor: codeEditor
}
}
id:root
SplitView {
orientation: Qt.Horizontal
anchors.fill: parent
SplitView {
//anchors.fill: parent
width: parent.width * 0.8
orientation: Qt.Vertical
Rectangle {
anchors.top: parent.top
id: contentView
width: parent.width
height: parent.height * 0.7
TextArea {
id: codeEditor
height: parent.height
font.family: "Monospace"
font.pointSize: 12
width: parent.width
anchors.centerIn: parent
tabChangesFocus: false
Keys.onPressed: {
if (event.key === Qt.Key_Tab) {
codeEditor.insert(codeEditor.cursorPosition, "\t");
event.accepted = true;
}
}
}
}
Rectangle {
anchors.bottom: parent.bottom
id: contextualView
width: parent.width
Layout.minimumHeight: 20
height: parent.height * 0.3
TabView {
id: contextualTabs
antialiasing: true
anchors.fill: parent
style: TabStyle {}
}
}
}
Rectangle {
anchors.right: parent.right
id: rightPaneView
width: parent.width * 0.2
height: parent.height
Layout.minimumWidth: 20
TabView {
id: rightPaneTabs
antialiasing: true
anchors.fill: parent
//style: TabStyle {}
}
}
CodeEditorExtensionManager {
tabView: contextualTabs
rightTabView: rightPaneTabs
editor: codeEditor
}
}
}

7
mix/qml/ModalDialog.qml

@ -18,10 +18,13 @@ Window
}
function open()
{
visible = true
visible = true;
}
function close()
{
visible = false
visible = false;
modalDialogContent.source = "";
modalDialogContent.sourceComponent = undefined;
modalDialog.destroy();
}
}

219
mix/qml/TransactionDialog.qml

@ -0,0 +1,219 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
Window {
modality: Qt.WindowModal
width:640
height:480
visible: false
function open()
{
visible = true;
}
function close()
{
visible = false;
}
property alias focus : titleField.focus
property alias transactionTitle : titleField.text
property int transactionIndex
property alias transactionParams : paramsModel;
property alias gas : gasField.text;
property alias gasPrice : gasPriceField.text;
property alias transactionValue : valueField.text;
property alias functionId : functionComboBox.currentText;
property var model;
signal accepted;
function reset(index, m) {
model = m;
var item = model.getItem(index);
transactionIndex = index;
transactionTitle = item.title;
gas = item.gas;
gasPrice = item.gasPrice;
transactionValue = item.value;
var functionId = item.functionId;
functionsModel.clear();
var functionIndex = -1;
var functions = model.getFunctions();
for (var f = 0; f < functions.length; f++) {
functionsModel.append({ text: functions[f] });
if (functions[f] === item.functionId)
functionIndex = f;
}
functionComboBox.currentIndex = functionIndex;
}
function loadParameters() {
if (!paramsModel)
return;
paramsModel.clear();
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
var parameters = model.getParameters(transactionIndex, functionsModel.get(functionComboBox.currentIndex).text);
for (var p = 0; p < parameters.length; p++) {
paramsModel.append({ name: parameters[p].name, type: parameters[p].type, value: parameters[p].value });
}
}
}
GridLayout {
id: dialogContent
columns: 2
anchors.fill: parent
anchors.margins: 10
rowSpacing: 10
columnSpacing: 10
Label {
text: qsTr("Title")
}
TextField {
id: titleField
focus: true
Layout.fillWidth: true
}
Label {
text: qsTr("Function")
}
ComboBox {
id: functionComboBox
Layout.fillWidth: true
currentIndex: -1
textRole: "text"
editable: false
model: ListModel {
id: functionsModel
}
onCurrentIndexChanged: {
loadParameters();
}
}
Label {
text: qsTr("Value")
}
TextField {
id: valueField
Layout.fillWidth: true
}
Label {
text: qsTr("Gas")
}
TextField {
id: gasField
Layout.fillWidth: true
}
Label {
text: qsTr("Gas price")
}
TextField {
id: gasPriceField
Layout.fillWidth: true
}
Label {
text: qsTr("Parameters")
}
TableView {
model: paramsModel
Layout.fillWidth: true
TableViewColumn {
role: "name"
title: "Name"
width: 120
}
TableViewColumn {
role: "type"
title: "Type"
width: 120
}
TableViewColumn {
role: "value"
title: "Value"
width: 120
}
itemDelegate: {
return editableDelegate;
}
}
}
RowLayout
{
anchors.bottom: parent.bottom
anchors.right: parent.right;
Button {
text: qsTr("Ok");
onClicked: {
close();
accepted();
}
}
Button {
text: qsTr("Cancel");
onClicked: close();
}
}
ListModel {
id: paramsModel
}
Component {
id: editableDelegate
Item {
Text {
width: parent.width
anchors.margins: 4
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
elide: styleData.elideMode
text: styleData.value !== undefined ? styleData.value : ""
color: styleData.textColor
visible: !styleData.selected
}
Loader {
id: loaderEditor
anchors.fill: parent
anchors.margins: 4
Connections {
target: loaderEditor.item
onTextChanged: {
paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text);
}
}
sourceComponent: (styleData.selected) ? editor : null
Component {
id: editor
TextInput {
id: textinput
color: styleData.textColor
text: styleData.value
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}
}
}
}

89
mix/qml/TransactionList.qml

@ -0,0 +1,89 @@
import QtQuick 2.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
Rectangle {
color: "transparent"
id: transactionListContainer
focus: true
anchors.topMargin: 10
anchors.left: parent.left
height: parent.height
width: parent.width
ListView {
anchors.top: parent.top
height: parent.height
width: parent.width
id: transactionList
model: transactionListModel
delegate: renderDelegate
}
Button {
anchors.bottom: parent.bottom
text: qsTr("Add")
onClicked:
{
// Set next id here to work around Qt bug
// https://bugreports.qt-project.org/browse/QTBUG-41327
// Second call to signal handle would just edit the item that was just created, no harm done
transactionDialog.reset(transactionListModel.count, transactionListModel);
transactionDialog.open();
transactionDialog.focus = true;
}
}
TransactionDialog {
id: transactionDialog
onAccepted: {
transactionListModel.edit(transactionDialog);
}
}
Component {
id: renderDelegate
Item {
id: wrapperItem
height: 20
width: parent.width
RowLayout
{
anchors.fill: parent
Text {
//anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
text: title
font.pointSize: 12
verticalAlignment: Text.AlignBottom
}
ToolButton {
text: qsTr("Edit");
Layout.fillHeight: true
onClicked: {
transactionDialog.reset(index, transactionListModel);
transactionDialog.open();
transactionDialog.focus = true;
}
}
ToolButton {
text: qsTr("Delete");
Layout.fillHeight: true
onClicked: {
}
}
ToolButton {
text: qsTr("Run");
Layout.fillHeight: true
onClicked: {
transactionListModel.runTransaction(index);
}
}
}
}
}
}

10
mix/qml/js/Debugger.js

@ -8,6 +8,7 @@ function init()
{
currentSelectedState = 0;
select(currentSelectedState);
displayReturnValue();
}
function moveSelection(incr)
@ -30,7 +31,7 @@ function select(stateIndex)
var state = debugStates[stateIndex];
var codeStr = bytesCodeMapping.getValue(state.curPC);
highlightSelection(codeStr);
currentSelectedState = codeStr;
currentSelectedState = stateIndex;
completeCtxInformation(state);
levelList.model = state.levels;
levelList.update();
@ -38,7 +39,6 @@ function select(stateIndex)
function highlightSelection(index)
{
console.log(index);
statesList.currentIndex = index;
}
@ -60,3 +60,9 @@ function endOfDebug()
debugMemoryTxt.text = state.endOfDebug;
headerInfoLabel.text = "EXIT | GAS: " + state.gasLeft;
}
function displayReturnValue()
{
headerReturnList.model = contractCallReturnParameters;
headerReturnList.update();
}

6
mix/qml/main.qml

@ -9,8 +9,6 @@ import CodeEditorExtensionManager 1.0
ApplicationWindow {
id: mainApplication
visible: true
x: Screen.width / 2 - width / 2
y: Screen.height / 2 - height / 2
width: 1200
height: 600
minimumWidth: 400
@ -26,6 +24,10 @@ ApplicationWindow {
}
}
}
Component.onCompleted: {
setX(Screen.width / 2 - width / 2);
setY(Screen.height / 2 - height / 2);
}
MainContent {
}

2
test/solidityExecutionFramework.h

@ -117,7 +117,7 @@ private:
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0)
{
m_state.addBalance(m_sender, _value); // just in case
eth::Executive executive(m_state, 0);
eth::Executive executive(m_state, eth::LastHashes(), 0);
eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
: eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
bytes transactionRLP = t.rlp();

205
test/stInitCodeTestFiller.json

@ -92,6 +92,36 @@
"value" : "1"
}
},
"StackUnderFlowContractCreation" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x6000f1",
"gasLimit" : "1000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "",
"value" : "0"
}
},
"TransactionSuicideInitCode" : {
"env" : {
@ -262,11 +292,11 @@
}
},
"CallTheContractToCreateContractWithInitCode" : {
"CallContractToCreateContractWhichWouldCreateContractInInitCode" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
@ -274,14 +304,15 @@
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "10000",
"balance": "1",
"nonce": 0,
"code": "{[[ 2 ]](ADDRESS)(CODECOPY 0 0 32)(CREATE 0 0 32)}",
"//": "{[[0]] 12 (CREATE 0 64 32)}",
"code": "{(MSTORE 0 0x600c600055602060406000f0)(CREATE 0 20 12)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
@ -291,12 +322,172 @@
"transaction" :
{
"data" : "0x00",
"gasLimit" : "10000",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1"
"value" : "0"
}
},
"CallContractToCreateContractWhichWouldCreateContractIfCalled" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 500 (SLOAD 0) 1 0 0 0 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"CallContractToCreateContractOOG" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "0",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 0 0 0 0 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"CallContractToCreateContractAndCallItOOG" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 1 0 0 0 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"CallContractToCreateContractNoCash" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1001 11 21)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
}
}

106
test/stSystemOperationsTestFiller.json

@ -740,7 +740,7 @@
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365223",
"gasLimit" : "365243",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
@ -774,7 +774,7 @@
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"gasLimit" : "365244",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
@ -1410,5 +1410,107 @@
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"callValue": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[0]] (CALLVALUE) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"currentAccountBalance": {
"env": {
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber": "0",
"currentGasLimit": "10000000",
"currentDifficulty": "256",
"currentTimestamp": 1,
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre": {
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "{ [[0]] (balance (address)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "",
"storage": {}
}
},
"transaction": {
"nonce": "0",
"gasPrice": "1",
"gasLimit": "10000000",
"to": "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value": "100000",
"secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data": ""
}
},
"callerAccountBalance": {
"env": {
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber": "0",
"currentGasLimit": "10000000",
"currentDifficulty": "256",
"currentTimestamp": 1,
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre": {
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "{ [[0]] (balance (caller)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "",
"storage": {}
}
},
"transaction": {
"nonce": "0",
"gasPrice": "1",
"gasLimit": "10000000",
"to": "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value": "100000",
"secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data": ""
}
}
}

137
test/stTransactionTestFiller.json

@ -187,5 +187,140 @@
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "502"
}
}
},
"ContractStoreClearsSuccess" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "10000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "7000",
"code" : "",
"nonce" : "0",
"storage" : {
}
},
"d2571607e241ecf590ed94b12d87c94babe36db6" : {
"balance" : "0",
"code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 0)}",
"nonce" : "0",
"storage" : {
"0x" : "0x0c",
"0x01" : "0x0c",
"0x02" : "0x0c",
"0x03" : "0x0c",
"0x04" : "0x0c",
"0x05" : "0x0c",
"0x06" : "0x0c",
"0x07" : "0x0c",
"0x08" : "0x0c",
"0x09" : "0x0c"
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "600",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
"value" : "10"
}
},
"ContractStoreClearsOOG" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "10000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "7000",
"code" : "",
"nonce" : "0",
"storage" : {
}
},
"d2571607e241ecf590ed94b12d87c94babe36db6" : {
"balance" : "0",
"code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 12)}",
"nonce" : "0",
"storage" : {
"0x" : "0x0c",
"0x01" : "0x0c",
"0x02" : "0x0c",
"0x03" : "0x0c",
"0x04" : "0x0c",
"0x05" : "0x0c",
"0x06" : "0x0c",
"0x07" : "0x0c",
"0x08" : "0x0c",
"0x09" : "0x0c"
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "600",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
"value" : "10"
}
},
"TransactionTooManyRlpElements" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "10000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "600",
"gasLimit" : "1600",
"gasPrice" : "1",
"gasPrice" : "12",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d9",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
"value" : "10"
}
},
}

2
test/state.cpp

@ -62,7 +62,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
try
{
theState.execute(tx, &output);
theState.execute(LastHashes(), tx, &output);
}
catch (Exception const& _e)
{

2
test/stateOriginal.cpp

@ -69,7 +69,7 @@ int stateTest()
assert(t.sender() == myMiner.address());
tx = t.rlp();
}
s.execute(tx);
s.execute(bc, tx);
cout << s;

2
test/vm.cpp

@ -33,7 +33,7 @@ using namespace dev::eth;
using namespace dev::test;
FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix.
ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {}
ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, LastHashes(), _depth) {}
h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&)
{

2392
test/vmArithmeticTestFiller.json

File diff suppressed because it is too large
Loading…
Cancel
Save