Browse Source

contracts library

cl-refactor
arkpar 10 years ago
parent
commit
f56bf9ae17
  1. 7
      mix/CMakeLists.txt
  2. 8
      mix/ClientModel.cpp
  3. 5
      mix/ClientModel.h
  4. 67
      mix/MixClient.cpp
  5. 1
      mix/MixClient.h
  6. 31
      mix/qml/ContractLibrary.qml
  7. 6
      mix/qml/ProjectModel.qml
  8. 13
      mix/qml/StateDialog.qml
  9. 95
      mix/qml/StateList.qml
  10. 172
      mix/qml/StateListModel.qml
  11. 16
      mix/qml/StatusPane.qml
  12. 2
      mix/qml/TransactionDialog.qml
  13. 5
      mix/qml/js/ProjectModel.js
  14. 8
      mix/qml/main.qml
  15. 4
      mix/res.qrc
  16. 45
      mix/stdc/config.sol
  17. 73
      mix/stdc/namereg.sol

7
mix/CMakeLists.txt

@ -13,7 +13,7 @@ aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(..)
find_package (Qt5WebEngine QUIET) find_package (Qt5WebEngine QUIET)
qt5_add_resources(UI_RESOURCES qml.qrc) qt5_add_resources(UI_RESOURCES res.qrc)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
@ -62,6 +62,7 @@ eth_install_executable(${EXECUTABLE}
QMLDIR ${CMAKE_CURRENT_SOURCE_DIR}/qml QMLDIR ${CMAKE_CURRENT_SOURCE_DIR}/qml
) )
#add qml files to project tree in Qt creator #add qml asnd stdc files to project tree in Qt creator
file(GLOB_RECURSE QMLFILES "qml/*.*") file(GLOB_RECURSE QMLFILES "qml/*.*")
add_custom_target(dummy SOURCES ${QMLFILES}) file(GLOB_RECURSE SOLFILES "stdc/*.*")
add_custom_target(dummy SOURCES ${QMLFILES} ${SOLFILES})

8
mix/ClientModel.cpp

