Browse Source

Merge pull request #1327 from arkpar/mix_srci

Mix: Support for solidity arrays and structs
cl-refactor
Gav Wood 10 years ago
parent
commit
f3ee18cfd4
  1. 6
      mix/AppContext.cpp
  2. 97
      mix/ClientModel.cpp
  3. 4
      mix/ClientModel.h
  4. 184
      mix/CodeModel.cpp
  5. 26
      mix/CodeModel.h
  6. 157
      mix/ContractCallDataEncoder.cpp
  7. 20
      mix/ContractCallDataEncoder.h
  8. 14
      mix/DebuggingStateWrapper.h
  9. 6
      mix/QBasicNodeDefinition.h
  10. 11
      mix/QContractDefinition.cpp
  11. 3
      mix/QContractDefinition.h
  12. 10
      mix/QFunctionDefinition.cpp
  13. 5
      mix/QFunctionDefinition.h
  14. 69
      mix/QVariableDeclaration.cpp
  15. 63
      mix/QVariableDeclaration.h
  16. 145
      mix/QVariableDefinition.cpp
  17. 86
      mix/QVariableDefinition.h
  18. 66
      mix/SolidityType.h
  19. 69
      mix/qml/DebugInfoList.qml
  20. 4
      mix/qml/Debugger.qml
  21. 7
      mix/qml/QBoolType.qml
  22. 10
      mix/qml/QBoolTypeView.qml
  23. 7
      mix/qml/QHashType.qml
  24. 6
      mix/qml/QHashTypeView.qml
  25. 7
      mix/qml/QIntType.qml
  26. 7
      mix/qml/QIntTypeView.qml
  27. 7
      mix/qml/QRealType.qml
  28. 7
      mix/qml/QStringType.qml
  29. 6
      mix/qml/QStringTypeView.qml
  30. 2
      mix/qml/StateDialog.qml
  31. 38
      mix/qml/StateListModel.qml
  32. 90
      mix/qml/StructView.qml
  33. 214
      mix/qml/TransactionDialog.qml
  34. 39
      mix/qml/VariablesView.qml
  35. 3
      mix/qml/html/WebContainer.html
  36. 8
      mix/qml/js/Debugger.js
  37. 7
      mix/res.qrc
  38. 26
      mix/stdc/std.sol

6
mix/AppContext.cpp

@ -68,14 +68,10 @@ 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"); qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration");
qmlRegisterType<RecordLogEntry>("org.ethereum.qml.RecordLogEntry", 1, 0, "RecordLogEntry"); qmlRegisterType<RecordLogEntry>("org.ethereum.qml.RecordLogEntry", 1, 0, "RecordLogEntry");
qmlRegisterType<SortFilterProxyModel>("org.ethereum.qml.SortFilterProxyModel", 1, 0, "SortFilterProxyModel"); qmlRegisterType<SortFilterProxyModel>("org.ethereum.qml.SortFilterProxyModel", 1, 0, "SortFilterProxyModel");
qmlRegisterType<QSolidityType>("org.ethereum.qml.QSolidityType", 1, 0, "QSolidityType");
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())

97
mix/ClientModel.cpp

@ -71,16 +71,11 @@ ClientModel::ClientModel(AppContext* _context):
m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()) m_context(_context), m_running(false), m_rpcConnector(new RpcConnector())
{ {
qRegisterMetaType<QBigInt*>("QBigInt*"); qRegisterMetaType<QBigInt*>("QBigInt*");
qRegisterMetaType<QIntType*>("QIntType*");
qRegisterMetaType<QStringType*>("QStringType*");
qRegisterMetaType<QRealType*>("QRealType*");
qRegisterMetaType<QHashType*>("QHashType*");
qRegisterMetaType<QEther*>("QEther*");
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*"); qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*");
qRegisterMetaType<QList<QVariableDefinition*>>("QList<QVariableDefinition*>"); qRegisterMetaType<QList<QVariableDefinition*>>("QList<QVariableDefinition*>");
qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>"); qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*"); qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
qRegisterMetaType<QSolidityType*>("QSolidityType*");
qRegisterMetaType<QMachineState*>("QMachineState"); qRegisterMetaType<QMachineState*>("QMachineState");
qRegisterMetaType<QInstruction*>("QInstruction"); qRegisterMetaType<QInstruction*>("QInstruction");
qRegisterMetaType<QCode*>("QCode"); qRegisterMetaType<QCode*>("QCode");
@ -191,14 +186,8 @@ void ClientModel::setupState(QVariantMap _state)
{ {
if (contractId.isEmpty() && m_context->codeModel()->hasContract()) //TODO: This is to support old project files, remove later if (contractId.isEmpty() && m_context->codeModel()->hasContract()) //TODO: This is to support old project files, remove later
contractId = m_context->codeModel()->contracts().keys()[0]; contractId = m_context->codeModel()->contracts().keys()[0];
QVariantList qParams = transaction.value("qType").toList();
TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice, Secret(sender.toStdString())); TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice, Secret(sender.toStdString()));
transactionSettings.parameterValues = transaction.value("parameters").toMap();
for (QVariant const& variant: qParams)
{
QVariableDefinition* param = qvariant_cast<QVariableDefinition*>(variant);
transactionSettings.parameterValues.push_back(param);
}
if (contractId == functionId || functionId == "Constructor") if (contractId == functionId || functionId == "Constructor")
transactionSettings.functionId.clear(); transactionSettings.functionId.clear();
@ -256,11 +245,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()));
if (!transaction.functionId.isEmpty()) if (!transaction.functionId.isEmpty())
encoder.encode(f); encoder.encode(f);
for (int p = 0; p < transaction.parameterValues.size(); p++) for (QVariableDeclaration const* p: f->parametersList())
{ {
if (f->parametersList().size() <= p || f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type()) QSolidityType const* type = p->type();
BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(transaction.functionId.toStdString())); QVariant value = transaction.parameterValues.value(p->name());
encoder.push(transaction.parameterValues.at(p)->encodeValue()); encoder.encode(value, type->type());
} }
if (transaction.functionId.isEmpty() || transaction.functionId == transaction.contractId) if (transaction.functionId.isEmpty() || transaction.functionId == transaction.contractId)
@ -347,9 +336,9 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
data.push_back(QMachineState::getDebugCallData(debugData, d)); data.push_back(QMachineState::getDebugCallData(debugData, d));
QVariantList states; QVariantList states;
QStringList solCallStack; QVariantList solCallStack;
std::map<int, SolidityDeclaration> solLocals; //<stack pos, declaration> std::map<int, QVariableDeclaration*> solLocals; //<stack pos, decl>
QList<int> returnStack; std::map<QString, QVariableDeclaration*> storageDeclarations; //<name, decl>
unsigned prevInstructionIndex = 0; unsigned prevInstructionIndex = 0;
for (MachineState const& s: _t.machineStates) for (MachineState const& s: _t.machineStates)
@ -366,44 +355,60 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
//register new local variable initialization //register new local variable initialization
auto localIter = contract->locals().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end)); auto localIter = contract->locals().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (localIter != contract->locals().end()) if (localIter != contract->locals().end())
solLocals[s.stack.size()] = localIter.value(); solLocals[s.stack.size()] = new QVariableDeclaration(debugData, localIter.value().name.toStdString(), localIter.value().type);
} }
if (instruction.type() == dev::eth::Tag) //TODO: use annotations if (instruction.type() == dev::eth::Tag)
{ {
//track calls into functions //track calls into functions
AssemblyItem const& prevInstruction = codeItems[s.codeIndex][prevInstructionIndex];
auto functionIter = contract->functions().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end)); auto functionIter = contract->functions().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (functionIter != contract->functions().end()) if (functionIter != contract->functions().end() && ((prevInstruction.getJumpType() == AssemblyItem::JumpType::IntoFunction) || solCallStack.empty()))
{ solCallStack.push_back(QVariant::fromValue(functionIter.value()));
QString functionName = functionIter.value(); else if (prevInstruction.getJumpType() == AssemblyItem::JumpType::OutOfFunction && !solCallStack.empty())
solCallStack.push_back(functionName);
returnStack.push_back(prevInstructionIndex + 1);
}
else if (!returnStack.empty() && instructionIndex == returnStack.back())
{
returnStack.pop_back();
solCallStack.pop_back(); solCallStack.pop_back();
}
} }
//format solidity context values //format solidity context values
QStringList locals; QVariantMap locals;
QVariantList localDeclarations;
QVariantMap localValues;
for(auto l: solLocals) for(auto l: solLocals)
if (l.first < (int)s.stack.size()) if (l.first < (int)s.stack.size())
locals.push_back(l.second.name + "\t" + formatValue(l.second.type, s.stack[l.first])); {
localDeclarations.push_back(QVariant::fromValue(l.second));
localValues[l.second->name()] = formatValue(l.second->type()->type(), s.stack[l.first]);
}
locals["variables"] = localDeclarations;
locals["values"] = localValues;
QStringList storage; QVariantMap storage;
QVariantList storageDeclarationList;
QVariantMap storageValues;
for(auto st: s.storage) for(auto st: s.storage)
{
if (st.first < std::numeric_limits<unsigned>::max()) if (st.first < std::numeric_limits<unsigned>::max())
{ {
auto storageIter = contract->storage().find(static_cast<unsigned>(st.first)); auto storageIter = contract->storage().find(static_cast<unsigned>(st.first));
if (storageIter != contract->storage().end()) if (storageIter != contract->storage().end())
storage.push_back(storageIter.value().name + "\t" + formatValue(storageIter.value().type, st.second)); {
QVariableDeclaration* storageDec = nullptr;
auto decIter = storageDeclarations.find(storageIter.value().name);
if (decIter != storageDeclarations.end())
storageDec = decIter->second;
else
{
storageDec = new QVariableDeclaration(debugData, storageIter.value().name.toStdString(), storageIter.value().type);
storageDeclarations[storageDec->name()] = storageDec;
}
storageDeclarationList.push_back(QVariant::fromValue(storageDec));
storageValues[storageDec->name()] = formatValue(storageDec->type()->type(), st.second);
}
} }
} storage["variables"] = storageDeclarationList;
storage["values"] = storageValues;
prevInstructionIndex = instructionIndex; prevInstructionIndex = instructionIndex;
solState = new QSolState(debugData, storage, solCallStack, locals, instruction.getLocation().start, instruction.getLocation().end); solState = new QSolState(debugData, std::move(storage), std::move(solCallStack), std::move(locals), instruction.getLocation().start, instruction.getLocation().end);
} }
states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState))); states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState)));
@ -413,9 +418,12 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
debugDataReady(debugData); debugDataReady(debugData);
} }
QString ClientModel::formatValue(SolidityType const&, dev::u256 const& _value) QVariant ClientModel::formatValue(SolidityType const& _type, dev::u256 const& _value)
{ {
return QString::fromStdString(prettyU256(_value)); ContractCallDataEncoder decoder;
bytes val = toBigEndian(_value);
QVariant res = decoder.decode(_type, val);
return res;
} }
void ClientModel::emptyRecord() void ClientModel::emptyRecord()
@ -526,9 +534,10 @@ void ClientModel::onNewTransaction()
{ {
function = funcDef->name(); function = funcDef->name();
ContractCallDataEncoder encoder; ContractCallDataEncoder encoder;
QList<QVariableDefinition*> returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue); QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue);
for (auto const& var: returnValues) returned += "(";
returned += var->value() + " | "; returned += returnValues.join(", ");
returned += ")";
} }
} }
} }

