Browse Source

- Transaction call debugging.

cl-refactor
yann300 10 years ago
committed by yann300
parent
commit
8d304d86d0
  1. 2
      libdevcore/CommonData.h
  2. 7
      libdevcore/CommonJS.cpp
  3. 5
      libdevcore/CommonJS.h
  4. 30
      libethereum/Executive.cpp
  5. 1
      libethereum/Executive.h
  6. 108
      mix/AssemblyDebuggerCtrl.cpp
  7. 9
      mix/AssemblyDebuggerCtrl.h
  8. 61
      mix/AssemblyDebuggerModel.cpp
  9. 9
      mix/AssemblyDebuggerModel.h
  10. 3
      mix/ConstantCompilationCtrl.cpp
  11. 3
      mix/ConstantCompilationModel.cpp
  12. 1
      mix/ConstantCompilationModel.h
  13. 135
      mix/ContractCallDataEncoder.cpp
  14. 56
      mix/ContractCallDataEncoder.h
  15. 8
      mix/DebuggingStateWrapper.cpp
  16. 4
      mix/DebuggingStateWrapper.h
  17. 5
      mix/QBasicNodeDefinition.h
  18. 10
      mix/QContractDefinition.cpp
  19. 5
      mix/QContractDefinition.h
  20. 4
      mix/QFunctionDefinition.cpp
  21. 2
      mix/QFunctionDefinition.h
  22. 4
      mix/QVariableDeclaration.h
  23. 55
      mix/QVariableDefinition.cpp
  24. 71
      mix/QVariableDefinition.h
  25. 20
      mix/TransactionBuilder.cpp
  26. 41
      mix/TransactionBuilder.h
  27. 53
      mix/qml/Debugger.qml
  28. 10
      mix/qml/js/Debugger.js

2
libdevcore/CommonData.h

@ -113,7 +113,7 @@ inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); ret
/// Convenience function for toBigEndian.
/// @returns a byte array just big enough to represent @a _val.
template <class _T>
inline bytes toCompactBigEndian(_T _val, unsigned _min = 0)
inline bytes toCompactBigEndian(_T _val, unsigned _min = 1)
{
int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {}

7
libdevcore/CommonJS.cpp

@ -54,4 +54,11 @@ bytes unpadded(bytes _b)
return _b;
}
std::string unpadded(std::string _b)
{
auto p = _b.find_last_not_of((char)0);
_b = _b.substr(p, _b.length() - 1);
return _b;
}
}

5
libdevcore/CommonJS.h

@ -35,12 +35,12 @@ template <unsigned S> std::string toJS(FixedHash<S> const& _h)
{
return "0x" + toHex(_h.ref());
}
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n)
{
return "0x" + toHex(toCompactBigEndian(_n));
}
inline std::string toJS(dev::bytes const& _n)
{
return "0x" + dev::toHex(_n);
@ -49,6 +49,7 @@ inline std::string toJS(dev::bytes const& _n)
bytes jsToBytes(std::string const& _s);
bytes padded(bytes _b, unsigned _l);
bytes unpadded(bytes _s);
std::string unpadded(std::string _s);
template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{

30
libethereum/Executive.cpp

@ -44,6 +44,36 @@ u256 Executive::gasUsed() const
return m_t.gas() - m_endGas;
}
bool Executive::forceSetup(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.
m_t = Transaction(_rlp);
m_sender = m_t.sender();
// Increment associated nonce for sender.
m_s.noteSending(m_sender);
u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice();
// Pay...
clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
m_s.subBalance(m_sender, cost);
if (m_ms)
{
m_ms->from = m_sender;
m_ms->to = m_t.receiveAddress();
m_ms->value = m_t.value();
m_ms->input = m_t.data();
}
auto gasCost = Interface::txGas(m_t.data());
if (m_t.isCreation())
return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasCost, &m_t.data(), m_sender);
else
return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)gasCost, m_sender);
}
bool Executive::setup(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.

1
libethereum/Executive.h

@ -47,6 +47,7 @@ public:
~Executive();
bool setup(bytesConstRef _transaction);
bool forceSetup(bytesConstRef _transaction);
bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress);
bool call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress);
bool go(OnOpFunc const& _onOp = OnOpFunc());

