From 40cf37dbb8ba6b5a4162f0c61e283a01cb0871df Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 8 May 2015 10:31:10 +0200 Subject: [PATCH 01/24] - basic transaction creation. --- mix/ClientModel.cpp | 36 +++++++++++++++------ mix/ClientModel.h | 11 ++++--- mix/qml/QAddressView.qml | 57 +++++++++++++++++++++++++++++++++ mix/qml/StateListModel.qml | 8 +++-- mix/qml/StructView.qml | 29 ++--------------- mix/qml/TransactionDialog.qml | 55 +++++++++++++++++++++++++++++++ mix/qml/js/TransactionHelper.js | 3 +- 7 files changed, 156 insertions(+), 43 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 717757c70..7f4817c91 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -250,7 +250,10 @@ void ClientModel::setupState(QVariantMap _state) u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); QString sender = transaction.value("sender").toString(); - bool isStdContract = (transaction.value("stdContract").toBool()); + bool isStdContract = transaction.value("stdContract").toBool(); + bool isContractCall; + if (!transaction.value("isContractCall").isNull()) + isContractCall = transaction.value("isContractCall").toBool(); if (isStdContract) { if (contractId.isEmpty()) //TODO: This is to support old project files, remove later @@ -266,7 +269,7 @@ void ClientModel::setupState(QVariantMap _state) { if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later contractId = m_codeModel->contracts().keys()[0]; - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString())); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCall); transactionSettings.parameterValues = transaction.value("parameters").toMap(); if (contractId == functionId || functionId == "Constructor") @@ -301,6 +304,13 @@ void ClientModel::executeSequence(vector const& _sequence, onStateReset(); for (TransactionSettings const& transaction: _sequence) { + if (!transaction.isContractCall) + { + QString address = resolveToken(transaction.contractId, deployedContracts); + callAddress(Address(address.toStdString()), bytes(), transaction); + onNewTransaction(); + continue; + } ContractCallDataEncoder encoder; if (!transaction.stdContractUrl.isEmpty()) { @@ -342,11 +352,8 @@ void ClientModel::executeSequence(vector const& _sequence, { QSolidityType const* type = p->type(); QVariant value = transaction.parameterValues.value(p->name()); - if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<") && value.toString().endsWith(">")) - { - QStringList nb = value.toString().remove("<").remove(">").split(" - "); - value = QVariant(QString::fromStdString("0x" + toHex(deployedContracts.at(nb.back().toInt()).ref()))); - } + if (type->type().type == SolidityType::Type::Address) + value = QVariant(resolveToken(value.toString(), deployedContracts)); encoder.encode(value, type->type()); } @@ -376,7 +383,7 @@ void ClientModel::executeSequence(vector const& _sequence, emit runStateChanged(); return; } - callContract(contractAddressIter->second, encoder.encodedData(), transaction); + callAddress(contractAddressIter->second, encoder.encodedData(), transaction); } } onNewTransaction(); @@ -399,6 +406,17 @@ void ClientModel::executeSequence(vector const& _sequence, }); } +QString ClientModel::resolveToken(QString const& _value, vector
const& _contracts) +{ + QString ret = _value; + if (_value.startsWith("<") && _value.endsWith(">")) + { + QStringList nb = ret.remove("<").remove(">").split(" - "); + ret = QString::fromStdString("0x" + toHex(_contracts.at(nb.back().toInt()).ref())); + } + return ret; +} + void ClientModel::showDebugger() { ExecutionResult last = m_client->lastExecution(); @@ -603,7 +621,7 @@ Address ClientModel::deployContract(bytes const& _code, TransactionSettings cons return newAddress; } -void ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) +void ClientModel::callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) { m_client->submitTransaction(_tr.sender, _tr.value, _contract, _data, _tr.gas, _tr.gasPrice, _tr.gasAuto); } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 9b0529ae6..db11406d6 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -53,10 +53,10 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender): - contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender) {} + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, int _isContractCall): + contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCall(_isContractCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): - contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl) {} + contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCall(true) {} /// Contract name QString contractId; @@ -76,6 +76,8 @@ struct TransactionSettings QString stdContractUrl; /// Sender Secret sender; + /// Is a call to a contract + bool isContractCall; }; @@ -220,12 +222,13 @@ private: QVariantMap gasCosts() const; void executeSequence(std::vector const& _sequence, std::map const& _accounts, Secret const& _miner); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); - void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); + void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void onNewTransaction(); void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); QVariant formatStorageValue(SolidityType const& _type, std::map const& _storage, unsigned _offset, dev::u256 const& _slot); + QString resolveToken(QString const& _value, std::vector
const& _contracts); std::atomic m_running; std::atomic m_mining; diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index 204e92508..19d98b166 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -8,6 +8,10 @@ Item property alias accountRef: ctrModel property string subType property bool readOnly + property alias currentIndex: trCombobox.currentIndex + property alias currentText: textinput.text + property variant accounts + signal indexChanged() id: editRoot height: 20 width: 320 @@ -17,6 +21,46 @@ Item id: boldFont } + function currentValue() { + return currentText; + } + + function currentType() + { + return accountRef.get(trCombobox.currentIndex).type; + } + + function load() + { + accountRef.clear(); + accountRef.append({"itemid": " - "}); + + if (subType === "contract" || subType === "address") + { + var trCr = 0; + for (var k = 0; k < transactionsModel.count; k++) + { + if (k >= transactionIndex) + break; + var tr = transactionsModel.get(k); + if (tr.functionId === tr.contractId /*&& (dec[1] === tr.contractId || item.subType === "address")*/) + { + accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); + trCr++; + } + } + } + if (subType === "address") + { + for (k = 0; k < accounts.length; k++) + { + if (accounts[k].address === undefined) + accounts[k].address = clientModel.address(accounts[k].secret); + accountRef.append({ "itemid": accounts[k].name, "value": "0x" + accounts[k].address, "type": "address" }); + } + } + } + function init() { trCombobox.visible = !readOnly @@ -35,6 +79,18 @@ Item } } + function select(address) + { + for (var k = 0; k < accountRef.count; k++) + { + if (accountRef.get(k).value === address) + { + trCombobox.currentIndex = k; + break; + } + } + } + Rectangle { anchors.fill: parent radius: 4 @@ -96,6 +152,7 @@ Item { textinput.text = ""; } + indexChanged(); } } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index 889a2d940..d4aa678a6 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -46,6 +46,7 @@ Item { t.sender = defaultAccount; //support for old project var r = { + type: t.type, contractId: t.contractId, functionId: t.functionId, url: t.url, @@ -55,7 +56,8 @@ Item { gasAuto: t.gasAuto, stdContract: t.stdContract ? true : false, parameters: {}, - sender: t.sender + sender: t.sender, + isContractCall: t.isContractCall }; for (var key in t.parameters) r.parameters[key] = t.parameters[key]; @@ -100,6 +102,7 @@ Item { function toPlainTransactionItem(t) { var r = { + type: t.type, contractId: t.contractId, functionId: t.functionId, url: t.url, @@ -109,7 +112,8 @@ Item { gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit }, stdContract: t.stdContract, sender: t.sender, - parameters: {} + parameters: {}, + isContractCall: t.isContractCall }; for (var key in t.parameters) r.parameters[key] = t.parameters[key]; diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 4df9ace67..4feab2166 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -75,38 +75,13 @@ Column item.readOnly = context === "variable"; if (ptype.category === QSolidityType.Address) { + item.accounts = accounts item.value = getValue(); if (context === "parameter") { var dec = modelData.type.name.split(" "); item.subType = dec[0]; - item.accountRef.append({"itemid": " - "}); - - if (item.subType === "contract" || item.subType === "address") - { - var trCr = 0; - for (var k = 0; k < transactionsModel.count; k++) - { - if (k >= transactionIndex) - break; - var tr = transactionsModel.get(k); - if (tr.functionId === tr.contractId && (dec[1] === tr.contractId || item.subType === "address")) - { - item.accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); - trCr++; - } - } - } - if (item.subType === "address") - { - for (k = 0; k < accounts.length; k++) - { - if (accounts[k].address === undefined) - accounts[k].address = clientModel.address(accounts[k].secret); - item.accountRef.append({ "itemid": accounts[k].name, "value": "0x" + accounts[k].address, "type": "address" }); - } - - } + item.load(); } item.init(); } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 66a98d19e..f56093336 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -82,6 +82,14 @@ Dialog { } initTypeLoader(); + trType.checked = item.isContractCall + trType.init(); + + recipients.accounts = senderComboBox.model; + recipients.subType = "address"; + recipients.load(); + recipients.init(); + recipients.select(contractId); visible = true; valueField.focus = true; } @@ -193,6 +201,13 @@ Dialog { item.functionId = transactionDialog.functionId; } + item.isContractCall = trType.checked; + if (!item.isContractCall) + { + item.functionId = recipients.currentText; + item.contractId = recipients.currentText; + } + item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.parameters = paramValues; return item; @@ -238,6 +253,46 @@ Dialog { } } + RowLayout + { + id: rowIsContract + Layout.fillWidth: true + height: 150 + CheckBox { + id: trType + onCheckedChanged: + { + init(); + } + + function init() + { + rowFunction.visible = checked; + rowContract.visible = checked; + rowRecipient.visible = !checked; + } + + text: qsTr("is contract call") + checked: true + } + } + + RowLayout + { + id: rowRecipient + Layout.fillWidth: true + height: 150 + DefaultLabel { + Layout.preferredWidth: 75 + text: qsTr("Recipient") + } + + QAddressView + { + id: recipients + } + } + RowLayout { id: rowContract diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index be057917c..57b03757a 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -9,7 +9,8 @@ function defaultTransaction() gasAuto: true, gasPrice: createEther("100000", QEther.Wei), parameters: {}, - stdContract: false + stdContract: false, + isContractCall: true }; } From 446abc57e55b3d6ba70875a06fd09b7964ecc7fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 8 May 2015 11:00:17 +0200 Subject: [PATCH 02/24] testeth: fix --singletest option --- test/TestHelper.cpp | 89 +++++++++++++++----------------- test/TestHelper.h | 3 +- test/libethereum/blockchain.cpp | 2 +- test/libethereum/state.cpp | 2 +- test/libethereum/transaction.cpp | 2 +- test/libevm/vm.cpp | 2 +- 6 files changed, 47 insertions(+), 53 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 144a1a286..e0aad310f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -549,58 +549,50 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e } } -void userDefinedTest(string testTypeFlag, std::function doTests) +void userDefinedTest(std::function doTests) { - Options::get(); // parse command line options, e.g. to enable JIT + if (!Options::get().singleTest) + { + cnote << "Missing user test specification\nUsage: testeth --singletest \n"; + return; + } - for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) + auto& filename = Options::get().singleTestFile; + auto& testname = Options::get().singleTestName; + int currentVerbosity = g_logVerbosity; + g_logVerbosity = 12; + try { - string arg = boost::unit_test::framework::master_test_suite().argv[i]; - if (arg == testTypeFlag) - { - if (boost::unit_test::framework::master_test_suite().argc <= i + 2) - { - cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " \n"; - return; - } - string filename = boost::unit_test::framework::master_test_suite().argv[i + 1]; - string testname = boost::unit_test::framework::master_test_suite().argv[i + 2]; - int currentVerbosity = g_logVerbosity; - g_logVerbosity = 12; - try - { - cnote << "Testing user defined test: " << filename; - json_spirit::mValue v; - string s = asString(contents(filename)); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); - json_spirit::read_string(s, v); - json_spirit::mObject oSingleTest; - - json_spirit::mObject::const_iterator pos = v.get_obj().find(testname); - if (pos == v.get_obj().end()) - { - cnote << "Could not find test: " << testname << " in " << filename << "\n"; - return; - } - else - oSingleTest[pos->first] = pos->second; + cnote << "Testing user defined test: " << filename; + json_spirit::mValue v; + string s = asString(contents(filename)); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); + json_spirit::read_string(s, v); + json_spirit::mObject oSingleTest; - json_spirit::mValue v_singleTest(oSingleTest); - doTests(v_singleTest, false); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e)); - g_logVerbosity = currentVerbosity; - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed Test with Exception: " << _e.what()); - g_logVerbosity = currentVerbosity; - } - g_logVerbosity = currentVerbosity; + json_spirit::mObject::const_iterator pos = v.get_obj().find(testname); + if (pos == v.get_obj().end()) + { + cnote << "Could not find test: " << testname << " in " << filename << "\n"; + return; } + else + oSingleTest[pos->first] = pos->second; + + json_spirit::mValue v_singleTest(oSingleTest); + doTests(v_singleTest, false); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e)); + g_logVerbosity = currentVerbosity; + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed Test with Exception: " << _e.what()); + g_logVerbosity = currentVerbosity; } + g_logVerbosity = currentVerbosity; } void executeTests(const string& _name, const string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function doTests) @@ -740,10 +732,11 @@ Options::Options() inputLimits = true; bigData = true; } - else if (arg == "--singletest" && i + 1 < argc) + else if (arg == "--singletest" && i + 2 < argc) { singleTest = true; - singleTestName = argv[i + 1]; + singleTestFile = argv[i + 1]; + singleTestName = argv[i + 2]; } } } diff --git a/test/TestHelper.h b/test/TestHelper.h index 02f509e4c..631bc4df2 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -157,7 +157,7 @@ void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates); void executeTests(const std::string& _name, const std::string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function doTests); -void userDefinedTest(std::string testTypeFlag, std::function doTests); +void userDefinedTest(std::function doTests); RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj); eth::LastHashes lastHashes(u256 _currentBlockNumber); json_spirit::mObject fillJsonWithState(eth::State _state); @@ -189,6 +189,7 @@ public: /// Test selection /// @{ bool singleTest = false; + std::string singleTestFile; std::string singleTestName; bool performance = false; bool quadratic = false; diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 954e65c8a..9eddb4657 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -711,7 +711,7 @@ BOOST_AUTO_TEST_CASE(bcWalletTest) BOOST_AUTO_TEST_CASE(userDefinedFile) { - dev::test::userDefinedTest("--singletest", dev::test::doBlockchainTests); + dev::test::userDefinedTest(dev::test::doBlockchainTests); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 93f7498b8..b7b45f93a 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(stRandom) BOOST_AUTO_TEST_CASE(userDefinedFileState) { - dev::test::userDefinedTest("--singletest", dev::test::doStateTests); + dev::test::userDefinedTest(dev::test::doStateTests); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/transaction.cpp b/test/libethereum/transaction.cpp index 058d03322..017e51ded 100644 --- a/test/libethereum/transaction.cpp +++ b/test/libethereum/transaction.cpp @@ -195,7 +195,7 @@ BOOST_AUTO_TEST_CASE(ttCreateTest) BOOST_AUTO_TEST_CASE(userDefinedFile) { - dev::test::userDefinedTest("--singletest", dev::test::doTransactionTests); + dev::test::userDefinedTest(dev::test::doTransactionTests); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 8b5a7c5d3..2d67d7670 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -548,7 +548,7 @@ BOOST_AUTO_TEST_CASE(vmRandom) BOOST_AUTO_TEST_CASE(userDefinedFile) { - dev::test::userDefinedTest("--singletest", dev::test::doVMTests); + dev::test::userDefinedTest(dev::test::doVMTests); } BOOST_AUTO_TEST_SUITE_END() From 5fe68b07c1236c64f58fa7b42bcfb6cc6506e957 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 8 May 2015 14:14:27 +0200 Subject: [PATCH 03/24] small changes --- mix/ClientModel.cpp | 2 +- mix/qml/StateListModel.qml | 2 ++ mix/qml/TransactionDialog.qml | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index d802d9a7b..95d4d497b 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -418,7 +418,7 @@ QString ClientModel::resolveToken(QString const& _value, vector
const& if (_value.startsWith("<") && _value.endsWith(">")) { QStringList nb = ret.remove("<").remove(">").split(" - "); - ret = QString::fromStdString("0x" + toHex(_contracts.at(nb.back().toInt()).ref())); + ret = QString::fromStdString("0x" + dev::toHex(_contracts.at(nb.back().toInt()).ref())); } return ret; } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d4aa678a6..3eac14a11 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -59,6 +59,8 @@ Item { sender: t.sender, isContractCall: t.isContractCall }; + if (r.isContractCall === undefined) + r.isContractCall = true; //support for old project for (var key in t.parameters) r.parameters[key] = t.parameters[key]; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index f56093336..84abb854b 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -270,6 +270,8 @@ Dialog { rowFunction.visible = checked; rowContract.visible = checked; rowRecipient.visible = !checked; + paramLabel.visible = checked; + paramScroll.visible = checked; } text: qsTr("is contract call") From 7802a9e00cca9070a7d20f8157611cfed26c2ecb Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 8 May 2015 17:27:15 +0200 Subject: [PATCH 04/24] bug fix --- mix/ClientModel.cpp | 36 ++++++++----- mix/ClientModel.h | 11 ++-- mix/qml/QAddressView.qml | 5 ++ mix/qml/StateDialog.qml | 4 +- mix/qml/StateListModel.qml | 14 +++-- mix/qml/TransactionDialog.qml | 92 +++++++++++++++++++++++---------- mix/qml/js/TransactionHelper.js | 3 +- 7 files changed, 112 insertions(+), 53 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 95d4d497b..a58366046 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -256,9 +256,9 @@ void ClientModel::setupState(QVariantMap _state) u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); QString sender = transaction.value("sender").toString(); bool isStdContract = transaction.value("stdContract").toBool(); - bool isContractCall; - if (!transaction.value("isContractCall").isNull()) - isContractCall = transaction.value("isContractCall").toBool(); + bool isContractCreation; + if (!transaction.value("isContractCreation").isNull()) + isContractCreation = transaction.value("isContractCreation").toBool(); if (isStdContract) { if (contractId.isEmpty()) //TODO: This is to support old project files, remove later @@ -274,7 +274,7 @@ void ClientModel::setupState(QVariantMap _state) { if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later contractId = m_codeModel->contracts().keys()[0]; - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCall); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation); transactionSettings.parameterValues = transaction.value("parameters").toMap(); if (contractId == functionId || functionId == "Constructor") @@ -310,9 +310,10 @@ void ClientModel::executeSequence(vector const& _sequence, m_gasCosts.clear(); for (TransactionSettings const& transaction: _sequence) { - if (!transaction.isContractCall) + QString contractName = resolveContractName(transaction.contractId); + QString address = resolveToken(transaction.contractId, deployedContracts); + if (transaction.functionId == "(transfert)") { - QString address = resolveToken(transaction.contractId, deployedContracts); callAddress(Address(address.toStdString()), bytes(), transaction); onNewTransaction(); continue; @@ -332,7 +333,7 @@ void ClientModel::executeSequence(vector const& _sequence, else { //encode data - CompiledContract const& compilerRes = m_codeModel->contract(transaction.contractId); + CompiledContract const& compilerRes = m_codeModel->contract(contractName); QFunctionDefinition const* f = nullptr; bytes contractCode = compilerRes.bytes(); shared_ptr contractDef = compilerRes.sharedContract(); @@ -363,7 +364,7 @@ void ClientModel::executeSequence(vector const& _sequence, encoder.encode(value, type->type()); } - if (transaction.functionId.isEmpty() || transaction.functionId == transaction.contractId) + if (transaction.functionId.isEmpty() || transaction.functionId == contractName) { bytes param = encoder.encodedData(); contractCode.insert(contractCode.end(), param.begin(), param.end()); @@ -372,8 +373,9 @@ void ClientModel::executeSequence(vector const& _sequence, auto contractAddressIter = m_contractAddresses.find(transaction.contractId); if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second) { - m_contractAddresses[transaction.contractId] = newAddress; - m_contractNames[newAddress] = transaction.contractId; + QString contractToken = "<" + transaction.contractId + " - " + QString::number(deployedContracts.size() - 1) + ">"; + m_contractAddresses[contractToken] = newAddress; + m_contractNames[newAddress] = contractToken; contractAddressesChanged(); } gasCostsChanged(); @@ -388,7 +390,7 @@ void ClientModel::executeSequence(vector const& _sequence, emit runStateChanged(); return; } - callAddress(contractAddressIter->second, encoder.encodedData(), transaction); + callAddress(Address(address.toStdString()), encoder.encodedData(), transaction); } m_gasCosts.append(m_client->lastExecution().gasUsed); } @@ -423,6 +425,14 @@ QString ClientModel::resolveToken(QString const& _value, vector
const& return ret; } +QString ClientModel::resolveContractName(QString const& _value) +{ + QString ret = _value; + if (_value.startsWith("<") && _value.endsWith(">")) + ret = ret.remove("<").remove(">").split(" - ").first(); + return ret; +} + void ClientModel::showDebugger() { ExecutionResult last = m_client->lastExecution(); @@ -446,7 +456,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) //try to resolve contract for source level debugging auto nameIter = m_contractNames.find(code.address); CompiledContract const* compilerRes = nullptr; - if (nameIter != m_contractNames.end() && (compilerRes = m_codeModel->tryGetContract(nameIter->second))) //returned object is guaranteed to live till the end of event handler in main thread + if (nameIter != m_contractNames.end() && (compilerRes = m_codeModel->tryGetContract(resolveContractName(nameIter->second)))) //returned object is guaranteed to live till the end of event handler in main thread { eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes->assemblyItems() : compilerRes->constructorAssemblyItems(); codes.back()->setDocument(compilerRes->documentId()); @@ -707,7 +717,7 @@ void ClientModel::onNewTransaction() auto contractAddressIter = m_contractNames.find(contractAddress); if (contractAddressIter != m_contractNames.end()) { - CompiledContract const& compilerRes = m_codeModel->contract(contractAddressIter->second); + CompiledContract const& compilerRes = m_codeModel->contract(resolveContractName(contractAddressIter->second)); const QContractDefinition* def = compilerRes.contract(); contract = def->name(); if (abi) diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 46cabe450..15cdc7086 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -53,10 +53,10 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, int _isContractCall): - contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCall(_isContractCall) {} + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, int _isContractCreation): + contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): - contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCall(true) {} + contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true) {} /// Contract name QString contractId; @@ -76,8 +76,8 @@ struct TransactionSettings QString stdContractUrl; /// Sender Secret sender; - /// Is a call to a contract - bool isContractCall; + /// Tr deploys a contract + bool isContractCreation; }; @@ -231,6 +231,7 @@ private: QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); QVariant formatStorageValue(SolidityType const& _type, std::map const& _storage, unsigned _offset, dev::u256 const& _slot); QString resolveToken(QString const& _value, std::vector
const& _contracts); + QString resolveContractName(QString const& _value); std::atomic m_running; std::atomic m_mining; diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index 19d98b166..c880f0904 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -30,6 +30,11 @@ Item return accountRef.get(trCombobox.currentIndex).type; } + function current() + { + return accountRef.get(trCombobox.currentIndex); + } + function load() { accountRef.clear(); diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 13d01d474..f8da6dabd 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -436,7 +436,7 @@ Dialog { model: transactionsModel headerVisible: false TableViewColumn { - role: "name" + role: "label" title: qsTr("Name") width: 150 delegate: Item { @@ -476,7 +476,7 @@ Dialog { text: { if (styleData.row >= 0) return transactionsModel.get( - styleData.row).functionId + styleData.row).label else return "" } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index 3eac14a11..a6069d620 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -57,10 +57,15 @@ Item { stdContract: t.stdContract ? true : false, parameters: {}, sender: t.sender, - isContractCall: t.isContractCall + isContractCreation: t.isContractCreation, + label: t.label }; - if (r.isContractCall === undefined) - r.isContractCall = true; //support for old project + + if (!r.label) + r.label = r.contractId + " " + r.functionId; + + if (r.isContractCreation === undefined) + r.isContractCreation = true; //support for old project for (var key in t.parameters) r.parameters[key] = t.parameters[key]; @@ -115,7 +120,8 @@ Item { stdContract: t.stdContract, sender: t.sender, parameters: {}, - isContractCall: t.isContractCall + isContractCreation: t.isContractCreation, + label: t.label }; for (var key in t.parameters) r.parameters[key] = t.parameters[key]; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 84abb854b..d26fbaf5a 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -66,34 +66,46 @@ Dialog { contractIndex = 0; //@todo suggest unused contract contractComboBox.currentIndex = contractIndex; - loadFunctions(contractComboBox.currentValue()); + recipients.accounts = senderComboBox.model; + recipients.subType = "address"; + recipients.load(); + recipients.init(); + recipients.select(contractId); + + if (item.isContractCreation) + loadFunctions(contractComboBox.currentValue()); + else + loadFunctions(contractFromToken(recipients.currentValue())) selectFunction(functionId); + trType.checked = item.isContractCreation + trType.init(); + paramsModel = []; - if (functionId !== contractComboBox.currentValue()) + if (item.isContractCreation) + loadCtorParameters(); + else loadParameters(); - else { - var contract = codeModel.contracts[contractId]; - if (contract) { - var params = contract.contract.constructor.parameters; - for (var p = 0; p < params.length; p++) - loadParameter(params[p]); - } - } - initTypeLoader(); - trType.checked = item.isContractCall - trType.init(); - recipients.accounts = senderComboBox.model; - recipients.subType = "address"; - recipients.load(); - recipients.init(); - recipients.select(contractId); + visible = true; valueField.focus = true; } + function loadCtorParameters(contractId) + { + paramsModel = []; + console.log(contractId); + var contract = codeModel.contracts[contractId]; + if (contract) { + var params = contract.contract.constructor.parameters; + for (var p = 0; p < params.length; p++) + loadParameter(params[p]); + } + initTypeLoader(); + } + function loadFunctions(contractId) { functionsModel.clear(); @@ -104,9 +116,7 @@ Dialog { functionsModel.append({ text: functions[f].name }); } } - //append constructor - functionsModel.append({ text: contractId }); - + functionsModel.append({ text: "(transfert)" }); } function selectContract(contractName) @@ -144,7 +154,7 @@ Dialog { function loadParameters() { paramsModel = [] if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var contract = codeModel.contracts[contractComboBox.currentValue()]; + var contract = codeModel.contracts[contractFromToken(recipients.currentValue())]; if (contract) { var func = contract.contract.functions[functionComboBox.currentIndex]; if (func) { @@ -201,17 +211,32 @@ Dialog { item.functionId = transactionDialog.functionId; } - item.isContractCall = trType.checked; - if (!item.isContractCall) + item.isContractCreation = trType.checked; + if (!item.isContractCreation) { - item.functionId = recipients.currentText; item.contractId = recipients.currentText; + item.label = item.contractId + " " + item.functionId; + if (recipients.current().type === "address") + item.functionId = "(transfert)"; + } + else + { + item.functionId = item.contractId; + item.label = qsTr("Deploy") + " " + item.contractId; } item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.parameters = paramValues; return item; } + + function contractFromToken(token) + { + if (token.indexOf('<') === 0) + return token.replace("<", "").replace(">", "").split(" - ")[0]; + return token; + } + contentItem: Rectangle { color: transactionDialogStyle.generic.backgroundColor ColumnLayout { @@ -267,14 +292,17 @@ Dialog { function init() { - rowFunction.visible = checked; + rowFunction.visible = !checked; rowContract.visible = checked; rowRecipient.visible = !checked; paramLabel.visible = checked; paramScroll.visible = checked; + functionComboBox.enabled = !checked; + if (checked) + loadCtorParameters(contractComboBox.currentValue()); } - text: qsTr("is contract call") + text: qsTr("is contract creation") checked: true } } @@ -292,6 +320,14 @@ Dialog { QAddressView { id: recipients + onIndexChanged: + { + rowFunction.visible = current().type === "contract"; + paramLabel.visible = current().type === "contract"; + paramScroll.visible = current().type === "contract"; + if (!rowIsContract.checked) + loadFunctions(contractFromToken(recipients.currentValue())) + } } } @@ -317,7 +353,7 @@ Dialog { id: contractsModel } onCurrentIndexChanged: { - loadFunctions(currentValue()); + loadCtorParameters(currentValue()); } } } diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index 01fe65b5d..33072fdba 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -10,7 +10,8 @@ function defaultTransaction() gasPrice: createEther("100000", QEther.Wei), parameters: {}, stdContract: false, - isContractCall: true + isContractCreation: true, + label: "" }; } From 0e7d6d77e5be791b2479440b9b6b427a6d978f28 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 8 May 2015 17:36:29 +0200 Subject: [PATCH 05/24] small changes --- mix/qml/StateListModel.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index a6069d620..a7b83aec9 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -62,10 +62,8 @@ Item { }; if (!r.label) - r.label = r.contractId + " " + r.functionId; + r.label = r.contractId + " - " + r.functionId; - if (r.isContractCreation === undefined) - r.isContractCreation = true; //support for old project for (var key in t.parameters) r.parameters[key] = t.parameters[key]; From 3fc50e3615348b86e97725afe63a61ebb712da41 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 8 May 2015 18:12:49 +0200 Subject: [PATCH 06/24] bux fix --- mix/ClientModel.cpp | 12 ++++++++++-- mix/ClientModel.h | 1 + mix/qml/StateListModel.qml | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index a58366046..8067f62c4 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -373,7 +373,7 @@ void ClientModel::executeSequence(vector const& _sequence, auto contractAddressIter = m_contractAddresses.find(transaction.contractId); if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second) { - QString contractToken = "<" + transaction.contractId + " - " + QString::number(deployedContracts.size() - 1) + ">"; + QString contractToken = retrieveToken(transaction.contractId, deployedContracts); m_contractAddresses[contractToken] = newAddress; m_contractNames[newAddress] = contractToken; contractAddressesChanged(); @@ -382,7 +382,7 @@ void ClientModel::executeSequence(vector const& _sequence, } else { - auto contractAddressIter = m_contractAddresses.find(transaction.contractId); + auto contractAddressIter = m_contractAddresses.find(retrieveToken(transaction.contractId, deployedContracts)); if (contractAddressIter == m_contractAddresses.end()) { emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); @@ -425,6 +425,14 @@ QString ClientModel::resolveToken(QString const& _value, vector
const& return ret; } +QString ClientModel::retrieveToken(QString const& _value, vector
const& _contracts) +{ + QString ret = _value; + if (!_value.startsWith("<") && !_value.endsWith(">")) + return "<" + _value + " - " + QString::number(_contracts.size() - 1) + ">"; + return ret; +} + QString ClientModel::resolveContractName(QString const& _value) { QString ret = _value; diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 15cdc7086..2ba37f593 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -232,6 +232,7 @@ private: QVariant formatStorageValue(SolidityType const& _type, std::map const& _storage, unsigned _offset, dev::u256 const& _slot); QString resolveToken(QString const& _value, std::vector
const& _contracts); QString resolveContractName(QString const& _value); + QString retrieveToken(QString const& _value, std::vector
const& _contracts); std::atomic m_running; std::atomic m_mining; diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index a7b83aec9..b4eed525d 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -64,6 +64,9 @@ Item { if (!r.label) r.label = r.contractId + " - " + r.functionId; + if (r.isContractCreation === undefined) + r.isContractCreation = r.functionId === r.contractId; + for (var key in t.parameters) r.parameters[key] = t.parameters[key]; From dc7df3cc0713561526bf547eb8dfaa8dda42d0da Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Sun, 10 May 2015 15:18:13 +0200 Subject: [PATCH 07/24] Test for Capability class Basic configuration for sending and receiving messgaes. --- test/libp2p/capability.cpp | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 test/libp2p/capability.cpp diff --git a/test/libp2p/capability.cpp b/test/libp2p/capability.cpp new file mode 100644 index 000000000..2dcf9b4ba --- /dev/null +++ b/test/libp2p/capability.cpp @@ -0,0 +1,157 @@ +/* +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 capability.cpp +* @author Vladislav Gluhovsky +* @date May 2015 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::p2p; + +struct P2PFixture +{ + P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; } + ~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; } +}; + +struct VerbosityHolder +{ + int m_oldLogVerbosity; + VerbosityHolder() : m_oldLogVerbosity(g_logVerbosity) { g_logVerbosity = 10; } + ~VerbosityHolder() { g_logVerbosity = m_oldLogVerbosity; } +}; + +class TestCapability : public Capability +{ + int m_cntReceivedMessages; + int m_testSum; + +public: + TestCapability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset) : Capability(_s, _h, _idOffset), m_cntReceivedMessages(0), m_testSum(0) {} + virtual ~TestCapability() {} + int countReceivedMessages() { return m_cntReceivedMessages; } + int testSum() { return m_testSum; } + static std::string name() { return "test"; } + static u256 version() { return 2; } + static unsigned messageCount() { return UserPacket + 1; } + + void sendTestMessage(int _i) + { + RLPStream s; + prep(s, UserPacket, 1); + s << _i; + sealAndSend(s); + } + +protected: + virtual bool interpret(unsigned _id, RLP const& _r) override + { + cnote << "Capability::interpret(): custom message received"; + BOOST_REQUIRE_EQUAL(_id, UserPacket); + ++m_cntReceivedMessages; + int i = _r[0].toInt(); + m_testSum += i; + return true; + } +}; + +class TestHostCapability : public HostCapability, public Worker +{ +public: + TestHostCapability() : Worker("test") {} + virtual ~TestHostCapability() {} + + void sendTestMessage(NodeId const& _id, int _x) + { + for (auto i: peerSessions()) + if (_id == i.second->id) + i.first->cap().get()->sendTestMessage(_x); + } + + std::pair retrieveTestData(NodeId const& _id) + { + int cnt = 0; + int checksum = 0; + for (auto i : peerSessions()) + if (_id == i.second->id) + { + cnt += i.first->cap().get()->countReceivedMessages(); + checksum += i.first->cap().get()->testSum(); + } + + return std::pair(cnt, checksum); + } +}; + +BOOST_FIXTURE_TEST_SUITE(p2pCapability, P2PFixture) + +BOOST_AUTO_TEST_CASE(capability) +{ + VerbosityHolder verbosityHolder; + cnote << "Testing Capability..."; + + const char* const localhost = "127.0.0.1"; + NetworkPreferences prefs1(localhost, 30301, false); + NetworkPreferences prefs2(localhost, 30302, false); + + Host host1("Test", prefs1); + auto thc1 = host1.registerCapability(new TestHostCapability()); + host1.start(); + + Host host2("Test", prefs2); + auto thc2 = host2.registerCapability(new TestHostCapability()); + host2.start(); + + int const step = 10; + + for (int i = 0; i < 3000; i += step) + if (!host1.isStarted() || !host2.isStarted()) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE(host1.isStarted() && host2.isStarted()); + host1.requirePeer(host2.id(), NodeIPEndpoint(bi::address::from_string(localhost), prefs2.listenPort, prefs2.listenPort)); + + for (int i = 0; i < 3000; i += step) + if (!host1.peerCount() || !host2.peerCount()) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE(host1.peerCount() > 0 && host2.peerCount() > 0); + + int const target = 7; + int checksum = 0; + for (int i = 0; i < target; checksum += i++) + thc2->sendTestMessage(host1.id(), i); + + this_thread::sleep_for(chrono::seconds(1)); + std::pair testData = thc1->retrieveTestData(host2.id()); + BOOST_REQUIRE_EQUAL(target, testData.first); + BOOST_REQUIRE_EQUAL(checksum, testData.second); +} + +BOOST_AUTO_TEST_SUITE_END() + + From 438d2b44edd22348a0233c49884a45239454f4bd Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 11 May 2015 09:56:17 +0200 Subject: [PATCH 08/24] small changes --- mix/ClientModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 8067f62c4..519b7ddf3 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -390,7 +390,7 @@ void ClientModel::executeSequence(vector const& _sequence, emit runStateChanged(); return; } - callAddress(Address(address.toStdString()), encoder.encodedData(), transaction); + callAddress(contractAddressIter->second, encoder.encodedData(), transaction); } m_gasCosts.append(m_client->lastExecution().gasUsed); } From 33d7e42866566d9fe225a4ab67eae05f7f52df5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 11 May 2015 11:38:11 +0200 Subject: [PATCH 09/24] CMake: set default RUNTIME_OUTPUT_DIRECTORY property to "bin" This commit changes output directory for runtime components (executables and DLLs) to "bin" directory. That allows running executables on Windows without need of install step. Closes ethereum/cpp-ethereum#1821 --- CMakeLists.txt | 1 + cmake/EthExecutableHelper.cmake | 33 +++++++++++++++++---------------- cmake/scripts/copydlls.cmake | 3 +-- libevmasm/CMakeLists.txt | 7 +------ 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ba214cce..4e7003692 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -295,6 +295,7 @@ message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}" message("------------------------------------------------------------------------") message("") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") set(CMAKE_THREAD_LIBS_INIT pthread) include(EthCompilerSettings) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 1d1cb887b..d971a5f92 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -45,25 +45,26 @@ endmacro() macro(eth_copy_dlls EXECUTABLE DLLS) # dlls must be unsubstitud list variable (without ${}) in format - # optimized;path_to_dll.dll;debug;path_to_dlld.dll + # optimized;path_to_dll.dll;debug;path_to_dlld.dll list(GET ${DLLS} 1 DLL_RELEASE) list(GET ${DLLS} 3 DLL_DEBUG) + get_target_property(TARGET_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE} RUNTIME_OUTPUT_DIRECTORY) add_custom_command(TARGET ${EXECUTABLE} - POST_BUILD - COMMAND ${CMAKE_COMMAND} ARGS - -DDLL_RELEASE="${DLL_RELEASE}" - -DDLL_DEBUG="${DLL_DEBUG}" + POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS + -DDLL_RELEASE="${DLL_RELEASE}" + -DDLL_DEBUG="${DLL_DEBUG}" -DCONF="$" - -DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" + -DDESTINATION="${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}" -P "${ETH_SCRIPTS_DIR}/copydlls.cmake" ) endmacro() -# +# # this function requires the following variables to be specified: # ETH_DEPENDENCY_INSTALL_DIR # -# params: +# params: # QMLDIR # @@ -74,7 +75,7 @@ macro(eth_install_executable EXECUTABLE) set (one_value_args QMLDIR) set (multi_value_args DLLS) cmake_parse_arguments (ETH_INSTALL_EXECUTABLE "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}") - + if (ETH_INSTALL_EXECUTABLE_QMLDIR) if (APPLE) set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}") @@ -91,13 +92,14 @@ macro(eth_install_executable EXECUTABLE) WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} COMMAND sh ${CMAKE_SOURCE_DIR}/macdeployfix.sh ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app/Contents ) - + + get_target_property(TARGET_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE} RUNTIME_OUTPUT_DIRECTORY) # This tool and next will inspect linked libraries in order to determine which dependencies are required if (${CMAKE_CFG_INTDIR} STREQUAL ".") # TODO: This should only happen for GUI application - set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTABLE}.app") + set(APP_BUNDLE_PATH "${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${EXECUTABLE}.app") else () - set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app") + set(APP_BUNDLE_PATH "${TARGET_RUNTIME_OUTPUT_DIRECTORY}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app") endif () install(CODE " @@ -111,14 +113,15 @@ macro(eth_install_executable EXECUTABLE) get_target_property(TARGET_LIBS ${EXECUTABLE} INTERFACE_LINK_LIBRARIES) string(REGEX MATCH "Qt5::Core" HAVE_QT ${TARGET_LIBS}) if ("${HAVE_QT}" STREQUAL "Qt5::Core") + get_target_property(TARGET_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE} RUNTIME_OUTPUT_DIRECTORY) add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) #workaround for https://bugreports.qt.io/browse/QTBUG-42083 add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM + WORKING_DIRECTORY ${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR} VERBATIM ) endif() @@ -144,5 +147,3 @@ macro(eth_install_executable EXECUTABLE) endif () endmacro() - - diff --git a/cmake/scripts/copydlls.cmake b/cmake/scripts/copydlls.cmake index 6d86b8e4e..57eb0ffd4 100644 --- a/cmake/scripts/copydlls.cmake +++ b/cmake/scripts/copydlls.cmake @@ -14,5 +14,4 @@ else () # Debug set(DLL ${DLL_DEBUG}) endif() -execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${DLL}" "${DESTINATION}") - +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DLL}" "${DESTINATION}") diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt index f8150806f..eb8fea95c 100644 --- a/libevmasm/CMakeLists.txt +++ b/libevmasm/CMakeLists.txt @@ -19,15 +19,10 @@ set(EXECUTABLE evmasm) file(GLOB HEADERS "*.h") -if (ETH_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) -else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) -endif() +add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcrypto) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) - From faee123b4a0e337fc275b828637f51c02e63e0b9 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 11 May 2015 12:39:37 +0200 Subject: [PATCH 10/24] Coding Standards fix --- test/libp2p/capability.cpp | 50 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/test/libp2p/capability.cpp b/test/libp2p/capability.cpp index 2dcf9b4ba..2f1509e80 100644 --- a/test/libp2p/capability.cpp +++ b/test/libp2p/capability.cpp @@ -40,49 +40,43 @@ struct P2PFixture struct VerbosityHolder { - int m_oldLogVerbosity; - VerbosityHolder() : m_oldLogVerbosity(g_logVerbosity) { g_logVerbosity = 10; } - ~VerbosityHolder() { g_logVerbosity = m_oldLogVerbosity; } + int oldLogVerbosity; + VerbosityHolder(): oldLogVerbosity(g_logVerbosity) { g_logVerbosity = 10; } + ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; } }; -class TestCapability : public Capability +class TestCapability: public Capability { - int m_cntReceivedMessages; - int m_testSum; - public: - TestCapability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset) : Capability(_s, _h, _idOffset), m_cntReceivedMessages(0), m_testSum(0) {} + TestCapability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): Capability(_s, _h, _idOffset), m_cntReceivedMessages(0), m_testSum(0) {} virtual ~TestCapability() {} int countReceivedMessages() { return m_cntReceivedMessages; } int testSum() { return m_testSum; } static std::string name() { return "test"; } static u256 version() { return 2; } static unsigned messageCount() { return UserPacket + 1; } - - void sendTestMessage(int _i) - { - RLPStream s; - prep(s, UserPacket, 1); - s << _i; - sealAndSend(s); - } + void sendTestMessage(int _i) { RLPStream s; sealAndSend(prep(s, UserPacket, 1) << _i); } protected: - virtual bool interpret(unsigned _id, RLP const& _r) override - { - cnote << "Capability::interpret(): custom message received"; - BOOST_REQUIRE_EQUAL(_id, UserPacket); - ++m_cntReceivedMessages; - int i = _r[0].toInt(); - m_testSum += i; - return true; - } + virtual bool interpret(unsigned _id, RLP const& _r) override; + + int m_cntReceivedMessages; + int m_testSum; }; -class TestHostCapability : public HostCapability, public Worker +bool TestCapability::interpret(unsigned _id, RLP const& _r) +{ + cnote << "Capability::interpret(): custom message received"; + BOOST_ASSERT(_id == UserPacket); + ++m_cntReceivedMessages; + m_testSum += _r[0].toInt(); + return true; +} + +class TestHostCapability: public HostCapability, public Worker { public: - TestHostCapability() : Worker("test") {} + TestHostCapability(): Worker("test") {} virtual ~TestHostCapability() {} void sendTestMessage(NodeId const& _id, int _x) @@ -96,7 +90,7 @@ public: { int cnt = 0; int checksum = 0; - for (auto i : peerSessions()) + for (auto i: peerSessions()) if (_id == i.second->id) { cnt += i.first->cap().get()->countReceivedMessages(); From 30ca78aa0b2f73999731c15d153ec629e20eea7e Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 11 May 2015 17:16:07 +0200 Subject: [PATCH 11/24] small changes --- mix/ClientModel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 87230664f..5f6a6c26c 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -256,9 +256,7 @@ void ClientModel::setupState(QVariantMap _state) u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); QString sender = transaction.value("sender").toString(); bool isStdContract = transaction.value("stdContract").toBool(); - bool isContractCreation; - if (!transaction.value("isContractCreation").isNull()) - isContractCreation = transaction.value("isContractCreation").toBool(); + bool isContractCreation = transaction.value("isContractCreation").toBool(); if (isStdContract) { if (contractId.isEmpty()) //TODO: This is to support old project files, remove later From 23d4ac1adb11e6b1689117fe7ddf432d57b2f836 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 11 May 2015 17:27:11 +0200 Subject: [PATCH 12/24] Coding Standards fix --- test/libp2p/capability.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/libp2p/capability.cpp b/test/libp2p/capability.cpp index 2f1509e80..e4d0d910c 100644 --- a/test/libp2p/capability.cpp +++ b/test/libp2p/capability.cpp @@ -40,9 +40,10 @@ struct P2PFixture struct VerbosityHolder { - int oldLogVerbosity; VerbosityHolder(): oldLogVerbosity(g_logVerbosity) { g_logVerbosity = 10; } ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; } + + int oldLogVerbosity; }; class TestCapability: public Capability @@ -122,16 +123,14 @@ BOOST_AUTO_TEST_CASE(capability) int const step = 10; - for (int i = 0; i < 3000; i += step) - if (!host1.isStarted() || !host2.isStarted()) - this_thread::sleep_for(chrono::milliseconds(step)); + for (int i = 0; i < 3000 && (!host1.isStarted() || !host2.isStarted()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); BOOST_REQUIRE(host1.isStarted() && host2.isStarted()); host1.requirePeer(host2.id(), NodeIPEndpoint(bi::address::from_string(localhost), prefs2.listenPort, prefs2.listenPort)); - for (int i = 0; i < 3000; i += step) - if (!host1.peerCount() || !host2.peerCount()) - this_thread::sleep_for(chrono::milliseconds(step)); + for (int i = 0; i < 3000 && (!host1.peerCount() || !host2.peerCount()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); BOOST_REQUIRE(host1.peerCount() > 0 && host2.peerCount() > 0); From 3323ebbd1dcbbb38ba6a86aa5b07c0aed8d6d7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 11 May 2015 17:40:00 +0200 Subject: [PATCH 13/24] Create symlink to old testeth location to make bildbot happy --- test/CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 39a235c58..bedbe42f3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -95,6 +95,12 @@ if (JSONRPC) target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES}) endif() +if (UNIX) # Create symlink to old testeth location to make bildbot happy + add_custom_command(TARGET testeth POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/bin/testeth ${CMAKE_BINARY_DIR}/test/testeth + ) +endif() + enable_testing() set(CTEST_OUTPUT_ON_FAILURE TRUE) @@ -110,7 +116,6 @@ eth_add_test(ClientBase ) eth_add_test(JsonRpc - ARGS --eth_testfile=BlockTests/bcJS_API_Test + ARGS --eth_testfile=BlockTests/bcJS_API_Test ARGS --eth_testfile=BlockTests/bcValidBlockTest ) - From c47fe49f80924e3fd54de006189ad7a515d37859 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 11 May 2015 22:54:12 +0200 Subject: [PATCH 14/24] Fixed warning: unused parameter --- test/libp2p/capability.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/libp2p/capability.cpp b/test/libp2p/capability.cpp index e4d0d910c..2c158f4d8 100644 --- a/test/libp2p/capability.cpp +++ b/test/libp2p/capability.cpp @@ -68,10 +68,10 @@ protected: bool TestCapability::interpret(unsigned _id, RLP const& _r) { cnote << "Capability::interpret(): custom message received"; - BOOST_ASSERT(_id == UserPacket); ++m_cntReceivedMessages; m_testSum += _r[0].toInt(); - return true; + BOOST_ASSERT(_id == UserPacket); + return (_id == UserPacket); } class TestHostCapability: public HostCapability, public Worker From 03a82e401c8cfe3c16139e6f5830ac74b5cd7ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 12 May 2015 09:37:39 +0200 Subject: [PATCH 15/24] testeth: support for --singletest option with only test name param. --- test/TestHelper.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index e0aad310f..1d7734e35 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -552,6 +552,9 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e void userDefinedTest(std::function doTests) { if (!Options::get().singleTest) + return; + + if (Options::get().singleTestFile.empty() || Options::get().singleTestName.empty()) { cnote << "Missing user test specification\nUsage: testeth --singletest \n"; return; @@ -732,11 +735,23 @@ Options::Options() inputLimits = true; bigData = true; } - else if (arg == "--singletest" && i + 2 < argc) + else if (arg == "--singletest" && i + 1 < argc) { singleTest = true; - singleTestFile = argv[i + 1]; - singleTestName = argv[i + 2]; + auto name1 = std::string{argv[i + 1]}; + if (i + 1 < argc) // two params + { + auto name2 = std::string{argv[i + 2]}; + if (name2[0] == '-') // not param, another option + singleTestName = std::move(name1); + else + { + singleTestFile = std::move(name1); + singleTestName = std::move(name2); + } + } + else + singleTestName = std::move(name1); } } } From 294a73a4e9f85ae3220c644cd520d9933ebf3966 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 12 May 2015 09:47:55 +0200 Subject: [PATCH 16/24] fixed RUNTIME_OUTPUT_DIRECTORY on osx --- cmake/EthExecutableHelper.cmake | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index d971a5f92..3dd7fa798 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -88,20 +88,15 @@ macro(eth_install_executable EXECUTABLE) if (APPLE) # First have qt5 install plugins and frameworks add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND ${MACDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app -executable=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app/Contents/MacOS/${EXECUTABLE} ${eth_qml_dir} - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMAND sh ${CMAKE_SOURCE_DIR}/macdeployfix.sh ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app/Contents + COMMAND ${MACDEPLOYQT_APP} ${EXECUTABLE}.app -executable=${EXECUTABLE}.app/Contents/MacOS/${EXECUTABLE} ${eth_qml_dir} + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR} + COMMAND sh ${CMAKE_SOURCE_DIR}/macdeployfix.sh ${EXECUTABLE}.app/Contents ) - get_target_property(TARGET_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE} RUNTIME_OUTPUT_DIRECTORY) - # This tool and next will inspect linked libraries in order to determine which dependencies are required - if (${CMAKE_CFG_INTDIR} STREQUAL ".") - # TODO: This should only happen for GUI application - set(APP_BUNDLE_PATH "${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${EXECUTABLE}.app") - else () - set(APP_BUNDLE_PATH "${TARGET_RUNTIME_OUTPUT_DIRECTORY}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app") - endif () + # TODO: This should only happen for GUI application + set(APP_BUNDLE_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INDIR}/${EXECUTABLE}.app") + # This tool and next will inspect linked libraries in order to determine which dependencies are required install(CODE " include(BundleUtilities) set(BU_CHMOD_BUNDLE_ITEMS 1) From 9ea0bf5ab1d8c6146377b9fd3d3642c5d176f698 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 12 May 2015 10:46:04 +0200 Subject: [PATCH 17/24] std::pair instead of QString manipulation --- mix/ClientModel.cpp | 78 +++++++++++++++++---------------- mix/ClientModel.h | 16 ++++--- mix/qml/StateListModel.qml | 9 +++- mix/qml/TransactionDialog.qml | 11 +++-- mix/qml/js/TransactionHelper.js | 3 +- 5 files changed, 67 insertions(+), 50 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 5f6a6c26c..bbb9b109b 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -193,7 +193,7 @@ QVariantMap ClientModel::contractAddresses() const { QVariantMap res; for (auto const& c: m_contractAddresses) - res.insert(c.first, QString::fromStdString(toJS(c.second))); + res.insert(c.first.first, QString::fromStdString(toJS(c.second))); return res; } @@ -257,6 +257,7 @@ void ClientModel::setupState(QVariantMap _state) QString sender = transaction.value("sender").toString(); bool isStdContract = transaction.value("stdContract").toBool(); bool isContractCreation = transaction.value("isContractCreation").toBool(); + bool isFunctionCall = transaction.value("isFunctionCall").toBool(); if (isStdContract) { if (contractId.isEmpty()) //TODO: This is to support old project files, remove later @@ -272,7 +273,7 @@ void ClientModel::setupState(QVariantMap _state) { if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later contractId = m_codeModel->contracts().keys()[0]; - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation, isFunctionCall); transactionSettings.parameterValues = transaction.value("parameters").toMap(); if (contractId == functionId || functionId == "Constructor") @@ -308,9 +309,9 @@ void ClientModel::executeSequence(vector const& _sequence, m_gasCosts.clear(); for (TransactionSettings const& transaction: _sequence) { - QString contractName = resolveContractName(transaction.contractId); - QString address = resolveToken(transaction.contractId, deployedContracts); - if (transaction.functionId == "(transfert)") + std::pair ctrInstance = resolvePair(transaction.contractId); + QString address = resolveToken(ctrInstance, deployedContracts); + if (transaction.isFunctionCall) { callAddress(Address(address.toStdString()), bytes(), transaction); onNewTransaction(); @@ -331,7 +332,7 @@ void ClientModel::executeSequence(vector const& _sequence, else { //encode data - CompiledContract const& compilerRes = m_codeModel->contract(contractName); + CompiledContract const& compilerRes = m_codeModel->contract(ctrInstance.first); QFunctionDefinition const* f = nullptr; bytes contractCode = compilerRes.bytes(); shared_ptr contractDef = compilerRes.sharedContract(); @@ -358,29 +359,28 @@ void ClientModel::executeSequence(vector const& _sequence, QSolidityType const* type = p->type(); QVariant value = transaction.parameterValues.value(p->name()); if (type->type().type == SolidityType::Type::Address) - value = QVariant(resolveToken(value.toString(), deployedContracts)); + { + std::pair ctrParamInstance = resolvePair(value.toString()); + value = QVariant(resolveToken(ctrParamInstance, deployedContracts)); + } encoder.encode(value, type->type()); } - if (transaction.functionId.isEmpty() || transaction.functionId == contractName) + if (transaction.functionId.isEmpty() || transaction.functionId == ctrInstance.first) { bytes param = encoder.encodedData(); contractCode.insert(contractCode.end(), param.begin(), param.end()); Address newAddress = deployContract(contractCode, transaction); deployedContracts.push_back(newAddress); - auto contractAddressIter = m_contractAddresses.find(transaction.contractId); - if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second) - { - QString contractToken = retrieveToken(transaction.contractId, deployedContracts); - m_contractAddresses[contractToken] = newAddress; - m_contractNames[newAddress] = contractToken; - contractAddressesChanged(); - } + std::pair contractToken = retrieveToken(transaction.contractId, deployedContracts); + m_contractAddresses[contractToken] = newAddress; + m_contractNames[newAddress] = contractToken.first; + contractAddressesChanged(); gasCostsChanged(); } else { - auto contractAddressIter = m_contractAddresses.find(retrieveToken(transaction.contractId, deployedContracts)); + auto contractAddressIter = m_contractAddresses.find(ctrInstance); if (contractAddressIter == m_contractAddresses.end()) { emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); @@ -412,31 +412,35 @@ void ClientModel::executeSequence(vector const& _sequence, }); } -QString ClientModel::resolveToken(QString const& _value, vector
const& _contracts) + +std::pair ClientModel::resolvePair(QString const& _contractId) { - QString ret = _value; - if (_value.startsWith("<") && _value.endsWith(">")) - { - QStringList nb = ret.remove("<").remove(">").split(" - "); - ret = QString::fromStdString("0x" + dev::toHex(_contracts.at(nb.back().toInt()).ref())); - } - return ret; + std::pair ret; + ret.first = _contractId; + ret.second = -1; + if (_contractId.startsWith("<") && _contractId.endsWith(">")) + { + QStringList values = ret.first.remove("<").remove(">").split(" - "); + ret.first = values[0]; + ret.second = values[1].toUInt(); + } + return ret; } -QString ClientModel::retrieveToken(QString const& _value, vector
const& _contracts) +QString ClientModel::resolveToken(std::pair const& _value, vector
const& _contracts) { - QString ret = _value; - if (!_value.startsWith("<") && !_value.endsWith(">")) - return "<" + _value + " - " + QString::number(_contracts.size() - 1) + ">"; - return ret; + if (_value.second != -1) + return QString::fromStdString("0x" + dev::toHex(_contracts.at(_value.second).ref())); + else + return _value.first; } -QString ClientModel::resolveContractName(QString const& _value) +std::pair ClientModel::retrieveToken(QString const& _value, vector
const& _contracts) { - QString ret = _value; - if (_value.startsWith("<") && _value.endsWith(">")) - ret = ret.remove("<").remove(">").split(" - ").first(); - return ret; + std::pair ret; + ret.first = _value; + ret.second = _contracts.size() - 1; + return ret; } void ClientModel::showDebugger() @@ -462,7 +466,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) //try to resolve contract for source level debugging auto nameIter = m_contractNames.find(code.address); CompiledContract const* compilerRes = nullptr; - if (nameIter != m_contractNames.end() && (compilerRes = m_codeModel->tryGetContract(resolveContractName(nameIter->second)))) //returned object is guaranteed to live till the end of event handler in main thread + if (nameIter != m_contractNames.end() && (compilerRes = m_codeModel->tryGetContract(nameIter->second))) //returned object is guaranteed to live till the end of event handler in main thread { eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes->assemblyItems() : compilerRes->constructorAssemblyItems(); codes.back()->setDocument(compilerRes->documentId()); @@ -723,7 +727,7 @@ void ClientModel::onNewTransaction() auto contractAddressIter = m_contractNames.find(contractAddress); if (contractAddressIter != m_contractNames.end()) { - CompiledContract const& compilerRes = m_codeModel->contract(resolveContractName(contractAddressIter->second)); + CompiledContract const& compilerRes = m_codeModel->contract(contractAddressIter->second); const QContractDefinition* def = compilerRes.contract(); contract = def->name(); if (abi) diff --git a/mix/ClientModel.h b/mix/ClientModel.h index a9cf89018..9d4168995 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -53,10 +53,10 @@ struct SolidityType; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, int _isContractCreation): - contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation) {} + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): + contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): - contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true) {} + contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(false) {} /// Contract name QString contractId; @@ -78,6 +78,8 @@ struct TransactionSettings Secret sender; /// Tr deploys a contract bool isContractCreation; + /// Tr call a ctr function + bool isFunctionCall; }; @@ -229,9 +231,9 @@ private: void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); - QString resolveToken(QString const& _value, std::vector
const& _contracts); - QString resolveContractName(QString const& _value); - QString retrieveToken(QString const& _value, std::vector
const& _contracts); + QString resolveToken(std::pair const& _value, std::vector
const& _contracts); + std::pair retrieveToken(QString const& _value, std::vector
const& _contracts); + std::pair resolvePair(QString const& _contractId); QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); std::atomic m_running; @@ -241,7 +243,7 @@ private: std::unique_ptr m_rpcConnector; std::unique_ptr m_web3Server; QList m_gasCosts; - std::map m_contractAddresses; + std::map, Address> m_contractAddresses; std::map m_contractNames; std::map m_stdContractAddresses; std::map m_stdContractNames; diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index b4eed525d..b4d9b6bc6 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -58,9 +58,13 @@ Item { parameters: {}, sender: t.sender, isContractCreation: t.isContractCreation, - label: t.label + label: t.label, + isFunctionCall: t.isFunctionCall }; + if (r.isFunctionCall === undefined) + r.isFunctionCall = true; + if (!r.label) r.label = r.contractId + " - " + r.functionId; @@ -122,7 +126,8 @@ Item { sender: t.sender, parameters: {}, isContractCreation: t.isContractCreation, - label: t.label + label: t.label, + isFunctionCall: t.isFunctionCall }; for (var key in t.parameters) r.parameters[key] = t.parameters[key]; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index d26fbaf5a..7c9b28aa7 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -87,8 +87,6 @@ Dialog { else loadParameters(); - - visible = true; valueField.focus = true; } @@ -212,12 +210,19 @@ Dialog { } item.isContractCreation = trType.checked; + + if (item.functionId === "(transfert)") + item.isFunctionCall = false; + if (!item.isContractCreation) { item.contractId = recipients.currentText; item.label = item.contractId + " " + item.functionId; if (recipients.current().type === "address") - item.functionId = "(transfert)"; + { + item.functionId = ""; + item.isFunctionCall = false; + } } else { diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index 33072fdba..b9a011b66 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -11,7 +11,8 @@ function defaultTransaction() parameters: {}, stdContract: false, isContractCreation: true, - label: "" + label: "", + isFunctionCall: true }; } From 40de803f66f35ecd5a4636effd04b5d1662a3f3d Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 12 May 2015 11:39:31 +0200 Subject: [PATCH 18/24] bug fix --- mix/ClientModel.cpp | 2 +- mix/ClientModel.h | 2 +- mix/qml/TransactionDialog.qml | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index dc9346d3e..fc8ce4c33 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -312,7 +312,7 @@ void ClientModel::executeSequence(vector const& _sequence, { std::pair ctrInstance = resolvePair(transaction.contractId); QString address = resolveToken(ctrInstance, deployedContracts); - if (transaction.isFunctionCall) + if (!transaction.isFunctionCall) { callAddress(Address(address.toStdString()), bytes(), transaction); onNewTransaction(); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 2ca3d2c69..e1648b78d 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -56,7 +56,7 @@ struct TransactionSettings TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): - contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(false) {} + contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(true) {} /// Contract name QString contractId; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 7c9b28aa7..d9c811704 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -210,9 +210,7 @@ Dialog { } item.isContractCreation = trType.checked; - - if (item.functionId === "(transfert)") - item.isFunctionCall = false; + item.isFunctionCall = item.functionId !== "(transfert)"; if (!item.isContractCreation) { From 3a81c1059846a93e1d46d843b319260c6b19b95e Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 12 May 2015 12:14:26 +0200 Subject: [PATCH 19/24] use - instead of "(transfer)" --- mix/qml/TransactionDialog.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index d9c811704..fe4bfc82e 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -107,6 +107,7 @@ Dialog { function loadFunctions(contractId) { functionsModel.clear(); + functionsModel.append({ text: " - " }); var contract = codeModel.contracts[contractId]; if (contract) { var functions = codeModel.contracts[contractId].contract.functions; @@ -114,7 +115,6 @@ Dialog { functionsModel.append({ text: functions[f].name }); } } - functionsModel.append({ text: "(transfert)" }); } function selectContract(contractName) @@ -210,7 +210,7 @@ Dialog { } item.isContractCreation = trType.checked; - item.isFunctionCall = item.functionId !== "(transfert)"; + item.isFunctionCall = item.functionId !== " - "; if (!item.isContractCreation) { From 0315689bb37f63c714abc6194a29f8312e6f9e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 12 May 2015 16:14:18 +0200 Subject: [PATCH 20/24] Ping buildbot --- test/libevm/vm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 2d67d7670..f9aac2eb2 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -432,7 +432,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } } -} } // Namespace Close +} } // namespace close BOOST_AUTO_TEST_SUITE(VMTests) From 212a01136bd28d0f53cab2e07c018ae888977377 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 12 May 2015 16:16:44 +0200 Subject: [PATCH 21/24] Unify blocks with shared code. --- libevmasm/Assembly.cpp | 10 +++ libevmasm/AssemblyItem.h | 2 + libevmasm/BlockDeduplicator.cpp | 93 ++++++++++++++++++++++++++ libevmasm/BlockDeduplicator.h | 69 +++++++++++++++++++ test/libsolidity/SolidityOptimizer.cpp | 38 ++++++++++- 5 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 libevmasm/BlockDeduplicator.cpp create mode 100644 libevmasm/BlockDeduplicator.h diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index abcd44516..1011392b9 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include using namespace std; using namespace dev; @@ -348,8 +349,17 @@ Assembly& Assembly::optimise(bool _enable) copy(orig, iter, back_inserter(optimisedItems)); } } + if (optimisedItems.size() < m_items.size()) + { m_items = move(optimisedItems); + count++; + } + + // This only modifies PushTags, we have to run again to actually remove code. + BlockDeduplicator dedup(m_items); + if (dedup.deduplicate()) + count++; } } diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 6f2a65de9..b3012a7ea 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -68,6 +68,8 @@ public: /// @returns true iff the type and data of the items are equal. bool operator==(AssemblyItem const& _other) const { return m_type == _other.m_type && m_data == _other.m_data; } bool operator!=(AssemblyItem const& _other) const { return !operator==(_other); } + /// Less-than operator compatible with operator==. + bool operator<(AssemblyItem const& _other) const { return std::tie(m_type, m_data) < std::tie(_other.m_type, _other.m_data); } /// @returns an upper bound for the number of bytes required by this item, assuming that /// the value of a jump tag takes @a _addressLength bytes. diff --git a/libevmasm/BlockDeduplicator.cpp b/libevmasm/BlockDeduplicator.cpp new file mode 100644 index 000000000..ca4f7e21a --- /dev/null +++ b/libevmasm/BlockDeduplicator.cpp @@ -0,0 +1,93 @@ +/* + 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 BlockDeduplicator.cpp + * @author Christian + * @date 2015 + * Unifies basic blocks that share content. + */ + +#include +#include +#include +#include + +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + + +bool BlockDeduplicator::deduplicate() +{ + // Compares indices based on the suffix that starts there, ignoring tags and stopping at + // opcodes that stop the control flow. + function comparator = [&](size_t _i, size_t _j) + { + if (_i == _j) + return false; + + BlockIterator first(m_items.begin() + _i, m_items.end()); + BlockIterator second(m_items.begin() + _j, m_items.end()); + BlockIterator end(m_items.end(), m_items.end()); + + if (first != end && (*first).type() == Tag) + ++first; + if (second != end && (*second).type() == Tag) + ++second; + + return std::lexicographical_compare(first, end, second, end); + }; + + set> blocksSeen(comparator); + map tagReplacement; + for (size_t i = 0; i < m_items.size(); ++i) + { + if (m_items.at(i).type() != Tag) + continue; + auto it = blocksSeen.find(i); + if (it == blocksSeen.end()) + blocksSeen.insert(i); + else + tagReplacement[m_items.at(i).data()] = m_items.at(*it).data(); + } + + bool ret = false; + for (AssemblyItem& item: m_items) + if (item.type() == PushTag && tagReplacement.count(item.data())) + { + ret = true; + item.setData(tagReplacement.at(item.data())); + } + return ret; +} + +BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++() +{ + if (it == end) + return *this; + if (SemanticInformation::altersControlFlow(*it) && *it != AssemblyItem(eth::Instruction::JUMPI)) + it = end; + else + { + ++it; + while (it != end && it->type() == Tag) + ++it; + } + return *this; +} diff --git a/libevmasm/BlockDeduplicator.h b/libevmasm/BlockDeduplicator.h new file mode 100644 index 000000000..8a82a1ed7 --- /dev/null +++ b/libevmasm/BlockDeduplicator.h @@ -0,0 +1,69 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @file BlockDeduplicator.h + * @author Christian + * @date 2015 + * Unifies basic blocks that share content. + */ + +#pragma once + +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +class AssemblyItem; +using AssemblyItems = std::vector; + +/** + * Optimizer class to be used to unify blocks that share content. + * Modifies the passed vector in place. + */ +class BlockDeduplicator +{ +public: + BlockDeduplicator(AssemblyItems& _items): m_items(_items) {} + /// @returns true if something was changed + bool deduplicate(); + +private: + /// Iterator that skips tags skips to the end if (all branches of) the control + /// flow does not continue to the next instruction. + struct BlockIterator: std::iterator + { + public: + BlockIterator(AssemblyItems::const_iterator _it, AssemblyItems::const_iterator _end): + it(_it), end(_end) { } + BlockIterator& operator++(); + bool operator==(BlockIterator const& _other) const { return it == _other.it; } + bool operator!=(BlockIterator const& _other) const { return it != _other.it; } + AssemblyItem const& operator*() const { return *it; } + AssemblyItems::const_iterator it; + AssemblyItems::const_iterator end; + }; + + AssemblyItems& m_items; +}; + +} +} diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index e50469dd6..efc9316b0 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include using namespace std; using namespace dev::eth; @@ -125,7 +126,7 @@ public: BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); } - void checkCFG(AssemblyItems const& _input, AssemblyItems const& _expectation) + AssemblyItems getCFG(AssemblyItems const& _input) { AssemblyItems output = _input; // Running it four times should be enough for these tests. @@ -138,6 +139,12 @@ public: back_inserter(optItems)); output = move(optItems); } + return output; + } + + void checkCFG(AssemblyItems const& _input, AssemblyItems const& _expectation) + { + AssemblyItems output = getCFG(_input); BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); } @@ -925,6 +932,35 @@ BOOST_AUTO_TEST_CASE(control_flow_graph_do_not_remove_returned_to) checkCFG(input, {u256(2)}); } +BOOST_AUTO_TEST_CASE(block_deduplicator) +{ + AssemblyItems input{ + AssemblyItem(PushTag, 2), + AssemblyItem(PushTag, 1), + AssemblyItem(PushTag, 3), + u256(6), + eth::Instruction::SWAP3, + eth::Instruction::JUMP, + AssemblyItem(Tag, 1), + u256(6), + eth::Instruction::SWAP3, + eth::Instruction::JUMP, + AssemblyItem(Tag, 2), + u256(6), + eth::Instruction::SWAP3, + eth::Instruction::JUMP, + AssemblyItem(Tag, 3) + }; + BlockDeduplicator dedup(input); + dedup.deduplicate(); + + set pushTags; + for (AssemblyItem const& item: input) + if (item.type() == PushTag) + pushTags.insert(item.data()); + BOOST_CHECK_EQUAL(pushTags.size(), 2); +} + BOOST_AUTO_TEST_SUITE_END() } From bf51bfef0e59c3be4e1ddcadc6b0c44a15b5d272 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 12 May 2015 17:00:23 +0200 Subject: [PATCH 22/24] Removed unnecessary include. --- libevmasm/BlockDeduplicator.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libevmasm/BlockDeduplicator.cpp b/libevmasm/BlockDeduplicator.cpp index ca4f7e21a..eadbe1b40 100644 --- a/libevmasm/BlockDeduplicator.cpp +++ b/libevmasm/BlockDeduplicator.cpp @@ -26,8 +26,6 @@ #include #include -#include - using namespace std; using namespace dev; using namespace dev::eth; From 18e223e9456195dbc56528927d211805de57202a Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 12 May 2015 17:50:41 +0200 Subject: [PATCH 23/24] Reverse if and else body. --- libsolidity/Compiler.cpp | 12 ++++-- test/libsolidity/SolidityCompiler.cpp | 59 +++++++++++++-------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index bcd4f9d68..66c503172 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -377,12 +377,16 @@ bool Compiler::visit(IfStatement const& _ifStatement) StackHeightChecker checker(m_context); CompilerContext::LocationSetter locationSetter(m_context, _ifStatement); compileExpression(_ifStatement.getCondition()); - eth::AssemblyItem trueTag = m_context.appendConditionalJump(); + m_context << eth::Instruction::ISZERO; + eth::AssemblyItem falseTag = m_context.appendConditionalJump(); + eth::AssemblyItem endTag = falseTag; + _ifStatement.getTrueStatement().accept(*this); if (_ifStatement.getFalseStatement()) + { + endTag = m_context.appendJumpToNew(); + m_context << falseTag; _ifStatement.getFalseStatement()->accept(*this); - eth::AssemblyItem endTag = m_context.appendJumpToNew(); - m_context << trueTag; - _ifStatement.getTrueStatement().accept(*this); + } m_context << endTag; checker.check(); diff --git a/test/libsolidity/SolidityCompiler.cpp b/test/libsolidity/SolidityCompiler.cpp index aa83c4650..dda7847ed 100644 --- a/test/libsolidity/SolidityCompiler.cpp +++ b/test/libsolidity/SolidityCompiler.cpp @@ -116,36 +116,35 @@ BOOST_AUTO_TEST_CASE(ifStatement) bytes code = compileContract(sourceCode); unsigned shift = 60; unsigned boilerplateSize = 73; - bytes expectation({byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x0, - byte(Instruction::DUP1), - byte(Instruction::PUSH1), byte(0x1b + shift), // "true" target - byte(Instruction::JUMPI), - // new check "else if" condition - byte(Instruction::DUP1), - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), byte(0x13 + shift), - byte(Instruction::JUMPI), - // "else" body - byte(Instruction::PUSH1), 0x4f, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x17 + shift), // exit path of second part - byte(Instruction::JUMP), - // "else if" body - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x4e, - byte(Instruction::POP), - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), byte(0x1f + shift), - byte(Instruction::JUMP), - // "if" body - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x4d, - byte(Instruction::POP), - byte(Instruction::JUMPDEST), - byte(Instruction::JUMPDEST), - byte(Instruction::POP), - byte(Instruction::JUMP)}); + bytes expectation({ + byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x0, + byte(Instruction::DUP1), + byte(Instruction::ISZERO), + byte(Instruction::PUSH1), byte(0x0f + shift), // "false" target + byte(Instruction::JUMPI), + // "if" body + byte(Instruction::PUSH1), 0x4d, + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0x21 + shift), + byte(Instruction::JUMP), + // new check "else if" condition + byte(Instruction::JUMPDEST), + byte(Instruction::DUP1), + byte(Instruction::ISZERO), + byte(Instruction::ISZERO), + byte(Instruction::PUSH1), byte(0x1c + shift), + byte(Instruction::JUMPI), + // "else if" body + byte(Instruction::PUSH1), 0x4e, + byte(Instruction::POP), + byte(Instruction::PUSH1), byte(0x20 + shift), + byte(Instruction::JUMP), + // "else" body + byte(Instruction::JUMPDEST), + byte(Instruction::PUSH1), 0x4f, + byte(Instruction::POP), + }); checkCodePresentAt(code, expectation, boilerplateSize); } From d638df83ae76519c506839ea827482074be11fb0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 May 2015 11:45:18 +0300 Subject: [PATCH 24/24] Revert "CMake: set default RUNTIME_OUTPUT_DIRECTORY property to "bin"" --- CMakeLists.txt | 1 - cmake/EthExecutableHelper.cmake | 44 ++++++++++++++++++--------------- cmake/scripts/copydlls.cmake | 3 ++- libevmasm/CMakeLists.txt | 7 +++++- test/CMakeLists.txt | 9 ++----- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac37454d8..289cecad8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -295,7 +295,6 @@ message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}" message("------------------------------------------------------------------------") message("") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") set(CMAKE_THREAD_LIBS_INIT pthread) include(EthCompilerSettings) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 3dd7fa798..1d1cb887b 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -45,26 +45,25 @@ endmacro() macro(eth_copy_dlls EXECUTABLE DLLS) # dlls must be unsubstitud list variable (without ${}) in format - # optimized;path_to_dll.dll;debug;path_to_dlld.dll + # optimized;path_to_dll.dll;debug;path_to_dlld.dll list(GET ${DLLS} 1 DLL_RELEASE) list(GET ${DLLS} 3 DLL_DEBUG) - get_target_property(TARGET_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE} RUNTIME_OUTPUT_DIRECTORY) add_custom_command(TARGET ${EXECUTABLE} - POST_BUILD - COMMAND ${CMAKE_COMMAND} ARGS - -DDLL_RELEASE="${DLL_RELEASE}" - -DDLL_DEBUG="${DLL_DEBUG}" + POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS + -DDLL_RELEASE="${DLL_RELEASE}" + -DDLL_DEBUG="${DLL_DEBUG}" -DCONF="$" - -DDESTINATION="${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}" + -DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" -P "${ETH_SCRIPTS_DIR}/copydlls.cmake" ) endmacro() -# +# # this function requires the following variables to be specified: # ETH_DEPENDENCY_INSTALL_DIR # -# params: +# params: # QMLDIR # @@ -75,7 +74,7 @@ macro(eth_install_executable EXECUTABLE) set (one_value_args QMLDIR) set (multi_value_args DLLS) cmake_parse_arguments (ETH_INSTALL_EXECUTABLE "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}") - + if (ETH_INSTALL_EXECUTABLE_QMLDIR) if (APPLE) set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}") @@ -88,15 +87,19 @@ macro(eth_install_executable EXECUTABLE) if (APPLE) # First have qt5 install plugins and frameworks add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND ${MACDEPLOYQT_APP} ${EXECUTABLE}.app -executable=${EXECUTABLE}.app/Contents/MacOS/${EXECUTABLE} ${eth_qml_dir} - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR} - COMMAND sh ${CMAKE_SOURCE_DIR}/macdeployfix.sh ${EXECUTABLE}.app/Contents + COMMAND ${MACDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app -executable=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app/Contents/MacOS/${EXECUTABLE} ${eth_qml_dir} + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND sh ${CMAKE_SOURCE_DIR}/macdeployfix.sh ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app/Contents ) - - # TODO: This should only happen for GUI application - set(APP_BUNDLE_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INDIR}/${EXECUTABLE}.app") - + # This tool and next will inspect linked libraries in order to determine which dependencies are required + if (${CMAKE_CFG_INTDIR} STREQUAL ".") + # TODO: This should only happen for GUI application + set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTABLE}.app") + else () + set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app") + endif () + install(CODE " include(BundleUtilities) set(BU_CHMOD_BUNDLE_ITEMS 1) @@ -108,15 +111,14 @@ macro(eth_install_executable EXECUTABLE) get_target_property(TARGET_LIBS ${EXECUTABLE} INTERFACE_LINK_LIBRARIES) string(REGEX MATCH "Qt5::Core" HAVE_QT ${TARGET_LIBS}) if ("${HAVE_QT}" STREQUAL "Qt5::Core") - get_target_property(TARGET_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE} RUNTIME_OUTPUT_DIRECTORY) add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) #workaround for https://bugreports.qt.io/browse/QTBUG-42083 add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" - WORKING_DIRECTORY ${TARGET_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR} VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM ) endif() @@ -142,3 +144,5 @@ macro(eth_install_executable EXECUTABLE) endif () endmacro() + + diff --git a/cmake/scripts/copydlls.cmake b/cmake/scripts/copydlls.cmake index 57eb0ffd4..6d86b8e4e 100644 --- a/cmake/scripts/copydlls.cmake +++ b/cmake/scripts/copydlls.cmake @@ -14,4 +14,5 @@ else () # Debug set(DLL ${DLL_DEBUG}) endif() -execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DLL}" "${DESTINATION}") +execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${DLL}" "${DESTINATION}") + diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt index eb8fea95c..f8150806f 100644 --- a/libevmasm/CMakeLists.txt +++ b/libevmasm/CMakeLists.txt @@ -19,10 +19,15 @@ set(EXECUTABLE evmasm) file(GLOB HEADERS "*.h") -add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) +if (ETH_STATIC) + add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) +else() + add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) +endif() target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcrypto) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bedbe42f3..39a235c58 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -95,12 +95,6 @@ if (JSONRPC) target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES}) endif() -if (UNIX) # Create symlink to old testeth location to make bildbot happy - add_custom_command(TARGET testeth POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/bin/testeth ${CMAKE_BINARY_DIR}/test/testeth - ) -endif() - enable_testing() set(CTEST_OUTPUT_ON_FAILURE TRUE) @@ -116,6 +110,7 @@ eth_add_test(ClientBase ) eth_add_test(JsonRpc - ARGS --eth_testfile=BlockTests/bcJS_API_Test + ARGS --eth_testfile=BlockTests/bcJS_API_Test ARGS --eth_testfile=BlockTests/bcValidBlockTest ) +