4
mix/ClientModel.h

@ -63,7 +63,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
QList<QVariableDefinition*> parameterValues; QVariantMap parameterValues;
/// Standard contract url /// Standard contract url
QString stdContractUrl; QString stdContractUrl;
/// Sender /// Sender
@ -199,7 +199,7 @@ private:
void onNewTransaction(); void onNewTransaction();
void onStateReset(); void onStateReset();
void showDebuggerForTransaction(ExecutionResult const& _t); void showDebuggerForTransaction(ExecutionResult const& _t);
QString formatValue(SolidityType const& _type, dev::u256 const& _value); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value);
AppContext* m_context; AppContext* m_context;
std::atomic<bool> m_running; std::atomic<bool> m_running;

184
mix/CodeModel.cpp

@ -28,6 +28,7 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libevmcore/SourceLocation.h> #include <libevmcore/SourceLocation.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/Types.h>
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
@ -49,86 +50,49 @@ const std::set<std::string> c_predefinedContracts =
namespace namespace
{ {
using namespace dev::solidity; using namespace dev::solidity;
class CollectDeclarationsVisitor: public ASTConstVisitor class CollectDeclarationsVisitor: public ASTConstVisitor
{
public:
CollectDeclarationsVisitor(QHash<LocationPair, QString>* _functions, QHash<LocationPair, SolidityDeclaration>* _locals, QHash<unsigned, SolidityDeclaration>* _storage):
m_functions(_functions), m_locals(_locals), m_storage(_storage), m_functionScope(false), m_storageSlot(0) {}
private:
LocationPair nodeLocation(ASTNode const& _node)
{ {
public: return LocationPair(_node.getLocation().start, _node.getLocation().end);
CollectDeclarationsVisitor(QHash<LocationPair, QString>* _functions, QHash<LocationPair, SolidityDeclaration>* _locals, QHash<unsigned, SolidityDeclaration>* _storage): }
m_functions(_functions), m_locals(_locals), m_storage(_storage), m_functionScope(false), m_storageSlot(0) {}
private:
QHash<LocationPair, QString>* m_functions;
QHash<LocationPair, SolidityDeclaration>* m_locals;
QHash<unsigned, SolidityDeclaration>* m_storage;
bool m_functionScope;
uint m_storageSlot;
LocationPair nodeLocation(ASTNode const& _node)
{
return LocationPair(_node.getLocation().start, _node.getLocation().end);
}
SolidityType nodeType(Type const* _type) virtual bool visit(FunctionDefinition const& _node)
{ {
if (!_type) m_functions->insert(nodeLocation(_node), QString::fromStdString(_node.getName()));
return SolidityType { SolidityType::Type::UnsignedInteger, 32 }; m_functionScope = true;
switch (_type->getCategory()) return true;
{ }
case Type::Category::Integer:
{
IntegerType const* it = dynamic_cast<IntegerType const*>(_type);
unsigned size = it->getNumBits() / 8;
SolidityType::Type typeCode = it->isAddress() ? SolidityType::Type::Address : it->isSigned() ? SolidityType::Type::SignedInteger : SolidityType::Type::UnsignedInteger;
return SolidityType { typeCode, size };
}
case Type::Category::Bool:
return SolidityType { SolidityType::Type::Bool, _type->getSizeOnStack() * 32 };
case Type::Category::FixedBytes:
{
FixedBytesType const* s = dynamic_cast<FixedBytesType const*>(_type);
return SolidityType { SolidityType::Type::FixedBytes, static_cast<unsigned>(s->getNumBytes()) };
}
case Type::Category::Contract:
return SolidityType { SolidityType::Type::Address, _type->getSizeOnStack() * 32 };
case Type::Category::Array:
case Type::Category::Enum:
case Type::Category::Function:
case Type::Category::IntegerConstant:
case Type::Category::Magic:
case Type::Category::Mapping:
case Type::Category::Modifier:
case Type::Category::Real:
case Type::Category::Struct:
case Type::Category::TypeType:
case Type::Category::Void:
default:
return SolidityType { SolidityType::Type::UnsignedInteger, 32 };
}
}
virtual bool visit(FunctionDefinition const& _node) virtual void endVisit(FunctionDefinition const&)
{ {
m_functions->insert(nodeLocation(_node), QString::fromStdString(_node.getName())); m_functionScope = false;
m_functionScope = true; }
return true;
}
virtual void endVisit(FunctionDefinition const&) virtual bool visit(VariableDeclaration const& _node)
{ {
m_functionScope = false; SolidityDeclaration decl;
} decl.type = CodeModel::nodeType(_node.getType().get());
decl.name = QString::fromStdString(_node.getName());
if (m_functionScope)
m_locals->insert(nodeLocation(_node), decl);
else
m_storage->insert(m_storageSlot++, decl);
return true;
}
virtual bool visit(VariableDeclaration const& _node) private:
{ QHash<LocationPair, QString>* m_functions;
SolidityDeclaration decl; QHash<LocationPair, SolidityDeclaration>* m_locals;
decl.type = nodeType(_node.getType().get()); QHash<unsigned, SolidityDeclaration>* m_storage;
decl.name = QString::fromStdString(_node.getName()); bool m_functionScope;
if (m_functionScope) uint m_storageSlot;
m_locals->insert(nodeLocation(_node), decl); };
else
m_storage->insert(m_storageSlot++, decl);
return true;
}
};
} }
void BackgroundWorker::queueCodeChange(int _jobId) void BackgroundWorker::queueCodeChange(int _jobId)
@ -142,8 +106,9 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
{ {
std::string name = _contractName.toStdString(); std::string name = _contractName.toStdString();
auto const& contractDefinition = _compiler.getContractDefinition(name); auto const& contractDefinition = _compiler.getContractDefinition(name);
m_contract.reset(new QContractDefinition(&contractDefinition)); m_contract.reset(new QContractDefinition(nullptr, &contractDefinition));
QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership);
m_contract->moveToThread(QApplication::instance()->thread());
m_bytes = _compiler.getBytecode(_contractName.toStdString()); m_bytes = _compiler.getBytecode(_contractName.toStdString());
m_assemblyItems = _compiler.getRuntimeAssemblyItems(name); m_assemblyItems = _compiler.getRuntimeAssemblyItems(name);
m_constructorAssemblyItems = _compiler.getAssemblyItems(name); m_constructorAssemblyItems = _compiler.getAssemblyItems(name);
@ -344,3 +309,70 @@ dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, co
return m_compiledContracts.at(_contractName); return m_compiledContracts.at(_contractName);
} }
SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
{
SolidityType r { SolidityType::Type::UnsignedInteger, 32, false, false, QString::fromStdString(_type->toString()), std::vector<SolidityDeclaration>(), std::vector<QString>() };
if (!_type)
return r;
r.dynamicSize = _type->isDynamicallySized();
switch (_type->getCategory())
{
case Type::Category::Integer:
{
IntegerType const* it = dynamic_cast<IntegerType const*>(_type);
r.size = it->getNumBits() / 8;
r.type = it->isAddress() ? SolidityType::Type::Address : it->isSigned() ? SolidityType::Type::SignedInteger : SolidityType::Type::UnsignedInteger;
}
break;
case Type::Category::Bool:
r.type = SolidityType::Type::Bool;
break;
case Type::Category::FixedBytes:
{
FixedBytesType const* b = dynamic_cast<FixedBytesType const*>(_type);
r.type = SolidityType::Type::Bytes;
r.size = static_cast<unsigned>(b->getNumBytes());
}
case Type::Category::Contract:
r.type = SolidityType::Type::Address;
break;
case Type::Category::Array:
{
ArrayType const* array = dynamic_cast<ArrayType const*>(_type);
if (array->isByteArray())
r.type = SolidityType::Type::Bytes;
else
r = nodeType(array->getBaseType().get());
r.array = true;
}
break;
case Type::Category::Enum:
{
r.type = SolidityType::Type::Enum;
EnumType const* e = dynamic_cast<EnumType const*>(_type);
for(auto const& enumValue: e->getEnumDefinition().getMembers())
r.enumNames.push_back(QString::fromStdString(enumValue->getName()));
}
break;
case Type::Category::Struct:
{
r.type = SolidityType::Type::Struct;
StructType const* s = dynamic_cast<StructType const*>(_type);
for(auto const& structMember: s->getMembers())
r.members.push_back(SolidityDeclaration { QString::fromStdString(structMember.first), nodeType(structMember.second.get()) });
}
break;
case Type::Category::Function:
case Type::Category::IntegerConstant:
case Type::Category::Magic:
case Type::Category::Mapping:
case Type::Category::Modifier:
case Type::Category::Real:
case Type::Category::TypeType:
case Type::Category::Void:
default:
break;
}
return r;
}