@ -90,6 +90,12 @@ QString ClientModel::apiCall(QString const& _message)
return m_rpcConnector->response(); return m_rpcConnector->response();
} }
void ClientModel::mine()
{
m_client->mine();
newBlock();
}
QString ClientModel::contractAddress() const QString ClientModel::contractAddress() const
{ {
return QString::fromStdString(dev::toJS(m_contractAddress)); return QString::fromStdString(dev::toJS(m_contractAddress));
@ -182,7 +188,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
//run contract creation first //run contract creation first
m_client->resetState(_balance); m_client->resetState(_balance);
ExecutionResult debuggingContent = deployContract(contractCode, ctrTransaction); ExecutionResult debuggingContent = deployContract(contractCode, ctrTransaction);
Address address = m_contractAddress Address address = m_contractAddress;
for (unsigned i = 0; i < _sequence.size(); ++i) for (unsigned i = 0; i < _sequence.size(); ++i)
debuggingContent = callContract(address, transactonData.at(i), _sequence.at(i)); debuggingContent = callContract(address, transactonData.at(i), _sequence.at(i));

5
mix/ClientModel.h

@ -84,6 +84,9 @@ public:
/// @returns RPC response in Json format /// @returns RPC response in Json format
Q_INVOKABLE QString apiCall(QString const& _message); Q_INVOKABLE QString apiCall(QString const& _message);
/// Simulate mining. Creates a new block
Q_INVOKABLE void mine();
public slots: public slots:
/// Run the contract constructor and show debugger window. /// Run the contract constructor and show debugger window.
void debugDeployment(); void debugDeployment();
@ -108,6 +111,8 @@ signals:
/// Contract address changed /// Contract address changed
void contractAddressChanged(); void contractAddressChanged();
/// Execution state changed /// Execution state changed
void newBlock();
/// Execution state changed
void stateChanged(); void stateChanged();
/// Show debugger window request /// Show debugger window request
void showDebuggerWindow(); void showDebuggerWindow();

67
mix/MixClient.cpp

@ -47,7 +47,10 @@ void MixClient::resetState(u256 _balance)
WriteGuard l(x_state); WriteGuard l(x_state);
m_state = eth::State(Address(), m_stateDB, BaseState::Empty); m_state = eth::State(Address(), m_stateDB, BaseState::Empty);
m_state.addBalance(m_userAccount.address(), _balance); m_state.addBalance(m_userAccount.address(), _balance);
m_blocks = Blocks { Block() }; Block genesis;
genesis.state = m_state;
Block open;
m_blocks = Blocks { genesis, open }; //last block contains a list of pending transactions to be finalized
} }
void MixClient::executeTransaction(bytesConstRef _rlp, State& _state) void MixClient::executeTransaction(bytesConstRef _rlp, State& _state)
@ -113,7 +116,7 @@ void MixClient::executeTransaction(bytesConstRef _rlp, State& _state)
void MixClient::validateBlock(int _block) const void MixClient::validateBlock(int _block) const
{ {
if ((unsigned)_block >= m_blocks.size() - 1) if (_block != -1 && _block != 0 && (unsigned)_block >= m_blocks.size() - 1)
{ {
InvalidBlockException exception; InvalidBlockException exception;
exception << BlockIndex(_block); exception << BlockIndex(_block);
@ -132,6 +135,18 @@ void MixClient::mine()
m_blocks.push_back(Block()); m_blocks.push_back(Block());
} }
State const& MixClient::asOf(int _block) const
{
validateBlock(_block);
if (_block == 0)
return m_blocks[m_blocks.size() - 2].state;
else if (_block == -1)
return m_state;
else
return m_blocks[_block].state;
}
void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{ {
WriteGuard l(x_state); WriteGuard l(x_state);
@ -180,37 +195,32 @@ bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _
u256 MixClient::balanceAt(Address _a, int _block) const u256 MixClient::balanceAt(Address _a, int _block) const
{ {
validateBlock(_block);
ReadGuard l(x_state); ReadGuard l(x_state);
return m_blocks[_block].state.balance(_a); return asOf(_block).balance(_a);
} }
u256 MixClient::countAt(Address _a, int _block) const u256 MixClient::countAt(Address _a, int _block) const
{ {
validateBlock(_block);
ReadGuard l(x_state); ReadGuard l(x_state);
return m_blocks[_block].state.transactionsFrom(_a); return asOf(_block).transactionsFrom(_a);
} }
u256 MixClient::stateAt(Address _a, u256 _l, int _block) const u256 MixClient::stateAt(Address _a, u256 _l, int _block) const
{ {
validateBlock(_block);
ReadGuard l(x_state); ReadGuard l(x_state);
return m_blocks[_block].state.storage(_a, _l); return asOf(_block).storage(_a, _l);
} }
bytes MixClient::codeAt(Address _a, int _block) const bytes MixClient::codeAt(Address _a, int _block) const
{ {
validateBlock(_block);
ReadGuard l(x_state); ReadGuard l(x_state);
return m_blocks[_block].state.code(_a); return asOf(_block).code(_a);
} }
std::map<u256, u256> MixClient::storageAt(Address _a, int _block) const std::map<u256, u256> MixClient::storageAt(Address _a, int _block) const
{ {
validateBlock(_block);
ReadGuard l(x_state); ReadGuard l(x_state);
return m_blocks[_block].state.storage(_a); return asOf(_block).storage(_a);
} }
eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const
@ -222,40 +232,20 @@ eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const
eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const
{ {
LocalisedLogEntries ret; LocalisedLogEntries ret;
unsigned blockNumber = m_blocks.size(); unsigned blockNumber = m_blocks.size() - 1;
unsigned begin = std::min<unsigned>(blockNumber, (unsigned)_f.latest()); unsigned begin = std::min<unsigned>(blockNumber, (unsigned)_f.latest());
unsigned end = std::min(blockNumber, std::min(begin, (unsigned)_f.earliest())); unsigned end = std::min(blockNumber, std::min(begin, (unsigned)_f.earliest()));
unsigned m = _f.max(); unsigned m = _f.max();
unsigned s = _f.skip(); unsigned s = _f.skip();
// Handle pending transactions differently as they're not on the block chain.
if (begin > blockNumber)
{
ReadGuard l(x_state);
for (unsigned i = 0; i < m_state.pending().size(); ++i)
{
// Might have a transaction that contains a matching log.
TransactionReceipt const& tr = m_state.receipt(i);
LogEntries le = _f.matches(tr);
if (le.size())
{
for (unsigned j = 0; j < le.size() && ret.size() != m; ++j)
if (s)
s--;
else
ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin));
}
}
begin = blockNumber;
}
unsigned n = begin; unsigned n = begin;
for (; ret.size() != m && n != end; n--) for (; ret.size() != m && n != end; n--)
{ {
// check block bloom bool pendingBlock = n == blockNumber;
if (_f.matches(m_blocks[n].info.logBloom)) if (pendingBlock || _f.matches(m_blocks[n].info.logBloom))
{
for (ExecutionResult const& t: m_blocks[n].transactions) for (ExecutionResult const& t: m_blocks[n].transactions)
{ {
if (_f.matches(t.receipt.bloom())) if (pendingBlock || _f.matches(t.receipt.bloom()))
{ {
LogEntries le = _f.matches(t.receipt); LogEntries le = _f.matches(t.receipt);
if (le.size()) if (le.size())
@ -270,8 +260,7 @@ eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const
} }
} }
} }
if (n == end) }
break;
} }
return ret; return ret;
} }