108
mix/AssemblyDebuggerCtrl.cpp

@ -18,8 +18,10 @@
*/
#include <QDebug>
#include <QVariableDefinition.h>
#include <QQmlContext>
#include <QModelIndex>
#include <libdevcore/CommonJS.h>
#include "libethereum/Transaction.h"
#include "AssemblyDebuggerModel.h"
#include "AssemblyDebuggerCtrl.h"
@ -27,11 +29,23 @@
#include "KeyEventManager.h"
#include "ApplicationCtx.h"
#include "DebuggingStateWrapper.h"
#include "QContractDefinition.h"
#include "QVariableDeclaration.h"
#include "ContractCallDataEncoder.h"
using namespace dev::eth;
using namespace dev::mix;
AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::ModalDialog)
{
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*");
qRegisterMetaType<QList<QVariableDefinition*>>("QList<QVariableDefinition*>");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
m_compilation = std::unique_ptr<ConstantCompilationModel>(new ConstantCompilationModel);
m_senderAddress = KeyPair::create(); //this address will be used as the sender address.
m_modelDebugger.get()->addBalance(m_senderAddress, 10000000000000*1000000 + 10000000);
m_doc = _doc;
}
@ -55,30 +69,80 @@ void AssemblyDebuggerCtrl::keyPressed(int _key)
{
if (_key == Qt::Key_F5)
{
if (!m_modelDebugger->compile(m_doc->toPlainText()))
m_previousDebugResult = deployContract();
}
else if(_key == Qt::Key_F4)
callContract(m_previousDebugResult.contractAddress);
else if(_key == Qt::Key_F3)
{
//Reset state;
m_modelDebugger.get()->resetState();
}
}
void AssemblyDebuggerCtrl::callContract(Address contractAddress)
{
CompilerResult compilerRes = m_compilation.get()->compile(m_doc->toPlainText());
if (!compilerRes.success)
{
ApplicationCtx::getInstance()->displayMessageDialog("debugger","compilation failed");
return;
}
ContractCallDataEncoder c;
std::shared_ptr<QContractDefinition> contractDef = QContractDefinition::Contract(m_doc->toPlainText());
QFunctionDefinition* fo = nullptr;
for (int i = 0; i < contractDef->functions().size(); i++)
{
QFunctionDefinition* f = (QFunctionDefinition*)contractDef->functions().at(i);
if (f->name() == "test2")
{
fo = f;
c.encode(i);
for (int k = 0; k < f->parameters().size(); k++)
{
ApplicationCtx::getInstance()->displayMessageDialog("debugger","compilation failed");
return;
c.encode((QVariableDeclaration*)f->parameters().at(k), QString("3"));
}
}
}
KeyPair ad = KeyPair::create();
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
DebuggingContent debuggingContent = m_modelDebugger->getContractInitiationDebugStates(amount, gasPrice, gas, m_doc->toPlainText(), ad);
Transaction tr = m_trBuilder.getDefaultBasicTransaction(contractAddress, c.encodedData(), m_senderAddress);
DebuggingContent debuggingContent = m_modelDebugger->getContractCallDebugStates(tr);
debuggingContent.returnParameters = c.decode(fo->returnParameters(), debuggingContent.returnValue);
finalizeExecution(debuggingContent);
}
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.states.size(); i++)
{
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes());
s->setState(debuggingContent.states.at(i));
wStates.append(s);
}
std::tuple<QList<QObject*>, QQMLMap*> code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode, this);
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("debugStates", QVariant::fromValue(wStates));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(code)));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(code)));
this->addContentOn(this);
};
DebuggingContent AssemblyDebuggerCtrl::deployContract()
{
CompilerResult compilerRes = m_compilation.get()->compile(m_doc->toPlainText());
if (!compilerRes.success)
{
ApplicationCtx::getInstance()->displayMessageDialog("debugger","compilation failed");
DebuggingContent res;
res.contentAvailable = false;
return res;
}
Transaction tr = m_trBuilder.getDefaultCreationTransaction(compilerRes.bytes, m_senderAddress);
DebuggingContent debuggingContent = m_modelDebugger->getContractInitiationDebugStates(tr);
finalizeExecution(debuggingContent);
return debuggingContent;
}
void AssemblyDebuggerCtrl::finalizeExecution(DebuggingContent debuggingContent)
{
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.states.size(); i++)
{
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes());
s->setState(debuggingContent.states.at(i));
wStates.append(s);
}
std::tuple<QList<QObject*>, QQMLMap*> code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode, this);
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("debugStates", QVariant::fromValue(wStates));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(code)));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(code)));
ApplicationCtx::getInstance()->appEngine()->rootContext()->setContextProperty("contractCallReturnParameters",
QVariant::fromValue(new QVariableDefinitionList(debuggingContent.returnParameters)));
this->addContentOn(this);
}