26
mix/CodeModel.h

@ -31,6 +31,7 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libevmcore/Assembly.h> #include <libevmcore/Assembly.h>
#include "SolidityType.h"
class QTextDocument; class QTextDocument;
@ -39,7 +40,8 @@ namespace dev
namespace solidity namespace solidity
{ {
class CompilerStack; class CompilerStack;
class Type;
} }
namespace mix namespace mix
@ -66,26 +68,6 @@ private:
using LocationPair = QPair<int, int>; using LocationPair = QPair<int, int>;
struct SolidityType
{
enum class Type //TODO: arrays and structs
{
SignedInteger,
UnsignedInteger,
Bool,
Address,
FixedBytes,
};
Type type;
unsigned size; //bytes
};
struct SolidityDeclaration
{
QString name;
SolidityType type;
};
///Compilation result model. Contains all the compiled contract data required by UI ///Compilation result model. Contains all the compiled contract data required by UI
class CompiledContract: public QObject class CompiledContract: public QObject
{ {
@ -165,6 +147,8 @@ public:
Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const; Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const;
/// Reset code model /// Reset code model
Q_INVOKABLE void reset() { reset(QVariantMap()); } Q_INVOKABLE void reset() { reset(QVariantMap()); }
/// Convert solidity type info to mix type
static SolidityType nodeType(dev::solidity::Type const* _type);
signals: signals:
/// Emited on compilation state change /// Emited on compilation state change

157
mix/ContractCallDataEncoder.cpp

@ -35,7 +35,9 @@ using namespace dev::mix;
bytes ContractCallDataEncoder::encodedData() bytes ContractCallDataEncoder::encodedData()
{ {
return m_encodedData; bytes r(m_encodedData);
r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end());
return r;
} }
void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) void ContractCallDataEncoder::encode(QFunctionDefinition const* _function)
@ -44,38 +46,149 @@ 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(QVariant const& _data, SolidityType const& _type)
{
if (_type.dynamicSize)
{
u256 count = 0;
if (_type.type == SolidityType::Type::Bytes)
count = encodeSingleItem(_data, _type, m_dynamicData);
else
{
QVariantList list = qvariant_cast<QVariantList>(_data);
for (auto const& item: list)
encodeSingleItem(item, _type, m_dynamicData);
count = list.size();
}
bytes sizeEnc(32);
toBigEndian(count, sizeEnc);
m_encodedData.insert(m_encodedData.end(), sizeEnc.begin(), sizeEnc.end());
}
else
encodeSingleItem(_data, _type, m_encodedData);
}
unsigned ContractCallDataEncoder::encodeSingleItem(QVariant const& _data, SolidityType const& _type, bytes& _dest)
{
if (_type.type == SolidityType::Type::Struct)
BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Struct parameters are not supported yet"));
unsigned const alignSize = 32;
QString src = _data.toString();
bytes result;
if (src.length() >= 2 && ((src.startsWith("\"") && src.endsWith("\"")) || (src.startsWith("\'") && src.endsWith("\'"))))
{
src = src.remove(src.length() - 1, 1).remove(0, 1);
QByteArray bytesAr = src.toLocal8Bit();
result = bytes(bytesAr.begin(), bytesAr.end());
}
else if (src.startsWith("0x"))
{
result = fromHex(src.toStdString().substr(2));
if (_type.type != SolidityType::Type::Bytes)
result = padded(result, alignSize);
}
else
{
bigint i(src.toStdString());
result = bytes(alignSize);
toBigEndian((u256)i, result);
}
unsigned dataSize = _type.dynamicSize ? result.size() : alignSize;
_dest.insert(_dest.end(), result.begin(), result.end());
if (_dest.size() % alignSize != 0)
_dest.resize((_dest.size() & ~(alignSize - 1)) + alignSize);
return dataSize;
}
void ContractCallDataEncoder::push(bytes const& _b) void ContractCallDataEncoder::push(bytes const& _b)
{ {
m_encodedData.insert(m_encodedData.end(), _b.begin(), _b.end()); m_encodedData.insert(m_encodedData.end(), _b.begin(), _b.end());
} }
QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const& _returnParameters, bytes _value) bigint ContractCallDataEncoder::decodeInt(dev::bytes const& _rawValue)
{
dev::u256 un = dev::fromBigEndian<dev::u256>(_rawValue);
if (un >> 255)
return (-s256(~un + 1));
return un;
}
QString ContractCallDataEncoder::toString(dev::bigint const& _int)
{
std::stringstream str;
str << std::dec << _int;
return QString::fromStdString(str.str());
}
dev::bytes ContractCallDataEncoder::encodeBool(QString const& _str)
{
bytes b(1);
b[0] = _str == "1" || _str.toLower() == "true " ? 1 : 0;
return padded(b, 32);
}
bool ContractCallDataEncoder::decodeBool(dev::bytes const& _rawValue)
{
byte ret = _rawValue.at(_rawValue.size() - 1);
return (ret != 0);
}
QString ContractCallDataEncoder::toString(bool _b)
{
return _b ? "true" : "false";
}
dev::bytes ContractCallDataEncoder::encodeBytes(QString const& _str)
{
QByteArray bytesAr = _str.toLocal8Bit();
bytes r = bytes(bytesAr.begin(), bytesAr.end());
return padded(r, 32);
}
dev::bytes ContractCallDataEncoder::decodeBytes(dev::bytes const& _rawValue)
{
return _rawValue;
}
QString ContractCallDataEncoder::toString(dev::bytes const& _b)
{
return QString::fromStdString(dev::toJS(_b));
}
QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& _value)
{ {
bytesConstRef value(&_value); bytesConstRef value(&_value);
bytes rawParam(32); bytes rawParam(32);
QList<QVariableDefinition*> r; value.populate(&rawParam);
QSolidityType::Type type = _type.type;
if (type == QSolidityType::Type::SignedInteger || type == QSolidityType::Type::UnsignedInteger || type == QSolidityType::Type::Address)
return QVariant::fromValue(toString(decodeInt(rawParam)));
else if (type == QSolidityType::Type::Bool)
return QVariant::fromValue(toString(decodeBool(rawParam)));
else if (type == QSolidityType::Type::Bytes || type == QSolidityType::Type::Hash)
return QVariant::fromValue(toString(decodeBytes(rawParam)));
else if (type == QSolidityType::Type::Struct)
return QVariant::fromValue(QString("struct")); //TODO
else
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found"));
}
QStringList ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const& _returnParameters, bytes _value)
{
bytesConstRef value(&_value);
bytes rawParam(32);
QStringList r;
for (int k = 0; k <_returnParameters.length(); k++) for (int k = 0; k <_returnParameters.length(); k++)
{ {
QVariableDeclaration* dec = static_cast<QVariableDeclaration*>(_returnParameters.at(k));
QVariableDefinition* def = nullptr;
if (dec->type().contains("int"))
def = new QIntType(dec, QString());
else if (dec->type().contains("real"))
def = new QRealType(dec, QString());
else if (dec->type().contains("bool"))
def = new QBoolType(dec, QString());
else if (dec->type().contains("string") || dec->type().contains("text"))
def = new QStringType(dec, QString());
else if (dec->type().contains("hash") || dec->type().contains("address"))
def = new QHashType(dec, QString());
else
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found"));
value.populate(&rawParam); value.populate(&rawParam);
def->decodeValue(rawParam); value = value.cropped(32);
r.push_back(def); QVariableDeclaration* dec = static_cast<QVariableDeclaration*>(_returnParameters.at(k));
value = value.cropped(32); SolidityType const& type = dec->type()->type();
qDebug() << "decoded return value : " << dec->type() << " " << def->value(); r.append(decode(type, rawParam).toString());
} }
return r; return r;
} }