1
mix/MixClient.h

@ -128,6 +128,7 @@ private:
void executeTransaction(bytesConstRef _rlp, eth::State& _state); void executeTransaction(bytesConstRef _rlp, eth::State& _state);
void validateBlock(int _block) const; void validateBlock(int _block) const;
void noteChanged(h256Set const& _filters); void noteChanged(h256Set const& _filters);
dev::eth::State const& asOf(int _block) const;
KeyPair m_userAccount; KeyPair m_userAccount;
eth::State m_state; eth::State m_state;

31
mix/qml/ContractLibrary.qml

@ -0,0 +1,31 @@
import QtQuick 2.2
Item {
id: contractLibrary
property alias model: contractListModel;
Connections {
target: appContext
Component.onCompleted: {
//TODO: load a list, dependencies, ets, from external files
var configSource = fileIo.readFile("qrc:///stdc/config.sol");
var nameRegSource = fileIo.readFile("qrc:///stdc/namereg.sol");
contractListModel.append({
name: "Config",
url: "qrc:///stdc/config.sol",
source: configSource
});
contractListModel.append({
name: "NameReg",
url: "qrc:///stdc/namereg.sol",
source: nameRegSource
});
}
}
ListModel {
id: contractListModel
}
}

6
mix/qml/ProjectModel.qml

