From 08d88f1a4aa6151ac626d80b1cf8650d805b73b9 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 4 Feb 2015 01:00:19 +0100 Subject: [PATCH 1/9] mix: Mining and transactions on a real blockchain --- mix/ClientModel.cpp | 39 +++++-- mix/MixClient.cpp | 219 ++++++++++++++++++++++++---------------- mix/MixClient.h | 30 +++--- mix/qml/MainContent.qml | 3 +- 4 files changed, 175 insertions(+), 116 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 365dce9a9..ebfd885f1 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -83,7 +84,7 @@ ClientModel::ClientModel(AppContext* _context): qRegisterMetaType("TransactionLogEntry"); connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); - m_client.reset(new MixClient()); + m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), std::vector { m_client->userAccount() }, m_client.get())); connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); @@ -93,6 +94,7 @@ ClientModel::ClientModel(AppContext* _context): ClientModel::~ClientModel() { + } QString ClientModel::apiCall(QString const& _message) @@ -111,8 +113,25 @@ QString ClientModel::apiCall(QString const& _message) void ClientModel::mine() { - m_client->mine(); - newBlock(); + if (m_running) + BOOST_THROW_EXCEPTION(ExecutionStateException()); + m_running = true; + emit runStarted(); + emit runStateChanged(); + QtConcurrent::run([=]() + { + try + { + m_client->mine(); + newBlock(); + } + catch (...) + { + std::cerr << boost::current_exception_diagnostic_information(); + emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); + } + m_running = false; + }); } QString ClientModel::contractAddress() const @@ -145,7 +164,7 @@ void ClientModel::setupState(QVariantMap _state) TransactionSettings transactionSettings(functionId, transaction.value("url").toString()); transactionSettings.gasPrice = 10000000000000; transactionSettings.gas = 125000; - transactionSettings.value = 100; + transactionSettings.value = 0; transactionSequence.push_back(transactionSettings); } else @@ -242,11 +261,13 @@ void ClientModel::executeSequence(std::vector const& _seque } catch(boost::exception const&) { + std::cerr << boost::current_exception_diagnostic_information(); emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } catch(std::exception const& e) { + std::cerr << boost::current_exception_diagnostic_information(); emit runFailed(e.what()); } m_running = false; @@ -256,7 +277,7 @@ void ClientModel::executeSequence(std::vector const& _seque void ClientModel::showDebugger() { - ExecutionResult const& last = m_client->record().back().transactions.back(); + ExecutionResult const& last = m_client->lastExecution(); showDebuggerForTransaction(last); } @@ -289,7 +310,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) void ClientModel::debugTransaction(unsigned _block, unsigned _index) { - auto const& t = m_client->record().at(_block).transactions.at(_index); + auto const& t = m_client->execution(_block, _index); showDebuggerForTransaction(t); } @@ -320,9 +341,9 @@ void ClientModel::onStateReset() void ClientModel::onNewTransaction() { - unsigned block = m_client->number(); - unsigned index = m_client->record().back().transactions.size() - 1; - ExecutionResult const& tr = m_client->record().back().transactions.back(); + unsigned block = m_client->number() + 1; + unsigned index = m_client->pendingExecutions().size() - 1; + ExecutionResult const& tr = m_client->lastExecution(); QString address = QString::fromStdString(toJS(tr.address)); QString value = QString::fromStdString(dev::toString(tr.value)); QString contract = address; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index a6c833532..7cbb8424b 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -36,35 +36,49 @@ using namespace dev; using namespace dev::eth; using namespace dev::mix; -const Secret c_stdSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); +const Secret c_userAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); -MixClient::MixClient(): - m_userAccount(c_stdSecret) +MixClient::MixClient(std::string const& _dbPath): + m_userAccount(c_userAccountSecret), m_bc(_dbPath, true), m_dbPath(_dbPath), m_minigThreads(0) +{ + //resetState(10000000 * ether); +} + +MixClient::~MixClient() { - resetState(10000000 * ether); } void MixClient::resetState(u256 _balance) { - WriteGuard l(x_state); - Guard fl(m_filterLock); - m_filters.clear(); - m_watches.clear(); - m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Genesis); - m_state.addBalance(m_userAccount.address(), _balance); - Block genesis; - genesis.state = m_state; - Block open; - m_blocks = Blocks { genesis, open }; //last block contains a list of pending transactions to be finalized -// m_lastHashes.clear(); -// m_lastHashes.resize(256); -// m_lastHashes[0] = genesis.hash; + (void) _balance; + { + WriteGuard l(x_state); + Guard fl(m_filterLock); + m_filters.clear(); + m_watches.clear(); + m_bc.reopen(m_dbPath, true); + m_state = eth::State(); + m_stateDB = OverlayDB(); + m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Genesis); + m_state.sync(m_bc); + m_startState = m_state; + m_pendingExecutions.clear(); + } + mine(); } void MixClient::executeTransaction(Transaction const& _t, State& _state) { bytes rlp = _t.rlp(); - Executive execution(_state, LastHashes(), 0); + + // do debugging run first + LastHashes lastHashes(256); + lastHashes[0] = m_bc.numberHash(m_bc.number()); + for (unsigned i = 1; i < 256; ++i) + lastHashes[i] = lastHashes[i - 1] ? m_bc.details(lastHashes[i - 1]).parent : h256(); + + State execState = _state; + Executive execution(execState, lastHashes, 0); execution.setup(&rlp); std::vector machineStates; std::vector levels; @@ -130,21 +144,25 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state) d.value = _t.value(); if (_t.isCreation()) d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); - d.receipt = TransactionReceipt(m_state.rootHash(), execution.gasUsed(), execution.logs()); //TODO: track gas usage - m_blocks.back().transactions.emplace_back(d); + d.receipt = TransactionReceipt(execState.rootHash(), execution.gasUsed(), execution.logs()); //TODO: track gas usage + m_pendingExecutions.emplace_back(std::move(d)); + // execute on a state + _state.execute(lastHashes, rlp, nullptr, true); + + // collect watches h256Set changed; Guard l(m_filterLock); for (std::pair& i: m_filters) - if ((unsigned)i.second.filter.latest() > m_blocks.size() - 1) + if ((unsigned)i.second.filter.latest() > m_bc.number()) { // acceptable number. - auto m = i.second.filter.matches(d.receipt); + auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); if (m.size()) { // filter catches them for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, m_blocks.size())); + i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1)); changed.insert(i.first); } } @@ -152,44 +170,56 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state) noteChanged(changed); } -void MixClient::validateBlock(int _block) const -{ - if (_block != -1 && _block != 0 && (unsigned)_block >= m_blocks.size() - 1) - BOOST_THROW_EXCEPTION(InvalidBlockException() << BlockIndex(_block)); -} - void MixClient::mine() { WriteGuard l(x_state); - Block& block = m_blocks.back(); - m_state.mine(0, true); + m_state.commitToMine(m_bc); + while (!m_state.mine(100, true).completed) {} m_state.completeMine(); - m_state.commitToMine(BlockChain()); - m_state.cleanup(true); - block.state = m_state; - block.info = m_state.info(); - block.hash = block.info.hash; - m_blocks.push_back(Block()); - + m_bc.import(m_state.blockData(), m_stateDB); + m_state.sync(m_bc); + //m_state.cleanup(true); + m_startState = m_state; + m_executions.emplace_back(std::move(m_pendingExecutions)); h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; noteChanged(changed); } -State const& MixClient::asOf(int _block) const +ExecutionResult const& MixClient::execution(unsigned _block, unsigned _transaction) const +{ + if (_block == m_bc.number() + 1) + return m_pendingExecutions.at(_transaction); + return m_executions.at(_block).at(_transaction); +} + +ExecutionResult const& MixClient::lastExecution() const +{ + if (m_pendingExecutions.size() > 0) + return m_pendingExecutions.back(); + return m_executions.back().back(); +} + +ExecutionResults const& MixClient::pendingExecutions() const { - validateBlock(_block); + return m_pendingExecutions; +} + +State MixClient::asOf(int _block) const +{ + ReadGuard l(x_state); if (_block == 0) - return m_blocks[m_blocks.size() - 2].state; - else if (_block == -1) return m_state; + else if (_block == -1) + return m_startState; else - return m_blocks[_block].state; + return State(m_stateDB, m_bc, m_bc.numberHash(_block)); } void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); + _gasPrice = 0; //TODO: remove after fixing setBalance Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); executeTransaction(t, m_state); } @@ -198,6 +228,7 @@ Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init, { WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); + _gasPrice = 0; //TODO: remove after fixing setBalance eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); executeTransaction(t, m_state); Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); @@ -228,36 +259,31 @@ bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _ bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state executeTransaction(t, temp); - return m_blocks.back().transactions.back().returnValue; + return m_pendingExecutions.back().returnValue; } u256 MixClient::balanceAt(Address _a, int _block) const { - ReadGuard l(x_state); return asOf(_block).balance(_a); } u256 MixClient::countAt(Address _a, int _block) const { - ReadGuard l(x_state); return asOf(_block).transactionsFrom(_a); } u256 MixClient::stateAt(Address _a, u256 _l, int _block) const { - ReadGuard l(x_state); return asOf(_block).storage(_a, _l); } bytes MixClient::codeAt(Address _a, int _block) const { - ReadGuard l(x_state); return asOf(_block).code(_a); } std::map MixClient::storageAt(Address _a, int _block) const { - ReadGuard l(x_state); return asOf(_block).storage(_a); } @@ -274,23 +300,40 @@ eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const { LocalisedLogEntries ret; - unsigned lastBlock = m_blocks.size() - 1; //last block contains pending transactions + unsigned lastBlock = m_bc.number(); unsigned block = std::min(lastBlock, (unsigned)_f.latest()); unsigned end = std::min(lastBlock, std::min(block, (unsigned)_f.earliest())); - for (; ret.size() != _f.max() && block != end; block--) + unsigned skip = _f.skip(); + // Pending transactions + if (block > m_bc.number()) { - bool pendingBlock = (block == lastBlock); - if (pendingBlock || _f.matches(m_blocks[block].info.logBloom)) - for (ExecutionResult const& t: m_blocks[block].transactions) - if (pendingBlock || _f.matches(t.receipt.bloom())) + ReadGuard l(x_state); + for (unsigned i = 0; i < m_state.pending().size(); ++i) + { + // Might have a transaction that contains a matching log. + TransactionReceipt const& tr = m_state.receipt(i); + LogEntries logEntries = _f.matches(tr); + for (unsigned entry = 0; entry < logEntries.size() && ret.size() != _f.max(); ++entry) + ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block)); + skip -= std::min(skip, static_cast(logEntries.size())); + } + block = m_bc.number(); + } + + // The rest + auto h = m_bc.numberHash(block); + for (; ret.size() != block && block != end; block--) + { + if (_f.matches(m_bc.info(h).logBloom)) + for (TransactionReceipt receipt: m_bc.receipts(h).receipts) + if (_f.matches(receipt.bloom())) { - LogEntries logEntries = _f.matches(t.receipt); - if (logEntries.size()) - { - for (unsigned entry = _f.skip(); entry < logEntries.size() && ret.size() != _f.max(); ++entry) - ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block)); - } + LogEntries logEntries = _f.matches(receipt); + for (unsigned entry = skip; entry < logEntries.size() && ret.size() != _f.max(); ++entry) + ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block)); + skip -= std::min(skip, static_cast(logEntries.size())); } + h = m_bc.details(h).parent; } return ret; } @@ -372,66 +415,65 @@ LocalisedLogEntries MixClient::checkWatch(unsigned _watchId) h256 MixClient::hashFromNumber(unsigned _number) const { - validateBlock(_number); - return m_blocks[_number].hash; + return m_bc.numberHash(_number); } eth::BlockInfo MixClient::blockInfo(h256 _hash) const { - (void)_hash; - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockInfo")); + return BlockInfo(m_bc.block(_hash)); } eth::BlockDetails MixClient::blockDetails(h256 _hash) const { - (void)_hash; - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockDetails")); + return m_bc.details(_hash); } eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const { - (void)_blockHash; - (void)_i; - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::transaction")); + auto bl = m_bc.block(_blockHash); + RLP b(bl); + if (_i < b[1].itemCount()) + return Transaction(b[1][_i].data(), CheckSignature::Range); + else + return Transaction(); } eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const { - (void)_blockHash; - (void)_i; - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::uncle")); + auto bl = m_bc.block(_blockHash); + RLP b(bl); + if (_i < b[2].itemCount()) + return BlockInfo::fromHeader(b[2][_i].data()); + else + return BlockInfo(); } unsigned MixClient::number() const { - return m_blocks.size() - 1; + return m_bc.number(); } eth::Transactions MixClient::pending() const { - return eth::Transactions(); + return m_state.pending(); } eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const { - (void)_txi; - (void)_block; - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff")); + State st(m_stateDB, m_bc, _block); + return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); } eth::StateDiff MixClient::diff(unsigned _txi, int _block) const { - (void)_txi; - (void)_block; - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff")); + State st = asOf(_block); + return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); } Addresses MixClient::addresses(int _block) const { - validateBlock(_block); - ReadGuard l(x_state); Addresses ret; - for (auto const& i: m_state.addresses()) + for (auto const& i: asOf(_block).addresses()) ret.push_back(i.first); return ret; } @@ -456,23 +498,22 @@ Address MixClient::address() const void MixClient::setMiningThreads(unsigned _threads) { - (void)_threads; - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::setMiningThreads")); + m_minigThreads = _threads; } unsigned MixClient::miningThreads() const { - return 0; + return m_minigThreads; } void MixClient::startMining() { - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::startMining")); + //no-op } void MixClient::stopMining() { - BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::stopMining")); + //no-op } bool MixClient::isMining() diff --git a/mix/MixClient.h b/mix/MixClient.h index c34fff60b..ca0101680 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -24,8 +24,10 @@ #pragma once #include +#include #include #include +#include #include "MachineStates.h" namespace dev @@ -33,26 +35,18 @@ namespace dev namespace mix { -struct Block -{ - ExecutionResults transactions; - h256 hash; - dev::eth::State state; - dev::eth::BlockInfo info; -}; - -using Blocks = std::vector; - - class MixClient: public dev::eth::Interface { public: - MixClient(); + MixClient(std::string const& _dbPath); + virtual ~MixClient(); /// Reset state to the empty state with given balance. void resetState(u256 _balance); KeyPair const& userAccount() const { return m_userAccount; } void mine(); - Blocks const& record() const { return m_blocks; } + ExecutionResult const& execution(unsigned _block, unsigned _transaction) const; + ExecutionResult const& lastExecution() const; + ExecutionResults const& pendingExecutions() const; //dev::eth::Interface void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; @@ -94,18 +88,22 @@ public: private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state); - void validateBlock(int _block) const; void noteChanged(h256Set const& _filters); - dev::eth::State const& asOf(int _block) const; + dev::eth::State asOf(int _block) const; KeyPair m_userAccount; eth::State m_state; + eth::State m_startState; OverlayDB m_stateDB; + eth::BlockChain m_bc; mutable boost::shared_mutex x_state; mutable std::mutex m_filterLock; std::map m_filters; std::map m_watches; - Blocks m_blocks; + std::vector m_executions; + ExecutionResults m_pendingExecutions; + std::string m_dbPath; + unsigned m_minigThreads; }; } diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 247de143f..e6c636514 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -59,8 +59,7 @@ Rectangle { } function hideRightView() { - if (rightView.visible) - rightView.hide(); + rightView.visible = false; } function toggleWebPreview() { From b9584c5f211c6dcdabeb1dc356e9190b857fd3a6 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 4 Feb 2015 17:41:56 +0100 Subject: [PATCH 2/9] style --- mix/ClientModel.cpp | 1 - mix/MixClient.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index ebfd885f1..2eb207576 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -94,7 +94,6 @@ ClientModel::ClientModel(AppContext* _context): ClientModel::~ClientModel() { - } QString ClientModel::apiCall(QString const& _message) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 7cbb8424b..82b5c01d7 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -41,6 +41,7 @@ const Secret c_userAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4d MixClient::MixClient(std::string const& _dbPath): m_userAccount(c_userAccountSecret), m_bc(_dbPath, true), m_dbPath(_dbPath), m_minigThreads(0) { + //TODO: put this into genesis block somehow //resetState(10000000 * ether); } From 1252ed3b881030a6e98222a526cb5be383dd34d4 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Thu, 5 Feb 2015 00:58:20 +0800 Subject: [PATCH 3/9] add several type error test cases --- test/SolidityNameAndTypeResolution.cpp | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 1a087592c..ae6c374b4 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -868,6 +868,42 @@ BOOST_AUTO_TEST_CASE(access_to_protected_state_variable) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(error_count_in_named_args) +{ + char const* sourceCode = "contract test {\n" + " function a(uint a, uint b) returns (uint r) { r = a + b; }\n" + " function b() returns (uint r) { r = a({a: 1}); }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(empty_in_named_args) +{ + char const* sourceCode = "contract test {\n" + " function a(uint a, uint b) returns (uint r) { r = a + b; }\n" + " function b() returns (uint r) { r = a({}); }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(duplicate_parameter_names_in_named_args) +{ + char const* sourceCode = "contract test {\n" + " function a(uint a, uint b) returns (uint r) { r = a + b; }\n" + " function b() returns (uint r) { r = a({a: 1, a: 2}); }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args) +{ + char const* sourceCode = "contract test {\n" + " function a(uint a, uint b) returns (uint r) { r = a + b; }\n" + " function b() returns (uint r) { r = a({a: 1, c: 2}); }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 0a25d83f27e484bfe0329ee15929aee2ae7da479 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Thu, 5 Feb 2015 01:11:53 +0800 Subject: [PATCH 4/9] fix string comparision bug revealed by previous test case This is due to refactoring of m_names using ASTPointer. --- libsolidity/AST.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 6028c07cf..dfb677f7e 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -505,7 +505,7 @@ void FunctionCall::checkTypeRequirements() // check duplicate names for (size_t i = 0; i < m_names.size(); i++) { for (size_t j = i + 1; j < m_names.size(); j++) { - if (m_names[i] == m_names[j]) + if (*m_names[i] == *m_names[j]) BOOST_THROW_EXCEPTION(createTypeError("Duplicate named argument.")); } } From c38ecd95d99f247d5ff669c3bf6493699d93e412 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Feb 2015 10:29:56 -0800 Subject: [PATCH 5/9] Split canon blockchain and basic blockchain. --- alethzero/MainWin.cpp | 17 +++-- libethereum/All.h | 2 +- libethereum/BlockChain.cpp | 62 +++--------------- libethereum/BlockChain.h | 18 +---- libethereum/CanonBlockChain.cpp | 80 ++++++++++++++++++++++- libethereum/CanonBlockChain.h | 76 +++++++++++++++++++-- libethereum/Client.h | 6 +- libethereum/State.cpp | 11 ++-- libethereum/State.h | 4 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 5 +- mix/MixClient.cpp | 6 +- test/fork.cpp | 2 +- test/genesis.cpp | 8 +-- test/state.cpp | 2 +- test/stateOriginal.cpp | 4 +- test/txTest.cpp | 2 +- third/MainWin.cpp | 6 +- 17 files changed, 199 insertions(+), 112 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1921e80cd..8d24dc36c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -136,9 +136,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << BlockChain::genesis().stateRoot << endl; - auto block = BlockChain::createGenesisBlock(); - cerr << "Block Hash: " << BlockChain::genesis().hash << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "Network protocol version: " << c_protocolVersion << endl; @@ -1047,7 +1047,7 @@ void Main::refreshBlockCount() ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); } -static bool blockMatch(string const& _f, BlockDetails const& _b, h256 _h, BlockChain const& _bc) +static bool blockMatch(string const& _f, BlockDetails const& _b, h256 _h, CanonBlockChain const& _bc) { try { @@ -1189,7 +1189,10 @@ void Main::timerEvent(QTimerEvent*) { auto ls = ethereum()->checkWatch(i.first); if (ls.size()) + { + cnote << "FIRING WATCH" << i.first << ls.size(); i.second(ls); + } } } @@ -1202,7 +1205,7 @@ string Main::renderDiff(StateDiff const& _d) const { s << "
"; - AccountDiff const& ad = i.second; + AccountDiff ad = i.second; s << "" << lead(ad.changeType()) << " " << " " << render(i.first).toStdString() << ""; if (!ad.exist.to()) continue; @@ -1210,7 +1213,7 @@ string Main::renderDiff(StateDiff const& _d) const if (ad.balance) { s << "
" << indent << "Balance " << dec << ad.balance.to() << " [=" << formatBalance(ad.balance.to()) << "]"; - auto d = (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from())); + bigint d = (dev::bigint)ad.balance.to() - (dev::bigint)ad.balance.from(); s << " " << showpos << dec << d << " [=" << formatBalance(d) << "]" << noshowpos << ""; } if (ad.nonce) diff --git a/libethereum/All.h b/libethereum/All.h index 11e0d55f3..24109cb87 100644 --- a/libethereum/All.h +++ b/libethereum/All.h @@ -1,7 +1,7 @@ #pragma once #include "Account.h" -#include "BlockChain.h" +#include "CanonBlockChain.h" #include "Client.h" #include "Defaults.h" #include "Executive.h" diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 1addcbc14..11ab08ce6 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -53,30 +53,6 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) return _out; } -std::map const& dev::eth::genesisState() -{ - static std::map s_ret; - if (s_ret.empty()) - { - // Initialise. - for (auto i: vector({ - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "e4157b34ea9615cfbde6b4fda419828124b70c78" - })) - s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation); - } - return s_ret; -} - -std::unique_ptr BlockChain::s_genesis; -boost::shared_mutex BlockChain::x_genesis; - ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub) { #if ALL_COMPILERS_ARE_CPP11_COMPLIANT @@ -91,31 +67,11 @@ ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub) #endif } -bytes BlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - TrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(14) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -BlockChain::BlockChain(std::string _path, bool _killExisting) +BlockChain::BlockChain(bytes const& _genesisBlock, std::string _path, bool _killExisting) { // Initialise with the genesis as the last block on the longest chain. - m_genesisHash = BlockChain::genesis().hash; - m_genesisBlock = BlockChain::createGenesisBlock(); + m_genesisBlock = _genesisBlock; + m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); open(_path, _killExisting); } @@ -353,7 +309,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) } #endif -// cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s ret; // This might be the new best block... @@ -377,7 +333,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, bool _post) const { -// cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); + // cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); if (!_from || !_to) { return h256s(); @@ -386,14 +342,14 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo h256s back; unsigned fn = details(_from).number; unsigned tn = details(_to).number; -// cdebug << "treeRoute" << fn << "..." << tn; + // cdebug << "treeRoute" << fn << "..." << tn; while (fn > tn) { if (_pre) ret.push_back(_from); _from = details(_from).parent; fn--; -// cdebug << "from:" << fn << _from.abridged(); + // cdebug << "from:" << fn << _from.abridged(); } while (fn < tn) { @@ -401,7 +357,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo back.push_back(_to); _to = details(_to).parent; tn--; -// cdebug << "to:" << tn << _to.abridged(); + // cdebug << "to:" << tn << _to.abridged(); } while (_from != _to) { @@ -415,7 +371,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo back.push_back(_to); fn--; tn--; -// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); + // cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); } if (o_common) *o_common = _from; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 4e5d66c9a..50ad78dac 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -69,8 +69,7 @@ ldb::Slice toSlice(h256 _h, unsigned _sub = 0); class BlockChain { public: - BlockChain(bool _killExisting = false): BlockChain(std::string(), _killExisting) {} - BlockChain(std::string _path, bool _killExisting = false); + BlockChain(bytes const& _genesisBlock, std::string _path, bool _killExisting); ~BlockChain(); void reopen(std::string _path, bool _killExisting = false) { close(); open(_path, _killExisting); } @@ -82,7 +81,7 @@ public: /// Sync the chain with any incoming blocks. All blocks should, if processed in order h256s sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); - /// Attempt to import the given block directly into the BlockChain and sync with the state DB. + /// 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. h256s attemptImport(bytes const& _block, OverlayDB const& _stateDB) noexcept; @@ -131,13 +130,6 @@ public: /// togther with all their quoted uncles. h256Set allUnclesFrom(h256 _parent) const; - /// @returns the genesis block header. - static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); s_genesis.reset(new BlockInfo); s_genesis->populate(&gb); } return *s_genesis; } - - /// @returns the genesis block as its RLP-encoded byte array. - /// @note This is slow as it's constructed anew each call. Consider genesis() instead. - static bytes createGenesisBlock(); - /** @returns the hash of all blocks between @a _from and @a _to, all blocks are ordered first by a number of * blocks that are parent-to-child, then two sibling blocks, then a number of blocks that are child-to-parent. * @@ -171,7 +163,7 @@ private: m_extrasDB->Get(m_readOptions, toSlice(_h, N), &s); if (s.empty()) { - // cout << "Not found in DB: " << _h << endl; +// cout << "Not found in DB: " << _h << endl; return _n; } @@ -208,10 +200,6 @@ private: ldb::WriteOptions m_writeOptions; friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); - - /// Static genesis info and its lock. - static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; }; std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 04713dc7e..fc7107154 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -1,12 +1,86 @@ +/* + 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 CanonBlockChain.cpp + * @author Gav Wood + * @date 2014 + */ + #include "CanonBlockChain.h" -CanonBlockChain::CanonBlockChain() -{ +#include +#include +#include +#include +#include +#include +#include +#include +#include "State.h" +#include "Defaults.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +#define ETH_CATCH 1 +std::map const& dev::eth::genesisState() +{ + static std::map s_ret; + if (s_ret.empty()) + { + // Initialise. + for (auto i: vector({ + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "b9c015918bdaba24b4ff057a92a3873d6eb201be", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "e4157b34ea9615cfbde6b4fda419828124b70c78" + })) + s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation); + } + return s_ret; } -CanonBlockChain::~CanonBlockChain() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; + +bytes CanonBlockChain::createGenesisBlock() { + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + TrieDB state(&db); + state.init(); + dev::eth::commit(genesisState(), db, state); + stateRoot = state.root(); + } + block.appendList(14) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); } +CanonBlockChain::CanonBlockChain(std::string _path, bool _killExisting): BlockChain(CanonBlockChain::createGenesisBlock(), _path, _killExisting) +{ +} diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index bc17e23ac..d9739097a 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -1,12 +1,76 @@ -#ifndef CANONBLOCKCHAIN_H -#define CANONBLOCKCHAIN_H +/* + 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. -class CanonBlockChain + 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 CanonBlockChain.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#pragma warning(push) +#pragma warning(disable: 4100 4267) +#include +#pragma warning(pop) + +#include +#include +#include +#include +#include +#include +#include "BlockDetails.h" +#include "Account.h" +#include "BlockQueue.h" +#include "BlockChain.h" +namespace ldb = leveldb; + +namespace dev +{ + +namespace eth +{ + +// TODO: Move all this Genesis stuff into Genesis.h/.cpp +std::map const& genesisState(); + +/** + * @brief Implements the blockchain database. All data this gives is disk-backed. + * @threadsafe + * @todo Make not memory hog (should actually act as a cache and deallocate old entries). + */ +class CanonBlockChain: public BlockChain { public: - CanonBlockChain(); - ~CanonBlockChain(); + CanonBlockChain(bool _killExisting = false): CanonBlockChain(std::string(), _killExisting) {} + CanonBlockChain(std::string _path, bool _killExisting = false); + ~CanonBlockChain() {} + + /// @returns the genesis block header. + static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); s_genesis.reset(new BlockInfo); s_genesis->populate(&gb); } return *s_genesis; } + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock(); + +private: + /// Static genesis info and its lock. + static boost::shared_mutex x_genesis; + static std::unique_ptr s_genesis; }; -#endif // CANONBLOCKCHAIN_H +} +} diff --git a/libethereum/Client.h b/libethereum/Client.h index d53781d90..0476db4fd 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -34,7 +34,7 @@ #include #include #include -#include "BlockChain.h" +#include "CanonBlockChain.h" #include "TransactionQueue.h" #include "State.h" #include "CommonNet.h" @@ -228,7 +228,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; } /// Get the object representing the current canonical blockchain. - BlockChain const& blockChain() const { return m_bc; } + CanonBlockChain const& blockChain() const { return m_bc; } // Mining stuff: @@ -308,7 +308,7 @@ private: State asOf(unsigned _h) const; VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - BlockChain m_bc; ///< Maintains block database. + CanonBlockChain m_bc; ///< Maintains block database. TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 3f81cd4c9..fd5f9187f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -35,6 +35,7 @@ #include "ExtVM.h" #include "Executive.h" #include "CachedAddressState.h" +#include "CanonBlockChain.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -74,18 +75,16 @@ State::State(Address _coinbaseAddress, OverlayDB const& _db, BaseState _bs): paranoia("beginning of normal construction.", true); - if (_bs == BaseState::Genesis) + if (_bs == BaseState::CanonGenesis) { dev::eth::commit(genesisState(), m_db, m_state); m_db.commit(); paranoia("after DB commit of normal construction.", true); - m_previousBlock = BlockChain::genesis(); + m_previousBlock = CanonBlockChain::genesis(); } else - { m_previousBlock.setEmpty(); - } resetCurrent(); @@ -304,7 +303,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.stateRoot != BlockChain::genesis().hash && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash); // push back for later replay. bi.populate(_bc.block(bi.parentHash)); // move to parent. @@ -698,7 +697,7 @@ void State::commitToMine(BlockChain const& _bc) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock != BlockChain::genesis()) + if (m_previousBlock.number != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. // cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; diff --git a/libethereum/State.h b/libethereum/State.h index 0a288238d..65a333fb4 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -53,7 +53,7 @@ struct StateTrace: public LogChannel { static const char* name() { return "=S="; struct StateDetail: public LogChannel { static const char* name() { return "/S/"; } static const int verbosity = 14; }; struct StateSafeExceptions: public LogChannel { static const char* name() { return "(S)"; } static const int verbosity = 21; }; -enum class BaseState { Empty, Genesis }; +enum class BaseState { Empty, CanonGenesis }; /** * @brief Model of the current state of the ledger. @@ -68,7 +68,7 @@ class State public: /// Construct state object. - State(Address _coinbaseAddress = Address(), OverlayDB const& _db = OverlayDB(), BaseState _bs = BaseState::Genesis); + State(Address _coinbaseAddress = Address(), OverlayDB const& _db = OverlayDB(), BaseState _bs = BaseState::CanonGenesis); /// Construct state object from arbitrary point in blockchain. State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index c8aff938f..26a3382c8 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -342,7 +342,10 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_changed(int const& _id) { - return toJson(client()->checkWatch(_id)); + auto entries = client()->checkWatch(_id); + if (entries.size()) + cnote << "FIRING WATCH" << _id << entries.size(); + return toJson(entries); } std::string WebThreeStubServerBase::eth_codeAt(string const& _address) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index a6c833532..ccc67ff50 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -50,7 +50,7 @@ void MixClient::resetState(u256 _balance) Guard fl(m_filterLock); m_filters.clear(); m_watches.clear(); - m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Genesis); + m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::CanonGenesis); m_state.addBalance(m_userAccount.address(), _balance); Block genesis; genesis.state = m_state; @@ -164,7 +164,7 @@ void MixClient::mine() Block& block = m_blocks.back(); m_state.mine(0, true); m_state.completeMine(); - m_state.commitToMine(BlockChain()); + m_state.commitToMine(CanonBlockChain()); m_state.cleanup(true); block.state = m_state; block.info = m_state.info(); diff --git a/test/fork.cpp b/test/fork.cpp index 1cdb8822c..bc6ed87bc 100644 --- a/test/fork.cpp +++ b/test/fork.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include "TestHelper.h" using namespace std; diff --git a/test/genesis.cpp b/test/genesis.cpp index 8cdb84024..7ca741ee9 100644 --- a/test/genesis.cpp +++ b/test/genesis.cpp @@ -24,7 +24,7 @@ #include #include "JsonSpiritHeaders.h" #include -#include +#include #include #include "TestHelper.h" @@ -58,9 +58,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(BlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(BlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(BlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/state.cpp b/test/state.cpp index 100634be3..fb54a62ae 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -24,7 +24,7 @@ #include #include "JsonSpiritHeaders.h" #include -#include +#include #include #include #include diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index b1a7c0d8e..65ff5084f 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include using namespace std; @@ -40,7 +40,7 @@ int stateTest() Defaults::setDBPath(boost::filesystem::temp_directory_path().string()); OverlayDB stateDB = State::openDB(); - BlockChain bc; + CanonBlockChain bc; State s(myMiner.address(), stateDB); cout << bc; diff --git a/test/txTest.cpp b/test/txTest.cpp index cc78c26a2..8d067f9bb 100644 --- a/test/txTest.cpp +++ b/test/txTest.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include "TestHelper.h" using namespace std; diff --git a/third/MainWin.cpp b/third/MainWin.cpp index eae421c24..64f90a761 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -97,8 +97,8 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << BlockChain::genesis().stateRoot << endl; - auto gb = BlockChain::createGenesisBlock(); + cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; cerr << "Block Hex: " << toHex(gb) << endl; From 325ec153892312758a0068daf2a9cb08204d7424 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Feb 2015 11:26:58 -0800 Subject: [PATCH 6/9] Move CommonJS to libethcore. Split it up ready for refactoring into libdevcore/libdevcrypto. --- alethzero/MainWin.cpp | 2 +- alethzero/OurWebThreeStubServer.h | 4 +- {libdevcore => libethcore}/CommonJS.cpp | 51 ++++++++++++----------- {libdevcore => libethcore}/CommonJS.h | 40 +++++++++++++----- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- libweb3jsonrpc/WebThreeStubServerBase.h | 4 +- mix/ClientModel.cpp | 2 +- mix/ContractCallDataEncoder.cpp | 2 +- mix/DebuggingStateWrapper.cpp | 2 +- mix/QBigInt.cpp | 2 +- mix/QBigInt.h | 2 +- mix/QVariableDefinition.cpp | 2 +- test/commonjs.cpp | 5 ++- test/jsonrpc.cpp | 2 +- 14 files changed, 71 insertions(+), 51 deletions(-) rename {libdevcore => libethcore}/CommonJS.cpp (99%) rename {libdevcore => libethcore}/CommonJS.h (94%) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 8d24dc36c..2a0a056a5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 5223d79bd..16981f9e1 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -20,7 +20,7 @@ */ #include -#include +#include #include #include @@ -35,7 +35,7 @@ public: std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; - virtual bool authenticate(dev::TransactionSkeleton const& _t); + virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); signals: void onNewId(QString _s); diff --git a/libdevcore/CommonJS.cpp b/libethcore/CommonJS.cpp similarity index 99% rename from libdevcore/CommonJS.cpp rename to libethcore/CommonJS.cpp index 980cb9081..3ed4e2796 100644 --- a/libdevcore/CommonJS.cpp +++ b/libethcore/CommonJS.cpp @@ -72,6 +72,31 @@ bytes unpadLeft(bytes _b) return _b; } +std::string fromRaw(h256 _n, unsigned* _inc) +{ + if (_n) + { + std::string s((char const*)_n.data(), 32); + auto l = s.find_first_of('\0'); + if (!l) + return ""; + if (l != std::string::npos) + { + auto p = s.find_first_not_of('\0', l); + if (!(p == std::string::npos || (_inc && p == 31))) + return ""; + if (_inc) + *_inc = (byte)s[31]; + s.resize(l); + } + for (auto i: s) + if (i < 32) + return ""; + return s; + } + return ""; +} + std::string prettyU256(u256 _n) { unsigned inc = 0; @@ -98,31 +123,6 @@ std::string prettyU256(u256 _n) return s.str(); } -std::string fromRaw(h256 _n, unsigned* _inc) -{ - if (_n) - { - std::string s((char const*)_n.data(), 32); - auto l = s.find_first_of('\0'); - if (!l) - return ""; - if (l != std::string::npos) - { - auto p = s.find_first_not_of('\0', l); - if (!(p == std::string::npos || (_inc && p == 31))) - return ""; - if (_inc) - *_inc = (byte)s[31]; - s.resize(l); - } - for (auto i: s) - if (i < 32) - return ""; - return s; - } - return ""; -} - Address fromString(std::string const& _sn) { if (_sn.size() == 40) @@ -132,3 +132,4 @@ Address fromString(std::string const& _sn) } } + diff --git a/libdevcore/CommonJS.h b/libethcore/CommonJS.h similarity index 94% rename from libdevcore/CommonJS.h rename to libethcore/CommonJS.h index 59e6c1d34..ccc3b3103 100644 --- a/libdevcore/CommonJS.h +++ b/libethcore/CommonJS.h @@ -24,9 +24,11 @@ #pragma once #include -#include -#include "Common.h" -#include "CommonData.h" +#include +#include +#include +#include +#include "CommonEth.h" namespace dev { @@ -94,16 +96,8 @@ template boost::multiprecision::number(_s); } -inline Public jsToPublic(std::string const& _s) { return jsToFixed(_s); } -inline Secret jsToSecret(std::string const& _s) { return jsToFixed(_s); } inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); } -inline std::string jsToBinary(std::string const& _s) -{ - return dev::toString(unpadded(jsToBytes(_s))); -} - inline std::string jsToDecimal(std::string const& _s) { return dev::toString(jsToU256(_s)); @@ -125,6 +119,29 @@ inline double jsFromFixed(std::string const& _s) return (double)jsToU256(_s) / (double)(dev::u256(1) << 128); } +} + +// devcrypto + +#include + +namespace dev +{ + +inline Public jsToPublic(std::string const& _s) { return jsToFixed(_s); } +inline Secret jsToSecret(std::string const& _s) { return jsToFixed(_s); } + +} + + +// ethcore +namespace dev +{ +namespace eth +{ + +inline Address jsToAddress(std::string const& _s) { return jsToFixed(_s); } + struct TransactionSkeleton { Address from; @@ -136,3 +153,4 @@ struct TransactionSkeleton }; } +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 26a3382c8..bcaa31036 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ee583efa3..ffb9e1738 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -36,9 +36,9 @@ namespace dev { class WebThreeNetworkFace; class KeyPair; -struct TransactionSkeleton; namespace eth { +struct TransactionSkeleton; class Interface; } namespace shh @@ -122,7 +122,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::TransactionSkeleton const& _t); + virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); protected: virtual dev::eth::Interface* client() = 0; diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 91e6bdd83..3a2b50999 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include "AppContext.h" #include "DebuggingStateWrapper.h" diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index bdec95ca4..29b43bc11 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include "QVariableDeclaration.h" #include "QVariableDefinition.h" diff --git a/mix/DebuggingStateWrapper.cpp b/mix/DebuggingStateWrapper.cpp index 42d0c97ac..d32be4989 100644 --- a/mix/DebuggingStateWrapper.cpp +++ b/mix/DebuggingStateWrapper.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/mix/QBigInt.cpp b/mix/QBigInt.cpp index 191d20459..21d32a9c3 100644 --- a/mix/QBigInt.cpp +++ b/mix/QBigInt.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include "QBigInt.h" using namespace dev; diff --git a/mix/QBigInt.h b/mix/QBigInt.h index c6ec72305..0712ff984 100644 --- a/mix/QBigInt.h +++ b/mix/QBigInt.h @@ -26,7 +26,7 @@ #include "boost/variant/multivisitors.hpp" #include #include -#include +#include #include using namespace dev; diff --git a/mix/QVariableDefinition.cpp b/mix/QVariableDefinition.cpp index a76388d68..c78273f99 100644 --- a/mix/QVariableDefinition.cpp +++ b/mix/QVariableDefinition.cpp @@ -20,7 +20,7 @@ */ #include -#include +#include #include "QVariableDefinition.h" using namespace dev::mix; diff --git a/test/commonjs.cpp b/test/commonjs.cpp index 860b713dd..041a14f68 100644 --- a/test/commonjs.cpp +++ b/test/commonjs.cpp @@ -20,7 +20,8 @@ */ #include -#include +#include +#include BOOST_AUTO_TEST_SUITE(commonjs) using namespace std; @@ -41,7 +42,7 @@ BOOST_AUTO_TEST_CASE(jsToAddress) cnote << "Testing jsToPublic..."; KeyPair kp = KeyPair::create(); string string = toJS(kp.address()); - Address address = dev::jsToAddress(string); + Address address = dev::eth::jsToAddress(string); BOOST_CHECK_EQUAL(kp.address(), address); } diff --git a/test/jsonrpc.cpp b/test/jsonrpc.cpp index 1f0a466b2..eaa9edc45 100644 --- a/test/jsonrpc.cpp +++ b/test/jsonrpc.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include From 91165617b56faddc71b4ce8672daf10b4c82722d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Feb 2015 12:07:30 -0800 Subject: [PATCH 7/9] Serpent update. --- libserpent/compiler.cpp | 92 ++++++++++------------------------------- libserpent/compiler.h | 5 +-- libserpent/util.cpp | 3 +- pullSerpent.sh | 5 ++- sc/cmdline.cpp | 5 +-- 5 files changed, 28 insertions(+), 82 deletions(-) diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp index 886eee6df..d19ef4354 100644 --- a/libserpent/compiler.cpp +++ b/libserpent/compiler.cpp @@ -77,43 +77,12 @@ Node popwrap(Node node) { return multiToken(nodelist, 2, node.metadata); } -// Grabs variables -mss getVariables(Node node, mss cur=mss()) { - Metadata m = node.metadata; - // Tokens don't contain any variables - if (node.type == TOKEN) - return cur; - // Don't descend into call fragments - else if (node.val == "lll") - return getVariables(node.args[1], cur); - // At global scope get/set/ref also declare - else if (node.val == "get" || node.val == "set" || node.val == "ref") { - if (node.args[0].type != TOKEN) - err("Variable name must be simple token," - " not complex expression! " + printSimple(node.args[0]), m); - if (!cur.count(node.args[0].val)) { - cur[node.args[0].val] = utd(cur.size() * 32 + 32); - //std::cerr << node.args[0].val << " " << cur[node.args[0].val] << "\n"; - } - } - // Recursively process children - for (unsigned i = 0; i < node.args.size(); i++) { - cur = getVariables(node.args[i], cur); - } - return cur; -} - // Turns LLL tree into tree of code fragments programData opcodeify(Node node, programAux aux=Aux(), programVerticalAux vaux=verticalAux()) { std::string symb = "_"+mkUniqueToken(); Metadata m = node.metadata; - // Get variables - if (!aux.vars.size()) { - aux.vars = getVariables(node); - aux.nextVarMem = aux.vars.size() * 32 + 32; - } // Numbers if (node.type == TOKEN) { return pd(aux, nodeToNumeric(node), 1); @@ -121,6 +90,10 @@ programData opcodeify(Node node, else if (node.val == "ref" || node.val == "get" || node.val == "set") { std::string varname = node.args[0].val; // Determine reference to variable + if (!aux.vars.count(node.args[0].val)) { + aux.vars[node.args[0].val] = utd(aux.nextVarMem); + aux.nextVarMem += 32; + } Node varNode = tkn(aux.vars[varname], m); //std::cerr << varname << " " << printSimple(varNode) << "\n"; // Set variable @@ -173,8 +146,7 @@ programData opcodeify(Node node, } // Comments do nothing else if (node.val == "comment") { - Node* nodelist = nullptr; - return pd(aux, multiToken(nodelist, 0, m), 0); + return pd(aux, astnode("_", m), 0); } // Custom operation sequence // eg. (ops bytez id msize swap1 msize add 0 swap1 mstore) == alloc @@ -371,7 +343,7 @@ Node buildFragmentTree(Node node) { // Builds a dictionary mapping labels to variable names -programAux buildDict(Node program, programAux aux, int labelLength) { +void buildDict(Node program, programAux &aux, int labelLength) { Metadata m = program.metadata; // Token if (program.type == TOKEN) { @@ -388,30 +360,24 @@ programAux buildDict(Node program, programAux aux, int labelLength) { } // A sub-program (ie. LLL) else if (program.val == "____CODE") { - programAux auks = Aux(); + int step = aux.step; + aux.step = 0; for (unsigned i = 0; i < program.args.size(); i++) { - auks = buildDict(program.args[i], auks, labelLength); + buildDict(program.args[i], aux, labelLength); } - for (std::map::iterator it=auks.vars.begin(); - it != auks.vars.end(); - it++) { - aux.vars[(*it).first] = (*it).second; - } - aux.step += auks.step; + aux.step += step; } // Normal sub-block else { for (unsigned i = 0; i < program.args.size(); i++) { - aux = buildDict(program.args[i], aux, labelLength); + buildDict(program.args[i], aux, labelLength); } } - return aux; } // Applies that dictionary -Node substDict(Node program, programAux aux, int labelLength) { +void substDict(Node program, programAux aux, int labelLength, std::vector &out) { Metadata m = program.metadata; - std::vector out; std::vector inner; if (program.type == TOKEN) { if (program.val[0] == '$') { @@ -428,46 +394,32 @@ Node substDict(Node program, programAux aux, int labelLength) { dist = decimalSub(end, start); inner = toByteArr(dist, m, labelLength); } - out.push_back(astnode("_", inner, m)); + for (unsigned i = 0; i < inner.size(); i++) out.push_back(inner[i]); } else if (program.val[0] == '~') { } else if (isNumberLike(program)) { inner = toByteArr(program.val, m); out.push_back(token("PUSH"+unsignedToDecimal(inner.size()))); - out.push_back(astnode("_", inner, m)); + for (unsigned i = 0; i < inner.size(); i++) out.push_back(inner[i]); } - else return program; + else out.push_back(program); } else { for (unsigned i = 0; i < program.args.size(); i++) { - Node n = substDict(program.args[i], aux, labelLength); - if (n.type == TOKEN || n.args.size()) out.push_back(n); + substDict(program.args[i], aux, labelLength, out); } } - return astnode("_", out, m); } // Compiled fragtree -> compiled fragtree without labels -Node dereference(Node program) { +std::vector dereference(Node program) { int sz = treeSize(program) * 4; int labelLength = 1; while (sz >= 256) { labelLength += 1; sz /= 256; } - programAux aux = buildDict(program, Aux(), labelLength); - return substDict(program, aux, labelLength); -} - -// Dereferenced fragtree -> opcodes -std::vector flatten(Node derefed) { + programAux aux = Aux(); + buildDict(program, aux, labelLength); std::vector o; - if (derefed.type == TOKEN) { - o.push_back(derefed); - } - else { - for (unsigned i = 0; i < derefed.args.size(); i++) { - std::vector oprime = flatten(derefed.args[i]); - for (unsigned j = 0; j < oprime.size(); j++) o.push_back(oprime[j]); - } - } + substDict(program, aux, labelLength, o); return o; } @@ -512,12 +464,12 @@ std::vector deserialize(std::string ser) { // Fragtree -> bin std::string assemble(Node fragTree) { - return serialize(flatten(dereference(fragTree))); + return serialize(dereference(fragTree)); } // Fragtree -> tokens std::vector prettyAssemble(Node fragTree) { - return flatten(dereference(fragTree)); + return dereference(fragTree); } // LLL -> bin diff --git a/libserpent/compiler.h b/libserpent/compiler.h index aecaa3718..cae87399d 100644 --- a/libserpent/compiler.h +++ b/libserpent/compiler.h @@ -8,14 +8,11 @@ #include "util.h" // Compiled fragtree -> compiled fragtree without labels -Node dereference(Node program); +std::vector dereference(Node program); // LLL -> fragtree Node buildFragmentTree(Node program); -// Dereferenced fragtree -> opcodes -std::vector flatten(Node derefed); - // opcodes -> bin std::string serialize(std::vector codons); diff --git a/libserpent/util.cpp b/libserpent/util.cpp index 18a8bafc2..5e83c0e41 100755 --- a/libserpent/util.cpp +++ b/libserpent/util.cpp @@ -5,7 +5,6 @@ #include "util.h" #include "bignum.h" #include -#include #include //Token or value node constructor @@ -260,7 +259,7 @@ std::string get_file_contents(std::string filename) { std::string contents; in.seekg(0, std::ios::end); - contents.resize((unsigned)in.tellg()); + contents.resize(in.tellg()); in.seekg(0, std::ios::beg); in.read(&contents[0], contents.size()); in.close(); diff --git a/pullSerpent.sh b/pullSerpent.sh index c159e3075..5f8bed05d 100755 --- a/pullSerpent.sh +++ b/pullSerpent.sh @@ -2,10 +2,11 @@ opwd="$PWD" cd ../serpent +git stash git pull +git stash pop cp bignum.* compiler.* funcs.* lllparser.* opcodes.h parser.* rewriter.* tokenize.* util.* ../cpp-ethereum/libserpent/ cp cmdline.* "$opwd/sc/" -cp pyserpent.* "$opwd/libpyserpent/" cd "$opwd" -perl -i -p -e 's:include "funcs.h":include :gc' sc/* libpyserpent/* +perl -i -p -e 's:include "funcs.h":include :gc' sc/* diff --git a/sc/cmdline.cpp b/sc/cmdline.cpp index a5fed37d6..04cdeaaf3 100644 --- a/sc/cmdline.cpp +++ b/sc/cmdline.cpp @@ -68,7 +68,7 @@ int main(int argv, char** argc) { std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n"; } else if (command == "dereference") { - std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n"; + std::cout << printTokens(dereference(parseLLL(input, true))) <<"\n"; } else if (command == "pretty_assemble") { std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n"; @@ -88,9 +88,6 @@ int main(int argv, char** argc) { else if (command == "serialize") { std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n"; } - else if (command == "flatten") { - std::cout << printTokens(flatten(parseLLL(input, true))) << "\n"; - } else if (command == "deserialize") { std::cout << printTokens(deserialize(hexToBin(input))) << "\n"; } From 5bd705b9f9d52ba50d3216c4f6444aa98f3bfaab Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Feb 2015 12:36:22 -0800 Subject: [PATCH 8/9] Wait until network is fully initialised before connecting. --- build.py | 27 --------------------------- libdevcrypto/TrieDB.h | 2 +- libp2p/Host.cpp | 6 ++++++ 3 files changed, 7 insertions(+), 28 deletions(-) delete mode 100755 build.py diff --git a/build.py b/build.py deleted file mode 100755 index 099a8721d..000000000 --- a/build.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/python -# cpp-ethereum build script -# to be used from CI server, or to build locally -# uses python instead of bash script for better cross-platform support - -# TODO Initial version. Needs much more improvements - -import argparse -import os -import subprocess - -def build_dependencies(): - if os.path.exists("extdep"): - os.chdir("extdep") - if not os.path.exists("build"): - os.makedirs("build") - os.chdir("build") - subprocess.check_call(["cmake", ".."]) - subprocess.check_call("make") - -parser = argparse.ArgumentParser() -parser.add_argument("cmd", help="what to build") - -args = parser.parse_args() -if args.cmd == "dep": - build_dependencies() - diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index b42d67aea..3da63edf4 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -49,7 +49,7 @@ extern const h256 EmptyTrie; /** * @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree. - * This version uses an database backend. + * This version uses a database backend. * Usage: * @code * GenericTrieDB t(&myDB); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 4cc985d65..a6267b7e9 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -378,6 +378,8 @@ string Host::pocHost() void Host::connect(std::string const& _addr, unsigned short _port) noexcept { + while (isWorking() && !m_run) + this_thread::sleep_for(chrono::milliseconds(50)); if (!m_run) return; @@ -409,6 +411,8 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept void Host::connect(bi::tcp::endpoint const& _ep) { + while (isWorking() && !m_run) + this_thread::sleep_for(chrono::milliseconds(50)); if (!m_run) return; @@ -430,6 +434,8 @@ void Host::connect(bi::tcp::endpoint const& _ep) void Host::connect(std::shared_ptr const& _n) { + while (isWorking() && !m_run) + this_thread::sleep_for(chrono::milliseconds(50)); if (!m_run) return; From cba12caf3e357bf20e69e406aa2d0c0728d50224 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 4 Feb 2015 12:52:59 -0800 Subject: [PATCH 9/9] Version bump. --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 428c86d66..365f65202 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.8.0"; +char const* Version = "0.8.1"; }