20
mix/ContractCallDataEncoder.h

@ -33,6 +33,7 @@ namespace mix
class QFunctionDefinition; class QFunctionDefinition;
class QVariableDeclaration; class QVariableDeclaration;
class QVariableDefinition; class QVariableDefinition;
class QSolidityType;
/** /**
* @brief Encode/Decode data to be sent to a transaction or to be displayed in a view. * @brief Encode/Decode data to be sent to a transaction or to be displayed in a view.
@ -43,15 +44,32 @@ public:
ContractCallDataEncoder() {} ContractCallDataEncoder() {}
/// Encode hash of the function to call. /// Encode hash of the function to call.
void encode(QFunctionDefinition const* _function); void encode(QFunctionDefinition const* _function);
/// Encode data for corresponding type
void encode(QVariant const& _data, SolidityType const& _type);
/// 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*> const& _dec, bytes _value); QStringList decode(QList<QVariableDeclaration*> const& _dec, bytes _value);
/// Decode single variable
QVariant decode(SolidityType const& _type, bytes const& _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. /// Push the given @a _b to the current param context.
void push(bytes const& _b); void push(bytes const& _b);
private:
unsigned encodeSingleItem(QVariant const& _data, SolidityType const& _type, bytes& _dest);
bigint decodeInt(dev::bytes const& _rawValue);
dev::bytes encodeInt(QString const& _str);
QString toString(dev::bigint const& _int);
dev::bytes encodeBool(QString const& _str);
bool decodeBool(dev::bytes const& _rawValue);
QString toString(bool _b);
dev::bytes encodeBytes(QString const& _str);
dev::bytes decodeBytes(dev::bytes const& _rawValue);
QString toString(dev::bytes const& _b);
private: private:
bytes m_encodedData; bytes m_encodedData;
bytes m_dynamicData;
}; };
} }

14
mix/DebuggingStateWrapper.h

@ -60,21 +60,21 @@ private:
class QSolState: public QObject class QSolState: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QStringList storage MEMBER m_storage CONSTANT) Q_PROPERTY(QVariantMap storage MEMBER m_storage CONSTANT)
Q_PROPERTY(QStringList callStack MEMBER m_callStack CONSTANT) Q_PROPERTY(QVariantList callStack MEMBER m_callStack CONSTANT)
Q_PROPERTY(QStringList locals MEMBER m_locals CONSTANT) Q_PROPERTY(QVariantMap locals MEMBER m_locals CONSTANT)
Q_PROPERTY(int start MEMBER m_start CONSTANT) Q_PROPERTY(int start MEMBER m_start CONSTANT)
Q_PROPERTY(int end MEMBER m_end CONSTANT) Q_PROPERTY(int end MEMBER m_end CONSTANT)
public: public:
QSolState(QObject* _parent, QStringList const& _storage, QStringList const& _callStack, QStringList const& _locals, int _start, int _end): QSolState(QObject* _parent, QVariantMap&& _storage, QVariantList&& _callStack, QVariantMap&& _locals, int _start, int _end):
QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end) QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end)
{ } { }
private: private:
QStringList m_storage; QVariantMap m_storage;
QStringList m_callStack; QVariantList m_callStack;
QStringList m_locals; QVariantMap m_locals;
int m_start; int m_start;
int m_end; int m_end;
}; };

6
mix/QBasicNodeDefinition.h

@ -35,10 +35,10 @@ class QBasicNodeDefinition: public QObject
Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString name READ name CONSTANT)
public: public:
QBasicNodeDefinition(): QObject() {} QBasicNodeDefinition(QObject* _parent = nullptr): QObject(_parent) {}
~QBasicNodeDefinition() {} ~QBasicNodeDefinition() {}
QBasicNodeDefinition(solidity::Declaration const* _d): QObject(), m_name(QString::fromStdString(_d->getName())) {} QBasicNodeDefinition(QObject* _parent, solidity::Declaration const* _d): QObject(_parent), m_name(QString::fromStdString(_d->getName())) {}
QBasicNodeDefinition(std::string const& _name): QObject(), m_name(QString::fromStdString(_name)) {} QBasicNodeDefinition(QObject* _parent, std::string const& _name): QObject(_parent), m_name(QString::fromStdString(_name)) {}
/// Get the name of the node. /// Get the name of the node.
QString name() const { return m_name; } QString name() const { return m_name; }

11
mix/QContractDefinition.cpp

@ -32,16 +32,17 @@
using namespace dev::solidity; using namespace dev::solidity;
using namespace dev::mix; using namespace dev::mix;
QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_contract) QContractDefinition::QContractDefinition(QObject* _parent, dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_parent, _contract)
{ {
QObject* parent = _parent ? _parent : this;
if (_contract->getConstructor() != nullptr) if (_contract->getConstructor() != nullptr)
m_constructor = new QFunctionDefinition(ContractType(*_contract).getConstructorType()); m_constructor = new QFunctionDefinition(parent, ContractType(*_contract).getConstructorType());
else else
m_constructor = new QFunctionDefinition(); m_constructor = new QFunctionDefinition(parent);
for (auto const& it: _contract->getInterfaceFunctions()) for (auto const& it: _contract->getInterfaceFunctions())
m_functions.append(new QFunctionDefinition(it.second));} m_functions.append(new QFunctionDefinition(parent, it.second));
}
QFunctionDefinition const* QContractDefinition::getFunction(dev::FixedHash<4> _hash) const QFunctionDefinition const* QContractDefinition::getFunction(dev::FixedHash<4> _hash) const
{ {

3
mix/QContractDefinition.h

@ -39,8 +39,7 @@ class QContractDefinition: public QBasicNodeDefinition
Q_PROPERTY(dev::mix::QFunctionDefinition* constructor READ constructor CONSTANT) Q_PROPERTY(dev::mix::QFunctionDefinition* constructor READ constructor CONSTANT)
public: public:
QContractDefinition() {} QContractDefinition(QObject* _parent, solidity::ContractDefinition const* _contract);
QContractDefinition(solidity::ContractDefinition const* _contract);
/// Get all the functions of the contract. /// Get all the functions of the contract.
QQmlListProperty<QFunctionDefinition> functions() const { return QQmlListProperty<QFunctionDefinition>(const_cast<QContractDefinition*>(this), const_cast<QContractDefinition*>(this)->m_functions); } QQmlListProperty<QFunctionDefinition> functions() const { return QQmlListProperty<QFunctionDefinition>(const_cast<QContractDefinition*>(this), const_cast<QContractDefinition*>(this)->m_functions); }
/// Get the constructor of the contract. /// Get the constructor of the contract.

10
mix/QFunctionDefinition.cpp

@ -28,15 +28,15 @@
using namespace dev::solidity; using namespace dev::solidity;
using namespace dev::mix; using namespace dev::mix;
QFunctionDefinition::QFunctionDefinition(dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(&_f->getDeclaration()), m_hash(dev::sha3(_f->getCanonicalSignature())) QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(_parent, &_f->getDeclaration()), m_hash(dev::sha3(_f->getCanonicalSignature()))
{ {
auto paramNames = _f->getParameterNames(); auto paramNames = _f->getParameterNames();
auto paramTypes = _f->getParameterTypeNames(); auto paramTypes = _f->getParameterTypes();
auto returnNames = _f->getReturnParameterNames(); auto returnNames = _f->getReturnParameterNames();
auto returnTypes = _f->getReturnParameterTypeNames(); auto returnTypes = _f->getReturnParameterTypes();
for (unsigned i = 0; i < paramNames.size(); ++i) for (unsigned i = 0; i < paramNames.size(); ++i)
m_parameters.append(new QVariableDeclaration(paramNames[i], paramTypes[i])); m_parameters.append(new QVariableDeclaration(_parent, paramNames[i], paramTypes[i].get()));
for (unsigned i = 0; i < returnNames.size(); ++i) for (unsigned i = 0; i < returnNames.size(); ++i)
m_returnParameters.append(new QVariableDeclaration(returnNames[i], returnTypes[i])); m_returnParameters.append(new QVariableDeclaration(_parent, returnNames[i], returnTypes[i].get()));
} }

5
mix/QFunctionDefinition.h

@ -38,8 +38,9 @@ class QFunctionDefinition: public QBasicNodeDefinition
Q_PROPERTY(QQmlListProperty<dev::mix::QVariableDeclaration> parameters READ parameters) Q_PROPERTY(QQmlListProperty<dev::mix::QVariableDeclaration> parameters READ parameters)
public: public:
QFunctionDefinition() {} QFunctionDefinition(){}
QFunctionDefinition(solidity::FunctionTypePointer const& _f); QFunctionDefinition(QObject* _parent): QBasicNodeDefinition(_parent) {}
QFunctionDefinition(QObject* _parent, solidity::FunctionTypePointer const& _f);
/// Get all input parameters of this function. /// Get all input parameters of this function.
QList<QVariableDeclaration*> const& parametersList() const { return m_parameters; } QList<QVariableDeclaration*> const& parametersList() const { return m_parameters; }
/// Get all input parameters of this function as QML property. /// Get all input parameters of this function as QML property.

69
mix/QVariableDeclaration.cpp

@ -0,0 +1,69 @@
/*
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.app
* @author Yann yann@ethdev.com
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2015
*/
#include "QVariableDeclaration.h"
#include "CodeModel.h"
namespace dev
{
namespace mix
{
QVariableDeclaration::QVariableDeclaration(QObject* _parent, solidity::VariableDeclaration const* _v):
QBasicNodeDefinition(_parent, _v),
m_type(new QSolidityType(this, CodeModel::nodeType(_v->getType().get())))
{
}
QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type):
QBasicNodeDefinition(_parent, _name),
m_type(new QSolidityType(_parent, _type))
{
}
QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type):
QBasicNodeDefinition(_parent, _name),
m_type(new QSolidityType(this, CodeModel::nodeType(_type)))
{
}
QSolidityType::QSolidityType(QObject* _parent, SolidityType const& _type):
QObject(_parent),
m_type(_type)
{
}
QVariantList QSolidityType::members() const
{
QVariantList members;
if (m_type.type == Type::Struct)
for (auto const& structMember: m_type.members)
members.push_back(QVariant::fromValue(new QVariableDeclaration(parent(), structMember.name.toStdString(), structMember.type)));
if (m_type.type == Type::Enum)
for (auto const& enumName: m_type.enumNames)
members.push_back(QVariant::fromValue(enumName));
return members;
}
}
}

