From e329364af4eff20f1ddee47a94ea54cff25067f3 Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Fri, 20 Mar 2015 01:46:39 +0330 Subject: [PATCH 01/50] Adding StatusComboBox --- mix/qml/StatesComboBox.qml | 185 ++++++++++++++++++++++++++++++++++++ mix/qml/TransactionLog.qml | 21 +++- mix/qml/img/edit_combox.png | Bin 0 -> 406 bytes mix/res.qrc | 2 + 4 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 mix/qml/StatesComboBox.qml create mode 100644 mix/qml/img/edit_combox.png diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml new file mode 100644 index 000000000..c89df5de5 --- /dev/null +++ b/mix/qml/StatesComboBox.qml @@ -0,0 +1,185 @@ +/* + 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 StatesComboBox.qml + * @author Ali Mashatan ali@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.1 + +Rectangle { + id:statesComboBox + + width:200; + height: 20; + + Component.onCompleted: + { + var top = dropDownList; + while (top.parent) + { + top = top.parent + if (top.objectName == "debugPanel") + break; + } + var coordinates = dropDownList.mapToItem(top, 0, 0) + dropDownList.parent = top; + dropDownList.x = coordinates.x + dropDownList.y = coordinates.y + } + + signal selectItem(real item); + signal editItem(real item); + + property variant items; + property alias selectedItem: chosenItemText.text; + property alias selectedIndex: listView.currentRow; + signal comboClicked; + + property variant colorItem; + property variant colorSelect; + + smooth:true; + Rectangle { + id:chosenItem + width:parent.width; + height:statesComboBox.height; + color: statesComboBox.color; + smooth:true; + Text { + anchors.top: parent.top; + anchors.left: parent.left; + anchors.margins: 2; + color: statesComboBox.colorItem; + id:chosenItemText + text:statesComboBox.items.get(0).title; + smooth:true + } + + MouseArea { + anchors.fill: parent; + onClicked: { + statesComboBox.state = statesComboBox.state==="dropDown"?"":"dropDown" + } + } + } + + Rectangle { + id:dropDownList + width:statesComboBox.width; + height:0; + clip:true; + radius:4; + anchors.top: chosenItem.bottom; + anchors.margins: 2; + color: statesComboBox.color + + TableView { + id:listView + height:500; + width:statesComboBox.width; + model: statesComboBox.items + currentRow: 0 + headerVisible: false; + backgroundVisible: false + alternatingRowColors : false; + frameVisible: false + + TableViewColumn { + role: "title" + title: "" + width: statesComboBox.width; + delegate: mainItemDelegate + //elideMode: Text.ElideNone + } + + Component { + id: mainItemDelegate + Item{ + id: itemDelegate + width:statesComboBox.width; + height: statesComboBox.height; + Text { + id: textItemid + text: styleData.value + color: statesComboBox.colorItem; + anchors.top: parent.top; + anchors.left: parent.left; + anchors.margins: 5; + + } + Rectangle + { + id: spaceItemid + anchors.top: textItemid.top; + anchors.left: textItemid.right + width: parent.width - textItemid.width - imageItemid.width - textItemid.anchors.margins- textItemid.anchors.margins + } + Image { + id: imageItemid + height:20 + width:20; + visible: false; + fillMode: Image.PreserveAspectFit + source: "img/edit_combox.png" + anchors.top: spaceItemid.top; + anchors.left: spaceItemid.right; + } + + MouseArea { + anchors.fill: parent; + hoverEnabled : true + + onEntered: { + imageItemid.visible = true; + textItemid.color = statesComboBox.colorSelect; + } + onExited: { + imageItemid.visible = false; + textItemid.color = statesComboBox.colorItem; + } + onClicked: { + if (mouseX > imageItemid.x && mouseX < imageItemid.x+ imageItemid.width + && mouseY > imageItemid.y && mouseY < imageItemid.y+ imageItemid.height) + statesComboBox.editItem(styleData.row); + else { + statesComboBox.state = "" + var prevSelection = chosenItemText.text + chosenItemText.text = modelData + if(chosenItemText.text != prevSelection) + statesComboBox.comboClicked(); + listView.currentRow = styleData.row; + statesComboBox.selectItem(styleData.row); + } + } + } + }//Item + }//Component + } + } + states: State { + name: "dropDown"; + PropertyChanges { target: dropDownList; height:20*statesComboBox.items.count } + } + + transitions: Transition { + NumberAnimation { target: dropDownList; properties: "height"; easing.type: Easing.OutExpo; duration: 1000 } + } +} diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 315028c74..d7bda8fc4 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -61,7 +61,7 @@ Item { } } - ComboBox { + /*ComboBox { id: statesCombo model: projectModel.stateListModel width: 150 @@ -77,7 +77,24 @@ Item { statesCombo.currentIndex = index; } } - } + }*/ + StatesComboBox + { + id: statesCombo + items:projectModel.stateListModel + onSelectItem: console.log("Combobox Select Item: " + item ) + onEditItem: console.log("Combobox Edit Item: " + item ) + colorItem: "black" + colorSelect: "yellow" + color: "gray" + Connections { + target: projectModel.stateListModel + onStateRun: { + if (statesCombo.selectedIndex !== index) + statesCombo.selectedIndex = index; + } + } + } Button { anchors.rightMargin: 9 diff --git a/mix/qml/img/edit_combox.png b/mix/qml/img/edit_combox.png new file mode 100644 index 0000000000000000000000000000000000000000..be3b359429d9191aee8366978092ddbbe37be67b GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX0wgC|rfC8xmUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(kexFf>&z!H+DD?|aXr8BwV~EA+J{d9U}xl-c#Q+N3{xm--e>HF>))CL_vxqQs|r zwi;2M<$qR`Wo5=c(R41^vJgnCar>}edXmAO{WbKscMO9L`h0wNvc(HQ7VvP zFfuSS)ip5GHL?gXG_f)@wK6o*HZZg@FqmUJ^9PEC-29Zxv`Q=*OduMnJ{sf#H86O( L`njxgN@xNAav_Q1 literal 0 HcmV?d00001 diff --git a/mix/res.qrc b/mix/res.qrc index fa50d6dd8..51f2b49c6 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -9,8 +9,10 @@ qml/ProjectList.qml qml/StateDialog.qml qml/StateList.qml + qml/StatesComboBox.qml qml/StateListModel.qml qml/img/dappProjectIcon.png + qml/img/edit_combox.png qml/img/jumpintoback.png qml/img/jumpintoforward.png qml/img/jumpoutback.png From 99a5df6b268d4c417ed6a835f5442ea8e06318a8 Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Sun, 22 Mar 2015 12:59:19 +0430 Subject: [PATCH 02/50] - Bug fix: When a state was selected, the state is not being showed in the combobox. - Removing animation --- mix/qml/StatesComboBox.qml | 21 ++- mix/qml/TransactionLog.qml | 334 ++++++++++++++++++------------------- 2 files changed, 170 insertions(+), 185 deletions(-) diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index c89df5de5..24bd57866 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -49,8 +49,14 @@ Rectangle { signal editItem(real item); property variant items; - property alias selectedItem: chosenItemText.text; - property alias selectedIndex: listView.currentRow; + readonly property alias selectedItem: chosenItemText.text; + readonly property alias selectedIndex: listView.currentRow; + function setSelectedIndex(index) + { + listView.currentRow = index; + chosenItemText.text = statesComboBox.items.get(0).title; + } + signal comboClicked; property variant colorItem; @@ -64,12 +70,12 @@ Rectangle { color: statesComboBox.color; smooth:true; Text { + id:chosenItemText anchors.top: parent.top; anchors.left: parent.left; anchors.margins: 2; color: statesComboBox.colorItem; - id:chosenItemText - text:statesComboBox.items.get(0).title; + text:"" smooth:true } @@ -96,7 +102,7 @@ Rectangle { height:500; width:statesComboBox.width; model: statesComboBox.items - currentRow: 0 + currentRow: -1 headerVisible: false; backgroundVisible: false alternatingRowColors : false; @@ -162,7 +168,7 @@ Rectangle { else { statesComboBox.state = "" var prevSelection = chosenItemText.text - chosenItemText.text = modelData + chosenItemText.text = styleData.value if(chosenItemText.text != prevSelection) statesComboBox.comboClicked(); listView.currentRow = styleData.row; @@ -179,7 +185,4 @@ Rectangle { PropertyChanges { target: dropDownList; height:20*statesComboBox.items.count } } - transitions: Transition { - NumberAnimation { target: dropDownList; properties: "height"; easing.type: Easing.OutExpo; duration: 1000 } - } } diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index d7bda8fc4..d0386706e 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -7,202 +7,184 @@ import org.ethereum.qml.RecordLogEntry 1.0 Item { - property ListModel fullModel: ListModel{} - property ListModel transactionModel: ListModel{} - property ListModel callModel: ListModel{} + property ListModel fullModel: ListModel{} + property ListModel transactionModel: ListModel{} + property ListModel callModel: ListModel{} - Action { - id: addStateAction - text: "Add State" - shortcut: "Ctrl+Alt+T" - enabled: codeModel.hasContract && !clientModel.running; - onTriggered: projectModel.stateListModel.addState(); - } - Action { - id: editStateAction - text: "Edit State" - shortcut: "Ctrl+Alt+T" - enabled: codeModel.hasContract && !clientModel.running && statesCombo.currentIndex >= 0 && projectModel.stateListModel.count > 0; - onTriggered: projectModel.stateListModel.editState(statesCombo.currentIndex); - } + Action { + id: addStateAction + text: "Add State" + shortcut: "Ctrl+Alt+T" + enabled: codeModel.hasContract && !clientModel.running; + onTriggered: projectModel.stateListModel.addState(); + } + Action { + id: editStateAction + text: "Edit State" + shortcut: "Ctrl+Alt+T" + enabled: codeModel.hasContract && !clientModel.running && statesCombo.selectedIndex >= 0 && projectModel.stateListModel.count > 0; + onTriggered: projectModel.stateListModel.editState(statesCombo.selectedIndex); + } - ColumnLayout { - anchors.fill: parent - RowLayout { + ColumnLayout { + anchors.fill: parent + RowLayout { - Connections - { - id: compilationStatus - target: codeModel - property bool compilationComplete: false - onCompilationComplete: compilationComplete = true - onCompilationError: compilationComplete = false - } - - Connections - { - target: projectModel - onProjectSaved: - { - if (projectModel.appIsClosing) - return; - if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) - projectModel.stateListModel.debugDefaultState(); - } - onProjectClosed: - { - fullModel.clear(); - transactionModel.clear(); - callModel.clear(); - } - onContractSaved: { - if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) - projectModel.stateListModel.debugDefaultState(); - } - } + Connections + { + id: compilationStatus + target: codeModel + property bool compilationComplete: false + onCompilationComplete: compilationComplete = true + onCompilationError: compilationComplete = false + } - /*ComboBox { - id: statesCombo - model: projectModel.stateListModel - width: 150 - editable: false - textRole: "title" - onActivated: { - model.runState(index); - } - Connections { - target: projectModel.stateListModel - onStateRun: { - if (statesCombo.currentIndex !== index) - statesCombo.currentIndex = index; - } - } - }*/ - StatesComboBox + Connections + { + target: projectModel + onProjectSaved: + { + if (projectModel.appIsClosing) + return; + if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) + projectModel.stateListModel.debugDefaultState(); + } + onProjectClosed: + { + fullModel.clear(); + transactionModel.clear(); + callModel.clear(); + } + onContractSaved: { + if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) + projectModel.stateListModel.debugDefaultState(); + } + } + StatesComboBox { id: statesCombo items:projectModel.stateListModel onSelectItem: console.log("Combobox Select Item: " + item ) - onEditItem: console.log("Combobox Edit Item: " + item ) + onEditItem: projectModel.stateListModel.editState(item) colorItem: "black" - colorSelect: "yellow" - color: "gray" + colorSelect: "blue" + color: "white" Connections { target: projectModel.stateListModel onStateRun: { if (statesCombo.selectedIndex !== index) - statesCombo.selectedIndex = index; + statesCombo.setSelectedIndex( index ); } } } - Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: editStateAction - } - Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: addStateAction - } - Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: mineAction - } + Button + { + anchors.rightMargin: 9 + anchors.verticalCenter: parent.verticalCenter + action: editStateAction + } + Button + { + anchors.rightMargin: 9 + anchors.verticalCenter: parent.verticalCenter + action: addStateAction + } + Button + { + anchors.rightMargin: 9 + anchors.verticalCenter: parent.verticalCenter + action: mineAction + } - ComboBox { - id: itemFilter + ComboBox { + id: itemFilter - function getCurrentModel() - { - return currentIndex === 0 ? fullModel : currentIndex === 1 ? transactionModel : currentIndex === 2 ? callModel : fullModel; - } + function getCurrentModel() + { + return currentIndex === 0 ? fullModel : currentIndex === 1 ? transactionModel : currentIndex === 2 ? callModel : fullModel; + } - model: ListModel { - ListElement { text: qsTr("Calls and Transactions"); value: 0; } - ListElement { text: qsTr("Only Transactions"); value: 1; } - ListElement { text: qsTr("Only Calls"); value: 2; } - } + model: ListModel { + ListElement { text: qsTr("Calls and Transactions"); value: 0; } + ListElement { text: qsTr("Only Transactions"); value: 1; } + ListElement { text: qsTr("Only Calls"); value: 2; } + } - onCurrentIndexChanged: - { - logTable.model = itemFilter.getCurrentModel(); - } - } - } - TableView { - id: logTable - Layout.fillWidth: true - Layout.fillHeight: true - model: fullModel + onCurrentIndexChanged: + { + logTable.model = itemFilter.getCurrentModel(); + } + } + } + TableView { + id: logTable + Layout.fillWidth: true + Layout.fillHeight: true + model: fullModel - TableViewColumn { - role: "transactionIndex" - title: qsTr("#") - width: 40 - } - TableViewColumn { - role: "contract" - title: qsTr("Contract") - width: 100 - } - TableViewColumn { - role: "function" - title: qsTr("Function") - width: 120 - } - TableViewColumn { - role: "value" - title: qsTr("Value") - width: 60 - } - TableViewColumn { - role: "address" - title: qsTr("Destination") - width: 130 - } - TableViewColumn { - role: "returned" - title: qsTr("Returned") - width: 120 - } - onActivated: { - var item = logTable.model.get(row); - if (item.type === RecordLogEntry.Transaction) - clientModel.debugRecord(item.recordIndex); - else - clientModel.emptyRecord(); - } - Keys.onPressed: { - if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { - var item = logTable.model.get(currentRow); - appContext.toClipboard(item.returned); - } - } - } - } + TableViewColumn { + role: "transactionIndex" + title: qsTr("#") + width: 40 + } + TableViewColumn { + role: "contract" + title: qsTr("Contract") + width: 100 + } + TableViewColumn { + role: "function" + title: qsTr("Function") + width: 120 + } + TableViewColumn { + role: "value" + title: qsTr("Value") + width: 60 + } + TableViewColumn { + role: "address" + title: qsTr("Destination") + width: 130 + } + TableViewColumn { + role: "returned" + title: qsTr("Returned") + width: 120 + } + onActivated: { + var item = logTable.model.get(row); + if (item.type === RecordLogEntry.Transaction) + clientModel.debugRecord(item.recordIndex); + else + clientModel.emptyRecord(); + } + Keys.onPressed: { + if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { + var item = logTable.model.get(currentRow); + appContext.toClipboard(item.returned); + } + } + } + } - Connections { - target: clientModel - onStateCleared: { - fullModel.clear(); - transactionModel.clear(); - callModel.clear(); - } - onNewRecord: { - fullModel.append(_r); - if (!_r.call) - transactionModel.append(_r); - else - callModel.append(_r); - } - onMiningComplete: { - fullModel.append(clientModel.lastBlock); - transactionModel.append(clientModel.lastBlock); - } - } + Connections { + target: clientModel + onStateCleared: { + fullModel.clear(); + transactionModel.clear(); + callModel.clear(); + } + onNewRecord: { + fullModel.append(_r); + if (!_r.call) + transactionModel.append(_r); + else + callModel.append(_r); + } + onMiningComplete: { + fullModel.append(clientModel.lastBlock); + transactionModel.append(clientModel.lastBlock); + } + } } From b9a7f0815f49237030a06df42b4eac64f6f13a74 Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Wed, 25 Mar 2015 02:47:15 +0430 Subject: [PATCH 03/50] Adding "create state" minor correction --- mix/qml/StatesComboBox.qml | 169 ++++++++++++++++++++++--------------- mix/qml/TransactionLog.qml | 7 +- 2 files changed, 104 insertions(+), 72 deletions(-) diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index 24bd57866..ada5e00d5 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -47,6 +47,7 @@ Rectangle { signal selectItem(real item); signal editItem(real item); + signal selectCreate(); property variant items; readonly property alias selectedItem: chosenItemText.text; @@ -86,7 +87,7 @@ Rectangle { } } } - +//ToDo: We need scrollbar for items Rectangle { id:dropDownList width:statesComboBox.width; @@ -96,93 +97,123 @@ Rectangle { anchors.top: chosenItem.bottom; anchors.margins: 2; color: statesComboBox.color + ColumnLayout{ + spacing: 2 + TableView { + id:listView + height:20; + implicitHeight: 0 + width:statesComboBox.width; + model: statesComboBox.items + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff; + currentRow: -1 + headerVisible: false; + backgroundVisible: false + alternatingRowColors : false; + frameVisible: false + + TableViewColumn { + role: "title" + title: "" + width: statesComboBox.width; + delegate: mainItemDelegate + } + + Component { + id: mainItemDelegate + Item{ + id: itemDelegate + width:statesComboBox.width; + height: statesComboBox.height; + Text { + id: textItemid + text: styleData.value + color: statesComboBox.colorItem; + anchors.top: parent.top; + anchors.left: parent.left; + anchors.margins: 5; - TableView { - id:listView - height:500; - width:statesComboBox.width; - model: statesComboBox.items - currentRow: -1 - headerVisible: false; - backgroundVisible: false - alternatingRowColors : false; - frameVisible: false - - TableViewColumn { - role: "title" - title: "" - width: statesComboBox.width; - delegate: mainItemDelegate - //elideMode: Text.ElideNone - } + } + Rectangle + { + id: spaceItemid + anchors.top: textItemid.top; + anchors.left: textItemid.right + width: parent.width - textItemid.width - imageItemid.width - textItemid.anchors.margins- textItemid.anchors.margins + } + Image { + id: imageItemid + height:20 + width:20; + visible: false; + fillMode: Image.PreserveAspectFit + source: "img/edit_combox.png" + anchors.top: spaceItemid.top; + anchors.left: spaceItemid.right; + } - Component { - id: mainItemDelegate - Item{ - id: itemDelegate + MouseArea { + anchors.fill: parent; + hoverEnabled : true + + onEntered: { + imageItemid.visible = true; + textItemid.color = statesComboBox.colorSelect; + } + onExited: { + imageItemid.visible = false; + textItemid.color = statesComboBox.colorItem; + } + onClicked: { + if (mouseX > imageItemid.x && mouseX < imageItemid.x+ imageItemid.width + && mouseY > imageItemid.y && mouseY < imageItemid.y+ imageItemid.height) + statesComboBox.editItem(styleData.row); + else { + statesComboBox.state = "" + var prevSelection = chosenItemText.text + chosenItemText.text = styleData.value + listView.currentRow = styleData.row; + statesComboBox.selectItem(styleData.row); + } + } + } + }//Item + }//Component + }//Table View + RowLayout{ + Rectangle{ + width: 1 + } + Text{ + id:createStateText width:statesComboBox.width; height: statesComboBox.height; - Text { - id: textItemid - text: styleData.value - color: statesComboBox.colorItem; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.margins: 5; - - } - Rectangle + font.pointSize: 10 + text:"Create State ..." + MouseArea { - id: spaceItemid - anchors.top: textItemid.top; - anchors.left: textItemid.right - width: parent.width - textItemid.width - imageItemid.width - textItemid.anchors.margins- textItemid.anchors.margins - } - Image { - id: imageItemid - height:20 - width:20; - visible: false; - fillMode: Image.PreserveAspectFit - source: "img/edit_combox.png" - anchors.top: spaceItemid.top; - anchors.left: spaceItemid.right; - } - - MouseArea { anchors.fill: parent; hoverEnabled : true onEntered: { - imageItemid.visible = true; - textItemid.color = statesComboBox.colorSelect; + createStateText.color = statesComboBox.colorSelect; } onExited: { - imageItemid.visible = false; - textItemid.color = statesComboBox.colorItem; + createStateText.color = statesComboBox.colorItem; } onClicked: { - if (mouseX > imageItemid.x && mouseX < imageItemid.x+ imageItemid.width - && mouseY > imageItemid.y && mouseY < imageItemid.y+ imageItemid.height) - statesComboBox.editItem(styleData.row); - else { - statesComboBox.state = "" - var prevSelection = chosenItemText.text - chosenItemText.text = styleData.value - if(chosenItemText.text != prevSelection) - statesComboBox.comboClicked(); - listView.currentRow = styleData.row; - statesComboBox.selectItem(styleData.row); - } + statesComboBox.state = "" + statesComboBox.selectCreate(); } } - }//Item - }//Component + } + } } } states: State { name: "dropDown"; - PropertyChanges { target: dropDownList; height:20*statesComboBox.items.count } + PropertyChanges { target: dropDownList; height:(20*(statesComboBox.items.count+1)) } + PropertyChanges { target:listView; height:20; implicitHeight: (20*(statesComboBox.items.count)) } } } diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index d0386706e..e0aec1a32 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -64,7 +64,8 @@ Item { { id: statesCombo items:projectModel.stateListModel - onSelectItem: console.log("Combobox Select Item: " + item ) + //onSelectItem: console.log("Combobox Select Item: " + item ) + onSelectCreate: projectModel.stateListModel.addState(); onEditItem: projectModel.stateListModel.editState(item) colorItem: "black" colorSelect: "blue" @@ -77,7 +78,7 @@ Item { } } } - Button + /*Button { anchors.rightMargin: 9 anchors.verticalCenter: parent.verticalCenter @@ -88,7 +89,7 @@ Item { anchors.rightMargin: 9 anchors.verticalCenter: parent.verticalCenter action: addStateAction - } + }*/ Button { anchors.rightMargin: 9 From f72d91b444aa082f506431c17b8f71043577403e Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Sat, 28 Mar 2015 00:21:24 +0430 Subject: [PATCH 04/50] Adding "play" button Changes in the appearance and behavior of StatesComboBox --- mix/qml/StatesComboBox.qml | 55 +++++++++++++++++++++++---------- mix/qml/TransactionLog.qml | 41 +++++++++++++++--------- mix/qml/img/pause_button.png | Bin 0 -> 200 bytes mix/qml/img/pause_button2x.png | Bin 0 -> 414 bytes mix/qml/img/play_button.png | Bin 0 -> 531 bytes mix/qml/img/play_button2x.png | Bin 0 -> 904 bytes mix/res.qrc | 6 +++- 7 files changed, 70 insertions(+), 32 deletions(-) create mode 100755 mix/qml/img/pause_button.png create mode 100755 mix/qml/img/pause_button2x.png create mode 100755 mix/qml/img/play_button.png create mode 100755 mix/qml/img/play_button2x.png diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index ada5e00d5..2c61863ec 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -23,6 +23,7 @@ import QtQuick 2.0 import QtQuick.Controls 1.0 import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 Rectangle { id:statesComboBox @@ -40,7 +41,13 @@ Rectangle { break; } var coordinates = dropDownList.mapToItem(top, 0, 0) + //the order is important + dropDownShowdowList.parent = top; dropDownList.parent = top; + + dropDownShowdowList.x = coordinates.x + dropDownShowdowList.y = coordinates.y + dropDownList.x = coordinates.x dropDownList.y = coordinates.y } @@ -48,7 +55,7 @@ Rectangle { signal selectItem(real item); signal editItem(real item); signal selectCreate(); - + property variant rowHeight:25; property variant items; readonly property alias selectedItem: chosenItemText.text; readonly property alias selectedIndex: listView.currentRow; @@ -87,16 +94,30 @@ Rectangle { } } } -//ToDo: We need scrollbar for items + + Rectangle { + id:dropDownShowdowList + width:statesComboBox.width; + opacity: 0.3 + height:0; + clip:true; + radius:4; + anchors.top: chosenItem.top; + anchors.margins: 2; + color: "gray" + } + //ToDo: We need scrollbar for items Rectangle { id:dropDownList width:statesComboBox.width; height:0; clip:true; radius:4; - anchors.top: chosenItem.bottom; + anchors.top: chosenItem.top; anchors.margins: 2; color: statesComboBox.color + + ColumnLayout{ spacing: 2 TableView { @@ -118,10 +139,13 @@ Rectangle { width: statesComboBox.width; delegate: mainItemDelegate } - + rowDelegate: Rectangle { + width:statesComboBox.width; + height: statesComboBox.rowHeight; + } Component { id: mainItemDelegate - Item{ + Rectangle { id: itemDelegate width:statesComboBox.width; height: statesComboBox.height; @@ -134,22 +158,16 @@ Rectangle { anchors.margins: 5; } - Rectangle - { - id: spaceItemid - anchors.top: textItemid.top; - anchors.left: textItemid.right - width: parent.width - textItemid.width - imageItemid.width - textItemid.anchors.margins- textItemid.anchors.margins - } Image { id: imageItemid height:20 width:20; + anchors.right:parent.right + anchors.top: parent.top; + anchors.margins: 5; visible: false; fillMode: Image.PreserveAspectFit source: "img/edit_combox.png" - anchors.top: spaceItemid.top; - anchors.left: spaceItemid.right; } MouseArea { @@ -180,6 +198,7 @@ Rectangle { }//Item }//Component }//Table View + RowLayout{ Rectangle{ width: 1 @@ -188,7 +207,7 @@ Rectangle { id:createStateText width:statesComboBox.width; height: statesComboBox.height; - font.pointSize: 10 + font.bold: true text:"Create State ..." MouseArea { @@ -208,12 +227,14 @@ Rectangle { } } } + } } states: State { name: "dropDown"; - PropertyChanges { target: dropDownList; height:(20*(statesComboBox.items.count+1)) } - PropertyChanges { target:listView; height:20; implicitHeight: (20*(statesComboBox.items.count)) } + PropertyChanges { target: dropDownList; height:(statesComboBox.rowHeight*(statesComboBox.items.count+1)) } + PropertyChanges { target: dropDownShowdowList; width:statesComboBox.width+3; height:(statesComboBox.rowHeight*(statesComboBox.items.count+1))+3 } + PropertyChanges { target:listView; height:20; implicitHeight: (statesComboBox.rowHeight*(statesComboBox.items.count)) } } } diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index e0aec1a32..48b166eca 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -6,7 +6,6 @@ import QtQuick.Layouts 1.1 import org.ethereum.qml.RecordLogEntry 1.0 Item { - property ListModel fullModel: ListModel{} property ListModel transactionModel: ListModel{} property ListModel callModel: ListModel{} @@ -25,11 +24,29 @@ Item { enabled: codeModel.hasContract && !clientModel.running && statesCombo.selectedIndex >= 0 && projectModel.stateListModel.count > 0; onTriggered: projectModel.stateListModel.editState(statesCombo.selectedIndex); } + Action { + id: playAndPauseAction + checkable: true; + checked: false; + iconSource: "qrc:/qml/img/play_button.png" + onToggled: { + if (checked) + { + this.iconSource = "qrc:/qml/img/pause_button2x.png" + console.log("play"); + }else{ + this.iconSource = "qrc:/qml/img/play_button2x.png" + console.log("pause"); + } + } + enabled: true + } ColumnLayout { anchors.fill: parent RowLayout { - + anchors.right: parent.right + anchors.left: parent.left Connections { id: compilationStatus @@ -78,18 +95,6 @@ Item { } } } - /*Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: editStateAction - } - Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: addStateAction - }*/ Button { anchors.rightMargin: 9 @@ -116,6 +121,14 @@ Item { logTable.model = itemFilter.getCurrentModel(); } } + Button + { + id: playPauseBtn + anchors.right: parent.right + anchors.rightMargin: 1 + anchors.verticalCenter: parent.verticalCenter + action: playAndPauseAction + } } TableView { id: logTable diff --git a/mix/qml/img/pause_button.png b/mix/qml/img/pause_button.png new file mode 100755 index 0000000000000000000000000000000000000000..e87889551dc9239887d84bd1511f2ce0f57904e1 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^=0L2+!3HFIm>NZa6k~CayA#8@b22Z1oF-2f$B+!x zx0f8b8WcoW0$xv%yBIB|$9ypJd+YTex4-*Vn#waWv2X||I5aRYGDSCL&;B9#Vz2#b z-Q=G0v6*?LVY|wf9~3T@D^JQUPCJ{qZb8HSO$nM8J!W;!;A%4o-!LUZ<*cg@tMe@F o2rrXK&y>^@5vH+lOcAbNY*gb=vpC{%3FsOIPgg&ebxsLQ0RFK*6951J literal 0 HcmV?d00001 diff --git a/mix/qml/img/pause_button2x.png b/mix/qml/img/pause_button2x.png new file mode 100755 index 0000000000000000000000000000000000000000..6f45b3236ab4e8debdc79082f4fa04df0f852786 GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0vp^c|aV)!3HGzUpB-7DaPU;cPEB*=VV?2*%6*Djv*C{ zZ!aF?ZFUe~aeSkp@3Lu&v4d0A+0}oJZ4Ri7tz+R3P;h8qU}Pea5y4$^js5;T>*s&& z{dvCc{qg)&-|y{-{`qFR%;v4a0(t3k^6K@cI~C=!=Q6_XB1e!{xYdR^Ld`nj=7~(o;#)#o2%V9XSG))=G0DU lVOkp}rA&&~Vc}%LRIk&@;p1(W6b}q=22WQ%mvv4FO#n*Mm`DHs literal 0 HcmV?d00001 diff --git a/mix/qml/img/play_button.png b/mix/qml/img/play_button.png new file mode 100755 index 0000000000000000000000000000000000000000..01a5c85cb2123f6b78e4a7914e18aab8b60f8fea GIT binary patch literal 531 zcmV+u0_^>XP)Px$%}GQ-RA>e5mc38HKp4j9M@$G4j;zkIx#&)qSQ=;-abVD06Wv_Ze?a^XEQF;C zq@#&0Ov22{%0!xwe)yF177}7>@2;4cR;I{g( zir3X@^}EyQT<{W{C67?JSO@@5R8{=|;1jm$Q5JD|V}-*d0>P)=W2;UL!>H#Ko%VZK za7<5K*YzoS@c|RUYb&fOuhFusC{3;?ioOunwQYNmCjKum!rj{^3cYxaH$H4`_Qm9# zFAOdbUO_LuVztMuR;!j5X7~G|;h3Igxm=#37cDlyV>}eNEep13s(wuiuBQzY95?Yi zuje?#n6z zCB;O+EwKfA!{KmJ1Qe^uz2~r6Ho#7c24jFUk^|%bIY17O1LOcXKn{=t{z>Ug}i6zkYRuPT8rapDbDIzSXX+Tz9^@P_t*Zzz@++eXqX$@|)LCV>?}> zP`Yly_cdXw|K@DJ-Cx5x>-sL2PVWT{_x1*@{KEU`p5phrC%LEOKNnQjW92Acdi_ML z`q{MN`{pYu*SN2;IGnaWXyqJ*?|Tn2zPz5aPBS?AjL9o|zE@?tU+XN7Uw_@+;GIF& zqHdkXOZx*qYr4Lx?np0s{3&MF6rI=M%6fZm$UfQE-*L%v@x>dbnH*k8+Oy!o>KDIz1}lQ$v^jqR`nuuAq^Y_Gm+I?1+F-g$BXZ}7P0u@o*fX=d!nUzY-zQS| z$}3E7(;Lfs&n;YLo&qXutQAsVqzFxLe4xMh>o;G?TQN_7S&PBb)z4*}Q$iB}AKit7 literal 0 HcmV?d00001 diff --git a/mix/res.qrc b/mix/res.qrc index 51f2b49c6..6397555db 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -12,7 +12,7 @@ qml/StatesComboBox.qml qml/StateListModel.qml qml/img/dappProjectIcon.png - qml/img/edit_combox.png + qml/img/edit_combox.png qml/img/jumpintoback.png qml/img/jumpintoforward.png qml/img/jumpoutback.png @@ -115,5 +115,9 @@ qml/StructView.qml qml/img/console.png qml/VariablesView.qml + qml/img/play_button2x.png + qml/img/play_button.png + qml/img/pause_button2x.png + qml/img/pause_button.png From 965f005a989e0b7fb5a46f364bfb96dad2e18aae Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 24 Mar 2015 14:53:15 +0100 Subject: [PATCH 05/50] Storage access optimisation. --- libevmcore/CommonSubexpressionEliminator.cpp | 205 ++++++++++++++----- libevmcore/CommonSubexpressionEliminator.h | 67 +++++- libevmcore/ExpressionClasses.cpp | 70 +++++-- libevmcore/ExpressionClasses.h | 10 +- test/SolidityOptimizer.cpp | 180 ++++++++++++++++ 5 files changed, 453 insertions(+), 79 deletions(-) diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index 7fed03b4e..43d01fc85 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -45,19 +45,24 @@ vector CommonSubexpressionEliminator::getOptimizedItems() // Debug info: //stream(cout, initialStackContents, targetStackContents); - return CSECodeGenerator(m_expressionClasses).generateCode(initialStackContents, targetStackContents); + return CSECodeGenerator(m_expressionClasses, m_storageWrites).generateCode( + initialStackContents, + targetStackContents + ); } ostream& CommonSubexpressionEliminator::stream( ostream& _out, - map _currentStack, + map _initialStack, map _targetStack ) const { auto streamExpressionClass = [this](ostream& _out, ExpressionClasses::Id _id) { auto const& expr = m_expressionClasses.representative(_id); - _out << " " << _id << ": " << *expr.item; + _out << " " << dec << _id << ": " << *expr.item; + if (expr.sequenceNumber) + _out << "@" << dec << expr.sequenceNumber; _out << "("; for (ExpressionClasses::Id arg: expr.arguments) _out << dec << arg << ","; @@ -66,18 +71,12 @@ ostream& CommonSubexpressionEliminator::stream( _out << "Optimizer analysis:" << endl; _out << "Final stack height: " << dec << m_stackHeight << endl; - _out << "Stack elements: " << endl; - for (auto const& it: m_stackElements) - { - _out << " " << dec << it.first << " = "; - streamExpressionClass(_out, it.second); - } _out << "Equivalence classes: " << endl; for (ExpressionClasses::Id eqClass = 0; eqClass < m_expressionClasses.size(); ++eqClass) streamExpressionClass(_out, eqClass); - _out << "Current stack: " << endl; - for (auto const& it: _currentStack) + _out << "Initial stack: " << endl; + for (auto const& it: _initialStack) { _out << " " << dec << it.first << ": "; streamExpressionClass(_out, it.second); @@ -96,9 +95,8 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) { if (_item.type() != Operation) { - if (_item.deposit() != 1) - BOOST_THROW_EXCEPTION(InvalidDeposit()); - setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {})); + assertThrow(_item.deposit() == 1, InvalidDeposit, ""); + setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {}, false)); } else { @@ -119,7 +117,12 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) vector arguments(info.args); for (int i = 0; i < info.args; ++i) arguments[i] = stackElement(m_stackHeight - i); - setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments)); + if (_item.instruction() == Instruction::SSTORE) + storeInStorage(arguments[0], arguments[1]); + else if (_item.instruction() == Instruction::SLOAD) + setStackElement(m_stackHeight + _item.deposit(), loadFromStorage(arguments[0])); + else + setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, false)); } m_stackHeight += _item.deposit(); } @@ -132,8 +135,7 @@ void CommonSubexpressionEliminator::setStackElement(int _stackHeight, Expression void CommonSubexpressionEliminator::swapStackElements(int _stackHeightA, int _stackHeightB) { - if (_stackHeightA == _stackHeightB) - BOOST_THROW_EXCEPTION(OptimizerException() << errinfo_comment("Swap on same stack elements.")); + assertThrow(_stackHeightA != _stackHeightB, OptimizerException, "Swap on same stack elements."); // ensure they are created stackElement(_stackHeightA); stackElement(_stackHeightB); @@ -157,6 +159,33 @@ ExpressionClasses::Id CommonSubexpressionEliminator::initialStackElement(int _st return m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight))); } +void CommonSubexpressionEliminator::storeInStorage(ExpressionClasses::Id _slot, ExpressionClasses::Id _value) +{ + if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value) + // do not execute the storage if we know that the value is already there + return; + m_sequenceNumber ++; + decltype(m_storageContent) storageContents; + // copy over values at points where we know that they are different from _slot + for (auto const& storageItem: m_storageContent) + if (m_expressionClasses.knownToBeDifferent(storageItem.first, _slot)) + storageContents.insert(storageItem); + m_storageContent = move(storageContents); + ExpressionClasses::Id id = m_expressionClasses.find(Instruction::SSTORE, {_slot, _value}, true, m_sequenceNumber); + m_storageWrites.insert(StorageWriteOperation(_slot, m_sequenceNumber, id)); + m_storageContent[_slot] = _value; + // increment a second time so that we get unique sequence numbers for writes + m_sequenceNumber ++; +} + +ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(ExpressionClasses::Id _slot) +{ + if (m_storageContent.count(_slot)) + return m_storageContent.at(_slot); + else + return m_storageContent[_slot] = m_expressionClasses.find(Instruction::SLOAD, {_slot}, true, m_sequenceNumber); +} + bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) { switch (_item.type()) @@ -180,6 +209,8 @@ bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC) return true; // GAS and PC assume a specific order of opcodes InstructionInfo info = instructionInfo(_item.instruction()); + if (_item.instruction() == Instruction::SSTORE) + return false; // the second requirement will be lifted once it is implemented return info.sideEffects || info.args > 2; } @@ -230,26 +261,49 @@ AssemblyItems CSECodeGenerator::generateCode( // @todo: provide information about the positions of copies of class elements - // generate the dependency graph + // generate the dependency graph starting from final storage writes and target stack contents + for (auto it = m_storageWrites.begin(); it != m_storageWrites.end();) + { + auto next = it; + ++next; + if (next == m_storageWrites.end() || next->slot != it->slot) + // last write to that storage slot + addDependencies(it->expression); + it = next; + } for (auto const& targetItem: _targetStackContents) { m_finalClasses.insert(targetItem.second); addDependencies(targetItem.second); } - // generate the actual elements + // Perform all operations on storage in order, if they are needed. + //@todo use better data structures to optimize these loops + unsigned maxSequenceNumber = 1; + for (StorageWriteOperation const& op: m_storageWrites) + maxSequenceNumber = max(maxSequenceNumber, op.sequenceNumber + 1); + for (unsigned sequenceNumber = 1; sequenceNumber <= maxSequenceNumber; ++sequenceNumber) + for (auto const& depPair: m_neededBy) + for (ExpressionClasses::Id const& id: {depPair.first, depPair.second}) + if ( + m_expressionClasses.representative(id).sequenceNumber == sequenceNumber && + !m_classPositions.count(id) + ) + generateClassElement(id, true); + + // generate the target stack elements for (auto const& targetItem: _targetStackContents) { - removeStackTopIfPossible(); int position = generateClassElement(targetItem.second); + assertThrow(position != c_invalidPosition, OptimizerException, ""); if (position == targetItem.first) continue; if (position < targetItem.first) // it is already at its target, we need another copy appendDup(position); else - appendSwapOrRemove(position); - appendSwapOrRemove(targetItem.first); + appendOrRemoveSwap(position); + appendOrRemoveSwap(targetItem.first); } // remove surplus elements @@ -270,23 +324,48 @@ AssemblyItems CSECodeGenerator::generateCode( // neither initial no target stack, no change in height finalHeight = 0; assertThrow(finalHeight == m_stackHeight, OptimizerException, "Incorrect final stack height."); - return m_generatedItems; } void CSECodeGenerator::addDependencies(ExpressionClasses::Id _c) { if (m_neededBy.count(_c)) - return; - for (ExpressionClasses::Id argument: m_expressionClasses.representative(_c).arguments) + return; // we already computed the dependencies for _c + ExpressionClasses::Expression const& expr = m_expressionClasses.representative(_c); + for (ExpressionClasses::Id argument: expr.arguments) { addDependencies(argument); m_neededBy.insert(make_pair(argument, _c)); } + if (expr.item->type() == Operation && expr.item->instruction() == Instruction::SLOAD) + { + // this loads an unknown value from storage and thus, in addition to its arguments, depends + // on all SSTORE operations to addresses where we do not know that they are different that + // occur before this SLOAD + ExpressionClasses::Id slotToLoadFrom = expr.arguments.at(0); + for (auto it = m_storageWrites.begin(); it != m_storageWrites.end();) + { + auto next = it; + ++next; + // note that SSTORE and SLOAD never have the same sequence number + if (it->sequenceNumber < expr.sequenceNumber && + !m_expressionClasses.knownToBeDifferent(it->slot, slotToLoadFrom) && + (next == m_storageWrites.end() || next->sequenceNumber > expr.sequenceNumber) + ) + { + addDependencies(it->expression); + m_neededBy.insert(make_pair(it->expression, _c)); + } + it = next; + } + } } -int CSECodeGenerator::generateClassElement(ExpressionClasses::Id _c) +int CSECodeGenerator::generateClassElement(ExpressionClasses::Id _c, bool _allowSequenced) { + // do some cleanup + removeStackTopIfPossible(); + if (m_classPositions.count(_c)) { assertThrow( @@ -296,7 +375,13 @@ int CSECodeGenerator::generateClassElement(ExpressionClasses::Id _c) ); return m_classPositions[_c]; } - ExpressionClasses::Ids const& arguments = m_expressionClasses.representative(_c).arguments; + ExpressionClasses::Expression const& expr = m_expressionClasses.representative(_c); + assertThrow( + _allowSequenced || expr.sequenceNumber == 0, + OptimizerException, + "Sequence constrained operation requested out of sequence." + ); + ExpressionClasses::Ids const& arguments = expr.arguments; for (ExpressionClasses::Id arg: boost::adaptors::reverse(arguments)) generateClassElement(arg); @@ -307,42 +392,42 @@ int CSECodeGenerator::generateClassElement(ExpressionClasses::Id _c) if (arguments.size() == 1) { if (canBeRemoved(arguments[0], _c)) - appendSwapOrRemove(generateClassElement(arguments[0])); + appendOrRemoveSwap(classElementPosition(arguments[0])); else - appendDup(generateClassElement(arguments[0])); + appendDup(classElementPosition(arguments[0])); } else if (arguments.size() == 2) { if (canBeRemoved(arguments[1], _c)) { - appendSwapOrRemove(generateClassElement(arguments[1])); + appendOrRemoveSwap(classElementPosition(arguments[1])); if (arguments[0] == arguments[1]) appendDup(m_stackHeight); else if (canBeRemoved(arguments[0], _c)) { - appendSwapOrRemove(m_stackHeight - 1); - appendSwapOrRemove(generateClassElement(arguments[0])); + appendOrRemoveSwap(m_stackHeight - 1); + appendOrRemoveSwap(classElementPosition(arguments[0])); } else - appendDup(generateClassElement(arguments[0])); + appendDup(classElementPosition(arguments[0])); } else { if (arguments[0] == arguments[1]) { - appendDup(generateClassElement(arguments[0])); + appendDup(classElementPosition(arguments[0])); appendDup(m_stackHeight); } else if (canBeRemoved(arguments[0], _c)) { - appendSwapOrRemove(generateClassElement(arguments[0])); - appendDup(generateClassElement(arguments[1])); - appendSwapOrRemove(m_stackHeight - 1); + appendOrRemoveSwap(classElementPosition(arguments[0])); + appendDup(classElementPosition(arguments[1])); + appendOrRemoveSwap(m_stackHeight - 1); } else { - appendDup(generateClassElement(arguments[1])); - appendDup(generateClassElement(arguments[0])); + appendDup(classElementPosition(arguments[1])); + appendDup(classElementPosition(arguments[0])); } } } @@ -355,20 +440,41 @@ int CSECodeGenerator::generateClassElement(ExpressionClasses::Id _c) for (size_t i = 0; i < arguments.size(); ++i) assertThrow(m_stack[m_stackHeight - i] == arguments[i], OptimizerException, "Expected arguments not present." ); - AssemblyItem const& item = *m_expressionClasses.representative(_c).item; - while (SemanticInformation::isCommutativeOperation(item) && + while (SemanticInformation::isCommutativeOperation(*expr.item) && !m_generatedItems.empty() && m_generatedItems.back() == AssemblyItem(Instruction::SWAP1)) // this will not append a swap but remove the one that is already there - appendSwapOrRemove(m_stackHeight - 1); + appendOrRemoveSwap(m_stackHeight - 1); for (auto arg: arguments) if (canBeRemoved(arg, _c)) m_classPositions[arg] = c_invalidPosition; for (size_t i = 0; i < arguments.size(); ++i) m_stack.erase(m_stackHeight - i); - appendItem(*m_expressionClasses.representative(_c).item); - m_stack[m_stackHeight] = _c; - return m_classPositions[_c] = m_stackHeight; + appendItem(*expr.item); + if (expr.item->type() != Operation || instructionInfo(expr.item->instruction()).ret == 1) + { + m_stack[m_stackHeight] = _c; + return m_classPositions[_c] = m_stackHeight; + } + else + { + assertThrow( + instructionInfo(expr.item->instruction()).ret == 0, + OptimizerException, + "Invalid number of return values." + ); + return m_classPositions[_c] = c_invalidPosition; + } +} + +int CSECodeGenerator::classElementPosition(ExpressionClasses::Id _id) const +{ + assertThrow( + m_classPositions.count(_id) && m_classPositions.at(_id) != c_invalidPosition, + OptimizerException, + "Element requested but is not present." + ); + return m_classPositions.at(_id); } bool CSECodeGenerator::canBeRemoved(ExpressionClasses::Id _element, ExpressionClasses::Id _result) @@ -401,22 +507,23 @@ bool CSECodeGenerator::removeStackTopIfPossible() void CSECodeGenerator::appendDup(int _fromPosition) { + assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); int nr = 1 + m_stackHeight - _fromPosition; assertThrow(nr <= 16, StackTooDeepException, "Stack too deep."); assertThrow(1 <= nr, OptimizerException, "Invalid stack access."); - m_generatedItems.push_back(AssemblyItem(dupInstruction(nr))); - m_stackHeight++; + appendItem(AssemblyItem(dupInstruction(nr))); m_stack[m_stackHeight] = m_stack[_fromPosition]; } -void CSECodeGenerator::appendSwapOrRemove(int _fromPosition) +void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition) { + assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); if (_fromPosition == m_stackHeight) return; int nr = m_stackHeight - _fromPosition; assertThrow(nr <= 16, StackTooDeepException, "Stack too deep."); assertThrow(1 <= nr, OptimizerException, "Invalid stack access."); - m_generatedItems.push_back(AssemblyItem(swapInstruction(nr))); + appendItem(AssemblyItem(swapInstruction(nr))); // The value of a class can be present in multiple locations on the stack. We only update the // "canonical" one that is tracked by m_classPositions if (m_classPositions[m_stack[m_stackHeight]] == m_stackHeight) diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index 331a7642d..c3e291afb 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include #include @@ -44,9 +46,9 @@ using AssemblyItems = std::vector; * known to be equal only once. * * The general workings are that for each assembly item that is fed into the eliminator, an - * equivalence class is derived from the operation and the equivalence class of its arguments and - * it is assigned to the next sequence number of a stack item. DUPi, SWAPi and some arithmetic - * instructions are used to infer equivalences while these classes are determined. + * equivalence class is derived from the operation and the equivalence class of its arguments. + * DUPi, SWAPi and some arithmetic instructions are used to infer equivalences while these + * classes are determined. * * When the list of optimized items is requested, they are generated in a bottom-up fashion, * adding code for equivalence classes that were not yet computed. @@ -54,6 +56,23 @@ using AssemblyItems = std::vector; class CommonSubexpressionEliminator { public: + struct StorageWriteOperation + { + StorageWriteOperation( + ExpressionClasses::Id _slot, + unsigned _sequenceNumber, + ExpressionClasses::Id _expression + ): slot(_slot), sequenceNumber(_sequenceNumber), expression(_expression) {} + bool operator<(StorageWriteOperation const& _other) const + { + return std::tie(slot, sequenceNumber, expression) < + std::tie(_other.slot, _other.sequenceNumber, _other.expression); + } + ExpressionClasses::Id slot; + unsigned sequenceNumber; + ExpressionClasses::Id expression; + }; + /// Feeds AssemblyItems into the eliminator and @returns the iterator pointing at the first /// item that must be fed into a new instance of the eliminator. template @@ -65,7 +84,7 @@ public: /// Streams debugging information to @a _out. std::ostream& stream( std::ostream& _out, - std::map _currentStack = std::map(), + std::map _initialStack = std::map(), std::map _targetStack = std::map() ) const; @@ -85,10 +104,23 @@ private: /// (must not be positive). ExpressionClasses::Id initialStackElement(int _stackHeight); + /// Increments the sequence number, deletes all storage information that might be overwritten + /// and stores the new value at the given slot. + void storeInStorage(ExpressionClasses::Id _slot, ExpressionClasses::Id _value); + /// Retrieves the current value at the given slot in storage or creates a new special sload class. + ExpressionClasses::Id loadFromStorage(ExpressionClasses::Id _slot); + /// Current stack height, can be negative. int m_stackHeight = 0; /// Current stack layout, mapping stack height -> equivalence class std::map m_stackElements; + /// Current sequence number, this is incremented with each modification to storage. + unsigned m_sequenceNumber = 1; + /// Knowledge about storage content. + std::map m_storageContent; + /// Keeps information about which storage slots were written to at which sequence number with + /// what SSTORE instruction. + std::set m_storageWrites; /// Structure containing the classes of equivalent expressions. ExpressionClasses m_expressionClasses; }; @@ -114,14 +146,19 @@ struct SemanticInformation class CSECodeGenerator { public: - CSECodeGenerator(ExpressionClasses const& _expressionClasses): - m_expressionClasses(_expressionClasses) + using StorageWriteOperation = CommonSubexpressionEliminator::StorageWriteOperation; + + CSECodeGenerator( + ExpressionClasses& _expressionClasses, + std::set const& _storageWrites + ): + m_expressionClasses(_expressionClasses), + m_storageWrites(_storageWrites) {} /// @returns the assembly items generated from the given requirements /// @param _initialStack current contents of the stack (up to stack height of zero) /// @param _targetStackContents final contents of the stack, by stack height relative to initial - /// @param _equivalenceClasses equivalence classes as expressions of how to compute them /// @note should only be called once on each object. AssemblyItems generateCode( std::map const& _initialStack, @@ -133,8 +170,13 @@ private: void addDependencies(ExpressionClasses::Id _c); /// Produce code that generates the given element if it is not yet present. - /// @returns the stack position of the element. - int generateClassElement(ExpressionClasses::Id _c); + /// @returns the stack position of the element or c_invalidPosition if it does not actually + /// generate a value on the stack. + /// @param _allowSequenced indicates that sequence-constrained operations are allowed + int generateClassElement(ExpressionClasses::Id _c, bool _allowSequenced = false); + /// @returns the position of the representative of the given id on the stack. + /// @note throws an exception if it is not on the stack. + int classElementPosition(ExpressionClasses::Id _id) const; /// @returns true if @a _element can be removed - in general or, if given, while computing @a _result. bool canBeRemoved(ExpressionClasses::Id _element, ExpressionClasses::Id _result = ExpressionClasses::Id(-1)); @@ -146,7 +188,7 @@ private: void appendDup(int _fromPosition); /// Appends a swap instruction to m_generatedItems to retrieve the element at the given stack position. /// @note this might also remove the last item if it exactly the same swap instruction. - void appendSwapOrRemove(int _fromPosition); + void appendOrRemoveSwap(int _fromPosition); /// Appends the given assembly item. void appendItem(AssemblyItem const& _item); @@ -163,7 +205,10 @@ private: std::map m_classPositions; /// The actual eqivalence class items and how to compute them. - ExpressionClasses const& m_expressionClasses; + ExpressionClasses& m_expressionClasses; + /// Keeps information about which storage slots were written to at which sequence number with + /// what SSTORE instruction. + std::set const& m_storageWrites; /// The set of equivalence classes that should be present on the stack at the end. std::set m_finalClasses; }; diff --git a/libevmcore/ExpressionClasses.cpp b/libevmcore/ExpressionClasses.cpp index b43b54113..298d11dbd 100644 --- a/libevmcore/ExpressionClasses.cpp +++ b/libevmcore/ExpressionClasses.cpp @@ -39,16 +39,22 @@ bool ExpressionClasses::Expression::operator<(ExpressionClasses::Expression cons { auto type = item->type(); auto otherType = _other.item->type(); - return std::tie(type, item->data(), arguments) < - std::tie(otherType, _other.item->data(), _other.arguments); + return std::tie(type, item->data(), arguments, sequenceNumber) < + std::tie(otherType, _other.item->data(), _other.arguments, _other.sequenceNumber); } -ExpressionClasses::Id ExpressionClasses::find(AssemblyItem const& _item, Ids const& _arguments) +ExpressionClasses::Id ExpressionClasses::find( + AssemblyItem const& _item, + Ids const& _arguments, + bool _copyItem, + unsigned _sequenceNumber +) { Expression exp; exp.id = Id(-1); exp.item = &_item; exp.arguments = _arguments; + exp.sequenceNumber = _sequenceNumber; if (SemanticInformation::isCommutativeOperation(_item)) sort(exp.arguments.begin(), exp.arguments.end()); @@ -58,9 +64,8 @@ ExpressionClasses::Id ExpressionClasses::find(AssemblyItem const& _item, Ids con if (!(e < exp || exp < e)) return e.id; - if (SemanticInformation::isDupInstruction(_item)) + if (_copyItem) { - // Special item that refers to values pre-existing on the stack m_spareAssemblyItem.push_back(make_shared(_item)); exp.item = m_spareAssemblyItem.back().get(); } @@ -74,6 +79,17 @@ ExpressionClasses::Id ExpressionClasses::find(AssemblyItem const& _item, Ids con return exp.id; } +bool ExpressionClasses::knownToBeDifferent(ExpressionClasses::Id _a, ExpressionClasses::Id _b) +{ + // Try to simplify "_a - _b" and return true iff the value is a non-zero constant. + //@todo we could try to cache this information + map matchGroups; + Pattern constant(Push); + constant.setMatchGroup(1, matchGroups); + Id difference = find(Instruction::SUB, {_a, _b}); + return constant.matches(representative(difference), *this) && constant.d() != u256(0); +} + string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const { Expression const& expr = representative(_id); @@ -189,27 +205,46 @@ Rules::Rules() // Moving constants to the outside, order matters here! // we need actions that return expressions (or patterns?) here, and we need also reversed rules // (X+A)+B -> X+(A+B) - m_rules.push_back({ + m_rules += vector>>{{ {op, {{op, {X, A}}, B}}, [=]() -> Pattern { return {op, {X, fun(A.d(), B.d())}}; } - }); + }, { // X+(Y+A) -> (X+Y)+A - m_rules.push_back({ {op, {{op, {X, A}}, Y}}, [=]() -> Pattern { return {op, {{op, {X, Y}}, A}}; } - }); + }, { // For now, we still need explicit commutativity for the inner pattern - m_rules.push_back({ {op, {{op, {A, X}}, B}}, [=]() -> Pattern { return {op, {X, fun(A.d(), B.d())}}; } - }); - m_rules.push_back({ + }, { {op, {{op, {A, X}}, Y}}, [=]() -> Pattern { return {op, {{op, {X, Y}}, A}}; } - }); + }}; + } + // move constants across subtractions + m_rules += vector>>{ + { + // X - A -> X + (-A) + {Instruction::SUB, {X, A}}, + [=]() -> Pattern { return {Instruction::ADD, {X, 0 - A.d()}}; } + }, { + // (X + A) - Y -> (X - Y) + A + {Instruction::SUB, {{Instruction::ADD, {X, A}}, Y}}, + [=]() -> Pattern { return {Instruction::ADD, {{Instruction::SUB, {X, Y}}, A}}; } + }, { + // (A + X) - Y -> (X - Y) + A + {Instruction::SUB, {{Instruction::ADD, {A, X}}, Y}}, + [=]() -> Pattern { return {Instruction::ADD, {{Instruction::SUB, {X, Y}}, A}}; } + }, { + // X - (Y + A) -> (X - Y) + (-A) + {Instruction::SUB, {X, {Instruction::ADD, {Y, A}}}}, + [=]() -> Pattern { return {Instruction::ADD, {{Instruction::SUB, {X, Y}}, 0 - A.d()}}; } + }, { + // X - (A + Y) -> (X - Y) + (-A) + {Instruction::SUB, {X, {Instruction::ADD, {A, Y}}}}, + [=]() -> Pattern { return {Instruction::ADD, {{Instruction::SUB, {X, Y}}, 0 - A.d()}}; } + } }; - - //@todo: (x+8)-3 and other things } ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr, bool _secondRun) @@ -231,7 +266,7 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr, //cout << ")" << endl; //cout << "with rule " << rule.first.toString() << endl; //ExpressionTemplate t(rule.second()); - //cout << "to" << rule.second().toString() << endl; + //cout << "to " << rule.second().toString() << endl; return rebuildExpression(ExpressionTemplate(rule.second())); } } @@ -254,8 +289,7 @@ ExpressionClasses::Id ExpressionClasses::rebuildExpression(ExpressionTemplate co Ids arguments; for (ExpressionTemplate const& t: _template.arguments) arguments.push_back(rebuildExpression(t)); - m_spareAssemblyItem.push_back(make_shared(_template.item)); - return find(*m_spareAssemblyItem.back(), arguments); + return find(_template.item, arguments); } diff --git a/libevmcore/ExpressionClasses.h b/libevmcore/ExpressionClasses.h index eda568e23..b7868ebb9 100644 --- a/libevmcore/ExpressionClasses.h +++ b/libevmcore/ExpressionClasses.h @@ -52,17 +52,25 @@ public: Id id; AssemblyItem const* item; Ids arguments; + unsigned sequenceNumber; ///< Storage modification sequence, only used for SLOAD/SSTORE instructions. bool operator<(Expression const& _other) const; }; /// Retrieves the id of the expression equivalence class resulting from the given item applied to the /// given classes, might also create a new one. - Id find(AssemblyItem const& _item, Ids const& _arguments = {}); + /// @param _copyItem if true, copies the assembly item to an internal storage instead of just + /// keeping a pointer. + /// The @a _sequenceNumber indicates the current storage access sequence. + Id find(AssemblyItem const& _item, Ids const& _arguments = {}, bool _copyItem = true, unsigned _sequenceNumber = 0); /// @returns the canonical representative of an expression class. Expression const& representative(Id _id) const { return m_representatives.at(_id); } /// @returns the number of classes. Id size() const { return m_representatives.size(); } + /// @returns true if the values of the given classes are known to be different (on every input). + /// @note that this function might still return false for some different inputs. + bool knownToBeDifferent(Id _a, Id _b); + std::string fullDAGToString(Id _id) const; private: diff --git a/test/SolidityOptimizer.cpp b/test/SolidityOptimizer.cpp index 2d5cff7ac..de4cac8fd 100644 --- a/test/SolidityOptimizer.cpp +++ b/test/SolidityOptimizer.cpp @@ -303,6 +303,186 @@ BOOST_AUTO_TEST_CASE(cse_associativity2) checkCSE(input, {Instruction::DUP2, Instruction::DUP2, Instruction::ADD, u256(5), Instruction::ADD}); } +BOOST_AUTO_TEST_CASE(cse_storage) +{ + AssemblyItems input{ + u256(0), + Instruction::SLOAD, + u256(0), + Instruction::SLOAD, + Instruction::ADD, + u256(0), + Instruction::SSTORE + }; + checkCSE(input, { + u256(0), + Instruction::DUP1, + Instruction::SLOAD, + Instruction::DUP1, + Instruction::ADD, + Instruction::SWAP1, + Instruction::SSTORE + }); +} + +BOOST_AUTO_TEST_CASE(cse_noninterleaved_storage) +{ + // two stores to the same location should be replaced by only one store, even if we + // read in the meantime + AssemblyItems input{ + u256(7), + Instruction::DUP2, + Instruction::SSTORE, + Instruction::DUP1, + Instruction::SLOAD, + u256(8), + Instruction::DUP3, + Instruction::SSTORE + }; + checkCSE(input, { + u256(8), + Instruction::DUP2, + Instruction::SSTORE, + u256(7) + }); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage) +{ + // stores and reads to/from two unknown locations, should not optimize away the first store + AssemblyItems input{ + u256(7), + Instruction::DUP2, + Instruction::SSTORE, // store to "DUP1" + Instruction::DUP2, + Instruction::SLOAD, // read from "DUP2", might be equal to "DUP1" + u256(0), + Instruction::DUP3, + Instruction::SSTORE // store different value to "DUP1" + }; + checkCSE(input, input); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage_same_value) +{ + // stores and reads to/from two unknown locations, should not optimize away the first store + // but it should optimize away the second, since we already know the value will be the same + AssemblyItems input{ + u256(7), + Instruction::DUP2, + Instruction::SSTORE, // store to "DUP1" + Instruction::DUP2, + Instruction::SLOAD, // read from "DUP2", might be equal to "DUP1" + u256(6), + u256(1), + Instruction::ADD, + Instruction::DUP3, + Instruction::SSTORE // store same value to "DUP1" + }; + checkCSE(input, { + u256(7), + Instruction::DUP2, + Instruction::SSTORE, + Instruction::DUP2, + Instruction::SLOAD + }); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage_at_known_location) +{ + // stores and reads to/from two known locations, should optimize away the first store, + // because we know that the location is different + AssemblyItems input{ + u256(0x70), + u256(1), + Instruction::SSTORE, // store to 1 + u256(2), + Instruction::SLOAD, // read from 2, is different from 1 + u256(0x90), + u256(1), + Instruction::SSTORE // store different value at 1 + }; + checkCSE(input, { + u256(2), + Instruction::SLOAD, + u256(0x90), + u256(1), + Instruction::SSTORE + }); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage_at_known_location_offset) +{ + // stores and reads to/from two locations which are known to be different, + // should optimize away the first store, because we know that the location is different + AssemblyItems input{ + u256(0x70), + Instruction::DUP2, + u256(1), + Instruction::ADD, + Instruction::SSTORE, // store to "DUP1"+1 + Instruction::DUP1, + u256(2), + Instruction::ADD, + Instruction::SLOAD, // read from "DUP1"+2, is different from "DUP1"+1 + u256(0x90), + Instruction::DUP3, + u256(1), + Instruction::ADD, + Instruction::SSTORE // store different value at "DUP1"+1 + }; + checkCSE(input, { + u256(2), + Instruction::DUP2, + Instruction::ADD, + Instruction::SLOAD, + u256(0x90), + u256(1), + Instruction::DUP4, + Instruction::ADD, + Instruction::SSTORE + }); +} + +BOOST_AUTO_TEST_CASE(cse_deep_stack) +{ + AssemblyItems input{ + Instruction::ADD, + Instruction::SWAP1, + Instruction::POP, + Instruction::SWAP8, + Instruction::POP, + Instruction::SWAP8, + Instruction::POP, + Instruction::SWAP8, + Instruction::SWAP5, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + }; + checkCSE(input, { + Instruction::SWAP4, + Instruction::SWAP12, + Instruction::SWAP3, + Instruction::SWAP11, + Instruction::POP, + Instruction::SWAP1, + Instruction::SWAP3, + Instruction::ADD, + Instruction::SWAP8, + Instruction::POP, + Instruction::SWAP6, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + }); +} + BOOST_AUTO_TEST_SUITE_END() } From c19229415d0f9704d5c9e6ac11733824a56dec20 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 25 Mar 2015 18:42:18 +0100 Subject: [PATCH 06/50] Some optimizations to the optimizer. --- libevmcore/ExpressionClasses.cpp | 19 ++++++++++--------- libevmcore/ExpressionClasses.h | 3 +++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libevmcore/ExpressionClasses.cpp b/libevmcore/ExpressionClasses.cpp index 298d11dbd..717379be5 100644 --- a/libevmcore/ExpressionClasses.cpp +++ b/libevmcore/ExpressionClasses.cpp @@ -59,10 +59,9 @@ ExpressionClasses::Id ExpressionClasses::find( if (SemanticInformation::isCommutativeOperation(_item)) sort(exp.arguments.begin(), exp.arguments.end()); - //@todo store all class members (not only the representatives) in an efficient data structure to search here - for (Expression const& e: m_representatives) - if (!(e < exp || exp < e)) - return e.id; + auto it = m_expressions.find(exp); + if (it != m_expressions.end()) + return it->id; if (_copyItem) { @@ -72,17 +71,19 @@ ExpressionClasses::Id ExpressionClasses::find( ExpressionClasses::Id id = tryToSimplify(exp); if (id < m_representatives.size()) - return id; - - exp.id = m_representatives.size(); - m_representatives.push_back(exp); + exp.id = id; + else + { + exp.id = m_representatives.size(); + m_representatives.push_back(exp); + } + m_expressions.insert(exp); return exp.id; } bool ExpressionClasses::knownToBeDifferent(ExpressionClasses::Id _a, ExpressionClasses::Id _b) { // Try to simplify "_a - _b" and return true iff the value is a non-zero constant. - //@todo we could try to cache this information map matchGroups; Pattern constant(Push); constant.setMatchGroup(1, matchGroups); diff --git a/libevmcore/ExpressionClasses.h b/libevmcore/ExpressionClasses.h index b7868ebb9..15824f6ad 100644 --- a/libevmcore/ExpressionClasses.h +++ b/libevmcore/ExpressionClasses.h @@ -53,6 +53,7 @@ public: AssemblyItem const* item; Ids arguments; unsigned sequenceNumber; ///< Storage modification sequence, only used for SLOAD/SSTORE instructions. + /// Behaves as if this was a tuple of (item->type(), item->data(), arguments, sequenceNumber). bool operator<(Expression const& _other) const; }; @@ -86,6 +87,8 @@ private: /// Expression equivalence class representatives - we only store one item of an equivalence. std::vector m_representatives; + /// All expression ever encountered. + std::set m_expressions; std::vector> m_spareAssemblyItem; }; From 9da4c207a3cdfc65096060f7069a452451ef293a Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 26 Mar 2015 13:03:24 +0100 Subject: [PATCH 07/50] Change to storage operations. --- libevmcore/CommonSubexpressionEliminator.cpp | 81 ++++++++++---------- libevmcore/CommonSubexpressionEliminator.h | 36 ++++----- libevmcore/ExpressionClasses.h | 9 ++- 3 files changed, 63 insertions(+), 63 deletions(-) diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index 43d01fc85..6002de758 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -45,7 +45,7 @@ vector CommonSubexpressionEliminator::getOptimizedItems() // Debug info: //stream(cout, initialStackContents, targetStackContents); - return CSECodeGenerator(m_expressionClasses, m_storageWrites).generateCode( + return CSECodeGenerator(m_expressionClasses, m_storeOperations).generateCode( initialStackContents, targetStackContents ); @@ -172,7 +172,7 @@ void CommonSubexpressionEliminator::storeInStorage(ExpressionClasses::Id _slot, storageContents.insert(storageItem); m_storageContent = move(storageContents); ExpressionClasses::Id id = m_expressionClasses.find(Instruction::SSTORE, {_slot, _value}, true, m_sequenceNumber); - m_storageWrites.insert(StorageWriteOperation(_slot, m_sequenceNumber, id)); + m_storeOperations.push_back(StoreOperation(_slot, m_sequenceNumber, id)); m_storageContent[_slot] = _value; // increment a second time so that we get unique sequence numbers for writes m_sequenceNumber ++; @@ -249,6 +249,16 @@ bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) return Instruction::SWAP1 <= _item.instruction() && _item.instruction() <= Instruction::SWAP16; } +CSECodeGenerator::CSECodeGenerator( + ExpressionClasses& _expressionClasses, + vector const& _storeOperations +): + m_expressionClasses(_expressionClasses) +{ + for (auto const& store: _storeOperations) + m_storeOperations[store.slot].push_back(store); +} + AssemblyItems CSECodeGenerator::generateCode( map const& _initialStack, map const& _targetStackContents @@ -261,35 +271,26 @@ AssemblyItems CSECodeGenerator::generateCode( // @todo: provide information about the positions of copies of class elements - // generate the dependency graph starting from final storage writes and target stack contents - for (auto it = m_storageWrites.begin(); it != m_storageWrites.end();) - { - auto next = it; - ++next; - if (next == m_storageWrites.end() || next->slot != it->slot) - // last write to that storage slot - addDependencies(it->expression); - it = next; - } + // generate the dependency graph starting from final storage and memory writes and target stack contents + for (auto const& p: m_storeOperations) + addDependencies(p.second.back().expression); for (auto const& targetItem: _targetStackContents) { m_finalClasses.insert(targetItem.second); addDependencies(targetItem.second); } - // Perform all operations on storage in order, if they are needed. - //@todo use better data structures to optimize these loops - unsigned maxSequenceNumber = 1; - for (StorageWriteOperation const& op: m_storageWrites) - maxSequenceNumber = max(maxSequenceNumber, op.sequenceNumber + 1); - for (unsigned sequenceNumber = 1; sequenceNumber <= maxSequenceNumber; ++sequenceNumber) - for (auto const& depPair: m_neededBy) - for (ExpressionClasses::Id const& id: {depPair.first, depPair.second}) - if ( - m_expressionClasses.representative(id).sequenceNumber == sequenceNumber && - !m_classPositions.count(id) - ) - generateClassElement(id, true); + // store all needed sequenced expressions + set> sequencedExpressions; + for (auto const& p: m_neededBy) + for (auto id: {p.first, p.second}) + if (unsigned seqNr = m_expressionClasses.representative(id).sequenceNumber) + sequencedExpressions.insert(make_pair(seqNr, id)); + + // Perform all operations on storage and memory in order, if they are needed. + for (auto const& seqAndId: sequencedExpressions) + if (!m_classPositions.count(seqAndId.second)) + generateClassElement(seqAndId.second, true); // generate the target stack elements for (auto const& targetItem: _targetStackContents) @@ -340,23 +341,25 @@ void CSECodeGenerator::addDependencies(ExpressionClasses::Id _c) if (expr.item->type() == Operation && expr.item->instruction() == Instruction::SLOAD) { // this loads an unknown value from storage and thus, in addition to its arguments, depends - // on all SSTORE operations to addresses where we do not know that they are different that - // occur before this SLOAD + // on all store operations to addresses where we do not know that they are different that + // occur before this load ExpressionClasses::Id slotToLoadFrom = expr.arguments.at(0); - for (auto it = m_storageWrites.begin(); it != m_storageWrites.end();) + for (auto const& p: m_storeOperations) { - auto next = it; - ++next; - // note that SSTORE and SLOAD never have the same sequence number - if (it->sequenceNumber < expr.sequenceNumber && - !m_expressionClasses.knownToBeDifferent(it->slot, slotToLoadFrom) && - (next == m_storageWrites.end() || next->sequenceNumber > expr.sequenceNumber) + ExpressionClasses::Id slot = p.first; + StoreOperations const& storeOps = p.second; + if ( + m_expressionClasses.knownToBeDifferent(slot, slotToLoadFrom) || + storeOps.front().sequenceNumber > expr.sequenceNumber ) - { - addDependencies(it->expression); - m_neededBy.insert(make_pair(it->expression, _c)); - } - it = next; + continue; + // note that store and load never have the same sequence number + ExpressionClasses::Id latestStore = storeOps.front().expression; + for (auto it = ++storeOps.begin(); it != storeOps.end(); ++it) + if (it->sequenceNumber < expr.sequenceNumber) + latestStore = it->expression; + addDependencies(latestStore); + m_neededBy.insert(make_pair(latestStore, _c)); } } } diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index c3e291afb..c4d960d91 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -56,18 +56,13 @@ using AssemblyItems = std::vector; class CommonSubexpressionEliminator { public: - struct StorageWriteOperation + struct StoreOperation { - StorageWriteOperation( + StoreOperation( ExpressionClasses::Id _slot, unsigned _sequenceNumber, ExpressionClasses::Id _expression ): slot(_slot), sequenceNumber(_sequenceNumber), expression(_expression) {} - bool operator<(StorageWriteOperation const& _other) const - { - return std::tie(slot, sequenceNumber, expression) < - std::tie(_other.slot, _other.sequenceNumber, _other.expression); - } ExpressionClasses::Id slot; unsigned sequenceNumber; ExpressionClasses::Id expression; @@ -114,13 +109,13 @@ private: int m_stackHeight = 0; /// Current stack layout, mapping stack height -> equivalence class std::map m_stackElements; - /// Current sequence number, this is incremented with each modification to storage. + /// Current sequence number, this is incremented with each modification to storage or memory. unsigned m_sequenceNumber = 1; /// Knowledge about storage content. std::map m_storageContent; - /// Keeps information about which storage slots were written to at which sequence number with - /// what SSTORE instruction. - std::set m_storageWrites; + /// Keeps information about which storage or memory slots were written to at which sequence + /// number with what instruction. + std::vector m_storeOperations; /// Structure containing the classes of equivalent expressions. ExpressionClasses m_expressionClasses; }; @@ -146,15 +141,12 @@ struct SemanticInformation class CSECodeGenerator { public: - using StorageWriteOperation = CommonSubexpressionEliminator::StorageWriteOperation; + using StoreOperation = CommonSubexpressionEliminator::StoreOperation; + using StoreOperations = std::vector; - CSECodeGenerator( - ExpressionClasses& _expressionClasses, - std::set const& _storageWrites - ): - m_expressionClasses(_expressionClasses), - m_storageWrites(_storageWrites) - {} + /// Initializes the code generator with the given classes and store operations. + /// The store operations have to be sorted ascendingly by sequence number. + CSECodeGenerator(ExpressionClasses& _expressionClasses, StoreOperations const& _storeOperations); /// @returns the assembly items generated from the given requirements /// @param _initialStack current contents of the stack (up to stack height of zero) @@ -206,9 +198,9 @@ private: /// The actual eqivalence class items and how to compute them. ExpressionClasses& m_expressionClasses; - /// Keeps information about which storage slots were written to at which sequence number with - /// what SSTORE instruction. - std::set const& m_storageWrites; + /// Keeps information about which storage or memory slots were written to by which operations. + /// The operations are sorted ascendingly by sequence number. + std::map m_storeOperations; /// The set of equivalence classes that should be present on the stack at the end. std::set m_finalClasses; }; diff --git a/libevmcore/ExpressionClasses.h b/libevmcore/ExpressionClasses.h index 15824f6ad..d76fd693d 100644 --- a/libevmcore/ExpressionClasses.h +++ b/libevmcore/ExpressionClasses.h @@ -61,8 +61,13 @@ public: /// given classes, might also create a new one. /// @param _copyItem if true, copies the assembly item to an internal storage instead of just /// keeping a pointer. - /// The @a _sequenceNumber indicates the current storage access sequence. - Id find(AssemblyItem const& _item, Ids const& _arguments = {}, bool _copyItem = true, unsigned _sequenceNumber = 0); + /// The @a _sequenceNumber indicates the current storage or memory access sequence. + Id find( + AssemblyItem const& _item, + Ids const& _arguments = {}, + bool _copyItem = true, + unsigned _sequenceNumber = 0 + ); /// @returns the canonical representative of an expression class. Expression const& representative(Id _id) const { return m_representatives.at(_id); } /// @returns the number of classes. From d6a611429f39d726672db6331db86e7d5306a05d Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 26 Mar 2015 15:50:50 +0100 Subject: [PATCH 08/50] Optimizer for memory. --- libevmcore/CommonSubexpressionEliminator.cpp | 70 +++++++++++++++++--- libevmcore/CommonSubexpressionEliminator.h | 16 ++++- libevmcore/ExpressionClasses.cpp | 13 ++++ libevmcore/ExpressionClasses.h | 2 + test/SolidityOptimizer.cpp | 53 +++++++++++++++ 5 files changed, 142 insertions(+), 12 deletions(-) diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index 6002de758..1d2a71836 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -121,6 +121,10 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) storeInStorage(arguments[0], arguments[1]); else if (_item.instruction() == Instruction::SLOAD) setStackElement(m_stackHeight + _item.deposit(), loadFromStorage(arguments[0])); + else if (_item.instruction() == Instruction::MSTORE) + storeInMemory(arguments[0], arguments[1]); + else if (_item.instruction() == Instruction::MLOAD) + setStackElement(m_stackHeight + _item.deposit(), loadFromMemory(arguments[0])); else setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, false)); } @@ -172,7 +176,7 @@ void CommonSubexpressionEliminator::storeInStorage(ExpressionClasses::Id _slot, storageContents.insert(storageItem); m_storageContent = move(storageContents); ExpressionClasses::Id id = m_expressionClasses.find(Instruction::SSTORE, {_slot, _value}, true, m_sequenceNumber); - m_storeOperations.push_back(StoreOperation(_slot, m_sequenceNumber, id)); + m_storeOperations.push_back(StoreOperation(StoreOperation::Storage, _slot, m_sequenceNumber, id)); m_storageContent[_slot] = _value; // increment a second time so that we get unique sequence numbers for writes m_sequenceNumber ++; @@ -186,6 +190,33 @@ ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(ExpressionC return m_storageContent[_slot] = m_expressionClasses.find(Instruction::SLOAD, {_slot}, true, m_sequenceNumber); } +void CommonSubexpressionEliminator::storeInMemory(ExpressionClasses::Id _slot, ExpressionClasses::Id _value) +{ + if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value) + // do not execute the store if we know that the value is already there + return; + m_sequenceNumber ++; + decltype(m_memoryContent) memoryContents; + // copy over values at points where we know that they are different from _slot by at least 32 + for (auto const& memoryItem: m_memoryContent) + if (m_expressionClasses.knownToBeDifferentBy32(memoryItem.first, _slot)) + memoryContents.insert(memoryItem); + m_memoryContent = move(memoryContents); + ExpressionClasses::Id id = m_expressionClasses.find(Instruction::MSTORE, {_slot, _value}, true, m_sequenceNumber); + m_storeOperations.push_back(StoreOperation(StoreOperation::Memory, _slot, m_sequenceNumber, id)); + m_memoryContent[_slot] = _value; + // increment a second time so that we get unique sequence numbers for writes + m_sequenceNumber ++; +} + +ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(ExpressionClasses::Id _slot) +{ + if (m_memoryContent.count(_slot)) + return m_memoryContent.at(_slot); + else + return m_memoryContent[_slot] = m_expressionClasses.find(Instruction::MLOAD, {_slot}, true, m_sequenceNumber); +} + bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) { switch (_item.type()) @@ -208,9 +239,19 @@ bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) return false; if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC) return true; // GAS and PC assume a specific order of opcodes + if (_item.instruction() == Instruction::MSIZE) + return true; // msize is modified already by memory access, avoid that for now + if (_item.instruction() == Instruction::SHA3) + return true; //@todo: we have to compare sha3's not based on their memory addresses but on the memory content. InstructionInfo info = instructionInfo(_item.instruction()); if (_item.instruction() == Instruction::SSTORE) return false; + if (_item.instruction() == Instruction::MSTORE) + return false; + //@todo: We do not handle the following memory instructions for now: + // calldatacopy, codecopy, extcodecopy, mstore8, + // msize (not that msize also depends on memory read access) + // the second requirement will be lifted once it is implemented return info.sideEffects || info.args > 2; } @@ -256,7 +297,7 @@ CSECodeGenerator::CSECodeGenerator( m_expressionClasses(_expressionClasses) { for (auto const& store: _storeOperations) - m_storeOperations[store.slot].push_back(store); + m_storeOperations[make_pair(store.target, store.slot)].push_back(store); } AssemblyItems CSECodeGenerator::generateCode( @@ -332,25 +373,34 @@ void CSECodeGenerator::addDependencies(ExpressionClasses::Id _c) { if (m_neededBy.count(_c)) return; // we already computed the dependencies for _c - ExpressionClasses::Expression const& expr = m_expressionClasses.representative(_c); + ExpressionClasses::Expression expr = m_expressionClasses.representative(_c); for (ExpressionClasses::Id argument: expr.arguments) { addDependencies(argument); m_neededBy.insert(make_pair(argument, _c)); } - if (expr.item->type() == Operation && expr.item->instruction() == Instruction::SLOAD) + if (expr.item->type() == Operation && ( + expr.item->instruction() == Instruction::SLOAD || + expr.item->instruction() == Instruction::MLOAD + )) { - // this loads an unknown value from storage and thus, in addition to its arguments, depends - // on all store operations to addresses where we do not know that they are different that - // occur before this load + // this loads an unknown value from storage or memory and thus, in addition to its + // arguments, depends on all store operations to addresses where we do not know that + // they are different that occur before this load + StoreOperation::Target target = expr.item->instruction() == Instruction::SLOAD ? + StoreOperation::Storage : StoreOperation::Memory; ExpressionClasses::Id slotToLoadFrom = expr.arguments.at(0); for (auto const& p: m_storeOperations) { - ExpressionClasses::Id slot = p.first; + if (p.first.first != target) + continue; + ExpressionClasses::Id slot = p.first.second; StoreOperations const& storeOps = p.second; + if (storeOps.front().sequenceNumber > expr.sequenceNumber) + continue; if ( - m_expressionClasses.knownToBeDifferent(slot, slotToLoadFrom) || - storeOps.front().sequenceNumber > expr.sequenceNumber + (target == StoreOperation::Memory && m_expressionClasses.knownToBeDifferentBy32(slot, slotToLoadFrom)) || + (target == StoreOperation::Storage && m_expressionClasses.knownToBeDifferent(slot, slotToLoadFrom)) ) continue; // note that store and load never have the same sequence number diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index c4d960d91..03f8cf987 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -58,11 +58,14 @@ class CommonSubexpressionEliminator public: struct StoreOperation { + enum Target { Memory, Storage }; StoreOperation( + Target _target, ExpressionClasses::Id _slot, unsigned _sequenceNumber, ExpressionClasses::Id _expression - ): slot(_slot), sequenceNumber(_sequenceNumber), expression(_expression) {} + ): target(_target), slot(_slot), sequenceNumber(_sequenceNumber), expression(_expression) {} + Target target; ExpressionClasses::Id slot; unsigned sequenceNumber; ExpressionClasses::Id expression; @@ -104,6 +107,12 @@ private: void storeInStorage(ExpressionClasses::Id _slot, ExpressionClasses::Id _value); /// Retrieves the current value at the given slot in storage or creates a new special sload class. ExpressionClasses::Id loadFromStorage(ExpressionClasses::Id _slot); + /// Increments the sequence number, deletes all memory information that might be overwritten + /// and stores the new value at the given slot. + void storeInMemory(ExpressionClasses::Id _slot, ExpressionClasses::Id _value); + /// Retrieves the current value at the given slot in memory or creates a new special mload class. + ExpressionClasses::Id loadFromMemory(ExpressionClasses::Id _slot); + /// Current stack height, can be negative. int m_stackHeight = 0; @@ -113,6 +122,9 @@ private: unsigned m_sequenceNumber = 1; /// Knowledge about storage content. std::map m_storageContent; + /// Knowledge about memory content. Keys are memory addresses, note that the values overlap + /// and are not contained here if they are not completely known. + std::map m_memoryContent; /// Keeps information about which storage or memory slots were written to at which sequence /// number with what instruction. std::vector m_storeOperations; @@ -200,7 +212,7 @@ private: ExpressionClasses& m_expressionClasses; /// Keeps information about which storage or memory slots were written to by which operations. /// The operations are sorted ascendingly by sequence number. - std::map m_storeOperations; + std::map, StoreOperations> m_storeOperations; /// The set of equivalence classes that should be present on the stack at the end. std::set m_finalClasses; }; diff --git a/libevmcore/ExpressionClasses.cpp b/libevmcore/ExpressionClasses.cpp index 717379be5..1c7a79e6b 100644 --- a/libevmcore/ExpressionClasses.cpp +++ b/libevmcore/ExpressionClasses.cpp @@ -91,6 +91,19 @@ bool ExpressionClasses::knownToBeDifferent(ExpressionClasses::Id _a, ExpressionC return constant.matches(representative(difference), *this) && constant.d() != u256(0); } +bool ExpressionClasses::knownToBeDifferentBy32(ExpressionClasses::Id _a, ExpressionClasses::Id _b) +{ + // Try to simplify "_a - _b" and return true iff the value is at least 32 away from zero. + map matchGroups; + Pattern constant(Push); + constant.setMatchGroup(1, matchGroups); + Id difference = find(Instruction::SUB, {_a, _b}); + if (!constant.matches(representative(difference), *this)) + return false; + // forbidden interval is ["-31", 31] + return constant.d() + 31 > u256(62); +} + string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const { Expression const& expr = representative(_id); diff --git a/libevmcore/ExpressionClasses.h b/libevmcore/ExpressionClasses.h index d76fd693d..5179845f6 100644 --- a/libevmcore/ExpressionClasses.h +++ b/libevmcore/ExpressionClasses.h @@ -76,6 +76,8 @@ public: /// @returns true if the values of the given classes are known to be different (on every input). /// @note that this function might still return false for some different inputs. bool knownToBeDifferent(Id _a, Id _b); + /// Similar to @a knownToBeDifferent but require that abs(_a - b) >= 32. + bool knownToBeDifferentBy32(Id _a, Id _b); std::string fullDAGToString(Id _id) const; diff --git a/test/SolidityOptimizer.cpp b/test/SolidityOptimizer.cpp index de4cac8fd..cf35536e6 100644 --- a/test/SolidityOptimizer.cpp +++ b/test/SolidityOptimizer.cpp @@ -444,6 +444,59 @@ BOOST_AUTO_TEST_CASE(cse_interleaved_storage_at_known_location_offset) }); } +BOOST_AUTO_TEST_CASE(cse_interleaved_memory_at_known_location_offset) +{ + // stores and reads to/from two locations which are known to be different, + // should not optimize away the first store, because the location overlaps with the load, + // but it should optimize away the second, because we know that the location is different by 32 + AssemblyItems input{ + u256(0x50), + Instruction::DUP2, + u256(2), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+2] = 0x50 + u256(0x60), + Instruction::DUP2, + u256(32), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+32] = 0x60 + Instruction::DUP1, + Instruction::MLOAD, // read from "DUP1" + u256(0x70), + Instruction::DUP3, + u256(32), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+32] = 0x70 + u256(0x80), + Instruction::DUP3, + u256(2), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+2] = 0x80 + }; + // If the actual code changes too much, we could also simply check that the output contains + // exactly 3 MSTORE and exactly 1 MLOAD instruction. + checkCSE(input, { + u256(0x50), + u256(2), + Instruction::DUP3, + Instruction::ADD, + Instruction::SWAP1, + Instruction::DUP2, + Instruction::MSTORE, // ["DUP1"+2] = 0x50 + Instruction::DUP2, + Instruction::MLOAD, // read from "DUP1" + u256(0x70), + u256(32), + Instruction::DUP5, + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+32] = 0x70 + u256(0x80), + Instruction::SWAP1, + Instruction::SWAP2, + Instruction::MSTORE // ["DUP1"+2] = 0x80 + }); +} + BOOST_AUTO_TEST_CASE(cse_deep_stack) { AssemblyItems input{ From b1ea943975e0986e1711cce2a8b3d3ad41f3ae10 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 27 Mar 2015 00:24:31 +0100 Subject: [PATCH 09/50] Optimize breaking item. --- libevmcore/Assembly.cpp | 15 +------- libevmcore/CommonSubexpressionEliminator.cpp | 39 ++++++++++++++++++-- libevmcore/CommonSubexpressionEliminator.h | 11 +++++- test/SolidityOptimizer.cpp | 32 ++++++++++++++++ 4 files changed, 78 insertions(+), 19 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index abe932282..0301c9325 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -187,18 +187,7 @@ Assembly& Assembly::optimise(bool _enable) { if (!_enable) return *this; - std::vector>> rules = - { - { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { PushTag, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { PushString, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { PushSub, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { PushSubSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { PushProgramSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } }, - { { Instruction::ISZERO, Instruction::ISZERO }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - }; - + std::vector>> rules; // jump to next instruction rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }}); @@ -235,8 +224,6 @@ Assembly& Assembly::optimise(bool _enable) *orig = move(*moveIter); iter = m_items.erase(orig, iter); } - if (iter != m_items.end()) - ++iter; } for (unsigned i = 0; i < m_items.size(); ++i) diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index 1d2a71836..cc2fdc8bd 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -32,6 +32,8 @@ using namespace dev::eth; vector CommonSubexpressionEliminator::getOptimizedItems() { + optimizeBreakingItem(); + map initialStackContents; map targetStackContents; int minHeight = m_stackHeight + 1; @@ -45,10 +47,13 @@ vector CommonSubexpressionEliminator::getOptimizedItems() // Debug info: //stream(cout, initialStackContents, targetStackContents); - return CSECodeGenerator(m_expressionClasses, m_storeOperations).generateCode( + AssemblyItems items = CSECodeGenerator(m_expressionClasses, m_storeOperations).generateCode( initialStackContents, targetStackContents ); + if (m_breakingItem) + items.push_back(*m_breakingItem); + return items; } ostream& CommonSubexpressionEliminator::stream( @@ -91,12 +96,12 @@ ostream& CommonSubexpressionEliminator::stream( return _out; } -void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) +void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item, bool _copyItem) { if (_item.type() != Operation) { assertThrow(_item.deposit() == 1, InvalidDeposit, ""); - setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {}, false)); + setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {}, _copyItem)); } else { @@ -126,12 +131,38 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) else if (_item.instruction() == Instruction::MLOAD) setStackElement(m_stackHeight + _item.deposit(), loadFromMemory(arguments[0])); else - setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, false)); + setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, _copyItem)); } m_stackHeight += _item.deposit(); } } +void CommonSubexpressionEliminator::optimizeBreakingItem() +{ + if (!m_breakingItem || *m_breakingItem != AssemblyItem(Instruction::JUMPI)) + return; + + using Id = ExpressionClasses::Id; + static AssemblyItem s_jump = Instruction::JUMP; + + Id condition = stackElement(m_stackHeight - 1); + Id zero = m_expressionClasses.find(u256(0)); + if (m_expressionClasses.knownToBeDifferent(condition, zero)) + { + feedItem(Instruction::SWAP1, true); + feedItem(Instruction::POP, true); + m_breakingItem = &s_jump; + return; + } + Id negatedCondition = m_expressionClasses.find(Instruction::ISZERO, {condition}); + if (m_expressionClasses.knownToBeDifferent(negatedCondition, zero)) + { + feedItem(Instruction::POP, true); + feedItem(Instruction::POP, true); + m_breakingItem = nullptr; + } +} + void CommonSubexpressionEliminator::setStackElement(int _stackHeight, ExpressionClasses::Id _class) { m_stackElements[_stackHeight] = _class; diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index 03f8cf987..09368f7d2 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -88,7 +88,10 @@ public: private: /// Feeds the item into the system for analysis. - void feedItem(AssemblyItem const& _item); + void feedItem(AssemblyItem const& _item, bool _copyItem = false); + + /// Tries to optimize the item that breaks the basic block at the end. + void optimizeBreakingItem(); /// Simplifies the given item using /// Assigns a new equivalence class to the next sequence number of the given stack element. @@ -130,6 +133,10 @@ private: std::vector m_storeOperations; /// Structure containing the classes of equivalent expressions. ExpressionClasses m_expressionClasses; + + /// The item that breaks the basic block, can be nullptr. + /// It is usually appended to the block but can be optimized in some cases. + AssemblyItem const* m_breakingItem = nullptr; }; /** @@ -225,6 +232,8 @@ _AssemblyItemIterator CommonSubexpressionEliminator::feedItems( { for (; _iterator != _end && !SemanticInformation::breaksBasicBlock(*_iterator); ++_iterator) feedItem(*_iterator); + if (_iterator != _end) + m_breakingItem = &(*_iterator++); return _iterator; } diff --git a/test/SolidityOptimizer.cpp b/test/SolidityOptimizer.cpp index cf35536e6..e69d5120e 100644 --- a/test/SolidityOptimizer.cpp +++ b/test/SolidityOptimizer.cpp @@ -536,6 +536,38 @@ BOOST_AUTO_TEST_CASE(cse_deep_stack) }); } +BOOST_AUTO_TEST_CASE(cse_jumpi_no_jump) +{ + AssemblyItems input{ + u256(0), + u256(1), + Instruction::DUP2, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + checkCSE(input, { + u256(0), + u256(1) + }); +} + +BOOST_AUTO_TEST_CASE(cse_jumpi_jump) +{ + AssemblyItems input{ + u256(1), + u256(1), + Instruction::DUP2, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + checkCSE(input, { + u256(1), + Instruction::DUP1, + AssemblyItem(PushTag, 1), + Instruction::JUMP + }); +} + BOOST_AUTO_TEST_SUITE_END() } From df4f1258e849744920addadf3e22e256820d0857 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 30 Mar 2015 14:02:27 +0200 Subject: [PATCH 10/50] failing tests for getting genesis block --- test/ClientBase.cpp | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/test/ClientBase.cpp b/test/ClientBase.cpp index 2197ac830..304182cfc 100644 --- a/test/ClientBase.cpp +++ b/test/ClientBase.cpp @@ -34,34 +34,45 @@ BOOST_AUTO_TEST_CASE(blocks) { enumerateClients([](Json::Value const& _json, dev::eth::ClientBase& _client) -> void { - for (string const& name: _json["postState"].getMemberNames()) + auto compareState = [&_client](Json::Value const& _o, string const& _name, BlockNumber _blockNumber) -> void { - Json::Value o = _json["postState"][name]; - Address address(name); + Address address(_name); // balanceAt - u256 expectedBalance = u256(o["balance"].asString()); - u256 balance = _client.balanceAt(address); + u256 expectedBalance = u256(_o["balance"].asString()); + u256 balance = _client.balanceAt(address, _blockNumber); ETH_CHECK_EQUAL(expectedBalance, balance); // countAt - u256 expectedCount = u256(o["nonce"].asString()); - u256 count = _client.countAt(address); + u256 expectedCount = u256(_o["nonce"].asString()); + u256 count = _client.countAt(address, _blockNumber); ETH_CHECK_EQUAL(expectedCount, count); // stateAt - for (string const& pos: o["storage"].getMemberNames()) + for (string const& pos: _o["storage"].getMemberNames()) { - u256 expectedState = u256(o["storage"][pos].asString()); - u256 state = _client.stateAt(address, u256(pos)); + u256 expectedState = u256(_o["storage"][pos].asString()); + u256 state = _client.stateAt(address, u256(pos), _blockNumber); ETH_CHECK_EQUAL(expectedState, state); } // codeAt - bytes expectedCode = fromHex(o["code"].asString()); - bytes code = _client.codeAt(address); + bytes expectedCode = fromHex(_o["code"].asString()); + bytes code = _client.codeAt(address, _blockNumber); ETH_CHECK_EQUAL_COLLECTIONS(expectedCode.begin(), expectedCode.end(), - code.begin(), code.end()); + code.begin(), code.end()); + }; + + for (string const& name: _json["postState"].getMemberNames()) + { + Json::Value o = _json["postState"][name]; + compareState(o, name, PendingBlock); + } + + for (string const& name: _json["pre"].getMemberNames()) + { + Json::Value o = _json["pre"][name]; + compareState(o, name, 0); } // number From 9d5c75aabe50e4fb93f7ac910c8efaee573f86f9 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 30 Mar 2015 16:46:14 +0200 Subject: [PATCH 11/50] Redesign of logs pane --- mix/qml/LogsPane.qml | 221 +++++++++++++++++++------------------- mix/qml/LogsPaneStyle.qml | 8 +- mix/qml/StatusPane.qml | 47 +++----- 3 files changed, 130 insertions(+), 146 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index b40dfc4c7..73c56d4e9 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -10,19 +10,124 @@ Rectangle function push(_level, _type, _content) { _content = _content.replace(/\n/g, " ") - logsModel.insert(0, { "type": _type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss dd.MM.yyyy"), "content": _content, "level": _level }); + logsModel.insert(0, { "type": _type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": _content, "level": _level }); } anchors.fill: parent radius: 5 color: LogsPaneStyle.generic.layout.backgroundColor - border.color: LogsPaneStyle.generic.layout.borderColor - border.width: LogsPaneStyle.generic.layout.borderWidth ColumnLayout { z: 2 height: parent.height width: parent.width spacing: 0 + + ListModel { + id: logsModel + } + + TableView { + id: logsTable + clip: true + Layout.fillWidth: true + Layout.preferredHeight: parent.height - rowAction.height + headerVisible : false + onDoubleClicked: + { + var log = logsModel.get(logsTable.currentRow); + if (log) + clipboard.text = (log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content); + } + + model: SortFilterProxyModel { + id: proxyModel + source: logsModel + property var roles: ["-", "javascript", "run", "state"] + + Component.onCompleted: { + filterType = regEx(proxyModel.roles); + } + + function search(_value) + { + filterContent = _value; + } + + function toogleFilter(_value) + { + var count = roles.length; + for (var i in roles) + { + if (roles[i] === _value) + { + roles.splice(i, 1); + break; + } + } + if (count === roles.length) + roles.push(_value); + + filterType = regEx(proxyModel.roles); + } + + function regEx(_value) + { + return "(?:" + roles.join('|') + ")"; + } + + filterType: "(?:javascript|run|state)" + filterContent: "" + filterSyntax: SortFilterProxyModel.RegExp + filterCaseSensitivity: Qt.CaseInsensitive + } + TableViewColumn + { + role: "date" + title: qsTr("date") + width: LogsPaneStyle.generic.layout.dateWidth + delegate: itemDelegate + } + TableViewColumn + { + role: "type" + title: qsTr("type") + width: LogsPaneStyle.generic.layout.typeWidth + delegate: itemDelegate + } + TableViewColumn + { + role: "content" + title: qsTr("content") + width: LogsPaneStyle.generic.layout.contentWidth + delegate: itemDelegate + } + + rowDelegate: Item { + Rectangle { + width: logsTable.width - 4 + height: 17 + color: styleData.alternate ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor + } + } + } + + Component { + id: itemDelegate + DefaultLabel { + text: styleData.value; + font.family: LogsPaneStyle.generic.layout.logLabelFont + font.pointSize: Style.absoluteSize(-1) + color: { + if (proxyModel.get(styleData.row).level === "error") + return "red"; + else if (proxyModel.get(styleData.row).level === "warning") + return "orange"; + else + return "#808080"; + } + } + } + Row { id: rowAction @@ -178,7 +283,7 @@ Rectangle } } - DefaultTextField + /*DefaultTextField { id: searchBox height: LogsPaneStyle.generic.layout.headerButtonHeight @@ -190,113 +295,7 @@ Rectangle onTextChanged: { proxyModel.search(text); } - } - } - - ListModel { - id: logsModel - } - - TableView { - id: logsTable - clip: true - Layout.fillWidth: true - Layout.preferredHeight: parent.height - rowAction.height - headerVisible : false - onDoubleClicked: - { - var log = logsModel.get(logsTable.currentRow); - if (log) - clipboard.text = (log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content); - } - - model: SortFilterProxyModel { - id: proxyModel - source: logsModel - property var roles: ["-", "javascript", "run", "state"] - - Component.onCompleted: { - filterType = regEx(proxyModel.roles); - } - - function search(_value) - { - filterContent = _value; - } - - function toogleFilter(_value) - { - var count = roles.length; - for (var i in roles) - { - if (roles[i] === _value) - { - roles.splice(i, 1); - break; - } - } - if (count === roles.length) - roles.push(_value); - - filterType = regEx(proxyModel.roles); - } - - function regEx(_value) - { - return "(?:" + roles.join('|') + ")"; - } - - filterType: "(?:javascript|run|state)" - filterContent: "" - filterSyntax: SortFilterProxyModel.RegExp - filterCaseSensitivity: Qt.CaseInsensitive - } - TableViewColumn - { - role: "date" - title: qsTr("date") - width: LogsPaneStyle.generic.layout.dateWidth - delegate: itemDelegate - } - TableViewColumn - { - role: "type" - title: qsTr("type") - width: LogsPaneStyle.generic.layout.typeWidth - delegate: itemDelegate - } - TableViewColumn - { - role: "content" - title: qsTr("content") - width: LogsPaneStyle.generic.layout.contentWidth - delegate: itemDelegate - } - - rowDelegate: Item { - Rectangle { - width: logsTable.width - 4 - height: 17 - color: styleData.alternate ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor - } - } - } - - Component { - id: itemDelegate - DefaultLabel { - text: styleData.value; - font.family: LogsPaneStyle.generic.layout.logLabelFont - font.pointSize: Style.absoluteSize(-1) - color: { - if (proxyModel.get(styleData.row).level === "error") - return "red"; - else if (proxyModel.get(styleData.row).level === "warning") - return "orange"; - else - return "#808080"; - } - } + }*/ } } } diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index 59b80653a..1c5e2f4f5 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -11,8 +11,6 @@ QtObject { property QtObject generic: QtObject { property QtObject layout: QtObject { property string backgroundColor: "#f7f7f7" - property string borderColor: "#5391d8" - property int borderWidth: 1 property int headerHeight: 35 property int headerButtonSpacing: 5 property int leftMargin: 10 @@ -20,9 +18,9 @@ QtObject { property string logLabelColor: "#5391d8" property string logLabelFont: "sans serif" property int headerInputWidth: 200 - property int dateWidth: 150 - property int typeWidth: 80 - property int contentWidth: 700 + property int dateWidth: 70 + property int typeWidth: 70 + property int contentWidth: 250 property string logAlternateColor: "#f0f0f0" } } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 6d4b5e7e1..151688cea 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -91,6 +91,7 @@ Rectangle { return formatted; } } + Connections { target:projectModel onDeploymentStarted: infoMessage(qsTr("Running deployment..."), "Deployment"); @@ -112,28 +113,9 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter radius: 3 - width: 500 + width: 650 height: 30 color: "#fcfbfc" - states: [ - State { - name: "logsOpened" - PropertyChanges { - target: statusContainer - border.color: "#5391d8" - border.width: 1 - } - }, - State { - name: "logsClosed" - PropertyChanges { - target: statusContainer - border.color: "#5391d8" - border.width: 0 - } - } - ] - Text { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter @@ -215,40 +197,45 @@ Rectangle { function toggle() { if (logsContainer.state === "opened") - { - statusContainer.state = "logsClosed"; logsContainer.state = "closed" - } else { - statusContainer.state = "logsOpened"; logsContainer.state = "opened"; logsContainer.focus = true; + calCoord(); forceActiveFocus(); } } id: logsContainer - width: 1000 - height: 0 + width: 650 + //height: 0 anchors.topMargin: 10 anchors.top: statusContainer.bottom + //anchors.left: statusContainer.left anchors.horizontalCenter: parent.horizontalCenter visible: false radius: 5 Component.onCompleted: + { + calCoord(); + } + + function calCoord() { var top = logsContainer; while (top.parent) top = top.parent - var coordinates = logsContainer.mapToItem(top, 0, 0) + var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; - logsContainer.x = coordinates.x - logsContainer.y = coordinates.y + //logsContainer.x = coordinates.x + 150; + logsContainer.y = coordinates.y; + console.log(logsContainer.x); } + LogsPane { - id: logPane + id: logPane; } states: [ State { From 9710ce3b7eaa5db9d549950e1514a8eb1bda99fa Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 31 Mar 2015 10:28:46 +0200 Subject: [PATCH 12/50] Fix #1475 --- alethzero/MainWin.cpp | 1 + libp2p/Host.cpp | 66 ++++++++++++++++++------------------------- test/peer.cpp | 9 ++++++ 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 0de7e2cb8..610fd032d 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1774,6 +1774,7 @@ void Main::on_net_triggered() else { ui->downloadView->setDownloadMan(nullptr); + writeSettings(); web3()->stopNetwork(); } } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index ab39c5c25..5aeeb3f82 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -678,9 +678,6 @@ void Host::disconnectLatePeers() bytes Host::saveNetwork() const { - if (!m_nodeTable) - return bytes(); - std::list peers; { RecursiveGuard l(x_sessions); @@ -692,27 +689,23 @@ bytes Host::saveNetwork() const RLPStream network; int count = 0; + for (auto const& p: peers) { - RecursiveGuard l(x_sessions); - for (auto const& p: peers) + // Only save peers which have connected within 2 days, with properly-advertised port and public IP address + bi::tcp::endpoint endpoint(p.peerEndpoint()); + if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && endpoint.port() < /*49152*/32768 && p.id != id() && !isPrivateAddress(p.endpoint.udp.address()) && !isPrivateAddress(endpoint.address())) { - // TODO: alpha: Figure out why it ever shares these ports.//p.address.port() >= 30300 && p.address.port() <= 30305 && - // TODO: alpha: if/how to save private addresses - // Only save peers which have connected within 2 days, with properly-advertised port and public IP address - if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && p.peerEndpoint().port() > 0 && p.peerEndpoint().port() < /*49152*/32768 && p.id != id() && !isPrivateAddress(p.endpoint.udp.address()) && !isPrivateAddress(p.endpoint.tcp.address())) - { - network.appendList(10); - if (p.peerEndpoint().address().is_v4()) - network << p.peerEndpoint().address().to_v4().to_bytes(); - else - network << p.peerEndpoint().address().to_v6().to_bytes(); - // TODO: alpha: replace 0 with trust-state of node - network << p.peerEndpoint().port() << p.id << 0 - << chrono::duration_cast(p.m_lastConnected.time_since_epoch()).count() - << chrono::duration_cast(p.m_lastAttempted.time_since_epoch()).count() - << p.m_failedAttempts << (unsigned)p.m_lastDisconnect << p.m_score << p.m_rating; - count++; - } + // todo: e2e ipv6 support + if (endpoint.address().is_v4()) + network << endpoint.address().to_v4().to_bytes(); + continue; + + network.appendList(10); + network << endpoint.port() << p.id << p.required + << chrono::duration_cast(p.m_lastConnected.time_since_epoch()).count() + << chrono::duration_cast(p.m_lastAttempted.time_since_epoch()).count() + << p.m_failedAttempts << (unsigned)p.m_lastDisconnect << p.m_score << p.m_rating; + count++; } } @@ -731,6 +724,7 @@ bytes Host::saveNetwork() const count++; } } + // else: TODO: use previous configuration if available RLPStream ret(3); ret << dev::p2p::c_protocolVersion << m_alias.secret(); @@ -757,22 +751,14 @@ void Host::restoreNetwork(bytesConstRef _b) for (auto i: r[2]) { + // todo: e2e ipv6 support + // bi::tcp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt()); + if (i[0].itemCount() != 4) + continue; bi::tcp::endpoint tcp; bi::udp::endpoint udp; - if (i[0].itemCount() == 4) - { - tcp = bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()); - udp = bi::udp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()); - } - else - { - tcp = bi::tcp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt()); - udp = bi::udp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt()); - } - - // skip private addresses - // todo: to support private addresseses entries must be stored - // and managed externally by host rather than nodetable. + tcp = bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()); + udp = bi::udp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()); if (isPrivateAddress(tcp.address()) || isPrivateAddress(udp.address())) continue; @@ -783,6 +769,7 @@ void Host::restoreNetwork(bytesConstRef _b) { shared_ptr p = make_shared(); p->id = id; + p->required = i[2].toInt(); p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt())); p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt())); p->m_failedAttempts = i[6].toInt(); @@ -792,7 +779,10 @@ void Host::restoreNetwork(bytesConstRef _b) p->endpoint.tcp = tcp; p->endpoint.udp = udp; m_peers[p->id] = p; - m_nodeTable->addNode(*p.get()); + if (p->required) + requirePeer(p->id, p->endpoint.udp.address(), p->endpoint.udp.port()); + else + m_nodeTable->addNode(*p.get()); } } } @@ -801,7 +791,7 @@ void Host::restoreNetwork(bytesConstRef _b) KeyPair Host::networkAlias(bytesConstRef _b) { RLP r(_b); - if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt() == 1) + if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt() == dev::p2p::c_protocolVersion) return move(KeyPair(move(Secret(r[1].toBytes())))); else return move(KeyPair::create()); diff --git a/test/peer.cpp b/test/peer.cpp index 48431504f..904de0e9d 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -57,6 +57,15 @@ BOOST_AUTO_TEST_CASE(host) g_logVerbosity = oldLogVerbosity; } +BOOST_AUTO_TEST_CASE(networkConfig) +{ + Host save("Test", NetworkPreferences(false)); + bytes store(save.saveNetwork()); + + Host restore("Test", NetworkPreferences(false), bytesConstRef(&store)); + BOOST_REQUIRE(save.id() == restore.id()); +} + BOOST_AUTO_TEST_CASE(save_nodes) { std::list hosts; From deaabe142a51fb14a64a8e912c45af49a531a810 Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Tue, 31 Mar 2015 13:41:37 +0430 Subject: [PATCH 13/50] Bug fix. --- mix/qml/TransactionLog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 83e64ebf1..e5787f19b 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -61,7 +61,7 @@ Item { target: projectModel onProjectSaved: { - if (projectModel.appIsClosing) + if (projectModel.appIsClosing || projectModel.projectIsClosing) return; if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) projectModel.stateListModel.debugDefaultState(); From 8f68a846da4086cdffd78ad2ba887591d87f7752 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 31 Mar 2015 11:21:43 +0200 Subject: [PATCH 14/50] nodeid doesn't cast to a bool (bug) --- libp2p/Host.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 5aeeb3f82..e530c7e66 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -728,7 +728,9 @@ bytes Host::saveNetwork() const RLPStream ret(3); ret << dev::p2p::c_protocolVersion << m_alias.secret(); - ret.appendList(count).appendRaw(network.out(), count); + ret.appendList(count); + if (count) + ret.appendRaw(network.out(), count); return ret.out(); } @@ -769,7 +771,7 @@ void Host::restoreNetwork(bytesConstRef _b) { shared_ptr p = make_shared(); p->id = id; - p->required = i[2].toInt(); + p->required = i[3].toInt(); p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt())); p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt())); p->m_failedAttempts = i[6].toInt(); From a224fd2727f33b7b096e3aa60b185d2839455123 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 31 Mar 2015 11:26:25 +0200 Subject: [PATCH 15/50] fix #1474 --- mix/qml/CodeEditorView.qml | 10 ++++++++++ mix/qml/WebPreview.qml | 7 ++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index b100dffd0..7ea1e30d9 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -11,6 +11,16 @@ Item { signal breakpointsChanged(string documentId) signal isCleanChanged(var isClean, string documentId) + function getDocumentIdByName(fileName) + { + for (var i = 0; i < editorListModel.count; i++) { + if (editorListModel.get(i).fileName === fileName) { + return editorListModel.get(i).documentId; + } + } + return null; + } + function getDocumentText(documentId) { for (var i = 0; i < editorListModel.count; i++) { if (editorListModel.get(i).documentId === documentId) { diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 8507c9b46..0bf31b326 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -155,18 +155,19 @@ Item { //document request if (urlPath === "/") urlPath = "/index.html"; - var documentId = urlPath.substr(urlPath.lastIndexOf("/") + 1); + var documentName = urlPath.substr(urlPath.lastIndexOf("/") + 1); + var documentId = projectModel.codeEditor.getDocumentIdByName(documentName); var content = ""; if (projectModel.codeEditor.isDocumentOpen(documentId)) content = projectModel.codeEditor.getDocumentText(documentId); else { var doc = projectModel.getDocument(documentId); - if (doc !== undefined) + if (doc) content = fileIo.readFile(doc.path); } - if (documentId === urlInput.text.replace(httpServer.url + "/", "")) { + if (documentName === urlInput.text.replace(httpServer.url + "/", "")) { //root page, inject deployment script content = "\n" + content; _request.setResponseContentType("text/html"); From 0e48d266c8cd2d94b2f1568665eeeaaf9fc88272 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 31 Mar 2015 11:37:10 +0200 Subject: [PATCH 16/50] Mix: fixed editor clipboard for os x --- mix/qml/html/codeeditor.js | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 299691ec0..4beae1955 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -22,17 +22,11 @@ editor.on("change", function(eMirror, object) { }); var mac = /Mac/.test(navigator.platform); +var extraKeys = {}; if (mac === true) { - editor.setOption("extraKeys", { - "Cmd-V": function(cm) { - cm.replaceSelection(clipboard); - }, - "Cmd-X": function(cm) { - window.document.execCommand("cut"); - }, - "Cmd-C": function(cm) { - window.document.execCommand("copy"); - }}); + extraKeys["Cmd-V"] = function(cm) { cm.replaceSelection(clipboard); }; + extraKeys["Cmd-X"] = function(cm) { window.document.execCommand("cut"); }; + extraKeys["Cmd-C"] = function(cm) { window.document.execCommand("copy"); }; } makeMarker = function() { @@ -102,16 +96,14 @@ setMode = function(mode) { if (mode === "javascript") { ternServer = new CodeMirror.TernServer({defs: [ ecma5Spec() ]}); - editor.setOption("extraKeys", { - "Ctrl-Space": function(cm) { ternServer.complete(cm); }, - "Ctrl-I": function(cm) { ternServer.showType(cm); }, - "Ctrl-O": function(cm) { ternServer.showDocs(cm); }, - "Alt-.": function(cm) { ternServer.jumpToDef(cm); }, - "Alt-,": function(cm) { ternServer.jumpBack(cm); }, - "Ctrl-Q": function(cm) { ternServer.rename(cm); }, - "Ctrl-.": function(cm) { ternServer.selectName(cm); }, - "'.'": function(cm) { setTimeout(function() { ternServer.complete(cm); }, 100); throw CodeMirror.Pass; } - }) + extraKeys["Ctrl-Space"] = function(cm) { ternServer.complete(cm); }; + extraKeys["Ctrl-I"] = function(cm) { ternServer.showType(cm); }; + extraKeys["Ctrl-O"] = function(cm) { ternServer.showDocs(cm); }; + extraKeys["Alt-."] = function(cm) { ternServer.jumpToDef(cm); }; + extraKeys["Alt-,"] = function(cm) { ternServer.jumpBack(cm); }; + extraKeys["Ctrl-Q"] = function(cm) { ternServer.rename(cm); }; + extraKeys["Ctrl-."] = function(cm) { ternServer.selectName(cm); }; + extraKeys["'.'"] = function(cm) { setTimeout(function() { ternServer.complete(cm); }, 100); throw CodeMirror.Pass; }; editor.on("cursorActivity", function(cm) { ternServer.updateArgHints(cm); }); } else if (mode === "solidity") @@ -119,9 +111,7 @@ setMode = function(mode) { CodeMirror.commands.autocomplete = function(cm) { CodeMirror.showHint(cm, CodeMirror.hint.anyword); } - editor.setOption("extraKeys", { - "Ctrl-Space": "autocomplete" - }) + extraKeys["Ctrl-Space"] = "autocomplete"; } }; @@ -199,3 +189,5 @@ compilationComplete = function() } compilationCompleteBool = true; } + +editor.setOption("extraKeys", extraKeys); From a0608412acc148889258e51eecde2b882207ba45 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 26 Mar 2015 21:06:59 +0100 Subject: [PATCH 17/50] removed trailing zeros from rpc results, fixed #1433 --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index cab986364..7524e7519 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -402,7 +402,7 @@ string WebThreeStubServerBase::eth_getCode(string const& _address, string const& { try { - return toJS(client()->codeAt(jsToAddress(_address), toBlockNumber(_blockNumber)), 1); + return toJS(client()->codeAt(jsToAddress(_address), toBlockNumber(_blockNumber))); } catch (...) { From ab0501a70c4c96bc71becc9b20ac4e7a3d45791b Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 31 Mar 2015 12:03:26 +0200 Subject: [PATCH 18/50] apply extrakeys on mode change --- mix/qml/html/codeeditor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 4beae1955..5d63a7a83 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -113,6 +113,7 @@ setMode = function(mode) { } extraKeys["Ctrl-Space"] = "autocomplete"; } + editor.setOption("extraKeys", extraKeys); }; setClipboardBase64 = function(text) { From b1ec65596f7c6532a6d0ea4ac9d70a569a0e3256 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 31 Mar 2015 12:26:42 +0200 Subject: [PATCH 19/50] fix bug found in code review. --- libp2p/Host.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index e530c7e66..45ebd6db1 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -692,14 +692,13 @@ bytes Host::saveNetwork() const for (auto const& p: peers) { // Only save peers which have connected within 2 days, with properly-advertised port and public IP address + // todo: e2e ipv6 support bi::tcp::endpoint endpoint(p.peerEndpoint()); + if (!endpoint.address().is_v4()) + continue; + if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && endpoint.port() < /*49152*/32768 && p.id != id() && !isPrivateAddress(p.endpoint.udp.address()) && !isPrivateAddress(endpoint.address())) { - // todo: e2e ipv6 support - if (endpoint.address().is_v4()) - network << endpoint.address().to_v4().to_bytes(); - continue; - network.appendList(10); network << endpoint.port() << p.id << p.required << chrono::duration_cast(p.m_lastConnected.time_since_epoch()).count() @@ -729,7 +728,7 @@ bytes Host::saveNetwork() const RLPStream ret(3); ret << dev::p2p::c_protocolVersion << m_alias.secret(); ret.appendList(count); - if (count) + if (!!count) ret.appendRaw(network.out(), count); return ret.out(); } From 1d4e61167ffb783781a2106d66d34737a2c5a161 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 31 Mar 2015 12:43:08 +0200 Subject: [PATCH 20/50] most compact number representation --- libdevcore/CommonJS.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libdevcore/CommonJS.h b/libdevcore/CommonJS.h index cc487d54c..ade089e16 100644 --- a/libdevcore/CommonJS.h +++ b/libdevcore/CommonJS.h @@ -38,7 +38,10 @@ template std::string toJS(FixedHash const& _h) template std::string toJS(boost::multiprecision::number> const& _n) { - return "0x" + toHex(toCompactBigEndian(_n, 1)); + std::string h = toHex(toCompactBigEndian(_n, 1)); + // remove first 0, if it is necessary; + std::string res = h[0] != '0' ? h : h.substr(1); + return "0x" + res; } inline std::string toJS(bytes const& _n, std::size_t _padding = 0) From 2ad558b9a962c04f856f304da6e6c7bd8ae8e134 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 31 Mar 2015 13:28:28 +0200 Subject: [PATCH 21/50] Started minor refactor - still API compatible though. --- libethash/CMakeLists.txt | 7 ++++ libethash/data_sizes.h | 4 +-- libethash/ethash.h | 75 ++++++++++++++++++++++------------------ libethash/internal.c | 14 ++++---- libethash/internal.h | 2 +- 5 files changed, 58 insertions(+), 44 deletions(-) diff --git a/libethash/CMakeLists.txt b/libethash/CMakeLists.txt index 38fc821c0..c92240086 100644 --- a/libethash/CMakeLists.txt +++ b/libethash/CMakeLists.txt @@ -12,6 +12,7 @@ endif() set(FILES util.c util.h + io.c internal.c ethash.h endian.h @@ -19,6 +20,12 @@ set(FILES util.c fnv.h data_sizes.h) +if (MSVC) + list(APPEND FILES io_win32.c) +else() + list(APPEND FILES io_posix.c) +endif() + if (NOT CRYPTOPP_FOUND) find_package(CryptoPP 5.6.2) endif() diff --git a/libethash/data_sizes.h b/libethash/data_sizes.h index 3b747b3ea..cf52ae4f8 100644 --- a/libethash/data_sizes.h +++ b/libethash/data_sizes.h @@ -48,7 +48,7 @@ extern "C" { // Sow[i*HashBytes]; j++]]]][[2]][[1]] -static const size_t dag_sizes[2048] = { +static const uint64_t dag_sizes[2048] = { 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, @@ -477,7 +477,7 @@ static const size_t dag_sizes[2048] = { // While[! PrimeQ[i], i--]; // Sow[i*HashBytes]; j++]]]][[2]][[1]] -const size_t cache_sizes[2048] = { +const uint64_t cache_sizes[2048] = { 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, diff --git a/libethash/ethash.h b/libethash/ethash.h index a7159de65..eb3097307 100644 --- a/libethash/ethash.h +++ b/libethash/ethash.h @@ -43,26 +43,26 @@ extern "C" { #endif typedef struct ethash_params { - size_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). - size_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)). + uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). + uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)). } ethash_params; typedef struct ethash_return_value { - uint8_t result[32]; - uint8_t mix_hash[32]; + uint8_t result[32]; + uint8_t mix_hash[32]; } ethash_return_value; -size_t ethash_get_datasize(const uint32_t block_number); -size_t ethash_get_cachesize(const uint32_t block_number); +uint64_t ethash_get_datasize(const uint32_t block_number); +uint64_t ethash_get_cachesize(const uint32_t block_number); // initialize the parameters static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) { - params->full_size = ethash_get_datasize(block_number); - params->cache_size = ethash_get_cachesize(block_number); + params->full_size = ethash_get_datasize(block_number); + params->cache_size = ethash_get_cachesize(block_number); } typedef struct ethash_cache { - void *mem; + void *mem; } ethash_cache; void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); @@ -72,44 +72,51 @@ void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_pa void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { - ethash_cache c; - c.mem = cache; - ethash_mkcache(&c, params, seed); + ethash_cache c; + c.mem = cache; + ethash_mkcache(&c, params, seed); } static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { - ethash_cache c; - c.mem = (void *) cache; - ethash_light(ret, &c, params, header_hash, nonce); + ethash_cache c; + c.mem = (void *) cache; + ethash_light(ret, &c, params, header_hash, nonce); } static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { - ethash_cache c; - c.mem = (void *) cache; - ethash_compute_full_data(full, params, &c); + ethash_cache c; + c.mem = (void *) cache; + ethash_compute_full_data(full, params, &c); } static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { - ethash_full(ret, full, params, header_hash, nonce); + ethash_full(ret, full, params, header_hash, nonce); } -// Returns if hash is less than or equal to difficulty -static inline int ethash_check_difficulty( - const uint8_t hash[32], - const uint8_t difficulty[32]) { - // Difficulty is big endian - for (int i = 0; i < 32; i++) { - if (hash[i] == difficulty[i]) continue; - return hash[i] < difficulty[i]; - } - return 1; +/// @brief Compare two s256-bit big-endian values. +/// @returns 1 if @a a is less than or equal to @a b, 0 otherwise. +/// Both parameters are 256-bit big-endian values. +static inline int ethash_leq_be256(const uint8_t a[32], const uint8_t b[32]) { + // Boundary is big endian + for (int i = 0; i < 32; i++) { + if (a[i] == b[i]) + continue; + return a[i] < b[i]; + } + return 1; } -int ethash_quick_check_difficulty( - const uint8_t header_hash[32], - const uint64_t nonce, - const uint8_t mix_hash[32], - const uint8_t difficulty[32]); +/// Perofrms a cursory check on the validity of the nonce. +/// @returns 1 if the nonce may possibly be valid for the given header_hash & boundary. +/// @p boundary equivalent to 2 ^ 256 / block_difficulty, represented as a 256-bit big-endian. +int ethash_preliminary_check_boundary( + const uint8_t header_hash[32], + const uint64_t nonce, + const uint8_t mix_hash[32], + const uint8_t boundary[32]); + +#define ethash_quick_check_difficulty ethash_preliminary_check_boundary +#define ethash_check_difficulty ethash_leq_be256 #ifdef __cplusplus } diff --git a/libethash/internal.c b/libethash/internal.c index 0a7e767e7..ae9b95065 100644 --- a/libethash/internal.c +++ b/libethash/internal.c @@ -37,12 +37,12 @@ #include "sha3.h" #endif // WITH_CRYPTOPP -size_t ethash_get_datasize(const uint32_t block_number) { +uint64_t ethash_get_datasize(const uint32_t block_number) { assert(block_number / EPOCH_LENGTH < 2048); return dag_sizes[block_number / EPOCH_LENGTH]; } -size_t ethash_get_cachesize(const uint32_t block_number) { +uint64_t ethash_get_cachesize(const uint32_t block_number) { assert(block_number / EPOCH_LENGTH < 2048); return cache_sizes[block_number / EPOCH_LENGTH]; } @@ -280,15 +280,15 @@ void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) { SHA3_256(seedhash, seedhash, 32); } -int ethash_quick_check_difficulty( +int ethash_preliminary_check_boundary( const uint8_t header_hash[32], const uint64_t nonce, const uint8_t mix_hash[32], - const uint8_t difficulty[32]) { + const uint8_t difficulty[32]) { - uint8_t return_hash[32]; + uint8_t return_hash[32]; ethash_quick_hash(return_hash, header_hash, nonce, mix_hash); - return ethash_check_difficulty(return_hash, difficulty); + return ethash_leq_be256(return_hash, difficulty); } void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { @@ -297,4 +297,4 @@ void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params c void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { ethash_hash(ret, NULL, cache, params, previous_hash, nonce); -} \ No newline at end of file +} diff --git a/libethash/internal.h b/libethash/internal.h index bcbacdaa4..ddd06e8f4 100644 --- a/libethash/internal.h +++ b/libethash/internal.h @@ -3,7 +3,7 @@ #include "endian.h" #include "ethash.h" -#define ENABLE_SSE 1 +#define ENABLE_SSE 0 #if defined(_M_X64) && ENABLE_SSE #include From 5039e4a9eeffd522d06fedc80ae339c84b39d78e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 31 Mar 2015 14:02:08 +0200 Subject: [PATCH 22/50] Add missing files. --- libethash/io.c | 89 +++++++++++++++++++++++++++++++++ libethash/io.h | 116 +++++++++++++++++++++++++++++++++++++++++++ libethash/io_posix.c | 76 ++++++++++++++++++++++++++++ libethash/io_win32.c | 73 +++++++++++++++++++++++++++ 4 files changed, 354 insertions(+) create mode 100644 libethash/io.c create mode 100644 libethash/io.h create mode 100644 libethash/io_posix.c create mode 100644 libethash/io_win32.c diff --git a/libethash/io.c b/libethash/io.c new file mode 100644 index 000000000..dd4f1f9e8 --- /dev/null +++ b/libethash/io.c @@ -0,0 +1,89 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io.c + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "io.h" +#include +#include + +// silly macro to save some typing +#define PASS_ARR(c_) (c_), sizeof(c_) + +static bool ethash_io_write_file(char const *dirname, + char const* filename, + size_t filename_length, + void const* data, + size_t data_size) +{ + bool ret = false; + char *fullname = ethash_io_create_filename(dirname, filename, filename_length); + if (!fullname) { + return false; + } + FILE *f = fopen(fullname, "wb"); + if (!f) { + goto free_name; + } + if (data_size != fwrite(data, 1, data_size, f)) { + goto close; + } + + ret = true; +close: + fclose(f); +free_name: + free(fullname); + return ret; +} + +bool ethash_io_write(char const *dirname, + ethash_params const* params, + ethash_blockhash_t seedhash, + void const* cache, + uint8_t **data, + size_t *data_size) +{ + char info_buffer[DAG_MEMO_BYTESIZE]; + // allocate the bytes + uint8_t *temp_data_ptr = malloc(params->full_size); + if (!temp_data_ptr) { + goto end; + } + ethash_compute_full_data(temp_data_ptr, params, cache); + + if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, params->full_size)) { + goto fail_free; + } + + ethash_io_serialize_info(REVISION, seedhash, info_buffer); + if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) { + goto fail_free; + } + + *data = temp_data_ptr; + *data_size = params->full_size; + return true; + +fail_free: + free(temp_data_ptr); +end: + return false; +} + +#undef PASS_ARR diff --git a/libethash/io.h b/libethash/io.h new file mode 100644 index 000000000..0fa292362 --- /dev/null +++ b/libethash/io.h @@ -0,0 +1,116 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#include +#include +#include +#include "ethash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ethash_blockhash { uint8_t b[32]; } ethash_blockhash_t; + +static const char DAG_FILE_NAME[] = "full"; +static const char DAG_MEMO_NAME[] = "full.info"; +// MSVC thinks that "static const unsigned int" is not a compile time variable. Sorry for the #define :( +#define DAG_MEMO_BYTESIZE 36 + +/// Possible return values of @see ethash_io_prepare +enum ethash_io_rc { + ETHASH_IO_FAIL = 0, ///< There has been an IO failure + ETHASH_IO_MEMO_MISMATCH, ///< Memo file either did not exist or there was content mismatch + ETHASH_IO_MEMO_MATCH, ///< Memo file existed and contents matched. No need to do anything +}; + +/** + * Prepares io for ethash + * + * Create the DAG directory if it does not exist, and check if the memo file matches. + * If it does not match then it's deleted to pave the way for @ref ethash_io_write() + * + * @param dirname A null terminated c-string of the path of the ethash + * data directory. If it does not exist it's created. + * @param seedhash The seedhash of the current block number + * @return For possible return values @see enum ethash_io_rc + */ +enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash); +/** + * Fully computes data and writes it to the file on disk. + * + * This function should be called after @see ethash_io_prepare() and only if + * its return value is @c ETHASH_IO_MEMO_MISMATCH. Will write both the full data + * and the memo file. + * + * @param[in] dirname A null terminated c-string of the path of the ethash + * data directory. Has to exist. + * @param[in] params An ethash_params object containing the full size + * and the cache size + * @param[in] seedhash The seedhash of the current block number + * @param[in] cache The cache data. Would have usually been calulated by + * @see ethash_prep_light(). + * @param[out] data Pass a pointer to uint8_t by reference here. If the + * function is succesfull then this point to the allocated + * data calculated by @see ethash_prep_full(). Memory + * ownership is transfered to the callee. Remember that + * you eventually need to free this with a call to free(). + * @param[out] data_size Pass a size_t by value. If the function is succesfull + * then this will contain the number of bytes allocated + * for @a data. + * @return True for success and false in case of failure. + */ +bool ethash_io_write(char const *dirname, + ethash_params const* params, + ethash_blockhash_t seedhash, + void const* cache, + uint8_t **data, + size_t *data_size); + +static inline void ethash_io_serialize_info(uint32_t revision, + ethash_blockhash_t seed_hash, + char *output) +{ + // if .info is only consumed locally we don't really care about endianess + memcpy(output, &revision, 4); + memcpy(output + 4, &seed_hash, 32); +} + +static inline char *ethash_io_create_filename(char const *dirname, + char const* filename, + size_t filename_length) +{ + // in C the cast is not needed, but a C++ compiler will complain for invalid conversion + char *name = (char*)malloc(strlen(dirname) + filename_length); + if (!name) { + return NULL; + } + + name[0] = '\0'; + strcat(name, dirname); + strcat(name, filename); + return name; +} + + +#ifdef __cplusplus +} +#endif diff --git a/libethash/io_posix.c b/libethash/io_posix.c new file mode 100644 index 000000000..693bdf750 --- /dev/null +++ b/libethash/io_posix.c @@ -0,0 +1,76 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io_posix.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include + +enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash) +{ + char read_buffer[DAG_MEMO_BYTESIZE]; + char expect_buffer[DAG_MEMO_BYTESIZE]; + enum ethash_io_rc ret = ETHASH_IO_FAIL; + + // assert directory exists, full owner permissions and read/search for others + int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (rc == -1 && errno != EEXIST) { + goto end; + } + + char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME)); + if (!memofile) { + goto end; + } + + // try to open memo file + FILE *f = fopen(memofile, "rb"); + if (!f) { + // file does not exist, so no checking happens. All is fine. + ret = ETHASH_IO_MEMO_MISMATCH; + goto free_memo; + } + + if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) { + goto close; + } + + ethash_io_serialize_info(REVISION, seedhash, expect_buffer); + if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { + // we have different memo contents so delete the memo file + if (unlink(memofile) != 0) { + goto close; + } + ret = ETHASH_IO_MEMO_MISMATCH; + } + + ret = ETHASH_IO_MEMO_MATCH; + +close: + fclose(f); +free_memo: + free(memofile); +end: + return ret; +} diff --git a/libethash/io_win32.c b/libethash/io_win32.c new file mode 100644 index 000000000..2cabc939a --- /dev/null +++ b/libethash/io_win32.c @@ -0,0 +1,73 @@ +/* + This file is part of ethash. + + ethash 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. + + ethash 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 ethash. If not, see . +*/ +/** @file io_win32.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include + +enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash) +{ + char read_buffer[DAG_MEMO_BYTESIZE]; + char expect_buffer[DAG_MEMO_BYTESIZE]; + enum ethash_io_rc ret = ETHASH_IO_FAIL; + + // assert directory exists + int rc = _mkdir(dirname); + if (rc == -1 && errno != EEXIST) { + goto end; + } + + char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME)); + if (!memofile) { + goto end; + } + + // try to open memo file + FILE *f = fopen(memofile, "rb"); + if (!f) { + // file does not exist, so no checking happens. All is fine. + ret = ETHASH_IO_MEMO_MISMATCH; + goto free_memo; + } + + if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) { + goto close; + } + + ethash_io_serialize_info(REVISION, seedhash, expect_buffer); + if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { + // we have different memo contents so delete the memo file + if (_unlink(memofile) != 0) { + goto close; + } + ret = ETHASH_IO_MEMO_MISMATCH; + } + + ret = ETHASH_IO_MEMO_MATCH; + +close: + fclose(f); +free_memo: + free(memofile); +end: + return ret; +} From fc1aac2ef42ff2778c1e9789c9ea48c74adfc4d5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 31 Mar 2015 14:59:21 +0200 Subject: [PATCH 23/50] style file --- mix/style.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 mix/style.xml diff --git a/mix/style.xml b/mix/style.xml new file mode 100644 index 000000000..75626ac24 --- /dev/null +++ b/mix/style.xml @@ -0,0 +1,19 @@ + + + + + + CodeStyleData + + false + 4 + 2 + false + 4 + + + + DisplayName + Eth + + From 73040eab7e08373d48e67ed36861976b65b44a2c Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 31 Mar 2015 15:07:05 +0200 Subject: [PATCH 24/50] Clarification about spacing. --- CodingStandards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodingStandards.txt b/CodingStandards.txt index e1a1b3ba9..a98a74c78 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -13,7 +13,7 @@ c. Don't use braces for condition-body one-liners. d. Never place condition bodies on same line as condition. e. Space between first paren and keyword, but *not* following first paren or preceeding final paren. f. No spaces when fewer than intra-expression three parens together; when three or more, space according to clarity. -g. No spaces for subscripting. +g. No spaces for subscripting or unary operators. h. No space before ':' but one after it, except in the ternary operator: one on both sides. i. Space all other operators. j. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. From 01e6801cf5e6b0f9f4cb6f50893e5354caf4137e Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 31 Mar 2015 15:10:21 +0200 Subject: [PATCH 25/50] Style. --- libevmcore/CommonSubexpressionEliminator.cpp | 26 ++++++++++---------- libevmcore/CommonSubexpressionEliminator.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index cc2fdc8bd..47bb5b512 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -199,7 +199,7 @@ void CommonSubexpressionEliminator::storeInStorage(ExpressionClasses::Id _slot, if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value) // do not execute the storage if we know that the value is already there return; - m_sequenceNumber ++; + m_sequenceNumber++; decltype(m_storageContent) storageContents; // copy over values at points where we know that they are different from _slot for (auto const& storageItem: m_storageContent) @@ -210,7 +210,7 @@ void CommonSubexpressionEliminator::storeInStorage(ExpressionClasses::Id _slot, m_storeOperations.push_back(StoreOperation(StoreOperation::Storage, _slot, m_sequenceNumber, id)); m_storageContent[_slot] = _value; // increment a second time so that we get unique sequence numbers for writes - m_sequenceNumber ++; + m_sequenceNumber++; } ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(ExpressionClasses::Id _slot) @@ -226,7 +226,7 @@ void CommonSubexpressionEliminator::storeInMemory(ExpressionClasses::Id _slot, E if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value) // do not execute the store if we know that the value is already there return; - m_sequenceNumber ++; + m_sequenceNumber++; decltype(m_memoryContent) memoryContents; // copy over values at points where we know that they are different from _slot by at least 32 for (auto const& memoryItem: m_memoryContent) @@ -237,7 +237,7 @@ void CommonSubexpressionEliminator::storeInMemory(ExpressionClasses::Id _slot, E m_storeOperations.push_back(StoreOperation(StoreOperation::Memory, _slot, m_sequenceNumber, id)); m_memoryContent[_slot] = _value; // increment a second time so that we get unique sequence numbers for writes - m_sequenceNumber ++; + m_sequenceNumber++; } ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(ExpressionClasses::Id _slot) @@ -281,7 +281,7 @@ bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) return false; //@todo: We do not handle the following memory instructions for now: // calldatacopy, codecopy, extcodecopy, mstore8, - // msize (not that msize also depends on memory read access) + // msize (note that msize also depends on memory read access) // the second requirement will be lifted once it is implemented return info.sideEffects || info.args > 2; @@ -592,10 +592,10 @@ bool CSECodeGenerator::removeStackTopIfPossible() void CSECodeGenerator::appendDup(int _fromPosition) { assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); - int nr = 1 + m_stackHeight - _fromPosition; - assertThrow(nr <= 16, StackTooDeepException, "Stack too deep."); - assertThrow(1 <= nr, OptimizerException, "Invalid stack access."); - appendItem(AssemblyItem(dupInstruction(nr))); + int instructionNum = 1 + m_stackHeight - _fromPosition; + assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); + assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); + appendItem(AssemblyItem(dupInstruction(instructionNum))); m_stack[m_stackHeight] = m_stack[_fromPosition]; } @@ -604,10 +604,10 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition) assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); if (_fromPosition == m_stackHeight) return; - int nr = m_stackHeight - _fromPosition; - assertThrow(nr <= 16, StackTooDeepException, "Stack too deep."); - assertThrow(1 <= nr, OptimizerException, "Invalid stack access."); - appendItem(AssemblyItem(swapInstruction(nr))); + int instructionNum = m_stackHeight - _fromPosition; + assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); + assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); + appendItem(AssemblyItem(swapInstruction(instructionNum))); // The value of a class can be present in multiple locations on the stack. We only update the // "canonical" one that is tracked by m_classPositions if (m_classPositions[m_stack[m_stackHeight]] == m_stackHeight) diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index 09368f7d2..a9a0c60a4 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -164,7 +164,7 @@ public: using StoreOperations = std::vector; /// Initializes the code generator with the given classes and store operations. - /// The store operations have to be sorted ascendingly by sequence number. + /// The store operations have to be sorted by sequence number in ascending order. CSECodeGenerator(ExpressionClasses& _expressionClasses, StoreOperations const& _storeOperations); /// @returns the assembly items generated from the given requirements From 9d2a23b51e881d316ca34fbc1e6d093868628c3a Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Tue, 31 Mar 2015 18:15:38 +0430 Subject: [PATCH 26/50] fix #1472 --- mix/qml/Debugger.qml | 27 +++++++++++++ mix/qml/StatesComboBox.qml | 78 +++++++++++++++++++------------------- mix/qml/TransactionLog.qml | 35 +---------------- 3 files changed, 66 insertions(+), 74 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 358750b24..202d27a0c 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -219,6 +219,33 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter id: jumpButtons spacing: 3 + + StepActionImage + { + id: playAction + enabledStateImg: "qrc:/qml/img/play_button.png" + disableStateImg: "qrc:/qml/img/play_button.png" + onClicked: console.log("play"); + width: 30 + height: 30 + buttonShortcut: "Ctrl+Shift+F8" + buttonTooltip: qsTr("Play") + visible: true + } + + StepActionImage + { + id: pauseAction + enabledStateImg: "qrc:/qml/img/pause_button.png" + disableStateImg: "qrc:/qml/img/pause_button.png" + onClicked: console.log("pause"); + width: 30 + height: 30 + buttonShortcut: "Ctrl+Shift+F9" + buttonTooltip: qsTr("Pause") + visible: true + } + StepActionImage { id: runBackAction; diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index 2c61863ec..26f41aa8d 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -26,9 +26,9 @@ import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 Rectangle { - id:statesComboBox + id: statesComboBox - width:200; + width: 200; height: 20; Component.onCompleted: @@ -72,19 +72,19 @@ Rectangle { smooth:true; Rectangle { - id:chosenItem - width:parent.width; - height:statesComboBox.height; - color: statesComboBox.color; - smooth:true; + id: chosenItem + width: parent.width; + height: statesComboBox.height; + color: statesComboBox.color; + smooth: true; Text { - id:chosenItemText + id: chosenItemText anchors.top: parent.top; anchors.left: parent.left; anchors.margins: 2; color: statesComboBox.colorItem; - text:"" - smooth:true + text: "" + smooth: true } MouseArea { @@ -96,35 +96,34 @@ Rectangle { } Rectangle { - id:dropDownShowdowList - width:statesComboBox.width; + id: dropDownShowdowList + width: statesComboBox.width; opacity: 0.3 - height:0; - clip:true; - radius:4; + height: 0; + clip: true; + radius: 4; anchors.top: chosenItem.top; anchors.margins: 2; color: "gray" } //ToDo: We need scrollbar for items Rectangle { - id:dropDownList - width:statesComboBox.width; - height:0; - clip:true; - radius:4; + id: dropDownList + width: statesComboBox.width; + height: 0; + clip: true; + radius: 4; anchors.top: chosenItem.top; anchors.margins: 2; color: statesComboBox.color - - ColumnLayout{ + ColumnLayout { spacing: 2 TableView { - id:listView - height:20; + id: listView + height: 20; implicitHeight: 0 - width:statesComboBox.width; + width: statesComboBox.width; model: statesComboBox.items horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff; currentRow: -1 @@ -140,14 +139,14 @@ Rectangle { delegate: mainItemDelegate } rowDelegate: Rectangle { - width:statesComboBox.width; + width: statesComboBox.width; height: statesComboBox.rowHeight; } Component { id: mainItemDelegate Rectangle { id: itemDelegate - width:statesComboBox.width; + width: statesComboBox.width; height: statesComboBox.height; Text { id: textItemid @@ -156,13 +155,12 @@ Rectangle { anchors.top: parent.top; anchors.left: parent.left; anchors.margins: 5; - } Image { id: imageItemid - height:20 - width:20; - anchors.right:parent.right + height: 20 + width: 20; + anchors.right: parent.right anchors.top: parent.top; anchors.margins: 5; visible: false; @@ -199,20 +197,20 @@ Rectangle { }//Component }//Table View - RowLayout{ - Rectangle{ + RowLayout { + Rectangle { width: 1 } Text{ - id:createStateText - width:statesComboBox.width; + id: createStateText + width: statesComboBox.width; height: statesComboBox.height; font.bold: true - text:"Create State ..." + text: "Create State ..." MouseArea { anchors.fill: parent; - hoverEnabled : true + hoverEnabled: true onEntered: { createStateText.color = statesComboBox.colorSelect; @@ -232,9 +230,9 @@ Rectangle { } states: State { name: "dropDown"; - PropertyChanges { target: dropDownList; height:(statesComboBox.rowHeight*(statesComboBox.items.count+1)) } - PropertyChanges { target: dropDownShowdowList; width:statesComboBox.width+3; height:(statesComboBox.rowHeight*(statesComboBox.items.count+1))+3 } - PropertyChanges { target:listView; height:20; implicitHeight: (statesComboBox.rowHeight*(statesComboBox.items.count)) } + PropertyChanges { target: dropDownList; height: (statesComboBox.rowHeight*(statesComboBox.items.count+1)) } + PropertyChanges { target: dropDownShowdowList; width: statesComboBox.width+3; height: (statesComboBox.rowHeight*(statesComboBox.items.count+1))+3 } + PropertyChanges { target: listView; height: 20; implicitHeight: (statesComboBox.rowHeight*(statesComboBox.items.count)) } } } diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index e5787f19b..1772c7f18 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -10,38 +10,6 @@ Item { property ListModel transactionModel: ListModel{} property ListModel callModel: ListModel{} - Action { - id: addStateAction - text: "Add State" - shortcut: "Ctrl+Alt+T" - enabled: codeModel.hasContract && !clientModel.running; - onTriggered: projectModel.stateListModel.addState(); - } - Action { - id: editStateAction - text: "Edit State" - shortcut: "Ctrl+Alt+T" - enabled: codeModel.hasContract && !clientModel.running && statesCombo.selectedIndex >= 0 && projectModel.stateListModel.count > 0; - onTriggered: projectModel.stateListModel.editState(statesCombo.selectedIndex); - } - Action { - id: playAndPauseAction - checkable: true; - checked: false; - iconSource: "qrc:/qml/img/play_button.png" - onToggled: { - if (checked) - { - this.iconSource = "qrc:/qml/img/pause_button2x.png" - console.log("play"); - }else{ - this.iconSource = "qrc:/qml/img/play_button2x.png" - console.log("pause"); - } - } - enabled: true - } - ColumnLayout { anchors.fill: parent RowLayout { @@ -80,8 +48,7 @@ Item { StatesComboBox { id: statesCombo - items:projectModel.stateListModel - //onSelectItem: console.log("Combobox Select Item: " + item ) + items: projectModel.stateListModel onSelectCreate: projectModel.stateListModel.addState(); onEditItem: projectModel.stateListModel.editState(item) colorItem: "black" From bcb76ac2a7593d93311fdbb5968a62938b45ca28 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 31 Mar 2015 16:56:02 +0200 Subject: [PATCH 27/50] logs window redesign --- mix/qml/LogsPane.qml | 395 +++++++++++++++++++++++--------- mix/qml/LogsPaneStyle.qml | 10 +- mix/qml/StatusPane.qml | 13 +- mix/qml/img/broom.png | Bin 501 -> 0 bytes mix/qml/img/clearicon.png | Bin 0 -> 2032 bytes mix/qml/img/cleariconactive.png | Bin 0 -> 2187 bytes mix/qml/img/copyicon.png | Bin 0 -> 871 bytes mix/qml/img/copyiconactive.png | Bin 0 -> 875 bytes mix/res.qrc | 5 +- 9 files changed, 295 insertions(+), 128 deletions(-) delete mode 100644 mix/qml/img/broom.png create mode 100644 mix/qml/img/clearicon.png create mode 100644 mix/qml/img/cleariconactive.png create mode 100644 mix/qml/img/copyicon.png create mode 100644 mix/qml/img/copyiconactive.png diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 1d832c21a..739ebc674 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -15,10 +15,11 @@ Rectangle anchors.fill: parent radius: 5 - color: LogsPaneStyle.generic.layout.backgroundColor - ColumnLayout { + color: "transparent" + id: logsPane + Column { z: 2 - height: parent.height + height: parent.height - rowAction.height width: parent.width spacing: 0 @@ -26,91 +27,129 @@ Rectangle id: logsModel } - TableView { - id: logsTable - clip: true - Layout.fillWidth: true - Layout.preferredHeight: parent.height - rowAction.height - headerVisible : false - onDoubleClicked: + ScrollView + { + id: scrollView + height: parent.height + width: parent.width + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + ColumnLayout { - var log = logsModel.get(logsTable.currentRow); - if (log) - clipboard.text = (log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content); - } + id: logsRect + spacing: 0 + Repeater { + clip: true + model: SortFilterProxyModel { + id: proxyModel + source: logsModel + property var roles: ["-", "javascript", "run", "state"] - model: SortFilterProxyModel { - id: proxyModel - source: logsModel - property var roles: ["-", "javascript", "run", "state"] + Component.onCompleted: { + filterType = regEx(proxyModel.roles); + } - Component.onCompleted: { - filterType = regEx(proxyModel.roles); - } + function search(_value) + { + filterContent = _value; + } - function search(_value) - { - filterContent = _value; - } + function toogleFilter(_value) + { + var count = roles.length; + for (var i in roles) + { + if (roles[i] === _value) + { + roles.splice(i, 1); + break; + } + } + if (count === roles.length) + roles.push(_value); - function toogleFilter(_value) - { - var count = roles.length; - for (var i in roles) - { - if (roles[i] === _value) + filterType = regEx(proxyModel.roles); + } + + function regEx(_value) { - roles.splice(i, 1); - break; + return "(?:" + roles.join('|') + ")"; } + + filterType: "(?:javascript|run|state)" + filterContent: "" + filterSyntax: SortFilterProxyModel.RegExp + filterCaseSensitivity: Qt.CaseInsensitive } - if (count === roles.length) - roles.push(_value); - filterType = regEx(proxyModel.roles); - } + Rectangle + { + width: 750 + height: 30 + color: + { + if (level === "warning" || level === "error") + return "#fffcd5"; + else + return index % 2 === 0 ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor; + } - function regEx(_value) - { - return "(?:" + roles.join('|') + ")"; - } - filterType: "(?:javascript|run|state)" - filterContent: "" - filterSyntax: SortFilterProxyModel.RegExp - filterCaseSensitivity: Qt.CaseInsensitive - } - TableViewColumn - { - role: "date" - title: qsTr("date") - width: LogsPaneStyle.generic.layout.dateWidth - delegate: itemDelegate - } - TableViewColumn - { - role: "type" - title: qsTr("type") - width: LogsPaneStyle.generic.layout.typeWidth - delegate: itemDelegate - } - TableViewColumn - { - role: "content" - title: qsTr("content") - width: LogsPaneStyle.generic.layout.contentWidth - delegate: itemDelegate - } + DefaultLabel { + text: date; + font.family: LogsPaneStyle.generic.layout.logLabelFont + width: LogsPaneStyle.generic.layout.dateWidth + font.pointSize: Style.absoluteSize(-1) + anchors.left: parent.left + anchors.leftMargin: 15 + anchors.verticalCenter: parent.verticalCenter + color: { + parent.getColor(level); + } + } - rowDelegate: Item { - Rectangle { - width: logsTable.width - 4 - height: 17 - color: styleData.alternate ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor + DefaultLabel { + text: type; + font.family: LogsPaneStyle.generic.layout.logLabelFont + width: LogsPaneStyle.generic.layout.typeWidth + font.pointSize: Style.absoluteSize(-1) + anchors.left: parent.left + anchors.leftMargin: 100 + anchors.verticalCenter: parent.verticalCenter + color: { + parent.getColor(level); + } + } + + DefaultLabel { + text: content; + font.family: LogsPaneStyle.generic.layout.logLabelFont + width: LogsPaneStyle.generic.layout.contentWidth + font.pointSize: Style.absoluteSize(-1) + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 190 + color: { + parent.getColor(level); + } + } + + function getColor() + { + if (level === "error") + return "red"; + else if (level === "warning") + return "orange"; + else + return "#808080"; + } + } } } + + } + Component { id: itemDelegate DefaultLabel { @@ -128,58 +167,43 @@ Rectangle } } + } + + Rectangle + { + gradient: Gradient { + GradientStop { position: 0.0; color: "#f1f1f1" } + GradientStop { position: 1.0; color: "#d9d7da" } + } + Layout.preferredHeight: LogsPaneStyle.generic.layout.headerHeight + height: LogsPaneStyle.generic.layout.headerHeight + width: logsPane.width + anchors.bottom: parent.bottom Row { id: rowAction - Layout.preferredHeight: LogsPaneStyle.generic.layout.headerHeight - height: LogsPaneStyle.generic.layout.headerHeight anchors.leftMargin: LogsPaneStyle.generic.layout.leftMargin anchors.left: parent.left spacing: LogsPaneStyle.generic.layout.headerButtonSpacing - Button - { - height: LogsPaneStyle.generic.layout.headerButtonHeight - anchors.verticalCenter: parent.verticalCenter - action: clearAction - iconSource: "qrc:/qml/img/broom.png" - } - - Action { - id: clearAction - enabled: logsModel.count > 0 - tooltip: qsTr("Clear") - onTriggered: { - logsModel.clear() - } - } - - Button + height: parent.height + Rectangle { - height: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + height: 20 + width: 50 anchors.verticalCenter: parent.verticalCenter - action: copytoClipBoardAction - iconSource: "qrc:/qml/img/copy.png" - } - - Action { - id: copytoClipBoardAction - enabled: logsModel.count > 0 - tooltip: qsTr("Copy to Clipboard") - onTriggered: { - var content = ""; - for (var k = 0; k < logsModel.count; k++) - { - var log = logsModel.get(k); - content += log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content + "\n"; - } - clipboard.text = content; + DefaultLabel + { + color: "#808080" + font.family: LogsPaneStyle.generic.layout.logLabelFont + text: qsTr("Show:") } } Rectangle { anchors.verticalCenter: parent.verticalCenter width: 1; - height: parent.height - 10 + height: parent.height color : "#808080" } @@ -187,6 +211,7 @@ Rectangle id: javascriptButton checkable: true height: LogsPaneStyle.generic.layout.headerButtonHeight + width: 20 anchors.verticalCenter: parent.verticalCenter checked: true onCheckedChanged: { @@ -202,16 +227,28 @@ Rectangle font.pointSize: Style.absoluteSize(-3) color: LogsPaneStyle.generic.layout.logLabelColor anchors.centerIn: parent - text: qsTr("JavaScript") + text: qsTr("JS") } } + background: + Rectangle { + color: javascriptButton.checked ? "#cfcfcf" : "transparent" + } } } + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color : "#808080" + } + ToolButton { id: runButton checkable: true height: LogsPaneStyle.generic.layout.headerButtonHeight + width: 30 anchors.verticalCenter: parent.verticalCenter checked: true onCheckedChanged: { @@ -230,14 +267,26 @@ Rectangle text: qsTr("Run") } } + background: + Rectangle { + color: runButton.checked ? "#cfcfcf" : "transparent" + } } } + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color : "#808080" + } + ToolButton { id: stateButton checkable: true height: LogsPaneStyle.generic.layout.headerButtonHeight anchors.verticalCenter: parent.verticalCenter + width: 35 checked: true onCheckedChanged: { proxyModel.toogleFilter("state") @@ -250,26 +299,144 @@ Rectangle DefaultLabel { font.family: LogsPaneStyle.generic.layout.logLabelFont font.pointSize: Style.absoluteSize(-3) - color: "#5391d8" + color: LogsPaneStyle.generic.layout.logLabelColor anchors.centerIn: parent text: qsTr("State") } } + background: + Rectangle { + color: stateButton.checked ? "#cfcfcf" : "transparent" + } + } + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color : "#808080" + } + } + + Row + { + height: parent.height + anchors.right: parent.right + anchors.rightMargin: 4 + spacing: 4 + Button + { + id: clearButton + height: LogsPaneStyle.generic.layout.headerButtonHeight + anchors.verticalCenter: parent.verticalCenter + action: hideAction + iconSource: "qrc:/qml/img/cleariconactive.png" + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } + } + } + + Image { + id: clearImage + source: "qrc:/qml/img/cleariconactive.png" + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 30 + height: 30 + } + + Button + { + id: exitButton + height: LogsPaneStyle.generic.layout.headerButtonHeight + anchors.verticalCenter: parent.verticalCenter + action: exitAction + iconSource: "qrc:/qml/img/exit.png" + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } + } + } + + Button + { + id: copyButton + height: LogsPaneStyle.generic.layout.headerButtonHeight + anchors.verticalCenter: parent.verticalCenter + action: copytoClipBoardAction + iconSource: "qrc:/qml/img/copyiconactive.png" + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } + } + } + + Action { + id: clearAction + tooltip: qsTr("Hide") + onTriggered: { + logsPane.parent.toggle(); + } + } + + Action { + id: hideAction + enabled: logsModel.count > 0 + tooltip: qsTr("Clear") + onTriggered: { + logsModel.clear() + } + } + + Action { + id: copytoClipBoardAction + enabled: logsModel.count > 0 + tooltip: qsTr("Copy to Clipboard") + onTriggered: { + var content = ""; + for (var k = 0; k < logsModel.count; k++) + { + var log = logsModel.get(k); + content += log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content + "\n"; + } + clipboard.text = content; } } DefaultTextField { id: searchBox - height: LogsPaneStyle.generic.layout.headerButtonHeight + height: LogsPaneStyle.generic.layout.headerButtonHeight - 5 anchors.verticalCenter: parent.verticalCenter - width: LogsPaneStyle.generic.layout.headerInputWidth + width: LogsPaneStyle.generic.layout.headerInputWidth - 40 font.family: LogsPaneStyle.generic.layout.logLabelFont font.pointSize: Style.absoluteSize(-3) font.italic: true + text: qsTr("Search") onTextChanged: { proxyModel.search(text); } + style: + TextFieldStyle { + background: Rectangle { + radius: 10 + } + } } } } diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index 1c5e2f4f5..17d30ff6c 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -11,17 +11,17 @@ QtObject { property QtObject generic: QtObject { property QtObject layout: QtObject { property string backgroundColor: "#f7f7f7" - property int headerHeight: 35 - property int headerButtonSpacing: 5 + property int headerHeight: 30 + property int headerButtonSpacing: 1 property int leftMargin: 10 property int headerButtonHeight: 30 - property string logLabelColor: "#5391d8" + property string logLabelColor: "#808080" property string logLabelFont: "sans serif" property int headerInputWidth: 200 property int dateWidth: 70 - property int typeWidth: 70 + property int typeWidth: 90 property int contentWidth: 250 - property string logAlternateColor: "#f0f0f0" + property string logAlternateColor: "#f6f5f6" } } } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index e097c866b..b42b13fef 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -45,7 +45,7 @@ Rectangle { function errorMessage(text, type) { status.state = "error"; - status.text = text + status.text = text; logPane.push("error", type, text); } @@ -76,7 +76,7 @@ Rectangle { function format(_message) { var formatted = _message.match(/(?:)/); - if (formatted) + if (!formatted) formatted = _message.match(/(?:)/); if (formatted && formatted.length > 1) formatted = formatted[1]; @@ -207,11 +207,9 @@ Rectangle { } id: logsContainer - width: 650 - //height: 0 - anchors.topMargin: 10 + width: 750 + anchors.topMargin: -30 anchors.top: statusContainer.bottom - //anchors.left: statusContainer.left anchors.horizontalCenter: parent.horizontalCenter visible: false radius: 5 @@ -227,9 +225,8 @@ Rectangle { top = top.parent var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; - //logsContainer.x = coordinates.x + 150; + logsContainer.x = coordinates.x + 150; logsContainer.y = coordinates.y; - console.log(logsContainer.x); } LogsPane diff --git a/mix/qml/img/broom.png b/mix/qml/img/broom.png deleted file mode 100644 index 76a9a0e0c90f9e671c3bbe3708f610c4a67f6383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 501 zcmVl0knEFf(l4s2f?(imaF8NZjcWVO_}LI%a>%36+i~6T z^SQ6|3LtJhk^&Jz2utc^beF3b$swE(%#*EL^P}y!?)c0Gl3UrZ22;|P1>z-6qMhu) zSc&&J#k}OZ**r#`z41$?i>u|{BT{dCD|@ZL88aFoS+UGi|GK$H7_unV$Vw4NT7uEW zm-O+BfvnnV%>p9leRp*vN5T*w=e|-;#;Y22rS3Px+s!2paRA>e5ntfWkEm&;17j4?BOR^BeKSH7) z3M(pzlKP`01WEiSQd_0DNwT$=jhHnQMWXVL+&{}mH%EdKH`+^|-{qXA^W5G0Joi4& zy*c7Ja5yjboZs*J{r%3%z31GFjC4p_AZ>xP1=1EsTVT#uATvxPwY9Y+MMXtTSy@@N z=$S8ZW@aX$@}l};W@hFkNhMBCPxp_Fjdl0;_x~ji!w7*BZfvr$`z7s* zunc3A^=Z$FVhA6G>qfFE4`GoPFQ_fA6aDu{JMlD0ouA?DnXp=*PNBe@v!YiNA4KUh zWJ4znj+%)gqPt!p-$3C35qJLl`EQmjTULyRWo~DX-bMKi>SeoUBI5_wR zx-O$rUSUP|%19)#cW7ux8^KX`LJzCg#bW7=MbAKXrzwf@i>9Yh+=i#cAPJ3W%1I{A z3cU~AzpB2)3Ts?ZaS5wcal0YmZSvDb*~&VQ-pHIj$h`9P;b52Rp)Au&UTJmMt}yHJ ztTZlRTDRdby%_uqvCdf%RE3>1)lU`{79I$jG+sUm>3)Hsu(l~kj!7cI*8Gs3EE4aL z#GRKeq(k>K*!CLiqL_`kXx5dmELOCtQ7xy&$H(RSG+}Tc{RAuMXJLApkCZNe>8Vzu zusdRPB`hZu3=wM%GGtEiS$4%yf&qjBF6G?sWCj#^Ak7j=hJQzz2A^naPEr_0L9$_;E$>_(lHbtR1TqjN%zQtcg6 zDceaSYkdHu%QPkvyROrzD`6T$t;D_-C}C0VM4I7!sIs#1CJoL{YQq@CZkOSSFcw>G z?-)ecP8vO}ixw?PiZm$!t86-7l;zlVh9T~>p=S9BuPJ{f!VO@YAbd1u-xKd zHM!W5eYm>5zP>c3XMhD4(uchc?}mnkTfn$dAPHu{?gr15u)4fDp*m*e=H@oL2??U! zf%Lk?ix+?8g*3ZJD;V?%%ZYdwZ?1$DiRdRGi^8@bh{cm(Cr#V6LYh+y>xRRnZzkAY zF`h*+8+FlaBEszqk#W`f0Z#wrb}!W6L>h&zq%p>NhI6HWQdryL0gOu+ z{3k@qX$2(0I))5rt zvkGHOU#EiSuORzn8W#N#fe!*mZty}64CN0Y_=1C?;4jleiQLXXQtopsf+(-1x)&hP zmv#p*fmJC_?=b}m7Qy88=1}^28q!(`N(WG|RhJfA*N2f}Soy^w<`q}4 z2qr)J5-wVHVJsv+EnT{FkovU%$RQRppEfU9vV{As!C&m{11M)g_9f)(N7t<)PkDBW z-`jub>v;}KV>2j=cTi_8UOxclWvs4WNzE?4^K3iykbH}19vT1lKecG&Zoe%-x`Qv4 zkMaC>koUEy$-8q!MMVRBUqjFRT9-<1+;2-72xrW$Kc+$a8tr;Wk70mwan-#?C>SC*gIk|uaH~jbESs>FDX$zz+khZ{Fw!lBxaB+RQQH;I- O0000Px-MM*?KRA>e5T5D_-MHD`>w=baB5~Qt(S|}1zh|!?(Dkd0IdI13+5X2WIgdau? z6_tP{_K#FlC{YumA^s5%!3Pq}tu+Kfc!@7e6k;kMY9bE_G=lWO?)aU(JA3zTclYjn zVH5AP+ZFNz0Gver1PMA}NPYMDF0F0%^4hcc!j*Hv(N!H+Q%UiBB5fu>HwZyR z>42A#ER;P7p(v0-(7NL zuB@Il;VI3>$_7+uPeIXg5~4DRh$I7`ze6XqlOgsSq@R?!cABX36w5{AkQzN=RBM8& z1!?s{lQTeY0*1GitVf>1RA{-_X}rF(c|=#ze`#j2B7E2CU#=k}Tr@Z#_m8FrgC^}&=M#|(QVJQz@GJ0pVFTL*fr1CT}8554KJ~lx_ zw5>#<+HOzE!?5T}vAqX2(Uy6-U7lg0aqVxj1j!Z`77_0$Ens>Y!}rlx)9{!o%SSwI&CzlAyloXiT&46Ix_mfY(#ea1(&Q7z zhcT^7{#)+C5N=N{%YE*Pr|S+-PtQ0hu?Sj$M;T*M`7m*43!4j6r1s}wqW|C z3GWf+n<~p!-2Uv17hvhxu=JntHbgaJV~kZ;X&OVNKt=)*A2ciuV z)?W_Ny!*m7bdI?(VF36nniy>`{)v=?c?SgxE>|kB^?NbaREw=25#lB%X~@mLT%>tU zV=66CxELd2Re8TSCE@sXF}{NWx$k0~@3uIVd6J$qe#7OkblaY<*1^h$Ogz}-nOL3R zJksbG|6m>jN=rKI@1NA~i8YPDW}|P2wjOWALSpwgNxAu-&Z7_RY`&cj19=O)If2za zK<{fFBmb`Qam9;Iob{mN9 zW*HN!c~bMQ5llFK#4~H-Bfkm>-ck7mPtuij8}m&XCzN**pv+@wBI`=|61EnA21{P= z(r`Wv5&DoOF?T>k-TV0@-K}@UU<$*6*ATRL`4Z-v3UzpgS-;-dG~!$czNUzqH0JjG z`6Rvbnd|?;5!5_PFlNT?ht-#`c`c)AN%~SH!^WPZE9*Ap%hJ*ipDS!h*j1qw`x3?w ziQhXxP#E%nt6r#VAJQc58(1;&gM5(2h(2tCa$vX1tb{*dT(~J=UFhZwh03QByGdgy zy_ZSfy!e~qbo8W>#lm&cmT_RW%dCViVa!|mV2?SNF=1}Ui*(iKs+^LJ=$cK~i9Ix7 z`zjSRPIsQkim(@H?0D{}s;}CdD@*I*>xXU0*3!c&hF00w9N6tLE8$BRCbj1T zU!}S$W|Mc5#x`_z)}(b~n8M`5uF6#GOW1UOSWB{nt!Vd2{UOrNRd3!4Z zV$6))51cPy%Xwv9<*=`(xO8CDPf0Gy`;aCvv$mrA<1nNnrA4!VL0us3339yo5{{Ed z90@gz7UzOkkPbI#tll%2bo9v%)5GCYSAfK_#D59QiLyj0m@xdaj+?>TrnUY$BT+R! zDKFAAvc#8kwDs6*EOuiUjfoYQgOCLhHt&YupH&Jp(pspwIk1kB%_eq}#u_r+lQggh zp}khv66Bk~%A7kjC?hsqpeQ<2&ql&GR2TYEjtzo-Kj&R-9Pg){b4; zk?x|#d*^Eg54r>INS=p1CaJc}_`iI%q<{oHOat)?7(?ySFh0jM>S4ZF7nJRkPLStu*?K%oZ;JPx&AxT6*RA>e5o4;=pF%-w|l5$+s3@jA`5?clsDzS6|DMO_EV2EHtELGL18xv)r z142|x4EzH~3_u13M1E943T&`3v`dyQhyhhXD5w$n)vv1y%BA($@!5B_a+a(++wb|k zkDqh#%MZ(1uwtv^&FAw=uIt{hZF>`TRs?N*Xfzr-g1Tqamd^A@>;UY8R4Vm6!?bBKDxs*qoX%mwHSaQ%li3Cc~(<#sxq zPq+_Nlx^v9xqK1M_K0_I{uQ?6I*+G_<`>A_Lj3`~`?!Ae7J;bmhK+QJ%%W?-B7KH$ zw*mgw^Klys@+^$MS_2a>+0fbp%Z4@rSSGYFz_Or?0+s=79B^1@BZ0#}8w)H7tqeGu z%?@ymzMD>`i>ObDgDT2-@6$NtZP08fOCD;q+7L$H(+sovak_Gf#o`)Ej*O2+qhlOD zcTt~s@>ghj+`v(%dT@RPJL4#FE5olguEV#Wz3}CB~RPQH`G3Z={Tn0KM z)f=Gg;z|+#iPdhST;*1W^kpk-g9XW8^(6Io=2^|}7T+p!s#{nHXaMaLR z07nU}4KNKlDAgl6^A_H-^t|)> zjAaxszM%UBkb5*3o_?dYG!GCrB#4$ x;#TxeSJSqG?*FHH?RNY0pD{tg$ymS&oB)dpf?$zAFg5@H002ovPDHLkV1mRUlNbO1 literal 0 HcmV?d00001 diff --git a/mix/qml/img/copyiconactive.png b/mix/qml/img/copyiconactive.png new file mode 100644 index 0000000000000000000000000000000000000000..387d7f1fa62de3d8c41537c20f31479c09aa6ec5 GIT binary patch literal 875 zcmV-x1C;!UP)Px&B}qge5o6l<#K@`W|+k`Yl54{u-p=s2M9tvK(6+8%S>Ou4%h!+u0g3{!o zUbG-$Q7}RL2fSH(@E{u7i$899^I$JRXawoOixkB|viqD(8k-HfJCoU+-5s)fNOor4 zoA*BRW|RGfEWn5zsFL^8(z|Sa;_x{nxC#i9Qn4&}Rj(B8O8L4tWnKD0>&j0Q%Ld>> z1}lFUaAKj>%)MDG+?JnY&of9Wd$YKoVX4||AmTIuZ3DrUyP2~W0jJmkjT1o|klL)B z?^@7u7|_aqOV_`R;gPW&J6R%nRxcMWcN6!2U8puc0^%%NpdUo$CBV#UMA+B$3Jz`f zhmUu(UMYS6GS9GT|LJCex7hZ65G1Qa1KVI>Lnj_MY-lZj!-UobI4o$bfWv^+4mc>Z zmcT)vwFQ=iRtCI(_GsHcJfAVLa~Z?9ZzrhYaQmJvRX4AA#Zo37RxhB*g1+<$%<5FPF9nw10VYLn@)kiz9wt@l^~0U6ZXU~_v0?WSS$FE?>E89+ zZwAUfr5#aN!|l^FsMH&bA<~Wv*iI%1(2)Ws0XlNvxS?YKjuSdI;JBb;1&#wccHpR? z69F70bYg(Lp#7wt?KA8ldM`cfybgO+QqK`Yun`HcDyb*P=rBvvmUd*OsG+pNs->RH znkWTcs}x?yB-N36z}L1ibC2AXPJv~%iB3Lgg>|ZyOs*qWVWnS7G8ORiIs0Vmc*|;i z^|P_Z2GiYU%{SgI7T0_2!FR1HJdW94zp3?n5MsA&kwxn}+tvze zlZOpx1-yFW;7raPfq5&W`*>Pm-7Cn;Kdmrtg>)ZJE3A73dHJUm z=B<$K<3fLGu^~&f?_ZelOw_;@nDb2itc4Xqml/fonts/SourceSerifPro-Semibold.ttf qml/img/available_updates.png qml/img/b64.png - qml/img/broom.png qml/img/bugiconactive.png qml/img/bugiconinactive.png qml/img/closedtriangleindicator.png @@ -53,5 +52,9 @@ stdc/config.sol stdc/namereg.sol stdc/std.sol + qml/img/clearicon.png + qml/img/cleariconactive.png + qml/img/copyicon.png + qml/img/copyiconactive.png From 323a1aea0e6c81b58b757c95eaf67612c9c9eae9 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 31 Mar 2015 18:15:45 +0200 Subject: [PATCH 28/50] ui changes --- mix/qml/LogsPane.qml | 244 +++++++++++++++++++++++++------------- mix/qml/LogsPaneStyle.qml | 2 +- 2 files changed, 161 insertions(+), 85 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 739ebc674..765f905b1 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -189,12 +189,13 @@ Rectangle Rectangle { color: "transparent" - height: 20 - width: 50 - anchors.verticalCenter: parent.verticalCenter + height: parent.height + width: 40 DefaultLabel { + anchors.verticalCenter: parent.verticalCenter color: "#808080" + font.pointSize: Style.absoluteSize(-3) font.family: LogsPaneStyle.generic.layout.logLabelFont text: qsTr("Show:") } @@ -204,7 +205,7 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#808080" + color : "transparent" } ToolButton { @@ -232,7 +233,7 @@ Rectangle } background: Rectangle { - color: javascriptButton.checked ? "#cfcfcf" : "transparent" + color: javascriptButton.checked ? "#dcdcdc" : "transparent" } } } @@ -241,7 +242,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#808080" + color : "#d3d0d0" + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color : "#f2f1f2" } ToolButton { @@ -269,7 +277,7 @@ Rectangle } background: Rectangle { - color: runButton.checked ? "#cfcfcf" : "transparent" + color: runButton.checked ? "#dcdcdc" : "transparent" } } } @@ -278,7 +286,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#808080" + color : "#d3d0d0" + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color : "#f2f1f2" } ToolButton { @@ -306,7 +321,7 @@ Rectangle } background: Rectangle { - color: stateButton.checked ? "#cfcfcf" : "transparent" + color: stateButton.checked ? "#dcdcdc" : "transparent" } } } @@ -315,7 +330,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#808080" + color : "#d3d0d0" + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 1; + height: parent.height + color : "#f2f1f2" } } @@ -323,98 +345,97 @@ Rectangle { height: parent.height anchors.right: parent.right - anchors.rightMargin: 4 - spacing: 4 - Button + anchors.rightMargin: 10 + spacing: 10 + Rectangle { - id: clearButton height: LogsPaneStyle.generic.layout.headerButtonHeight anchors.verticalCenter: parent.verticalCenter - action: hideAction - iconSource: "qrc:/qml/img/cleariconactive.png" - style: - ButtonStyle { - background: - Rectangle { - height: LogsPaneStyle.generic.layout.headerButtonHeight - implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight - color: "transparent" + color: "transparent" + width: 20 + Button + { + id: clearButton + action: clearAction + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + height: 25 + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } } } - } - Image { - id: clearImage - source: "qrc:/qml/img/cleariconactive.png" - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - width: 30 - height: 30 - } + Image { + id: clearImage + source: "qrc:/qml/img/cleariconactive.png" + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 20 + height: 20 + } - Button - { - id: exitButton - height: LogsPaneStyle.generic.layout.headerButtonHeight - anchors.verticalCenter: parent.verticalCenter - action: exitAction - iconSource: "qrc:/qml/img/exit.png" - style: - ButtonStyle { - background: - Rectangle { - height: LogsPaneStyle.generic.layout.headerButtonHeight - color: "transparent" + Action { + id: clearAction + enabled: logsModel.count > 0 + tooltip: qsTr("Clear") + onTriggered: { + logsModel.clear(); } } } - Button + Rectangle { - id: copyButton height: LogsPaneStyle.generic.layout.headerButtonHeight anchors.verticalCenter: parent.verticalCenter - action: copytoClipBoardAction - iconSource: "qrc:/qml/img/copyiconactive.png" - style: - ButtonStyle { - background: - Rectangle { - height: LogsPaneStyle.generic.layout.headerButtonHeight - color: "transparent" + color: "transparent" + width: 20 + Button + { + id: copyButton + action: copyAction + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + height: 25 + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } } } - } - - Action { - id: clearAction - tooltip: qsTr("Hide") - onTriggered: { - logsPane.parent.toggle(); - } - } - Action { - id: hideAction - enabled: logsModel.count > 0 - tooltip: qsTr("Clear") - onTriggered: { - logsModel.clear() + Image { + id: copyImage + source: "qrc:/qml/img/copyiconactive.png" + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 20 + height: 20 } - } - Action { - id: copytoClipBoardAction - enabled: logsModel.count > 0 - tooltip: qsTr("Copy to Clipboard") - onTriggered: { - var content = ""; - for (var k = 0; k < logsModel.count; k++) - { - var log = logsModel.get(k); - content += log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content + "\n"; + Action { + id: copyAction + enabled: logsModel.count > 0 + tooltip: qsTr("Copy to Clipboard") + onTriggered: { + var content = ""; + for (var k = 0; k < logsModel.count; k++) + { + var log = logsModel.get(k); + content += log.type + "\t" + log.level + "\t" + log.date + "\t" + log.content + "\n"; + } + clipboard.text = content; } - clipboard.text = content; } } @@ -427,10 +448,22 @@ Rectangle font.family: LogsPaneStyle.generic.layout.logLabelFont font.pointSize: Style.absoluteSize(-3) font.italic: true - text: qsTr("Search") + text: qsTr(" - Search - ") + onFocusChanged: + { + if (!focus && text === "") + text = qsTr(" - Search - "); + else if (focus && text === qsTr(" - Search - ")) + text = ""; + } + onTextChanged: { - proxyModel.search(text); + if (text === qsTr(" - Search - ")) + proxyModel.search(""); + else + proxyModel.search(text); } + style: TextFieldStyle { background: Rectangle { @@ -438,6 +471,49 @@ Rectangle } } } + + + Rectangle + { + height: LogsPaneStyle.generic.layout.headerButtonHeight + anchors.verticalCenter: parent.verticalCenter + color: "transparent" + width: 20 + Button + { + id: hideButton + action: hideAction + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + height: 25 + style: + ButtonStyle { + background: + Rectangle { + height: LogsPaneStyle.generic.layout.headerButtonHeight + implicitHeight: LogsPaneStyle.generic.layout.headerButtonHeight + color: "transparent" + } + } + } + + Image { + id: hideImage + source: "qrc:/qml/img/exit.png" + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 20 + height: 20 + } + + Action { + id: hideAction + tooltip: qsTr("Exit") + onTriggered: { + logsPane.parent.toggle(); + } + } + } } } } diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index 17d30ff6c..215f17bd7 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -12,7 +12,7 @@ QtObject { property QtObject layout: QtObject { property string backgroundColor: "#f7f7f7" property int headerHeight: 30 - property int headerButtonSpacing: 1 + property int headerButtonSpacing: 0 property int leftMargin: 10 property int headerButtonHeight: 30 property string logLabelColor: "#808080" From 3d7b28afb7a5ae740f5025056a4041d64420afcc Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 31 Mar 2015 18:20:31 +0200 Subject: [PATCH 29/50] add disabled clear button and copy button --- mix/qml/LogsPane.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 765f905b1..21bd9fd96 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -373,7 +373,7 @@ Rectangle Image { id: clearImage - source: "qrc:/qml/img/cleariconactive.png" + source: clearAction.enabled ? "qrc:/qml/img/cleariconactive.png" : "qrc:/qml/img/clearicon.png" anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: 20 @@ -416,7 +416,7 @@ Rectangle Image { id: copyImage - source: "qrc:/qml/img/copyiconactive.png" + source: copyAction.enabled ? "qrc:/qml/img/copyiconactive.png" : "qrc:/qml/img/copyicon.png" anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: 20 From 7bc2251eed74de29862c3cdd37ca24e3840aaaa8 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 31 Mar 2015 18:46:01 +0200 Subject: [PATCH 30/50] debug highlighting filter --- mix/CodeModel.cpp | 22 +++++++++++++++++++--- mix/qml/CodeEditorView.qml | 9 --------- mix/qml/ProjectModel.qml | 1 + mix/qml/WebPreview.qml | 2 +- mix/qml/html/codeeditor.js | 2 -- mix/qml/js/ProjectModel.js | 10 +++++++++- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index a96ab8791..3d0f0c749 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -93,8 +93,24 @@ private: bool m_functionScope; uint m_storageSlot; }; + +dev::eth::AssemblyItems filterLocations(dev::eth::AssemblyItems const& _locations, dev::solidity::ContractDefinition const& _contract, QHash _functions) +{ + dev::eth::AssemblyItems result; + result.reserve(_locations.size()); + std::string sourceName = *_contract.getLocation().sourceName; + for (dev::eth::AssemblyItem item : _locations) + { + dev::SourceLocation const& l = item.getLocation(); + if (sourceName != *l.sourceName || _contract.getLocation() == l || _functions.contains(LocationPair(l.start, l.end))) + item.setLocation(dev::SourceLocation(-1, -1, l.sourceName)); + result.push_back(item); + } + return result; } +} //namespace + void BackgroundWorker::queueCodeChange(int _jobId) { m_model->runCompilationJob(_jobId); @@ -105,13 +121,11 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler m_sourceHash(qHash(_source)) { std::string name = _contractName.toStdString(); - auto const& contractDefinition = _compiler.getContractDefinition(name); + ContractDefinition const& contractDefinition = _compiler.getContractDefinition(name); m_contract.reset(new QContractDefinition(nullptr, &contractDefinition)); QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership); m_contract->moveToThread(QApplication::instance()->thread()); m_bytes = _compiler.getBytecode(_contractName.toStdString()); - m_assemblyItems = _compiler.getRuntimeAssemblyItems(name); - m_constructorAssemblyItems = _compiler.getAssemblyItems(name); dev::solidity::InterfaceHandler interfaceHandler; m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition)); @@ -122,6 +136,8 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler CollectDeclarationsVisitor visitor(&m_functions, &m_locals, &m_storage); contractDefinition.accept(visitor); + m_assemblyItems = filterLocations(_compiler.getRuntimeAssemblyItems(name), contractDefinition, m_functions); + m_constructorAssemblyItems = filterLocations(_compiler.getAssemblyItems(name), contractDefinition, m_functions); } QString CompiledContract::codeHex() const diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 7ea1e30d9..25ecbc98c 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -11,15 +11,6 @@ Item { signal breakpointsChanged(string documentId) signal isCleanChanged(var isClean, string documentId) - function getDocumentIdByName(fileName) - { - for (var i = 0; i < editorListModel.count; i++) { - if (editorListModel.get(i).fileName === fileName) { - return editorListModel.get(i).documentId; - } - } - return null; - } function getDocumentText(documentId) { for (var i = 0; i < editorListModel.count; i++) { diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index f4b73b601..ec7681f16 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -64,6 +64,7 @@ Item { function renameDocument(documentId, newName) { ProjectModelCode.renameDocument(documentId, newName); } function removeDocument(documentId) { ProjectModelCode.removeDocument(documentId); } function getDocument(documentId) { return ProjectModelCode.getDocument(documentId); } + function getDocumentIdByName(documentName) { return ProjectModelCode.getDocumentIdByName(documentName); } function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } function deployProject() { ProjectModelCode.deployProject(false); } diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 0bf31b326..768d188cb 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -156,7 +156,7 @@ Item { if (urlPath === "/") urlPath = "/index.html"; var documentName = urlPath.substr(urlPath.lastIndexOf("/") + 1); - var documentId = projectModel.codeEditor.getDocumentIdByName(documentName); + var documentId = projectModel.getDocumentIdByName(documentName); var content = ""; if (projectModel.codeEditor.isDocumentOpen(documentId)) content = projectModel.codeEditor.getDocumentText(documentId); diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 5d63a7a83..d61d6e51f 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -124,8 +124,6 @@ var executionMark; highlightExecution = function(start, end) { if (executionMark) executionMark.clear(); - if (start === 0 && end + 1 === editor.getValue().length) - return; // Do not hightlight the whole document. if (debugWarning) debugWarning.clear(); executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" }); diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 177115f83..25e8dcb77 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -172,7 +172,7 @@ function getDocumentIndex(documentId) for (var i = 0; i < projectListModel.count; i++) if (projectListModel.get(i).documentId === documentId) return i; - console.error("Cant find document " + documentId); + console.error("Can't find document " + documentId); return -1; } @@ -291,6 +291,14 @@ function getDocument(documentId) { return projectListModel.get(i); } +function getDocumentIdByName(fileName) +{ + for (var i = 0; i < projectListModel.count; i++) + if (projectListModel.get(i).fileName === fileName) + return projectListModel.get(i).documentId; + return null; +} + function removeDocument(documentId) { var i = getDocumentIndex(documentId); var document = projectListModel.get(i); From db30ab24a045735f9b05a40bccdbb159891ec038 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 31 Mar 2015 18:54:13 +0200 Subject: [PATCH 31/50] Make paranoia safe again after a break caused by BlockChain cache flushing. Fixes #1334 --- libdevcrypto/MemoryDB.h | 2 ++ libethereum/BlockChain.cpp | 21 +++++++++++++++------ libethereum/State.cpp | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/libdevcrypto/MemoryDB.h b/libdevcrypto/MemoryDB.h index 7d39ba73b..7858126f8 100644 --- a/libdevcrypto/MemoryDB.h +++ b/libdevcrypto/MemoryDB.h @@ -32,8 +32,10 @@ namespace dev { struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; }; +struct DBWarn: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 1; }; #define dbdebug clog(DBChannel) +#define dbwarn clog(DBWarn) class MemoryDB { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 508531f9d..8c0bd2b8b 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -339,6 +339,13 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) #endif // All ok - insert into DB { + // ensure parent is cached for later addition. + // TODO: this is a bit horrible would be better refactored into an enveloping UpgradableGuard + // together with an "ensureCachedWithUpdatableLock(l)" method. + // This is safe in practice since the caches don't get flushed nearly often enough to be + // done here. + details(bi.parentHash); + WriteGuard l(x_details); m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}); m_details[bi.parentHash].children.push_back(newHash); @@ -455,14 +462,14 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) h256s BlockChain::treeRoute(h256 const& _from, h256 const& _to, h256* o_common, bool _pre, bool _post) const { - // cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); + cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); if (!_from || !_to) return h256s(); h256s ret; h256s back; unsigned fn = details(_from).number; unsigned tn = details(_to).number; - // cdebug << "treeRoute" << fn << "..." << tn; + cdebug << "treeRoute" << fn << "..." << tn; h256 from = _from; while (fn > tn) { @@ -470,7 +477,7 @@ h256s BlockChain::treeRoute(h256 const& _from, h256 const& _to, h256* o_common, ret.push_back(from); from = details(from).parent; fn--; - // cdebug << "from:" << fn << _from.abridged(); + cdebug << "from:" << fn << _from.abridged(); } h256 to = _to; while (fn < tn) @@ -479,12 +486,14 @@ h256s BlockChain::treeRoute(h256 const& _from, h256 const& _to, h256* o_common, back.push_back(to); to = details(to).parent; tn--; - // cdebug << "to:" << tn << _to.abridged(); + cdebug << "to:" << tn << _to.abridged(); } while (from != to) { - assert(from); - assert(to); + if (!from) + assert(from); + if (!to) + assert(to); from = details(from).parent; to = details(to).parent; if (_pre) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c52c90921..fa457dc41 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -725,7 +725,7 @@ void State::commitToMine(BlockChain const& _bc) uncommitToMine(); // cnote << "Committing to mine on block" << m_previousBlock.hash.abridged(); -#ifdef ETH_PARANOIA +#if ETH_PARANOIA && 0 commit(); cnote << "Pre-reward stateRoot:" << m_state.root(); #endif From 3efcc49bdfdc751dc17a1fc63f6337d1e7b00bad Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 31 Mar 2015 18:54:50 +0200 Subject: [PATCH 32/50] Upgrade to latest ethhash API. --- libethash/ethash.h | 78 +++++++++++++++++++++++++---------------- libethash/internal.c | 30 ++++++++-------- libethash/internal.h | 6 ++-- libethash/io.c | 2 +- libethash/io_posix.c | 2 +- libethash/io_win32.c | 2 +- libethcore/Ethasher.cpp | 25 ++++++++++--- libethcore/Ethasher.h | 27 ++++++-------- test/dagger.cpp | 4 +-- 9 files changed, 100 insertions(+), 76 deletions(-) diff --git a/libethash/ethash.h b/libethash/ethash.h index eb3097307..7594fc835 100644 --- a/libethash/ethash.h +++ b/libethash/ethash.h @@ -24,19 +24,20 @@ #include #include #include +#include #include "compiler.h" -#define REVISION 23 -#define DATASET_BYTES_INIT 1073741824U // 2**30 -#define DATASET_BYTES_GROWTH 8388608U // 2**23 -#define CACHE_BYTES_INIT 1073741824U // 2**24 -#define CACHE_BYTES_GROWTH 131072U // 2**17 -#define EPOCH_LENGTH 30000U -#define MIX_BYTES 128 -#define HASH_BYTES 64 -#define DATASET_PARENTS 256 -#define CACHE_ROUNDS 3 -#define ACCESSES 64 +#define ETHASH_REVISION 23 +#define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30 +#define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23 +#define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24 +#define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17 +#define ETHASH_EPOCH_LENGTH 30000U +#define ETHASH_MIX_BYTES 128 +#define ETHASH_HASH_BYTES 64 +#define ETHASH_DATASET_PARENTS 256 +#define ETHASH_CACHE_ROUNDS 3 +#define ETHASH_ACCESSES 64 #ifdef __cplusplus extern "C" { @@ -61,34 +62,49 @@ static inline void ethash_params_init(ethash_params *params, const uint32_t bloc params->cache_size = ethash_get_cachesize(block_number); } -typedef struct ethash_cache { - void *mem; -} ethash_cache; +/*********************************** + * OLD API ************************* + *********************************** + ******************** (deprecated) * + ***********************************/ -void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); -void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); -void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); -void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); +void ethash_mkcache(void *cache, ethash_params const *params, const uint8_t seed[32]); +void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); +void ethash_compute_full_data(void *mem, ethash_params const *params, void const *cache); +void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); -static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { - ethash_cache c; - c.mem = cache; - ethash_mkcache(&c, params, seed); -} +/*********************************** + * NEW API ************************* + ***********************************/ + +// TODO: compute params and seed in ethash_new_light; it should take only block_number +// TODO: store params in ethash_light_t/ethash_full_t to avoid having to repass into compute/new_full + +typedef uint8_t const ethash_seedhash_t[32]; -static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { - ethash_cache c; - c.mem = (void *) cache; - ethash_light(ret, &c, params, header_hash, nonce); +typedef void const* ethash_light_t; +static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) { + void* ret = malloc(params->cache_size); + ethash_mkcache(ret, params, seed); + return ret; +} +static inline void ethash_compute_light(ethash_return_value *ret, ethash_light_t light, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { + ethash_light(ret, light, params, header_hash, nonce); +} +static inline void ethash_delete_light(ethash_light_t light) { + free((void*)light); } +typedef void const* ethash_full_t; +static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) { + void* ret = malloc(params->full_size); + ethash_compute_full_data(ret, params, light); + return ret; +} static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { - ethash_cache c; - c.mem = (void *) cache; - ethash_compute_full_data(full, params, &c); + ethash_compute_full_data(full, params, cache); } - static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_full(ret, full, params, header_hash, nonce); } diff --git a/libethash/internal.c b/libethash/internal.c index ae9b95065..130ca13c3 100644 --- a/libethash/internal.c +++ b/libethash/internal.c @@ -38,13 +38,13 @@ #endif // WITH_CRYPTOPP uint64_t ethash_get_datasize(const uint32_t block_number) { - assert(block_number / EPOCH_LENGTH < 2048); - return dag_sizes[block_number / EPOCH_LENGTH]; + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return dag_sizes[block_number / ETHASH_EPOCH_LENGTH]; } uint64_t ethash_get_cachesize(const uint32_t block_number) { - assert(block_number / EPOCH_LENGTH < 2048); - return cache_sizes[block_number / EPOCH_LENGTH]; + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return cache_sizes[block_number / ETHASH_EPOCH_LENGTH]; } // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) @@ -63,7 +63,7 @@ void static ethash_compute_cache_nodes( SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64); } - for (unsigned j = 0; j != CACHE_ROUNDS; j++) { + for (unsigned j = 0; j != ETHASH_CACHE_ROUNDS; j++) { for (unsigned i = 0; i != num_nodes; i++) { uint32_t const idx = nodes[i].words[0] % num_nodes; node data; @@ -85,10 +85,10 @@ void static ethash_compute_cache_nodes( } void ethash_mkcache( - ethash_cache *cache, + void *cache, ethash_params const *params, const uint8_t seed[32]) { - node *nodes = (node *) cache->mem; + node *nodes = (node *) cache; ethash_compute_cache_nodes(nodes, params, seed); } @@ -96,10 +96,10 @@ void ethash_calculate_dag_item( node *const ret, const unsigned node_index, const struct ethash_params *params, - const struct ethash_cache *cache) { + const void *cache) { uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); - node const *cache_nodes = (node const *) cache->mem; + node const *cache_nodes = (node const *) cache; node const *init = &cache_nodes[node_index % num_parent_nodes]; memcpy(ret, init, sizeof(node)); @@ -114,7 +114,7 @@ void ethash_calculate_dag_item( __m128i xmm3 = ret->xmm[3]; #endif - for (unsigned i = 0; i != DATASET_PARENTS; ++i) { + for (unsigned i = 0; i != ETHASH_DATASET_PARENTS; ++i) { uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes; node const *parent = &cache_nodes[parent_index]; @@ -150,7 +150,7 @@ void ethash_calculate_dag_item( void ethash_compute_full_data( void *mem, ethash_params const *params, - ethash_cache const *cache) { + void const *cache) { assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0); assert((params->full_size % sizeof(node)) == 0); node *full_nodes = mem; @@ -164,7 +164,7 @@ void ethash_compute_full_data( static void ethash_hash( ethash_return_value *ret, node const *full_nodes, - ethash_cache const *cache, + void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { @@ -201,7 +201,7 @@ static void ethash_hash( num_full_pages = (unsigned) (params->full_size / page_size); - for (unsigned i = 0; i != ACCESSES; ++i) { + for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) { uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages; for (unsigned n = 0; n != MIX_NODES; ++n) { @@ -275,7 +275,7 @@ void ethash_quick_hash( void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) { memset(seedhash, 0, 32); - const uint32_t epochs = block_number / EPOCH_LENGTH; + const uint32_t epochs = block_number / ETHASH_EPOCH_LENGTH; for (uint32_t i = 0; i < epochs; ++i) SHA3_256(seedhash, seedhash, 32); } @@ -295,6 +295,6 @@ void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params c ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); } -void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { +void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { ethash_hash(ret, NULL, cache, params, previous_hash, nonce); } diff --git a/libethash/internal.h b/libethash/internal.h index ddd06e8f4..dec7e6b13 100644 --- a/libethash/internal.h +++ b/libethash/internal.h @@ -15,7 +15,7 @@ extern "C" { // compile time settings #define NODE_WORDS (64/4) -#define MIX_WORDS (MIX_BYTES/4) +#define MIX_WORDS (ETHASH_MIX_BYTES/4) #define MIX_NODES (MIX_WORDS / NODE_WORDS) #include @@ -34,7 +34,7 @@ void ethash_calculate_dag_item( node *const ret, const unsigned node_index, ethash_params const *params, - ethash_cache const *cache + void const *cache ); void ethash_quick_hash( @@ -45,4 +45,4 @@ void ethash_quick_hash( #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/libethash/io.c b/libethash/io.c index dd4f1f9e8..0e935fa59 100644 --- a/libethash/io.c +++ b/libethash/io.c @@ -71,7 +71,7 @@ bool ethash_io_write(char const *dirname, goto fail_free; } - ethash_io_serialize_info(REVISION, seedhash, info_buffer); + ethash_io_serialize_info(ETHASH_REVISION, seedhash, info_buffer); if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) { goto fail_free; } diff --git a/libethash/io_posix.c b/libethash/io_posix.c index 693bdf750..9d9ccac69 100644 --- a/libethash/io_posix.c +++ b/libethash/io_posix.c @@ -56,7 +56,7 @@ enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seed goto close; } - ethash_io_serialize_info(REVISION, seedhash, expect_buffer); + ethash_io_serialize_info(ETHASH_REVISION, seedhash, expect_buffer); if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { // we have different memo contents so delete the memo file if (unlink(memofile) != 0) { diff --git a/libethash/io_win32.c b/libethash/io_win32.c index 2cabc939a..77367fdd9 100644 --- a/libethash/io_win32.c +++ b/libethash/io_win32.c @@ -53,7 +53,7 @@ enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seed goto close; } - ethash_io_serialize_info(REVISION, seedhash, expect_buffer); + ethash_io_serialize_info(ETHASH_REVISION, seedhash, expect_buffer); if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { // we have different memo contents so delete the memo file if (_unlink(memofile) != 0) { diff --git a/libethcore/Ethasher.cpp b/libethcore/Ethasher.cpp index 880bc139a..64db69187 100644 --- a/libethcore/Ethasher.cpp +++ b/libethcore/Ethasher.cpp @@ -41,7 +41,23 @@ using namespace eth; Ethasher* dev::eth::Ethasher::s_this = nullptr; -bytes const& Ethasher::cache(BlockInfo const& _header) +Ethasher::~Ethasher() +{ + while (!m_caches.empty()) + killCache(m_caches.begin()->first); +} + +void Ethasher::killCache(h256 const& _s) +{ + RecursiveGuard l(x_this); + if (m_caches.count(_s)) + { + ethash_delete_light(m_caches.at(_s)); + m_caches.erase(_s); + } +} + +void const* Ethasher::cache(BlockInfo const& _header) { RecursiveGuard l(x_this); if (_header.number > c_ethashEpochLength * 2048) @@ -54,8 +70,7 @@ bytes const& Ethasher::cache(BlockInfo const& _header) if (!m_caches.count(_header.seedHash())) { ethash_params p = params((unsigned)_header.number); - m_caches[_header.seedHash()].resize(p.cache_size); - ethash_prep_light(m_caches[_header.seedHash()].data(), &p, _header.seedHash().data()); + m_caches[_header.seedHash()] = ethash_new_light(&p, _header.seedHash().data()); } return m_caches[_header.seedHash()]; } @@ -84,7 +99,7 @@ bytesConstRef Ethasher::full(BlockInfo const& _header) ethash_params p = params((unsigned)_header.number); m_fulls[_header.seedHash()] = bytesRef(new byte[p.full_size], p.full_size); auto c = cache(_header); - ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c.data()); + ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c); writeFile(memoFile, m_fulls[_header.seedHash()]); writeFile(memoFile + ".info", info); } @@ -147,7 +162,7 @@ Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce) { auto p = Ethasher::params(_header); ethash_return_value r; - ethash_compute_light(&r, Ethasher::get()->cache(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); + ethash_compute_light(&r, Ethasher::get()->cache(_header), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); // cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/Ethasher.h b/libethcore/Ethasher.h index c160d38da..a10c206d1 100644 --- a/libethcore/Ethasher.h +++ b/libethcore/Ethasher.h @@ -30,21 +30,8 @@ #include #include #include // TODO: REMOVE once everything merged into this class and an opaque API can be provided. -static const unsigned c_ethashRevision = REVISION; -static const unsigned c_ethashEpochLength = EPOCH_LENGTH; -#undef REVISION -#undef DATASET_BYTES_INIT -#undef DATASET_BYTES_GROWTH -#undef CACHE_BYTES_INIT -#undef CACHE_BYTES_GROWTH -#undef DAGSIZE_BYTES_INIT -#undef DAG_GROWTH -#undef EPOCH_LENGTH -#undef MIX_BYTES -#undef HASH_BYTES -#undef DATASET_PARENTS -#undef CACHE_ROUNDS -#undef ACCESSES +static const unsigned c_ethashRevision = ETHASH_REVISION; +static const unsigned c_ethashEpochLength = ETHASH_EPOCH_LENGTH; #include "Common.h" #include "BlockInfo.h" @@ -57,10 +44,14 @@ class Ethasher { public: Ethasher() {} + ~Ethasher(); static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; } - bytes const& cache(BlockInfo const& _header); + using LightType = void const*; + using FullType = void const*; + + LightType cache(BlockInfo const& _header); bytesConstRef full(BlockInfo const& _header); static ethash_params params(BlockInfo const& _header); static ethash_params params(unsigned _n); @@ -104,9 +95,11 @@ public: }; private: + void killCache(h256 const& _s); + static Ethasher* s_this; RecursiveMutex x_this; - std::map m_caches; + std::map m_caches; std::map m_fulls; }; diff --git a/test/dagger.cpp b/test/dagger.cpp index f7230f705..4dda9c4fc 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -63,8 +63,8 @@ BOOST_AUTO_TEST_CASE(basic_test) unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); - BOOST_REQUIRE_EQUAL(Ethasher::get()->cache(header).size(), cacheSize); - BOOST_REQUIRE_EQUAL(sha3(Ethasher::get()->cache(header)), cacheHash); + BOOST_REQUIRE_EQUAL(Ethasher::get()->params(header).cache_size, cacheSize); + BOOST_REQUIRE_EQUAL(sha3(bytesConstRef((byte const*)Ethasher::get()->cache(header), cacheSize)), cacheHash); #if TEST_FULL unsigned fullSize(o["full_size"].get_int()); From ed62ee21f3592464fe5bab06425945bf7357309e Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Wed, 1 Apr 2015 04:20:17 +0430 Subject: [PATCH 33/50] -Bug fix: get first item of list in setSelectedIndex function. -Putting qsTr for all user-visible strings. --- mix/qml/StatesComboBox.qml | 201 +++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 97 deletions(-) diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index 26f41aa8d..246b3e93b 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -28,22 +28,20 @@ import QtGraphicalEffects 1.0 Rectangle { id: statesComboBox - width: 200; - height: 20; - - Component.onCompleted: - { - var top = dropDownList; - while (top.parent) - { + width: 200 + height: 20 + + Component.onCompleted: { + var top = dropDownList + while (top.parent) { top = top.parent if (top.objectName == "debugPanel") - break; + break } var coordinates = dropDownList.mapToItem(top, 0, 0) //the order is important - dropDownShowdowList.parent = top; - dropDownList.parent = top; + dropDownShowdowList.parent = top + dropDownList.parent = top dropDownShowdowList.x = coordinates.x dropDownShowdowList.y = coordinates.y @@ -52,187 +50,196 @@ Rectangle { dropDownList.y = coordinates.y } - signal selectItem(real item); - signal editItem(real item); - signal selectCreate(); - property variant rowHeight:25; - property variant items; - readonly property alias selectedItem: chosenItemText.text; - readonly property alias selectedIndex: listView.currentRow; - function setSelectedIndex(index) - { - listView.currentRow = index; - chosenItemText.text = statesComboBox.items.get(0).title; + signal selectItem(real item) + signal editItem(real item) + signal selectCreate + property variant rowHeight: 25 + property variant items + property alias selectedItem: chosenItemText.text + property alias selectedIndex: listView.currentRow + function setSelectedIndex(index) { + listView.currentRow = index + chosenItemText.text = statesComboBox.items.get(index).title } - signal comboClicked; + signal comboClicked - property variant colorItem; - property variant colorSelect; + property variant colorItem + property variant colorSelect - smooth:true; + smooth: true Rectangle { id: chosenItem - width: parent.width; - height: statesComboBox.height; - color: statesComboBox.color; - smooth: true; + width: parent.width + height: statesComboBox.height + color: statesComboBox.color + smooth: true Text { id: chosenItemText - anchors.top: parent.top; - anchors.left: parent.left; - anchors.margins: 2; - color: statesComboBox.colorItem; + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 2 + color: statesComboBox.colorItem text: "" smooth: true } MouseArea { - anchors.fill: parent; + anchors.fill: parent onClicked: { - statesComboBox.state = statesComboBox.state==="dropDown"?"":"dropDown" + statesComboBox.state = statesComboBox.state === "dropDown" ? "" : "dropDown" } } } Rectangle { id: dropDownShowdowList - width: statesComboBox.width; + width: statesComboBox.width opacity: 0.3 - height: 0; - clip: true; - radius: 4; - anchors.top: chosenItem.top; - anchors.margins: 2; + height: 0 + clip: true + radius: 4 + anchors.top: chosenItem.top + anchors.margins: 2 color: "gray" } //ToDo: We need scrollbar for items Rectangle { id: dropDownList - width: statesComboBox.width; - height: 0; - clip: true; - radius: 4; - anchors.top: chosenItem.top; - anchors.margins: 2; + width: statesComboBox.width + height: 0 + clip: true + radius: 4 + anchors.top: chosenItem.top + anchors.margins: 2 color: statesComboBox.color ColumnLayout { spacing: 2 TableView { id: listView - height: 20; + height: 20 implicitHeight: 0 - width: statesComboBox.width; + width: statesComboBox.width model: statesComboBox.items - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff; + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff currentRow: -1 - headerVisible: false; + headerVisible: false backgroundVisible: false - alternatingRowColors : false; + alternatingRowColors: false frameVisible: false TableViewColumn { role: "title" title: "" - width: statesComboBox.width; + width: statesComboBox.width delegate: mainItemDelegate } - rowDelegate: Rectangle { - width: statesComboBox.width; - height: statesComboBox.rowHeight; + rowDelegate: Rectangle { + width: statesComboBox.width + height: statesComboBox.rowHeight } Component { id: mainItemDelegate Rectangle { id: itemDelegate - width: statesComboBox.width; - height: statesComboBox.height; + width: statesComboBox.width + height: statesComboBox.height Text { id: textItemid text: styleData.value - color: statesComboBox.colorItem; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.margins: 5; + color: statesComboBox.colorItem + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 5 } Image { id: imageItemid height: 20 - width: 20; + width: 20 anchors.right: parent.right - anchors.top: parent.top; - anchors.margins: 5; - visible: false; + anchors.top: parent.top + anchors.margins: 5 + visible: false fillMode: Image.PreserveAspectFit source: "img/edit_combox.png" } MouseArea { - anchors.fill: parent; - hoverEnabled : true + anchors.fill: parent + hoverEnabled: true onEntered: { - imageItemid.visible = true; - textItemid.color = statesComboBox.colorSelect; + imageItemid.visible = true + textItemid.color = statesComboBox.colorSelect } onExited: { - imageItemid.visible = false; - textItemid.color = statesComboBox.colorItem; + imageItemid.visible = false + textItemid.color = statesComboBox.colorItem } onClicked: { - if (mouseX > imageItemid.x && mouseX < imageItemid.x+ imageItemid.width - && mouseY > imageItemid.y && mouseY < imageItemid.y+ imageItemid.height) - statesComboBox.editItem(styleData.row); + if (mouseX > imageItemid.x + && mouseX < imageItemid.x + imageItemid.width + && mouseY > imageItemid.y + && mouseY < imageItemid.y + imageItemid.height) + statesComboBox.editItem(styleData.row) else { statesComboBox.state = "" var prevSelection = chosenItemText.text chosenItemText.text = styleData.value - listView.currentRow = styleData.row; - statesComboBox.selectItem(styleData.row); + listView.currentRow = styleData.row + statesComboBox.selectItem(styleData.row) } } } - }//Item - }//Component - }//Table View + } //Item + } //Component + } //Table View RowLayout { Rectangle { width: 1 } - Text{ + Text { id: createStateText - width: statesComboBox.width; - height: statesComboBox.height; + width: statesComboBox.width + height: statesComboBox.height font.bold: true - text: "Create State ..." - MouseArea - { - anchors.fill: parent; + text: qsTr("Create State ...") + MouseArea { + anchors.fill: parent hoverEnabled: true onEntered: { - createStateText.color = statesComboBox.colorSelect; + createStateText.color = statesComboBox.colorSelect } onExited: { - createStateText.color = statesComboBox.colorItem; + createStateText.color = statesComboBox.colorItem } onClicked: { statesComboBox.state = "" - statesComboBox.selectCreate(); + statesComboBox.selectCreate() } } } } - } } states: State { - name: "dropDown"; - PropertyChanges { target: dropDownList; height: (statesComboBox.rowHeight*(statesComboBox.items.count+1)) } - PropertyChanges { target: dropDownShowdowList; width: statesComboBox.width+3; height: (statesComboBox.rowHeight*(statesComboBox.items.count+1))+3 } - PropertyChanges { target: listView; height: 20; implicitHeight: (statesComboBox.rowHeight*(statesComboBox.items.count)) } + name: "dropDown" + PropertyChanges { + target: dropDownList + height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) + } + PropertyChanges { + target: dropDownShowdowList + width: statesComboBox.width + 3 + height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) + 3 + } + PropertyChanges { + target: listView + height: 20 + implicitHeight: (statesComboBox.rowHeight * (statesComboBox.items.count)) + } } - } From d0825c2cd8b97397dfb293b97b61948ec2b2e887 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 1 Apr 2015 11:03:20 +0200 Subject: [PATCH 34/50] re-enabled debugging into base contracts --- mix/CodeModel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 3d0f0c749..53ec34e2b 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -98,11 +98,10 @@ dev::eth::AssemblyItems filterLocations(dev::eth::AssemblyItems const& _location { dev::eth::AssemblyItems result; result.reserve(_locations.size()); - std::string sourceName = *_contract.getLocation().sourceName; for (dev::eth::AssemblyItem item : _locations) { dev::SourceLocation const& l = item.getLocation(); - if (sourceName != *l.sourceName || _contract.getLocation() == l || _functions.contains(LocationPair(l.start, l.end))) + if (_contract.getLocation() == l || _functions.contains(LocationPair(l.start, l.end))) item.setLocation(dev::SourceLocation(-1, -1, l.sourceName)); result.push_back(item); } From d6cf8492312341bbbd8df0cc80cb1aa74e26b5f5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 1 Apr 2015 11:48:34 +0200 Subject: [PATCH 35/50] Moved semantic information to its own file. --- libevmcore/CommonSubexpressionEliminator.cpp | 75 +------------ libevmcore/CommonSubexpressionEliminator.h | 17 +-- libevmcore/SemanticInformation.cpp | 107 +++++++++++++++++++ libevmcore/SemanticInformation.h | 50 +++++++++ 4 files changed, 160 insertions(+), 89 deletions(-) create mode 100644 libevmcore/SemanticInformation.cpp create mode 100644 libevmcore/SemanticInformation.h diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index 47bb5b512..5c6ba95af 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include using namespace std; using namespace dev; @@ -248,79 +248,6 @@ ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(ExpressionCl return m_memoryContent[_slot] = m_expressionClasses.find(Instruction::MLOAD, {_slot}, true, m_sequenceNumber); } -bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) -{ - switch (_item.type()) - { - default: - case UndefinedItem: - case Tag: - return true; - case Push: - case PushString: - case PushTag: - case PushSub: - case PushSubSize: - case PushProgramSize: - case PushData: - return false; - case Operation: - { - if (isSwapInstruction(_item) || isDupInstruction(_item)) - return false; - if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC) - return true; // GAS and PC assume a specific order of opcodes - if (_item.instruction() == Instruction::MSIZE) - return true; // msize is modified already by memory access, avoid that for now - if (_item.instruction() == Instruction::SHA3) - return true; //@todo: we have to compare sha3's not based on their memory addresses but on the memory content. - InstructionInfo info = instructionInfo(_item.instruction()); - if (_item.instruction() == Instruction::SSTORE) - return false; - if (_item.instruction() == Instruction::MSTORE) - return false; - //@todo: We do not handle the following memory instructions for now: - // calldatacopy, codecopy, extcodecopy, mstore8, - // msize (note that msize also depends on memory read access) - - // the second requirement will be lifted once it is implemented - return info.sideEffects || info.args > 2; - } - } -} - -bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item) -{ - if (_item.type() != Operation) - return false; - switch (_item.instruction()) - { - case Instruction::ADD: - case Instruction::MUL: - case Instruction::EQ: - case Instruction::AND: - case Instruction::OR: - case Instruction::XOR: - return true; - default: - return false; - } -} - -bool SemanticInformation::isDupInstruction(AssemblyItem const& _item) -{ - if (_item.type() != Operation) - return false; - return Instruction::DUP1 <= _item.instruction() && _item.instruction() <= Instruction::DUP16; -} - -bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) -{ - if (_item.type() != Operation) - return false; - return Instruction::SWAP1 <= _item.instruction() && _item.instruction() <= Instruction::SWAP16; -} - CSECodeGenerator::CSECodeGenerator( ExpressionClasses& _expressionClasses, vector const& _storeOperations diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index a9a0c60a4..0dbb47b29 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace dev { @@ -139,20 +140,6 @@ private: AssemblyItem const* m_breakingItem = nullptr; }; -/** - * Helper functions to provide context-independent information about assembly items. - */ -struct SemanticInformation -{ - /// @returns true if the given items starts a new basic block - static bool breaksBasicBlock(AssemblyItem const& _item); - /// @returns true if the item is a two-argument operation whose value does not depend on the - /// order of its arguments. - static bool isCommutativeOperation(AssemblyItem const& _item); - static bool isDupInstruction(AssemblyItem const& _item); - static bool isSwapInstruction(AssemblyItem const& _item); -}; - /** * Unit that generates code from current stack layout, target stack layout and information about * the equivalence classes. @@ -230,7 +217,7 @@ _AssemblyItemIterator CommonSubexpressionEliminator::feedItems( _AssemblyItemIterator _end ) { - for (; _iterator != _end && !SemanticInformation::breaksBasicBlock(*_iterator); ++_iterator) + for (; _iterator != _end && !SemanticInformation::breaksCSEAnalysisBlock(*_iterator); ++_iterator) feedItem(*_iterator); if (_iterator != _end) m_breakingItem = &(*_iterator++); diff --git a/libevmcore/SemanticInformation.cpp b/libevmcore/SemanticInformation.cpp new file mode 100644 index 000000000..e561e7554 --- /dev/null +++ b/libevmcore/SemanticInformation.cpp @@ -0,0 +1,107 @@ +/* + 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 SemanticInformation.cpp + * @author Christian + * @date 2015 + * Helper to provide semantic information about assembly items. + */ + +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item) +{ + switch (_item.type()) + { + default: + case UndefinedItem: + case Tag: + return true; + case Push: + case PushString: + case PushTag: + case PushSub: + case PushSubSize: + case PushProgramSize: + case PushData: + return false; + case Operation: + { + if (isSwapInstruction(_item) || isDupInstruction(_item)) + return false; + if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC) + return true; // GAS and PC assume a specific order of opcodes + if (_item.instruction() == Instruction::MSIZE) + return true; // msize is modified already by memory access, avoid that for now + if (_item.instruction() == Instruction::SHA3) + return true; //@todo: we have to compare sha3's not based on their memory addresses but on the memory content. + InstructionInfo info = instructionInfo(_item.instruction()); + if (_item.instruction() == Instruction::SSTORE) + return false; + if (_item.instruction() == Instruction::MSTORE) + return false; + //@todo: We do not handle the following memory instructions for now: + // calldatacopy, codecopy, extcodecopy, mstore8, + // msize (note that msize also depends on memory read access) + + // the second requirement will be lifted once it is implemented + return info.sideEffects || info.args > 2; + } + } +} + +bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item) +{ + if (_item.type() != Operation) + return false; + switch (_item.instruction()) + { + case Instruction::ADD: + case Instruction::MUL: + case Instruction::EQ: + case Instruction::AND: + case Instruction::OR: + case Instruction::XOR: + return true; + default: + return false; + } +} + +bool SemanticInformation::isDupInstruction(AssemblyItem const& _item) +{ + if (_item.type() != Operation) + return false; + return Instruction::DUP1 <= _item.instruction() && _item.instruction() <= Instruction::DUP16; +} + +bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) +{ + if (_item.type() != Operation) + return false; + return Instruction::SWAP1 <= _item.instruction() && _item.instruction() <= Instruction::SWAP16; +} + +bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item) +{ + return _item == AssemblyItem(Instruction::JUMP) || _item == AssemblyItem(Instruction::JUMPI); +} diff --git a/libevmcore/SemanticInformation.h b/libevmcore/SemanticInformation.h new file mode 100644 index 000000000..7497dc651 --- /dev/null +++ b/libevmcore/SemanticInformation.h @@ -0,0 +1,50 @@ +/* + 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 SemanticInformation.h + * @author Christian + * @date 2015 + * Helper to provide semantic information about assembly items. + */ + +#pragma once + + +namespace dev +{ +namespace eth +{ + +class AssemblyItem; + +/** + * Helper functions to provide context-independent information about assembly items. + */ +struct SemanticInformation +{ + /// @returns true if the given items starts a new block for common subexpression analysis. + static bool breaksCSEAnalysisBlock(AssemblyItem const& _item); + /// @returns true if the item is a two-argument operation whose value does not depend on the + /// order of its arguments. + static bool isCommutativeOperation(AssemblyItem const& _item); + static bool isDupInstruction(AssemblyItem const& _item); + static bool isSwapInstruction(AssemblyItem const& _item); + static bool isJumpInstruction(AssemblyItem const& _item); +}; + +} +} From 600b12ab783cf36ec34e04df9b915088c7b6b4a9 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 1 Apr 2015 11:53:57 +0200 Subject: [PATCH 36/50] LogsPanel --- mix/qml/LogsPane.qml | 43 +++++++++++++++++++++++++++++++-------- mix/qml/LogsPaneStyle.qml | 2 +- mix/qml/StatusPane.qml | 10 +++------ 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 21bd9fd96..f600f9f9d 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -13,6 +13,11 @@ Rectangle logsModel.insert(0, { "type": _type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": _content, "level": _level }); } + Keys.onEscapePressed: + { + parent.toggle(); + } + anchors.fill: parent radius: 5 color: "transparent" @@ -33,7 +38,7 @@ Rectangle height: parent.height width: parent.width horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - ColumnLayout + Column { id: logsRect spacing: 0 @@ -93,6 +98,26 @@ Rectangle return index % 2 === 0 ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor; } + MouseArea + { + anchors.fill: parent + onClicked: + { + if (logContent.elide === Text.ElideNone) + { + logContent.elide = Text.ElideRight; + logContent.wrapMode = Text.NoWrap + parent.height = 30; + } + else + { + logContent.elide = Text.ElideNone; + logContent.wrapMode = Text.WordWrap; + parent.height = logContent.lineCount * 30; + } + } + } + DefaultLabel { text: date; @@ -120,12 +145,16 @@ Rectangle } } - DefaultLabel { + Text { + id: logContent text: content; font.family: LogsPaneStyle.generic.layout.logLabelFont width: LogsPaneStyle.generic.layout.contentWidth font.pointSize: Style.absoluteSize(-1) anchors.verticalCenter: parent.verticalCenter + elide: Text.ElideRight + + maximumLineCount: 10 anchors.left: parent.left anchors.leftMargin: 190 color: { @@ -145,11 +174,8 @@ Rectangle } } } - - } - Component { id: itemDelegate DefaultLabel { @@ -166,7 +192,6 @@ Rectangle } } } - } Rectangle @@ -377,7 +402,7 @@ Rectangle anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: 20 - height: 20 + height: 25 } Action { @@ -420,7 +445,7 @@ Rectangle anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: 20 - height: 20 + height: 25 } Action { @@ -503,7 +528,7 @@ Rectangle anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: 20 - height: 20 + height: 25 } Action { diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index 215f17bd7..8e0dfd5f4 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -20,7 +20,7 @@ QtObject { property int headerInputWidth: 200 property int dateWidth: 70 property int typeWidth: 90 - property int contentWidth: 250 + property int contentWidth: 560 property string logAlternateColor: "#f6f5f6" } } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index b42b13fef..3d366021f 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -112,7 +112,7 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter radius: 3 - width: 650 + width: 600 height: 30 color: "#fcfbfc" Text { @@ -201,8 +201,8 @@ Rectangle { { logsContainer.state = "opened"; logsContainer.focus = true; - calCoord(); forceActiveFocus(); + calCoord(); } } @@ -213,10 +213,6 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter visible: false radius: 5 - Component.onCompleted: - { - calCoord(); - } function calCoord() { @@ -225,7 +221,7 @@ Rectangle { top = top.parent var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; - logsContainer.x = coordinates.x + 150; + logsContainer.x = coordinates.x; logsContainer.y = coordinates.y; } From 0e247e0282edaaf1f2cff9b424407be60c481a67 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 27 Mar 2015 17:07:32 +0100 Subject: [PATCH 37/50] style fixes --- libsolidity/AST.cpp | 2 +- libsolidity/Types.cpp | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index e3c9bc964..7fe3a9825 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -337,7 +337,7 @@ void FunctionDefinition::checkTypeRequirements() { if (!var->getType()->canLiveOutsideStorage()) BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); - if (!(var->getType()->externalType()) && getVisibility() >= Visibility::Public) + if (getVisibility() >= Visibility::Public && !(var->getType()->externalType())) BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for function with external visibility")); } for (ASTPointer const& modifier: m_functionModifiers) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 5fd7d24a6..e784c6b8c 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -1103,11 +1103,16 @@ TypePointer FunctionType::externalType() const TypePointers paramTypes; TypePointers retParamTypes; - for (auto it = m_parameterTypes.cbegin(); it != m_parameterTypes.cend(); ++it) - paramTypes.push_back((*it)->externalType()); - for (auto it = m_returnParameterTypes.cbegin(); it != m_returnParameterTypes.cend(); ++it) - retParamTypes.push_back((*it)->externalType()); - + for(auto type: m_parameterTypes) + { + solAssert(!!type->externalType(), "To be included in external type of the function, the argument should have external type."); + paramTypes.push_back(type->externalType()); + } + for(auto param: m_returnParameterTypes) + { + solAssert(!!param->externalType(), "To be included in external type of the function, the argument should have external type."); + retParamTypes.push_back(param->externalType()); + } return make_shared(paramTypes, retParamTypes, m_location, m_arbitraryParameters); } From 4173a71846c7e35002c56a7c990aace40e9579cd Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 30 Mar 2015 14:34:38 +0200 Subject: [PATCH 38/50] changed checking for external type in VariableDeclaration::checkTypeRequirements() changed error msg --- libsolidity/AST.cpp | 17 ++++++++++++++++- test/SolidityNameAndTypeResolution.cpp | 14 ++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 7fe3a9825..a111a6f88 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -338,7 +338,14 @@ void FunctionDefinition::checkTypeRequirements() if (!var->getType()->canLiveOutsideStorage()) BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); if (getVisibility() >= Visibility::Public && !(var->getType()->externalType())) - BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for function with external visibility")); + { + // todo delete when arrays as parameter type in internal functions will be implemented + ArrayType const* type = dynamic_cast(var->getType().get()); + if (getVisibility() == Visibility::Public && type) + BOOST_THROW_EXCEPTION(var->createTypeError("Array type is not allowed as parameter for internal functions.")); + else + BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for function with external visibility.")); + } } for (ASTPointer const& modifier: m_functionModifiers) modifier->checkTypeRequirements(isConstructor() ? @@ -379,6 +386,14 @@ void VariableDeclaration::checkTypeRequirements() m_value->expectType(*m_type); if (m_isStateVariable && !m_type->externalType() && getVisibility() >= Visibility::Public) BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for state variables.")); + + auto sharedToExternalTypes = FunctionType(*this).externalType(); // do not distroy the shared pointer. + auto externalFunctionTypes = dynamic_cast(sharedToExternalTypes.get()); + TypePointers retParamTypes = externalFunctionTypes->getReturnParameterTypes(); + TypePointers parameterTypes = externalFunctionTypes->getParameterTypes(); + for (auto parameter: parameterTypes + retParamTypes) + if (!parameter && !(parameter->externalType())) + BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for state variables.")); } else { // no type declared and no previous assignment, infer the type diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index ddcf36140..531f3bc13 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -460,7 +460,7 @@ BOOST_AUTO_TEST_CASE(function_external_types) uint a; } contract Test { - function boo(uint arg2, bool arg3, bytes8 arg4, bool[2] pairs, uint[] dynamic, C carg) external returns (uint ret) { + function boo(uint arg2, bool arg3, bytes8 arg4, bool[2] pairs, uint[] dynamic, C carg, address[] addresses) external returns (uint ret) { ret = 5; } })"; @@ -471,7 +471,7 @@ BOOST_AUTO_TEST_CASE(function_external_types) auto functions = contract->getDefinedFunctions(); if (functions.empty()) continue; - BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8,bool[2],uint256[],address)", functions[0]->externalSignature()); + BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8,bool[2],uint256[],address,address[])", functions[0]->externalSignature()); } } @@ -503,6 +503,16 @@ BOOST_AUTO_TEST_CASE(function_external_call_not_allowed_conversion) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +// todo delete when implemented +BOOST_AUTO_TEST_CASE(arrays_in_internal_functions) +{ + char const* text = R"( + contract Test { + function foo(address[] addresses) {} + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_CASE(function_internal_allowed_conversion) { char const* text = R"( From 4352423fea12a3896af3580f2b3097674cdd1ae9 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 1 Apr 2015 15:19:33 +0200 Subject: [PATCH 39/50] miner changes in the implementation of the externalTypes function of FunctionType. better error messages for exeptions style fixes after review --- libsolidity/AST.cpp | 18 ++++++++---------- libsolidity/Types.cpp | 12 +++++++----- libsolidity/Types.h | 2 ++ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index a111a6f88..d489a4489 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -339,12 +339,11 @@ void FunctionDefinition::checkTypeRequirements() BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); if (getVisibility() >= Visibility::Public && !(var->getType()->externalType())) { - // todo delete when arrays as parameter type in internal functions will be implemented - ArrayType const* type = dynamic_cast(var->getType().get()); - if (getVisibility() == Visibility::Public && type) + // todo delete when will be implemented arrays as parameter type in internal functions + if (getVisibility() == Visibility::Public && var->getType()->getCategory() == Type::Category::Array) BOOST_THROW_EXCEPTION(var->createTypeError("Array type is not allowed as parameter for internal functions.")); else - BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for function with external visibility.")); + BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for public and external functions.")); } } for (ASTPointer const& modifier: m_functionModifiers) @@ -389,12 +388,11 @@ void VariableDeclaration::checkTypeRequirements() auto sharedToExternalTypes = FunctionType(*this).externalType(); // do not distroy the shared pointer. auto externalFunctionTypes = dynamic_cast(sharedToExternalTypes.get()); - TypePointers retParamTypes = externalFunctionTypes->getReturnParameterTypes(); - TypePointers parameterTypes = externalFunctionTypes->getParameterTypes(); - for (auto parameter: parameterTypes + retParamTypes) - if (!parameter && !(parameter->externalType())) - BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for state variables.")); - } else + for (auto parameter: externalFunctionTypes->getParameterTypes() + externalFunctionTypes->getReturnParameterTypes()) + if (!parameter || !(parameter->externalType())) + BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables.")); + } + else { // no type declared and no previous assignment, infer the type m_value->checkTypeRequirements(); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index e784c6b8c..86b740262 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -1103,15 +1103,17 @@ TypePointer FunctionType::externalType() const TypePointers paramTypes; TypePointers retParamTypes; - for(auto type: m_parameterTypes) + for (auto type: m_parameterTypes) { - solAssert(!!type->externalType(), "To be included in external type of the function, the argument should have external type."); + if(!type->externalType()) + return TypePointer(); paramTypes.push_back(type->externalType()); } - for(auto param: m_returnParameterTypes) + for (auto type: m_returnParameterTypes) { - solAssert(!!param->externalType(), "To be included in external type of the function, the argument should have external type."); - retParamTypes.push_back(param->externalType()); + if(!type->externalType()) + return TypePointer(); + retParamTypes.push_back(type->externalType()); } return make_shared(paramTypes, retParamTypes, m_location, m_arbitraryParameters); } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 99fd878f0..cea711991 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -512,6 +512,8 @@ public: virtual Category getCategory() const override { return Category::Function; } + /// @returns TypePointer of a new FunctionType object. All input/return parameters are an appropriate external types of input/return parameters of current function. + /// Returns an empty shared pointer if one of input/return parameters does not have an externaltype. virtual TypePointer externalType() const override; explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); From b4e869acfaac4a4313c19bb634b842ce6cd65ff6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 1 Apr 2015 15:25:32 +0200 Subject: [PATCH 40/50] ui changes --- mix/qml/LogsPane.qml | 55 +++++++++++++++++++++++++++------------ mix/qml/LogsPaneStyle.qml | 2 +- mix/qml/StatusPane.qml | 27 ++++++++++++------- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index f600f9f9d..23ab8e682 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -7,19 +7,29 @@ import "." Rectangle { + property variant currentStatus; function push(_level, _type, _content) { _content = _content.replace(/\n/g, " ") logsModel.insert(0, { "type": _type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": _content, "level": _level }); } - Keys.onEscapePressed: + onVisibleChanged: { - parent.toggle(); + if (visible && (logsModel.count === 0 || (logsModel.get(0).date !== currentStatus.date && logsModel.get(0).content !== currentStatus.content))) + logsModel.insert(0, { "type": currentStatus.type, "date": currentStatus.date, "content": currentStatus.content, "level": currentStatus.level }); + else if (!visible) + { + for (var k = 0; k < logsModel.count; k++) + { + if (logsModel.get(k).type === "Comp") //do not keep compilation logs. + logsModel.remove(k); + } + } } anchors.fill: parent - radius: 5 + radius: 10 color: "transparent" id: logsPane Column { @@ -43,11 +53,13 @@ Rectangle id: logsRect spacing: 0 Repeater { + id: logsRepeater clip: true + property string frontColor: "transparent" model: SortFilterProxyModel { id: proxyModel source: logsModel - property var roles: ["-", "javascript", "run", "state"] + property var roles: ["-", "javascript", "run", "state", "comp"] Component.onCompleted: { filterType = regEx(proxyModel.roles); @@ -80,7 +92,7 @@ Rectangle return "(?:" + roles.join('|') + ")"; } - filterType: "(?:javascript|run|state)" + filterType: "(?:javascript|run|state|comp)" filterContent: "" filterSyntax: SortFilterProxyModel.RegExp filterCaseSensitivity: Qt.CaseInsensitive @@ -92,12 +104,17 @@ Rectangle height: 30 color: { + var cl; if (level === "warning" || level === "error") - return "#fffcd5"; + cl = "#fffcd5"; else - return index % 2 === 0 ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor; + cl = index % 2 === 0 ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor; + if (index === 0) + logsRepeater.frontColor = cl; + return cl; } + MouseArea { anchors.fill: parent @@ -148,13 +165,11 @@ Rectangle Text { id: logContent text: content; - font.family: LogsPaneStyle.generic.layout.logLabelFont + font.family: "sans serif" width: LogsPaneStyle.generic.layout.contentWidth font.pointSize: Style.absoluteSize(-1) anchors.verticalCenter: parent.verticalCenter elide: Text.ElideRight - - maximumLineCount: 10 anchors.left: parent.left anchors.leftMargin: 190 color: { @@ -230,7 +245,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "transparent" + color : "#d3d0d0" + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 2; + height: parent.height + color : "#f2f1f2" } ToolButton { @@ -272,7 +294,7 @@ Rectangle Rectangle { anchors.verticalCenter: parent.verticalCenter - width: 1; + width: 2; height: parent.height color : "#f2f1f2" } @@ -311,14 +333,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#d3d0d0" + color: "#d3d0d0" } Rectangle { anchors.verticalCenter: parent.verticalCenter - width: 1; + width: 2; height: parent.height - color : "#f2f1f2" + color: "#f2f1f2" } ToolButton { @@ -360,7 +382,7 @@ Rectangle Rectangle { anchors.verticalCenter: parent.verticalCenter - width: 1; + width: 2; height: parent.height color : "#f2f1f2" } @@ -541,4 +563,5 @@ Rectangle } } } + } diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index 8e0dfd5f4..e4985b70e 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -15,7 +15,7 @@ QtObject { property int headerButtonSpacing: 0 property int leftMargin: 10 property int headerButtonHeight: 30 - property string logLabelColor: "#808080" + property string logLabelColor: "#4a4a4a" property string logLabelFont: "sans serif" property int headerInputWidth: 200 property int dateWidth: 70 diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 3d366021f..4a9287bec 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -9,7 +9,7 @@ Rectangle { id: statusHeader objectName: "statusPane" property variant webPreview - + property alias currentStatus: logPane.currentStatus function updateStatus(message) { if (!message) @@ -17,6 +17,7 @@ Rectangle { status.state = ""; status.text = qsTr("Compile successfully."); debugImg.state = "active"; + currentStatus = { "type": "Comp", "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": status.text, "level": "info" } } else { @@ -24,6 +25,7 @@ Rectangle { var errorInfo = ErrorLocationFormater.extractErrorInfo(message, true); status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail; debugImg.state = ""; + currentStatus = { "type": "Comp", "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": status.text, "level": "error" } } debugRunActionIcon.enabled = codeModel.hasContract; } @@ -33,6 +35,7 @@ Rectangle { status.state = ""; status.text = text logPane.push("info", type, text); + currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "info" } } function warningMessage(text, type) @@ -40,6 +43,7 @@ Rectangle { status.state = "warning"; status.text = text logPane.push("warning", type, text); + currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "warning" } } function errorMessage(text, type) @@ -47,6 +51,7 @@ Rectangle { status.state = "error"; status.text = text; logPane.push("error", type, text); + currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "error" } } Connections { @@ -118,7 +123,7 @@ Rectangle { Text { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter - font.pointSize: StatusPaneStyle.general.statusFontSize + font.pointSize: Style.absoluteSize(-1) height: 15 font.family: "sans serif" objectName: "status" @@ -196,7 +201,9 @@ Rectangle { function toggle() { if (logsContainer.state === "opened") + { logsContainer.state = "closed" + } else { logsContainer.state = "opened"; @@ -208,11 +215,10 @@ Rectangle { id: logsContainer width: 750 - anchors.topMargin: -30 anchors.top: statusContainer.bottom - anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 4 visible: false - radius: 5 + radius: 10 function calCoord() { @@ -221,28 +227,31 @@ Rectangle { top = top.parent var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; - logsContainer.x = coordinates.x; - logsContainer.y = coordinates.y; + logsContainer.x = status.x + statusContainer.x - LogsPaneStyle.generic.layout.dateWidth - LogsPaneStyle.generic.layout.typeWidth - 30 } LogsPane { id: logPane; } + states: [ State { name: "opened"; PropertyChanges { target: logsContainer; height: 500; visible: true } + PropertyChanges { target: statusContainer; width: 100; height: 25 } }, State { name: "closed"; PropertyChanges { target: logsContainer; height: 0; visible: false } + PropertyChanges { target: statusContainer; width: 600; height: 30 } } ] transitions: Transition { NumberAnimation { properties: "height"; easing.type: Easing.InOutQuad; duration: 200 } - NumberAnimation { properties: "visible"; easing.type: Easing.InOutQuad; duration: 200 } - } + NumberAnimation { target: logsContainer; properties: "visible"; easing.type: Easing.InOutQuad; duration: 200 } + NumberAnimation { target: statusContainer; properties: "width"; easing.type: Easing.InOutQuad; duration: 500 } + } } } From f4ea6b8e8d2f8c72223372113ddcf84cecbc1c23 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 1 Apr 2015 15:26:37 +0200 Subject: [PATCH 41/50] Update Types.h --- libsolidity/Types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index cea711991..e1852bc7f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -513,7 +513,7 @@ public: virtual Category getCategory() const override { return Category::Function; } /// @returns TypePointer of a new FunctionType object. All input/return parameters are an appropriate external types of input/return parameters of current function. - /// Returns an empty shared pointer if one of input/return parameters does not have an externaltype. + /// Returns an empty shared pointer if one of the input/return parameters does not have an externaltype. virtual TypePointer externalType() const override; explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); From c5df9e205b8c9c76d74a7337db02e62956765873 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 1 Apr 2015 15:41:24 +0200 Subject: [PATCH 42/50] Update AST.cpp --- libsolidity/AST.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index d489a4489..fec123f75 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -341,7 +341,7 @@ void FunctionDefinition::checkTypeRequirements() { // todo delete when will be implemented arrays as parameter type in internal functions if (getVisibility() == Visibility::Public && var->getType()->getCategory() == Type::Category::Array) - BOOST_THROW_EXCEPTION(var->createTypeError("Array type is not allowed as parameter for internal functions.")); + BOOST_THROW_EXCEPTION(var->createTypeError("Arrays only implemented for external functions.")); else BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for public and external functions.")); } @@ -386,7 +386,7 @@ void VariableDeclaration::checkTypeRequirements() if (m_isStateVariable && !m_type->externalType() && getVisibility() >= Visibility::Public) BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for state variables.")); - auto sharedToExternalTypes = FunctionType(*this).externalType(); // do not distroy the shared pointer. + auto sharedToExternalTypes = FunctionType(*this).externalType(); // do not destroy the shared pointer. auto externalFunctionTypes = dynamic_cast(sharedToExternalTypes.get()); for (auto parameter: externalFunctionTypes->getParameterTypes() + externalFunctionTypes->getReturnParameterTypes()) if (!parameter || !(parameter->externalType())) From ab0b92242f58503e3a7f5732a0adf0b0b790fa8d Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 1 Apr 2015 15:42:30 +0200 Subject: [PATCH 43/50] Update Types.cpp --- libsolidity/Types.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 86b740262..78649cc95 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -1105,13 +1105,13 @@ TypePointer FunctionType::externalType() const for (auto type: m_parameterTypes) { - if(!type->externalType()) + if (!type->externalType()) return TypePointer(); paramTypes.push_back(type->externalType()); } for (auto type: m_returnParameterTypes) { - if(!type->externalType()) + if (!type->externalType()) return TypePointer(); retParamTypes.push_back(type->externalType()); } From 119101812103b7123b86d7f293d3c690a0456530 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 1 Apr 2015 15:43:01 +0200 Subject: [PATCH 44/50] style --- mix/qml/LogsPane.qml | 28 ++++++++++++++-------------- mix/qml/LogsPaneStyle.qml | 4 ++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 23ab8e682..86378ff17 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -106,7 +106,7 @@ Rectangle { var cl; if (level === "warning" || level === "error") - cl = "#fffcd5"; + cl = LogsPaneStyle.generic.layout.errorColor; else cl = index % 2 === 0 ? "transparent" : LogsPaneStyle.generic.layout.logAlternateColor; if (index === 0) @@ -165,7 +165,7 @@ Rectangle Text { id: logContent text: content; - font.family: "sans serif" + font.family: LogsPaneStyle.generic.layout.logLabelFont width: LogsPaneStyle.generic.layout.contentWidth font.pointSize: Style.absoluteSize(-1) anchors.verticalCenter: parent.verticalCenter @@ -234,7 +234,7 @@ Rectangle DefaultLabel { anchors.verticalCenter: parent.verticalCenter - color: "#808080" + color: LogsPaneStyle.generic.layout.logLabelColor font.pointSize: Style.absoluteSize(-3) font.family: LogsPaneStyle.generic.layout.logLabelFont text: qsTr("Show:") @@ -245,14 +245,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#d3d0d0" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 } Rectangle { anchors.verticalCenter: parent.verticalCenter width: 2; height: parent.height - color : "#f2f1f2" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 } ToolButton { @@ -280,7 +280,7 @@ Rectangle } background: Rectangle { - color: javascriptButton.checked ? "#dcdcdc" : "transparent" + color: javascriptButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" } } } @@ -289,14 +289,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#d3d0d0" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 } Rectangle { anchors.verticalCenter: parent.verticalCenter width: 2; height: parent.height - color : "#f2f1f2" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 } ToolButton { @@ -324,7 +324,7 @@ Rectangle } background: Rectangle { - color: runButton.checked ? "#dcdcdc" : "transparent" + color: runButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" } } } @@ -333,14 +333,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color: "#d3d0d0" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 } Rectangle { anchors.verticalCenter: parent.verticalCenter width: 2; height: parent.height - color: "#f2f1f2" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 } ToolButton { @@ -368,7 +368,7 @@ Rectangle } background: Rectangle { - color: stateButton.checked ? "#dcdcdc" : "transparent" + color: stateButton.checked ? LogsPaneStyle.generic.layout.buttonSelected : "transparent" } } } @@ -377,14 +377,14 @@ Rectangle anchors.verticalCenter: parent.verticalCenter width: 1; height: parent.height - color : "#d3d0d0" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor1 } Rectangle { anchors.verticalCenter: parent.verticalCenter width: 2; height: parent.height - color : "#f2f1f2" + color: LogsPaneStyle.generic.layout.buttonSeparatorColor2 } } diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index e4985b70e..19f6a653e 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -22,6 +22,10 @@ QtObject { property int typeWidth: 90 property int contentWidth: 560 property string logAlternateColor: "#f6f5f6" + property string errorColor: "#fffcd5" + property string buttonSeparatorColor1: "#d3d0d0" + property string buttonSeparatorColor2: "#f2f1f2" + property string buttonSelected: "#dcdcdc" } } } From 7d9d8fe200afc53061456f360e91a5d1d2406dbf Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 1 Apr 2015 15:50:01 +0200 Subject: [PATCH 45/50] small change --- mix/qml/LogsPane.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 86378ff17..c619080bf 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -489,9 +489,8 @@ Rectangle DefaultTextField { id: searchBox - height: LogsPaneStyle.generic.layout.headerButtonHeight - 5 anchors.verticalCenter: parent.verticalCenter - width: LogsPaneStyle.generic.layout.headerInputWidth - 40 + width: LogsPaneStyle.generic.layout.headerInputWidth - 50 font.family: LogsPaneStyle.generic.layout.logLabelFont font.pointSize: Style.absoluteSize(-3) font.italic: true From 065d9a9e68b3e4ca8413ff5eca15ccca18633080 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 1 Apr 2015 15:57:39 +0200 Subject: [PATCH 46/50] VariableDeclaration::checkTypeRequirements() refactoring --- libsolidity/AST.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index fec123f75..095ba7bf1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -386,11 +386,8 @@ void VariableDeclaration::checkTypeRequirements() if (m_isStateVariable && !m_type->externalType() && getVisibility() >= Visibility::Public) BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for state variables.")); - auto sharedToExternalTypes = FunctionType(*this).externalType(); // do not destroy the shared pointer. - auto externalFunctionTypes = dynamic_cast(sharedToExternalTypes.get()); - for (auto parameter: externalFunctionTypes->getParameterTypes() + externalFunctionTypes->getReturnParameterTypes()) - if (!parameter || !(parameter->externalType())) - BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables.")); + if (!FunctionType(*this).externalType()) + BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables.")); } else { From 37086e60e2b8f9ce059a4408cf5eb04af517ba69 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 1 Apr 2015 18:51:49 +0200 Subject: [PATCH 47/50] removed friendship for Assembly and AssemblyItem added set functions for type and data members of AssemblyItem --- libevmcore/Assembly.cpp | 40 +++++++++++++++++++-------------------- libevmcore/Assembly.h | 2 +- libevmcore/AssemblyItem.h | 5 +++-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 0301c9325..904903761 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -34,9 +34,9 @@ void Assembly::append(Assembly const& _a) for (AssemblyItem i: _a.m_items) { if (i.type() == Tag || i.type() == PushTag) - i.m_data += m_usedTags; + i.setData(i.data() + m_usedTags); else if (i.type() == PushSub || i.type() == PushSubSize) - i.m_data += m_subs.size(); + i.setData(i.data() + m_usedTags); append(i); } m_deposit = newDeposit; @@ -106,34 +106,34 @@ ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& for (AssemblyItem const& i: m_items) { _out << _prefix; - switch (i.m_type) + switch (i.type()) { case Operation: _out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); break; case Push: - _out << " PUSH " << i.m_data; + _out << " PUSH " << i.data(); break; case PushString: - _out << " PUSH \"" << m_strings.at((h256)i.m_data) << "\""; + _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; break; case PushTag: - _out << " PUSH [tag" << i.m_data << "]"; + _out << " PUSH [tag" << i.data() << "]"; break; case PushSub: - _out << " PUSH [$" << h256(i.m_data).abridged() << "]"; + _out << " PUSH [$" << h256(i.data()).abridged() << "]"; break; case PushSubSize: - _out << " PUSH #[$" << h256(i.m_data).abridged() << "]"; + _out << " PUSH #[$" << h256(i.data()).abridged() << "]"; break; case PushProgramSize: _out << " PUSHSIZE"; break; case Tag: - _out << "tag" << i.m_data << ": " << endl << _prefix << " JUMPDEST"; + _out << "tag" << i.data() << ": " << endl << _prefix << " JUMPDEST"; break; case PushData: - _out << " PUSH [" << hex << (unsigned)i.m_data << "]"; + _out << " PUSH [" << hex << (unsigned)i.data() << "]"; break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); @@ -189,7 +189,7 @@ Assembly& Assembly::optimise(bool _enable) return *this; std::vector>> rules; // jump to next instruction - rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }}); + rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data() == m[2].data()) return {m[2]}; else return m.toVector(); }}); unsigned total = 0; for (unsigned count = 1; count > 0; total += count) @@ -331,16 +331,16 @@ bytes Assembly::assemble() const // m_data must not change from here on for (AssemblyItem const& i: m_items) - switch (i.m_type) + switch (i.type()) { case Operation: - ret.push_back((byte)i.m_data); + ret.push_back((byte)i.data()); break; case PushString: { ret.push_back((byte)Instruction::PUSH32); unsigned ii = 0; - for (auto j: m_strings.at((h256)i.m_data)) + for (auto j: m_strings.at((h256)i.data())) if (++ii > 32) break; else @@ -351,30 +351,30 @@ bytes Assembly::assemble() const } case Push: { - byte b = max(1, dev::bytesRequired(i.m_data)); + byte b = max(1, dev::bytesRequired(i.data())); ret.push_back((byte)Instruction::PUSH1 - 1 + b); ret.resize(ret.size() + b); bytesRef byr(&ret.back() + 1 - b, b); - toBigEndian(i.m_data, byr); + toBigEndian(i.data(), byr); break; } case PushTag: { ret.push_back(tagPush); - tagRef[ret.size()] = (unsigned)i.m_data; + tagRef[ret.size()] = (unsigned)i.data(); ret.resize(ret.size() + bytesPerTag); break; } case PushData: case PushSub: { ret.push_back(dataRefPush); - dataRef.insert(make_pair((h256)i.m_data, ret.size())); + dataRef.insert(make_pair((h256)i.data(), ret.size())); ret.resize(ret.size() + bytesPerDataRef); break; } case PushSubSize: { - auto s = m_data[i.m_data].size(); + auto s = m_data[i.data()].size(); byte b = max(1, dev::bytesRequired(s)); ret.push_back((byte)Instruction::PUSH1 - 1 + b); ret.resize(ret.size() + b); @@ -390,7 +390,7 @@ bytes Assembly::assemble() const break; } case Tag: - tagPos[(unsigned)i.m_data] = ret.size(); + tagPos[(unsigned)i.data()] = ret.size(); ret.push_back((byte)Instruction::JUMPDEST); break; default: diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 315e6aaed..2744af900 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -65,7 +65,7 @@ public: template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItems const& getItems() const { return m_items; } AssemblyItem const& back() const { return m_items.back(); } - std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } + std::string backString() const { return m_items.size() && m_items.back().type() == PushString ? m_strings.at((h256)m_items.back().data()) : std::string(); } void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } diff --git a/libevmcore/AssemblyItem.h b/libevmcore/AssemblyItem.h index e7beced39..3e222a6eb 100644 --- a/libevmcore/AssemblyItem.h +++ b/libevmcore/AssemblyItem.h @@ -40,8 +40,6 @@ class Assembly; class AssemblyItem { - friend class Assembly; - public: enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; @@ -54,6 +52,9 @@ public: AssemblyItemType type() const { return m_type; } u256 const& data() const { return m_data; } + void setType(AssemblyItemType const _type) { m_type = _type; } + void setData(u256 const& _data) { m_data = _data; } + /// @returns the instruction of this item (only valid if type() == Operation) Instruction instruction() const { return Instruction(byte(m_data)); } From 11670e68d3e51151057cfcfb10ec4ed44b199615 Mon Sep 17 00:00:00 2001 From: Ali Mashatan Date: Thu, 2 Apr 2015 00:20:27 +0430 Subject: [PATCH 48/50] fix #1472 --- mix/qml/Debugger.qml | 50 ++-- mix/qml/StatesComboBox.qml | 454 ++++++++++++++++++------------------- mix/qml/TransactionLog.qml | 292 ++++++++++++------------ 3 files changed, 398 insertions(+), 398 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 202d27a0c..9ab2f03a4 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -220,31 +220,31 @@ Rectangle { id: jumpButtons spacing: 3 - StepActionImage - { - id: playAction - enabledStateImg: "qrc:/qml/img/play_button.png" - disableStateImg: "qrc:/qml/img/play_button.png" - onClicked: console.log("play"); - width: 30 - height: 30 - buttonShortcut: "Ctrl+Shift+F8" - buttonTooltip: qsTr("Play") - visible: true - } - - StepActionImage - { - id: pauseAction - enabledStateImg: "qrc:/qml/img/pause_button.png" - disableStateImg: "qrc:/qml/img/pause_button.png" - onClicked: console.log("pause"); - width: 30 - height: 30 - buttonShortcut: "Ctrl+Shift+F9" - buttonTooltip: qsTr("Pause") - visible: true - } + StepActionImage + { + id: playAction + enabledStateImg: "qrc:/qml/img/play_button.png" + disableStateImg: "qrc:/qml/img/play_button.png" + onClicked: console.log("play"); + width: 30 + height: 30 + buttonShortcut: "Ctrl+Shift+F8" + buttonTooltip: qsTr("Play") + visible: true + } + + StepActionImage + { + id: pauseAction + enabledStateImg: "qrc:/qml/img/pause_button.png" + disableStateImg: "qrc:/qml/img/pause_button.png" + onClicked: console.log("pause"); + width: 30 + height: 30 + buttonShortcut: "Ctrl+Shift+F9" + buttonTooltip: qsTr("Pause") + visible: true + } StepActionImage { diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index 246b3e93b..34567d083 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file StatesComboBox.qml * @author Ali Mashatan ali@ethdev.com @@ -26,220 +26,220 @@ import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 Rectangle { - id: statesComboBox - - width: 200 - height: 20 - - Component.onCompleted: { - var top = dropDownList - while (top.parent) { - top = top.parent - if (top.objectName == "debugPanel") - break - } - var coordinates = dropDownList.mapToItem(top, 0, 0) - //the order is important - dropDownShowdowList.parent = top - dropDownList.parent = top - - dropDownShowdowList.x = coordinates.x - dropDownShowdowList.y = coordinates.y - - dropDownList.x = coordinates.x - dropDownList.y = coordinates.y - } - - signal selectItem(real item) - signal editItem(real item) - signal selectCreate - property variant rowHeight: 25 - property variant items - property alias selectedItem: chosenItemText.text - property alias selectedIndex: listView.currentRow - function setSelectedIndex(index) { - listView.currentRow = index - chosenItemText.text = statesComboBox.items.get(index).title - } - - signal comboClicked - - property variant colorItem - property variant colorSelect - - smooth: true - Rectangle { - id: chosenItem - width: parent.width - height: statesComboBox.height - color: statesComboBox.color - smooth: true - Text { - id: chosenItemText - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: 2 - color: statesComboBox.colorItem - text: "" - smooth: true - } - - MouseArea { - anchors.fill: parent - onClicked: { - statesComboBox.state = statesComboBox.state === "dropDown" ? "" : "dropDown" - } - } - } - - Rectangle { - id: dropDownShowdowList - width: statesComboBox.width - opacity: 0.3 - height: 0 - clip: true - radius: 4 - anchors.top: chosenItem.top - anchors.margins: 2 - color: "gray" - } - //ToDo: We need scrollbar for items - Rectangle { - id: dropDownList - width: statesComboBox.width - height: 0 - clip: true - radius: 4 - anchors.top: chosenItem.top - anchors.margins: 2 - color: statesComboBox.color - - ColumnLayout { - spacing: 2 - TableView { - id: listView - height: 20 - implicitHeight: 0 - width: statesComboBox.width - model: statesComboBox.items - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - currentRow: -1 - headerVisible: false - backgroundVisible: false - alternatingRowColors: false - frameVisible: false - - TableViewColumn { - role: "title" - title: "" - width: statesComboBox.width - delegate: mainItemDelegate - } - rowDelegate: Rectangle { - width: statesComboBox.width - height: statesComboBox.rowHeight - } - Component { - id: mainItemDelegate - Rectangle { - id: itemDelegate - width: statesComboBox.width - height: statesComboBox.height - Text { - id: textItemid - text: styleData.value - color: statesComboBox.colorItem - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: 5 - } - Image { - id: imageItemid - height: 20 - width: 20 - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: 5 - visible: false - fillMode: Image.PreserveAspectFit - source: "img/edit_combox.png" - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - - onEntered: { - imageItemid.visible = true - textItemid.color = statesComboBox.colorSelect - } - onExited: { - imageItemid.visible = false - textItemid.color = statesComboBox.colorItem - } - onClicked: { - if (mouseX > imageItemid.x - && mouseX < imageItemid.x + imageItemid.width - && mouseY > imageItemid.y - && mouseY < imageItemid.y + imageItemid.height) - statesComboBox.editItem(styleData.row) - else { - statesComboBox.state = "" - var prevSelection = chosenItemText.text - chosenItemText.text = styleData.value - listView.currentRow = styleData.row - statesComboBox.selectItem(styleData.row) - } - } - } - } //Item - } //Component - } //Table View - - RowLayout { - Rectangle { - width: 1 - } - Text { - id: createStateText - width: statesComboBox.width - height: statesComboBox.height - font.bold: true - text: qsTr("Create State ...") - MouseArea { - anchors.fill: parent - hoverEnabled: true - - onEntered: { - createStateText.color = statesComboBox.colorSelect - } - onExited: { - createStateText.color = statesComboBox.colorItem - } - onClicked: { - statesComboBox.state = "" - statesComboBox.selectCreate() - } - } - } - } - } - } - states: State { - name: "dropDown" - PropertyChanges { - target: dropDownList - height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) - } - PropertyChanges { - target: dropDownShowdowList - width: statesComboBox.width + 3 - height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) + 3 - } - PropertyChanges { - target: listView - height: 20 - implicitHeight: (statesComboBox.rowHeight * (statesComboBox.items.count)) - } - } + id: statesComboBox + + width: 200 + height: 20 + + Component.onCompleted: { + var top = dropDownList + while (top.parent) { + top = top.parent + if (top.objectName == "debugPanel") + break + } + var coordinates = dropDownList.mapToItem(top, 0, 0) + //the order is important + dropDownShowdowList.parent = top + dropDownList.parent = top + + dropDownShowdowList.x = coordinates.x + dropDownShowdowList.y = coordinates.y + + dropDownList.x = coordinates.x + dropDownList.y = coordinates.y + } + + signal selectItem(real item) + signal editItem(real item) + signal selectCreate + property variant rowHeight: 25 + property variant items + property alias selectedItem: chosenItemText.text + property alias selectedIndex: listView.currentRow + function setSelectedIndex(index) { + listView.currentRow = index + chosenItemText.text = statesComboBox.items.get(index).title + } + + signal comboClicked + + property variant colorItem + property variant colorSelect + + smooth: true + Rectangle { + id: chosenItem + width: parent.width + height: statesComboBox.height + color: statesComboBox.color + smooth: true + Text { + id: chosenItemText + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 2 + color: statesComboBox.colorItem + text: "" + smooth: true + } + + MouseArea { + anchors.fill: parent + onClicked: { + statesComboBox.state = statesComboBox.state === "dropDown" ? "" : "dropDown" + } + } + } + + Rectangle { + id: dropDownShowdowList + width: statesComboBox.width + opacity: 0.3 + height: 0 + clip: true + radius: 4 + anchors.top: chosenItem.top + anchors.margins: 2 + color: "gray" + } + //ToDo: We need scrollbar for items + Rectangle { + id: dropDownList + width: statesComboBox.width + height: 0 + clip: true + radius: 4 + anchors.top: chosenItem.top + anchors.margins: 2 + color: statesComboBox.color + + ColumnLayout { + spacing: 2 + TableView { + id: listView + height: 20 + implicitHeight: 0 + width: statesComboBox.width + model: statesComboBox.items + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + currentRow: -1 + headerVisible: false + backgroundVisible: false + alternatingRowColors: false + frameVisible: false + + TableViewColumn { + role: "title" + title: "" + width: statesComboBox.width + delegate: mainItemDelegate + } + rowDelegate: Rectangle { + width: statesComboBox.width + height: statesComboBox.rowHeight + } + Component { + id: mainItemDelegate + Rectangle { + id: itemDelegate + width: statesComboBox.width + height: statesComboBox.height + Text { + id: textItemid + text: styleData.value + color: statesComboBox.colorItem + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 5 + } + Image { + id: imageItemid + height: 20 + width: 20 + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 5 + visible: false + fillMode: Image.PreserveAspectFit + source: "img/edit_combox.png" + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onEntered: { + imageItemid.visible = true + textItemid.color = statesComboBox.colorSelect + } + onExited: { + imageItemid.visible = false + textItemid.color = statesComboBox.colorItem + } + onClicked: { + if (mouseX > imageItemid.x + && mouseX < imageItemid.x + imageItemid.width + && mouseY > imageItemid.y + && mouseY < imageItemid.y + imageItemid.height) + statesComboBox.editItem(styleData.row) + else { + statesComboBox.state = "" + var prevSelection = chosenItemText.text + chosenItemText.text = styleData.value + listView.currentRow = styleData.row + statesComboBox.selectItem(styleData.row) + } + } + } + } //Item + } //Component + } //Table View + + RowLayout { + Rectangle { + width: 1 + } + Text { + id: createStateText + width: statesComboBox.width + height: statesComboBox.height + font.bold: true + text: qsTr("Create State ...") + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onEntered: { + createStateText.color = statesComboBox.colorSelect + } + onExited: { + createStateText.color = statesComboBox.colorItem + } + onClicked: { + statesComboBox.state = "" + statesComboBox.selectCreate() + } + } + } + } + } + } + states: State { + name: "dropDown" + PropertyChanges { + target: dropDownList + height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) + } + PropertyChanges { + target: dropDownShowdowList + width: statesComboBox.width + 3 + height: (statesComboBox.rowHeight * (statesComboBox.items.count + 1)) + 3 + } + PropertyChanges { + target: listView + height: 20 + implicitHeight: (statesComboBox.rowHeight * (statesComboBox.items.count)) + } + } } diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 1772c7f18..3bcc6c270 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -6,157 +6,157 @@ import QtQuick.Layouts 1.1 import org.ethereum.qml.RecordLogEntry 1.0 Item { - property ListModel fullModel: ListModel{} - property ListModel transactionModel: ListModel{} - property ListModel callModel: ListModel{} + property ListModel fullModel: ListModel{} + property ListModel transactionModel: ListModel{} + property ListModel callModel: ListModel{} - ColumnLayout { - anchors.fill: parent - RowLayout { - anchors.right: parent.right - anchors.left: parent.left - Connections - { - id: compilationStatus - target: codeModel - property bool compilationComplete: false - onCompilationComplete: compilationComplete = true - onCompilationError: compilationComplete = false - } + ColumnLayout { + anchors.fill: parent + RowLayout { + anchors.right: parent.right + anchors.left: parent.left + Connections + { + id: compilationStatus + target: codeModel + property bool compilationComplete: false + onCompilationComplete: compilationComplete = true + onCompilationError: compilationComplete = false + } - Connections - { - target: projectModel - onProjectSaved: - { - if (projectModel.appIsClosing || projectModel.projectIsClosing) - return; - if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) - projectModel.stateListModel.debugDefaultState(); - } - onProjectClosed: - { - fullModel.clear(); - transactionModel.clear(); - callModel.clear(); - } - onContractSaved: { - if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) - projectModel.stateListModel.debugDefaultState(); - } - } - StatesComboBox - { - id: statesCombo - items: projectModel.stateListModel - onSelectCreate: projectModel.stateListModel.addState(); - onEditItem: projectModel.stateListModel.editState(item) - colorItem: "black" - colorSelect: "blue" - color: "white" - Connections { - target: projectModel.stateListModel - onStateRun: { - if (statesCombo.selectedIndex !== index) - statesCombo.setSelectedIndex( index ); - } - } - } - Button - { - anchors.rightMargin: 9 - anchors.verticalCenter: parent.verticalCenter - action: mineAction - } + Connections + { + target: projectModel + onProjectSaved: + { + if (projectModel.appIsClosing || projectModel.projectIsClosing) + return; + if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) + projectModel.stateListModel.debugDefaultState(); + } + onProjectClosed: + { + fullModel.clear(); + transactionModel.clear(); + callModel.clear(); + } + onContractSaved: { + if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running) + projectModel.stateListModel.debugDefaultState(); + } + } + StatesComboBox + { + id: statesCombo + items: projectModel.stateListModel + onSelectCreate: projectModel.stateListModel.addState(); + onEditItem: projectModel.stateListModel.editState(item) + colorItem: "black" + colorSelect: "blue" + color: "white" + Connections { + target: projectModel.stateListModel + onStateRun: { + if (statesCombo.selectedIndex !== index) + statesCombo.setSelectedIndex( index ); + } + } + } + Button + { + anchors.rightMargin: 9 + anchors.verticalCenter: parent.verticalCenter + action: mineAction + } - ComboBox { - id: itemFilter + ComboBox { + id: itemFilter - function getCurrentModel() - { - return currentIndex === 0 ? fullModel : currentIndex === 1 ? transactionModel : currentIndex === 2 ? callModel : fullModel; - } + function getCurrentModel() + { + return currentIndex === 0 ? fullModel : currentIndex === 1 ? transactionModel : currentIndex === 2 ? callModel : fullModel; + } - model: ListModel { - ListElement { text: qsTr("Calls and Transactions"); value: 0; } - ListElement { text: qsTr("Only Transactions"); value: 1; } - ListElement { text: qsTr("Only Calls"); value: 2; } - } + model: ListModel { + ListElement { text: qsTr("Calls and Transactions"); value: 0; } + ListElement { text: qsTr("Only Transactions"); value: 1; } + ListElement { text: qsTr("Only Calls"); value: 2; } + } - onCurrentIndexChanged: - { - logTable.model = itemFilter.getCurrentModel(); - } - } - } - TableView { - id: logTable - Layout.fillWidth: true - Layout.fillHeight: true - model: fullModel + onCurrentIndexChanged: + { + logTable.model = itemFilter.getCurrentModel(); + } + } + } + TableView { + id: logTable + Layout.fillWidth: true + Layout.fillHeight: true + model: fullModel - TableViewColumn { - role: "transactionIndex" - title: qsTr("#") - width: 40 - } - TableViewColumn { - role: "contract" - title: qsTr("Contract") - width: 100 - } - TableViewColumn { - role: "function" - title: qsTr("Function") - width: 120 - } - TableViewColumn { - role: "value" - title: qsTr("Value") - width: 60 - } - TableViewColumn { - role: "address" - title: qsTr("Destination") - width: 130 - } - TableViewColumn { - role: "returned" - title: qsTr("Returned") - width: 120 - } - onActivated: { - var item = logTable.model.get(row); - if (item.type === RecordLogEntry.Transaction) - clientModel.debugRecord(item.recordIndex); - else - clientModel.emptyRecord(); - } - Keys.onPressed: { - if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { - var item = logTable.model.get(currentRow); - appContext.toClipboard(item.returned); - } - } - } - } - Connections { - target: clientModel - onStateCleared: { - fullModel.clear(); - transactionModel.clear(); - callModel.clear(); - } - onNewRecord: { - fullModel.append(_r); - if (!_r.call) - transactionModel.append(_r); - else - callModel.append(_r); - } - onMiningComplete: { - fullModel.append(clientModel.lastBlock); - transactionModel.append(clientModel.lastBlock); - } - } + TableViewColumn { + role: "transactionIndex" + title: qsTr("#") + width: 40 + } + TableViewColumn { + role: "contract" + title: qsTr("Contract") + width: 100 + } + TableViewColumn { + role: "function" + title: qsTr("Function") + width: 120 + } + TableViewColumn { + role: "value" + title: qsTr("Value") + width: 60 + } + TableViewColumn { + role: "address" + title: qsTr("Destination") + width: 130 + } + TableViewColumn { + role: "returned" + title: qsTr("Returned") + width: 120 + } + onActivated: { + var item = logTable.model.get(row); + if (item.type === RecordLogEntry.Transaction) + clientModel.debugRecord(item.recordIndex); + else + clientModel.emptyRecord(); + } + Keys.onPressed: { + if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { + var item = logTable.model.get(currentRow); + appContext.toClipboard(item.returned); + } + } + } + } + Connections { + target: clientModel + onStateCleared: { + fullModel.clear(); + transactionModel.clear(); + callModel.clear(); + } + onNewRecord: { + fullModel.append(_r); + if (!_r.call) + transactionModel.append(_r); + else + callModel.append(_r); + } + onMiningComplete: { + fullModel.append(clientModel.lastBlock); + transactionModel.append(clientModel.lastBlock); + } + } } From 04d0584bc537bf94334c1766d14b93b80141ffaf Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 2 Apr 2015 10:20:33 +0200 Subject: [PATCH 49/50] - add Search icon. - fix animation bad behavior --- mix/qml/LogsPane.qml | 71 +++++++++++++++++++++++-------------- mix/qml/LogsPaneStyle.qml | 4 +-- mix/qml/StatusPane.qml | 4 +-- mix/qml/img/searchicon.png | Bin 0 -> 1439 bytes mix/res.qrc | 1 + 5 files changed, 49 insertions(+), 31 deletions(-) create mode 100644 mix/qml/img/searchicon.png diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index c619080bf..ca123f6a0 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -37,7 +37,6 @@ Rectangle height: parent.height - rowAction.height width: parent.width spacing: 0 - ListModel { id: logsModel } @@ -100,7 +99,7 @@ Rectangle Rectangle { - width: 750 + width: LogsPaneStyle.generic.layout.dateWidth + LogsPaneStyle.generic.layout.contentWidth + LogsPaneStyle.generic.layout.typeWidth height: 30 color: { @@ -171,7 +170,7 @@ Rectangle anchors.verticalCenter: parent.verticalCenter elide: Text.ElideRight anchors.left: parent.left - anchors.leftMargin: 190 + anchors.leftMargin: 230 color: { parent.getColor(level); } @@ -486,39 +485,59 @@ Rectangle } } - DefaultTextField + Rectangle { - id: searchBox + width: 120 + radius: 10 + height: 25 + color: "white" anchors.verticalCenter: parent.verticalCenter - width: LogsPaneStyle.generic.layout.headerInputWidth - 50 - font.family: LogsPaneStyle.generic.layout.logLabelFont - font.pointSize: Style.absoluteSize(-3) - font.italic: true - text: qsTr(" - Search - ") - onFocusChanged: + + Image { - if (!focus && text === "") - text = qsTr(" - Search - "); - else if (focus && text === qsTr(" - Search - ")) - text = ""; + id: searchImg + source: "qrc:/qml/img/searchicon.png" + fillMode: Image.PreserveAspectFit + width: 20 + height: 25 + z: 3 } - onTextChanged: { - if (text === qsTr(" - Search - ")) - proxyModel.search(""); - else - proxyModel.search(text); - } + DefaultTextField + { + id: searchBox + z: 2 + width: 100 + anchors.left: searchImg.right + anchors.leftMargin: -7 + font.family: LogsPaneStyle.generic.layout.logLabelFont + font.pointSize: Style.absoluteSize(-3) + font.italic: true + text: qsTr(" - Search - ") + onFocusChanged: + { + if (!focus && text === "") + text = qsTr(" - Search - "); + else if (focus && text === qsTr(" - Search - ")) + text = ""; + } - style: - TextFieldStyle { - background: Rectangle { - radius: 10 + onTextChanged: { + if (text === qsTr(" - Search - ")) + proxyModel.search(""); + else + proxyModel.search(text); + } + + style: + TextFieldStyle { + background: Rectangle { + radius: 10 + } } } } - Rectangle { height: LogsPaneStyle.generic.layout.headerButtonHeight diff --git a/mix/qml/LogsPaneStyle.qml b/mix/qml/LogsPaneStyle.qml index 19f6a653e..0bbdfcee4 100644 --- a/mix/qml/LogsPaneStyle.qml +++ b/mix/qml/LogsPaneStyle.qml @@ -18,8 +18,8 @@ QtObject { property string logLabelColor: "#4a4a4a" property string logLabelFont: "sans serif" property int headerInputWidth: 200 - property int dateWidth: 70 - property int typeWidth: 90 + property int dateWidth: 150 + property int typeWidth: 150 property int contentWidth: 560 property string logAlternateColor: "#f6f5f6" property string errorColor: "#fffcd5" diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 4a9287bec..6d8042add 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -227,7 +227,7 @@ Rectangle { top = top.parent var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; - logsContainer.x = status.x + statusContainer.x - LogsPaneStyle.generic.layout.dateWidth - LogsPaneStyle.generic.layout.typeWidth - 30 + logsContainer.x = status.x + statusContainer.x - LogsPaneStyle.generic.layout.dateWidth - LogsPaneStyle.generic.layout.typeWidth + 70 } LogsPane @@ -239,7 +239,6 @@ Rectangle { State { name: "opened"; PropertyChanges { target: logsContainer; height: 500; visible: true } - PropertyChanges { target: statusContainer; width: 100; height: 25 } }, State { name: "closed"; @@ -250,7 +249,6 @@ Rectangle { transitions: Transition { NumberAnimation { properties: "height"; easing.type: Easing.InOutQuad; duration: 200 } NumberAnimation { target: logsContainer; properties: "visible"; easing.type: Easing.InOutQuad; duration: 200 } - NumberAnimation { target: statusContainer; properties: "width"; easing.type: Easing.InOutQuad; duration: 500 } } } } diff --git a/mix/qml/img/searchicon.png b/mix/qml/img/searchicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c10dc9228e7f7ccf39670ea9c7f6c4acbd19caa4 GIT binary patch literal 1439 zcmV;Q1z`G#P)Px)SxH1eRA>e5nq6pIMHI)oNwd4H4@#r9jbBJg5%M7RK}scr65pFdi@-Fdi@-Fdi@-Fdit62V&)bO{dez zcs#x*7K`lye=Fr?OV4bvSe#v6UY=ZBTs+CRTsidnVMa>0udi==MMcG1ka`Z18~qeB zW`QxI5Knh^cVF}y8)aW4gqf+0$z(DEiNlasZy8viJWJb;l$U6yTHH+eAmvVb9Q7sg zdvkMhuMZ9m{u3oRFRajnA$xBkkvI;4M=S+D6SBS3M>{$?e)m#}%pHXMK4iMc+hq)- z&lL)V=exSPe)W=xsx1`Z{{H@L82lB+Y#|pgx-*~84?^f#5Ca*vp2&C=xePdQWU|!j zQ>oN+5P6+3+JpxN25!f=Z!q*B%0E$l07J)gjNsjWjCcQIWbYA)@m{p zs|{GGACkv}Ed6=v&*+jBd_sSc;tBHK#c6NU22d>k{CgcKgXDnG;mkyMt zj51+XQ(0UjefD2bmcJ!zBFWYjnG$8fXue;x6V9^8lqC_;Hg-u@luDEc^KF#zcUcBp ziqa4#7Bg#O+lLNkcc{7&;raRb4QQ(rjm*N;P?~*&9oSVZEiDP3p~_uKgfp3pYz#^p zd}hI(X=SAW1WMQtUlJv=tFn9AmgL->Ti;QgoMv~we5=oUFRm%hK0C!C}Aqrpy45JTAHV_?I_c)#B$O$`)h!N_wklRX|{Nf-xsLO^ugA`Yd_iMc%}W zjx)3S0G4xj9oyM)-sd}Y6|MOhwuw1snzi6OxsjRn{ISlK@hWc`!eYFO^mjBh@;Q^= zwF0L#AJR@H&hTc@m!D_ld#yBSHx*$aZ<8jZz`vN;5AGfAv@!qy002ovPDHLkV1lXRpyU7m literal 0 HcmV?d00001 diff --git a/mix/res.qrc b/mix/res.qrc index 3a4254791..e981f22ae 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -56,5 +56,6 @@ qml/img/cleariconactive.png qml/img/copyicon.png qml/img/copyiconactive.png + qml/img/searchicon.png From 877380bf586ae755487ede47dc507c4478613005 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 2 Apr 2015 12:30:03 +0200 Subject: [PATCH 50/50] - Add actions for play and stop debugging. - Small change in layout of statecombobox. --- mix/qml/Debugger.qml | 12 +++++------ mix/qml/StatesComboBox.qml | 39 +++++++++++++++++++++++----------- mix/qml/TransactionLog.qml | 6 ++++-- mix/qml/img/stop_button2x.png | Bin 0 -> 235 bytes mix/res.qrc | 1 + 5 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 mix/qml/img/stop_button2x.png diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 9ab2f03a4..836bbaf94 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -225,24 +225,24 @@ Rectangle { id: playAction enabledStateImg: "qrc:/qml/img/play_button.png" disableStateImg: "qrc:/qml/img/play_button.png" - onClicked: console.log("play"); + onClicked: projectModel.stateListModel.runState(transactionLog.selectedStateIndex) width: 30 height: 30 buttonShortcut: "Ctrl+Shift+F8" - buttonTooltip: qsTr("Play") + buttonTooltip: qsTr("Start Debugging") visible: true } StepActionImage { id: pauseAction - enabledStateImg: "qrc:/qml/img/pause_button.png" - disableStateImg: "qrc:/qml/img/pause_button.png" - onClicked: console.log("pause"); + enabledStateImg: "qrc:/qml/img/stop_button2x.png" + disableStateImg: "qrc:/qml/img/stop_button2x.png" + onClicked: Debugger.init(null); width: 30 height: 30 buttonShortcut: "Ctrl+Shift+F9" - buttonTooltip: qsTr("Pause") + buttonTooltip: qsTr("Stop Debugging") visible: true } diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index 34567d083..bc7a4853d 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -29,7 +29,7 @@ Rectangle { id: statesComboBox width: 200 - height: 20 + height: 23 Component.onCompleted: { var top = dropDownList @@ -53,7 +53,7 @@ Rectangle { signal selectItem(real item) signal editItem(real item) signal selectCreate - property variant rowHeight: 25 + property int rowHeight: 25 property variant items property alias selectedItem: chosenItemText.text property alias selectedIndex: listView.currentRow @@ -67,21 +67,31 @@ Rectangle { property variant colorItem property variant colorSelect + SourceSansProRegular + { + id: regularFont + } + + SourceSansProBold + { + id: boldFont + } + smooth: true Rectangle { id: chosenItem width: parent.width height: statesComboBox.height color: statesComboBox.color - smooth: true + Text { id: chosenItemText - anchors.top: parent.top anchors.left: parent.left - anchors.margins: 2 + anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter color: statesComboBox.colorItem text: "" - smooth: true + font.family: regularFont.name } MouseArea { @@ -111,7 +121,7 @@ Rectangle { clip: true radius: 4 anchors.top: chosenItem.top - anchors.margins: 2 + anchors.topMargin: 23 color: statesComboBox.color ColumnLayout { @@ -151,7 +161,9 @@ Rectangle { color: statesComboBox.colorItem anchors.top: parent.top anchors.left: parent.left - anchors.margins: 5 + anchors.leftMargin: 10 + anchors.topMargin: 5 + font.family: regularFont.name } Image { id: imageItemid @@ -197,15 +209,18 @@ Rectangle { } //Table View RowLayout { - Rectangle { - width: 1 - } + anchors.top: listView.bottom + anchors.topMargin: 4 + anchors.left: parent.left + anchors.leftMargin: 10 Text { id: createStateText width: statesComboBox.width height: statesComboBox.height - font.bold: true + font.family: boldFont.name + color: "#808080" text: qsTr("Create State ...") + font.weight: Font.DemiBold MouseArea { anchors.fill: parent hoverEnabled: true diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 3bcc6c270..5668c6e05 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -9,6 +9,7 @@ Item { property ListModel fullModel: ListModel{} property ListModel transactionModel: ListModel{} property ListModel callModel: ListModel{} + property int selectedStateIndex: statesCombo.selectedIndex ColumnLayout { anchors.fill: parent @@ -45,14 +46,15 @@ Item { projectModel.stateListModel.debugDefaultState(); } } + StatesComboBox { id: statesCombo items: projectModel.stateListModel onSelectCreate: projectModel.stateListModel.addState(); onEditItem: projectModel.stateListModel.editState(item) - colorItem: "black" - colorSelect: "blue" + colorItem: "#808080" + colorSelect: "#4a90e2" color: "white" Connections { target: projectModel.stateListModel diff --git a/mix/qml/img/stop_button2x.png b/mix/qml/img/stop_button2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1727b729a391be03065cecb0146a086d9c34ceb4 GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^c|aV)!3HGzUpB-7DYhhUcNd2LAh=-f^2tCE&H|6f zVg?3oVGw3ym^DWND9B#o>FdgVpM{CTifz*yho?ZH3QrfukcwMxFER2mC~z=1ny3n9 zuGAISzMIKl9tTh!3L5gVe>Kglj61h})kO1Kb>ICDakdw5sLLEuoKwI-h;>L2tPW-t ai2kzU%1ag>C*>4l5YN-q&t;ucLK6TB13`2E literal 0 HcmV?d00001 diff --git a/mix/res.qrc b/mix/res.qrc index 24bbc3830..0149b96e4 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -62,5 +62,6 @@ qml/img/copyicon.png qml/img/copyiconactive.png qml/img/searchicon.png + qml/img/stop_button2x.png