From 0ed47e9020b6207cf4991ee38721eb81ab8c4fcb Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Jul 2015 13:37:38 +0200 Subject: [PATCH 01/21] Improved gas computation for CALLCODE. --- libsolidity/ExpressionCompiler.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 470fd7c58..786d386d9 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1072,6 +1072,7 @@ void ExpressionCompiler::appendExternalFunctionCall( using FunctionKind = FunctionType::Location; FunctionKind funKind = _functionType.getLocation(); bool returnSuccessCondition = funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode; + bool isCallCode = funKind == FunctionKind::BareCallCode || funKind == FunctionKind::CallCode; //@todo only return the first return value for now Type const* firstReturnType = @@ -1158,13 +1159,20 @@ void ExpressionCompiler::appendExternalFunctionCall( if (_functionType.gasSet()) m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); else + { // send all gas except the amount needed to execute "SUB" and "CALL" // @todo this retains too much gas for now, needs to be fine-tuned. + u256 gasNeededByCaller = eth::c_callGas + 10; + if (_functionType.valueSet()) + gasNeededByCaller += eth::c_callValueTransferGas; + if (!isCallCode) + gasNeededByCaller += eth::c_callNewAccountGas; // we never know m_context << - u256(eth::c_callGas + 10 + (_functionType.valueSet() ? eth::c_callValueTransferGas : 0) + eth::c_callNewAccountGas) << + gasNeededByCaller << eth::Instruction::GAS << eth::Instruction::SUB; - if (funKind == FunctionKind::CallCode || funKind == FunctionKind::BareCallCode) + } + if (isCallCode) m_context << eth::Instruction::CALLCODE; else m_context << eth::Instruction::CALL; From bb5568aa27b621d6b22fafaff2e4aff2cb6234fc Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 29 Jul 2015 10:51:48 +0200 Subject: [PATCH 02/21] ui changes on deploydialog --- mix/qml/DeployContractStep.qml | 9 +++++++++ mix/qml/PackagingStep.qml | 28 +++++++++++++++------------- mix/qml/RegisteringStep.qml | 32 ++++++++++++++++---------------- mix/qml/StateListModel.qml | 4 ++-- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 01f06e4f2..aad31383d 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -136,9 +136,11 @@ Rectangle { ScrollView { anchors.fill: parent + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff ColumnLayout { spacing: 0 + ListModel { id: trListModel @@ -213,6 +215,13 @@ Rectangle { font.italic: true } } + + Rectangle + { + Layout.preferredWidth: scenarioList.width + Layout.preferredHeight: 1 + color: "#cccccc" + } } } } diff --git a/mix/qml/PackagingStep.qml b/mix/qml/PackagingStep.qml index 6f7ed3f11..26b5c8540 100644 --- a/mix/qml/PackagingStep.qml +++ b/mix/qml/PackagingStep.qml @@ -51,13 +51,14 @@ Rectangle { id: col spacing: 20 + anchors.left: parent.left + anchors.leftMargin: 10 Label { anchors.top: parent.top Layout.fillWidth: true - anchors.left: parent.left - anchors.leftMargin: 10 + text: qsTr("Upload and update your Dapp assets") } @@ -67,11 +68,11 @@ Rectangle { Layout.preferredHeight: 20 Rectangle { - Layout.preferredWidth: col.width / 2 + Layout.preferredWidth: col.width / 5 Label { text: qsTr("Save Package to") - anchors.right: parent.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } } @@ -80,7 +81,7 @@ Rectangle { { id: packageFolder visible: true - Layout.preferredWidth: 150 + Layout.preferredWidth: 360 text: projectPath + "package/" } @@ -102,7 +103,8 @@ Rectangle { Button { id: generatePackageBtn - anchors.horizontalCenter: parent.horizontalCenter + anchors.left: parent.left + anchors.leftMargin: 10 text: qsTr("Generate Package") onClicked: { @@ -117,7 +119,6 @@ Rectangle { anchors.top: generatePackageBtn.bottom anchors.topMargin: 10 visible: root.lastDeployDate !== "" - anchors.horizontalCenter: parent.horizontalCenter Label { id: lastPackage @@ -137,11 +138,11 @@ Rectangle { Layout.preferredHeight: 20 Rectangle { - Layout.preferredWidth: col.width / 2 + Layout.preferredWidth: col.width / 5 Label { text: qsTr("Local package URL") - anchors.right: parent.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } } @@ -149,7 +150,7 @@ Rectangle { DefaultTextField { id: localPackageUrl - Layout.preferredWidth: 235 + Layout.preferredWidth: 450 readOnly: true } } @@ -157,7 +158,6 @@ Rectangle { Label { Layout.preferredWidth: 300 - anchors.horizontalCenter: parent.horizontalCenter text: qsTr("You have to upload the package to a remote folder, or use a service like pastebin") wrapMode: Text.WordWrap clip: true @@ -171,8 +171,9 @@ Rectangle { Button { Layout.preferredWidth: 200 - anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Copy Base64") + anchors.left: parent.left + anchors.leftMargin: 10 onClicked: { clipboard.text = deploymentDialog.packageStep.packageBase64; @@ -188,8 +189,9 @@ Rectangle { Button { Layout.preferredWidth: 200 - anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Open pastebin") + anchors.left: parent.left + anchors.leftMargin: 10 onClicked: { Qt.openUrlExternally("http://pastebin.com/"); diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index e275e1434..c8c98de90 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -82,11 +82,11 @@ Rectangle { anchors.topMargin: 10 id: col spacing: 20 + anchors.left: parent.left + anchors.leftMargin: 10 Label { anchors.top: parent.top - anchors.left: parent.left - anchors.leftMargin: 10 Layout.fillWidth: true text: qsTr("Register your Dapp on the Name registrar Contract") } @@ -97,11 +97,11 @@ Rectangle { Layout.preferredHeight: 20 Rectangle { - Layout.preferredWidth: col.width / 2 + Layout.preferredWidth: col.width / 5 Label { text: qsTr("Root Registrar address") - anchors.right: parent.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } } @@ -111,7 +111,7 @@ Rectangle { id: registrarAddr text: "c6d9d2cd449a754c494264e1809c50e34d64562b" visible: true - Layout.preferredWidth: 235 + Layout.preferredWidth: 450 } } @@ -121,11 +121,11 @@ Rectangle { Layout.preferredHeight: 20 Rectangle { - Layout.preferredWidth: col.width / 2 + Layout.preferredWidth: col.width / 5 Label { text: qsTr("Http URL") - anchors.right: parent.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } } @@ -133,7 +133,7 @@ Rectangle { DefaultTextField { id: applicationUrlHttpCtrl - Layout.preferredWidth: 235 + Layout.preferredWidth: 450 } Label @@ -150,11 +150,11 @@ Rectangle { Layout.preferredHeight: 20 Rectangle { - Layout.preferredWidth: col.width / 2 + Layout.preferredWidth: col.width / 5 Label { text: qsTr("Registration Cost") - anchors.right: parent.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter id: ctrRegisterLabel function calculateRegisterGas() @@ -192,11 +192,11 @@ Rectangle { Layout.preferredHeight: 20 Rectangle { - Layout.preferredWidth: col.width / 2 + Layout.preferredWidth: col.width / 5 Label { text: qsTr("Ethereum URL") - anchors.right: parent.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } } @@ -205,10 +205,10 @@ Rectangle { { height: 25 color: "transparent" - Layout.preferredWidth: 235 + Layout.preferredWidth: 450 DefaultTextField { - width: 235 + width: 450 id: applicationUrlEthCtrl onTextChanged: { ctrRegisterLabel.calculateRegisterGas(); @@ -223,11 +223,11 @@ Rectangle { Layout.preferredHeight: 20 Rectangle { - Layout.preferredWidth: col.width / 2 + Layout.preferredWidth: col.width / 4 Label { text: qsTr("Formatted Ethereum URL") - anchors.right: parent.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index e7b092463..a428b23cf 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -298,7 +298,7 @@ Item { var ctorTr = defaultTransactionItem(); ctorTr.functionId = c; ctorTr.contractId = c; - ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId; + ctorTr.label = ctorTr.contractId + "." + ctorTr.contractId + "()" ctorTr.sender = item.accounts[0].secret; item.transactions.push(ctorTr); item.blocks[0].transactions.push(ctorTr) @@ -340,7 +340,7 @@ Item { var ctorTr = defaultTransactionItem(); ctorTr.functionId = c; ctorTr.contractId = c; - ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId; + ctorTr.label = ctorTr.contractId + "." + ctorTr.contractId + "()"; ctorTr.sender = state.accounts[0].secret; state.transactions.push(ctorTr); changed = true; From 5319baa978630db58c9a525ebc931f76c78446e5 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 30 Jul 2015 09:38:30 +0200 Subject: [PATCH 03/21] changes on QBoolTypeView.qml QAddressView.qml --- mix/ClientModel.cpp | 25 +++++- mix/ContractCallDataEncoder.cpp | 43 ++++++--- mix/QVariableDeclaration.h | 2 + mix/qml/QAddressView.qml | 152 +++++++++++++++++++++----------- mix/qml/QBoolTypeView.qml | 63 +++++++++++-- mix/qml/QIntTypeView.qml | 4 +- mix/qml/QStringTypeView.qml | 3 +- mix/qml/ScenarioLoader.qml | 1 - mix/qml/StructView.qml | 41 +++++++-- mix/qml/TransactionDialog.qml | 9 +- mix/qml/VariablesView.qml | 2 +- mix/qml/js/InputValidator.js | 9 +- 12 files changed, 257 insertions(+), 97 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index ab15f55ca..c2e199326 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -388,10 +388,29 @@ void ClientModel::executeSequence(vector const& _sequence) { QSolidityType const* type = p->type(); QVariant value = transaction.parameterValues.value(p->name()); - if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<")) + if (type->type().type == SolidityType::Type::Address) { - std::pair ctrParamInstance = resolvePair(value.toString()); - value = QVariant(resolveToken(ctrParamInstance)); + if (type->array()) + { + QJsonArray jsonDoc = QJsonDocument::fromJson(value.toString().toUtf8()).array(); + int k = 0; + for (QJsonValue const& item: jsonDoc) + { + if (item.toString().startsWith("<")) + { + std::pair ctrParamInstance = resolvePair(item.toString()); + jsonDoc.replace(k, resolveToken(ctrParamInstance)); + } + k++; + } + QJsonDocument doc(jsonDoc); + value = QVariant(doc.toJson(QJsonDocument::Compact)); + } + else if (value.toString().startsWith("<")) + { + std::pair ctrParamInstance = resolvePair(value.toString()); + value = QVariant(resolveToken(ctrParamInstance)); + } } encoder.encode(value, type->type()); } diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 5ed014088..947853c46 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -101,9 +101,9 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& bytes empty(32); size_t sizePos = m_dynamicData.size(); m_dynamicData += empty; //reserve space for count - u256 count = encodeSingleItem(_data.toString(), _type, m_dynamicData); + encodeSingleItem(_data.toString(), _type, m_dynamicData); vector_ref sizeRef(m_dynamicData.data() + sizePos, 32); - toBigEndian(count, sizeRef); + toBigEndian(_data.toString().size(), sizeRef); m_staticOffsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); m_encodedData += empty; //reserve space for offset } @@ -262,6 +262,8 @@ QJsonArray ContractCallDataEncoder::decodeArray(SolidityType const& _type, bytes QJsonArray array; bytesConstRef value(&_value); int count = 0; + bigint offset = pos; + int valuePosition = pos; if (!_type.dynamicSize) count = _type.count; else @@ -269,14 +271,33 @@ QJsonArray ContractCallDataEncoder::decodeArray(SolidityType const& _type, bytes bytesConstRef value(_value.data() + pos, 32); // offset bytes rawParam(32); value.populate(&rawParam); - bigint offset = decodeInt(rawParam); - pos = static_cast(offset) + 32; - value = bytesConstRef(_value.data() + static_cast(offset), 32); // offset + offset = decodeInt(rawParam); + valuePosition = static_cast(offset) + 32; + pos += 32; + value = bytesConstRef(_value.data() + static_cast(offset), 32); // count value.populate(&rawParam); count = static_cast(decodeInt(rawParam)); } - for (int k = 0; k < count; ++k) - array.append(decodeArrayContent(_type, _value, pos)); + if (_type.type == QSolidityType::Type::Bytes || _type.type == QSolidityType::Type::String) + { + bytesConstRef value(_value.data() + (static_cast(offset) + 32), 32); + bytes rawParam(count); + value.populate(&rawParam); + if (_type.type == QSolidityType::Type::Bytes) + array.append(toString(decodeBytes(rawParam))); + else + array.append(toChar(decodeBytes(rawParam))); + } + else + { + for (int k = 0; k < count; ++k) + { + if (_type.dynamicSize) + array.append(decodeArrayContent(_type, _value, valuePosition)); + else + array.append(decodeArrayContent(_type, _value, pos)); + } + } return array; } @@ -329,18 +350,14 @@ QStringList ContractCallDataEncoder::decode(QList const& QJsonArray array = decodeArray(type, _v, readPosition); QJsonDocument jsonDoc = QJsonDocument::fromVariant(array.toVariantList()); r.append(jsonDoc.toJson(QJsonDocument::Compact)); - if (type.dynamicSize) - readPosition++; - else - readPosition = type.count; } else { - bytesConstRef value(_value.data() + (readPosition * 32), 32); + bytesConstRef value(_value.data() + readPosition, 32); bytes rawParam(32); value.populate(&rawParam); r.append(decode(type, rawParam).toString()); - readPosition++; + readPosition += 32; } } return r; diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index 583847b44..0b6ab3bf2 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -47,6 +47,7 @@ class QSolidityType: public QObject Q_PROPERTY(int size READ size CONSTANT) Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QVariantList members READ members CONSTANT) + Q_PROPERTY(bool array READ array CONSTANT) public: QSolidityType() {} @@ -71,6 +72,7 @@ public: int size() const { return m_type.size; } QString name() const { return m_type.name; } QVariantList members() const; + bool array() const { return m_type.array; } private: SolidityType m_type; diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index 56aefcf3e..2b5521124 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -1,8 +1,10 @@ import QtQuick 2.0 import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 +import QtQuick.Layouts 1.1 +import "js/InputValidator.js" as InputValidator -Row +ColumnLayout { property alias value: textinput.text property alias accountRef: ctrModel @@ -12,8 +14,16 @@ Row property alias displayInput: textInputRect.visible property variant accounts signal indexChanged() + spacing: 0 id: editRoot - height: 20 + height: + { + if (isArray() && !readOnly) + return 60 + else + return 30 + } + width: 320 SourceSansProBold @@ -21,6 +31,12 @@ Row id: boldFont } + function isArray() + { + InputValidator.init() + return InputValidator.isArray(subType) + } + function currentValue() { return value; } @@ -38,7 +54,7 @@ Row function load() { accountRef.clear(); - if (subType === "contract" || subType === "address") + if (subType.indexOf("contract") !== -1 || subType.indexOf("address") !== -1) { var trCr = 0; if (blockChainPanel) @@ -59,7 +75,7 @@ Row } } } - if (subType === "address") + if (subType.indexOf("address") !== -1) { for (k = 0; k < accounts.length; k++) { @@ -72,8 +88,24 @@ Row function init() { - trCombobox.visible = !readOnly textinput.readOnly = readOnly + if (isArray() || readOnly) + displayInput = true + else + displayInput = false + + if (isArray() || !readOnly) + trCombobox.visible = true + else + trCombobox.visible = false + + if (!trCombobox.visible) + { + trCombobox.height = 0 + textinput.anchors.top = textinput.parent.top + } + + if (!readOnly) { for (var k = 0; k < ctrModel.count; k++) @@ -86,7 +118,8 @@ Row } trCombobox.currentIndex = 0; } - trCombobox.update() + if (!isArray()) + trCombobox.update() } function select(address) @@ -101,17 +134,73 @@ Row } } + ListModel + { + id: ctrModel + } + + Row + { + anchors.top: parent.top + height: 30 + id: rowCombobox + ComboBox + { + property bool selected: false + id: trCombobox + model: ctrModel + width: 265 + textRole: "itemid" + function update() + { + trCombobox.selected = false; + if (currentText === "") + return; + else if (currentText !== " - ") + { + if (model.get(currentIndex).type === "contract") + textinput.text = "<" + currentText + ">"; + else + textinput.text = model.get(currentIndex).value; //address + trCombobox.selected = true; + } + else if (textinput.text.indexOf("<") === 0) + { + textinput.text = ""; + } + indexChanged(); + } + + onCurrentIndexChanged: { + if (!isArray()) + update() + } + } + + Button + { + id: btnAdd + text: qsTr("Add") + visible: false + onClicked: + { + var ar = JSON.parse(textinput.text) + ar.push(trCombobox.model.get(currentIndex).value) + textinput.text = JSON.stringify(ar) + } + } + } + + Rectangle { radius: 4 - anchors.verticalCenter: parent.verticalCenter - height: 20 + width: 350 + height: 30 id: textInputRect - TextInput { + TextField { id: textinput text: value - width: parent.width - height: parent.width - wrapMode: Text.WordWrap + anchors.fill: parent clip: true font.family: boldFont.name MouseArea { @@ -130,43 +219,4 @@ Row } } } - - ListModel - { - id: ctrModel - } - - ComboBox - { - property bool selected: false - id: trCombobox - model: ctrModel - width: 350 - textRole: "itemid" - anchors.verticalCenter: parent.verticalCenter - - function update() - { - trCombobox.selected = false; - if (currentText === "") - return; - else if (currentText !== " - ") - { - if (model.get(currentIndex).type === "contract") - textinput.text = "<" + currentText + ">"; - else - textinput.text = model.get(currentIndex).value; //address - trCombobox.selected = true; - } - else if (textinput.text.indexOf("<") === 0) - { - textinput.text = ""; - } - indexChanged(); - } - - onCurrentIndexChanged: { - update() - } - } } diff --git a/mix/qml/QBoolTypeView.qml b/mix/qml/QBoolTypeView.qml index 12c932762..21405208a 100644 --- a/mix/qml/QBoolTypeView.qml +++ b/mix/qml/QBoolTypeView.qml @@ -1,5 +1,6 @@ import QtQuick 2.0 import QtQuick.Controls 1.3 +import "js/InputValidator.js" as InputValidator Item { @@ -7,6 +8,7 @@ Item property string value property string defaultValue property bool readOnly: !boolCombo.enabled + property string subType height: 20 width: 150 @@ -14,20 +16,56 @@ Item boolCombo.enabled = !readOnly; } + function isArray() + { + InputValidator.init() + return InputValidator.isArray(subType) + } + function init() + { + if (!isArray()) + { + boolArray.visible = false + boolCombo.visible = true + + value = format(value) + + var setValue = "1" + if (value === "") + setValue = parseInt(defaultValue); + else + setValue = parseInt(value); + boolCombo.checked = setValue === "1" ? true: false + boolCombo.enabled = !readOnly; + } + else + { + boolArray.visible = true + boolCombo.visible = false + if (value === "") + boolArray.text = "[]" + else + boolArray.text = value + + var formattedparam = [] + var param = JSON.parse(boolArray.text) + for (var k in JSON.parse(boolArray.text)) + formattedparam.push(parseInt(format(param[k]))) + boolArray.text = JSON.stringify(formattedparam) + value = "" + value = boolArray.text + console.log("gfdg " + value) + } + } + + function format(value) { value = value === true ? "1" : value value = value === false ? "0" : value; value = value === "true" ? "1" : value value = value === "false" ? "0" : value; - - var setValue = "1" - if (value === "") - setValue = parseInt(defaultValue); - else - setValue = parseInt(value); - boolCombo.checked = setValue === "1" ? true: false - boolCombo.enabled = !readOnly; + return value } Rectangle { @@ -52,6 +90,15 @@ Item } text: qsTr("True") } + + TextField + { + id: boolArray + onTextChanged: + { + value = text + } + } } } diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml index 6bee54a1f..65e029ad5 100644 --- a/mix/qml/QIntTypeView.qml +++ b/mix/qml/QIntTypeView.qml @@ -5,7 +5,7 @@ Item property alias value: textinput.text property alias readOnly: textinput.readOnly id: editRoot - width: 200 + width: 350 DebuggerPaneStyle { id: dbgStyle } @@ -15,7 +15,7 @@ Item id: textinput selectByMouse: true text: value - implicitWidth: 200 + implicitWidth: 350 MouseArea { id: mouseArea anchors.fill: parent diff --git a/mix/qml/QStringTypeView.qml b/mix/qml/QStringTypeView.qml index 25831cb00..e8b798784 100644 --- a/mix/qml/QStringTypeView.qml +++ b/mix/qml/QStringTypeView.qml @@ -6,7 +6,7 @@ Item property alias value: textinput.text property alias readOnly: textinput.readOnly id: editRoot - width: readOnly ? textinput.implicitWidth : 150 + width: 350 DebuggerPaneStyle { id: dbgStyle @@ -17,6 +17,7 @@ Item id: textinput selectByMouse: true text: value + width: 350 MouseArea { id: mouseArea anchors.fill: parent diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 8b6886c93..db3692a5c 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -28,7 +28,6 @@ ColumnLayout function needSaveOrReload() { - editStatus.visible = true } RowLayout diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 96a828eba..9ba29031d 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -13,7 +13,14 @@ Column property int transactionIndex property string context Layout.fillWidth: true - spacing: 5 + spacing: 0 + property int colHeight + + onValueChanged: + { + colHeight = 0 + } + Repeater { id: repeater @@ -21,8 +28,17 @@ Column RowLayout { id: row - height: 30 + (members[index].type.category === QSolidityType.Struct ? (30 * members[index].type.members.length) : 0) Layout.fillWidth: true + + Component.onCompleted: + { + if (QSolidityType.Address === members[index].type.category && members[index].type.array && context === "parameter") + height = 60 + else + height = 30 + (members[index].type.category === QSolidityType.Struct ? (30 * members[index].type.members.length) : 0) + root.colHeight += height + } + Rectangle { Layout.preferredWidth: 150 @@ -30,12 +46,14 @@ Column { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - Label { + Label + { id: nameLabel text: modelData.name } - Label { + Label + { id: typeLabel text: " (" + modelData.type.name + ")" font.italic: true @@ -72,6 +90,12 @@ Column var ptype = members[index].type; var pname = members[index].name; var vals = value; + + item.onValueChanged.connect(function() { + vals[pname] = item.value; + valueChanged(); + }); + item.readOnly = context === "variable"; if (ptype.category === QSolidityType.Address) { @@ -83,6 +107,7 @@ Column item.subType = dec[0]; item.load(); } + console.log("jj" + pname) item.init(); } else if (ptype.category === QSolidityType.Struct && !item.members) @@ -94,12 +119,10 @@ Column item.value = getValue(); if (ptype.category === QSolidityType.Bool) + { + item.subType = modelData.type.name item.init(); - - item.onValueChanged.connect(function() { - vals[pname] = item.value; - valueChanged(); - }); + } var newWidth = nameLabel.width + typeLabel.width + item.width + 108; if (root.width < newWidth) diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index e47bd9ed2..ccf564659 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -120,6 +120,7 @@ Dialog { var type = parameter.type; var pname = parameter.name; paramsModel.push({ name: pname, type: type }); + console.log(JSON.stringify(paramsModel)) } function loadParameters() { @@ -237,13 +238,15 @@ Dialog { recipientsAccount.select(contractId); if (functionId) selectFunction(functionId); + else + functionComboBox.currentIndex = 0 if (isFunctionCall) { labelRecipient.text = qsTr("Recipient Contract") functionRect.show() loadFunctions(TransactionHelper.contractFromToken(recipientsAccount.currentValue())) loadParameters(); - paramScroll.updateView() + //paramScroll.updateView() } else { @@ -496,11 +499,9 @@ Dialog { function updateView() { paramScroll.visible = paramsModel.length > 0 - paramScroll.Layout.preferredHeight = paramsModel.length < 6 ? paramsModel.length * 30 : 205 + paramScroll.Layout.preferredHeight = paramScroll.colHeight if (paramsModel.length === 0) - { paramScroll.height = 0 - } } } diff --git a/mix/qml/VariablesView.qml b/mix/qml/VariablesView.qml index aec629853..517204877 100644 --- a/mix/qml/VariablesView.qml +++ b/mix/qml/VariablesView.qml @@ -25,7 +25,7 @@ DebugInfoList members: [] value: {} context: "variable" - width:parent.width + width: parent.width } } } diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js index c0626e0f1..ea8d6dad5 100644 --- a/mix/qml/js/InputValidator.js +++ b/mix/qml/js/InputValidator.js @@ -32,10 +32,11 @@ function init() function check(type, value) { var res = { valid: true, message : "" } - if (isContractType(type)) - res = validateAddress(type, value); - else if (isArray(type)) + + if (isArray(type)) res = validateArray(type, value); + else if (isContractType(type)) + res = validateAddress(type, value); else if (type.indexOf("int") !== -1) res = validateInt(type, value); else if (type.indexOf("enum") !== -1) @@ -196,7 +197,7 @@ function validateBytes(_type, _value) function validateBool(_type, _value) { var ret = { valid: true, message: "" } - if (_value !== "1" && _value !== "0") + if (!(_value === "1" || _value === "0" || _value === 1 || _value === 0)) { ret.valid = false; ret.message = _value + " is not in the correct bool format"; From b0865ea28f507a8238a6cf1b63cd79ed286b4e79 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 30 Jul 2015 10:38:02 +0200 Subject: [PATCH 04/21] ui bug fix --- mix/qml/QBoolTypeView.qml | 10 +++++++--- mix/qml/StructView.qml | 14 ++++++++------ mix/qml/TransactionDialog.qml | 4 ++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/mix/qml/QBoolTypeView.qml b/mix/qml/QBoolTypeView.qml index 21405208a..200b6b405 100644 --- a/mix/qml/QBoolTypeView.qml +++ b/mix/qml/QBoolTypeView.qml @@ -53,12 +53,16 @@ Item for (var k in JSON.parse(boolArray.text)) formattedparam.push(parseInt(format(param[k]))) boolArray.text = JSON.stringify(formattedparam) - value = "" - value = boolArray.text - console.log("gfdg " + value) + } } + function finalize() + { + if (isArray()) + value = boolArray.text + } + function format(value) { value = value === true ? "1" : value diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 9ba29031d..2f55b0a73 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -91,11 +91,6 @@ Column var pname = members[index].name; var vals = value; - item.onValueChanged.connect(function() { - vals[pname] = item.value; - valueChanged(); - }); - item.readOnly = context === "variable"; if (ptype.category === QSolidityType.Address) { @@ -107,7 +102,6 @@ Column item.subType = dec[0]; item.load(); } - console.log("jj" + pname) item.init(); } else if (ptype.category === QSolidityType.Struct && !item.members) @@ -124,9 +118,17 @@ Column item.init(); } + item.onValueChanged.connect(function() { + vals[pname] = item.value; + valueChanged(); + }); + var newWidth = nameLabel.width + typeLabel.width + item.width + 108; if (root.width < newWidth) root.width = newWidth; + + if (item.finalize) + item.finalize() } function getValue() diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 60b8eedc7..a60ea05b3 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -246,7 +246,7 @@ Dialog { functionRect.show() loadFunctions(TransactionHelper.contractFromToken(recipientsAccount.currentValue())) loadParameters(); - //paramScroll.updateView() + paramScroll.updateView() } else { @@ -492,7 +492,7 @@ Dialog { StructView { id: paramScroll - members: paramsModel; + members: paramsModel accounts: senderComboBox.model context: "parameter" Layout.fillWidth: true From 98788b69b685ba723b5c745bac04a8aec82b0253 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 30 Jul 2015 12:13:32 +0200 Subject: [PATCH 05/21] small changes --- mix/qml/QAddressView.qml | 12 ++++++++---- mix/qml/QBoolTypeView.qml | 1 - mix/qml/StructView.qml | 17 ++++++++++++----- mix/qml/TransactionDialog.qml | 4 +--- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index 2b5521124..0a8d09056 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -88,6 +88,7 @@ ColumnLayout function init() { + btnAdd.visible = isArray() textinput.readOnly = readOnly if (isArray() || readOnly) displayInput = true @@ -101,25 +102,28 @@ ColumnLayout if (!trCombobox.visible) { + rowCombobox.visible = false + rowCombobox.height = 0 trCombobox.height = 0 textinput.anchors.top = textinput.parent.top } - if (!readOnly) { + trCombobox.currentIndex = 0 for (var k = 0; k < ctrModel.count; k++) { if (ctrModel.get(k).value === value) { - trCombobox.currentIndex = k; - return; + trCombobox.currentIndex = k + break } } - trCombobox.currentIndex = 0; } if (!isArray()) trCombobox.update() + else if (value === "") + textinput.text = "[]" } function select(address) diff --git a/mix/qml/QBoolTypeView.qml b/mix/qml/QBoolTypeView.qml index 200b6b405..25577b1ea 100644 --- a/mix/qml/QBoolTypeView.qml +++ b/mix/qml/QBoolTypeView.qml @@ -53,7 +53,6 @@ Item for (var k in JSON.parse(boolArray.text)) formattedparam.push(parseInt(format(param[k]))) boolArray.text = JSON.stringify(formattedparam) - } } diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 2f55b0a73..bc3f9499e 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -16,8 +16,10 @@ Column spacing: 0 property int colHeight - onValueChanged: + function clear() { + value = {} + members = [] colHeight = 0 } @@ -119,18 +121,23 @@ Column } item.onValueChanged.connect(function() { - vals[pname] = item.value; - valueChanged(); + syncValue(vals, pname) }); var newWidth = nameLabel.width + typeLabel.width + item.width + 108; if (root.width < newWidth) root.width = newWidth; - if (item.finalize) - item.finalize() + syncValue(vals, pname) } + function syncValue(vals, pname) + { + vals[pname] = item.value; + valueChanged(); + } + + function getValue() { var r = ""; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index a60ea05b3..4c0dff366 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -120,7 +120,6 @@ Dialog { var type = parameter.type; var pname = parameter.name; paramsModel.push({ name: pname, type: type }); - console.log(JSON.stringify(paramsModel)) } function loadParameters() { @@ -153,8 +152,7 @@ Dialog { function initTypeLoader() { - paramScroll.value = {} - paramScroll.members = [] + paramScroll.clear() paramScroll.value = paramValues; paramScroll.members = paramsModel; paramScroll.updateView() From 159343c5dfcfd1729db5732180fc35202f1578e8 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 31 Jul 2015 14:21:47 +0200 Subject: [PATCH 06/21] unchecked Use Private Chain in case cancel --- alethzero/MainWin.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 214dbab1e..f318ce3de 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1043,7 +1043,10 @@ void Main::on_usePrivate_triggered() bool ok; pc = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0)), &ok); if (!ok) + { + ui->usePrivate->setChecked(false); return; + } } setPrivateChain(pc); } From bcb13b21d18d16676808b724fd03b51924e459d3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 31 Jul 2015 15:45:11 +0200 Subject: [PATCH 07/21] ui changes --- mix/qml/BlockChain.qml | 5 ++--- mix/qml/Debugger.qml | 1 - mix/qml/DeployContractStep.qml | 12 +++++++----- mix/qml/DeploymentWorker.qml | 8 +++----- mix/qml/RegisteringStep.qml | 12 +++++++----- mix/qml/StateDialog.qml | 2 +- mix/qml/StateList.qml | 3 ++- mix/qml/TransactionDialog.qml | 9 +++++---- mix/qml/Watchers.qml | 1 - mix/qml/html/codeeditor.js | 2 +- 10 files changed, 28 insertions(+), 27 deletions(-) diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 2c247d282..69d42799c 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -376,7 +376,6 @@ ColumnLayout { block.status = "mined" retBlocks.push(block) } - } if (retBlocks.length === 0) retBlocks.push(projectModel.stateListModel.createEmptyBlock()) @@ -587,7 +586,7 @@ ColumnLayout { itemTr.parameters = _r.parameters itemTr.isContractCreation = itemTr.functionId === itemTr.contractId itemTr.label = _r.label - itemTr.isFunctionCall = itemTr.functionId !== "" + itemTr.isFunctionCall = itemTr.functionId !== "" && itemTr.functionId !== "" itemTr.returned = _r.returned itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) itemTr.sender = _r.sender @@ -617,7 +616,7 @@ ColumnLayout { clientModel.addAccount(ac.secret); for (var k in Object.keys(blockChainPanel.states)) blockChainPanel.states[k].accounts["0x" + ac.address] = "0 wei" // add the account in all the previous state (balance at O) - accountAdded(ac.address, "0") + accountAdded("0x" + ac.address, "0") } Layout.preferredWidth: 100 Layout.preferredHeight: 30 diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 0129f864d..0b833c4de 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -112,7 +112,6 @@ Rectangle { ColumnLayout { id: debugScrollArea anchors.fill: parent - //orientation: Qt.Vertical spacing: 0 RowLayout { diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index bccd1ec14..3bf5c217e 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -19,7 +19,7 @@ Rectangle { id: root property int labelWidth: 150 - + property bool verifyDeploy: true function show() { @@ -37,12 +37,12 @@ Rectangle { } verifyDeployedContract() - deployedAddresses.refresh() - worker.renewCtx() + worker.renewCtx() + verifyDeploy = true worker.pooler.onTriggered.connect(function() { - if (root.visible) + if (root.visible && verifyDeploy) verifyDeployedContract(); }) } @@ -73,10 +73,13 @@ Rectangle { verificationLabel.text = nb if (trLost.length > 0) { + verifyDeploy = false verificationTextArea.visible = true verificationLabel.visible = false + verificationTextArea.text = "" deploymentStepChanged("following transactions are invalidated:") verificationTextArea.text += "\n" + qsTr("Transactions lost") + "\n" + verificationTextArea.textColor = "red" for (var k in trLost) { deploymentStepChanged(trLost[k]) @@ -533,6 +536,5 @@ Rectangle { } } } - } diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index 76e981d8c..cf29e3d25 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -128,7 +128,7 @@ Item params: [], id: req }); - var label = {} + var label = [] for (var k in trHashes) { req++ @@ -142,15 +142,13 @@ Item } TransactionHelper.rpcCall(requests, function (httpRequest, response){ - console.log(response) - var ret = JSON.parse(response) var b = ret[0].result; var trLost = [] for (var k in ret) { - if (ret[k].result === null) - trLost.push(label[ret[k]]) + if (!ret[k].result) + trLost.push(label[ret[k].id]) } callback(parseInt(b, 16), trLost) }); diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index facc09320..5ea83efd8 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -206,7 +206,7 @@ Rectangle { text: qsTr("Ethereum URL") anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter - } + } } Rectangle @@ -252,7 +252,7 @@ Rectangle { Label { id: verificationEthUrl - anchors.verticalCenter: parent.verticalCenter; + anchors.verticalCenter: parent.verticalCenter; anchors.topMargin: 10 font.italic: true font.pointSize: appStyle.absoluteSize(-1) @@ -264,7 +264,7 @@ Rectangle { { anchors.bottom: parent.bottom anchors.bottomMargin: 10 - width: parent.width + width: parent.width function registerHash(gasPrice, callback) { @@ -276,7 +276,7 @@ Rectangle { inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); } if (!worker.stopForInputError(inError)) - { + { NetworkDeploymentCode.registerDapp(ethUrl, gasPrice, function(){ projectModel.applicationUrlEth = applicationUrlEthCtrl.text projectModel.saveProject() @@ -309,7 +309,9 @@ Rectangle { inError.push(qsTr(applicationUrlHttpCtrl.text)); if (!worker.stopForInputError(inError)) { - registerToUrlHint(applicationUrlHttpCtrl.text, gasPrice, function(){ + var url = applicationUrlHttpCtrl.text + url = url.replace("http://", "").replace("https://", "") + registerToUrlHint(url, gasPrice, function(){ projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text projectModel.saveProject() verificationUrl.text = qsTr("waiting verifications") diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 56be75a09..cd19751b6 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -15,7 +15,7 @@ Dialog { width: 630 height: 660 - title: qsTr("Edit State") + title: qsTr("Edit Genesis Parameters") visible: false property alias isDefault: defaultCheckBox.checked diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index e081947e2..b12aa2fb2 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -17,6 +17,7 @@ Dialog { ColumnLayout { anchors.fill: parent + anchors.margins: 10 TableView { id: list Layout.fillHeight: true @@ -57,7 +58,7 @@ Dialog { verticalAlignment: Text.AlignBottom } ToolButton { - text: qsTr("Edit"); + text: qsTr("Edit Genesis"); Layout.fillHeight: true onClicked: list.model.editState(styleData.row); } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 4c0dff366..f0440101b 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -8,6 +8,7 @@ import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper import "js/InputValidator.js" as InputValidator import "js/NetworkDeployment.js" as NetworkDeployment +import "js/QEtherHelper.js" as QEtherHelper import "." Dialog { @@ -54,7 +55,6 @@ Dialog { if (item.sender) senderComboBox.select(item.sender); - trTypeCreate.checked = item.isContractCreation trTypeSend.checked = !item.isFunctionCall trTypeExecute.checked = item.isFunctionCall && !item.isContractCreation @@ -520,7 +520,7 @@ Dialog { Layout.preferredWidth: 350 id: valueField edit: true - displayFormattedValue: false + displayFormattedValue: true displayUnitSelection: true } } @@ -656,11 +656,12 @@ Dialog { Label { id: gasPriceMarket anchors.top: gasPriceLabel.bottom + anchors.topMargin: 10 Component.onCompleted: { NetworkDeployment.gasPrice(function(result) { - gasPriceMarket.text = qsTr("Current market: ") + " " + result + " Wei"; + gasPriceMarket.text = qsTr("Current market: ") + " " + QEtherHelper.createEther(result, QEther.Wei).format() }, function (){}); } } @@ -668,7 +669,7 @@ Dialog { } Ether { - Layout.preferredWidth: 350 + Layout.preferredWidth: 400 id: gasPriceField edit: true displayFormattedValue: false diff --git a/mix/qml/Watchers.qml b/mix/qml/Watchers.qml index 654670d6c..c7c6e8335 100644 --- a/mix/qml/Watchers.qml +++ b/mix/qml/Watchers.qml @@ -13,7 +13,6 @@ import "." Rectangle { color: "#4F4F4F" - radius: 4 property variant tx property variant currentState property variant bc diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 108df5952..68172200f 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -246,7 +246,7 @@ displayGasEstimation = function(show) { var color; var colorIndex = Math.round(step * gasCosts[i].gas); - if (gasCosts[i].isInfinite || colorIndex > colorGradient.length) + if (gasCosts[i].isInfinite || colorIndex >= colorGradient.length) color = colorGradient[colorGradient.length - 1]; else color = colorGradient[colorIndex]; From 862c39c8f48d5d7b825a1f42f28b9e68746b1d94 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 31 Jul 2015 18:28:27 +0200 Subject: [PATCH 08/21] bugfix --- test/libwhisper/whisperTopic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libwhisper/whisperTopic.cpp b/test/libwhisper/whisperTopic.cpp index bf15a14c9..106520221 100644 --- a/test/libwhisper/whisperTopic.cpp +++ b/test/libwhisper/whisperTopic.cpp @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(topic) }); Host host2("Test", NetworkPreferences("127.0.0.1", 30310, false)); - host1.setIdealPeerCount(1); + host2.setIdealPeerCount(1); auto whost2 = host2.registerCapability(new WhisperHost()); host2.start(); From e892152ba8b11e0721923167d5155d46eeeb7a3d Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 31 Jul 2015 19:23:31 +0200 Subject: [PATCH 09/21] Create and output clone contracts. --- libsolidity/Compiler.cpp | 88 +++++++++++++++++++++++++++-------- libsolidity/Compiler.h | 14 ++++++ libsolidity/CompilerStack.cpp | 11 +++++ libsolidity/CompilerStack.h | 6 +++ solc/CommandLineInterface.cpp | 44 +++++++++++++----- 5 files changed, 132 insertions(+), 31 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 6ed6480f2..eadfc204a 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -53,31 +54,45 @@ void Compiler::compileContract(ContractDefinition const& _contract, m_context = CompilerContext(); // clear it just in case { CompilerContext::LocationSetter locationSetterRunTime(m_context, _contract); - CompilerUtils(m_context).initialiseFreeMemoryPointer(); initializeContext(_contract, _contracts); appendFunctionSelector(_contract); - set functions = m_context.getFunctionsWithoutCode(); - while (!functions.empty()) - { - for (Declaration const* function: functions) - { - m_context.setStackOffset(0); - function->accept(*this); - } - functions = m_context.getFunctionsWithoutCode(); - } + appendFunctionsWithoutCode(); } // Swap the runtime context with the creation-time context swap(m_context, m_runtimeContext); CompilerContext::LocationSetter locationSetterCreationTime(m_context, _contract); - CompilerUtils(m_context).initialiseFreeMemoryPointer(); initializeContext(_contract, _contracts); packIntoContractCreator(_contract, m_runtimeContext); if (m_optimize) m_context.optimise(m_optimizeRuns); } +void Compiler::compileClone( + ContractDefinition const& _contract, + map const& _contracts +) +{ + m_context = CompilerContext(); // clear it just in case + initializeContext(_contract, _contracts); + + appendInitAndConstructorCode(_contract); + + //@todo determine largest return size of all runtime functions + eth::AssemblyItem runtimeSub = m_context.addSubroutine(getCloneRuntime()); + solAssert(runtimeSub.data() < numeric_limits::max(), ""); + m_runtimeSub = size_t(runtimeSub.data()); + + // stack contains sub size + m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY; + m_context << u256(0) << eth::Instruction::RETURN; + + appendFunctionsWithoutCode(); + + if (m_optimize) + m_context.optimise(m_optimizeRuns); +} + eth::AssemblyItem Compiler::getFunctionEntryLabel(FunctionDefinition const& _function) const { return m_runtimeContext.getFunctionEntryLabelIfExists(_function); @@ -86,13 +101,14 @@ eth::AssemblyItem Compiler::getFunctionEntryLabel(FunctionDefinition const& _fun void Compiler::initializeContext(ContractDefinition const& _contract, map const& _contracts) { + CompilerUtils(m_context).initialiseFreeMemoryPointer(); m_context.setCompiledContracts(_contracts); m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts()); registerStateVariables(_contract); m_context.resetVisitedNodes(&_contract); } -void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) +void Compiler::appendInitAndConstructorCode(ContractDefinition const& _contract) { // Determine the arguments that are used for the base constructors. std::vector const& bases = _contract.getLinearizedBaseContracts(); @@ -126,22 +142,22 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp appendConstructor(*constructor); else if (auto c = m_context.getNextConstructor(_contract)) appendBaseConstructor(*c); +} + +void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) +{ + appendInitAndConstructorCode(_contract); eth::AssemblyItem runtimeSub = m_context.addSubroutine(_runtimeContext.getAssembly()); solAssert(runtimeSub.data() < numeric_limits::max(), ""); m_runtimeSub = size_t(runtimeSub.data()); + // stack contains sub size m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY; m_context << u256(0) << eth::Instruction::RETURN; // note that we have to include the functions again because of absolute jump labels - set functions = m_context.getFunctionsWithoutCode(); - while (!functions.empty()) - { - for (Declaration const* function: functions) - function->accept(*this); - functions = m_context.getFunctionsWithoutCode(); - } + appendFunctionsWithoutCode(); } void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor) @@ -618,6 +634,20 @@ bool Compiler::visit(PlaceholderStatement const& _placeholderStatement) return true; } +void Compiler::appendFunctionsWithoutCode() +{ + set functions = m_context.getFunctionsWithoutCode(); + while (!functions.empty()) + { + for (Declaration const* function: functions) + { + m_context.setStackOffset(0); + function->accept(*this); + } + functions = m_context.getFunctionsWithoutCode(); + } +} + void Compiler::appendModifierOrFunctionCode() { solAssert(m_currentFunction, ""); @@ -674,3 +704,21 @@ void Compiler::compileExpression(Expression const& _expression, TypePointer cons if (_targetType) CompilerUtils(m_context).convertType(*_expression.getType(), *_targetType); } + +eth::Assembly Compiler::getCloneRuntime() +{ + eth::Assembly a; + a << eth::Instruction::CALLDATASIZE; + a << u256(0) << eth::Instruction::DUP1 << eth::Instruction::CALLDATACOPY; + //@todo adjust for larger return values, make this dynamic. + a << u256(0x20) << u256(0) << eth::Instruction::CALLDATASIZE; + a << u256(0) << eth::Instruction::DUP1; + // this is the address which has to be substituted by the linker. + //@todo implement as special "marker" AssemblyItem. + a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); + a << u256(eth::c_callGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB; + a << eth::Instruction::CALLCODE; + //@todo adjust for larger return values, make this dynamic. + a << u256(0x20) << u256(0) << eth::Instruction::RETURN; + return a; +} diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index ac794f89e..bec2b0641 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -44,6 +44,12 @@ public: void compileContract(ContractDefinition const& _contract, std::map const& _contracts); + /// Compiles a contract that uses CALLCODE to call into a pre-deployed version of the given + /// contract at runtime, but contains the full creation-time code. + void compileClone( + ContractDefinition const& _contract, + std::map const& _contracts + ); bytes getAssembledBytecode() { return m_context.getAssembledBytecode(); } bytes getRuntimeBytecode() { return m_context.getAssembledRuntimeBytecode(m_runtimeSub); } /// @arg _sourceCodes is the map of input files to source code strings @@ -68,6 +74,8 @@ private: /// Adds the code that is run at creation time. Should be run after exchanging the run-time context /// with a new and initialized context. Adds the constructor code. void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext); + /// Appends state variable initialisation and constructor code. + void appendInitAndConstructorCode(ContractDefinition const& _contract); void appendBaseConstructor(FunctionDefinition const& _constructor); void appendConstructor(FunctionDefinition const& _constructor); void appendFunctionSelector(ContractDefinition const& _contract); @@ -103,6 +111,9 @@ private: virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; + /// Repeatedly visits all function which are referenced but which are not compiled yet. + void appendFunctionsWithoutCode(); + /// Appends one layer of function modifier code of the current function, or the function /// body itself if the last modifier was reached. void appendModifierOrFunctionCode(); @@ -110,6 +121,9 @@ private: void appendStackVariableInitialisation(VariableDeclaration const& _variable); void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); + /// @returns the runtime assembly for clone contracts. + static eth::Assembly getCloneRuntime(); + bool const m_optimize; unsigned const m_optimizeRuns; CompilerContext m_context; diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index f056bb9b1..a85738ebd 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -166,7 +166,13 @@ void CompilerStack::compile(bool _optimize, unsigned _runs) compiledContract.bytecode = compiler->getAssembledBytecode(); compiledContract.runtimeBytecode = compiler->getRuntimeBytecode(); compiledContract.compiler = move(compiler); + compiler = make_shared(_optimize, _runs); + compiler->compileContract(*contract, contractBytecode); contractBytecode[compiledContract.contract] = &compiledContract.bytecode; + + Compiler cloneCompiler(_optimize, _runs); + cloneCompiler.compileClone(*contract, contractBytecode); + compiledContract.cloneBytecode = cloneCompiler.getAssembledBytecode(); } } @@ -199,6 +205,11 @@ bytes const& CompilerStack::getRuntimeBytecode(string const& _contractName) cons return getContract(_contractName).runtimeBytecode; } +bytes const& CompilerStack::getCloneBytecode(string const& _contractName) const +{ + return getContract(_contractName).cloneBytecode; +} + dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const { return dev::sha3(getRuntimeBytecode(_contractName)); diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index a7c6ea3ba..735c4d156 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -99,6 +99,11 @@ public: bytes const& getBytecode(std::string const& _contractName = "") const; /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; + /// @returns the bytecode of a contract that uses an already deployed contract via CALLCODE. + /// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to + /// substituted by the actual address. Note that this sequence starts end ends in three X + /// characters but can contain anything in between. + bytes const& getCloneBytecode(std::string const& _contractName = "") const; /// @returns normal contract assembly items eth::AssemblyItems const* getAssemblyItems(std::string const& _contractName = "") const; /// @returns runtime contract assembly items @@ -167,6 +172,7 @@ private: std::shared_ptr compiler; bytes bytecode; bytes runtimeBytecode; + bytes cloneBytecode; std::shared_ptr interfaceHandler; mutable std::unique_ptr interface; mutable std::unique_ptr solidityInterface; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 1b1dbd3eb..e579d8839 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -63,6 +63,7 @@ static string const g_argAsmJsonStr = "asm-json"; static string const g_argAstStr = "ast"; static string const g_argAstJson = "ast-json"; static string const g_argBinaryStr = "binary"; +static string const g_argCloneBinaryStr = "clone-binary"; static string const g_argOpcodesStr = "opcodes"; static string const g_argNatspecDevStr = "natspec-dev"; static string const g_argNatspecUserStr = "natspec-user"; @@ -71,6 +72,7 @@ static string const g_argAddStandard = "add-std"; /// Possible arguments to for --combined-json static set const g_combinedJsonArgs{ "binary", + "clone-binary", "opcodes", "json-abi", "sol-abi", @@ -110,7 +112,8 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args) humanTargetedStdout(_args, g_argAsmStr) || humanTargetedStdout(_args, g_argAsmJsonStr) || humanTargetedStdout(_args, g_argOpcodesStr) || - humanTargetedStdout(_args, g_argBinaryStr); + humanTargetedStdout(_args, g_argBinaryStr) || + humanTargetedStdout(_args, g_argCloneBinaryStr); } static inline bool outputToFile(OutputType type) @@ -140,18 +143,33 @@ static std::istream& operator>>(std::istream& _in, OutputType& io_output) void CommandLineInterface::handleBinary(string const& _contract) { - auto choice = m_args[g_argBinaryStr].as(); - if (outputToStdout(choice)) + if (m_args.count(g_argBinaryStr)) { - cout << "Binary: " << endl; - cout << toHex(m_compiler->getBytecode(_contract)) << endl; + if (outputToStdout(m_args[g_argBinaryStr].as())) + { + cout << "Binary: " << endl; + cout << toHex(m_compiler->getBytecode(_contract)) << endl; + } + if (outputToFile(m_args[g_argBinaryStr].as())) + { + ofstream outFile(_contract + ".binary"); + outFile << toHex(m_compiler->getBytecode(_contract)); + outFile.close(); + } } - - if (outputToFile(choice)) + if (m_args.count(g_argCloneBinaryStr)) { - ofstream outFile(_contract + ".binary"); - outFile << toHex(m_compiler->getBytecode(_contract)); - outFile.close(); + if (outputToStdout(m_args[g_argCloneBinaryStr].as())) + { + cout << "Clone Binary: " << endl; + cout << toHex(m_compiler->getCloneBytecode(_contract)) << endl; + } + if (outputToFile(m_args[g_argCloneBinaryStr].as())) + { + ofstream outFile(_contract + ".clone_binary"); + outFile << toHex(m_compiler->getCloneBytecode(_contract)); + outFile.close(); + } } } @@ -177,7 +195,7 @@ void CommandLineInterface::handleBytecode(string const& _contract) { if (m_args.count(g_argOpcodesStr)) handleOpcode(_contract); - if (m_args.count(g_argBinaryStr)) + if (m_args.count(g_argBinaryStr) || m_args.count(g_argCloneBinaryStr)) handleBinary(_contract); } @@ -329,6 +347,8 @@ bool CommandLineInterface::parseArguments(int argc, char** argv) "Request to output the Opcodes of the contract.") (g_argBinaryStr.c_str(), po::value()->value_name("stdout|file|both"), "Request to output the contract in binary (hexadecimal).") + (g_argCloneBinaryStr.c_str(), po::value()->value_name("stdout|file|both"), + "Request to output the clone contract in binary (hexadecimal).") (g_argAbiStr.c_str(), po::value()->value_name("stdout|file|both"), "Request to output the contract's JSON ABI interface.") (g_argSolAbiStr.c_str(), po::value()->value_name("stdout|file|both"), @@ -490,6 +510,8 @@ void CommandLineInterface::handleCombinedJSON() contractData["json-abi"] = m_compiler->getInterface(contractName); if (requests.count("binary")) contractData["binary"] = toHex(m_compiler->getBytecode(contractName)); + if (requests.count("clone-binary")) + contractData["clone-binary"] = toHex(m_compiler->getCloneBytecode(contractName)); if (requests.count("opcodes")) contractData["opcodes"] = eth::disassemble(m_compiler->getBytecode(contractName)); if (requests.count("asm")) From 5baf03ddfeb2882c0d09297c632a09a92f4c112b Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 31 Jul 2015 19:42:15 +0200 Subject: [PATCH 10/21] Improved invalid-password message for eth. --- eth/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index ad2872dd2..a17e04e9c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1726,7 +1726,7 @@ int main(int argc, char** argv) masterPassword = getPassword("Please enter your MASTER password: "); if (keyManager.load(masterPassword)) break; - cout << "Password invalid. Try again." << endl; + cout << "The password you entered is incorrect. If you have forgotten your password, and you wish to start afresh, manually remove the file: " + getDataDir("ethereum") + "/keys.info" << endl; } } else From a59eab65c9c1ea529010b353de27da6fb5cde546 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 1 Aug 2015 13:49:58 +0100 Subject: [PATCH 11/21] Plugin infrastructure. Initial separation of accounts into plugin. --- alethzero/AllAccounts.cpp | 115 ++++++++++++++++++++++++++++++++ alethzero/AllAccounts.h | 56 ++++++++++++++++ alethzero/AllAccounts.ui | 134 ++++++++++++++++++++++++++++++++++++++ alethzero/CMakeLists.txt | 5 +- alethzero/Main.ui | 92 -------------------------- alethzero/MainFace.cpp | 60 +++++++++++++++++ alethzero/MainFace.h | 86 ++++++++++++++++++++++++ alethzero/MainWin.cpp | 78 +++------------------- alethzero/MainWin.h | 11 ++-- 9 files changed, 468 insertions(+), 169 deletions(-) create mode 100644 alethzero/AllAccounts.cpp create mode 100644 alethzero/AllAccounts.h create mode 100644 alethzero/AllAccounts.ui create mode 100644 alethzero/MainFace.cpp create mode 100644 alethzero/MainFace.h diff --git a/alethzero/AllAccounts.cpp b/alethzero/AllAccounts.cpp new file mode 100644 index 000000000..3e2d5234a --- /dev/null +++ b/alethzero/AllAccounts.cpp @@ -0,0 +1,115 @@ +/* + 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 . +*/ +/** @file AllAccounts.h + * @author Gav Wood + * @date 2015 + */ + +#include "AllAccounts.h" +#include +#include +#include +#include +#include +#include "ui_AllAccounts.h" +using namespace std; +using namespace dev; +using namespace az; +using namespace eth; + +AllAccounts::AllAccounts(MainFace* _m): + Plugin(_m, "AllAccounts"), + m_ui(new Ui::AllAccounts) +{ + m_ui->setupUi(dock()); + + refresh(); +} + +AllAccounts::~AllAccounts() +{ + +} + +// TODO: Introduce interface for MainWin's refreshAccounts() and have it call refresh(). + +void AllAccounts::refresh() +{ + DEV_TIMED_FUNCTION; +#if ETH_FATDB || !ETH_TRUE + cwatch << "refreshAccounts()"; + m_ui->accounts->clear(); + bool showContract = m_ui->showContracts->isChecked(); + bool showBasic = m_ui->showBasic->isChecked(); + bool onlyNamed = m_ui->onlyNamed->isChecked(); + for (auto const& i: ethereum()->addresses()) + { + bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); + if (!((showContract && isContract) || (showBasic && !isContract))) + continue; + string r = render(i); + if (onlyNamed && !(r.find('"') != string::npos || r.substr(0, 2) == "XE")) + continue; + (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), ui->accounts)) + ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); + } +#endif + m_refreshAccounts->setEnabled(false); +} + +void AllAccounts::on_accounts_currentItemChanged() +{ + m_ui->accountInfo->clear(); + if (auto item = m_ui->accounts->currentItem()) + { + auto hba = item->data(Qt::UserRole).toByteArray(); + assert(hba.size() == 20); + auto address = h160((byte const*)hba.data(), h160::ConstructFromPointer); + + stringstream s; + try + { + auto storage = ethereum()->storageAt(address); + for (auto const& i: storage) + s << "@" << showbase << hex << main()->prettyU256(i.first) << "    " << showbase << hex << main()->prettyU256(i.second) << "
"; + s << "

Body Code (" << sha3(ethereum()->codeAt(address)).abridged() << ")

" << disassemble(ethereum()->codeAt(address)); + s << ETH_HTML_DIV(ETH_HTML_MONO) << toHex(ethereum()->codeAt(address)) << ""; + m_ui->accountInfo->appendHtml(QString::fromStdString(s.str())); + } + catch (dev::InvalidTrie) + { + m_ui->accountInfo->appendHtml("Corrupted trie."); + } + ui->accountInfo->moveCursor(QTextCursor::Start); + } +} + +void AllAccounts::on_accounts_doubleClicked() +{ + if (ui->accounts->count()) + { + auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); + auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); + qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray()))); + } +} + +void AllAccounts::on_refreshAccounts_clicked() +{ + refreshAccounts(); +} + diff --git a/alethzero/AllAccounts.h b/alethzero/AllAccounts.h new file mode 100644 index 000000000..910c19344 --- /dev/null +++ b/alethzero/AllAccounts.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 . +*/ +/** @file AllAccounts.h + * @author Gav Wood + * @date 2015 + */ + +#pragma once + +#include +#include +#include "MainFace.h" + +namespace Ui { +class AllAccounts; +} + +namespace dev +{ +namespace az +{ + +class AllAccounts: public Plugin +{ +public: + AllAccounts(MainFace* _m): Plugin(_m, "AllAccounts") {} + ~AllAccounts(); + + void refresh(); + +public slots: + void on_accounts_currentItemChanged(); + void on_accounts_doubleClicked(); + void on_refreshAccounts_clicked(); + +private: + Ui::AllAccounts* m_ui; + QAction* m_refreshAccounts; +}; + +} +} diff --git a/alethzero/AllAccounts.ui b/alethzero/AllAccounts.ui new file mode 100644 index 000000000..ca0ad31bc --- /dev/null +++ b/alethzero/AllAccounts.ui @@ -0,0 +1,134 @@ + + + AllAccounts + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Filter... + + + + + + + Basic + + + true + + + + + + + Contracts + + + true + + + true + + + + + + + Only Named + + + true + + + false + + + + + + + Refresh + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + 0 + 0 + + + + Qt::NoFocus + + + QFrame::NoFrame + + + + + + 2 + 0 + + + + Qt::WheelFocus + + + QFrame::NoFrame + + + true + + + + + + + + + diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 1b1138eab..75576ecc1 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -31,6 +31,9 @@ qt5_wrap_ui(ui_ExportState.h ExportState.ui) qt5_wrap_ui(ui_GetPassword.h GetPassword.ui) qt5_wrap_ui(ui_GasPricing.h GasPricing.ui) +# Extensions +qt5_wrap_ui(ui_AllAccounts.h AllAccounts.ui) + file(GLOB HEADERS "*.h") if (APPLE) @@ -42,7 +45,7 @@ endif () # eth_add_executable is defined in cmake/EthExecutableHelper.cmake eth_add_executable(${EXECUTABLE} ICON alethzero - UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui GasPricing.ui + UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui GasPricing.ui AllAccounts.ui WIN_RESOURCES alethzero.rc ) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b1a93aaab..800c74d56 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -615,98 +615,6 @@ 0 - - - - - - Filter... - - - - - - - Basic - - - true - - - - - - - Contracts - - - true - - - true - - - - - - - Only Named - - - true - - - false - - - - - - - Refresh - - - - - - - - - Qt::Horizontal - - - - - 0 - 0 - - - - Qt::NoFocus - - - QFrame::NoFrame - - - - - - 2 - 0 - - - - Qt::WheelFocus - - - QFrame::NoFrame - - - true - - - - diff --git a/alethzero/MainFace.cpp b/alethzero/MainFace.cpp new file mode 100644 index 000000000..a7ca1f1c7 --- /dev/null +++ b/alethzero/MainFace.cpp @@ -0,0 +1,60 @@ +/* + 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 . +*/ +/** @file MainFace.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "MainFace.h" + +using namespace dev; +using namespace az; + +Plugin::Plugin(MainFace* _f, std::string const& _name): + m_main(_f), + m_name(_name) +{ + _f->adoptPlugin(this); +} + + +QDockWidget* Plugin::dock(Qt::DockWidgetArea _area, QString _title) +{ + if (_title.isEmpty()) + _title = QString::fromStdString(m_name); + if (!m_dock) + { + m_dock = new QDockWidget(_title, m_main); + m_main->addDockWidget(_area, m_dock); + } + return m_dock; +} + +void Plugin::addToDock(Qt::DockWidgetArea _area, QDockWidget* _dockwidget, Qt::Orientation _orientation) +{ + m_main->addDockWidget(_area, m_dock, _orientation); +} + +void Plugin::addAction(QAction* _a) +{ + m_main->addAction(_a); +} + +void MainFace::killPlugins() +{ + m_plugins.clear(); +} diff --git a/alethzero/MainFace.h b/alethzero/MainFace.h new file mode 100644 index 000000000..48ba25901 --- /dev/null +++ b/alethzero/MainFace.h @@ -0,0 +1,86 @@ +/* + 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 . +*/ +/** @file MainFace.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Context.h" + +namespace dev +{ + +namespace web3 { class WebThreeDirect; } +namespace eth { class Client; } +namespace shh { class WhisperHost; } + +namespace az +{ + +class Plugin; + +class MainFace: public QMainWindow, public Context +{ +public: + explicit MainFace(QWidget* _parent = nullptr): QMainWindow(_parent) {} + + void adoptPlugin(Plugin* _p) { m_plugins.insert(_p->name(), std::shared_ptr(_p)); } + void killPlugins(); + + // TODO: tidy - all should be references that throw if module unavailable. + // TODO: provide a set of available web3 modules. + virtual dev::web3::WebThreeDirect* web3() const = 0; + virtual dev::eth::Client* ethereum() const = 0; + virtual std::shared_ptr whisper() const = 0; + +private: + std::unordered_map> m_plugins; +}; + +class Plugin +{ +public: + Plugin(MainFace* _f, std::string const& _name); + virtual ~Plugin() {} + + std::string const& name() const { return m_name; } + + dev::web3::WebThreeDirect* web3() const { return m_main->web3(); } + dev::eth::Client* ethereum() const { return m_main->ethereum(); } + std::shared_ptr whisper() const { return m_main->whisper(); } + MainFace* main() { return m_main; } + QDockWidget* dock(Qt::DockWidgetArea _area = Qt::RightDockWidgetArea, QString _title = QString()); + void addToDock(Qt::DockWidgetArea _area, QDockWidget* _dockwidget, Qt::Orientation _orientation); + void addAction(QAction* _a); + +private: + MainFace* m_main; + std::string m_name; + QDockWidget* m_dock; +}; + +} + +} diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f7f0f0fa5..863190d9d 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -74,13 +74,15 @@ #include "DappHost.h" #include "WebPage.h" #include "ExportState.h" +#include "AllAccounts.h" #include "ui_Main.h" #include "ui_GetPassword.h" #include "ui_GasPricing.h" using namespace std; using namespace dev; -using namespace dev::p2p; -using namespace dev::eth; +using namespace az; +using namespace p2p; +using namespace eth; namespace js = json_spirit; string Main::fromRaw(h256 _n, unsigned* _inc) @@ -126,8 +128,8 @@ static QString filterOutTerminal(QString _s) return _s.replace(QRegExp("\x1b\\[(\\d;)?\\d+m"), ""); } -Main::Main(QWidget *parent) : - QMainWindow(parent), +Main::Main(QWidget* _parent): + MainFace(_parent), ui(new Ui::Main), m_transact(nullptr), m_dappLoader(nullptr), @@ -302,6 +304,8 @@ Main::Main(QWidget *parent) : s.setValue("splashMessage", false); } } + + new dev::az::AllAccounts(this); } Main::~Main() @@ -1283,35 +1287,6 @@ void Main::on_onlyNamed_toggled() ui->refreshAccounts->setEnabled(true); } -void Main::on_refreshAccounts_clicked() -{ - refreshAccounts(); -} - -void Main::refreshAccounts() -{ - DEV_TIMED_FUNCTION; -#if ETH_FATDB || !ETH_TRUE - cwatch << "refreshAccounts()"; - ui->accounts->clear(); - bool showContract = ui->showContracts->isChecked(); - bool showBasic = ui->showBasic->isChecked(); - bool onlyNamed = ui->onlyNamed->isChecked(); - for (auto const& i: ethereum()->addresses()) - { - bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); - if (!((showContract && isContract) || (showBasic && !isContract))) - continue; - string r = render(i); - if (onlyNamed && !(r.find('"') != string::npos || r.substr(0, 2) == "XE")) - continue; - (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), ui->accounts)) - ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); - } -#endif - ui->refreshAccounts->setEnabled(false); -} - void Main::refreshBlockCount() { auto d = ethereum()->blockChain().details(); @@ -1919,33 +1894,6 @@ void Main::debugDumpState(int _add) } } -void Main::on_accounts_currentItemChanged() -{ - ui->accountInfo->clear(); - if (auto item = ui->accounts->currentItem()) - { - auto hba = item->data(Qt::UserRole).toByteArray(); - assert(hba.size() == 20); - auto address = h160((byte const*)hba.data(), h160::ConstructFromPointer); - - stringstream s; - try - { - auto storage = ethereum()->storageAt(address); - for (auto const& i: storage) - s << "@" << showbase << hex << prettyU256(i.first) << "    " << showbase << hex << prettyU256(i.second) << "
"; - s << "

Body Code (" << sha3(ethereum()->codeAt(address)).abridged() << ")

" << disassemble(ethereum()->codeAt(address)); - s << ETH_HTML_DIV(ETH_HTML_MONO) << toHex(ethereum()->codeAt(address)) << ""; - ui->accountInfo->appendHtml(QString::fromStdString(s.str())); - } - catch (dev::InvalidTrie) - { - ui->accountInfo->appendHtml("Corrupted trie."); - } - ui->accountInfo->moveCursor(QTextCursor::Start); - } -} - void Main::on_idealPeers_valueChanged(int) { m_webThree->setIdealPeerCount(ui->idealPeers->value()); @@ -1964,16 +1912,6 @@ void Main::on_ourAccounts_doubleClicked() m_logHistory.clear(); }*/ -void Main::on_accounts_doubleClicked() -{ - if (ui->accounts->count()) - { - auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); - auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); - qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray()))); - } -} - static shh::Topics topicFromText(QString _s) { shh::BuildTopic ret; diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 307cc1533..4e13ad208 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -42,6 +42,7 @@ #include "Transact.h" #include "NatspecHandler.h" #include "Connect.h" +#include "MainFace.h" class QListWidgetItem; class QActionGroup; @@ -69,7 +70,7 @@ using WatchHandler = std::function; QString contentsOfQResource(std::string const& res); -class Main: public QMainWindow, public Context +class Main: public dev::az::MainFace { Q_OBJECT @@ -77,9 +78,9 @@ public: explicit Main(QWidget *parent = 0); ~Main(); - dev::WebThreeDirect* web3() const { return m_webThree.get(); } - dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } - std::shared_ptr whisper() const { return m_webThree->whisper(); } + dev::WebThreeDirect* web3() const override { return m_webThree.get(); } + dev::eth::Client* ethereum() const override { return m_webThree->ethereum(); } + std::shared_ptr whisper() const override { return m_webThree->whisper(); } bool confirm() const; NatSpecFace* natSpec() { return &m_natSpecDB; } @@ -159,8 +160,6 @@ private slots: // Stuff concerning the blocks/transactions/accounts panels void on_ourAccounts_itemClicked(QListWidgetItem* _i); void on_ourAccounts_doubleClicked(); - void on_accounts_doubleClicked(); - void on_accounts_currentItemChanged(); void on_transactionQueue_currentItemChanged(); void on_blockChainFilter_textChanged(); void on_blocks_currentItemChanged(); From 602cc0458dd88f5f862274161fa305d6a393ce1e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 2 Aug 2015 13:38:01 +0100 Subject: [PATCH 12/21] Initial draft of AllAccounts plugin. --- alethzero/AllAccounts.cpp | 19 +++++++++++-------- alethzero/AllAccounts.h | 16 ++++++++++++---- alethzero/MainFace.cpp | 6 ++++++ alethzero/MainFace.h | 4 ++++ alethzero/MainWin.cpp | 24 +----------------------- alethzero/MainWin.h | 7 ------- 6 files changed, 34 insertions(+), 42 deletions(-) diff --git a/alethzero/AllAccounts.cpp b/alethzero/AllAccounts.cpp index 3e2d5234a..d93cd1322 100644 --- a/alethzero/AllAccounts.cpp +++ b/alethzero/AllAccounts.cpp @@ -36,16 +36,19 @@ AllAccounts::AllAccounts(MainFace* _m): m_ui(new Ui::AllAccounts) { m_ui->setupUi(dock()); - + installWatches(); refresh(); } AllAccounts::~AllAccounts() { - } -// TODO: Introduce interface for MainWin's refreshAccounts() and have it call refresh(). +void AllAccounts::installWatches() +{ + installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); + installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); +} void AllAccounts::refresh() { @@ -71,6 +74,11 @@ void AllAccounts::refresh() m_refreshAccounts->setEnabled(false); } +void AllAccounts::onAllChange() +{ + ui->refreshAccounts->setEnabled(true); +} + void AllAccounts::on_accounts_currentItemChanged() { m_ui->accountInfo->clear(); @@ -108,8 +116,3 @@ void AllAccounts::on_accounts_doubleClicked() } } -void AllAccounts::on_refreshAccounts_clicked() -{ - refreshAccounts(); -} - diff --git a/alethzero/AllAccounts.h b/alethzero/AllAccounts.h index 910c19344..e9ded1999 100644 --- a/alethzero/AllAccounts.h +++ b/alethzero/AllAccounts.h @@ -40,14 +40,22 @@ public: AllAccounts(MainFace* _m): Plugin(_m, "AllAccounts") {} ~AllAccounts(); - void refresh(); - -public slots: +private slots: void on_accounts_currentItemChanged(); void on_accounts_doubleClicked(); - void on_refreshAccounts_clicked(); + void on_refreshAccounts_clicked() { refresh(); } + + void on_accountsFilter_textChanged() { onAllChange(); } + void on_showBasic_toggled() { onAllChange(); } + void on_showContracts_toggled() { onAllChange(); } + void on_onlyNamed_toggled() { onAllChange(); } private: + void onAllChange(); + + void installWatches(); + void refresh(); + Ui::AllAccounts* m_ui; QAction* m_refreshAccounts; }; diff --git a/alethzero/MainFace.cpp b/alethzero/MainFace.cpp index a7ca1f1c7..97a615008 100644 --- a/alethzero/MainFace.cpp +++ b/alethzero/MainFace.cpp @@ -58,3 +58,9 @@ void MainFace::killPlugins() { m_plugins.clear(); } + +void MainFace::allChange() +{ + for (auto const& p: m_plugins) + p.second->onAllChange(); +} diff --git a/alethzero/MainFace.h b/alethzero/MainFace.h index 48ba25901..2104ea05b 100644 --- a/alethzero/MainFace.h +++ b/alethzero/MainFace.h @@ -49,6 +49,8 @@ public: void adoptPlugin(Plugin* _p) { m_plugins.insert(_p->name(), std::shared_ptr(_p)); } void killPlugins(); + void allChange(); + // TODO: tidy - all should be references that throw if module unavailable. // TODO: provide a set of available web3 modules. virtual dev::web3::WebThreeDirect* web3() const = 0; @@ -75,6 +77,8 @@ public: void addToDock(Qt::DockWidgetArea _area, QDockWidget* _dockwidget, Qt::Orientation _orientation); void addAction(QAction* _a); + virtual void onAllChange() {} + private: MainFace* m_main; std::string m_name; diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 863190d9d..72271bcef 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -526,7 +526,6 @@ void Main::onNewBlock() // update blockchain dependent views. refreshBlockCount(); refreshBlockChain(); - ui->refreshAccounts->setEnabled(true); // We must update balances since we can't filter updates to basic accounts. refreshBalances(); @@ -538,7 +537,6 @@ void Main::onNewPending() // update any pending-transaction dependent views. refreshPending(); - ui->refreshAccounts->setEnabled(true); } void Main::on_forceMining_triggered() @@ -1241,8 +1239,8 @@ void Main::refreshAll() refreshBlockChain(); refreshBlockCount(); refreshPending(); - ui->refreshAccounts->setEnabled(true); refreshBalances(); + allChange(); } void Main::refreshPending() @@ -1267,26 +1265,6 @@ void Main::refreshPending() } } -void Main::on_accountsFilter_textChanged() -{ - ui->refreshAccounts->setEnabled(true); -} - -void Main::on_showBasic_toggled() -{ - ui->refreshAccounts->setEnabled(true); -} - -void Main::on_showContracts_toggled() -{ - ui->refreshAccounts->setEnabled(true); -} - -void Main::on_onlyNamed_toggled() -{ - ui->refreshAccounts->setEnabled(true); -} - void Main::refreshBlockCount() { auto d = ethereum()->blockChain().details(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 4e13ad208..f1e11cea6 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -145,13 +145,6 @@ private slots: void on_claimPresale_triggered(); void on_exportKey_triggered(); - // Account pane - void on_accountsFilter_textChanged(); - void on_showBasic_toggled(); - void on_showContracts_toggled(); - void on_onlyNamed_toggled(); - void on_refreshAccounts_clicked(); - // Tools void on_newTransaction_triggered(); void on_loadJS_triggered(); From 380b3a82049788a649336e8f391729c065237af2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 2 Aug 2015 13:54:57 +0100 Subject: [PATCH 13/21] Build fixes for plugin stuff. --- alethzero/AllAccounts.cpp | 17 +++++++++-------- alethzero/AllAccounts.h | 2 +- alethzero/MainFace.cpp | 10 +++++++--- alethzero/MainFace.h | 17 ++++++++++++----- alethzero/MainWin.cpp | 2 +- alethzero/MainWin.h | 6 ++---- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/alethzero/AllAccounts.cpp b/alethzero/AllAccounts.cpp index d93cd1322..fcb673775 100644 --- a/alethzero/AllAccounts.cpp +++ b/alethzero/AllAccounts.cpp @@ -21,6 +21,7 @@ #include "AllAccounts.h" #include +#include #include #include #include @@ -46,8 +47,8 @@ AllAccounts::~AllAccounts() void AllAccounts::installWatches() { - installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); - installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); + main()->installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); + main()->installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); } void AllAccounts::refresh() @@ -64,10 +65,10 @@ void AllAccounts::refresh() bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); if (!((showContract && isContract) || (showBasic && !isContract))) continue; - string r = render(i); + string r = static_cast(main())->render(i); if (onlyNamed && !(r.find('"') != string::npos || r.substr(0, 2) == "XE")) continue; - (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), ui->accounts)) + (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), m_ui->accounts)) ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); } #endif @@ -76,7 +77,7 @@ void AllAccounts::refresh() void AllAccounts::onAllChange() { - ui->refreshAccounts->setEnabled(true); + m_ui->refreshAccounts->setEnabled(true); } void AllAccounts::on_accounts_currentItemChanged() @@ -102,15 +103,15 @@ void AllAccounts::on_accounts_currentItemChanged() { m_ui->accountInfo->appendHtml("Corrupted trie."); } - ui->accountInfo->moveCursor(QTextCursor::Start); + m_ui->accountInfo->moveCursor(QTextCursor::Start); } } void AllAccounts::on_accounts_doubleClicked() { - if (ui->accounts->count()) + if (m_ui->accounts->count()) { - auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); + auto hba = m_ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray()))); } diff --git a/alethzero/AllAccounts.h b/alethzero/AllAccounts.h index e9ded1999..72f97d882 100644 --- a/alethzero/AllAccounts.h +++ b/alethzero/AllAccounts.h @@ -37,7 +37,7 @@ namespace az class AllAccounts: public Plugin { public: - AllAccounts(MainFace* _m): Plugin(_m, "AllAccounts") {} + AllAccounts(MainFace* _m); ~AllAccounts(); private slots: diff --git a/alethzero/MainFace.cpp b/alethzero/MainFace.cpp index 97a615008..45669626b 100644 --- a/alethzero/MainFace.cpp +++ b/alethzero/MainFace.cpp @@ -20,7 +20,7 @@ */ #include "MainFace.h" - +using namespace std; using namespace dev; using namespace az; @@ -31,7 +31,6 @@ Plugin::Plugin(MainFace* _f, std::string const& _name): _f->adoptPlugin(this); } - QDockWidget* Plugin::dock(Qt::DockWidgetArea _area, QString _title) { if (_title.isEmpty()) @@ -46,7 +45,7 @@ QDockWidget* Plugin::dock(Qt::DockWidgetArea _area, QString _title) void Plugin::addToDock(Qt::DockWidgetArea _area, QDockWidget* _dockwidget, Qt::Orientation _orientation) { - m_main->addDockWidget(_area, m_dock, _orientation); + m_main->addDockWidget(_area, _dockwidget, _orientation); } void Plugin::addAction(QAction* _a) @@ -54,6 +53,11 @@ void Plugin::addAction(QAction* _a) m_main->addAction(_a); } +void MainFace::adoptPlugin(Plugin* _p) +{ + m_plugins[_p->name()] = shared_ptr(_p); +} + void MainFace::killPlugins() { m_plugins.clear(); diff --git a/alethzero/MainFace.h b/alethzero/MainFace.h index 2104ea05b..c5ea23798 100644 --- a/alethzero/MainFace.h +++ b/alethzero/MainFace.h @@ -24,16 +24,18 @@ #include #include #include +#include #include #include #include +#include #include "Context.h" namespace dev { -namespace web3 { class WebThreeDirect; } -namespace eth { class Client; } +class WebThreeDirect; +namespace eth { class Client; class LogFilter; } namespace shh { class WhisperHost; } namespace az @@ -41,22 +43,27 @@ namespace az class Plugin; +using WatchHandler = std::function; + class MainFace: public QMainWindow, public Context { public: explicit MainFace(QWidget* _parent = nullptr): QMainWindow(_parent) {} - void adoptPlugin(Plugin* _p) { m_plugins.insert(_p->name(), std::shared_ptr(_p)); } + void adoptPlugin(Plugin* _p); void killPlugins(); void allChange(); // TODO: tidy - all should be references that throw if module unavailable. // TODO: provide a set of available web3 modules. - virtual dev::web3::WebThreeDirect* web3() const = 0; + virtual dev::WebThreeDirect* web3() const = 0; virtual dev::eth::Client* ethereum() const = 0; virtual std::shared_ptr whisper() const = 0; + virtual unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) = 0; + virtual unsigned installWatch(dev::h256 const& _tf, WatchHandler const& _f) = 0; + private: std::unordered_map> m_plugins; }; @@ -69,7 +76,7 @@ public: std::string const& name() const { return m_name; } - dev::web3::WebThreeDirect* web3() const { return m_main->web3(); } + dev::WebThreeDirect* web3() const { return m_main->web3(); } dev::eth::Client* ethereum() const { return m_main->ethereum(); } std::shared_ptr whisper() const { return m_main->whisper(); } MainFace* main() { return m_main; } diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 72271bcef..3b28cc7b3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -418,7 +418,7 @@ unsigned Main::installWatch(LogFilter const& _tf, WatchHandler const& _f) return ret; } -unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f) +unsigned Main::installWatch(h256 const& _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf, Reaping::Manual); m_handlers[ret] = _f; diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index f1e11cea6..74352ba9e 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -26,7 +26,6 @@ #endif #include - #include #include #include @@ -132,7 +131,6 @@ private slots: // View void on_refresh_triggered(); void on_showAll_triggered() { refreshBlockChain(); } - void on_showAllAccounts_triggered() { refreshAccounts(); } void on_preview_triggered(); // Account management @@ -221,8 +219,8 @@ private: void setPrivateChain(QString const& _private, bool _forceConfigure = false); - unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f); - unsigned installWatch(dev::h256 _tf, WatchHandler const& _f); + unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) override; + unsigned installWatch(dev::h256 const& _tf, WatchHandler const& _f) override; void uninstallWatch(unsigned _w); void keysChanged(); From c4f3c3683f0c0a5e9a9be3234c95776b7a4ada44 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 2 Aug 2015 14:45:45 +0100 Subject: [PATCH 14/21] Final bugs squished for plugin system & AllAccounts. --- alethzero/AllAccounts.cpp | 13 +++++++++++-- alethzero/AllAccounts.h | 16 +++++----------- alethzero/MainFace.cpp | 1 + alethzero/MainFace.h | 4 ++-- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/alethzero/AllAccounts.cpp b/alethzero/AllAccounts.cpp index fcb673775..71c96cc62 100644 --- a/alethzero/AllAccounts.cpp +++ b/alethzero/AllAccounts.cpp @@ -36,9 +36,18 @@ AllAccounts::AllAccounts(MainFace* _m): Plugin(_m, "AllAccounts"), m_ui(new Ui::AllAccounts) { - m_ui->setupUi(dock()); + dock(Qt::RightDockWidgetArea, "All Accounts")->setWidget(new QWidget()); + m_ui->setupUi(dock()->widget()); installWatches(); refresh(); + + connect(m_ui->accounts, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(on_accounts_currentItemChanged())); + connect(m_ui->accounts, SIGNAL(doubleClicked(QModelIndex)), SLOT(on_accounts_doubleClicked())); + connect(m_ui->refreshAccounts, SIGNAL(clicked()), SLOT(refresh())); + connect(m_ui->accountsFilter, SIGNAL(textChanged(QString)), SLOT(onAllChange())); + connect(m_ui->showBasic, SIGNAL(toggled(bool)), SLOT(onAllChange())); + connect(m_ui->showContracts, SIGNAL(toggled(bool)), SLOT(onAllChange())); + connect(m_ui->onlyNamed, SIGNAL(toggled(bool)), SLOT(onAllChange())); } AllAccounts::~AllAccounts() @@ -72,7 +81,7 @@ void AllAccounts::refresh() ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); } #endif - m_refreshAccounts->setEnabled(false); + m_ui->refreshAccounts->setEnabled(false); } void AllAccounts::onAllChange() diff --git a/alethzero/AllAccounts.h b/alethzero/AllAccounts.h index 72f97d882..ee3f3a15d 100644 --- a/alethzero/AllAccounts.h +++ b/alethzero/AllAccounts.h @@ -34,8 +34,10 @@ namespace dev namespace az { -class AllAccounts: public Plugin +class AllAccounts: public QObject, public Plugin { + Q_OBJECT + public: AllAccounts(MainFace* _m); ~AllAccounts(); @@ -43,21 +45,13 @@ public: private slots: void on_accounts_currentItemChanged(); void on_accounts_doubleClicked(); - void on_refreshAccounts_clicked() { refresh(); } - - void on_accountsFilter_textChanged() { onAllChange(); } - void on_showBasic_toggled() { onAllChange(); } - void on_showContracts_toggled() { onAllChange(); } - void on_onlyNamed_toggled() { onAllChange(); } -private: void onAllChange(); - - void installWatches(); void refresh(); +private: + void installWatches(); Ui::AllAccounts* m_ui; - QAction* m_refreshAccounts; }; } diff --git a/alethzero/MainFace.cpp b/alethzero/MainFace.cpp index 45669626b..82c76563a 100644 --- a/alethzero/MainFace.cpp +++ b/alethzero/MainFace.cpp @@ -39,6 +39,7 @@ QDockWidget* Plugin::dock(Qt::DockWidgetArea _area, QString _title) { m_dock = new QDockWidget(_title, m_main); m_main->addDockWidget(_area, m_dock); + m_dock->setFeatures(QDockWidget::AllDockWidgetFeatures | QDockWidget::DockWidgetVerticalTitleBar); } return m_dock; } diff --git a/alethzero/MainFace.h b/alethzero/MainFace.h index c5ea23798..f6bf5b75a 100644 --- a/alethzero/MainFace.h +++ b/alethzero/MainFace.h @@ -87,9 +87,9 @@ public: virtual void onAllChange() {} private: - MainFace* m_main; + MainFace* m_main = nullptr; std::string m_name; - QDockWidget* m_dock; + QDockWidget* m_dock = nullptr; }; } From 3029a3c221af3e3165b851a9469ab75c21dfe996 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 3 Aug 2015 06:15:25 +0200 Subject: [PATCH 15/21] nonce fix --- libdevcrypto/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index e7304f3f9..c073fbf30 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -367,7 +367,7 @@ Secret Nonce::next() { initialiseIfNeeded(); m_value = sha3(m_value); - return m_value; + return sha3(m_value); } void Nonce::resetInternal() From bc5e44c51ab7e3c4591db08241f5f9214d36eb35 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 3 Aug 2015 06:55:43 +0200 Subject: [PATCH 16/21] Remove nonce use in kdf used by cryptopp signing. Update doc of Nonce class. --- libdevcrypto/Common.cpp | 2 +- libdevcrypto/Common.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index c073fbf30..b0db3ea4f 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -300,7 +300,7 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) { // H(H(r||k)^h) h256 s; - sha3mac(Nonce::get().ref(), _priv.ref(), s.ref()); + sha3mac(Secret::random().ref(), _priv.ref(), s.ref()); s ^= _hash; sha3(s.ref(), s.ref()); diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 426c9cc3d..af25836a9 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -189,6 +189,12 @@ h256 kdf(Secret const& _priv, h256 const& _hash); /** * @brief Generator for nonce material. + *The Nonce class should only be used when a non-repeating nonce + * is required and, in its current form, not recommended for signatures. + * This is primarily because the key-material for signatures is + * encrypted on disk whereas the seed for Nonce is not. + * Thus, Nonce's primary intended use at this time is for networking + * where the key is also stored in plaintext. */ class Nonce { From 8ce1ed28b659566b6e0bc1cf4ea997a094d6b86d Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 3 Aug 2015 13:55:15 +0200 Subject: [PATCH 17/21] -d command line option supported in AlethZero --- alethzero/MainWin.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 877d393f6..dda627aa4 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -136,6 +136,7 @@ Main::Main(QWidget *parent) : QtWebEngine::initialize(); setWindowFlags(Qt::Window); ui->setupUi(this); + std::string dbPath = getDataDir(); for (int i = 1; i < qApp->arguments().size(); ++i) { @@ -146,6 +147,8 @@ Main::Main(QWidget *parent) : resetNetwork(eth::Network::Olympic); else if (arg == "--genesis-json" && i + 1 < qApp->arguments().size()) CanonBlockChain::setGenesis(contentsString(qApp->arguments()[++i].toStdString())); + else if ((arg == "--db-path" || arg == "-d") && i + 1 < qApp->arguments().size()) + dbPath = qApp->arguments()[++i].toStdString(); } if (c_network == eth::Network::Olympic) @@ -200,8 +203,8 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - if (!dev::contents(getDataDir() + "/genesis.json").empty()) - CanonBlockChain::setGenesis(contentsString(getDataDir() + "/genesis.json")); + if (!dev::contents(dbPath + "/genesis.json").empty()) + CanonBlockChain::setGenesis(contentsString(dbPath + "/genesis.json")); cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); @@ -226,7 +229,7 @@ Main::Main(QWidget *parent) : QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); - m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath, WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); From 35d4c15ebecb6e4dd06c3f0f46966d393da4f7d1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 3 Aug 2015 15:23:28 +0200 Subject: [PATCH 18/21] get home dir even when no env available on linux --- libdevcore/FileSystem.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libdevcore/FileSystem.cpp b/libdevcore/FileSystem.cpp index dfda891f5..5e19ab099 100644 --- a/libdevcore/FileSystem.cpp +++ b/libdevcore/FileSystem.cpp @@ -27,7 +27,7 @@ #if defined(_WIN32) #include -#elif defined(__APPLE__) +#else #include #include #include @@ -56,14 +56,12 @@ std::string dev::getDataDir(std::string _prefix) #else boost::filesystem::path dataDirPath; char const* homeDir = getenv("HOME"); -#if defined(__APPLE__) if (!homeDir || strlen(homeDir) == 0) { struct passwd* pwd = getpwuid(getuid()); if (pwd) homeDir = pwd->pw_dir; } -#endif if (!homeDir || strlen(homeDir) == 0) dataDirPath = boost::filesystem::path("/"); From 056180fb24ced86125a35786633a3e897f51a500 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 3 Aug 2015 18:09:39 +0200 Subject: [PATCH 19/21] strings as mapping keys. --- libsolidity/AST.cpp | 3 +- libsolidity/ExpressionCompiler.cpp | 35 +++++++++++++++++------ libsolidity/Types.cpp | 2 ++ test/libsolidity/SolidityEndToEndTest.cpp | 33 +++++++++++++++++++++ 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index ee6e52250..05e2d52e8 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -784,8 +784,7 @@ void Expression::expectType(Type const& _expectedType) " is not implicitly convertible to expected type " + _expectedType.toString() + "." - ) - ); + )); } void Expression::requireLValue() diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 786d386d9..f27cf5fe5 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -85,6 +85,10 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& if (auto mappingType = dynamic_cast(returnType.get())) { solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); + solAssert( + !paramTypes[i]->isDynamicallySized(), + "Accessors for mapping with dynamically-sized keys not yet implemented." + ); // pop offset m_context << eth::Instruction::POP; // move storage offset to memory. @@ -803,15 +807,30 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) if (baseType.getCategory() == Type::Category::Mapping) { // stack: storage_base_ref - Type const& keyType = *dynamic_cast(baseType).getKeyType(); - m_context << u256(0); // memory position + auto const& mapping = dynamic_cast(baseType); + Type const& keyType = *mapping.getKeyType(); solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); - solAssert(keyType.getCalldataEncodedSize() <= 0x20, "Dynamic keys not yet implemented."); - appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); - m_context << eth::Instruction::SWAP1; - solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); - utils().storeInMemoryDynamic(IntegerType(256)); - m_context << u256(0) << eth::Instruction::SHA3; + if (keyType.isDynamicallySized()) + { + _indexAccess.getIndexExpression()->accept(*this); + utils().fetchFreeMemoryPointer(); + // stack: base index mem + // note: the following operations must not allocate memory! + utils().encodeToMemory(TypePointers{mapping.getKeyType()}, TypePointers(), false, true); + m_context << eth::Instruction::SWAP1; + utils().storeInMemoryDynamic(IntegerType(256)); + utils().toSizeAfterFreeMemoryPointer(); + } + else + { + m_context << u256(0); // memory position + appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); + m_context << eth::Instruction::SWAP1; + solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); + utils().storeInMemoryDynamic(IntegerType(256)); + m_context << u256(0); + } + m_context << eth::Instruction::SHA3; m_context << u256(0); setLValueToStorageItem(_indexAccess); } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index d85c0511f..89ff2134f 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -179,6 +179,8 @@ TypePointer Type::fromMapping(ElementaryTypeName& _keyType, TypeName& _valueType BOOST_THROW_EXCEPTION(_valueType.createTypeError("Invalid type name.")); // Convert value type to storage reference. valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType); + // Convert key type to memory. + keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType); return make_shared(keyType, valueType); } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d44545145..fc1d2eab8 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -5099,6 +5099,39 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0))); } +BOOST_AUTO_TEST_CASE(string_as_mapping_key) +{ + char const* sourceCode = R"( + contract Test { + mapping(string => uint) data; + function set(string _s, uint _v) { data[_s] = _v; } + function get(string _s) returns (uint) { return data[_s]; } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + vector strings{ + "Hello, World!", + "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", + "", + "1" + }; + for (unsigned i = 0; i < strings.size(); i++) + BOOST_CHECK(callContractFunction( + "set(string,uint256)", + u256(0x40), + u256(7 + i), + u256(strings[i].size()), + strings[i] + ) == encodeArgs()); + for (unsigned i = 0; i < strings.size(); i++) + BOOST_CHECK(callContractFunction( + "get(string)", + u256(0x20), + u256(strings[i].size()), + strings[i] + ) == encodeArgs(u256(7 + i))); +} + BOOST_AUTO_TEST_SUITE_END() } From 88488dfdb4a92507a680bbd68605ce7875b08513 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 3 Aug 2015 18:27:33 +0200 Subject: [PATCH 20/21] Brace style, windows build fix. --- alethzero/AllAccounts.h | 3 ++- alethzero/MainWin.h | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/alethzero/AllAccounts.h b/alethzero/AllAccounts.h index ee3f3a15d..7104a6d70 100644 --- a/alethzero/AllAccounts.h +++ b/alethzero/AllAccounts.h @@ -25,7 +25,8 @@ #include #include "MainFace.h" -namespace Ui { +namespace Ui +{ class AllAccounts; } diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 74352ba9e..918ff3ef4 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -65,8 +65,6 @@ class DappLoader; class DappHost; struct Dapp; -using WatchHandler = std::function; - QString contentsOfQResource(std::string const& res); class Main: public dev::az::MainFace @@ -219,8 +217,8 @@ private: void setPrivateChain(QString const& _private, bool _forceConfigure = false); - unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) override; - unsigned installWatch(dev::h256 const& _tf, WatchHandler const& _f) override; + unsigned installWatch(dev::eth::LogFilter const& _tf, dev::az::WatchHandler const& _f) override; + unsigned installWatch(dev::h256 const& _tf, dev::az::WatchHandler const& _f) override; void uninstallWatch(unsigned _w); void keysChanged(); @@ -256,7 +254,7 @@ private: std::unique_ptr m_webThree; - std::map m_handlers; + std::map m_handlers; unsigned m_nameRegFilter = (unsigned)-1; unsigned m_currenciesFilter = (unsigned)-1; unsigned m_balancesFilter = (unsigned)-1; From 36fb64a7d4b8296ec7c1441fc4657a5fa276138d Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Aug 2015 11:12:44 +0200 Subject: [PATCH 21/21] Version 0.1.1 --- libsolidity/Version.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/Version.cpp b/libsolidity/Version.cpp index 971fb334b..75a0dd256 100644 --- a/libsolidity/Version.cpp +++ b/libsolidity/Version.cpp @@ -29,7 +29,7 @@ using namespace dev; using namespace dev::solidity; using namespace std; -char const* dev::solidity::VersionNumber = "0.1.0"; +char const* dev::solidity::VersionNumber = "0.1.1"; extern string const dev::solidity::VersionString = string(dev::solidity::VersionNumber) + "-" +