63
mix/QVariableDeclaration.h

@ -20,34 +20,77 @@
*/ */
#include <QDebug> #include <QDebug>
#include <QStringList> #include <QVariantList>
#include <libsolidity/AST.h>
#include "QBasicNodeDefinition.h" #include "QBasicNodeDefinition.h"
#include "SolidityType.h"
#pragma once #pragma once
namespace solidity
{
class Type;
class VariableDeclaration;
}
namespace dev namespace dev
{ {
namespace mix namespace mix
{ {
/// UI wrapper around solidity type
class QSolidityType: public QObject
{
Q_OBJECT
Q_PROPERTY(int category READ category CONSTANT) //qml does not support enum properties
Q_PROPERTY(int size READ size CONSTANT)
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QVariantList members READ members CONSTANT)
public:
QSolidityType() {}
QSolidityType(QObject* _parent, SolidityType const& _type);
using Type = SolidityType::Type;
enum QmlType //TODO: Q_ENUMS does not support enum forwarding. Keep in sync with SolidityType::Type
{
SignedInteger,
UnsignedInteger,
Hash,
Bool,
Address,
Bytes,
Enum,
Struct
};
Q_ENUMS(QmlType)
SolidityType const& type() const { return m_type; }
Type category() const { return m_type.type; }
int size() const { return m_type.size; }
QString name() const { return m_type.name; }
QVariantList members() const;
private:
SolidityType m_type;
};
/// UI wrapper around declaration (name + type)
class QVariableDeclaration: public QBasicNodeDefinition class QVariableDeclaration: public QBasicNodeDefinition
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString type READ type WRITE setType) Q_PROPERTY(QSolidityType* type READ type CONSTANT)
public: public:
QVariableDeclaration() {} QVariableDeclaration() {}
QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {} QVariableDeclaration(QObject* _parent, solidity::VariableDeclaration const* _v);
QVariableDeclaration(std::string const& _name, std::string const& _type): QBasicNodeDefinition(_name), m_type(QString::fromStdString(_type)) {} QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type);
QString type() const { return m_type; } QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type);
void setType(QString _type) { m_type = _type; } QSolidityType* type() const { return m_type; }
void setType(QSolidityType* _type) { m_type = _type; }
private: private:
QString m_type; QSolidityType* m_type;
}; };
} }
} }
Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*)

145
mix/QVariableDefinition.cpp