@ -17,6 +17,7 @@ Item {
signal documentAdded(var documentId) signal documentAdded(var documentId)
signal projectSaving(var projectData) signal projectSaving(var projectData)
signal projectSaved() signal projectSaved()
signal newProject(var projectData)
signal documentSaved(var documentId) signal documentSaved(var documentId)
property bool isEmpty: (projectPath === "") property bool isEmpty: (projectPath === "")
@ -27,6 +28,7 @@ Item {
property string projectTitle: "" property string projectTitle: ""
property string currentDocumentId: "" property string currentDocumentId: ""
property var listModel: projectListModel property var listModel: projectListModel
property var stateListModel: projectStateListModel.model
//interface //interface
function saveAll() { ProjectModelCode.saveAll(); } function saveAll() { ProjectModelCode.saveAll(); }
@ -84,6 +86,10 @@ Item {
id: projectListModel id: projectListModel
} }
StateListModel {
id: projectStateListModel
}
Settings { Settings {
id: projectSettings id: projectSettings
property string lastProjectPath; property string lastProjectPath;

13
mix/qml/StateDialog.qml

@ -17,11 +17,12 @@ Window {
property alias stateTitle: titleField.text property alias stateTitle: titleField.text
property alias stateBalance: balanceField.value property alias stateBalance: balanceField.value
property alias isDefault: defaultCheckBox.checked
property int stateIndex property int stateIndex
property var stateTransactions: [] property var stateTransactions: []
signal accepted signal accepted
function open(index, item) { function open(index, item, setDefault) {
stateIndex = index; stateIndex = index;
stateTitle = item.title; stateTitle = item.title;
balanceField.value = item.balance; balanceField.value = item.balance;
@ -32,6 +33,7 @@ Window {
transactionsModel.append(item.transactions[t]); transactionsModel.append(item.transactions[t]);
stateTransactions.push(item.transactions[t]); stateTransactions.push(item.transactions[t]);
} }
isDefault = setDefault;
visible = true; visible = true;
titleField.focus = true; titleField.focus = true;
} }
@ -77,6 +79,14 @@ Window {
Layout.fillWidth: true Layout.fillWidth: true
} }
Label {
text: qsTr("Default")
}
CheckBox {
id: defaultCheckBox
Layout.fillWidth: true
}
Label { Label {
text: qsTr("Transactions") text: qsTr("Transactions")
} }
@ -152,6 +162,7 @@ Window {
} }
ToolButton { ToolButton {
text: qsTr("Edit"); text: qsTr("Edit");
visible: !stdContract
Layout.fillHeight: true Layout.fillHeight: true
onClicked: transactionsModel.editTransaction(index) onClicked: transactionsModel.editTransaction(index)
} }

95
mix/qml/StateList.qml

@ -3,8 +3,6 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
Rectangle { Rectangle {
color: "#ededed" color: "#ededed"
@ -14,32 +12,13 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
height: parent.height height: parent.height
width: parent.width width: parent.width
property var stateList: []
Connections {
target: projectModel
onProjectClosed: {
stateListModel.clear();
}
onProjectLoaded: {
if (!projectData.states)
projectData.states = [];
var items = projectData.states;
for(var i = 0; i < items.length; i++) {
stateListModel.append(items[i]);
stateList.push(items[i])
}
}
onProjectSaving: {
projectData.states = stateList;
}
}
ListView { ListView {
id: list
anchors.top: parent.top anchors.top: parent.top
height: parent.height height: parent.height
width: parent.width width: parent.width
model: stateListModel model: projectModel.stateListModel
delegate: renderDelegate delegate: renderDelegate
} }
@ -48,65 +27,6 @@ Rectangle {
action: addStateAction action: addStateAction
} }
StateDialog {
id: stateDialog
onAccepted: {
var item = stateDialog.getItem();
if (stateDialog.stateIndex < stateListModel.count) {
stateList[stateDialog.stateIndex] = item;
stateListModel.set(stateDialog.stateIndex, item);
} else {
stateList.push(item);
stateListModel.append(item);
}
stateListModel.save();
}
}
ListModel {
id: stateListModel
function addState() {
var ether = QEtherHelper.createEther("100000000000000000000000000", QEther.Wei);
var item = {
title: "",
balance: ether,
transactions: []
};
var ctorTr = {
value: QEtherHelper.createEther("100", QEther.Wei),
functionId: qsTr("Constructor"),
gas: QEtherHelper.createEther("125000", QEther.Wei),
gasPrice: QEtherHelper.createEther("10000000000000", QEther.Wei),
executeConstructor: true
};
item.transactions.push(ctorTr);
stateDialog.open(stateListModel.count, item);
}
function editState(index) {
stateDialog.open(index, stateList[index]);
}
function runState(index) {
var item = stateList[index];
clientModel.debugState(item);
}
function deleteState(index) {
stateListModel.remove(index);
stateList.splice(index, 1);
save();
}
function save() {
projectModel.saveProject();
}
}
Component { Component {
id: renderDelegate id: renderDelegate
Item { Item {
@ -125,20 +45,17 @@ Rectangle {
ToolButton { ToolButton {
text: qsTr("Edit"); text: qsTr("Edit");
Layout.fillHeight: true Layout.fillHeight: true
onClicked: stateListModel.editState(index); onClicked: list.model.editState(index);
} }
ToolButton { ToolButton {
text: qsTr("Delete"); text: qsTr("Delete");
Layout.fillHeight: true Layout.fillHeight: true
onClicked: stateListModel.deleteState(index); onClicked: list.model.deleteState(index);
} }
ToolButton { ToolButton {
text: qsTr("Run"); text: qsTr("Run");
Layout.fillHeight: true Layout.fillHeight: true
onClicked: onClicked: list.model.runState(index);
{
stateListModel.runState(index)
}
} }
} }
} }
@ -149,7 +66,7 @@ Rectangle {
text: "&Add State" text: "&Add State"
shortcut: "Ctrl+T" shortcut: "Ctrl+T"
enabled: codeModel.hasContract && !clientModel.running; enabled: codeModel.hasContract && !clientModel.running;
onTriggered: stateListModel.addState(); onTriggered: list.model.addState();
} }
} }

