From 683dd220518362af6b890b52e6e0e89703efeb8d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Apr 2015 01:12:04 +0200 Subject: [PATCH 1/7] Allow fudging of calls so they never fail. --- CMakeLists.txt | 17 ++++++++--------- CodingStandards.txt | 16 +++++++++++----- libethereum/Client.cpp | 6 +++--- libethereum/Client.h | 2 +- libethereum/ClientBase.cpp | 14 ++++++++++---- libethereum/ClientBase.h | 5 +++-- libethereum/Interface.h | 14 ++++++++++---- libethereum/State.cpp | 11 ----------- libweb3jsonrpc/WebThreeStubServerBase.cpp | 7 ++++--- mix/MixClient.cpp | 18 ++++++++++++------ mix/MixClient.h | 6 +++--- 11 files changed, 65 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2da01d20f..100ef9139 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Normally, set(...CACHE...) creates cache variables, but does not modify them. function(createDefaultCacheConfig) set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)") - set(PARANOIA OFF CACHE BOOL "Additional run-time checks") + set(PARANOID OFF CACHE BOOL "Additional run-time checks") set(JSONRPC ON CACHE BOOL "Build with jsonprc. default on") set(FATDB OFF CACHE BOOL "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents.") set(USENPM OFF CACHE BOOL "Use npm to recompile ethereum.js if it was changed") @@ -35,7 +35,7 @@ endfunction() # propagates CMake configuration options to the compiler function(configureProject) - if (PARANOIA) + if (PARANOID) add_definitions(-DETH_PARANOIA) endif () @@ -89,7 +89,7 @@ function(createBuildInfo) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/int") endif () - if (PARANOIA) + if (PARANOID) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/PARA") endif () @@ -123,9 +123,9 @@ cmake_policy(SET CMP0015 NEW) # Clear invalid option if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") - if (PARANOIA) + if (PARANOID) message("Paranoia requires debug - disabling for release build.") - set(PARANOIA OFF) + set(PARANOID OFF) endif () if (VMTRACE) message("VM Tracing requires debug - disabling for release build.") @@ -151,10 +151,10 @@ if (HEADLESS) set(BUNDLE "minimal") endif () -if (PARANOIA) - set(PARANOIA ON) +if (PARANOID) + set(PARANOID ON) else () - set(PARANOIA OFF) + set(PARANOID OFF) endif () if (VMTRACE) set(VMTRACE ON) @@ -282,7 +282,6 @@ message("--------------------------------------------------------------- feature message("-- Chromium support ${ETH_HAVE_WEBENGINE}") message("-- VMTRACE VM execution tracing ${VMTRACE}") message("-- PROFILING Profiling support ${PROFILING}") -message("-- PARANOIA Additional (SLOW) database checking ${PARANOIA}") message("-- FATDB Full database exploring ${FATDB}") message("-- JSONRPC JSON-RPC support ${JSONRPC}") message("-- USENPM Javascript source building ${USENPM}") diff --git a/CodingStandards.txt b/CodingStandards.txt index a98a74c78..bd5cb4ce7 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -113,26 +113,33 @@ d. Favour declarations close to use; don't habitually declare at top of scope al e. Always pass non-trivial parameters with a const& suffix. f. If a function returns multiple values, use std::tuple (std::pair acceptable). Prefer not using */& arguments, except where efficiency requires. g. Never use a macro where adequate non-preprocessor C++ can be written. -h. Prefer "using NewType = OldType" to "typedef OldType NewType". -i. Make use of auto whenever type is clear or unimportant: +h. Make use of auto whenever type is clear or unimportant: - Always avoid doubly-stating the type. - Use to avoid vast and unimportant type declarations. +i. Don't pass bools: prefer enumerations instead. +j. Prefer enum class to straight enum. (WRONG) const double d = 0; int i, j; char *s; -float meanAndSigma(std::vector _v, float* _sigma); +float meanAndSigma(std::vector _v, float* _sigma, bool _approximate); Derived* x(dynamic_cast(base)); for (map::iterator i = l.begin(); i != l.end(); ++l) {} + (CORRECT) +enum class Accuracy +{ + Approximate, + Exact +}; double const d = 0; int i; int j; char* s; -std::tuple meanAndSigma(std::vector const& _v); +std::tuple meanAndSigma(std::vector const& _v, Accuracy _a); auto x = dynamic_cast(base); for (auto i = x.begin(); i != x.end(); ++i) {} @@ -192,7 +199,6 @@ c. Where there are exceptions to this (due to excessive use and clear meaning), d. In general expressions should be roughly as important/semantically meaningful as the space they occupy. - 11. Commenting a. Comments should be doxygen-compilable, using @notation rather than \notation. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index c703c6e95..80788aa22 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -397,7 +397,7 @@ void Client::setupState(State& _s) _s.commitToMine(m_bc); } -ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice) +ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from) { ExecutionResult ret; try @@ -407,10 +407,10 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 { ReadGuard l(x_stateDB); temp = m_postMine; - temp.addBalance(Address(), _value + _gasPrice * _gas); + temp.addBalance(_from, _value + _gasPrice * _gas); } Executive e(temp, LastHashes(), 0); - if (!e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address())) + if (!e.call(_dest, _dest, _from, _value, _gasPrice, &_data, _gas, _from)) e.go(); ret = e.executionResult(); } diff --git a/libethereum/Client.h b/libethereum/Client.h index bdd875e95..25a087de0 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -159,7 +159,7 @@ public: using Interface::call; // to remove warning about hiding virtual function /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH. - ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether); + ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address()); /// Get the remaining gas limit in this block. virtual u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index d1d9bc27f..1d27bcfce 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -65,14 +65,17 @@ Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes con } // TODO: remove try/catch, allow exceptions -ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) +ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) { ExecutionResult ret; try { State temp = asOf(_blockNumber); - u256 n = temp.transactionsFrom(toAddress(_secret)); + Address a = toAddress(_secret); + u256 n = temp.transactionsFrom(a); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + if (_ff == FudgeFactor::Lenient) + temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted); } catch (...) @@ -82,16 +85,19 @@ ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, byt return ret; } -ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) +ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) { ExecutionResult ret; try { State temp = asOf(_blockNumber); - u256 n = temp.transactionsFrom(toAddress(_secret)); + Address a = toAddress(_secret); + u256 n = temp.transactionsFrom(a); // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); Transaction t(_value, _gasPrice, _gas, _data, n, _secret); + if (_ff == FudgeFactor::Lenient) + temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted); } catch (...) diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 2d5b4a802..d06904b5d 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -82,9 +82,10 @@ public: virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; /// Makes the given call. Nothing is recorded into the state. - virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; + virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override; - virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; + /// Makes the given create. Nothing is recorded into the state. + virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override; using Interface::balanceAt; using Interface::countAt; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 0151a8ccb..ac41b0ec1 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -46,6 +46,12 @@ enum class Reaping Manual }; +enum class FudgeFactor +{ + Strict, + Lenient +}; + /** * @brief Main API hub for interfacing with Ethereum. */ @@ -71,13 +77,13 @@ public: virtual void flushTransactions() = 0; /// Makes the given call. Nothing is recorded into the state. - virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) = 0; - ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) { return call(_secret, _value, _dest, _data, _gas, _gasPrice, m_default); } + virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0; + ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return call(_secret, _value, _dest, _data, _gas, _gasPrice, m_default, _ff); } /// Does the given creation. Nothing is recorded into the state. /// @returns the pair of the Address of the created contract together with its code. - virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) = 0; - ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) { return create(_secret, _value, _data, _gas, _gasPrice, m_default); } + virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0; + ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return create(_secret, _value, _data, _gas, _gasPrice, m_default, _ff); } // [STATE-QUERY API] diff --git a/libethereum/State.cpp b/libethereum/State.cpp index fcd223661..5631ffe28 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -543,8 +543,6 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) // m_currentBlock is assumed to be prepopulated and reset. BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce); - cdebug << "enacting" << BlockInfo::headerHash(_block).abridged() << "==" << bi.hash().abridged() << "on" << m_previousBlock.hash().abridged(); - cdebug << m_currentBlock; #if !ETH_RELEASE assert(m_previousBlock.hash() == bi.parentHash); @@ -560,9 +558,6 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - cdebug << "populated and verified. incoming block hash is" << m_currentBlock.hash().abridged(); - cdebug << m_currentBlock; - // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -631,7 +626,6 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) // Initialise total difficulty calculation. u256 tdIncrease = m_currentBlock.difficulty; - // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) BOOST_THROW_EXCEPTION(TooManyUncles()); @@ -686,11 +680,6 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } - cdebug << m_currentBlock; - auto hh = m_currentBlock.hash(); - m_currentBlock.noteDirty(); - cdebug << "done enacting. new stateroot is" << m_currentBlock.stateRoot.abridged() << ", hash is" << m_currentBlock.hash().abridged() << " = " << hh; - return tdIncrease; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 072d96331..291415a68 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -497,12 +497,13 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const& string ret; if (!t.from) t.from = m_accounts->getDefaultTransactAccount(); - if (!m_accounts->isRealAccount(t.from)) - return ret; +// if (!m_accounts->isRealAccount(t.from)) +// return ret; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) - t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + t.gas = client()->gasLimitRemaining(); + ret = toJS(client()->call(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice, number).output); return ret; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 60d97e5b7..ff35a6d78 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -295,12 +295,15 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons return address; } -dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto) +dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff) { (void)_blockNumber; + Address a = toAddress(_secret); State temp = asOf(eth::PendingBlock); - u256 n = temp.transactionsFrom(toAddress(_secret)); + u256 n = temp.transactionsFrom(a); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + if (_ff == FudgeFactor::Lenient) + temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state executeTransaction(t, temp, true, _gasAuto, _secret); @@ -317,22 +320,25 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons return submitTransaction(_secret, _endowment, _init, _gas, _gasPrice, false); } -dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) +dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) { - return call(_secret, _value, _dest, _data, _gas, _gasPrice, _blockNumber,false); + return call(_secret, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff); } -dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) +dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) { (void)_blockNumber; u256 n; + Address a = toAddress(_secret); State temp; { ReadGuard lr(x_state); temp = asOf(eth::PendingBlock); - n = temp.transactionsFrom(toAddress(_secret)); + n = temp.transactionsFrom(a); } Transaction t(_value, _gasPrice, _gas, _data, n, _secret); + if (_ff == FudgeFactor::Lenient) + temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state executeTransaction(t, temp, true, false, _secret); diff --git a/mix/MixClient.h b/mix/MixClient.h index c52e7bd88..480509545 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -55,12 +55,12 @@ public: void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override; - dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock) override; - dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock) override; + dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; + dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto); Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto); - dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto); + dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); void setAddress(Address _us) override; void setMiningThreads(unsigned _threads) override; From e162fd4cd8bccc67a530410118cffed47a3d7b5a Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 9 Apr 2015 17:51:07 +0200 Subject: [PATCH 2/7] UI improvement --- mix/qml/Debugger.qml | 6 +- mix/qml/StateDialog.qml | 168 ++++++++++++++++++---------------- mix/qml/StateListModel.qml | 4 +- mix/qml/StatusPane.qml | 31 +++++++ mix/qml/TransactionDialog.qml | 1 - mix/qml/TransactionLog.qml | 10 +- 6 files changed, 135 insertions(+), 85 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index e5c7e576d..df9f221a8 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -215,14 +215,16 @@ Rectangle { id: buttonRow height: 30 Layout.fillWidth: true + width: parent.width color: "transparent" Rectangle { anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: parent.left + anchors.leftMargin: machineStates.sideMargin color: "transparent" - width: parent.width * 0.4 + width: 240 RowLayout { anchors.horizontalCenter: parent.horizontalCenter id: jumpButtons @@ -358,7 +360,7 @@ Rectangle { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right - width: parent.width * 0.6 + width: parent.width - 265 color: "transparent" Slider { id: statesSlider diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 0af27f055..82e817eb1 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -13,7 +13,7 @@ Dialog { id: modalStateDialog modality: Qt.ApplicationModal - width: 590 + width: 630 height: 480 title: qsTr("Edit State") visible: false @@ -79,7 +79,10 @@ Dialog { } contentItem: Rectangle { color: stateDialogStyle.generic.backgroundColor - ColumnLayout { + Rectangle { + color: stateDialogStyle.generic.backgroundColor + anchors.top: parent.top + anchors.margins: 10 anchors.fill: parent ColumnLayout { anchors.fill: parent @@ -91,7 +94,7 @@ Dialog { { Layout.fillWidth: true DefaultLabel { - Layout.preferredWidth: 75 + Layout.preferredWidth: 85 text: qsTr("Title") } DefaultTextField @@ -112,10 +115,10 @@ Dialog { Rectangle { - Layout.preferredWidth: 75 + Layout.preferredWidth: 85 DefaultLabel { id: accountsLabel - Layout.preferredWidth: 75 + Layout.preferredWidth: 85 text: qsTr("Accounts") } @@ -227,7 +230,7 @@ Dialog { { Layout.fillWidth: true DefaultLabel { - Layout.preferredWidth: 75 + Layout.preferredWidth: 85 text: qsTr("Default") } CheckBox { @@ -240,52 +243,91 @@ Dialog { { Layout.fillWidth: true } - } - ColumnLayout { - anchors.top: dialogContent.bottom - anchors.topMargin: 5 - spacing: 0 RowLayout { - Layout.preferredWidth: 150 - DefaultLabel { - text: qsTr("Transactions: ") - } + Layout.fillWidth: true - Button + Rectangle { - iconSource: "qrc:/qml/img/plus.png" - action: newTrAction - width: 10 - height: 10 - anchors.right: parent.right - } + Layout.preferredWidth: 85 + DefaultLabel { + id: transactionsLabel + Layout.preferredWidth: 85 + text: qsTr("Transactions") + } - Action { - id: newTrAction - tooltip: qsTr("Create a new transaction") - onTriggered: transactionsModel.addTransaction() + 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() + } } - } - ScrollView - { - Layout.fillHeight: true - Layout.preferredWidth: 300 - Column + TableView { - Layout.fillHeight: true - Repeater - { - id: trRepeater - model: transactionsModel - delegate: transactionRenderDelegate - visible: transactionsModel.count > 0 - height: 20 * transactionsModel.count + id: transactionsView + Layout.fillWidth: true + model: transactionsModel + headerVisible: false + TableViewColumn { + role: "name" + 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: styleData.row >= 0 ? transactionsModel.get(styleData.row).functionId : "" + } + } + } + } + rowDelegate: + Rectangle { + color: styleData.alternate ? "transparent" : "#f0f0f0" + height: 30; } } } + } RowLayout @@ -304,6 +346,13 @@ Dialog { text: qsTr("Cancel"); onClicked: close(); } + Button { + text: qsTr("Delete"); + onClicked: { + projectModel.stateListModel.deleteState(stateIndex); + close(); + } + } } ListModel { @@ -325,7 +374,6 @@ Dialog { } 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 @@ -350,44 +398,6 @@ Dialog { } } - Component { - id: transactionRenderDelegate - RowLayout { - DefaultLabel { - Layout.preferredWidth: 150 - text: functionId - } - - Button - { - id: deleteBtn - iconSource: "qrc:/qml/img/delete_sign.png" - action: deleteAction - width: 10 - height: 10 - Action { - id: deleteAction - tooltip: qsTr("Delete") - onTriggered: transactionsModel.deleteTransaction(index) - } - } - - Button - { - iconSource: "qrc:/qml/img/edit.png" - action: editAction - visible: stdContract === false - width: 10 - height: 10 - Action { - id: editAction - tooltip: qsTr("Edit") - onTriggered: transactionsModel.editTransaction(index) - } - } - } - } - TransactionDialog { id: transactionDialog diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index 7b7f33361..a0cb25eb3 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -167,6 +167,7 @@ Item { signal defaultStateChanged; signal stateListModelReady; signal stateRun(int index) + signal stateDeleted(int index) function defaultTransactionItem() { return TransactionHelper.defaultTransaction(); @@ -293,9 +294,8 @@ Item { } else if (defaultStateIndex > index) defaultStateIndex--; - save(); - + stateDeleted(index); } function save() { diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 9e10edbe9..f3bde4a04 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.InverseMouseArea 1.0 +import QtGraphicalEffects 1.0 import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." @@ -246,6 +247,27 @@ Rectangle { tooltip: "" } + Rectangle + { + id: logsShadow + width: logsContainer.width + 5 + height: 0 + opacity: 0.3 + clip: true + anchors.top: logsContainer.top + anchors.margins: 4 + Rectangle { + color: "gray" + anchors.top: parent.top + radius: 10 + id: roundRect + height: 400 + width: parent.width + } + } + + + Rectangle { InverseMouseArea @@ -287,9 +309,16 @@ Rectangle { top = top.parent var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; + logsShadow.parent = top; logsContainer.x = status.x + statusContainer.x - logStyle.generic.layout.dateWidth - logStyle.generic.layout.typeWidth + 70 + logsShadow.x = status.x + statusContainer.x - logStyle.generic.layout.dateWidth - logStyle.generic.layout.typeWidth + 70; + logsShadow.z = 1 + logsContainer.z = 2 if (Qt.platform.os === "osx") + { logsContainer.y = statusContainer.y; + logsShadow.y = statusContainer.y; + } } LogsPaneStyle { @@ -305,6 +334,7 @@ Rectangle { State { name: "opened"; PropertyChanges { target: logsContainer; height: 500; visible: true } + PropertyChanges { target: logsShadow; height: 500; visible: true } PropertyChanges { target: outsideClick; active: true } }, @@ -313,6 +343,7 @@ Rectangle { PropertyChanges { target: logsContainer; height: 0; visible: false } PropertyChanges { target: statusContainer; width: 600; height: 30 } PropertyChanges { target: outsideClick; active: false } + PropertyChanges { target: logsShadow; height: 0; visible: false } } ] transitions: Transition { diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 2c36bf2ea..ed76d48eb 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -400,7 +400,6 @@ Dialog { Button { text: qsTr("Cancel"); onClicked: close(); - Layout.fillWidth: true } } } diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index ca8b37098..86f8b2a74 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -52,7 +52,7 @@ Item { { id: statesCombo items: projectModel.stateListModel - onSelectCreate: projectModel.stateListModel.addState(); + onSelectCreate: projectModel.stateListModel.addState() onEditItem: projectModel.stateListModel.editState(item) colorItem: "#808080" colorSelect: "#4a90e2" @@ -63,8 +63,16 @@ Item { if (statesCombo.selectedIndex !== index) statesCombo.setSelectedIndex(index) } + onStateListModelReady: { + statesCombo.setSelectedIndex(projectModel.stateListModel.defaultStateIndex) + } + onStateDeleted: { + if (index === statesCombo.selectedIndex) + statesCombo.setSelectedIndex(0); + } } } + Button { anchors.rightMargin: 9 From 51f575e049d8a472c11047f4341f1b1d5e66906a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Apr 2015 22:36:16 +0200 Subject: [PATCH 3/7] Blockchain import/export. One or two minor additons to eth. --- eth/main.cpp | 134 +++++++++++++++++++++++++++++++------ libdevcore/RLP.cpp | 2 +- libdevcore/RLP.h | 5 +- libdevcrypto/Common.cpp | 6 +- libethereum/BlockChain.cpp | 8 +-- libethereum/BlockChain.h | 10 ++- libethereum/Client.h | 3 +- libethereum/ClientBase.cpp | 5 ++ libethereum/ClientBase.h | 4 +- libtestutils/FixedClient.h | 1 + mix/MixClient.h | 7 +- 11 files changed, 147 insertions(+), 38 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 1f5b6d574..4ced0272c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -115,9 +115,14 @@ void help() << " /Etherum or Library/Application Support/Ethereum)." << endl << " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl << " -e,--ether-price Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl + << " -E,--export Export file as a concatenated series of blocks and exit." << endl + << " --export-from Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl + << " --export-to Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl + << " --export-only Equivalent to --export-from n --export-to n." << endl << " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl << " -h,--help Show this help message and exit." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl + << " -I,--import Import file as a concatenated series of blocks and exit." << endl #if ETH_JSONRPC << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl @@ -209,33 +214,61 @@ void doInitDAG(unsigned _n) exit(0); } -static const unsigned NoDAGInit = (unsigned)-3; +enum class OperationMode +{ + Node, + Import, + Export, + DAGInit +}; int main(int argc, char** argv) { - unsigned initDAG = NoDAGInit; - string listenIP; - unsigned short listenPort = 30303; - string publicIP; - string remoteHost; - unsigned short remotePort = 30303; + /// Operating mode. + OperationMode mode = OperationMode::Node; string dbPath; - unsigned mining = ~(unsigned)0; - NodeMode mode = NodeMode::Full; - unsigned peers = 5; - int miners = -1; + + /// File name for import/export. + string filename; + + /// Hashes/numbers for export range. + string exportFrom = "1"; + string exportTo = "latest"; + + /// DAG initialisation param. + unsigned initDAG; + + /// General params for Node operation + NodeMode nodeMode = NodeMode::Full; bool interactive = false; #if ETH_JSONRPC int jsonrpc = -1; #endif - bool bootstrap = false; bool upnp = true; - bool forceMining = false; WithExisting killChain = WithExisting::Trust; bool jit = false; + + /// Networking params. + string clientName; + string listenIP; + unsigned short listenPort = 30303; + string publicIP; + string remoteHost; + unsigned short remotePort = 30303; + unsigned peers = 5; + bool bootstrap = false; + + /// Mining params + unsigned mining = ~(unsigned)0; + int miners = -1; + bool forceMining = false; + bool turboMining = false; + + /// Structured logging params bool structuredLogging = false; string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S"; - string clientName; + + /// Transaction params TransactionPriority priority = TransactionPriority::Medium; double etherPrice = 30.679; double blockFees = 15.0; @@ -275,6 +308,16 @@ int main(int argc, char** argv) remoteHost = argv[++i]; else if ((arg == "-p" || arg == "--port") && i + 1 < argc) remotePort = (short)atoi(argv[++i]); + else if ((arg == "-I" || arg == "--import") && i + 1 < argc) + { + mode = OperationMode::Import; + filename = argv[++i]; + } + else if ((arg == "-E" || arg == "--export") && i + 1 < argc) + { + mode = OperationMode::Export; + filename = argv[++i]; + } else if ((arg == "-n" || arg == "--upnp") && i + 1 < argc) { string m = argv[++i]; @@ -321,6 +364,7 @@ int main(int argc, char** argv) else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc) { string m = boost::to_lower_copy(string(argv[++i])); + mode = OperationMode::DAGInit; if (m == "next") initDAG = PendingBlock; else if (m == "this") @@ -402,6 +446,8 @@ int main(int argc, char** argv) bootstrap = true; else if (arg == "-f" || arg == "--force-mining") forceMining = true; + else if (arg == "-T" || arg == "--turbo-mining") + turboMining = true; else if (arg == "-i" || arg == "--interactive") interactive = true; #if ETH_JSONRPC @@ -420,9 +466,9 @@ int main(int argc, char** argv) { string m = argv[++i]; if (m == "full") - mode = NodeMode::Full; + nodeMode = NodeMode::Full; else if (m == "peer") - mode = NodeMode::PeerServer; + nodeMode = NodeMode::PeerServer; else { cerr << "Unknown mode: " << m << endl; @@ -452,7 +498,7 @@ int main(int argc, char** argv) // Two codepaths is necessary since named block require database, but numbered // blocks are superuseful to have when database is already open in another process. - if (initDAG < NoDAGInit) + if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) doInitDAG(initDAG); if (!clientName.empty()) @@ -469,23 +515,69 @@ int main(int argc, char** argv) clientImplString, dbPath, killChain, - mode == NodeMode::Full ? set{"eth", "shh"} : set(), + nodeMode == NodeMode::Full ? set{"eth", "shh"} : set(), netPrefs, &nodesState, miners ); - if (initDAG == LatestBlock || initDAG == PendingBlock) + if (mode == OperationMode::DAGInit) doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); - + + auto toNumber = [&](string const& s) -> unsigned { + if (s == "latest") + return web3.ethereum()->number(); + if (s.size() == 64 || (s.size() == 66 && s.substr(0, 2) == "0x")) + return web3.ethereum()->blockChain().number(h256(s)); + try { + return stol(s); + } + catch (...) + { + cerr << "Bad block number/hash option: " << s << endl; + exit(-1); + } + }; + + if (mode == OperationMode::Export) + { + ofstream fout; + fout.open(filename); + unsigned last = toNumber(exportTo); + for (unsigned i = toNumber(exportFrom); i <= last; ++i) + { + bytes block = web3.ethereum()->blockChain().block(web3.ethereum()->blockChain().numberHash(i)); + fout.write((char const*)block.data(), block.size()); + } + return 0; + } + + if (mode == OperationMode::Import) + { + ifstream fin; + fin.open(filename); + + while (fin) + { + bytes block(8); + fin.read((char*)block.data(), 8); + unsigned remaining = RLP(block, RLP::LaisezFaire).actualSize() - 8; + block.resize(remaining); + fin.read((char*)block.data() + 8, remaining); + web3.ethereum()->injectBlock(block); + } + return 0; + } + web3.setIdealPeerCount(peers); std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); - eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr; + eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr; StructuredLogger::starting(clientImplString, dev::Version); if (c) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + c->setTurboMining(turboMining); c->setAddress(coinbase); } diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp index 26f10ecf5..994aac265 100644 --- a/libdevcore/RLP.cpp +++ b/libdevcore/RLP.cpp @@ -107,7 +107,7 @@ unsigned RLP::actualSize() const if (isSingleByte()) return 1; if (isData() || isList()) - return payload().data() - m_data.data() + length(); + return payloadOffset() + length(); return 0; } diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a837f9221..caaf10b6a 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -290,7 +290,7 @@ public: RLPs toList() const; /// @returns the data payload. Valid for all types. - bytesConstRef payload() const { return isSingleByte() ? m_data.cropped(0, 1) : m_data.cropped(1 + lengthSize()); } + bytesConstRef payload() const { return m_data.cropped(payloadOffset()); } /// @returns the theoretical size of this item. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. @@ -309,6 +309,9 @@ private: /// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data. unsigned length() const; + /// @returns the number of bytes into the data that the payload starts. + unsigned payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); } + /// @returns the number of data items. unsigned items() const; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index e108b230f..f9720fb8d 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -37,9 +37,9 @@ static Secp256k1 s_secp256k1; bool dev::SignatureStruct::isValid() const { - if (this->v > 1 || - this->r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || - this->s >= h256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")) + if (v > 1 || + r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || + s >= h256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")) return false; return true; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index f64d6557c..cb2d26eff 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -240,7 +240,7 @@ void BlockChain::rebuild(std::string const& _path, std::function BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); } -pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force) noexcept +pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force) noexcept { try { @@ -347,7 +347,7 @@ pair BlockChain::attemptImport(bytes const& _block, OverlayDB const } } -pair BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force) +pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -386,7 +386,7 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, #endif // Check block doesn't already exist first! - if (isKnown(bi.hash()) && !_force) + if (isKnown(bi.hash()) && _force == Aversion::AvoidOldBlocks) { clog(BlockChainNote) << bi.hash() << ": Not new."; BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index b4e18a037..765e00b03 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -80,6 +80,12 @@ enum { using ProgressCallback = std::function; +enum class Aversion +{ + AvoidOldBlocks, + ImportOldBlocks +}; + /** * @brief Implements the blockchain database. All data this gives is disk-backed. * @threadsafe @@ -102,11 +108,11 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force = false) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair import(bytes const& _block, OverlayDB const& _stateDB, bool _force = false); + std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; diff --git a/libethereum/Client.h b/libethereum/Client.h index 25a087de0..57fe0d9de 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -229,8 +229,9 @@ public: protected: /// InterfaceStub methods + virtual BlockChain& bc() override { return m_bc; } virtual BlockChain const& bc() const override { return m_bc; } - + /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. using ClientBase::asOf; diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 1d27bcfce..f57b2b174 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -107,6 +107,11 @@ ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _da return ret; } +void ClientBase::injectBlock(bytes const& _block) +{ + bc().import(_block, preMine().db()); +} + u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const { return asOf(_block).balance(_a); diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index d06904b5d..00bb02ed4 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -109,7 +109,6 @@ public: virtual LocalisedLogEntries peekWatch(unsigned _watchId) const override; virtual LocalisedLogEntries checkWatch(unsigned _watchId) override; - // TODO: switch all the _blockHash arguments to also accept _blockNumber virtual h256 hashFromNumber(BlockNumber _number) const override; virtual eth::BlockInfo blockInfo(h256 _hash) const override; virtual eth::BlockDetails blockDetails(h256 _hash) const override; @@ -125,6 +124,8 @@ public: virtual eth::Transactions pending() const override; virtual h256s pendingHashes() const override; + void injectBlock(bytes const& _block); + using Interface::diff; virtual StateDiff diff(unsigned _txi, h256 _block) const override; virtual StateDiff diff(unsigned _txi, BlockNumber _block) const override; @@ -155,6 +156,7 @@ public: protected: /// The interface that must be implemented in any class deriving this. /// { + virtual BlockChain& bc() = 0; virtual BlockChain const& bc() const = 0; virtual State asOf(h256 const& _h) const = 0; virtual State preMine() const = 0; diff --git a/libtestutils/FixedClient.h b/libtestutils/FixedClient.h index 95acc3edb..59da9075f 100644 --- a/libtestutils/FixedClient.h +++ b/libtestutils/FixedClient.h @@ -42,6 +42,7 @@ public: // stub virtual void flushTransactions() override {} + virtual eth::BlockChain& bc() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("FixedClient::bc()")); } virtual eth::BlockChain const& bc() const override { return m_bc; } using ClientBase::asOf; virtual eth::State asOf(h256 const& _h) const override; diff --git a/mix/MixClient.h b/mix/MixClient.h index 480509545..39d5bf081 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -79,11 +79,10 @@ public: std::vector userAccounts() { return m_userAccounts; } protected: - virtual dev::eth::BlockChain& bc() { return *m_bc; } - - /// InterfaceStub methods - virtual dev::eth::State asOf(h256 const& _block) const override; + /// ClientBase methods using ClientBase::asOf; + virtual dev::eth::State asOf(h256 const& _block) const override; + virtual dev::eth::BlockChain& bc() { return *m_bc; } virtual dev::eth::BlockChain const& bc() const override { return *m_bc; } virtual dev::eth::State preMine() const override { ReadGuard l(x_state); return m_startState; } virtual dev::eth::State postMine() const override { ReadGuard l(x_state); return m_state; } From f89d32966b330d8089841130b00d5b8b59baefbe Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Apr 2015 00:50:07 +0200 Subject: [PATCH 4/7] Fixes for import/export. --- eth/main.cpp | 134 +++++++++++++++++++++++++++++------------- libdevcore/Log.cpp | 2 +- libdevcore/Worker.cpp | 12 ++-- 3 files changed, 101 insertions(+), 47 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 4ced0272c..e9d63b42a 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -116,9 +116,9 @@ void help() << " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl << " -e,--ether-price Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl << " -E,--export Export file as a concatenated series of blocks and exit." << endl - << " --export-from Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl - << " --export-to Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl - << " --export-only Equivalent to --export-from n --export-to n." << endl + << " --from Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl + << " --to Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl + << " --only Equivalent to --export-from n --export-to n." << endl << " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl << " -h,--help Show this help message and exit." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl @@ -222,8 +222,18 @@ enum class OperationMode DAGInit }; +enum class Format +{ + Binary, + Hex, + Human +}; + int main(int argc, char** argv) { + // Init defaults + Defaults::get(); + /// Operating mode. OperationMode mode = OperationMode::Node; string dbPath; @@ -234,6 +244,7 @@ int main(int argc, char** argv) /// Hashes/numbers for export range. string exportFrom = "1"; string exportTo = "latest"; + Format exportFormat = Format::Binary; /// DAG initialisation param. unsigned initDAG; @@ -263,6 +274,8 @@ int main(int argc, char** argv) int miners = -1; bool forceMining = false; bool turboMining = false; + KeyPair us = KeyPair::create(); + Address coinbase = us.address(); /// Structured logging params bool structuredLogging = false; @@ -273,13 +286,6 @@ int main(int argc, char** argv) double etherPrice = 30.679; double blockFees = 15.0; - // Init defaults - Defaults::get(); - - // Our address. - KeyPair us = KeyPair::create(); - Address coinbase = us.address(); - string configFile = getDataDir() + "/config.rlp"; bytes b = contents(configFile); if (b.size()) @@ -288,12 +294,6 @@ int main(int argc, char** argv) us = KeyPair(config[0].toHash()); coinbase = config[1].toHash
(); } - else - { - RLPStream config(2); - config << us.secret() << coinbase; - writeFile(configFile, config.out()); - } for (int i = 1; i < argc; ++i) { @@ -318,6 +318,27 @@ int main(int argc, char** argv) mode = OperationMode::Export; filename = argv[++i]; } + else if (arg == "--format" && i + 1 < argc) + { + string m = argv[++i]; + if (m == "binary") + exportFormat = Format::Binary; + else if (m == "hex") + exportFormat = Format::Hex; + else if (m == "human") + exportFormat = Format::Human; + else + { + cerr << "Bad " << arg << " option: " << m << endl; + return -1; + } + } + else if (arg == "--to" && i + 1 < argc) + exportTo = argv[++i]; + else if (arg == "--from" && i + 1 < argc) + exportFrom = argv[++i]; + else if (arg == "--only" && i + 1 < argc) + exportTo = exportFrom = argv[++i]; else if ((arg == "-n" || arg == "--upnp") && i + 1 < argc) { string m = argv[++i]; @@ -327,7 +348,7 @@ int main(int argc, char** argv) upnp = false; else { - cerr << "Invalid -n/--upnp option: " << m << endl; + cerr << "Bad " << arg << " option: " << m << endl; return -1; } } @@ -344,14 +365,13 @@ int main(int argc, char** argv) } catch (BadHexCharacter& _e) { - cwarn << "invalid hex character, coinbase rejected"; - cwarn << boost::diagnostic_information(_e); - break; + cerr << "Bad hex in " << arg << " option: " << argv[i] << endl; + return -1; } catch (...) { - cwarn << "coinbase rejected"; - break; + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; } else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) us = KeyPair(h256(fromHex(argv[++i]))); @@ -495,6 +515,11 @@ int main(int argc, char** argv) } } + { + RLPStream config(2); + config << us.secret() << coinbase; + writeFile(configFile, config.out()); + } // Two codepaths is necessary since named block require database, but numbered // blocks are superuseful to have when database is already open in another process. @@ -504,8 +529,6 @@ int main(int argc, char** argv) if (!clientName.empty()) clientName += "/"; - cout << credits(); - StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); @@ -541,34 +564,66 @@ int main(int argc, char** argv) if (mode == OperationMode::Export) { - ofstream fout; - fout.open(filename); + ofstream fout(filename, std::ofstream::binary); + ostream& out = (filename.empty() || filename == "--") ? cout : fout; + unsigned last = toNumber(exportTo); for (unsigned i = toNumber(exportFrom); i <= last; ++i) { bytes block = web3.ethereum()->blockChain().block(web3.ethereum()->blockChain().numberHash(i)); - fout.write((char const*)block.data(), block.size()); + switch (exportFormat) + { + case Format::Binary: out.write((char const*)block.data(), block.size()); break; + case Format::Hex: out << toHex(block) << endl; break; + case Format::Human: out << RLP(block) << endl; break; + default:; + } } return 0; } if (mode == OperationMode::Import) { - ifstream fin; - fin.open(filename); - - while (fin) + ifstream fin(filename, std::ifstream::binary); + istream& in = (filename.empty() || filename == "--") ? cin : fin; + unsigned alreadyHave = 0; + unsigned good = 0; + unsigned futureTime = 0; + unsigned unknownParent = 0; + unsigned bad = 0; + while (in.peek() != -1) { bytes block(8); - fin.read((char*)block.data(), 8); - unsigned remaining = RLP(block, RLP::LaisezFaire).actualSize() - 8; - block.resize(remaining); - fin.read((char*)block.data() + 8, remaining); - web3.ethereum()->injectBlock(block); + in.read((char*)block.data(), 8); + block.resize(RLP(block, RLP::LaisezFaire).actualSize()); + in.read((char*)block.data() + 8, block.size() - 8); + try + { + web3.ethereum()->injectBlock(block); + good++; + } + catch (AlreadyHaveBlock const&) + { + alreadyHave++; + } + catch (UnknownParent const&) + { + unknownParent++; + } + catch (FutureTime const&) + { + futureTime++; + } + catch (...) + { + bad++; + } } + cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl; return 0; } + cout << credits(); web3.setIdealPeerCount(peers); std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr; @@ -645,10 +700,9 @@ int main(int argc, char** argv) } else if (cmd == "connect") { - string addr; - unsigned port; - iss >> addr >> port; - web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort)); + string addrPort; + iss >> addrPort; + web3.addNode(p2p::NodeId(), addrPort); } else if (cmd == "netstop") { diff --git a/libdevcore/Log.cpp b/libdevcore/Log.cpp index 1c7a34932..7196ea358 100644 --- a/libdevcore/Log.cpp +++ b/libdevcore/Log.cpp @@ -43,7 +43,7 @@ void dev::simpleDebugOut(std::string const& _s, char const*) static Mutex s_lock; Guard l(s_lock); - cout << _s << endl << flush; + cerr << _s << endl << flush; // helpful to use OutputDebugString on windows #ifdef _WIN32 diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 014780a66..175323620 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -29,11 +29,11 @@ using namespace dev; void Worker::startWorking() { - cdebug << "startWorking for thread" << m_name; + cnote << "startWorking for thread" << m_name; Guard l(x_work); if (m_work) return; - cdebug << "Spawning" << m_name; + cnote << "Spawning" << m_name; m_stop = false; m_work.reset(new thread([&]() { @@ -45,21 +45,21 @@ void Worker::startWorking() this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); doWork(); } - cdebug << "Finishing up worker thread"; + cnote << "Finishing up worker thread"; doneWorking(); })); } void Worker::stopWorking() { - cdebug << "stopWorking for thread" << m_name; + cnote << "stopWorking for thread" << m_name; Guard l(x_work); if (!m_work) return; - cdebug << "Stopping" << m_name; + cnote << "Stopping" << m_name; m_stop = true; m_work->join(); m_work.reset(); - cdebug << "Stopped" << m_name; + cnote << "Stopped" << m_name; } From 978a9db37730a227fddcc58acf516fbeaf5f83ef Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Apr 2015 01:01:08 +0200 Subject: [PATCH 5/7] Warning fix. --- eth/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index e9d63b42a..c83332c20 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -247,7 +247,7 @@ int main(int argc, char** argv) Format exportFormat = Format::Binary; /// DAG initialisation param. - unsigned initDAG; + unsigned initDAG = 0; /// General params for Node operation NodeMode nodeMode = NodeMode::Full; From bf1841aa9b2df93879377a33398b8a1ecd1389dd Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 10 Apr 2015 09:23:49 +0200 Subject: [PATCH 6/7] small ui changes --- mix/qml/StateDialog.qml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 82e817eb1..2d07e4b31 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -335,6 +335,14 @@ Dialog { 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: { @@ -346,13 +354,6 @@ Dialog { text: qsTr("Cancel"); onClicked: close(); } - Button { - text: qsTr("Delete"); - onClicked: { - projectModel.stateListModel.deleteState(stateIndex); - close(); - } - } } ListModel { From 566a1f4285026a15378cef1374842c9d6dc90911 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 10 Apr 2015 09:28:47 +0200 Subject: [PATCH 7/7] Rollback Debugger.qml --- mix/qml/Debugger.qml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index df9f221a8..e5c7e576d 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -215,16 +215,14 @@ Rectangle { id: buttonRow height: 30 Layout.fillWidth: true - width: parent.width color: "transparent" Rectangle { anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: parent.left - anchors.leftMargin: machineStates.sideMargin color: "transparent" - width: 240 + width: parent.width * 0.4 RowLayout { anchors.horizontalCenter: parent.horizontalCenter id: jumpButtons @@ -360,7 +358,7 @@ Rectangle { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right - width: parent.width - 265 + width: parent.width * 0.6 color: "transparent" Slider { id: statesSlider