9
mix/AssemblyDebuggerCtrl.h

@ -24,6 +24,7 @@
#include "Extension.h"
#include "ConstantCompilationModel.h"
#include "AssemblyDebuggerModel.h"
#include "TransactionBuilder.h"
namespace dev
{
@ -44,7 +45,15 @@ public:
private:
std::unique_ptr<AssemblyDebuggerModel> m_modelDebugger;
std::unique_ptr<ConstantCompilationModel> m_compilation;
QTextDocument* m_doc;
TransactionBuilder m_trBuilder;
KeyPair m_senderAddress;
DebuggingContent deployContract();
void callContract(Address contractAddress);
void finalizeExecution(DebuggingContent content);
DebuggingContent m_previousDebugResult;
public Q_SLOTS:
void keyPressed(int);

61
mix/AssemblyDebuggerModel.cpp

@ -22,6 +22,7 @@
#include "libethereum/ExtVM.h"
#include "libevm/VM.h"
#include "libdevcore/Common.h"
#include "libdevcore/CommonJS.h"
#include "ApplicationCtx.h"
#include "TransactionBuilder.h"
#include "AssemblyDebuggerModel.h"
@ -36,11 +37,16 @@ AssemblyDebuggerModel::AssemblyDebuggerModel()
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState));
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::bytesConstRef _rawTransaction)
void AssemblyDebuggerModel::addBalance(KeyPair address, u256 amount)
{
//m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState));
m_executiveState.addBalance(dev::toAddress(address.secret()), amount);
//m_currentExecution.reset();
}
DebuggingContent AssemblyDebuggerModel::executeTransaction()
{
QList<DebuggingState> states;
Transaction tr(_rawTransaction);
m_currentExecution.get()->create(tr.sender(), tr.value(), tr.gasPrice(), tr.gas(), &tr.data(), tr.sender());
std::vector<DebuggingState const*> levels;
bytes code;
bytesConstRef data;
@ -68,8 +74,10 @@ DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::by
m_currentExecution.get()->go(onOp);
m_currentExecution.get()->finalize(onOp);
m_executiveState.completeMine();
DebuggingContent d;
d.returnValue = m_currentExecution.get()->out().toVector();
d.states = states;
d.executionCode = code;
d.executionData = data;
@ -78,33 +86,34 @@ DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::by
return d;
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::u256 _value,
dev::u256 _gasPrice,
dev::u256 _gas,
QString code,
KeyPair _key)
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(Transaction _tr)
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(code);
if (!res.success)
{
DebuggingContent r;
r.contentAvailable = false;
r.message = "compile failed";
return r;
}
bytes b = _tr.rlp();
dev::bytesConstRef bytesRef = &b;
m_currentExecution.get()->forceSetup(bytesRef);
DebuggingContent d = executeTransaction();
TransactionBuilder trBuild;
Transaction tr = trBuild.getCreationTransaction(_value, _gasPrice, _gas, res.bytes,
m_executiveState.transactionsFrom(dev::toAddress(_key.secret())), _key.secret());
bytes b = tr.rlp();
h256 th = sha3(rlpList(_tr.sender(), _tr.nonce()));
d.contractAddress = right160(th);
m_currentExecution.reset();
return d;
}
DebuggingContent AssemblyDebuggerModel::getContractCallDebugStates(Transaction _tr)
{
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState));
bytes b = _tr.rlp();
dev::bytesConstRef bytesRef = &b;
return getContractInitiationDebugStates(bytesRef);
m_currentExecution.get()->forceSetup(bytesRef);
DebuggingContent d = executeTransaction();
d.contractAddress = _tr.receiveAddress();
m_currentExecution.reset();
return d;
}
bool AssemblyDebuggerModel::compile(QString _code)
void AssemblyDebuggerModel::resetState()
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(_code);
return res.success;
m_executiveState = State();
}

