From f75f4d8dc77d00590af372a43b551660e2910b98 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 27 Jul 2015 12:32:13 +0200 Subject: [PATCH 01/18] refactoring of topic test --- test/libwhisper/whisperTopic.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/test/libwhisper/whisperTopic.cpp b/test/libwhisper/whisperTopic.cpp index 6a58be045..eda73a6ff 100644 --- a/test/libwhisper/whisperTopic.cpp +++ b/test/libwhisper/whisperTopic.cpp @@ -57,6 +57,8 @@ BOOST_AUTO_TEST_CASE(topic) bool host1Ready = false; unsigned result = 0; + unsigned const step = 10; + std::thread listener([&]() { setThreadName("other"); @@ -85,22 +87,31 @@ BOOST_AUTO_TEST_CASE(topic) host1.setIdealPeerCount(1); auto whost2 = host2.registerCapability(new WhisperHost()); host2.start(); - - while (!host1.haveNetwork()) - this_thread::sleep_for(chrono::milliseconds(5)); + + for (unsigned i = 0; i < 3000 && (!host1.haveNetwork() || !host2.haveNetwork()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE(host1.haveNetwork()); + BOOST_REQUIRE(host2.haveNetwork()); + host2.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), port1, port1)); - // wait for nodes to connect - this_thread::sleep_for(chrono::milliseconds(1000)); - - while (!host1Ready) - this_thread::sleep_for(chrono::milliseconds(10)); + for (unsigned i = 0; i < 3000 && (!host1.peerCount() || !host2.peerCount()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE(host1.peerCount()); + BOOST_REQUIRE(host2.peerCount()); + + for (unsigned i = 0; i < 3000 && !host1Ready; i += step) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE(host1Ready); KeyPair us = KeyPair::create(); for (int i = 0; i < 10; ++i) { whost2->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even")); - this_thread::sleep_for(chrono::milliseconds(250)); + this_thread::sleep_for(chrono::milliseconds(50)); } listener.join(); From 87fb4118174bdbe810295829caffca79bc1e1879 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 27 Jul 2015 14:13:07 +0200 Subject: [PATCH 02/18] updated test topic advertising --- test/libwhisper/whisperTopic.cpp | 46 +++++++++++++++++--------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/test/libwhisper/whisperTopic.cpp b/test/libwhisper/whisperTopic.cpp index eda73a6ff..e8bd48946 100644 --- a/test/libwhisper/whisperTopic.cpp +++ b/test/libwhisper/whisperTopic.cpp @@ -325,39 +325,39 @@ BOOST_AUTO_TEST_CASE(topicAdvertising) while (!host1.haveNetwork()) this_thread::sleep_for(chrono::milliseconds(10)); + unsigned const step = 10; uint16_t port2 = 30318; Host host2("second", NetworkPreferences("127.0.0.1", port2, false)); host2.setIdealPeerCount(1); auto whost2 = host2.registerCapability(new WhisperHost()); unsigned w2 = whost2->installWatch(BuildTopicMask("test2")); - host2.start(); - while (!host2.haveNetwork()) - this_thread::sleep_for(chrono::milliseconds(10)); - host1.addNode(host2.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), port2, port2)); - while (!host1.haveNetwork()) - this_thread::sleep_for(chrono::milliseconds(10)); + for (unsigned i = 0; i < 3000 && (!host1.haveNetwork() || !host2.haveNetwork()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); - while (!host1.peerCount()) - this_thread::sleep_for(chrono::milliseconds(10)); + host1.addNode(host2.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), port2, port2)); - while (!host2.peerCount()) - this_thread::sleep_for(chrono::milliseconds(10)); + for (unsigned i = 0; i < 3000 && (!host1.peerCount() || !host2.peerCount()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); std::vector, std::shared_ptr>> sessions; + TopicBloomFilterHash bf1; - for (int i = 0; i < 600; ++i) + for (int i = 0; i < 600 && !bf1; ++i) { sessions = whost1->peerSessions(); - if (!sessions.empty() && sessions.back().first->cap()->bloom()) - break; - else - this_thread::sleep_for(chrono::milliseconds(10)); + if (!sessions.empty()) + { + bf1 = sessions.back().first->cap()->bloom(); + if (bf1) + break; + } + + this_thread::sleep_for(chrono::milliseconds(10)); } BOOST_REQUIRE(sessions.size()); - TopicBloomFilterHash bf1 = sessions.back().first->cap()->bloom(); TopicBloomFilterHash bf2 = whost2->bloom(); BOOST_REQUIRE_EQUAL(bf1, bf2); BOOST_REQUIRE(bf1); @@ -368,16 +368,18 @@ BOOST_AUTO_TEST_CASE(topicAdvertising) for (int i = 0; i < 600; ++i) { sessions = whost2->peerSessions(); - if (!sessions.empty() && sessions.back().first->cap()->bloom()) - break; - else - this_thread::sleep_for(chrono::milliseconds(10)); + if (!sessions.empty()) + { + bf2 = sessions.back().first->cap()->bloom(); + if (bf2) + break; + } + + this_thread::sleep_for(chrono::milliseconds(10)); } BOOST_REQUIRE(sessions.size()); BOOST_REQUIRE_EQUAL(sessions.back().second->id, host1.id()); - - bf2 = sessions.back().first->cap()->bloom(); bf1 = whost1->bloom(); BOOST_REQUIRE_EQUAL(bf1, bf2); BOOST_REQUIRE(bf1); From b00e3aa4675869043f97bdb7f5e34aa0275562eb Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 27 Jul 2015 14:14:26 +0200 Subject: [PATCH 03/18] bug fix: use of bytes, bytes32 --- mix/ContractCallDataEncoder.cpp | 52 ++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index ff858efbf..5b356a4cd 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -101,9 +102,9 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& bytes empty(32); size_t sizePos = m_dynamicData.size(); m_dynamicData += empty; //reserve space for count - u256 count = encodeSingleItem(_data.toString(), _type, m_dynamicData); + encodeSingleItem(_data.toString(), _type, m_dynamicData); vector_ref sizeRef(m_dynamicData.data() + sizePos, 32); - toBigEndian(count, sizeRef); + toBigEndian(_data.toString().size(), sizeRef); m_staticOffsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); m_encodedData += empty; //reserve space for offset } @@ -223,11 +224,7 @@ dev::bytes ContractCallDataEncoder::decodeBytes(dev::bytes const& _rawValue) QString ContractCallDataEncoder::toString(dev::bytes const& _b) { - QString str; - if (asString(_b, str)) - return "\"" + str + "\" " + QString::fromStdString(dev::toJS(_b)); - else - return QString::fromStdString(dev::toJS(_b)); + return QString::fromStdString(dev::toJS(_b)); } QString ContractCallDataEncoder::toChar(dev::bytes const& _b) @@ -242,8 +239,6 @@ QJsonValue ContractCallDataEncoder::decodeArrayContent(SolidityType const& _type if (_type.baseType->array) { QJsonArray sub = decodeArray(*_type.baseType, _value, pos); - if (_type.baseType->dynamicSize) - pos = pos + 32; return sub; } else @@ -262,6 +257,8 @@ QJsonArray ContractCallDataEncoder::decodeArray(SolidityType const& _type, bytes QJsonArray array; bytesConstRef value(&_value); int count = 0; + bigint offset = pos; + int valuePosition = pos; if (!_type.dynamicSize) count = _type.count; else @@ -269,14 +266,33 @@ QJsonArray ContractCallDataEncoder::decodeArray(SolidityType const& _type, bytes bytesConstRef value(_value.data() + pos, 32); // offset bytes rawParam(32); value.populate(&rawParam); - bigint offset = decodeInt(rawParam); - pos = static_cast(offset) + 32; - value = bytesConstRef(_value.data() + static_cast(offset), 32); // offset + offset = decodeInt(rawParam); + valuePosition = static_cast(offset) + 32; + pos += 32; + value = bytesConstRef(_value.data() + static_cast(offset), 32); // count value.populate(&rawParam); count = static_cast(decodeInt(rawParam)); } - for (int k = 0; k < count; ++k) - array.append(decodeArrayContent(_type, _value, pos)); + if (_type.type == QSolidityType::Type::Bytes || _type.type == QSolidityType::Type::String) + { + bytesConstRef value(_value.data() + (static_cast(offset) + 32), 32); + bytes rawParam(count); + value.populate(&rawParam); + if (_type.type == QSolidityType::Type::Bytes) + array.append(toString(decodeBytes(rawParam))); + else + array.append(toChar(decodeBytes(rawParam))); + } + else + { + for (int k = 0; k < count; ++k) + { + if (_type.dynamicSize) + array.append(decodeArrayContent(_type, _value, valuePosition)); + else + array.append(decodeArrayContent(_type, _value, pos)); + } + } return array; } @@ -322,18 +338,14 @@ QStringList ContractCallDataEncoder::decode(QList const& QJsonArray array = decodeArray(type, _v, readPosition); QJsonDocument jsonDoc = QJsonDocument::fromVariant(array.toVariantList()); r.append(jsonDoc.toJson(QJsonDocument::Compact)); - if (type.dynamicSize) - readPosition++; - else - readPosition = type.count; } else { - bytesConstRef value(_value.data() + (readPosition * 32), 32); + bytesConstRef value(_value.data() + readPosition, 32); bytes rawParam(32); value.populate(&rawParam); r.append(decode(type, rawParam).toString()); - readPosition++; + readPosition += 32; } } return r; From 5902496db598b1b896b262741e67dfacdf375fed Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 27 Jul 2015 14:35:43 +0200 Subject: [PATCH 04/18] bug fix (while selecting a function to call) --- mix/qml/TransactionDialog.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index e47bd9ed2..cc2ca2e79 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -125,7 +125,7 @@ Dialog { function loadParameters() { paramsModel = [] if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var contract = codeModel.contracts[TransactionHelper.contractFromToken(contractCreationComboBox.currentValue())]; + var contract = codeModel.contracts[TransactionHelper.contractFromToken(recipientsAccount.currentValue())]; if (contract) { var func = getFunction(functionComboBox.currentText, contract); if (func) { @@ -498,9 +498,7 @@ Dialog { paramScroll.visible = paramsModel.length > 0 paramScroll.Layout.preferredHeight = paramsModel.length < 6 ? paramsModel.length * 30 : 205 if (paramsModel.length === 0) - { paramScroll.height = 0 - } } } From 7a9df8017b9561fd171f2d4678a1f57b4f8fa050 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 27 Jul 2015 15:31:02 +0200 Subject: [PATCH 05/18] bugfix (bad scenario loaded in the deployment dialog) --- mix/qml/DeployContractStep.qml | 7 ------- mix/qml/ScenarioLoader.qml | 3 +-- mix/qml/StateListModel.qml | 10 ++++++---- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 01f06e4f2..d7060f1ee 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -112,14 +112,10 @@ Rectangle { for (var k = 0; k < projectModel.stateListModel.get(currentIndex).blocks.count; k++) { for (var j = 0; j < projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.count; j++) - { trListModel.append(projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.get(j)); - } } for (var k = 0; k < trListModel.count; k++) - { trList.itemAt(k).init() - } ctrDeployCtrLabel.calculateContractDeployGas(); } } @@ -166,9 +162,7 @@ Rectangle { if (trListModel.get(index).parameters) { for (var k in trListModel.get(index).parameters) - { paramList.append({ "name": k, "value": trListModel.get(index).parameters[k] }) - } } } @@ -220,7 +214,6 @@ Rectangle { } } - ColumnLayout { anchors.top: parent.top diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 8b6886c93..5b8cb2d70 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -291,7 +291,7 @@ ColumnLayout text: qsTr("Restore") function restore() { - var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) + var state = projectModel.stateListModel.reloadStateFromProject(scenarioList.currentIndex) if (state) { restored(state) @@ -302,7 +302,6 @@ ColumnLayout roundLeft: true } - Rectangle { width: 1 diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index e7b092463..efa52f853 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -186,12 +186,13 @@ Item { onProjectLoading: stateListModel.loadStatesFromProject(projectData); onProjectFileSaving: { projectData.states = [] - for(var i = 0; i < stateListModel.count; i++) { + for(var i = 0; i < stateListModel.count; i++) + { projectData.states.push(toPlainStateItem(stateList[i])); + stateListModel.set(i, stateList[i]); } projectData.defaultStateIndex = stateListModel.defaultStateIndex; stateListModel.data = projectData - } onNewProject: { var state = toPlainStateItem(stateListModel.createDefaultState()); @@ -247,7 +248,8 @@ Item { signal stateRun(int index) signal stateDeleted(int index) - function defaultTransactionItem() { + function defaultTransactionItem() + { return TransactionHelper.defaultTransaction(); } @@ -409,7 +411,7 @@ Item { return "" } - function reloadStateFromFromProject(index) + function reloadStateFromProject(index) { if (data) { From eae8de56d77dcc285f8f6b294cd3c2d16fdeea68 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 27 Jul 2015 16:50:31 +0200 Subject: [PATCH 06/18] update the number of verification during the deployment process --- mix/qml/BlockChain.qml | 25 ++++++++++++++----------- mix/qml/DeployContractStep.qml | 15 +++++++++++++-- mix/qml/DeploymentDialog.qml | 2 ++ mix/qml/DeploymentWorker.qml | 12 +++++++++++- mix/qml/RegisteringStep.qml | 8 ++++++++ 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 960d95ebf..41c65553a 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -395,19 +395,22 @@ ColumnLayout { text: qsTr("Add Tx") onClicked: { - var lastBlock = model.blocks[model.blocks.length - 1]; - if (lastBlock.status === "mined") + if (model && model.blocks) { - var newblock = projectModel.stateListModel.createEmptyBlock() - blockModel.appendBlock(newblock) - model.blocks.push(newblock); - } + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + { + var newblock = projectModel.stateListModel.createEmptyBlock() + blockModel.appendBlock(newblock) + model.blocks.push(newblock); + } - var item = TransactionHelper.defaultTransaction() - transactionDialog.stateAccounts = model.accounts - transactionDialog.execute = true - transactionDialog.editMode = false - transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + var item = TransactionHelper.defaultTransaction() + transactionDialog.stateAccounts = model.accounts + transactionDialog.execute = true + transactionDialog.editMode = false + transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + } } width: 100 height: 30 diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index d7060f1ee..39881879c 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -36,6 +36,19 @@ Rectangle { accountsList.currentIndex = 0 } + verifyDeployedContract() + + deployedAddresses.refresh() + worker.renewCtx() + + worker.pooler.onTriggered.connect(function() { + if (root.visible) + verifyDeployedContract(); + }) + } + + function verifyDeployedContract() + { if (projectModel.deployBlockNumber !== -1) { worker.verifyHashes(projectModel.deploymentTrHashes, function (bn, trLost) @@ -43,8 +56,6 @@ Rectangle { root.updateVerification(bn, trLost) }); } - deployedAddresses.refresh() - worker.renewCtx() } function updateVerification(blockNumber, trLost) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 280ce0d07..b80a823f2 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -27,6 +27,7 @@ Dialog { function close() { visible = false; + worker.pooler.running = false } function open() @@ -36,6 +37,7 @@ Dialog { registerStep.visible = false steps.init() worker.renewCtx() + worker.pooler.running = true visible = true; } diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index c7532c840..11c54fe6b 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -19,6 +19,7 @@ Item property alias gasPriceInt: gasPriceInt property variant balances: ({}) property variant accounts: [] + property alias pooler: pooler signal gasPriceLoaded() function renewCtx() @@ -193,7 +194,8 @@ Item id: codeModelGasEstimation } - ClientModel { + ClientModel + { id: clientModelGasEstimation codeModel: codeModelGasEstimation Component.onCompleted: @@ -202,6 +204,14 @@ Item } } + Timer + { + id: pooler + interval: 5000 + repeat: true + running: false + } + Timer { id: poolLog diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index e275e1434..3201b9827 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -32,6 +32,14 @@ Rectangle { visible = true + worker.pooler.onTriggered.connect(function() { + if (root.visible) + verifyRegistering(); + }) + } + + function verifyRegistering() + { verificationEthUrl.text = "" if (projectModel.registerContentHashTrHash !== "" && projectModel.registerContentHashBlockNumber !== -1) { From 4ff552d006433bb8aa41ec5f51dfa1eb247efc2e Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 27 Jul 2015 16:59:45 +0200 Subject: [PATCH 07/18] minor update --- test/libwhisper/whisperTopic.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/test/libwhisper/whisperTopic.cpp b/test/libwhisper/whisperTopic.cpp index e8bd48946..bf15a14c9 100644 --- a/test/libwhisper/whisperTopic.cpp +++ b/test/libwhisper/whisperTopic.cpp @@ -348,13 +348,9 @@ BOOST_AUTO_TEST_CASE(topicAdvertising) { sessions = whost1->peerSessions(); if (!sessions.empty()) - { bf1 = sessions.back().first->cap()->bloom(); - if (bf1) - break; - } - this_thread::sleep_for(chrono::milliseconds(10)); + this_thread::sleep_for(chrono::milliseconds(step)); } BOOST_REQUIRE(sessions.size()); @@ -364,18 +360,15 @@ BOOST_AUTO_TEST_CASE(topicAdvertising) BOOST_REQUIRE(!whost1->bloom()); unsigned w1 = whost1->installWatch(BuildTopicMask("test1")); + bf2 = TopicBloomFilterHash(); - for (int i = 0; i < 600; ++i) + for (int i = 0; i < 600 && !bf2; ++i) { sessions = whost2->peerSessions(); if (!sessions.empty()) - { bf2 = sessions.back().first->cap()->bloom(); - if (bf2) - break; - } - this_thread::sleep_for(chrono::milliseconds(10)); + this_thread::sleep_for(chrono::milliseconds(step)); } BOOST_REQUIRE(sessions.size()); From 43a39fae07f77ce77bba6aa34cd11d6e5b3c54d5 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 28 Jul 2015 11:18:06 +0200 Subject: [PATCH 08/18] bug fix (when deploying a contract which has not been opened) --- mix/qml/DeploymentWorker.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index 11c54fe6b..76e981d8c 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -170,10 +170,11 @@ Item { if (!clientModelGasEstimation.running) { - var ctr = projectModel.codeEditor.getContracts() - for (var k in ctr) + for (var si = 0; si < projectModel.listModel.count; si++) { - codeModelGasEstimation.registerCodeChange(ctr[k].document.documentId, ctr[k].getText()); + var document = projectModel.listModel.get(si); + if (document.isContract) + codeModelGasEstimation.registerCodeChange(document.documentId, fileIo.readFile(document.path)); } gasEstimationConnect.callback = callback clientModelGasEstimation.setupScenario(scenario) From 1aa2cbd180a9b4edbfa03004dc703b4c9ff577dc Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 28 Jul 2015 15:30:25 +0200 Subject: [PATCH 09/18] readd stateList, genesisContract, Startting parameters --- mix/ClientModel.cpp | 18 ++- mix/qml/Application.qml | 8 +- mix/qml/Block.qml | 4 +- mix/qml/BlockChain.qml | 52 ++++++- mix/qml/DeployContractStep.qml | 3 +- mix/qml/ScenarioExecution.qml | 5 +- mix/qml/ScenarioLoader.qml | 48 +++++-- mix/qml/StateDialog.qml | 241 ++------------------------------- mix/qml/StateList.qml | 15 +- mix/qml/StateListModel.qml | 29 ++-- 10 files changed, 147 insertions(+), 276 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index ab15f55ca..7bc25fd3f 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -81,7 +81,7 @@ ClientModel::ClientModel(): qRegisterMetaType("QInstruction"); qRegisterMetaType("QCode"); qRegisterMetaType("QCallData"); - qRegisterMetaType("RecordLogEntry*"); + qRegisterMetaType("RecordLogEntry*"); } ClientModel::~ClientModel() @@ -236,6 +236,7 @@ void ClientModel::setupScenario(QVariantMap _scenario) QVariantList blocks = _scenario.value("blocks").toList(); QVariantList stateAccounts = _scenario.value("accounts").toList(); + QVariantList stateContracts = _scenario.value("contracts").toList(); m_accounts.clear(); m_accountsSecret.clear(); @@ -258,6 +259,19 @@ void ClientModel::setupScenario(QVariantMap _scenario) } m_ethAccounts->setAccounts(m_accountsSecret); + for (auto const& c: stateContracts) + { + QVariantMap contract = c.toMap(); + Address address = Address(fromHex(contract.value("address").toString().toStdString())); + Account account(qvariant_cast(contract.value("balance"))->toU256Wei(), Account::ContractConception); + bytes code = fromHex(contract.value("code").toString().toStdString()); + account.setCode(std::move(code)); + QVariantMap storageMap = contract.value("storage").toMap(); + for(auto s = storageMap.cbegin(); s != storageMap.cend(); ++s) + account.setStorage(fromBigEndian(fromHex(s.key().toStdString())), fromBigEndian(fromHex(s.value().toString().toStdString()))); + m_accounts[address] = account; + } + bool trToExecute = false; for (auto const& b: blocks) { @@ -891,7 +905,7 @@ void ClientModel::onNewTransaction() QVariantMap accountBalances; for (auto const& ctr : m_contractAddresses) { - u256 wei = m_client->balanceAt(ctr.second, PendingBlock); + u256 wei = m_client->balanceAt(ctr.second, PendingBlock); accountBalances.insert("0x" + QString::fromStdString(ctr.second.hex()), QEther(wei, QEther::Wei).format()); } for (auto const& account : m_accounts) diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index 5ae12b816..188d87be9 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -108,12 +108,14 @@ ApplicationWindow { title: qsTr("Deploy") MenuItem { action: mineAction } MenuSeparator {} - MenuItem { action: editStatesAction } - MenuSeparator {} MenuItem { action: deployViaRpcAction } MenuSeparator {} MenuItem { action: toggleRunOnLoadAction } } + Menu { + title: qsTr("Scenario") + MenuItem { action: editStatesAction } + } Menu { title: qsTr("Debug") MenuItem { action: debugRunAction } @@ -184,7 +186,7 @@ ApplicationWindow { Action { id: editStatesAction - text: qsTr("Edit States") + text: qsTr("Edit Scenarii") shortcut: "Ctrl+Alt+E" onTriggered: stateList.open(); } diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index 383cb85e8..532e348d7 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -22,6 +22,7 @@ ColumnLayout property int blockIndex property variant scenario property string labelColor: "#414141" + property int scenarioIndex signal txSelected(var txIndex) function calculateHeight() @@ -105,13 +106,14 @@ ColumnLayout anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 14 - visible: false + visible: number === -2 MouseArea { anchors.fill: parent onClicked: { // load edit block panel + projectModel.stateListModel.editState(scenarioIndex) } } } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 41c65553a..25793a35f 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -16,6 +16,7 @@ ColumnLayout { property alias trDialog: transactionDialog property alias blockChainRepeater: blockChainRepeater property variant model + property int scenarioIndex property var states: ({}) spacing: 0 property int previousWidth @@ -26,6 +27,25 @@ ColumnLayout { signal rebuilding signal accountAdded(string address, string amount) + Connections + { + target: projectModel.stateListModel + onAccountsValidated: + { + if (rebuild.accountsSha3 !== codeModel.sha3(JSON.stringify(_accounts))) + rebuild.needRebuild("AccountsChanged") + else + rebuild.notNeedRebuild("AccountsChanged") + } + onContractsValidated: + { + if (rebuild.contractsSha3 !== codeModel.sha3(JSON.stringify(_contracts))) + rebuild.needRebuild("ContractsChanged") + else + rebuild.notNeedRebuild("ContractsChanged") + } + } + Connections { target: codeModel @@ -94,13 +114,15 @@ ColumnLayout { return states[record] } - function load(scenario) + function load(scenario, index) { if (!scenario) return; if (model) rebuild.startBlinking() model = scenario + scenarioIndex = index + genesis.scenarioIndex = index states = [] blockModel.clear() for (var b in model.blocks) @@ -138,6 +160,20 @@ ColumnLayout { width: parent.width spacing: 20 + Block + { + id: genesis + scenario: blockChainPanel.model + scenarioIndex: scenarioIndex + Layout.preferredWidth: blockChainScrollView.width + Layout.preferredHeight: 60 + blockIndex: -1 + transactions: [] + status: "" + number: -2 + trHeight: 60 + } + Repeater // List of blocks { id: blockChainRepeater @@ -264,6 +300,8 @@ ColumnLayout { roundRight: true property variant contractsHex: ({}) property variant txSha3: ({}) + property variant accountsSha3 + property variant contractsSha3 property variant txChanged: [] property var blinkReasons: [] @@ -352,10 +390,22 @@ ColumnLayout { ensureNotFuturetime.start() takeCodeSnapshot() takeTxSnaphot() + takeAccountsSnapshot() + takeContractsSnapShot() blinkReasons = [] clientModel.setupScenario(model); } + function takeContractsSnapShot() + { + contractsSha3 = codeModel.sha3(JSON.stringify(model.contracts)) + } + + function takeAccountsSnapshot() + { + accountsSha3 = codeModel.sha3(JSON.stringify(model.accounts)) + } + function takeCodeSnapshot() { contractsHex = {} diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 39881879c..9bdcd765c 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -490,7 +490,8 @@ Rectangle { id: clearDeployAction onTriggered: { worker.forceStopPooling() - fileIo.deleteDir(projectModel.deploymentDir) + if (projectModel.deploymentDir && projectModel.deploymentDir !== "") + fileIo.deleteDir(projectModel.deploymentDir) projectModel.cleanDeploymentStatus() deploymentDialog.steps.reset() } diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index 00c09f4cf..9b4bcd39f 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -70,7 +70,7 @@ Rectangle { onLoaded: { watchers.clear() - blockChain.load(scenario) + blockChain.load(scenario, loader.selectedScenarioIndex) } } @@ -91,7 +91,8 @@ Rectangle { updateWatchers(blockIndex, txIndex) } - function updateWatchers(blockIndex, txIndex){ + function updateWatchers(blockIndex, txIndex) + { var tx = blockChain.model.blocks[blockIndex].transactions[txIndex] var state = blockChain.getState(tx.recordIndex) watchers.updateWidthTx(tx, state, blockIndex, txIndex) diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 5b8cb2d70..24b5962c1 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -20,6 +20,7 @@ ColumnLayout signal loaded(variant scenario) signal renamed(variant scenario) signal deleted() + property alias selectedScenarioIndex: scenarioList.currentIndex spacing: 0 function init() { @@ -80,15 +81,14 @@ ColumnLayout } } - Label - { - anchors.left: editImg.right - text: "X" - height: parent.height - color: "#cccccc" + Image { + source: "qrc:/qml/img/delete_sign.png" + height: parent.height - 16 + fillMode: Image.PreserveAspectFit id: deleteImg + anchors.left: editImg.right anchors.top: parent.top - anchors.topMargin: 7 + anchors.topMargin: 8 visible: projectModel.stateListModel.count > 1 MouseArea { @@ -98,13 +98,37 @@ ColumnLayout if (projectModel.stateListModel.count > 1) { projectModel.stateListModel.deleteState(scenarioList.currentIndex) - scenarioList.currentIndex = 0 - deleted() + scenarioList.init() + } + } + } + } + + Label + { + + MouseArea + { + anchors.fill: parent + onClicked: + { + if (projectModel.stateListModel.count > 1) + { + projectModel.stateListModel.deleteState(scenarioList.currentIndex) + scenarioList.init() } } } } + Connections + { + target: projectModel.stateListModel + onStateDeleted: { + scenarioList.init() + } + } + ComboBox { id: scenarioList @@ -122,6 +146,12 @@ ColumnLayout restoreScenario.restore() } + function init() + { + scenarioList.currentIndex = 0 + deleted() + } + function load() { var state = projectModel.stateListModel.getState(currentIndex) diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 404a524f4..56be75a09 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -18,12 +18,8 @@ Dialog { title: qsTr("Edit State") visible: false - property alias stateTitle: titleField.text property alias isDefault: defaultCheckBox.checked - property alias model: transactionsModel - property alias transactionDialog: transactionDialog property alias minerComboBox: comboMiner - property alias newAccAction: newAccountAction property int stateIndex property var stateTransactions: [] property var stateAccounts: [] @@ -36,16 +32,6 @@ Dialog { function open(index, item, setDefault) { stateIndex = index - stateTitle = item.title - transactionsModel.clear() - - stateTransactions = [] - var transactions = item.transactions - for (var t = 0; t < transactions.length; t++) { - transactionsModel.append(item.transactions[t]) - stateTransactions.push(item.transactions[t]) - } - accountsModel.clear() stateAccounts = [] var miner = 0 @@ -66,8 +52,8 @@ Dialog { visible = true isDefault = setDefault - titleField.focus = true - defaultCheckBox.enabled = !isDefault + console.log(isDefault) + defaultCheckBox.checked = isDefault comboMiner.model = stateAccounts comboMiner.currentIndex = miner forceActiveFocus() @@ -84,8 +70,6 @@ Dialog { function getItem() { var item = { - title: stateDialog.stateTitle, - transactions: stateTransactions, accounts: stateAccounts, contracts: stateContracts } @@ -95,6 +79,7 @@ Dialog { break } } + item.defaultState = defaultCheckBox.checked return item } @@ -111,21 +96,6 @@ Dialog { ColumnLayout { id: dialogContent anchors.top: parent.top - RowLayout { - Layout.fillWidth: true - DefaultLabel { - Layout.preferredWidth: 85 - text: qsTr("Title") - } - DefaultTextField { - id: titleField - Layout.fillWidth: true - } - } - - CommonSeparator { - Layout.fillWidth: true - } RowLayout { Layout.fillWidth: true @@ -258,30 +228,6 @@ Dialog { Layout.preferredWidth: 85 text: qsTr("Accounts") } - - Button { - id: newAccountButton - anchors.top: accountsLabel.bottom - anchors.topMargin: 10 - iconSource: "qrc:/qml/img/plus.png" - action: newAccountAction - } - - Action { - id: newAccountAction - tooltip: qsTr("Add new Account") - onTriggered: { - add() - } - - function add() { - var account = stateListModel.newAccount( - "1000000", QEther.Ether) - stateAccounts.push(account) - accountsModel.append(account) - return account - } - } } MessageDialog { @@ -313,21 +259,8 @@ Dialog { id: deleteAccountAction tooltip: qsTr("Delete Account") onTriggered: { - if (transactionsModel.isUsed( - stateAccounts[styleData.row].secret)) - alertAlreadyUsed.open() - else { - if (stateAccounts[styleData.row].name - === comboMiner.currentText) - comboMiner.currentIndex = 0 - stateAccounts.splice( - styleData.row, - 1) - accountsModel.remove( - styleData.row) - comboMiner.model = stateAccounts //TODO: filter accounts wo private keys - comboMiner.update() - } + stateAccounts.splice(styleData.row, 1) + accountsView.model.remove(styleData.row) } } @@ -405,115 +338,17 @@ Dialog { Layout.fillWidth: true } - RowLayout { - Layout.fillWidth: true - - Rectangle { - Layout.preferredWidth: 85 - DefaultLabel { - id: transactionsLabel - Layout.preferredWidth: 85 - text: qsTr("Transactions") - } - - Button { - anchors.top: transactionsLabel.bottom - anchors.topMargin: 10 - iconSource: "qrc:/qml/img/plus.png" - action: newTrAction - } - - Action { - id: newTrAction - tooltip: qsTr("Create a new transaction") - onTriggered: transactionsModel.addTransaction() - } - } - - TableView { - id: transactionsView - Layout.fillWidth: true - model: transactionsModel - headerVisible: false - TableViewColumn { - role: "label" - title: qsTr("Name") - width: 150 - delegate: Item { - RowLayout { - height: 30 - width: parent.width - Button { - iconSource: "qrc:/qml/img/delete_sign.png" - action: deleteTransactionAction - } - - Action { - id: deleteTransactionAction - tooltip: qsTr("Delete") - onTriggered: transactionsModel.deleteTransaction( - styleData.row) - } - - Button { - iconSource: "qrc:/qml/img/edit.png" - action: editAction - visible: styleData.row - >= 0 ? !transactionsModel.get( - styleData.row).stdContract : false - width: 10 - height: 10 - Action { - id: editAction - tooltip: qsTr("Edit") - onTriggered: transactionsModel.editTransaction( - styleData.row) - } - } - - DefaultLabel { - Layout.preferredWidth: 150 - text: { - if (styleData.row >= 0) - return transactionsModel.get( - styleData.row).label - else - return "" - } - } - } - } - } - rowDelegate: Rectangle { - color: styleData.alternate ? "transparent" : "#f0f0f0" - height: 30 - } - } - } } RowLayout { anchors.bottom: parent.bottom anchors.right: parent.right - Button { - text: qsTr("Delete") - enabled: !modalStateDialog.isDefault - onClicked: { - projectModel.stateListModel.deleteState(stateIndex) - close() - } - } Button { text: qsTr("OK") onClicked: { - if (titleField.text === "") - alertDialog.open() - else - { - close() - accepted() - } + close() + accepted() } } Button { @@ -522,21 +357,6 @@ Dialog { } } - MessageDialog - { - id: alertDialog - text: qsTr("Please provide a name.") - } - - ListModel { - id: accountsModel - - function removeAccount(_i) { - accountsModel.remove(_i) - stateAccounts.splice(_i, 1) - } - } - ListModel { id: contractsModel @@ -547,50 +367,11 @@ Dialog { } ListModel { - id: transactionsModel - - function editTransaction(index) { - transactionDialog.stateAccounts = stateAccounts - transactionDialog.open(index, - transactionsModel.get(index)) - } - - function addTransaction() { - // Set next id here to work around Qt bug - // https://bugreports.qt-project.org/browse/QTBUG-41327 - // Second call to signal handler would just edit the item that was just created, no harm done - var item = TransactionHelper.defaultTransaction() - transactionDialog.stateAccounts = stateAccounts - transactionDialog.open(transactionsModel.count, item) - } - - function deleteTransaction(index) { - stateTransactions.splice(index, 1) - transactionsModel.remove(index) - } - - function isUsed(secret) { - for (var i in stateTransactions) { - if (stateTransactions[i].sender === secret) - return true - } - return false - } - } + id: accountsModel - TransactionDialog { - id: transactionDialog - onAccepted: { - var item = transactionDialog.getItem() - if (transactionDialog.transactionIndex < transactionsModel.count) { - transactionsModel.set( - transactionDialog.transactionIndex, - item) - stateTransactions[transactionDialog.transactionIndex] = item - } else { - transactionsModel.append(item) - stateTransactions.push(item) - } + function removeAccount(_i) { + accountsModel.remove(_i) + stateAccounts.splice(_i, 1) } } } diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index 39567feac..3558350b7 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -27,7 +27,7 @@ Dialog { frameVisible: false TableViewColumn { role: "title" - title: qsTr("State") + title: qsTr("Scenario") width: list.width } } @@ -71,25 +71,12 @@ Dialog { Layout.fillHeight: true onClicked: list.model.deleteState(styleData.row); } - ToolButton { - text: qsTr("Run"); - Layout.fillHeight: true - onClicked: list.model.runState(styleData.row); - } } } } Row { - Action { - id: addStateAction - text: qsTr("Add State") - shortcut: "Ctrl+T" - enabled: codeModel.hasContract && !clientModel.running; - onTriggered: list.model.addState(); - } - Action { id: closeAction text: qsTr("Close") diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index efa52f853..b55781396 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -222,20 +222,19 @@ Item { function saveState(item) { - if (stateDialog.stateIndex < stateListModel.count) { - if (stateDialog.isDefault) - stateListModel.defaultStateIndex = stateIndex; - stateList[stateDialog.stateIndex] = item; - stateListModel.set(stateDialog.stateIndex, item); - } else { - if (stateDialog.isDefault) - stateListModel.defaultStateIndex = 0; - stateList.push(item); - stateListModel.append(item); + stateList[stateDialog.stateIndex].accounts = item.accounts + stateList[stateDialog.stateIndex].contracts = item.contracts + stateListModel.get(stateDialog.stateIndex).accounts = item.accounts + stateListModel.get(stateDialog.stateIndex).contracts = item.contracts + stateListModel.accountsValidated(item.accounts) + stateListModel.contractsValidated(item.contracts) + stateListModel.get(stateDialog.stateIndex).miner = item.miner + stateList[stateDialog.stateIndex].miner = item.miner + if (item.defaultState) + { + stateListModel.defaultStateIndex = stateDialog.stateIndex + stateListModel.defaultStateChanged() } - if (stateDialog.isDefault) - stateListModel.defaultStateChanged(); - stateListModel.save(); } } @@ -243,6 +242,8 @@ Item { id: stateListModel property int defaultStateIndex: 0 property variant data + signal accountsValidated(var _accounts) + signal contractsValidated(var _contracts) signal defaultStateChanged; signal stateListModelReady; signal stateRun(int index) @@ -367,6 +368,8 @@ Item { } function editState(index) { + console.log(index) + console.log(defaultStateIndex) stateDialog.open(index, stateList[index], defaultStateIndex === index); } From b8c01de80b234aa4ca0736d207bea251125748e4 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 28 Jul 2015 16:54:14 +0200 Subject: [PATCH 10/18] autoselect transaction --- mix/qml/Block.qml | 28 +++++++++++++++++++++------- mix/qml/BlockChain.qml | 7 +++++++ mix/qml/ScenarioExecution.qml | 3 ++- mix/qml/StateList.qml | 4 ---- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index 532e348d7..de606a6c0 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -46,6 +46,11 @@ ColumnLayout transactionDialog.open(txIndex, blockIndex, transactions.get(txIndex)) } + function select(txIndex) + { + transactionRepeater.itemAt(txIndex).select() + } + onOpenedTrChanged: { Layout.preferredHeight = calculateHeight() @@ -129,6 +134,12 @@ ColumnLayout id: rowTransaction Layout.preferredHeight: trHeight spacing: 0 + + function select() + { + rowContentTr.select() + } + function displayContent() { logsText.text = "" @@ -222,6 +233,15 @@ ColumnLayout } } + function select() + { + rowContentTr.selected = true + rowContentTr.color = "#4F4F4F" + hash.color = "#EAB920" + func.color = "#EAB920" + txSelected(index) + } + function deselect() { rowContentTr.selected = false @@ -235,13 +255,7 @@ ColumnLayout anchors.fill: parent onClicked: { if (!rowContentTr.selected) - { - rowContentTr.selected = true - rowContentTr.color = "#4F4F4F" - hash.color = "#EAB920" - func.color = "#EAB920" - txSelected(index) - } + rowContentTr.select() else rowContentTr.deselect() diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 25793a35f..2c247d282 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -184,6 +184,11 @@ ColumnLayout { itemAt(blockIndex).editTx(txIndex) } + function select(blockIndex, txIndex) + { + itemAt(blockIndex).select(txIndex) + } + Block { Connections @@ -569,6 +574,7 @@ ColumnLayout { trModel.sender = _r.sender trModel.returnParameters = _r.returnParameters blockModel.setTransaction(blockIndex, trIndex, trModel) + blockChainRepeater.select(blockIndex, trIndex) return; } } @@ -590,6 +596,7 @@ ColumnLayout { itemTr.returnParameters = _r.returnParameters model.blocks[model.blocks.length - 1].transactions.push(itemTr) blockModel.appendTransaction(itemTr) + blockChainRepeater.select(blockIndex, trIndex) } onNewState: { diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index 9b4bcd39f..dde32fa97 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -85,7 +85,8 @@ Rectangle { target: blockChain property var currentSelectedBlock property var currentSelectedTx - onTxSelected: { + onTxSelected: + { currentSelectedBlock = blockIndex currentSelectedTx = txIndex updateWatchers(blockIndex, txIndex) diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index 3558350b7..e081947e2 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -37,10 +37,6 @@ Dialog { anchors.bottom: parent.bottom anchors.right: parent.right anchors.rightMargin: 10 - Button { - action: addStateAction - } - Button { action: closeAction } From b5f9eb4cc695d6640ed85ad0bcab4a94cafae402 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 28 Jul 2015 16:57:27 +0200 Subject: [PATCH 11/18] small changes --- mix/qml/StateListModel.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index b55781396..f144560cf 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -368,8 +368,6 @@ Item { } function editState(index) { - console.log(index) - console.log(defaultStateIndex) stateDialog.open(index, stateList[index], defaultStateIndex === index); } From 1b558a07d9ae49dfd00592d7ec8d8d1c4eb3e624 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 28 Jul 2015 17:15:47 +0200 Subject: [PATCH 12/18] small ui changes --- mix/qml/Block.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index de606a6c0..be540919a 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -96,7 +96,7 @@ ColumnLayout text: { if (number === -2) - return qsTr("STARTING PARAMETERS") + return qsTr("GENESIS PARAMETERS") else if (status === "mined") return qsTr("BLOCK") + " " + number else From 2565fe1fa70368f4b2e6741f612219f51de70a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Jul 2015 15:10:41 +0200 Subject: [PATCH 13/18] Fix EVM JIT stack limit checking. Tests inlcuded. --- evmjit/libevmjit/BasicBlock.cpp | 3 +- evmjit/libevmjit/BasicBlock.h | 3 +- .../vmIOandFlowOperationsTestFiller.json | 76 ++++++++++++++++++- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index a41743d0b..be57a28b8 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -49,7 +49,7 @@ void BasicBlock::LocalStack::push(llvm::Value* _value) assert(_value->getType() == Type::Word); m_bblock.m_currentStack.push_back(_value); m_bblock.m_tosOffset += 1; - m_maxSize = std::max(m_maxSize, m_bblock.m_currentStack.size()); + m_maxSize = std::max(m_maxSize, m_bblock.m_tosOffset); } llvm::Value* BasicBlock::LocalStack::pop() @@ -388,4 +388,3 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) } } } - diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 321499196..ddf73a04c 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -52,7 +52,7 @@ public: private: BasicBlock& m_bblock; - size_t m_maxSize = 0; ///< Max size reached by the stack. + int m_maxSize = 0; ///< Max size reached by the stack. }; explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); @@ -127,4 +127,3 @@ private: } } } - diff --git a/test/libevm/VMTestsFiller/vmIOandFlowOperationsTestFiller.json b/test/libevm/VMTestsFiller/vmIOandFlowOperationsTestFiller.json index ee68f0d67..ece519112 100644 --- a/test/libevm/VMTestsFiller/vmIOandFlowOperationsTestFiller.json +++ b/test/libevm/VMTestsFiller/vmIOandFlowOperationsTestFiller.json @@ -140,7 +140,7 @@ "0x01" : "0x17" } } - }, + }, "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "100000000000000000000000", @@ -1372,6 +1372,76 @@ } }, + "loop_stacklimit_1020": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "storage" : { + "0x02" : "0x23" + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "100000000000000000000000", + "nonce" : "0", + "code" : "(asm 0 CALLVALUE JUMPDEST 1 SWAP1 SUB SWAP1 1 ADD DUP2 DUP1 3 JUMPI 0 MSTORE 1 MSTORE 0 MSIZE RETURN)", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1020", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "100000" + } + }, + + "loop_stacklimit_1021": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "storage" : { + "0x02" : "0x23" + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "100000000000000000000000", + "nonce" : "0", + "code" : "(asm 0 CALLVALUE JUMPDEST 1 SWAP1 SUB SWAP1 1 ADD DUP2 DUP1 3 JUMPI 0 MSTORE 1 MSTORE 0 MSIZE RETURN)", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1021", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "100000" + } + }, + "jump0_withoutJumpdest": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -2226,7 +2296,7 @@ "0x03" : "0x02" } } - }, + }, "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "100000000000000000000000", @@ -3939,7 +4009,7 @@ "gas" : "100000" } }, - + "jumpi_at_the_end" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", From 7704698d294159b008a6cb0ec5ca0fce17c5edb6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jul 2015 11:34:37 +0200 Subject: [PATCH 14/18] Make Nonce use Secret. --- libdevcore/CommonIO.cpp | 8 ++++++++ libdevcore/CommonIO.h | 2 ++ libdevcrypto/Common.cpp | 16 ++++++++-------- libdevcrypto/Common.h | 24 +++++++++++++++++------- test/libp2p/rlpx.cpp | 24 ++++++++++++------------ 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 067d75559..9137e1750 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -91,6 +91,14 @@ bytes dev::contents(string const& _file) return contentsGeneric(_file); } +bytesSec dev::contentsSec(string const& _file) +{ + bytes b = contentsGeneric(_file); + bytesSec ret(b); + bytesRef(&b).cleanse(); + return ret; +} + string dev::contentsString(string const& _file) { return contentsGeneric(_file); diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index da0f6a963..1b4af178e 100644 --- a/libdevcore/CommonIO.h +++ b/libdevcore/CommonIO.h @@ -48,6 +48,8 @@ std::string getPassword(std::string const& _prompt); /// Retrieve and returns the contents of the given file. /// If the file doesn't exist or isn't readable, returns an empty container / bytes. bytes contents(std::string const& _file); +/// Secure variation. +bytesSec contentsSec(std::string const& _file); /// Retrieve and returns the contents of the given file as a std::string. /// If the file doesn't exist or isn't readable, returns an empty container / bytes. std::string contentsString(std::string const& _file); diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 2854db062..e7304f3f9 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -150,7 +150,7 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) std::pair dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain) { - h128 iv(Nonce::get()); + h128 iv(Nonce::get().makeInsecure()); return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); } @@ -312,7 +312,7 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) mutex Nonce::s_x; static string s_seedFile; -h256 Nonce::get() +Secret Nonce::get() { // todo: atomic efface bit, periodic save, kdf, rr, rng // todo: encrypt @@ -350,11 +350,11 @@ void Nonce::initialiseIfNeeded() if (m_value) return; - bytes b = contents(seedFile()); + bytesSec b = contentsSec(seedFile()); if (b.size() == 32) - memcpy(m_value.data(), b.data(), 32); + b.ref().populate(m_value.writable().ref()); else - m_value = h256::random(); + m_value = Secret::random(); if (!m_value) BOOST_THROW_EXCEPTION(InvalidState()); @@ -363,7 +363,7 @@ void Nonce::initialiseIfNeeded() writeFile(seedFile(), bytes()); } -h256 Nonce::next() +Secret Nonce::next() { initialiseIfNeeded(); m_value = sha3(m_value); @@ -374,8 +374,8 @@ void Nonce::resetInternal() { // this might throw next(); - writeFile(seedFile(), m_value.asBytes()); - m_value = h256(); + writeFile(seedFile(), m_value.ref()); + m_value.clear(); } string const& Nonce::seedFile() diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c90481cb4..426c9cc3d 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -181,7 +181,8 @@ private: namespace crypto { -struct InvalidState: public dev::Exception {}; + +DEV_SIMPLE_EXCEPTION(InvalidState); /// Key derivation h256 kdf(Secret const& _priv, h256 const& _hash); @@ -189,35 +190,44 @@ h256 kdf(Secret const& _priv, h256 const& _hash); /** * @brief Generator for nonce material. */ -struct Nonce +class Nonce { +public: /// Returns the next nonce (might be read from a file). - static h256 get(); + static Secret get(); + /// Stores the current nonce in a file and resets Nonce to the uninitialised state. static void reset(); + /// Sets the location of the seed file to a non-default place. Used for testing. static void setSeedFilePath(std::string const& _filePath); private: - Nonce() {} + Nonce() = default; ~Nonce(); + /// @returns the singleton instance. static Nonce& singleton(); + /// Reads the last seed from the seed file. void initialiseIfNeeded(); + /// @returns the next nonce. - h256 next(); + Secret next(); + /// Stores the current seed in the seed file. void resetInternal(); + /// @returns the path of the seed file. static std::string const& seedFile(); + Secret m_value; + /// Mutex for the singleton object. /// @note Every access to any private function has to be guarded by this mutex. static std::mutex s_x; - - h256 m_value; }; + } } diff --git a/test/libp2p/rlpx.cpp b/test/libp2p/rlpx.cpp index e03c6a296..c50857007 100644 --- a/test/libp2p/rlpx.cpp +++ b/test/libp2p/rlpx.cpp @@ -455,12 +455,12 @@ BOOST_AUTO_TEST_CASE(ecies_interop_test_primitives) BOOST_AUTO_TEST_CASE(segmentedPacketFlush) { ECDHE localEph; - h256 localNonce = Nonce::get(); + Secret localNonce = Nonce::get(); ECDHE remoteEph; - h256 remoteNonce = Nonce::get(); + Secret remoteNonce = Nonce::get(); bytes ackCipher{0}; bytes authCipher{1}; - RLPXFrameCoder encoder(true, remoteEph.pubkey(), remoteNonce, localEph, localNonce, &ackCipher, &authCipher); + RLPXFrameCoder encoder(true, remoteEph.pubkey(), remoteNonce.makeInsecure(), localEph, localNonce.makeInsecure(), &ackCipher, &authCipher); /// Test writing a 64byte RLPStream and drain with frame size that /// forces packet to be pieced into 4 frames. @@ -506,7 +506,7 @@ BOOST_AUTO_TEST_CASE(segmentedPacketFlush) } // read and assemble dequed encframes - RLPXFrameCoder decoder(false, localEph.pubkey(), localNonce, remoteEph, remoteNonce, &ackCipher, &authCipher); + RLPXFrameCoder decoder(false, localEph.pubkey(), localNonce.makeInsecure(), remoteEph, remoteNonce.makeInsecure(), &ackCipher, &authCipher); vector packets; RLPXFrameReader r(0); for (size_t i = 0; i < encframes.size(); i++) @@ -529,12 +529,12 @@ BOOST_AUTO_TEST_CASE(segmentedPacketFlush) BOOST_AUTO_TEST_CASE(coalescedPacketsPadded) { ECDHE localEph; - h256 localNonce = Nonce::get(); + Secret localNonce = Nonce::get(); ECDHE remoteEph; - h256 remoteNonce = Nonce::get(); + Secret remoteNonce = Nonce::get(); bytes ackCipher{0}; bytes authCipher{1}; - RLPXFrameCoder encoder(true, remoteEph.pubkey(), remoteNonce, localEph, localNonce, &ackCipher, &authCipher); + RLPXFrameCoder encoder(true, remoteEph.pubkey(), remoteNonce.makeInsecure(), localEph, localNonce.makeInsecure(), &ackCipher, &authCipher); /// Test writing four 32 byte RLPStream packets such that /// a single 1KB frame will incldue all four packets. @@ -559,7 +559,7 @@ BOOST_AUTO_TEST_CASE(coalescedPacketsPadded) BOOST_REQUIRE_EQUAL(expectedFrameSize, encframes[0].size()); // read and assemble dequed encframes - RLPXFrameCoder decoder(false, localEph.pubkey(), localNonce, remoteEph, remoteNonce, &ackCipher, &authCipher); + RLPXFrameCoder decoder(false, localEph.pubkey(), localNonce.makeInsecure(), remoteEph, remoteNonce.makeInsecure(), &ackCipher, &authCipher); vector packets; RLPXFrameReader r(0); bytesRef frameWithHeader(encframes[0].data(), encframes[0].size()); @@ -587,12 +587,12 @@ BOOST_AUTO_TEST_CASE(coalescedPacketsPadded) BOOST_AUTO_TEST_CASE(singleFramePacketFlush) { ECDHE localEph; - h256 localNonce = Nonce::get(); + Secret localNonce = Nonce::get(); ECDHE remoteEph; - h256 remoteNonce = Nonce::get(); + Secret remoteNonce = Nonce::get(); bytes ackCipher{0}; bytes authCipher{1}; - RLPXFrameCoder encoder(true, remoteEph.pubkey(), remoteNonce, localEph, localNonce, &ackCipher, &authCipher); + RLPXFrameCoder encoder(true, remoteEph.pubkey(), remoteNonce.makeInsecure(), localEph, localNonce.makeInsecure(), &ackCipher, &authCipher); /// Test writing four 32 byte RLPStream packets such that /// a single 1KB frame will incldue all four packets. @@ -611,7 +611,7 @@ BOOST_AUTO_TEST_CASE(singleFramePacketFlush) BOOST_REQUIRE_EQUAL(dequeLen, encframes[0].size()); // read and assemble dequed encframes - RLPXFrameCoder decoder(false, localEph.pubkey(), localNonce, remoteEph, remoteNonce, &ackCipher, &authCipher); + RLPXFrameCoder decoder(false, localEph.pubkey(), localNonce.makeInsecure(), remoteEph, remoteNonce.makeInsecure(), &ackCipher, &authCipher); vector packets; RLPXFrameReader r(0); bytesRef frameWithHeader(encframes[0].data(), encframes[0].size()); From 0c8f4d4e1109751fa5b89c3afd23abf2d0fa3125 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Jul 2015 15:44:53 +0200 Subject: [PATCH 15/18] Store the response as a string. --- libjsconsole/JSV8Connector.cpp | 2 +- libjsconsole/JSV8Connector.h | 17 +++++++++------ libjsconsole/JSV8RemoteConnector.cpp | 29 +++++++++++++++++++------ libjsconsole/JSV8RemoteConnector.h | 32 ++++++++++++++++++++++------ libjsengine/JSEngine.h | 2 ++ libjsengine/JSPrinter.h | 2 ++ libjsengine/JSV8Engine.h | 2 ++ libjsengine/JSV8Printer.h | 2 ++ libjsengine/JSV8RPC.cpp | 8 ------- libjsengine/JSV8RPC.h | 8 +++---- 10 files changed, 72 insertions(+), 32 deletions(-) diff --git a/libjsconsole/JSV8Connector.cpp b/libjsconsole/JSV8Connector.cpp index ed560a368..12fbe0bae 100644 --- a/libjsconsole/JSV8Connector.cpp +++ b/libjsconsole/JSV8Connector.cpp @@ -39,7 +39,7 @@ bool JSV8Connector::StopListening() bool JSV8Connector::SendResponse(std::string const& _response, void* _addInfo) { (void)_addInfo; - m_lastResponse = _response.c_str(); + m_lastResponse = _response; return true; } diff --git a/libjsconsole/JSV8Connector.h b/libjsconsole/JSV8Connector.h index 34c38fed1..1a908e885 100644 --- a/libjsconsole/JSV8Connector.h +++ b/libjsconsole/JSV8Connector.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include @@ -30,20 +31,24 @@ namespace dev namespace eth { -class JSV8Connector: public jsonrpc::AbstractServerConnector, public JSV8RPC +class JSV8Connector: public jsonrpc::AbstractServerConnector, private JSV8RPC { - public: JSV8Connector(JSV8Engine const& _engine): JSV8RPC(_engine) {} virtual ~JSV8Connector(); // implement AbstractServerConnector interface - bool StartListening(); - bool StopListening(); - bool SendResponse(std::string const& _response, void* _addInfo = nullptr); + bool StartListening() override; + bool StopListening() override; + bool SendResponse(std::string const& _response, void* _addInfo = nullptr) override; +private: // implement JSV8RPC interface - void onSend(char const* _payload); + void onSend(char const* _payload) override; + + char const* lastResponse() const override { return m_lastResponse.c_str(); } + + std::string m_lastResponse = R"({"id": 1, "jsonrpc": "2.0", "error": "Uninitalized JSV8RPC!"})"; }; } diff --git a/libjsconsole/JSV8RemoteConnector.cpp b/libjsconsole/JSV8RemoteConnector.cpp index 72e64faae..55bda4e72 100644 --- a/libjsconsole/JSV8RemoteConnector.cpp +++ b/libjsconsole/JSV8RemoteConnector.cpp @@ -1,10 +1,27 @@ -// -// Created by Marek Kotewicz on 15/06/15. -// +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file JSV8RemoteConnector.cpp + * @author Marek Kotewicz + * @date 2015 + * Connector from the standalone javascript console to a remote RPC node. + */ #include "JSV8RemoteConnector.h" -using namespace std; using namespace dev; using namespace dev::eth; @@ -13,8 +30,6 @@ void JSV8RemoteConnector::onSend(char const* _payload) m_request.setUrl(m_url); m_request.setBody(_payload); long code; - string response; - tie(code, response) = m_request.post(); + tie(code, m_lastResponse) = m_request.post(); (void)code; - m_lastResponse = response.c_str(); } diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h index 5d28094ad..d765f13da 100644 --- a/libjsconsole/JSV8RemoteConnector.h +++ b/libjsconsole/JSV8RemoteConnector.h @@ -1,10 +1,27 @@ -// -// Created by Marek Kotewicz on 15/06/15. -// +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file JSV8RemoteConnector.cpp + * @author Marek Kotewicz + * @date 2015 + * Connector from the standalone javascript console to a remote RPC node. + */ #pragma once -#include #include #include "CURLRequest.h" @@ -13,18 +30,21 @@ namespace dev namespace eth { -class JSV8RemoteConnector : public JSV8RPC +class JSV8RemoteConnector: private JSV8RPC { public: JSV8RemoteConnector(JSV8Engine const& _engine, std::string _url): JSV8RPC(_engine), m_url(_url) {} virtual ~JSV8RemoteConnector() {} +private: // implement JSV8RPC interface - void onSend(char const* _payload); + void onSend(char const* _payload) override; + const char* lastResponse() const override { return m_lastResponse.c_str(); } private: std::string m_url; + std::string m_lastResponse = R"({"id": 1, "jsonrpc": "2.0", "error": "Uninitalized JSV8RPC!"})"; CURLRequest m_request; }; diff --git a/libjsengine/JSEngine.h b/libjsengine/JSEngine.h index d44fc7828..adebfdd13 100644 --- a/libjsengine/JSEngine.h +++ b/libjsengine/JSEngine.h @@ -23,6 +23,8 @@ #pragma once #include +/// Do not use libstd headers here, it will break on MacOS. + namespace dev { namespace eth diff --git a/libjsengine/JSPrinter.h b/libjsengine/JSPrinter.h index bf13fcea7..6ced09eff 100644 --- a/libjsengine/JSPrinter.h +++ b/libjsengine/JSPrinter.h @@ -24,6 +24,8 @@ #include "JSEngine.h" +/// Do not use libstd headers here, it will break on MacOS. + namespace dev { namespace eth diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h index db75cafbc..9d08d9b43 100644 --- a/libjsengine/JSV8Engine.h +++ b/libjsengine/JSV8Engine.h @@ -28,6 +28,8 @@ #pragma clang diagnostic pop #include "JSEngine.h" +/// Do not use libstd headers here, it will break on MacOS. + namespace dev { namespace eth diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h index 2ec9c78b6..ec2f2aac1 100644 --- a/libjsengine/JSV8Printer.h +++ b/libjsengine/JSV8Printer.h @@ -25,6 +25,8 @@ #include "JSPrinter.h" #include "JSV8Engine.h" +/// Do not use libstd headers here, it will break on MacOS. + namespace dev { namespace eth diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp index 0c61eb37c..a24420d43 100644 --- a/libjsengine/JSV8RPC.cpp +++ b/libjsengine/JSV8RPC.cpp @@ -89,12 +89,4 @@ JSV8RPC::JSV8RPC(JSV8Engine const& _engine): m_engine(_engine) v8::Handle func = v8::Handle::Cast(web3object->Get(setProvider)); v8::Local values[1] = {obj}; func->Call(func, 1, values); - - m_lastResponse = R"( - { - "id": 1, - "jsonrpc": "2.0", - "error": "Uninitalized JSV8RPC!" - } - )"; } diff --git a/libjsengine/JSV8RPC.h b/libjsengine/JSV8RPC.h index a2180ef51..13e225e93 100644 --- a/libjsengine/JSV8RPC.h +++ b/libjsengine/JSV8RPC.h @@ -24,6 +24,8 @@ #include +/// Do not use libstd headers here, it will break on MacOS. + namespace dev { namespace eth @@ -33,14 +35,12 @@ class JSV8RPC { public: JSV8RPC(JSV8Engine const& _engine); + virtual ~JSV8RPC() { } virtual void onSend(char const* _payload) = 0; - char const* lastResponse() const { return m_lastResponse; } + virtual char const* lastResponse() const = 0; private: JSV8Engine const& m_engine; - -protected: - char const* m_lastResponse; }; } From 17783e16c98c008e464ed327f32a29f1b3d234d1 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 29 Jul 2015 17:29:43 +0200 Subject: [PATCH 16/18] add timestamp tests --- .../bcValidBlockTestFiller.json | 296 ++++++++++++++++++ test/libethereum/blockchain.cpp | 13 +- 2 files changed, 306 insertions(+), 3 deletions(-) diff --git a/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json index 8562cf5e2..4894c713f 100644 --- a/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json +++ b/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json @@ -1,4 +1,300 @@ { + "timeDiff12" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "231072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blockHeader" : { + "RelTimestamp" : "12" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "timeDiff13" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "231072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blockHeader" : { + "RelTimestamp" : "13" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "timeDiff14" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "231072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blockHeader" : { + "RelTimestamp" : "14" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "timeDiff0" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "231072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blockHeader" : { + "RelTimestamp" : "0" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + "diff1024" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index efe6585ad..ce06a1749 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -46,7 +46,7 @@ RLPStream createFullBlockFromHeader(BlockHeader const& _bi, bytes const& _txs = mArray writeTransactionsToJson(Transactions const& txs); mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi); -void overwriteBlockHeader(BlockHeader& _current_BlockHeader, mObject& _blObj); +void overwriteBlockHeader(BlockHeader& _current_BlockHeader, mObject& _blObj, const BlockHeader& _parent); void updatePoW(BlockHeader& _bi); mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); @@ -223,7 +223,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } if (blObj.count("blockHeader")) - overwriteBlockHeader(current_BlockHeader, blObj); + overwriteBlockHeader(current_BlockHeader, blObj, vBiBlocks[vBiBlocks.size()-1]); if (blObj.count("blockHeader") && blObj["blockHeader"].get_obj().count("bruncle")) current_BlockHeader.populateFromParent(vBiBlocks[vBiBlocks.size() -1]); @@ -664,7 +664,7 @@ bytes createBlockRLPFromFields(mObject& _tObj, h256 const& _stateRoot) return rlpStream.out(); } -void overwriteBlockHeader(BlockHeader& _header, mObject& _blObj) +void overwriteBlockHeader(BlockHeader& _header, mObject& _blObj, BlockHeader const& _parent) { auto ho = _blObj["blockHeader"].get_obj(); if (ho.size() != 14) @@ -684,6 +684,13 @@ void overwriteBlockHeader(BlockHeader& _header, mObject& _blObj) ho.count("timestamp") ? toInt(ho["timestamp"]) : _header.timestamp(), ho.count("extraData") ? importByteArray(ho["extraData"].get_str()) : _header.extraData()); + if (ho.count("RelTimestamp")) + { + tmp.setTimestamp(toInt(ho["RelTimestamp"]) +_parent.timestamp()); + tmp.setDifficulty(tmp.calculateDifficulty(_parent)); + this_thread::sleep_for(chrono::seconds((int)toInt(ho["RelTimestamp"]))); + } + // find new valid nonce if (static_cast(tmp) != static_cast(_header) && tmp.difficulty()) mine(tmp); From 5bb90fb71291d375215cbcd66dddd11d0f5de1d5 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 29 Jul 2015 19:30:28 +0200 Subject: [PATCH 17/18] adjust blockGasLimit in order to get same result for gasPricer test in olympic/frontier moder --- .../BlockchainTestsFiller/bcValidBlockTestFiller.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json index 4894c713f..b6dd28be3 100644 --- a/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json +++ b/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json @@ -559,6 +559,9 @@ }, "blocks" : [ { + "blockHeader" : { + "gasLimit" : "3141592" + }, "transactions" : [ { "data" : "", From d10338a99b6d732d90a690f15c0f530dca2e6efa Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Jul 2015 19:31:25 +0200 Subject: [PATCH 18/18] Tests for FixedFeeRegistrar. --- .../libsolidity/SolidityFixedFeeRegistrar.cpp | 237 ++++++++++++++++++ test/libsolidity/solidityExecutionFramework.h | 1 + 2 files changed, 238 insertions(+) create mode 100644 test/libsolidity/SolidityFixedFeeRegistrar.cpp diff --git a/test/libsolidity/SolidityFixedFeeRegistrar.cpp b/test/libsolidity/SolidityFixedFeeRegistrar.cpp new file mode 100644 index 000000000..26373499a --- /dev/null +++ b/test/libsolidity/SolidityFixedFeeRegistrar.cpp @@ -0,0 +1,237 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2015 + * Tests for a fixed fee registrar contract. + */ + +#include +#include +#include +#include +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +static char const* registrarCode = R"DELIMITER( +//sol FixedFeeRegistrar +// Simple global registrar with fixed-fee reservations. +// @authors: +// Gav Wood + +contract Registrar { + event Changed(string indexed name); + + function owner(string _name) constant returns (address o_owner); + function addr(string _name) constant returns (address o_address); + function subRegistrar(string _name) constant returns (address o_subRegistrar); + function content(string _name) constant returns (bytes32 o_content); +} + +contract FixedFeeRegistrar is Registrar { + struct Record { + address addr; + address subRegistrar; + bytes32 content; + address owner; + } + + modifier onlyrecordowner(string _name) { if (m_record(_name).owner == msg.sender) _ } + + function reserve(string _name) { + Record rec = m_record(_name); + if (rec.owner == 0 && msg.value >= c_fee) { + rec.owner = msg.sender; + Changed(_name); + } + } + function disown(string _name, address _refund) onlyrecordowner(_name) { + delete m_recordData[uint(sha3(_name)) / 8]; + _refund.send(c_fee); + Changed(_name); + } + function transfer(string _name, address _newOwner) onlyrecordowner(_name) { + m_record(_name).owner = _newOwner; + Changed(_name); + } + function setAddr(string _name, address _a) onlyrecordowner(_name) { + m_record(_name).addr = _a; + Changed(_name); + } + function setSubRegistrar(string _name, address _registrar) onlyrecordowner(_name) { + m_record(_name).subRegistrar = _registrar; + Changed(_name); + } + function setContent(string _name, bytes32 _content) onlyrecordowner(_name) { + m_record(_name).content = _content; + Changed(_name); + } + + function record(string _name) constant returns (address o_addr, address o_subRegistrar, bytes32 o_content, address o_owner) { + Record rec = m_record(_name); + o_addr = rec.addr; + o_subRegistrar = rec.subRegistrar; + o_content = rec.content; + o_owner = rec.owner; + } + function addr(string _name) constant returns (address) { return m_record(_name).addr; } + function subRegistrar(string _name) constant returns (address) { return m_record(_name).subRegistrar; } + function content(string _name) constant returns (bytes32) { return m_record(_name).content; } + function owner(string _name) constant returns (address) { return m_record(_name).owner; } + + Record[2**253] m_recordData; + function m_record(string _name) constant internal returns (Record storage o_record) { + return m_recordData[uint(sha3(_name)) / 8]; + } + uint constant c_fee = 69 ether; +} +)DELIMITER"; + +static unique_ptr s_compiledRegistrar; + +class RegistrarTestFramework: public ExecutionFramework +{ +protected: + void deployRegistrar() + { + if (!s_compiledRegistrar) + { + m_optimize = true; + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", registrarCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed"); + s_compiledRegistrar.reset(new bytes(m_compiler.getBytecode("FixedFeeRegistrar"))); + } + sendMessage(*s_compiledRegistrar, true); + BOOST_REQUIRE(!m_output.empty()); + } + u256 const m_fee = u256("69000000000000000000"); +}; + +/// This is a test suite that tests optimised code! +BOOST_FIXTURE_TEST_SUITE(SolidityFixedFeeRegistrar, RegistrarTestFramework) + +BOOST_AUTO_TEST_CASE(creation) +{ + deployRegistrar(); +} + +BOOST_AUTO_TEST_CASE(reserve) +{ + // Test that reserving works and fee is taken into account. + deployRegistrar(); + string name[] = {"abc", "def", "ghi"}; + m_sender = Address(0x123); + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name[0])) == encodeArgs()); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[0])) == encodeArgs(h256(0x123))); + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee + 1, encodeDyn(name[1])) == encodeArgs()); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[1])) == encodeArgs(h256(0x123))); + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee - 1, encodeDyn(name[2])) == encodeArgs()); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[2])) == encodeArgs(h256(0))); +} + +BOOST_AUTO_TEST_CASE(double_reserve) +{ + // Test that it is not possible to re-reserve from a different address. + deployRegistrar(); + string name = "abc"; + m_sender = Address(0x123); + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs()); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123))); + + m_sender = Address(0x124); + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs()); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123))); +} + +BOOST_AUTO_TEST_CASE(properties) +{ + // Test setting and retrieving the various properties works. + deployRegistrar(); + string names[] = {"abc", "def", "ghi"}; + size_t addr = 0x9872543; + for (string const& name: names) + { + addr++; + size_t sender = addr + 10007; + m_sender = Address(sender); + // setting by sender works + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs()); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(sender))); + BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(addr), u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr)); + BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20, u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20)); + BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90, u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90)); + // but not by someone else + m_sender = Address(h256(addr + 10007 - 1)); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(sender)); + BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), addr + 1, u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr)); + BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20 + 1, u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20)); + BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90 + 1, u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90)); + } +} + +BOOST_AUTO_TEST_CASE(transfer) +{ + deployRegistrar(); + string name = "abc"; + m_sender = Address(0x123); + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs()); + BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("transfer(string,address)", u256(0x40), u256(555), u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(555))); + BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(123))); +} + +BOOST_AUTO_TEST_CASE(disown) +{ + deployRegistrar(); + string name = "abc"; + m_sender = Address(0x123); + BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs()); + BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(124), u256(name.length()), name) == encodeArgs()); + BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), u256(125), u256(name.length()), name) == encodeArgs()); + + BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), 0); + BOOST_CHECK(callContractFunction("disown(string,address)", u256(0x40), u256(0x124), name.size(), name) == encodeArgs()); + BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), m_fee); + + BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(u256(0))); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 0e8637012..e4c4087f4 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -130,6 +130,7 @@ public: static bytes encode(bool _value) { return encode(byte(_value)); } static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(size_t _value) { return encode(u256(_value)); } static bytes encode(char const* _value) { return encode(std::string(_value)); } static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } static bytes encode(u256 const& _value) { return toBigEndian(_value); }