Browse Source

Merge remote-tracking branch 'up/develop' into ui_improvement

Conflicts:
	mix/qml/StateListModel.qml
	mix/qml/main.qml
cl-refactor
yann300 10 years ago
parent
commit
49173feb8f
  1. 7
      alethzero/MainWin.cpp
  2. 22
      libdevcore/CommonJS.cpp
  3. 8
      libdevcore/CommonJS.h
  4. 21
      libethcore/CommonEth.cpp
  5. 2
      libethcore/CommonEth.h
  6. 7
      libethereum/Client.cpp
  7. 41
      libethereum/State.cpp
  8. 10
      libethereum/State.h
  9. 6
      mix/AppContext.cpp
  10. 1
      mix/AssemblyDebuggerControl.cpp
  11. 37
      mix/ClientModel.cpp
  12. 3
      mix/ClientModel.h
  13. 98
      mix/ContractCallDataEncoder.cpp
  14. 16
      mix/ContractCallDataEncoder.h
  15. 1
      mix/Exceptions.h
  16. 79
      mix/MachineStates.h
  17. 15
      mix/MixClient.cpp
  18. 42
      mix/MixClient.h
  19. 3
      mix/QBigInt.h
  20. 8
      mix/QVariableDeclaration.h
  21. 90
      mix/QVariableDefinition.cpp
  22. 90
      mix/QVariableDefinition.h
  23. 1
      mix/main.cpp
  24. 101
      mix/qml/MainContent.qml
  25. 3
      mix/qml/ProjectModel.qml
  26. 7
      mix/qml/QBoolType.qml
  27. 42
      mix/qml/QBoolTypeView.qml
  28. 7
      mix/qml/QHashType.qml
  29. 22
      mix/qml/QHashTypeView.qml
  30. 7
      mix/qml/QIntType.qml
  31. 24
      mix/qml/QIntTypeView.qml
  32. 7
      mix/qml/QRealType.qml
  33. 15
      mix/qml/QRealTypeView.qml
  34. 7
      mix/qml/QStringType.qml
  35. 25
      mix/qml/QStringTypeView.qml
  36. 7
      mix/qml/QVariableDeclaration.qml
  37. 13
      mix/qml/QVariableDefinition.qml
  38. 47
      mix/qml/Splitter.qml
  39. 51
      mix/qml/StateListModel.qml
  40. 155
      mix/qml/TransactionDialog.qml
  41. 2
      mix/qml/WebPreview.qml
  42. 1
      mix/qml/html/codeeditor.js
  43. 3
      mix/qml/js/ProjectModel.js
  44. 39
      mix/qml/main.qml
  45. 13
      mix/res.qrc
  46. 7
      test/stateOriginal.cpp

7
alethzero/MainWin.cpp

@ -1209,8 +1209,9 @@ string Main::renderDiff(StateDiff const& _d) const
if (ad.balance) if (ad.balance)
{ {
s << "<br/>" << indent << "Balance " << dec << formatBalance(ad.balance.to()); s << "<br/>" << indent << "Balance " << dec << ad.balance.to() << " [=" << formatBalance(ad.balance.to()) << "]";
s << " <b>" << showpos << (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from())) << noshowpos << "</b>"; auto d = (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from()));
s << " <b>" << showpos << dec << d << " [=" << formatBalance(d) << "]" << noshowpos << "</b>";
} }
if (ad.nonce) if (ad.nonce)
{ {
@ -1219,7 +1220,7 @@ string Main::renderDiff(StateDiff const& _d) const
} }
if (ad.code) if (ad.code)
{ {
s << "<br/>" << indent << "Code " << hex << ad.code.to().size() << " bytes"; s << "<br/>" << indent << "Code " << dec << ad.code.to().size() << " bytes";
if (ad.code.from().size()) if (ad.code.from().size())
s << " (" << ad.code.from().size() << " bytes)"; s << " (" << ad.code.from().size() << " bytes)";
} }

22
libdevcore/CommonJS.cpp

@ -45,6 +45,12 @@ bytes padded(bytes _b, unsigned _l)
return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l))); return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
} }
bytes paddedRight(bytes _b, unsigned _l)
{
_b.resize(_l);
return _b;
}
bytes unpadded(bytes _b) bytes unpadded(bytes _b)
{ {
auto p = asString(_b).find_last_not_of((char)0); auto p = asString(_b).find_last_not_of((char)0);
@ -52,12 +58,18 @@ bytes unpadded(bytes _b)
return _b; return _b;
} }
std::string unpadLeft(std::string _b) bytes unpadLeft(bytes _b)
{ {
auto p = _b.find_first_not_of('0'); unsigned int i = 0;
if (p == std::string::npos) if (_b.size() == 0)
return "0"; return _b;
return _b.substr(p, _b.length() - 1);
while (i < _b.size() && _b[i] == byte(0))
i++;
if (i != 0)
_b.erase(_b.begin(), _b.begin() + i);
return _b;
} }
std::string prettyU256(u256 _n) std::string prettyU256(u256 _n)

8
libdevcore/CommonJS.h

@ -48,12 +48,14 @@ inline std::string toJS(dev::bytes const& _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. /// 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); bytes jsToBytes(std::string const& _s);
/// Add '0' on the head of _b until _l. /// Add '0' on the head of @a _b until @a _l.
bytes padded(bytes _b, unsigned _l); bytes padded(bytes _b, unsigned _l);
/// Add '0' on the queue of @a _b until @a _l.
bytes paddedRight(bytes _b, unsigned _l);
/// Removing all trailing '0'. Returns empty array if input contains only '0' char. /// Removing all trailing '0'. Returns empty array if input contains only '0' char.
bytes unpadded(bytes _s); bytes unpadded(bytes _s);
/// Remove all '0' on the head of _s. Returns 0 if _s contains only '0'. /// Remove all 0 byte on the head of @a _s.
std::string unpadLeft(std::string _s); bytes unpadLeft(bytes _s);
/// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256. /// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256.
std::string prettyU256(u256 _n); std::string prettyU256(u256 _n);
/// Convert h256 into user-readable string (by directly using std::string constructor). /// Convert h256 into user-readable string (by directly using std::string constructor).

21
libethcore/CommonEth.cpp

@ -63,22 +63,31 @@ vector<pair<u256, string>> const& units()
return g_units; return g_units;
} }
std::string formatBalance(u256 _b) std::string formatBalance(bigint const& _b)
{ {
ostringstream ret; ostringstream ret;
if (_b > g_units[0].first * 10000) u256 b;
if (_b < 0)
{ {
ret << (_b / g_units[0].first) << " " << g_units[0].second; ret << "-";
b = (u256)-_b;
}
else
b = (u256)_b;
if (b > g_units[0].first * 10000)
{
ret << (b / g_units[0].first) << " " << g_units[0].second;
return ret.str(); return ret.str();
} }
ret << setprecision(5); ret << setprecision(5);
for (auto const& i: g_units) for (auto const& i: g_units)
if (i.first != 1 && _b >= i.first * 100) if (i.first != 1 && b >= i.first * 100)
{ {
ret << (double(_b / (i.first / 1000)) / 1000.0) << " " << i.second; ret << (double(b / (i.first / 1000)) / 1000.0) << " " << i.second;
return ret.str(); return ret.str();
} }
ret << _b << " wei"; ret << b << " wei";
return ret.str(); return ret.str();
} }

2
libethcore/CommonEth.h

@ -39,7 +39,7 @@ extern const unsigned c_protocolVersion;
extern const unsigned c_databaseVersion; extern const unsigned c_databaseVersion;
/// User-friendly string representation of the amount _b in wei. /// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b); std::string formatBalance(bigint const& _b);
/// Get information concerning the currency denominations. /// Get information concerning the currency denominations.
std::vector<std::pair<u256, std::string>> const& units(); std::vector<std::pair<u256, std::string>> const& units();