9
mix/AssemblyDebuggerModel.h

@ -22,6 +22,7 @@
#include <QObject>
#include <QList>
#include "libethereum/State.h"
#include "libethereum/Transaction.h"
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
#include "DebuggingStateWrapper.h"
@ -36,11 +37,13 @@ class AssemblyDebuggerModel
{
public:
AssemblyDebuggerModel();
DebuggingContent getContractInitiationDebugStates(dev::u256, dev::u256, dev::u256, QString, KeyPair);
DebuggingContent getContractInitiationDebugStates(dev::bytesConstRef);
bool compile(QString);
DebuggingContent getContractInitiationDebugStates(dev::eth::Transaction);
DebuggingContent getContractCallDebugStates(dev::eth::Transaction);
void addBalance(KeyPair address, u256 amount);
void resetState();
private:
DebuggingContent executeTransaction();
std::unique_ptr<dev::eth::Executive> m_currentExecution;
dev::eth::State m_executiveState;
};

3
mix/ConstantCompilationCtrl.cpp

@ -20,14 +20,17 @@
* Ethereum IDE client.
*/
#include <QQmlContext>
#include <QQuickItem>
#include <QtCore/QFileInfo>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtCore/QtCore>
#include <QDebug>
#include "ApplicationCtx.h"
#include "ConstantCompilationCtrl.h"
#include "ConstantCompilationModel.h"
#include "QContractDefinition.h"
using namespace dev::mix;
ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::Tab)

3
mix/ConstantCompilationModel.cpp

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

1
mix/ConstantCompilationModel.h

@ -23,6 +23,7 @@
#pragma once
#include <libevm/VM.h>
#include <libsolidity/AST.h>
#include <QObject>
namespace dev

135
mix/ContractCallDataEncoder.cpp