@ -1,145 +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 QVariableDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#include <libdevcore/CommonData.h>
#include <libethcore/CommonJS.h>
#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);
}
/*
* 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";
}

86
mix/QVariableDefinition.h

@ -63,95 +63,9 @@ private:
QVariableDeclaration* m_dec; 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;
};
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(): m_boolValue(false) {}
QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value), m_boolValue(false) {}
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::QIntType*)
Q_DECLARE_METATYPE(dev::mix::QStringType*)
Q_DECLARE_METATYPE(dev::mix::QHashType*)
Q_DECLARE_METATYPE(dev::mix::QBoolType*)

66
mix/SolidityType.h

@ -0,0 +1,66 @@
/*
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 SolidityType.h
* @author Yann yann@ethdev.com
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2015
* Ethereum IDE client.
*/
#pragma once
#include <QString>
#include <vector>
namespace dev
{
namespace mix
{
struct SolidityDeclaration;
//Type info extracted from solidity AST
struct SolidityType
{
enum Type //keep in sync with QSolidity::Type
{
SignedInteger,
UnsignedInteger,
Hash, //TODO: remove
Bool,
Address,
Bytes,
Enum,
Struct
};
Type type;
unsigned size; //in bytes,
bool array;
bool dynamicSize;
QString name;
std::vector<SolidityDeclaration> members; //for struct
std::vector<QString> enumNames; //for enum
};
struct SolidityDeclaration
{
QString name;
SolidityType type;
};
}
}

69
mix/qml/DebugInfoList.qml

@ -11,6 +11,8 @@ ColumnLayout {
property bool enableSelection: false; property bool enableSelection: false;
property real storedHeight: 0; property real storedHeight: 0;
property Component itemDelegate property Component itemDelegate
property Component componentDelegate
property alias item: loader.item
signal rowActivated(int index) signal rowActivated(int index)
spacing: 0 spacing: 0
@ -91,43 +93,54 @@ ColumnLayout {
} }
} }
] ]
TableView { Loader
clip: true; {
alternatingRowColors: false id: loader
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.topMargin: 3 anchors.topMargin: 3
anchors.leftMargin: 3 anchors.leftMargin: 3
width: parent.width - 3 width: parent.width - 3
height: parent.height - 6 height: parent.height - 6
model: listModel sourceComponent: componentDelegate ? componentDelegate : table
selectionMode: enableSelection ? SelectionMode.SingleSelection : SelectionMode.NoSelection }
headerDelegate: null Component
itemDelegate: root.itemDelegate {
onHeightChanged: { id: table
if (height <= 0 && collapsible) { TableView
if (storedHeight <= 0) {
storedHeight = 200; clip: true;
storageContainer.state = "collapsed"; alternatingRowColors: false
} anchors.fill: parent
else if (height > 0 && storageContainer.state == "collapsed") { model: listModel
//TODO: fix increasing size selectionMode: enableSelection ? SelectionMode.SingleSelection : SelectionMode.NoSelection
//storageContainer.state = ""; headerDelegate: null
itemDelegate: root.itemDelegate
onHeightChanged: {
if (height <= 0 && collapsible) {
if (storedHeight <= 0)
storedHeight = 200;
storageContainer.state = "collapsed";
}
else if (height > 0 && storageContainer.state == "collapsed") {
//TODO: fix increasing size
//storageContainer.state = "";
}
} }
} onActivated: rowActivated(row);
onActivated: rowActivated(row); Keys.onPressed: {
Keys.onPressed: { if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < listModel.length) {
if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < listModel.length) { var str = "";
var str = ""; for (var i = 0; i < listModel.length; i++)
for (var i = 0; i < listModel.length; i++) str += listModel[i] + "\n";
str += listModel[i] + "\n"; appContext.toClipboard(str);
appContext.toClipboard(str); }
} }
}
TableViewColumn { TableViewColumn {
role: "modelData" role: "modelData"
width: parent.width width: parent.width
}
} }
} }
} }

4
mix/qml/Debugger.qml