172
mix/qml/StateListModel.qml

@ -0,0 +1,172 @@
import QtQuick 2.2
import QtQuick.Controls.Styles 1.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
Item {
property int defaultStateIndex: -1
property alias model: stateListModel
property var stateList: []
function fromPlainStateItem(s) {
return {
title: s.title,
balance: QEtherHelper.createEther(s.balance.value, s.balance.unit),
transactions: s.transactions.map(fromPlainTransactionItem)
};
}
function fromPlainTransactionItem(t) {
return {
functionId: t.functionId,
value: QEtherHelper.createEther(t.value.value, t.value.unit),
gas: QEtherHelper.createEther(t.gas.value, t.gas.unit),
gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit),
executeConstructor: t.executeConstructor,
stdContract: t.stdContract
};
}
function toPlainStateItem(s) {
return {
title: s.title,
balance: { balance: s.balance.value, unit: s.balance.unit },
transactions: s.transactions.map(toPlainTransactionItem)
};
}
function toPlainTransactionItem(t) {
return {
functionId: t.functionId,
value: { value: t.value.value, unit: t.value.unit },
gas: { value: t.gas.value, unit: t.gas.unit },
gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit },
executeConstructor: t.executeConstructor,
stdContract: t.stdContract
};
}
Connections {
target: projectModel
onProjectClosed: {
stateListModel.clear();
stateList = [];
}
onProjectLoaded: {
if (!projectData.states)
projectData.states = [];
if (projectData.defaultStateIndex)
defaultStateIndex = projectData.defaultStateIndex;
var items = projectData.states;
for(var i = 0; i < items.length; i++) {
var item = fromPlainStateItem(items[i]);
stateListModel.append(item);
stateList.push(item);
}
}
onProjectSaving: {
projectData.states = []
for(var i = 0; i < stateListModel.count; i++) {
projectData.states.push(toPlainStateItem(stateList[i]));
}
projectData.defaultStateIndex = defaultStateIndex;
}
onNewProject: {
var state = toPlainTransactionItem(stateListModel.createDefaultState());
state.title = qsTr("Default");
projectData.states = [ state ];
projectData.defaultStateIndex = 0;
}
}
StateDialog {
id: stateDialog
onAccepted: {
var item = stateDialog.getItem();
if (stateDialog.stateIndex < stateListModel.count) {
defaultStateIndex = stateDialog.isDefault;
stateList[stateDialog.stateIndex] = item;
stateListModel.set(stateDialog.stateIndex, item);
} else {
stateList.push(item);
stateListModel.append(item);
}
stateListModel.save();
}
}
ContractLibrary {
id: contractLibrary;
}
ListModel {
id: stateListModel
function defaultTransactionItem() {
return {
value: QEtherHelper.createEther("100", QEther.Wei),
gas: QEtherHelper.createEther("125000", QEther.Wei),
gasPrice: QEtherHelper.createEther("10000000000000", QEther.Wei),
executeConstructor: false,
stdContract: false
};
}
function createDefaultState() {
var ether = QEtherHelper.createEther("100000000000000000000000000", QEther.Wei);
var item = {
title: "",
balance: ether,
transactions: []
};
//add all stdc contracts
for (var i = 0; i < contractLibrary.model.count; i++) {
var contractTransaction = defaultTransactionItem();
var contractItem = contractLibrary.model.get(i);
contractTransaction.url = contractItem.url;
contractTransaction.functionId = contractItem.name;
contractTransaction.stdContract = true;
item.transactions.push(contractTransaction);
};
//add constructor
var ctorTr = defaultTransactionItem();
ctorTr.executeConstructor = true;
ctorTr.functionId = qsTr("Constructor");
item.transactions.push(ctorTr);
return item;
}
function addState() {
var item = createDefaultState();
stateDialog.open(stateListModel.count, item, defaultStateIndex === -1);
}
function editState(index) {
stateDialog.open(index, stateList[index], defaultStateIndex === index);
}
function runState(index) {
var item = stateList[index];
clientModel.debugState(item);
}
function deleteState(index) {
stateListModel.remove(index);
stateList.splice(index, 1);
if (index === defaultStateIndex)
defaultStateIndex = -1;
save();
}
function save() {
projectModel.saveProject();
}
}
}