@ -0,0 +1,135 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ContractCallDataEncoder.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include <QMap>
#include <QStringList>
#include <libdevcore/CommonJS.h>
#include "libsolidity/AST.h"
#include "QVariableDeclaration.h"
#include "QVariableDefinition.h"
#include "ContractCallDataEncoder.h"
using namespace dev;
using namespace dev::solidity;
using namespace dev::mix;
ContractCallDataEncoder::ContractCallDataEncoder()
{
}
bytes ContractCallDataEncoder::encodedData()
{
return m_encodedData;
}
void ContractCallDataEncoder::encode(int _functionIndex)
{
bytes i = jsToBytes(std::to_string(_functionIndex));
m_encodedData.insert(m_encodedData.end(), i.begin(), i.end());
}
void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, bool _value)
{
return encode(_dec, QString(formatBool(_value)));
}
void ContractCallDataEncoder::encode(QVariableDeclaration* _dec, QString _value)
{
int padding = this->padding(_dec->type());
bytes data = padded(jsToBytes(_value.toStdString()), padding);
m_encodedData.insert(m_encodedData.end(), data.begin(), data.end());
}
QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QObject*> _returnParameters, bytes _value)
{
QList<QVariableDefinition*> r;
std::string returnValue = toJS(_value);
returnValue = returnValue.substr(2, returnValue.length() - 1);
for (int k = 0; k <_returnParameters.length(); k++)
{
QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k);
int padding = this->padding(dec->type());
std::string rawParam = returnValue.substr(0, padding * 2);
r.append(new QVariableDefinition(dec, convertToReadable(unpadded(rawParam), dec)));
returnValue = returnValue.substr(padding, returnValue.length() - 1);
}
return r;
}
int ContractCallDataEncoder::padding(QString type)
{
// TODO : to be improved (load types automatically from solidity library).
if (type.indexOf("uint") != 1)
{
return integerPadding(type.remove("uint").toInt());
}
else if (type.indexOf("int") != -1)
{
//int
return integerPadding(type.remove("int").toInt());
}
else if (type.indexOf("bool") != -1)
{
return 1;
}
else if ((type.indexOf("address") != -1))
{
return 20;
}
return 0;
}
int ContractCallDataEncoder::integerPadding(int bitValue)
{
return bitValue / 8;
}
QString ContractCallDataEncoder::formatBool(bool _value)
{
return (_value ? "1" : "0");
}
QString ContractCallDataEncoder::convertToReadable(std::string _v, QVariableDeclaration* _dec)
{
if (_dec->type().indexOf("int") != -1)
{
return convertToInt(_v);
}
else if (_dec->type().indexOf("bool") != -1)
{
return convertToBool(_v);
}
else
{
return QString::fromStdString(_v);
}
}
QString ContractCallDataEncoder::convertToBool(std::string _v)
{
return _v == "1" ? "true" : "false";
}
QString ContractCallDataEncoder::convertToInt(std::string _v)
{
return QString::fromStdString(_v);
}

56
mix/ContractCallDataEncoder.h

@ -0,0 +1,56 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ContractCallDataEncoder.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include "QVariableDeclaration.h"
#include "QVariableDefinition.h"
namespace dev
{
namespace mix
{
class ContractCallDataEncoder
{
public:
ContractCallDataEncoder();
void encode(QVariableDeclaration* _dec, QString _value);
QList<QVariableDefinition*> decode(QList<QObject*> _dec, bytes _value);
void encode(QVariableDeclaration* _dec, bool _value);
void encode(int _functionIndex);
bytes encodedData();
private:
QMap<QString, int> typePadding;
int padding(QString _type);
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);
bytes m_encodedData;
};
}
}

8
mix/DebuggingStateWrapper.cpp