7
libethereum/Client.cpp

@ -226,7 +226,7 @@ void Client::uninstallWatch(unsigned _i)
void Client::noteChanged(h256Set const& _filters) void Client::noteChanged(h256Set const& _filters)
{ {
Guard l(m_filterLock); Guard l(m_filterLock);
cnote << "noteChanged(" << _filters << ")"; // cnote << "noteChanged(" << _filters << ")";
// accrue all changes left in each filter into the watches. // accrue all changes left in each filter into the watches.
for (auto& i: m_watches) for (auto& i: m_watches)
if (_filters.count(i.second.id)) if (_filters.count(i.second.id))
@ -361,13 +361,12 @@ void Client::setupState(State& _s)
cwork << "SETUP MINE"; cwork << "SETUP MINE";
_s = m_postMine; _s = m_postMine;
} }
_s.setUncles(m_bc);
if (m_paranoia) if (m_paranoia)
{ {
if (_s.amIJustParanoid(m_bc)) if (_s.amIJustParanoid(m_bc))
{ {
cnote << "I'm just paranoid. Block is fine."; cnote << "I'm just paranoid. Block is fine.";
_s.commitToMine(); _s.commitToMine(m_bc);
} }
else else
{ {
@ -375,7 +374,7 @@ void Client::setupState(State& _s)
} }
} }
else else
_s.commitToMine(); _s.commitToMine(m_bc);
} }
void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)

41
libethereum/State.cpp