@ -574,7 +574,7 @@ Rectangle {
Layout.maximumHeight: 800 Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight(); onHeightChanged: machineStates.updateHeight();
visible: !assemblyMode visible: !assemblyMode
StorageView { VariablesView {
title : qsTr("Locals") title : qsTr("Locals")
anchors.fill: parent anchors.fill: parent
id: solLocals id: solLocals
@ -589,7 +589,7 @@ Rectangle {
Layout.maximumHeight: 800 Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight(); onHeightChanged: machineStates.updateHeight();
visible: !assemblyMode visible: !assemblyMode
StorageView { VariablesView {
title : qsTr("Members") title : qsTr("Members")
anchors.fill: parent anchors.fill: parent
id: solStorage id: solStorage

7
mix/qml/QBoolType.qml

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

10
mix/qml/QBoolTypeView.qml

@ -4,8 +4,10 @@ import QtQuick.Controls 1.3
Item Item
{ {
id: editRoot id: editRoot
property string text property string value
property string defaultValue property string defaultValue
height: 20
width: 150
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
@ -14,10 +16,10 @@ Item
property bool inited: false property bool inited: false
Component.onCompleted: Component.onCompleted:
{ {
if (text === "") if (value === "")
currentIndex = parseInt(defaultValue); currentIndex = parseInt(defaultValue);
else else
currentIndex = parseInt(text); currentIndex = parseInt(value);
inited = true inited = true
} }
@ -26,7 +28,7 @@ Item
onCurrentIndexChanged: onCurrentIndexChanged:
{ {
if (inited) if (inited)
text = comboModel.get(currentIndex).value; value = comboModel.get(currentIndex).value;
} }
model: ListModel model: ListModel
{ {

7
mix/qml/QHashType.qml

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

6
mix/qml/QHashTypeView.qml

@ -2,8 +2,10 @@ import QtQuick 2.0
Item Item
{ {
property alias text: textinput.text property alias value: textinput.text
id: editRoot id: editRoot
height: 20
width: 150
SourceSansProBold SourceSansProBold
{ {
@ -16,7 +18,7 @@ Item
color: "#f7f7f7" color: "#f7f7f7"
TextInput { TextInput {
id: textinput id: textinput
text: text text: value
anchors.fill: parent anchors.fill: parent
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
clip: true clip: true

7
mix/qml/QIntType.qml

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

7
mix/qml/QIntTypeView.qml

@ -1,9 +1,12 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Layouts 1.1
Item Item
{ {
property alias text: textinput.text property alias value: textinput.text
id: editRoot id: editRoot
height: 20
width: 150
SourceSansProBold SourceSansProBold
{ {
@ -16,7 +19,7 @@ Item
color: "#f7f7f7" color: "#f7f7f7"
TextInput { TextInput {
id: textinput id: textinput
text: text text: value
anchors.fill: parent anchors.fill: parent
font.family: boldFont.name font.family: boldFont.name
clip: true clip: true

7
mix/qml/QRealType.qml

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

7
mix/qml/QStringType.qml

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

6
mix/qml/QStringTypeView.qml

@ -2,8 +2,10 @@ import QtQuick 2.0
Item Item
{ {
property alias text: textinput.text property alias value: textinput.text
id: editRoot id: editRoot
height: 20
width: 150
SourceSansProBold SourceSansProBold
{ {
@ -16,7 +18,7 @@ Item
color: "#f7f7f7" color: "#f7f7f7"
TextInput { TextInput {
id: textinput id: textinput
text: text text: value
clip: true clip: true
anchors.fill: parent anchors.fill: parent
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere

2
mix/qml/StateDialog.qml

@ -373,7 +373,7 @@ Window {
{ {
iconSource: "qrc:/qml/img/edit.png" iconSource: "qrc:/qml/img/edit.png"
action: editAction action: editAction
visible: !stdContract visible: stdContract === false
width: 10 width: 10
height: 10 height: 10
Action { Action {

38
mix/qml/StateListModel.qml

@ -41,38 +41,13 @@ Item {
value: QEtherHelper.createEther(t.value.value, t.value.unit), value: QEtherHelper.createEther(t.value.value, t.value.unit),
gas: QEtherHelper.createBigInt(t.gas.value), gas: QEtherHelper.createBigInt(t.gas.value),
gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit), gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit),
stdContract: t.stdContract, stdContract: t.stdContract ? true : false,
parameters: {}, parameters: {},
sender: t.sender sender: t.sender
}; };
var qType = [];
for (var key in t.parameters) for (var key in t.parameters)
{ r.parameters[key] = t.parameters[key];
r.parameters[key] = t.parameters[key].value;
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");
else {
console.log("Unknown parameter type: " + type);
continue;
}
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;
} }
@ -118,14 +93,7 @@ Item {
parameters: {} parameters: {}
}; };
for (var key in t.parameters) for (var key in t.parameters)
{ r.parameters[key] = t.parameters[key];
var param = {
name: key,
value: t.parameters[key],
type: getParamType(key, t.qType)
}
r.parameters[key] = param;
}
return r; return r;
} }

90
mix/qml/StructView.qml

@ -0,0 +1,90 @@
import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import org.ethereum.qml.QSolidityType 1.0
Column
{
id: root
property alias members: repeater.model //js array
property var value : { }
Layout.fillWidth: true
Repeater
{
id: repeater
visible: model.length > 0
Layout.fillWidth: true
RowLayout
{
id: row
height: 20 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0)
Layout.fillWidth: true
DefaultLabel {
height: 20
id: typeLabel
text: modelData.type.name
Layout.preferredWidth: 50
}
DefaultLabel {
id: nameLabel
text: modelData.name
Layout.preferredWidth: 80
}
DefaultLabel {
id: equalLabel
text: "="
Layout.preferredWidth: 15
}
Loader
{
id: typeLoader
Layout.preferredWidth: 150
sourceComponent:
{
var t = modelData.type.category;
if (t === QSolidityType.SignedInteger || t === QSolidityType.UnsignedInteger)
return Qt.createComponent("qrc:/qml/QIntTypeView.qml");
else if (t === QSolidityType.Bool)
return Qt.createComponent("qrc:/qml/QBoolTypeView.qml");
else if (t === QSolidityType.Bytes)
return Qt.createComponent("qrc:/qml/QStringTypeView.qml");
else if (t === QSolidityType.Hash || t === QSolidityType.Address)
return Qt.createComponent("qrc:/qml/QHashTypeView.qml");
else if (t === QSolidityType.Struct)
return Qt.createComponent("qrc:/qml/StructView.qml");
else
return undefined;
}
onLoaded:
{
var ptype = members[index].type;
var pname = members[index].name;
var vals = value;
if (ptype.category === QSolidityType.Struct && !item.members) {
item.value = getValue();
item.members = ptype.members;
}
else
item.value = getValue();
item.onValueChanged.connect(function() {
vals[pname] = item.value;
valueChanged();
});
}
function getValue()
{
if (value && value[modelData.name] !== undefined)
return value[modelData.name];
else if (modelData.type.category === QSolidityType.Struct)
return {};
return "";
}
}
}
}
}

214
mix/qml/TransactionDialog.qml

@ -11,26 +11,23 @@ Window {
id: modalTransactionDialog id: modalTransactionDialog
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
width: 520 width: 520
height: (paramsModel.count > 0 ? 500 : 300) height: 500;
visible: false visible: false
color: StateDialogStyle.generic.backgroundColor color: StateDialogStyle.generic.backgroundColor
title: qsTr("Edit Transaction") title: qsTr("Edit Transaction")
property int transactionIndex property int transactionIndex
property alias transactionParams: paramsModel;
property alias gas: gasValueEdit.gasValue; property alias gas: gasValueEdit.gasValue;
property alias gasPrice: gasPriceField.value; property alias gasPrice: gasPriceField.value;
property alias transactionValue: valueField.value; property alias transactionValue: valueField.value;
property string contractId: contractComboBox.currentValue(); property string contractId: contractComboBox.currentValue();
property alias functionId: functionComboBox.currentText; property alias functionId: functionComboBox.currentText;
property var itemParams; property var paramValues;
property var paramsModel: [];
property bool useTransactionDefaultValue: false property bool useTransactionDefaultValue: false
property var qType;
property alias stateAccounts: senderComboBox.model property alias stateAccounts: senderComboBox.model
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;
@ -44,7 +41,7 @@ Window {
var functionId = item.functionId; var functionId = item.functionId;
rowFunction.visible = true; rowFunction.visible = true;
itemParams = item.parameters !== undefined ? item.parameters : {}; paramValues = item.parameters !== undefined ? item.parameters : {};
if (item.sender) if (item.sender)
senderComboBox.select(item.sender); senderComboBox.select(item.sender);
@ -73,15 +70,15 @@ Window {
functionComboBox.currentIndex = functionIndex; functionComboBox.currentIndex = functionIndex;
paramsModel.clear(); paramsModel = [];
if (functionId !== contractComboBox.currentValue()) if (functionId !== contractComboBox.currentValue())
loadParameters(); loadParameters();
else { else {
var contract = codeModel.contracts[contractId]; var contract = codeModel.contracts[contractId];
if (contract) { if (contract) {
var parameters = contract.contract.constructor.parameters; var params = contract.contract.constructor.parameters;
for (var p = 0; p < parameters.length; p++) for (var p = 0; p < params.length; p++)
loadParameter(parameters[p]); loadParameter(params[p]);
} }
} }
modalTransactionDialog.setX((Screen.width - width) / 2); modalTransactionDialog.setX((Screen.width - width) / 2);
@ -89,6 +86,9 @@ Window {
visible = true; visible = true;
valueField.focus = true; valueField.focus = true;
modalTransactionDialog.height = (paramsModel.length > 0 ? 500 : 300);
paramLabel.visible = paramsModel.length > 0;
paramScroll.visible = paramsModel.length > 0;
} }
function loadFunctions(contractId) function loadFunctions(contractId)
@ -110,32 +110,11 @@ Window {
{ {
var type = parameter.type; var type = parameter.type;
var pname = parameter.name; var pname = parameter.name;
var varComponent; paramsModel.push({ name: pname, type: 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(parameter);
qType.push({ name: pname, value: param });
paramsModel.append({ name: pname, type: type, value: value });
} }
function loadParameters() { function loadParameters() {
paramsModel.clear(); paramsModel = []
if (!paramsModel)
return;
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
var contract = codeModel.contracts[contractComboBox.currentValue()]; var contract = codeModel.contracts[contractComboBox.currentValue()];
if (contract) { if (contract) {
@ -147,15 +126,11 @@ Window {
} }
} }
} }
} typeLoader.value = {}
typeLoader.members = []
typeLoader.value = paramValues;
typeLoader.members = paramsModel;
function param(name)
{
for (var k = 0; k < paramsModel.count; k++)
{
if (paramsModel.get(k).name === name)
return paramsModel.get(k);
}
} }
function close() function close()
@ -163,15 +138,6 @@ 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;
@ -194,15 +160,7 @@ Window {
} }
item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.sender = senderComboBox.model[senderComboBox.currentIndex].secret;
var orderedQType = []; item.parameters = paramValues;
for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p);
var qtypeParam = qTypeParam(parameter.name);
qtypeParam.setValue(parameter.value);
orderedQType.push(qtypeParam);
item.parameters[parameter.name] = parameter.value;
}
item.qType = orderedQType;
return item; return item;
} }
@ -370,145 +328,27 @@ Window {
id: paramLabel id: paramLabel
text: qsTr("Parameters:") text: qsTr("Parameters:")
Layout.preferredWidth: 75 Layout.preferredWidth: 75
visible: paramsModel.count > 0
} }
ScrollView ScrollView
{ {
id: paramScroll
anchors.top: paramLabel.bottom anchors.top: paramLabel.bottom
anchors.topMargin: 10 anchors.topMargin: 10
Layout.preferredWidth: 350 Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
visible: paramsModel.count > 0 StructView
Column
{ {
id: paramRepeater id: typeLoader
Layout.fillWidth: true Layout.preferredWidth: 150
Layout.fillHeight: true members: paramsModel;
spacing: 3
Repeater
{
height: 20 * paramsModel.count
model: paramsModel
visible: paramsModel.count > 0
RowLayout
{
id: row
Layout.fillWidth: true
height: 20
DefaultLabel {
id: typeLabel
text: type
Layout.preferredWidth: 50
}
DefaultLabel {
id: nameLabel
text: name
Layout.preferredWidth: 80
}
DefaultLabel {
id: equalLabel
text: "="
Layout.preferredWidth: 15
}
Loader
{
id: typeLoader
Layout.preferredWidth: 150
function getCurrent()
{
return modalTransactionDialog.param(name);
}
Connections {
target: typeLoader.item
onTextChanged: {
typeLoader.getCurrent().value = typeLoader.item.text;
}
}
sourceComponent:
{
if (type.indexOf("int") !== -1)
return intViewComp;
else if (type.indexOf("bool") !== -1)
return boolViewComp;
else if (type.indexOf("string") !== -1)
return stringViewComp;
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
return hashViewComp;
else
return null;
}
Component
{
id: intViewComp
QIntTypeView
{
height: 20
width: 150
id: intView
text: typeLoader.getCurrent().value
}
}
Component
{
id: boolViewComp
QBoolTypeView
{
height: 20
width: 150
id: boolView
defaultValue: "1"
Component.onCompleted:
{
var current = typeLoader.getCurrent().value;
(current === "" ? text = defaultValue : text = current);
}
}
}
Component
{
id: stringViewComp
QStringTypeView
{
height: 20
width: 150
id: stringView
text:
{
return typeLoader.getCurrent().value
}
}
}
Component
{
id: hashViewComp
QHashTypeView
{
height: 20
width: 150
id: hashView
text: typeLoader.getCurrent().value
}
}
}
}
}
} }
} }
CommonSeparator CommonSeparator
{ {
Layout.fillWidth: true Layout.fillWidth: true
visible: paramsModel.count > 0 visible: paramsModel.length > 0
} }
} }
@ -530,8 +370,4 @@ Window {
} }
} }
} }
ListModel {
id: paramsModel
}
} }

39
mix/qml/VariablesView.qml

@ -0,0 +1,39 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import "."
DebugInfoList
{
id: storage
collapsible: true
title : qsTr("Storage")
componentDelegate: structComp
Component
{
id: structComp
ScrollView
{
property alias members: typeLoader.members;
property alias value: typeLoader.value;
anchors.fill: parent
StructView
{
id: typeLoader
members: []
value: {}
Layout.preferredWidth: parent.width
}
}
}
function setData(members, values) {
storage.item.value = {};
storage.item.members = [];
storage.item.value = values; //TODO: use a signal for this?
storage.item.members = members;
}
}

3
mix/qml/html/WebContainer.html

@ -20,7 +20,8 @@ updateContracts = function(contracts) {
window.web3.reset(); window.web3.reset();
window.contracts = {}; window.contracts = {};
for (var c in contracts) { for (var c in contracts) {
var contract = window.web3.eth.contract(contracts[c].address, contracts[c].interface); var contractProto = window.web3.eth.contract(contracts[c].interface);
var contract = new contractProto(contracts[c].address);
window.contracts[c] = { window.contracts[c] = {
address: c.address, address: c.address,
interface: c.interface, interface: c.interface,

8
mix/qml/js/Debugger.js

@ -199,12 +199,12 @@ function completeCtxInformation(state)
storage.listModel = state.debugStorage; storage.listModel = state.debugStorage;
memoryDump.listModel = state.debugMemory; memoryDump.listModel = state.debugMemory;
if (state.solidity) { if (state.solidity) {
solLocals.listModel = state.solidity.locals; solLocals.setData(state.solidity.locals.variables, state.solidity.locals.values);
solStorage.listModel = state.solidity.storage; solStorage.setData(state.solidity.storage.variables, state.solidity.storage.values);
solCallStack.listModel = state.solidity.callStack; solCallStack.listModel = state.solidity.callStack;
} else { } else {
solLocals.listModel = []; solLocals.setData([], {});
solStorage.listModel = []; solStorage.setData([], {});
solCallStack.listModel = []; solCallStack.listModel = [];
} }
} }

7
mix/res.qrc

@ -44,13 +44,8 @@
<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/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/QStringType.qml</file>
<file>qml/QBoolTypeView.qml</file> <file>qml/QBoolTypeView.qml</file>
<file>qml/QIntTypeView.qml</file> <file>qml/QIntTypeView.qml</file>
<file>qml/QRealTypeView.qml</file> <file>qml/QRealTypeView.qml</file>
@ -115,6 +110,8 @@
<file>qml/img/copy.png</file> <file>qml/img/copy.png</file>
<file>qml/img/broom.png</file> <file>qml/img/broom.png</file>
<file>qml/LogsPaneStyle.qml</file> <file>qml/LogsPaneStyle.qml</file>
<file>qml/StructView.qml</file>
<file>qml/img/console.png</file> <file>qml/img/console.png</file>
<file>qml/VariablesView.qml</file>
</qresource> </qresource>
</RCC> </RCC>

26
mix/stdc/std.sol

@ -13,14 +13,12 @@ contract Config is mortal {
if (tx.origin != owner) if (tx.origin != owner)
return; return;
services[id] = service; services[id] = service;
log1(0, id);
} }
function unregister(uint id) { function unregister(uint id) {
if (msg.sender != owner && services[id] != msg.sender) if (msg.sender != owner && services[id] != msg.sender)
return; return;
services[id] = address(0); services[id] = address(0);
log1(0, id);
} }
function lookup(uint service) constant returns(address a) { function lookup(uint service) constant returns(address a) {
@ -56,8 +54,8 @@ web3.eth.contract(addrConfig, abiConfig).lookup(1).call().then(function(r){ addr
// Gav Wood <g@ethdev.com> // Gav Wood <g@ethdev.com>
contract NameRegister { contract NameRegister {
function getAddress(string32 _name) constant returns (address o_owner) {} function getAddress(bytes32 _name) constant returns (address o_owner) {}
function getName(address _owner) constant returns (string32 o_name) {} function getName(address _owner) constant returns (bytes32 o_name) {}
} }
contract NameReg is owned, NameRegister { contract NameReg is owned, NameRegister {
@ -68,11 +66,9 @@ contract NameReg is owned, NameRegister {
toName[this] = "NameReg"; toName[this] = "NameReg";
toAddress["NameReg"] = this; toAddress["NameReg"] = this;
Config(addrConfig).register(1, this); Config(addrConfig).register(1, this);
log1(0, hash256(addrConfig));
log1(0, hash256(this));
} }
function register(string32 name) { function register(bytes32 name) {
// Don't allow the same name to be overwritten. // Don't allow the same name to be overwritten.
if (toAddress[name] != address(0)) if (toAddress[name] != address(0))
return; return;
@ -82,41 +78,39 @@ contract NameReg is owned, NameRegister {
toName[msg.sender] = name; toName[msg.sender] = name;
toAddress[name] = msg.sender; toAddress[name] = msg.sender;
log1(0, hash256(msg.sender));
} }
function unregister() { function unregister() {
string32 n = toName[msg.sender]; bytes32 n = toName[msg.sender];
if (n == "") if (n == "")
return; return;
log1(0, hash256(toAddress[n]));
toName[msg.sender] = ""; toName[msg.sender] = "";
toAddress[n] = address(0); toAddress[n] = address(0);
} }
function addressOf(string32 name) constant returns (address addr) { function addressOf(bytes32 name) constant returns (address addr) {
return toAddress[name]; return toAddress[name];
} }
function nameOf(address addr) constant returns (string32 name) { function nameOf(address addr) constant returns (bytes32 name) {
return toName[addr]; return toName[addr];
} }
mapping (address => string32) toName; mapping (address => bytes32) toName;
mapping (string32 => address) toAddress; mapping (bytes32 => address) toAddress;
} }
/* /*
// Solidity Interface: // Solidity Interface:
contract NameReg{function kill(){}function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}} contract NameReg{function kill(){}function register(bytes32 name){}function addressOf(bytes32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(bytes32 name){}}
// Example Solidity use: // Example Solidity use:
NameReg(addrNameReg).register("Some Contract"); NameReg(addrNameReg).register("Some Contract");
// JS Interface: // JS Interface:
var abiNameReg = [{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]}]; var abiNameReg = [{"constant":true,"inputs":[{"name":"name","type":"bytes32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"bytes32"}]},{"constant":false,"inputs":[{"name":"name","type":"bytes32"}],"name":"register","outputs":[]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]}];
// Example JS use: // Example JS use:
web3.eth.contract(addrNameReg, abiNameReg).register("My Name").transact(); web3.eth.contract(addrNameReg, abiNameReg).register("My Name").transact();

Loading…
Cancel
Save