@ -42,7 +42,7 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << hex << std::setw(4) << std::setfill('0') << i;
out << std::setw(4) << std::setfill('0') << i;
codeMapping[i] = codeStr.size();
int line = i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
@ -102,7 +102,7 @@ QStringList DebuggingStateWrapper::levels()
std::ostringstream out;
out << m_state.cur.abridged();
if (i)
out << " " << instructionInfo(m_state.inst).name << " @0x" << hex << m_state.curPC;
out << " " << instructionInfo(m_state.inst).name << " @0x" << m_state.curPC;
levelsStr.append(QString::fromStdString(out.str()));
}
return levelsStr;
@ -143,9 +143,9 @@ QString DebuggingStateWrapper::prettyU256(u256 _n)
QString raw;
std::ostringstream s;
if (!(_n >> 64))
s << " " << (uint64_t)_n << " (0x" << hex << (uint64_t)_n << ")";
s << " " << (uint64_t)_n << " (0x" << (uint64_t)_n << ")";
else if (!~(_n >> 64))
s << " " << (int64_t)_n << " (0x" << hex << (int64_t)_n << ")";
s << " " << (int64_t)_n << " (0x" << (int64_t)_n << ")";
else if ((_n >> 160) == 0)
{
Address a = right160(_n);

4
mix/DebuggingStateWrapper.h

@ -26,6 +26,7 @@
#include "libethereum/State.h"
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
#include "QVariableDefinition.h"
namespace dev
{
@ -53,8 +54,11 @@ struct DebuggingContent
QList<DebuggingState> states;
bytes executionCode;
bytesConstRef executionData;
Address contractAddress;
bool contentAvailable;
QString message;
bytes returnValue;
QList<QVariableDefinition*> returnParameters;
};
/* contains the line nb of the assembly code and the corresponding index in the code bytes array */

5
mix/QBasicNodeDefinition.h

@ -36,8 +36,9 @@ class QBasicNodeDefinition: public QObject
public:
QBasicNodeDefinition(): QObject() {}
~QBasicNodeDefinition() {}
QBasicNodeDefinition(std::shared_ptr<dev::solidity::Declaration> _d, QObject* _parent): QObject(_parent), m_dec(_d) {}
~QBasicNodeDefinition() {
}
QBasicNodeDefinition(std::shared_ptr<dev::solidity::Declaration> _d): QObject(), m_dec(_d) {}
QString name() { return QString::fromStdString(m_dec.get()->getName()); }
protected:

10
mix/QContractDefinition.cpp

@ -29,27 +29,27 @@
using namespace dev::solidity;
using namespace dev::mix;
QContractDefinition* QContractDefinition::Contract(QString _source, QObject* _parent)
std::shared_ptr<QContractDefinition> QContractDefinition::Contract(QString _source)
{
Parser parser;
std::shared_ptr<ContractDefinition> contract = parser.parse(std::make_shared<Scanner>(CharStream(_source.toStdString())));
NameAndTypeResolver resolver({});
resolver.resolveNamesAndTypes(*contract);
return new QContractDefinition(contract, _parent);
return std::make_shared<QContractDefinition>(contract);
}
QContractDefinition::QContractDefinition(std::shared_ptr<ContractDefinition> _contract, QObject* _parent): QBasicNodeDefinition(_contract, _parent), m_def(_contract)
QContractDefinition::QContractDefinition(std::shared_ptr<ContractDefinition> _contract): QBasicNodeDefinition(_contract)
{
initQFunctions();
}
void QContractDefinition::initQFunctions()
{
std::vector<FunctionDefinition const*> functions = m_def.get()->getInterfaceFunctions();
std::vector<FunctionDefinition const*> functions = ((ContractDefinition*)m_dec.get())->getInterfaceFunctions();
for (unsigned i = 0; i < functions.size(); i++)
{
FunctionDefinition* func = (FunctionDefinition*)functions.at(i);
std::shared_ptr<FunctionDefinition> sharedFunc(func);
m_functions.append(new QFunctionDefinition(sharedFunc, parent(), i));
m_functions.append(new QFunctionDefinition(sharedFunc, i));
}
}

5
mix/QContractDefinition.h

@ -37,12 +37,11 @@ class QContractDefinition: public QBasicNodeDefinition
Q_PROPERTY(QList<QObject*> functions READ functions)
public:
QContractDefinition(std::shared_ptr<dev::solidity::ContractDefinition> _contract, QObject* _parent);
QContractDefinition(std::shared_ptr<dev::solidity::ContractDefinition> _contract);
QList<QObject*> functions() { return m_functions; }
static QContractDefinition* Contract(QString _code, QObject* _parent);
static std::shared_ptr<QContractDefinition> Contract(QString _code);
private:
std::shared_ptr<dev::solidity::ContractDefinition> m_def;
QList<QObject*> m_functions;
void initQFunctions();
};

4
mix/QFunctionDefinition.cpp

@ -30,12 +30,12 @@ void QFunctionDefinition::initQParameters()
std::vector<std::shared_ptr<VariableDeclaration>> parameters = ((FunctionDefinition*)m_dec.get())->getParameterList().getParameters();
for (unsigned i = 0; i < parameters.size(); i++)
{
m_parameters.append(new QVariableDeclaration(parameters.at(i), parent()));
m_parameters.append(new QVariableDeclaration(parameters.at(i)));
}
std::vector<std::shared_ptr<VariableDeclaration>> returnParameters = ((FunctionDefinition*)m_dec.get())->getReturnParameters();
for (unsigned i = 0; i < returnParameters.size(); i++)
{
m_returnParameters.append(new QVariableDeclaration(returnParameters.at(i), parent()));
m_returnParameters.append(new QVariableDeclaration(returnParameters.at(i)));
}
}