@ -639,8 +639,7 @@ void State::uncommitToMine()
bool State::amIJustParanoid(BlockChain const& _bc) bool State::amIJustParanoid(BlockChain const& _bc)
{ {
setUncles(_bc); commitToMine(_bc);
commitToMine();
// Update difficulty according to timestamp. // Update difficulty according to timestamp.
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
@ -683,8 +682,20 @@ LogBloom State::logBloom() const
return ret; return ret;
} }
void State::setUncles(BlockChain const& _bc) void State::commitToMine(BlockChain const& _bc)
{ {
uncommitToMine();
// cnote << "Committing to mine on block" << m_previousBlock.hash.abridged();
#ifdef ETH_PARANOIA
commit();
cnote << "Pre-reward stateRoot:" << m_state.root();
#endif
m_lastTx = m_db;
Addresses uncleAddresses;
RLPStream unclesData; RLPStream unclesData;
unsigned unclesCount = 0; unsigned unclesCount = 0;
if (m_previousBlock != BlockChain::genesis()) if (m_previousBlock != BlockChain::genesis())
@ -703,26 +714,11 @@ void State::setUncles(BlockChain const& _bc)
BlockInfo ubi(_bc.block(u)); BlockInfo ubi(_bc.block(u));
ubi.streamRLP(unclesData, WithNonce); ubi.streamRLP(unclesData, WithNonce);
++unclesCount; ++unclesCount;
uncleAddresses.push_back(ubi.coinbaseAddress);
} }
} }
} }
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
m_currentBlock.sha3Uncles = sha3(m_currentUncles);
}
void State::commitToMine()
{
uncommitToMine();
// cnote << "Committing to mine on block" << m_previousBlock.hash.abridged();
#ifdef ETH_PARANOIA
commit();
cnote << "Pre-reward stateRoot:" << m_state.root();
#endif
m_lastTx = m_db;
MemoryDB tm; MemoryDB tm;
GenericTrieDB<MemoryDB> transactionsTrie(&tm); GenericTrieDB<MemoryDB> transactionsTrie(&tm);
transactionsTrie.init(); transactionsTrie.init();
@ -752,13 +748,12 @@ void State::commitToMine()
txs.swapOut(m_currentTxs); txs.swapOut(m_currentTxs);
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
m_currentBlock.transactionsRoot = transactionsTrie.root(); m_currentBlock.transactionsRoot = transactionsTrie.root();
m_currentBlock.receiptsRoot = receiptsTrie.root(); m_currentBlock.receiptsRoot = receiptsTrie.root();
m_currentBlock.logBloom = logBloom(); m_currentBlock.logBloom = logBloom();
m_currentBlock.sha3Uncles = sha3(m_currentUncles);
Addresses uncleAddresses;
for (const auto& r: RLP(m_currentUncles))
uncleAddresses.push_back(BlockInfo::fromHeader(r.data()).coinbaseAddress);
// Apply rewards last of all. // Apply rewards last of all.
applyRewards(uncleAddresses); applyRewards(uncleAddresses);

10
libethereum/State.h

@ -105,16 +105,13 @@ public:
/// @returns true if all is ok. If it's false, worry. /// @returns true if all is ok. If it's false, worry.
bool amIJustParanoid(BlockChain const& _bc); bool amIJustParanoid(BlockChain const& _bc);
/// @brief Loads current block uncles from blockchain
void setUncles(BlockChain const& _bc);
/// Prepares the current state for mining. /// Prepares the current state for mining.
/// Commits all transactions into the trie, compiles uncles and transactions list, applies all /// Commits all transactions into the trie, compiles uncles and transactions list, applies all
/// rewards and populates the current block header with the appropriate hashes. /// rewards and populates the current block header with the appropriate hashes.
/// The only thing left to do after this is to actually mine(). /// The only thing left to do after this is to actually mine().
/// ///
/// This may be called multiple times and without issue. /// This may be called multiple times and without issue.
void commitToMine(); void commitToMine(BlockChain const& _bc);
/// Attempt to find valid nonce for block that this state represents. /// Attempt to find valid nonce for block that this state represents.
/// This function is thread-safe. You can safely have other interactions with this object while it is happening. /// This function is thread-safe. You can safely have other interactions with this object while it is happening.
@ -125,11 +122,14 @@ public:
/** Commit to DB and build the final block if the previous call to mine()'s result is completion. /** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like: * Typically looks like:
* @code * @code
* while (notYetMined)
* {
* // lock * // lock
* commitToMine(); * commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* // unlock * // unlock
* MineInfo info; * MineInfo info;
* for (info.complete = false; !info.complete; info = mine()) {} * for (info.complete = false; !info.complete; info = mine()) {}
* }
* // lock * // lock
* completeMine(); * completeMine();
* // unlock * // unlock

6
mix/AppContext.cpp

@ -63,6 +63,12 @@ void AppContext::load()
m_applicationEngine->rootContext()->setContextProperty("fileIo", m_fileIo.get()); m_applicationEngine->rootContext()->setContextProperty("fileIo", m_fileIo.get());
qmlRegisterType<QEther>("org.ethereum.qml.QEther", 1, 0, "QEther"); qmlRegisterType<QEther>("org.ethereum.qml.QEther", 1, 0, "QEther");
qmlRegisterType<QBigInt>("org.ethereum.qml.QBigInt", 1, 0, "QBigInt"); qmlRegisterType<QBigInt>("org.ethereum.qml.QBigInt", 1, 0, "QBigInt");
qmlRegisterType<QIntType>("org.ethereum.qml.QIntType", 1, 0, "QIntType");
qmlRegisterType<QRealType>("org.ethereum.qml.QRealType", 1, 0, "QRealType");
qmlRegisterType<QStringType>("org.ethereum.qml.QStringType", 1, 0, "QStringType");
qmlRegisterType<QHashType>("org.ethereum.qml.QHashType", 1, 0, "QHashType");
qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration");
QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml")); QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml"));
QObject* projectModel = projectModelComponent.create(); QObject* projectModel = projectModelComponent.create();
if (projectModelComponent.isError()) if (projectModelComponent.isError())

1
mix/AssemblyDebuggerControl.cpp

@ -20,7 +20,6 @@
#include <QDebug> #include <QDebug>
#include <QQmlContext> #include <QQmlContext>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include "AppContext.h"
#include "ClientModel.h" #include "ClientModel.h"
#include "AssemblyDebuggerControl.h" #include "AssemblyDebuggerControl.h"

37
mix/ClientModel.cpp

@ -66,6 +66,10 @@ ClientModel::ClientModel(AppContext* _context):
m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address()) m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address())
{ {
qRegisterMetaType<QBigInt*>("QBigInt*"); qRegisterMetaType<QBigInt*>("QBigInt*");
qRegisterMetaType<QIntType*>("QIntType*");
qRegisterMetaType<QStringType*>("QStringType*");
qRegisterMetaType<QRealType*>("QRealType*");
qRegisterMetaType<QHashType*>("QHashType*");
qRegisterMetaType<QEther*>("QEther*"); qRegisterMetaType<QEther*>("QEther*");
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*"); qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*"); qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*");
@ -146,13 +150,13 @@ void ClientModel::setupState(QVariantMap _state)
} }
else else
{ {
QVariantMap params = transaction.value("parameters").toMap(); QVariantList qParams = transaction.value("qType").toList();
TransactionSettings transactionSettings(functionId, value, gas, gasPrice); TransactionSettings transactionSettings(functionId, value, gas, gasPrice);
for (auto p = params.cbegin(); p != params.cend(); ++p) for (QVariant const& variant: qParams)
{ {
QBigInt* param = qvariant_cast<QBigInt*>(p.value()); QVariableDefinition* param = qvariant_cast<QVariableDefinition*>(variant);
transactionSettings.parameterValues.insert(std::make_pair(p.key(), boost::get<dev::u256>(param->internalValue()))); transactionSettings.parameterValues.push_back(param);
} }
if (transaction.value("executeConstructor").toBool()) if (transaction.value("executeConstructor").toBool())
@ -212,14 +216,11 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString())); BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString()));
encoder.encode(f); encoder.encode(f);
for (int p = 0; p < f->parametersList().size(); p++) for (int p = 0; p < transaction.parameterValues.size(); p++)
{ {
QVariableDeclaration* var = f->parametersList().at(p); if (f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type())
u256 value = 0; BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(f->parametersList().at(p)->type().toStdString()));
auto v = transaction.parameterValues.find(var->name()); encoder.push(transaction.parameterValues.at(p)->encodeValue());
if (v != transaction.parameterValues.cend())
value = v->second;
encoder.encode(var, value);
} }
if (transaction.functionId.isEmpty()) if (transaction.functionId.isEmpty())
@ -330,11 +331,6 @@ void ClientModel::onNewTransaction()
bool creation = tr.contractAddress != 0; bool creation = tr.contractAddress != 0;
if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress));
else
returned = QString::fromStdString(toJS(tr.returnValue));
//TODO: handle value transfer //TODO: handle value transfer
FixedHash<4> functionHash; FixedHash<4> functionHash;
bool call = false; bool call = false;
@ -363,6 +359,9 @@ void ClientModel::onNewTransaction()
function = QObject::tr("<none>"); function = QObject::tr("<none>");
} }
if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress));
if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress)) if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress))
{ {
auto compilerRes = m_context->codeModel()->code(); auto compilerRes = m_context->codeModel()->code();
@ -372,7 +371,13 @@ void ClientModel::onNewTransaction()
{ {
QFunctionDefinition* funcDef = def->getFunction(functionHash); QFunctionDefinition* funcDef = def->getFunction(functionHash);
if (funcDef) if (funcDef)
{
function = funcDef->name(); function = funcDef->name();
ContractCallDataEncoder encoder;
QList<QVariableDefinition*> returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue);
for (auto const& var: returnValues)
returned += var->value() + " | ";
}
} }
} }

3
mix/ClientModel.h

@ -27,6 +27,7 @@
#include <map> #include <map>
#include <QString> #include <QString>
#include "MixClient.h" #include "MixClient.h"
#include "QVariableDefinition.h"
namespace dev namespace dev
{ {
@ -59,7 +60,7 @@ struct TransactionSettings
/// Gas price /// Gas price
u256 gasPrice; u256 gasPrice;
/// Mapping from contract function parameter name to value /// Mapping from contract function parameter name to value
std::map<QString, u256> parameterValues; QList<QVariableDefinition*> parameterValues;
/// Standard contract url /// Standard contract url
QString stdContractUrl; QString stdContractUrl;
}; };

98
mix/ContractCallDataEncoder.cpp

@ -44,89 +44,37 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function)
m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end());
} }
void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, bool _value) void ContractCallDataEncoder::push(bytes const& _b)
{ {
return encode(_dec, QString(formatBool(_value))); m_encodedData.insert(m_encodedData.end(), _b.begin(), _b.end());
} }
void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, QString _value) QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const& _returnParameters, bytes _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 const* _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; QList<QVariableDefinition*> r;
std::string returnValue = toJS(_value);
returnValue = returnValue.substr(2, returnValue.length() - 1);
for (int k = 0; k <_returnParameters.length(); k++) for (int k = 0; k <_returnParameters.length(); k++)
{ {
QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k); QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k);
int padding = this->padding(dec->type()); QVariableDefinition* def = nullptr;
std::string rawParam = returnValue.substr(0, padding * 2); if (dec->type().contains("int"))
r.append(new QVariableDefinition(dec, convertToReadable(unpadLeft(rawParam), dec))); def = new QIntType(dec, QString());
returnValue = returnValue.substr(rawParam.length(), returnValue.length() - 1); else if (dec->type().contains("real"))
} def = new QRealType(dec, QString());
return r; else if (dec->type().contains("bool"))
} def = new QBoolType(dec, QString());
else if (dec->type().contains("string") || dec->type().contains("text"))
int ContractCallDataEncoder::padding(QString type) def = new QStringType(dec, QString());
{ else if (dec->type().contains("hash") || dec->type().contains("address"))
// TODO : to be improved (load types automatically from solidity library). def = new QHashType(dec, QString());
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 32;
else else
return 0; BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found"));
}
bytes rawParam(_value.begin(), _value.begin() + 32);
int ContractCallDataEncoder::integerPadding(int bitValue) def->decodeValue(rawParam);
{ r.push_back(def);
return bitValue / 8; if (_value.size() > 32)
_value = bytes(_value.begin() + 32, _value.end());
qDebug() << "decoded return value : " << dec->type() << " " << def->value();
} }
return r;
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());
} }

16
mix/ContractCallDataEncoder.h

@ -41,27 +41,17 @@ class ContractCallDataEncoder
{ {
public: public:
ContractCallDataEncoder() {} ContractCallDataEncoder() {}
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration const* _dec, QString _value);
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration const* _dec, u256 _value);
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration const* _dec, bool _value);
/// Encode hash of the function to call. /// Encode hash of the function to call.
void encode(QFunctionDefinition const* _function); void encode(QFunctionDefinition const* _function);
/// Decode variable in order to be sent to QML view. /// Decode variable in order to be sent to QML view.
QList<QVariableDefinition*> decode(QList<QVariableDeclaration*> _dec, bytes _value); QList<QVariableDefinition*> decode(QList<QVariableDeclaration*> const& _dec, bytes _value);
/// Get all encoded data encoded by encode function. /// Get all encoded data encoded by encode function.
bytes encodedData(); bytes encodedData();
/// Push the given @a _b to the current param context.
void push(bytes const& _b);
private: private:
int padding(QString _type);
bytes m_encodedData; 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);
}; };
} }

1
mix/Exceptions.h

@ -38,6 +38,7 @@ struct FileIoException: virtual Exception {};
struct InvalidBlockException: virtual Exception {}; struct InvalidBlockException: virtual Exception {};
struct FunctionNotFoundException: virtual Exception {}; struct FunctionNotFoundException: virtual Exception {};
struct ExecutionStateException: virtual Exception {}; struct ExecutionStateException: virtual Exception {};
struct ParameterChangedException: virtual Exception {};
typedef boost::error_info<struct tagQmlError, QQmlError> QmlErrorInfo; typedef boost::error_info<struct tagQmlError, QQmlError> QmlErrorInfo;
typedef boost::error_info<struct tagFileError, std::string> FileError; typedef boost::error_info<struct tagFileError, std::string> FileError;

79
mix/MachineStates.h

@ -0,0 +1,79 @@
/*
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 MixClient.h
* @author Yann yann@ethdev.com
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2015
* Ethereum IDE client.
*/
#pragma once
#include <vector>
#include <map>
#include <stdint.h>
#include <libdevcore/Common.h>
#include <libdevcrypto/Common.h>
#include <libevmcore/Instruction.h>
#include <libethereum/TransactionReceipt.h>
namespace dev
{
namespace mix
{
/**
* @brief Store information about a machine state.
*/
struct MachineState
{
uint64_t steps;
dev::Address address;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<unsigned> levels;
unsigned codeIndex;
unsigned dataIndex;
};
/**
* @brief Store information about a machine states.
*/
struct ExecutionResult
{
ExecutionResult() : receipt(dev::h256(), dev::h256(), dev::eth::LogEntries()) {}
std::vector<MachineState> machineStates;
std::vector<bytes> transactionData;
std::vector<bytes> executionCode;
bytes returnValue;
dev::Address address;
dev::Address sender;
dev::Address contractAddress;
dev::u256 value;
dev::eth::TransactionReceipt receipt;
};
using ExecutionResults = std::vector<ExecutionResult>;
}
}

15
mix/MixClient.cpp

@ -56,16 +56,15 @@ void MixClient::resetState(u256 _balance)
genesis.state = m_state; genesis.state = m_state;
Block open; Block open;
m_blocks = Blocks { genesis, open }; //last block contains a list of pending transactions to be finalized m_blocks = Blocks { genesis, open }; //last block contains a list of pending transactions to be finalized
m_lastHashes.clear(); // m_lastHashes.clear();
m_lastHashes.resize(256); // m_lastHashes.resize(256);
m_lastHashes[0] = genesis.hash; // m_lastHashes[0] = genesis.hash;
} }
void MixClient::executeTransaction(Transaction const& _t, State& _state) void MixClient::executeTransaction(Transaction const& _t, State& _state)
{ {
bytes rlp = _t.rlp(); bytes rlp = _t.rlp();
Executive execution(_state, LastHashes(), 0);
Executive execution(_state, m_lastHashes, 0);
execution.setup(&rlp); execution.setup(&rlp);
std::vector<MachineState> machineStates; std::vector<MachineState> machineStates;
std::vector<unsigned> levels; std::vector<unsigned> levels;
@ -165,14 +164,12 @@ void MixClient::mine()
Block& block = m_blocks.back(); Block& block = m_blocks.back();
m_state.mine(0, true); m_state.mine(0, true);
m_state.completeMine(); m_state.completeMine();
m_state.commitToMine(); m_state.commitToMine(BlockChain());
m_state.cleanup(true);
block.state = m_state; block.state = m_state;
block.info = m_state.info(); block.info = m_state.info();
block.hash = block.info.hash; block.hash = block.info.hash;
m_state.cleanup(true);
m_blocks.push_back(Block()); m_blocks.push_back(Block());
m_lastHashes.insert(m_lastHashes.begin(), block.hash);
m_lastHashes.resize(256);
h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter };
noteChanged(changed); noteChanged(changed);

42
mix/MixClient.h

@ -26,52 +26,13 @@
#include <vector> #include <vector>
#include <libethereum/Interface.h> #include <libethereum/Interface.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include "MachineStates.h"
namespace dev namespace dev
{ {
namespace mix namespace mix
{ {
/**
* @brief Store information about a machine state.
*/
struct MachineState
{
uint64_t steps;
dev::Address address;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<unsigned> levels;
unsigned codeIndex;
unsigned dataIndex;
};
/**
* @brief Store information about a machine states.
*/
struct ExecutionResult
{
ExecutionResult(): receipt(dev::h256(), dev::h256(), dev::eth::LogEntries()) {}
std::vector<MachineState> machineStates;
std::vector<bytes> transactionData;
std::vector<bytes> executionCode;
bytes returnValue;
dev::Address address;
dev::Address sender;
dev::Address contractAddress;
dev::u256 value;
dev::eth::TransactionReceipt receipt;
};
using ExecutionResults = std::vector<ExecutionResult>;
struct Block struct Block
{ {
ExecutionResults transactions; ExecutionResults transactions;
@ -145,7 +106,6 @@ private:
std::map<h256, dev::eth::InstalledFilter> m_filters; std::map<h256, dev::eth::InstalledFilter> m_filters;
std::map<unsigned, dev::eth::ClientWatch> m_watches; std::map<unsigned, dev::eth::ClientWatch> m_watches;
Blocks m_blocks; Blocks m_blocks;
eth::LastHashes m_lastHashes;
}; };
} }

3
mix/QBigInt.h

@ -36,7 +36,7 @@ namespace dev
namespace mix namespace mix
{ {
using BigIntVariant = boost::variant<dev::u256, dev::bigint>; using BigIntVariant = boost::variant<dev::u256, dev::bigint, dev::s256>;
struct add: public boost::static_visitor<BigIntVariant> struct add: public boost::static_visitor<BigIntVariant>
{ {
@ -75,6 +75,7 @@ public:
QBigInt(dev::u256 const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } QBigInt(dev::u256 const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
QBigInt(dev::bigint const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } QBigInt(dev::bigint const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
QBigInt(BigIntVariant const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value){ QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } QBigInt(BigIntVariant const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value){ QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
QBigInt(dev::s256 const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
~QBigInt() {} ~QBigInt() {}
/// @returns the current used big integer. /// @returns the current used big integer.

8
mix/QVariableDeclaration.h

@ -19,6 +19,8 @@
* @date 2014 * @date 2014
*/ */
#include <QDebug>
#include <QStringList>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include "QBasicNodeDefinition.h" #include "QBasicNodeDefinition.h"
@ -32,16 +34,20 @@ namespace mix
class QVariableDeclaration: public QBasicNodeDefinition class QVariableDeclaration: public QBasicNodeDefinition
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString type READ type CONSTANT) Q_PROPERTY(QString type READ type WRITE setType)
public: public:
QVariableDeclaration() {} QVariableDeclaration() {}
QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {} QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {}
QVariableDeclaration(std::string const& _name, std::string const& _type): QBasicNodeDefinition(_name), m_type(QString::fromStdString(_type)) {} QVariableDeclaration(std::string const& _name, std::string const& _type): QBasicNodeDefinition(_name), m_type(QString::fromStdString(_type)) {}
QString type() const { return m_type; } QString type() const { return m_type; }
void setType(QString _type) { m_type = _type; }
private: private:
QString m_type; QString m_type;
}; };
} }
} }
Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*)

90
mix/QVariableDefinition.cpp

@ -19,6 +19,8 @@
* @date 2014 * @date 2014
*/ */
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonJS.h>
#include "QVariableDefinition.h" #include "QVariableDefinition.h"
using namespace dev::mix; using namespace dev::mix;
@ -53,3 +55,91 @@ QVariableDefinition* QVariableDefinitionList::val(int _idx)
return nullptr; return nullptr;
return m_def.at(_idx); return m_def.at(_idx);
} }
/*
* QIntType
*/
void QIntType::setValue(dev::bigint _value)
{
m_bigIntvalue = _value;
std::stringstream str;
str << std::dec << m_bigIntvalue;
m_value = QString::fromStdString(str.str());
}
dev::bytes QIntType::encodeValue()
{
dev::bigint i(value().toStdString());
bytes ret(32);
toBigEndian((u256)i, ret);
return ret;
}
void QIntType::decodeValue(dev::bytes const& _rawValue)
{
dev::u256 un = dev::fromBigEndian<dev::u256>(_rawValue);
if (un >> 255)
setValue(-s256(~un + 1));
else
setValue(un);
}
/*
* QHashType
*/
dev::bytes QHashType::encodeValue()
{
QByteArray bytesAr = value().toLocal8Bit();
bytes r = bytes(bytesAr.begin(), bytesAr.end());
return padded(r, 32);
}
void QHashType::decodeValue(dev::bytes const& _rawValue)
{
std::string _ret = asString(unpadLeft(_rawValue));
setValue(QString::fromStdString(_ret));
}
/*
* QRealType
*/
dev::bytes QRealType::encodeValue()
{
return bytes();
}
void QRealType::decodeValue(dev::bytes const& _rawValue)
{
Q_UNUSED(_rawValue);
}
/*
* QStringType
*/
dev::bytes QStringType::encodeValue()
{
QByteArray b = value().toUtf8();
bytes r = bytes(b.begin(), b.end());
return paddedRight(r, 32);
}
void QStringType::decodeValue(dev::bytes const& _rawValue)
{
setValue(QString::fromUtf8((char*)_rawValue.data()));
}
/*
* QBoolType
*/
dev::bytes QBoolType::encodeValue()
{
return padded(jsToBytes(value().toStdString()), 32);
}
void QBoolType::decodeValue(dev::bytes const& _rawValue)
{
byte ret = _rawValue.at(_rawValue.size() - 1);
bool boolRet = (ret == byte(1));
m_boolValue = boolRet;
m_value = m_boolValue ? "1" : "0";
}

90
mix/QVariableDefinition.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <QAbstractListModel> #include <QAbstractListModel>
#include "QBigInt.h"
#include "QVariableDeclaration.h" #include "QVariableDeclaration.h"
namespace dev namespace dev
@ -37,15 +38,26 @@ class QVariableDefinition: public QObject
Q_PROPERTY(QVariableDeclaration* declaration READ declaration CONSTANT) Q_PROPERTY(QVariableDeclaration* declaration READ declaration CONSTANT)
public: public:
QVariableDefinition() {}
QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(), m_value(_value), m_dec(_def) {} QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(), m_value(_value), m_dec(_def) {}
/// Return the associated declaration of this variable definition. /// Return the associated declaration of this variable definition. Invokable from QML.
QVariableDeclaration* declaration() const { return m_dec; } Q_INVOKABLE QVariableDeclaration* declaration() const { return m_dec; }
/// Return the variable value. /// Return the variable value.
QString value() const { return m_value; } QString value() const { return m_value; }
/// Set a new value for this instance. Invokable from QML.
Q_INVOKABLE void setValue(QString _value) { m_value = _value; }
/// Set a new Declaration for this instance. Invokable from QML.
Q_INVOKABLE void setDeclaration(QVariableDeclaration* _dec) { m_dec = _dec; }
/// Encode the current value in order to be used as function parameter.
virtual bytes encodeValue() = 0;
/// Decode the return value @a _rawValue.
virtual void decodeValue(dev::bytes const& _rawValue) = 0;
protected:
QString m_value;
private: private:
QString m_value;
QVariableDeclaration* m_dec; QVariableDeclaration* m_dec;
}; };
@ -67,7 +79,77 @@ private:
QList<QVariableDefinition*> m_def; QList<QVariableDefinition*> m_def;
}; };
class QIntType: public QVariableDefinition
{
Q_OBJECT
public:
QIntType() {}
QIntType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
/// @returns an instance of QBigInt for the current value.
QBigInt* toBigInt() { return new QBigInt(m_bigIntvalue); }
dev::bigint bigInt() { return m_bigIntvalue; }
void setValue(dev::bigint _value);
private:
dev::bigint m_bigIntvalue;
};
class QRealType: public QVariableDefinition
{
Q_OBJECT
public:
QRealType() {}
QRealType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
};
class QStringType: public QVariableDefinition
{
Q_OBJECT
public:
QStringType() {}
QStringType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
};
class QHashType: public QVariableDefinition
{
Q_OBJECT
public:
QHashType() {}
QHashType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
};
class QBoolType: public QVariableDefinition
{
Q_OBJECT
public:
QBoolType() {}
QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
/// @returns the boolean value for the current definition.
bool toBool() { return m_boolValue; }
private:
bool m_boolValue;
};
} }
} }
Q_DECLARE_METATYPE(dev::mix::QVariableDefinition*) Q_DECLARE_METATYPE(dev::mix::QIntType*)
Q_DECLARE_METATYPE(dev::mix::QStringType*)
Q_DECLARE_METATYPE(dev::mix::QHashType*)
Q_DECLARE_METATYPE(dev::mix::QBoolType*)