16
mix/qml/StatusPane.qml

@ -27,6 +27,22 @@ Rectangle {
debugRunActionIcon.enabled = statusPane.result.successful; debugRunActionIcon.enabled = statusPane.result.successful;
} }
function infoMessage(text)
{
status.state = "";
status.text = text
logslink.visible = false;
}
Connections {
target:clientModel
onRunStarted: infoMessage(qsTr("Running transactions.."));
onRunFailed: infoMessage(qsTr("Error running transactions"));
onRunComplete: infoMessage(qsTr("Run complete"));
onNewBlock: infoMessage(qsTr("New block created"));
}
color: "transparent" color: "transparent"
anchors.fill: parent anchors.fill: parent
Rectangle { Rectangle {

2
mix/qml/TransactionDialog.qml

@ -49,7 +49,7 @@ Window {
} }
if (functionIndex == -1 && functionsModel.count > 0) if (functionIndex == -1 && functionsModel.count > 0)
functionIndex = 0; //@todo suggest unused funtion functionIndex = 0; //@todo suggest unused function
functionComboBox.currentIndex = functionIndex; functionComboBox.currentIndex = functionIndex;
paramsModel.clear(); paramsModel.clear();

5
mix/qml/js/ProjectModel.js

@ -47,7 +47,7 @@ function saveProject() {
for (var i = 0; i < projectListModel.count; i++) for (var i = 0; i < projectListModel.count; i++)
projectData.files.push(projectListModel.get(i).fileName) projectData.files.push(projectListModel.get(i).fileName)
projectSaving(projectData); projectSaving(projectData);
var json = JSON.stringify(projectData); var json = JSON.stringify(projectData, null, "\t");
var projectFile = projectPath + projectFileName; var projectFile = projectPath + projectFileName;
fileIo.writeFile(projectFile, json); fileIo.writeFile(projectFile, json);
projectSaved(); projectSaved();
@ -173,7 +173,8 @@ function doCreateProject(title, path) {
//TODO: copy from template //TODO: copy from template
fileIo.writeFile(dirPath + indexFile, "<html></html>"); fileIo.writeFile(dirPath + indexFile, "<html></html>");
fileIo.writeFile(dirPath + contractsFile, "contract MyContract {\n}\n"); fileIo.writeFile(dirPath + contractsFile, "contract MyContract {\n}\n");
var json = JSON.stringify(projectData); newProject(projectData);
var json = JSON.stringify(projectData, null, "\t");
fileIo.writeFile(projectFile, json); fileIo.writeFile(projectFile, json);
loadProject(dirPath); loadProject(dirPath);
} }

8
mix/qml/main.qml

@ -37,6 +37,7 @@ ApplicationWindow {
title: qsTr("Debug") title: qsTr("Debug")
MenuItem { action: debugRunAction } MenuItem { action: debugRunAction }
MenuItem { action: debugResetStateAction } MenuItem { action: debugResetStateAction }
MenuItem { action: mineAction }
} }
Menu { Menu {
title: qsTr("Windows") title: qsTr("Windows")
@ -76,6 +77,13 @@ ApplicationWindow {
onTriggered: Qt.quit(); onTriggered: Qt.quit();
} }
Action {
id: mineAction
text: "Mine"
shortcut: "Ctrl+M"
onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running
}
Action { Action {
id: debugRunAction id: debugRunAction
text: "&Run" text: "&Run"

4
mix/qml.qrc → mix/res.qrc

@ -10,6 +10,7 @@
<file>qml/ProjectList.qml</file> <file>qml/ProjectList.qml</file>
<file>qml/StateDialog.qml</file> <file>qml/StateDialog.qml</file>
<file>qml/StateList.qml</file> <file>qml/StateList.qml</file>
<file>qml/StateListModel.qml</file>
<file>qml/img/jumpintoback.png</file> <file>qml/img/jumpintoback.png</file>
<file>qml/img/jumpintoforward.png</file> <file>qml/img/jumpintoforward.png</file>
<file>qml/img/jumpoutback.png</file> <file>qml/img/jumpoutback.png</file>
@ -44,5 +45,8 @@
<file>qml/js/QEtherHelper.js</file> <file>qml/js/QEtherHelper.js</file>
<file>qml/js/TransactionHelper.js</file> <file>qml/js/TransactionHelper.js</file>
<file>qml/Splitter.qml</file> <file>qml/Splitter.qml</file>
<file>qml/ContractLibrary.qml</file>
<file>stdc/config.sol</file>
<file>stdc/namereg.sol</file>
</qresource> </qresource>
</RCC> </RCC>

45
mix/stdc/config.sol

@ -0,0 +1,45 @@
//sol Config
// Simple global configuration registrar.
// @authors:
// Gav Wood <g@ethdev.com>
#require owned, mortal
contract Config is mortal, owned {
function register(uint id, address service) {
if (tx.origin != owner)
return;
services[id] = service;
log1(0, id);
}
function unregister(uint id) {
if (msg.sender != owner && services[id] != msg.sender)
return;
services[id] = address(0);
log1(0, id);
}
function lookup(uint service) constant returns(address a) {
return services[service];
}
mapping (uint => address) services;
}
/*
// Solidity Interface:
contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}
// Example Solidity use:
address addrConfig = 0x661005d2720d855f1d9976f88bb10c1a3398c77f;
address addrNameReg = Config(addrConfig).lookup(1);
// JS Interface:
var abiConfig = [{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"service","type":"uint256"}],"name":"lookup","outputs":[{"name":"a","type":"address"}]},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"service","type":"address"}],"name":"register","outputs":[]},{"constant":false,"inputs":[{"name":"id","type":"uint256"}],"name":"unregister","outputs":[]}];
// Example JS use:
var addrConfig = "0x661005d2720d855f1d9976f88bb10c1a3398c77f";
var addrNameReg;
web3.eth.contract(addrConfig, abiConfig).lookup(1).call().then(function(r){ addrNameReg = r; })
*/

73
mix/stdc/namereg.sol

@ -0,0 +1,73 @@
//sol NameReg
// Simple global name registrar.
// @authors:
// kobigurk (from #ethereum-dev)
// Gav Wood <g@ethdev.com>
contract NameRegister {
function getAddress(string32 _name) constant returns (address o_owner) {}
function getName(address _owner) constant returns (string32 o_name) {}
}
#require Config, owned
contract NameReg is owned, NameRegister {
function NameReg() {
toName[Config()] = "Config";
toAddress["Config"] = Config();
toName[this] = "NameReg";
toAddress["NameReg"] = this;
Config().register(1, this);
log1(0, hash256(Config()));
log1(0, hash256(this));
}
function register(string32 name) {
// Don't allow the same name to be overwritten.
if (toAddress[name] != address(0))
return;
// Unregister previous name if there was one.
if (toName[msg.sender] != "")
toAddress[toName[msg.sender]] = 0;
toName[msg.sender] = name;
toAddress[name] = msg.sender;
log1(0, hash256(msg.sender));
}
function unregister() {
string32 n = toName[msg.sender];
if (n == "")
return;
log1(0, hash256(toAddress[n]));
toName[msg.sender] = "";
toAddress[n] = address(0);
}
function addressOf(string32 name) constant returns (address addr) {
return toAddress[name];
}
function nameOf(address addr) constant returns (string32 name) {
return toName[addr];
}
mapping (address => string32) toName;
mapping (string32 => address) toAddress;
}
/*
// Solidity Interface:
contract NameReg{function kill(){}function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}}
// Example Solidity use:
NameReg(addrNameReg).register("Some Contract");
// JS Interface:
var abiNameReg = [{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]}];
// Example JS use:
web3.eth.contract(addrNameReg, abiNameReg).register("My Name").transact();
*/
Loading…
Cancel
Save