2
mix/QFunctionDefinition.h

@ -37,7 +37,7 @@ class QFunctionDefinition: public QBasicNodeDefinition
Q_PROPERTY(int index READ index)
public:
QFunctionDefinition(std::shared_ptr<dev::solidity::FunctionDefinition> _f, QObject* _parent, int _index): QBasicNodeDefinition(_f, _parent), m_index(_index) { initQParameters(); }
QFunctionDefinition(std::shared_ptr<dev::solidity::FunctionDefinition> _f, int _index): QBasicNodeDefinition(_f), m_index(_index) { initQParameters(); }
QList<QObject*> parameters() { return m_parameters; }
QList<QObject*> returnParameters() { return m_returnParameters; }
int index() { return m_index; }

4
mix/QVariableDeclaration.h

@ -35,7 +35,7 @@ class QVariableDeclaration: public QBasicNodeDefinition
Q_PROPERTY(QString type READ type)
public:
QVariableDeclaration(std::shared_ptr<dev::solidity::VariableDeclaration> _v, QObject* _parent): QBasicNodeDefinition(_v, _parent), m_var(_v) {}
QVariableDeclaration(std::shared_ptr<dev::solidity::VariableDeclaration> _v): QBasicNodeDefinition(_v), m_var(_v) {}
QString type() { return QString::fromStdString(m_var.get()->getType()->toString()); }
private:
@ -44,3 +44,5 @@ private:
}
}
Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*)

55
mix/QVariableDefinition.cpp

@ -0,0 +1,55 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file QVariableDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#include "QVariableDefinition.h"
using namespace dev::mix;
int QVariableDefinitionList::rowCount(const QModelIndex& parent) const
{
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);
}

71
mix/QVariableDefinition.h

@ -0,0 +1,71 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file QVariableDefinition.h
* @author Yann yann@ethdev.com
* @date 2014
*/
#pragma once
#include <QAbstractListModel>
#include "QVariableDeclaration.h"
namespace dev
{
namespace mix
{
class QVariableDefinition: public QObject
{
Q_OBJECT
Q_PROPERTY(QString value READ value)
Q_PROPERTY(QVariableDeclaration* declaration READ declaration)
public:
QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(_def->parent()), m_value(_value), m_dec(_def) {}
QVariableDeclaration* declaration() { return m_dec; }
QString value() { return m_value; }
private:
QVariableDeclaration* m_dec;
QString m_value;
};
class QVariableDefinitionList: public QAbstractListModel
{
Q_OBJECT
//Q_PROPERTY(QList<QVariableDefinition*> def READ def)
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;
QVariableDefinition* val(int idx);
QList<QVariableDefinition*> def() {
return m_def;
}
private:
QList<QVariableDefinition*> m_def;
};
}
}
Q_DECLARE_METATYPE(dev::mix::QVariableDefinition*)

20
mix/TransactionBuilder.cpp

@ -32,9 +32,25 @@ Transaction TransactionBuilder::getCreationTransaction(u256 _value, u256 _gasPri
}
Transaction TransactionBuilder::getBasicTransaction(u256 _value, u256 _gasPrice, u256 _gas,
QString address, bytes _data, u256 _nonce, Secret _secret) const
Address address, bytes _data, u256 _nonce, Secret _secret) const
{
return Transaction(_value, _gasPrice, _gas, fromString(address), _data, _nonce, _secret);
return Transaction(_value, _gasPrice, _gas, address, _data, _nonce, _secret);
}
Transaction TransactionBuilder::getDefaultCreationTransaction(dev::bytes code, KeyPair sender) const
{
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
return getCreationTransaction(amount, gasPrice, gas, code, 0, sender.secret());
}
Transaction TransactionBuilder::getDefaultBasicTransaction(Address contractAddress, dev::bytes data, KeyPair sender) const
{
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
return getBasicTransaction(amount, gasPrice, gas, contractAddress, data, 0, sender.secret());
}
int TransactionBuilder::fromHex(char _i) const