1
mix/main.cpp

@ -35,6 +35,7 @@ int main(int _argc, char* _argv[])
//work around ubuntu appmenu-qt5 bug //work around ubuntu appmenu-qt5 bug
//https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853 //https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853
putenv((char*)"QT_QPA_PLATFORMTHEME="); putenv((char*)"QT_QPA_PLATFORMTHEME=");
putenv((char*)"QSG_RENDER_LOOP=threaded");
#endif #endif
try try
{ {

101
mix/qml/MainContent.qml

@ -23,14 +23,20 @@ Rectangle {
property alias rightViewVisible : rightView.visible property alias rightViewVisible : rightView.visible
property alias webViewVisible : webPreview.visible property alias webViewVisible : webPreview.visible
property alias projectViewVisible : projectList.visible
property alias runOnProjectLoad : mainSettings.runOnProjectLoad
property bool webViewHorizontal : codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally property bool webViewHorizontal : codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally
property bool firstCompile: true
onWidthChanged: Connections {
{ target: codeModel
if (rightView.visible) onCompilationComplete: {
contentView.width = parent.width - projectList.width - rightView.width; if (firstCompile) {
else firstCompile = false;
contentView.width = parent.width - projectList.width; if (codeModel.code.successful && runOnProjectLoad)
startQuickDebugging();
}
}
} }
function startQuickDebugging() function startQuickDebugging()
@ -40,15 +46,11 @@ Rectangle {
} }
function toggleRightView() { function toggleRightView() {
if (!rightView.visible) rightView.visible = !rightView.visible;
rightView.show();
else
rightView.hide();
} }
function ensureRightView() { function ensureRightView() {
if (!rightView.visible) rightView.visible = true;
rightView.show();
} }
function rightViewIsVisible() function rightViewIsVisible()
@ -65,6 +67,10 @@ Rectangle {
webPreview.visible = !webPreview.visible; webPreview.visible = !webPreview.visible;
} }
function toggleProjectView() {
projectList.visible = !projectList.visible;
}
function toggleWebPreviewOrientation() { function toggleWebPreviewOrientation() {
codeWebSplitter.orientation = (codeWebSplitter.orientation === Qt.Vertical ? Qt.Horizontal : Qt.Vertical); codeWebSplitter.orientation = (codeWebSplitter.orientation === Qt.Vertical ? Qt.Horizontal : Qt.Vertical);
} }
@ -75,19 +81,18 @@ Rectangle {
} }
Settings { Settings {
id: mainLayoutSettings id: mainSettings
property alias codeWebOrientation: codeWebSplitter.orientation property alias codeWebOrientation: codeWebSplitter.orientation
property alias webWidth: webPreview.width property alias webWidth: webPreview.width
property alias webHeight: webPreview.height property alias webHeight: webPreview.height
property alias showProjectView: projectList.visible
property bool runOnProjectLoad: false
} }
GridLayout ColumnLayout
{ {
anchors.fill: parent anchors.fill: parent
rows: 2 spacing: 0
flow: GridLayout.TopToBottom
columnSpacing: 0
rowSpacing: 0
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 50 height: 50
@ -128,29 +133,26 @@ Rectangle {
property alias rightViewWidth: rightView.width property alias rightViewWidth: rightView.width
} }
SplitView
{
anchors.fill: parent
handleDelegate: Rectangle {
width: 4
height: 4
color: "#cccccc"
}
orientation: Qt.Horizontal
ProjectList { ProjectList {
anchors.left: parent.left
id: projectList id: projectList
width: 200 width: 200
height: parent.height Layout.minimumWidth: 180
Layout.minimumWidth: 200 Layout.fillHeight: true
}
Splitter
{
id: resizeLeft
itemToStick: projectList
itemMinimumWidth: projectList.Layout.minimumWidth
direction: "right"
brother: contentView
color: "#a2a2a2"
} }
Rectangle { Rectangle {
anchors.left: projectList.right
id: contentView id: contentView
width: parent.width - projectList.width Layout.fillHeight: true
height: parent.height Layout.fillWidth: true
SplitView { SplitView {
handleDelegate: Rectangle { handleDelegate: Rectangle {
width: 4 width: 4
@ -177,35 +179,11 @@ Rectangle {
} }
} }
Splitter
{
id: resizeRight
visible: false;
itemToStick: rightView
itemMinimumWidth: rightView.Layout.minimumWidth
direction: "left"
brother: contentView
color: "#a2a2a2"
}
Rectangle { Rectangle {
visible: false; visible: false;
id: rightView; id: rightView;
Layout.fillHeight: true
Keys.onEscapePressed: hide() Keys.onEscapePressed: visible = false
function show() {
visible = true;
resizeRight.visible = true;
contentView.width = parent.width - projectList.width - rightView.width;
}
function hide() {
resizeRight.visible = false;
visible = false;
contentView.width = parent.width - projectList.width;
}
height: parent.height; height: parent.height;
width: 515 width: 515
Layout.minimumWidth: 515 Layout.minimumWidth: 515
@ -245,6 +223,7 @@ Rectangle {
} }
} }
} }
}

3
mix/qml/ProjectModel.qml

@ -10,7 +10,8 @@ Item {
id: projectModel id: projectModel
signal projectClosed signal projectClosed
signal projectLoaded(var projectData) signal projectLoading(var projectData)
signal projectLoaded()
signal documentOpened(var document) signal documentOpened(var document)
signal documentRemoved(var documentId) signal documentRemoved(var documentId)
signal documentUpdated(var documentId) //renamed signal documentUpdated(var documentId) //renamed

7
mix/qml/QBoolType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QBoolType 1.0
QBoolType
{
}

42
mix/qml/QBoolTypeView.qml

@ -0,0 +1,42 @@
import QtQuick 2.0
import QtQuick.Controls 1.3
Item
{
id: editRoot
property string text
property string defaultValue
Rectangle {
anchors.fill: parent
ComboBox
{
property bool inited: false
Component.onCompleted:
{
if (text === "")
currentIndex = parseInt(defaultValue);
else
currentIndex = parseInt(text);
inited = true
}
id: boolCombo
anchors.fill: parent
onCurrentIndexChanged:
{
if (inited)
text = comboModel.get(currentIndex).value;
}
model: ListModel
{
id: comboModel
ListElement { text: qsTr("False"); value: "0" }
ListElement { text: qsTr("True"); value: "1" }
}
}
}
}

7
mix/qml/QHashType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QHashType 1.0
QHashType
{
}

22
mix/qml/QHashTypeView.qml

@ -0,0 +1,22 @@
import QtQuick 2.0
Item
{
property alias text: textinput.text
id: editRoot
Rectangle {
anchors.fill: parent
TextInput {
id: textinput
text: text
anchors.fill: parent
wrapMode: Text.WrapAnywhere
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}

7
mix/qml/QIntType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QIntType 1.0
QIntType
{
}

24
mix/qml/QIntTypeView.qml

@ -0,0 +1,24 @@
import QtQuick 2.0
Item
{
property alias text: textinput.text
id: editRoot
Rectangle {
anchors.fill: parent
TextInput {
id: textinput
text: text
anchors.fill: parent
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}

7
mix/qml/QRealType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QRealType 1.0
QRealType
{
}

15
mix/qml/QRealTypeView.qml

@ -0,0 +1,15 @@
import QtQuick 2.0
Component
{
Rectangle {
anchors.fill: parent
Text{
anchors.fill: parent
text: qsTr("Real")
}
}
}

7
mix/qml/QStringType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QStringType 1.0
QStringType
{
}

25
mix/qml/QStringTypeView.qml

@ -0,0 +1,25 @@
import QtQuick 2.0
Item
{
property alias text: textinput.text
id: editRoot
Rectangle {
anchors.fill: parent
TextInput {
id: textinput
text: text
anchors.fill: parent
wrapMode: Text.WrapAnywhere
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}

7
mix/qml/QVariableDeclaration.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QVariableDeclaration 1.0
QVariableDeclaration
{
}

13
mix/qml/QVariableDefinition.qml

@ -0,0 +1,13 @@
/*
* Used to instanciate a QVariableDefinition obj using Qt.createComponent function.
*/
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import org.ethereum.qml.QVariableDefinition 1.0
QVariableDefinition
{
id: qVariableDefinition
}

47
mix/qml/Splitter.qml

@ -1,47 +0,0 @@
import QtQuick 2.2
Rectangle {
property variant itemToStick;
property int itemMinimumWidth;
property string direction;
property variant brother;
Component.onCompleted:
{
if (direction === "left")
anchors.right = itemToStick.left;
else if (direction === "right")
anchors.left = itemToStick.right;
}
width: 5
height: parent.height
anchors.top: parent.top;
MouseArea
{
property int startX: 0;
anchors.fill: parent
onPressed: startX = mouseX;
onPositionChanged:
{
parent.x += mouseX;
var diff = 0;
if (direction == "left")
diff = mouseX - startX;
else if (direction == "right")
diff = -(mouseX - startX);
if (itemMinimumWidth > itemToStick.width - diff)
{
brother.width = brother.width + diff;
itemToStick.width = itemMinimumWidth;
}
else
{
brother.width = brother.width + diff;
itemToStick.width = itemToStick.width - diff;
}
}
cursorShape: Qt.SizeHorCursor
}
}

51
mix/qml/StateListModel.qml

@ -31,12 +31,30 @@ Item {
stdContract: t.stdContract, stdContract: t.stdContract,
parameters: {} parameters: {}
}; };
for (var key in t.parameters) { var qType = [];
var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml"); for (var key in t.parameters)
var param = intComponent.createObject(); {
param.setValue(t.parameters[key]); r.parameters[key] = t.parameters[key].value;
r.parameters[key] = param; var type = t.parameters[key].type;
} var varComponent;
if (type.indexOf("int") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QIntType.qml");
else if (type.indexOf("real") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QRealType.qml");
else if (type.indexOf("string") !== -1 || type.indexOf("text") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QStringType.qml");
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
else if (type.indexOf("bool") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml");
var param = varComponent.createObject(stateListModel);
var dec = Qt.createComponent("qrc:/qml/QVariableDeclaration.qml");
param.setDeclaration(dec.createObject(stateListModel, { "type": type }));
param.setValue(r.parameters[key]);
qType.push(param);
}
r.qType = qType;
return r; return r;
} }
@ -48,6 +66,16 @@ Item {
}; };
} }
function getParamType(param, params)
{
for (var k in params)
{
if (params[k].declaration.name === param)
return params[k].declaration.type;
}
return '';
}
function toPlainTransactionItem(t) { function toPlainTransactionItem(t) {
var r = { var r = {
functionId: t.functionId, functionId: t.functionId,
@ -60,7 +88,14 @@ Item {
parameters: {} parameters: {}
}; };
for (var key in t.parameters) for (var key in t.parameters)
r.parameters[key] = t.parameters[key].value(); {
var param = {
name: key,
value: t.parameters[key],
type: getParamType(key, t.qType)
}
r.parameters[key] = param;
}
return r; return r;
} }
@ -70,7 +105,7 @@ Item {
stateListModel.clear(); stateListModel.clear();
stateList = []; stateList = [];
} }
onProjectLoaded: stateListModel.loadStatesFromProject(projectData); onProjectLoading: stateListModel.loadStatesFromProject(projectData);
onProjectSaving: { onProjectSaving: {
projectData.states = [] projectData.states = []
for(var i = 0; i < stateListModel.count; i++) { for(var i = 0; i < stateListModel.count; i++) {

155
mix/qml/TransactionDialog.qml

@ -9,7 +9,7 @@ Window {
id: modalTransactionDialog id: modalTransactionDialog
modality: Qt.WindowModal modality: Qt.WindowModal
width:640 width:640
height:480 height:640
visible: false visible: false
property int transactionIndex property int transactionIndex
@ -21,10 +21,12 @@ Window {
property var itemParams; property var itemParams;
property bool isConstructorTransaction; property bool isConstructorTransaction;
property bool useTransactionDefaultValue: false property bool useTransactionDefaultValue: false
property var qType;
signal accepted; signal accepted;
function open(index, item) { function open(index, item) {
qType = [];
rowFunction.visible = !useTransactionDefaultValue; rowFunction.visible = !useTransactionDefaultValue;
rowValue.visible = !useTransactionDefaultValue; rowValue.visible = !useTransactionDefaultValue;
rowGas.visible = !useTransactionDefaultValue; rowGas.visible = !useTransactionDefaultValue;
@ -68,6 +70,7 @@ Window {
} }
function loadParameters() { function loadParameters() {
paramsModel.clear();
if (!paramsModel) if (!paramsModel)
return; return;
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
@ -75,7 +78,27 @@ Window {
var parameters = func.parameters; var parameters = func.parameters;
for (var p = 0; p < parameters.length; p++) { for (var p = 0; p < parameters.length; p++) {
var pname = parameters[p].name; var pname = parameters[p].name;
paramsModel.append({ name: pname, type: parameters[p].type, value: itemParams[pname] !== undefined ? itemParams[pname].value() : "" }); var varComponent;
var type = parameters[p].type;
if (type.indexOf("int") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QIntType.qml");
else if (type.indexOf("real") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QRealType.qml");
else if (type.indexOf("string") !== -1 || type.indexOf("text") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QStringType.qml");
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
else if (type.indexOf("bool") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml");
var param = varComponent.createObject(modalTransactionDialog);
var value = itemParams[pname] !== undefined ? itemParams[pname] : "";
param.setValue(value);
param.setDeclaration(parameters[p]);
qType.push({ name: pname, value: param });
paramsModel.append({ name: pname, type: parameters[p].type, value: value });
} }
} }
} }
@ -85,6 +108,15 @@ Window {
visible = false; visible = false;
} }
function qTypeParam(name)
{
for (var k in qType)
{
if (qType[k].name === name)
return qType[k].value;
}
}
function getItem() function getItem()
{ {
var item; var item;
@ -109,14 +141,15 @@ Window {
if (isConstructorTransaction) if (isConstructorTransaction)
item.functionId = qsTr("Constructor"); item.functionId = qsTr("Constructor");
var orderedQType = [];
for (var p = 0; p < transactionDialog.transactionParams.count; p++) { for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p); var parameter = transactionDialog.transactionParams.get(p);
var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml"); var qtypeParam = qTypeParam(parameter.name);
var param = intComponent.createObject(modalTransactionDialog); qtypeParam.setValue(parameter.value);
orderedQType.push(qtypeParam);
param.setValue(parameter.value); item.parameters[parameter.name] = parameter.value;
item.parameters[parameter.name] = param;
} }
item.qType = orderedQType;
return item; return item;
} }
@ -219,8 +252,10 @@ Window {
} }
TableView { TableView {
model: paramsModel model: paramsModel
Layout.fillWidth: true Layout.preferredWidth: 120 * 2 + 240
Layout.minimumHeight: 150
Layout.preferredHeight: 400
Layout.maximumHeight: 600
TableViewColumn { TableViewColumn {
role: "name" role: "name"
title: qsTr("Name") title: qsTr("Name")
@ -234,12 +269,11 @@ Window {
TableViewColumn { TableViewColumn {
role: "value" role: "value"
title: qsTr("Value") title: qsTr("Value")
width: 120 width: 240
} }
itemDelegate: { rowDelegate: rowDelegate
return editableDelegate; itemDelegate: editableDelegate
}
} }
} }
} }
@ -268,19 +302,15 @@ Window {
} }
Component { Component {
id: editableDelegate id: rowDelegate
Item { Item {
height: 100
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
} }
Component {
id: editableDelegate
Item {
Loader { Loader {
id: loaderEditor id: loaderEditor
anchors.fill: parent anchors.fill: parent
@ -289,14 +319,87 @@ Window {
target: loaderEditor.item target: loaderEditor.item
onTextChanged: { onTextChanged: {
if (styleData.role === "value" && styleData.row < paramsModel.count) if (styleData.role === "value" && styleData.row < paramsModel.count)
paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text); loaderEditor.updateValue(styleData.row, styleData.role, loaderEditor.item.text);
}
}
function updateValue(row, role, value)
{
paramsModel.setProperty(styleData.row, styleData.role, value);
}
sourceComponent:
{
if (styleData.role === "value")
{
if (paramsModel.get(styleData.row) === undefined)
return null;
if (paramsModel.get(styleData.row).type.indexOf("int") !== -1)
return intViewComp;
else if (paramsModel.get(styleData.row).type.indexOf("bool") !== -1)
return boolViewComp;
else if (paramsModel.get(styleData.row).type.indexOf("string") !== -1)
return stringViewComp;
else if (paramsModel.get(styleData.row).type.indexOf("hash") !== -1)
return hashViewComp;
}
else
return editor;
}
Component
{
id: intViewComp
QIntTypeView
{
id: intView
text: styleData.value
}
}
Component
{
id: boolViewComp
QBoolTypeView
{
id: boolView
defaultValue: "1"
Component.onCompleted:
{
loaderEditor.updateValue(styleData.row, styleData.role,
(paramsModel.get(styleData.row).value === "" ? defaultValue :
paramsModel.get(styleData.row).value));
text = (paramsModel.get(styleData.row).value === "" ? defaultValue : paramsModel.get(styleData.row).value);
} }
} }
sourceComponent: (styleData.selected) ? editor : null }
Component
{
id: stringViewComp
QStringTypeView
{
id: stringView
text: styleData.value
}
}
Component
{
id: hashViewComp
QHashTypeView
{
id: hashView
text: styleData.value
}
}
Component { Component {
id: editor id: editor
TextInput { TextInput {
id: textinput id: textinput
readOnly: true
color: styleData.textColor color: styleData.textColor
text: styleData.value text: styleData.value
MouseArea { MouseArea {

2
mix/qml/WebPreview.qml

@ -86,7 +86,7 @@ Item {
updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } ) updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } )
} }
onProjectLoaded: { onProjectLoading: {
for (var i = 0; i < target.listModel.count; i++) { for (var i = 0; i < target.listModel.count; i++) {
var document = target.listModel.get(i); var document = target.listModel.get(i);
if (document.isHtml) { if (document.isHtml) {

1
mix/qml/html/codeeditor.js

@ -31,6 +31,7 @@ getText = function() {
setTextBase64 = function(text) { setTextBase64 = function(text) {
editor.setValue(window.atob(text)); editor.setValue(window.atob(text));
editor.getDoc().clearHistory();
editor.focus(); editor.focus();
}; };

3
mix/qml/js/ProjectModel.js

@ -73,7 +73,8 @@ function loadProject(path) {
addFile(projectData.files[i]); addFile(projectData.files[i]);
} }
projectSettings.lastProjectPath = path; projectSettings.lastProjectPath = path;
projectLoaded(projectData); projectLoading(projectData);
projectLoaded()
} }
function addExistingFile() { function addExistingFile() {

39
mix/qml/main.qml

@ -36,14 +36,16 @@ ApplicationWindow {
Menu { Menu {
title: qsTr("Deploy") title: qsTr("Deploy")
MenuItem { action: debugRunAction } MenuItem { action: debugRunAction }
MenuItem { action: debugResetStateAction }
MenuItem { action: mineAction } MenuItem { action: mineAction }
MenuSeparator {}
MenuItem { action: toggleRunOnLoadAction }
} }
Menu { Menu {
title: qsTr("Windows") title: qsTr("Windows")
MenuItem { action: openNextDocumentAction } MenuItem { action: openNextDocumentAction }
MenuItem { action: openPrevDocumentAction } MenuItem { action: openPrevDocumentAction }
MenuSeparator {} MenuSeparator {}
MenuItem { action: toggleProjectNavigatorAction }
MenuItem { action: showHideRightPanelAction } MenuItem { action: showHideRightPanelAction }
MenuItem { action: toggleWebPreviewAction } MenuItem { action: toggleWebPreviewAction }
MenuItem { action: toggleWebPreviewOrientationAction } MenuItem { action: toggleWebPreviewOrientationAction }
@ -82,7 +84,7 @@ ApplicationWindow {
Action { Action {
id: mineAction id: mineAction
text: "Mine" text: qsTr("Mine")
shortcut: "Ctrl+M" shortcut: "Ctrl+M"
onTriggered: clientModel.mine(); onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running enabled: codeModel.hasContract && !clientModel.running
@ -102,40 +104,51 @@ ApplicationWindow {
Action { Action {
id: debugRunAction id: debugRunAction
text: "&Deploy" text: qsTr("Deploy")
shortcut: "F5" shortcut: "F5"
onTriggered: mainContent.startQuickDebugging() onTriggered: mainContent.startQuickDebugging()
enabled: codeModel.hasContract && !clientModel.running enabled: codeModel.hasContract && !clientModel.running
} }
Action {
id: debugResetStateAction
text: "Reset &State"
shortcut: "F6"
onTriggered: clientModel.resetState();
}
Action { Action {
id: toggleWebPreviewAction id: toggleWebPreviewAction
text: "Show Web View" text: qsTr("Show Web View")
shortcut: "F2" shortcut: "F2"
checkable: true checkable: true
checked: mainContent.webViewVisible checked: mainContent.webViewVisible
onTriggered: mainContent.toggleWebPreview(); onTriggered: mainContent.toggleWebPreview();
} }
Action {
id: toggleProjectNavigatorAction
text: qsTr("Show Project Navigator")
shortcut: "Alt+0"
checkable: true
checked: mainContent.projectViewVisible
onTriggered: mainContent.toggleProjectView();
}
Action { Action {
id: toggleWebPreviewOrientationAction id: toggleWebPreviewOrientationAction
text: "Horizontal Web View" text: qsTr("Horizontal Web View")
shortcut: "" shortcut: ""
checkable: true checkable: true
checked: mainContent.webViewHorizontal checked: mainContent.webViewHorizontal
onTriggered: mainContent.toggleWebPreviewOrientation(); onTriggered: mainContent.toggleWebPreviewOrientation();
} }
Action {
id: toggleRunOnLoadAction
text: qsTr("Load State on Startup")
shortcut: ""
checkable: true
checked: mainContent.runOnProjectLoad
onTriggered: mainContent.runOnProjectLoad = !mainContent.runOnProjectLoad
}
Action { Action {
id: showHideRightPanelAction id: showHideRightPanelAction
text: "Show Right View" text: qsTr("Show Right View")
shortcut: "F7" shortcut: "F7"
checkable: true checkable: true
checked: mainContent.rightViewVisible checked: mainContent.rightViewVisible

13
mix/res.qrc

@ -42,9 +42,19 @@
<file>qml/Ether.qml</file> <file>qml/Ether.qml</file>
<file>qml/EtherValue.qml</file> <file>qml/EtherValue.qml</file>
<file>qml/BigIntValue.qml</file> <file>qml/BigIntValue.qml</file>
<file>qml/QVariableDefinition.qml</file>
<file>qml/QBoolType.qml</file>
<file>qml/QHashType.qml</file>
<file>qml/QIntType.qml</file>
<file>qml/QRealType.qml</file>
<file>qml/js/QEtherHelper.js</file> <file>qml/js/QEtherHelper.js</file>
<file>qml/js/TransactionHelper.js</file> <file>qml/js/TransactionHelper.js</file>
<file>qml/Splitter.qml</file> <file>qml/QStringType.qml</file>
<file>qml/QBoolTypeView.qml</file>
<file>qml/QIntTypeView.qml</file>
<file>qml/QRealTypeView.qml</file>
<file>qml/QStringTypeView.qml</file>
<file>qml/QHashTypeView.qml</file>
<file>qml/ContractLibrary.qml</file> <file>qml/ContractLibrary.qml</file>
<file>stdc/config.sol</file> <file>stdc/config.sol</file>
<file>stdc/namereg.sol</file> <file>stdc/namereg.sol</file>
@ -52,5 +62,6 @@
<file>qml/TransactionLog.qml</file> <file>qml/TransactionLog.qml</file>
<file>res/mix_256x256x32.png</file> <file>res/mix_256x256x32.png</file>
<file>qml/CallStack.qml</file> <file>qml/CallStack.qml</file>
<file>qml/QVariableDeclaration.qml</file>
</qresource> </qresource>
</RCC> </RCC>

7
test/stateOriginal.cpp

@ -51,7 +51,7 @@ int stateTest()
cout << s; cout << s;
// Mine to get some ether! // Mine to get some ether!
s.commitToMine(); s.commitToMine(bc);
while (!s.mine(100).completed) {} while (!s.mine(100).completed) {}
s.completeMine(); s.completeMine();
bc.attemptImport(s.blockData(), stateDB); bc.attemptImport(s.blockData(), stateDB);
@ -74,8 +74,9 @@ int stateTest()
cout << s; cout << s;
// Mine to get some ether and set in stone. // Mine to get some ether and set in stone.
s.commitToMine(); s.commitToMine(bc);
while (!s.mine(100).completed) {} s.commitToMine(bc);
while (!s.mine(50).completed) { s.commitToMine(bc); }
s.completeMine(); s.completeMine();
bc.attemptImport(s.blockData(), stateDB); bc.attemptImport(s.blockData(), stateDB);

Loading…
Cancel
Save