41
mix/TransactionBuilder.h

@ -1,15 +1,15 @@
/*
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/>.
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TransactionBuilder.h
* @author Yann yann@ethdev.com
@ -32,15 +32,18 @@ namespace mix
class TransactionBuilder
{
public:
TransactionBuilder() {}
dev::eth::Transaction getBasicTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
QString address, bytes _data, dev::u256 _nonce, Secret _secret) const;
dev::eth::Transaction getCreationTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
dev::bytes _data, dev::u256 _nonce, Secret _secret) const;
TransactionBuilder() {}
dev::eth::Transaction getBasicTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
dev::Address address, bytes _data, dev::u256 _nonce, Secret _secret) const;
dev::eth::Transaction getCreationTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
dev::bytes _data, dev::u256 _nonce, Secret _secret) const;
dev::eth::Transaction getDefaultCreationTransaction(dev::bytes code, KeyPair sender) const;
dev::eth::Transaction getDefaultBasicTransaction(dev::Address contractAddress, dev::bytes data, KeyPair sender) const;
private:
bytes fromHex(std::string const& _s) const;
int fromHex(char _i) const;
Address fromString(QString const& _a) const;
bytes fromHex(std::string const& _s) const;
int fromHex(char _i) const;
Address fromString(QString const& _a) const;
};
}

53
mix/qml/Debugger.qml

@ -11,17 +11,49 @@ Rectangle {
Rectangle {
color: "transparent"
id: headerInfo
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
height: 30
height: 60
anchors.top: parent.top
Label {
anchors.centerIn: parent
font.family: "Verdana"
font.pointSize: 9
font.italic: true
id: headerInfoLabel
Column {
width: parent.width
height: parent.height
Rectangle {
color: "transparent"
width: parent.width
height: 30
Label {
anchors.centerIn: parent
font.family: "Verdana"
font.pointSize: 9
font.italic: true
id: headerInfoLabel
}
}
Rectangle {
color: "transparent"
width: parent.width
height: 30
ListView {
orientation: ListView.Horizontal
anchors.centerIn: parent;
id: headerReturnList
delegate: renderDelegateReturnValues
}
Component {
id: renderDelegateReturnValues
Item {
id: wrapperItem
width: parent.width
Text {
anchors.centerIn: parent
text: variable.declaration.name + " : " + variable.value
font.pointSize: 9
}
}
}
}
}
}
Keys.onPressed: {
@ -38,7 +70,7 @@ Rectangle {
anchors.topMargin: 10
anchors.top: headerInfo.bottom
anchors.left: parent.left
height: parent.height - 30
height: parent.height - 70
width: parent.width * 0.5
ListView {
@ -232,6 +264,9 @@ Rectangle {
anchors.bottom: parent.bottom
width: parent.width
height: parent.height - 15
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
id: debugCallDataTxt
readOnly: true;
}

10
mix/qml/js/Debugger.js

@ -8,6 +8,7 @@ function init()
{
currentSelectedState = 0;
select(currentSelectedState);
displayReturnValue();
}
function moveSelection(incr)
@ -27,10 +28,11 @@ function moveSelection(incr)
function select(stateIndex)
{
console.log(stateIndex);
var state = debugStates[stateIndex];
var codeStr = bytesCodeMapping.getValue(state.curPC);
highlightSelection(codeStr);
currentSelectedState = codeStr;
currentSelectedState = stateIndex;
completeCtxInformation(state);
levelList.model = state.levels;
levelList.update();
@ -61,3 +63,9 @@ function endOfDebug()
var gascost = state.gas - state.gasCost;
headerInfoLabel.text = "EXIT | GAS: " + gascost;
}
function displayReturnValue()
{
headerReturnList.model = contractCallReturnParameters;
headerReturnList.update();
}

Loading…
Cancel
Save