diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 8cde476c3..fce3200cb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -805,6 +805,7 @@ void Main::readSettings(bool _skipGeometry) ui->usePrivate->setChecked(m_privateChain.size()); ui->verbosity->setValue(s.value("verbosity", 1).toInt()); ui->jitvm->setChecked(s.value("jitvm", true).toBool()); + on_jitvm_triggered(); ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html on_urlEdit_returnPressed(); diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index eb8588ceb..53535a489 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -21,7 +21,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE") if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX") diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 0d6a6e00a..68161526d 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -51,7 +51,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.timestamp = static_cast(_ext.currentBlock.timestamp); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); - m_data.codeHash = eth2llvm(sha3(_ext.code)); + m_data.codeHash = eth2llvm(_ext.codeHash); auto env = reinterpret_cast(&_ext); auto exitCode = m_engine.run(&m_data, env); diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index b701fed8d..9fffe784e 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -264,7 +264,6 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Element x; { - Guard l(x_curve); m_curve.DecodePoint(x, encodedpoint, 33); if (!m_curve.VerifyPoint(x)) return recovered; @@ -286,7 +285,6 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Point p; byte recoveredbytes[65]; { - Guard l(x_curve); // todo: make generator member p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); m_curve.EncodePoint(recoveredbytes, p, false); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 67e42d7c8..1c4d0073f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include "GenesisInfo.h" #include "State.h" #include "Defaults.h" + using namespace std; using namespace dev; using namespace dev::eth; @@ -307,7 +309,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st { // _bq.tick(*this); - vector> blocks; + VerifiedBlocks blocks; _bq.drain(blocks, _max); h256s fresh; @@ -320,7 +322,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE(Block import, 500) - r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); fresh += r.first; dead += r.second; } @@ -329,14 +331,14 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st cwarn << "ODD: Import queue contains block with unknown parent." << LogTag::Error << boost::current_exception_diagnostic_information(); // NOTE: don't reimport since the queue should guarantee everything in the right order. // Can't continue - chain bad. - badBlocks.push_back(block.first.hash()); + badBlocks.push_back(block.verified.info.hash()); } catch (Exception const& _e) { cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(_e); // NOTE: don't reimport since the queue should guarantee everything in the right order. // Can't continue - chain bad. - badBlocks.push_back(block.first.hash()); + badBlocks.push_back(block.verified.info.hash()); } } return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); @@ -346,7 +348,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(_block, _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(_block, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -369,14 +371,13 @@ pair BlockChain::attemptImport(bytes const& _block, O ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) { // VERIFY: populates from the block and checks the block is internally coherent. - BlockInfo bi; + VerifiedBlockRef block; #if ETH_CATCH try #endif { - bi.populate(&_block); - bi.verifyInternals(&_block); + block = verifyBlock(_block, _ir); } #if ETH_CATCH catch (Exception const& _e) @@ -387,10 +388,10 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import } #endif - return import(bi, _block, _db, _ir); + return import(block, _db, _ir); } -ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) +ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -405,28 +406,28 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla #endif // Check block doesn't already exist first! - if (isKnown(_bi.hash()) && (_ir & ImportRequirements::DontHave)) + if (isKnown(_block.info.hash()) && (_ir & ImportRequirements::DontHave)) { - clog(BlockChainNote) << _bi.hash() << ": Not new."; + clog(BlockChainNote) << _block.info.hash() << ": Not new."; BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); } // Work out its number as the parent's number + 1 - if (!isKnown(_bi.parentHash)) + if (!isKnown(_block.info.parentHash)) { - clog(BlockChainNote) << _bi.hash() << ": Unknown parent " << _bi.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_bi.parentHash); + auto pd = details(_block.info.parentHash); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_bi.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_bi.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _bi.number; + auto parentBlock = block(_block.info.parentHash); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -434,14 +435,14 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla } // Check it's not crazy - if (_bi.timestamp > (u256)time(0)) + if (_block.info.timestamp > (u256)time(0)) { - clog(BlockChainChat) << _bi.hash() << ": Future time " << _bi.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } - clog(BlockChainChat) << "Attempting import of " << _bi.hash() << "..."; + clog(BlockChainChat) << "Attempting import of " << _block.info.hash() << "..."; #if ETH_TIMED_IMPORTS preliminaryChecks = t.elapsed(); @@ -461,7 +462,7 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(&_block, _bi, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this, _ir); BlockLogBlooms blb; BlockReceipts br; @@ -497,22 +498,22 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_bi.parentHash); + details(_block.info.parentHash); DEV_WRITE_GUARDED(x_details) - m_details[_bi.parentHash].children.push_back(_bi.hash()); + m_details[_block.info.parentHash].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); t.restart(); #endif - blocksBatch.Put(toSlice(_bi.hash()), (ldb::Slice)ref(_block)); + blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_bi.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _bi.parentHash, {}).rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); #if ETH_TIMED_IMPORTS || !ETH_TRUE writing = t.elapsed(); @@ -530,20 +531,20 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla { clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(_e); _e << errinfo_comment("Malformed block "); - clog(BlockChainWarn) << "Block: " << _bi.hash(); - clog(BlockChainWarn) << _bi; - clog(BlockChainWarn) << "Block parent: " << _bi.parentHash; - clog(BlockChainWarn) << BlockInfo(block(_bi.parentHash)); + clog(BlockChainWarn) << "Block: " << _block.info.hash(); + clog(BlockChainWarn) << _block.info; + clog(BlockChainWarn) << "Block parent: " << _block.info.parentHash; + clog(BlockChainWarn) << BlockInfo(block(_block.info.parentHash)); throw; } #endif StructuredLogger::chainReceivedNewBlock( - _bi.headerHash(WithoutNonce).abridged(), - _bi.nonce.abridged(), + _block.info.headerHash(WithoutNonce).abridged(), + _block.info.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _bi.parentHash.abridged() + _block.info.parentHash.abridged() ); // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; @@ -556,8 +557,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _bi.parentHash); - route.push_back(_bi.hash()); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be if (common != last) @@ -569,8 +570,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i) { BlockInfo tbi; - if (*i == _bi.hash()) - tbi = _bi; + if (*i == _block.info.hash()) + tbi = _block.info; else tbi = BlockInfo(block(*i)); @@ -597,7 +598,7 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla h256s newTransactionAddresses; { bytes blockBytes; - RLP blockRLP(*i == _bi.hash() ? _block : (blockBytes = block(*i))); + RLP blockRLP(*i == _block.info.hash() ? _block.block : &(blockBytes = block(*i))); TransactionAddress ta; ta.blockHash = tbi.hash(); for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index) @@ -613,17 +614,17 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // FINALLY! change our best hash. { - newLastBlockHash = _bi.hash(); - newLastBlockNumber = (unsigned)_bi.number; + newLastBlockHash = _block.info.hash(); + newLastBlockNumber = (unsigned)_block.info.number; } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _bi.number << "). Has" << (details(_bi.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _bi.headerHash(WithoutNonce).abridged(), - _bi.nonce.abridged(), + _block.info.headerHash(WithoutNonce).abridged(), + _block.info.nonce.abridged(), currentHash().abridged(), - _bi.parentHash.abridged() + _block.info.parentHash.abridged() ); } else @@ -634,24 +635,26 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla m_blocksDB->Write(m_writeOptions, &blocksBatch); m_extrasDB->Write(m_writeOptions, &extrasBatch); - if (isKnown(_bi.hash()) && !details(_bi.hash())) +#if ETH_DEBUG || !ETH_TRUE + if (isKnown(_block.info.hash()) && !details(_block.info.hash())) { clog(BlockChainDebug) << "Known block just inserted has no details."; - clog(BlockChainDebug) << "Block:" << _bi; + clog(BlockChainDebug) << "Block:" << _block.info; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); } try { - State canary(_db, *this, _bi.hash(), ImportRequirements::DontHave); + State canary(_db, *this, _block.info.hash(), ImportRequirements::DontHave); } catch (...) { clog(BlockChainDebug) << "Failed to initialise State object form imported block."; - clog(BlockChainDebug) << "Block:" << _bi; + clog(BlockChainDebug) << "Block:" << _block.info; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); } +#endif if (m_lastBlockHash != newLastBlockHash) DEV_WRITE_GUARDED(x_lastBlockHash) @@ -1054,3 +1057,78 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } + +VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, ImportRequirements::value) +{ + VerifiedBlockRef res; + try + { + res.info.populate(_block, CheckEverything); + res.info.verifyInternals(&_block); + } + catch (InvalidBlockNonce&) + { + badBlock(_block, "Invalid block nonce"); + cwarn << " Nonce:" << res.info.nonce.hex(); + cwarn << " PoWHash:" << res.info.headerHash(WithoutNonce).hex(); + cwarn << " SeedHash:" << res.info.seedHash().hex(); + cwarn << " Target:" << res.info.boundary().hex(); + cwarn << " MixHash:" << res.info.mixHash.hex(); + Ethash::Result er = EthashAux::eval(res.info.seedHash(), res.info.headerHash(WithoutNonce), res.info.nonce); + cwarn << " Ethash v:" << er.value.hex(); + cwarn << " Ethash mH:" << er.mixHash.hex(); + throw; + } + catch (Exception& _e) + { + badBlock(_block, _e.what()); + throw; + } + + RLP r(&_block); + for (auto const& uncle: r[2]) + { + try + { + BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); + } + catch (InvalidNonce&) + { + badBlockHeader(uncle.data(), "Invalid uncle nonce"); + BlockInfo bi = BlockInfo::fromHeader(uncle.data(), CheckNothing); + cwarn << " Nonce:" << bi.nonce.hex(); + cwarn << " PoWHash:" << bi.headerHash(WithoutNonce).hex(); + cwarn << " SeedHash:" << bi.seedHash().hex(); + cwarn << " Target:" << bi.boundary().hex(); + cwarn << " MixHash:" << bi.mixHash.hex(); + Ethash::Result er = EthashAux::eval(bi.seedHash(), bi.headerHash(WithoutNonce), bi.nonce); + cwarn << " Ethash v:" << er.value.hex(); + cwarn << " Ethash mH:" << er.mixHash.hex(); + throw; + } + catch (Exception& _e) + { + badBlockHeader(uncle.data(), _e.what()); + throw; + } + } + + unsigned i = 0; + for (auto const& tr: r[1]) + { + try + { + res.transactions.push_back(Transaction(tr.data(), CheckTransaction::Everything)); + } + catch (...) + { + badBlock(_block, "Invalid transaction"); + cwarn << " Transaction Index:" << i; + throw; + } + ++i; + } + res.block = bytesConstRef(&_block); + return move(res); +} + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index a67ec9a9c..e05de885a 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -40,6 +40,7 @@ #include "Account.h" #include "Transaction.h" #include "BlockQueue.h" +#include "VerifiedBlock.h" namespace ldb = leveldb; namespace std @@ -120,7 +121,7 @@ public: /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -256,6 +257,9 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); + /// Verify block and prepare it for enactment + static VerifiedBlockRef verifyBlock(bytes const& _block, ImportRequirements::value _ir = ImportRequirements::Default); + private: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 360bf915e..b6d427e29 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -22,10 +22,11 @@ #include "BlockQueue.h" #include #include -#include #include #include #include "BlockChain.h" +#include "VerifiedBlock.h" + using namespace std; using namespace dev; using namespace dev::eth; @@ -71,62 +72,14 @@ void BlockQueue::verifierBody() m_unverified.pop_front(); BlockInfo bi; bi.mixHash = work.first; - m_verifying.push_back(make_pair(bi, bytes())); + m_verifying.push_back(VerifiedBlock { VerifiedBlockRef { bytesConstRef(), move(bi), Transactions() }, bytes() }); } - std::pair res; - swap(work.second, res.second); - try { - try { - res.first.populate(res.second, CheckEverything, work.first); - res.first.verifyInternals(&res.second); - } - catch (InvalidBlockNonce&) - { - badBlock(res.second, "Invalid block nonce"); - cwarn << " Nonce:" << res.first.nonce.hex(); - cwarn << " PoWHash:" << res.first.headerHash(WithoutNonce).hex(); - cwarn << " SeedHash:" << res.first.seedHash().hex(); - cwarn << " Target:" << res.first.boundary().hex(); - cwarn << " MixHash:" << res.first.mixHash.hex(); - Ethash::Result er = EthashAux::eval(res.first.seedHash(), res.first.headerHash(WithoutNonce), res.first.nonce); - cwarn << " Ethash v:" << er.value.hex(); - cwarn << " Ethash mH:" << er.mixHash.hex(); - throw; - } - catch (Exception& _e) - { - badBlock(res.second, _e.what()); - throw; - } - - RLP r(&res.second); - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (InvalidNonce&) - { - badBlockHeader(uncle.data(), "Invalid uncle nonce"); - BlockInfo bi = BlockInfo::fromHeader(uncle.data(), CheckNothing); - cwarn << " Nonce:" << bi.nonce.hex(); - cwarn << " PoWHash:" << bi.headerHash(WithoutNonce).hex(); - cwarn << " SeedHash:" << bi.seedHash().hex(); - cwarn << " Target:" << bi.boundary().hex(); - cwarn << " MixHash:" << bi.mixHash.hex(); - Ethash::Result er = EthashAux::eval(bi.seedHash(), bi.headerHash(WithoutNonce), bi.nonce); - cwarn << " Ethash v:" << er.value.hex(); - cwarn << " Ethash mH:" << er.mixHash.hex(); - throw; - } - catch (Exception& _e) - { - badBlockHeader(uncle.data(), _e.what()); - throw; - } - } + VerifiedBlock res; + swap(work.second, res.blockData); + try + { + res.verified = BlockChain::verifyBlock(res.blockData); } catch (...) { @@ -141,7 +94,7 @@ void BlockQueue::verifierBody() unique_lock l(m_verification); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->first.mixHash == work.first) + if (it->verified.info.mixHash == work.first) { m_verifying.erase(it); goto OK1; @@ -154,12 +107,12 @@ void BlockQueue::verifierBody() bool ready = false; { unique_lock l(m_verification); - if (m_verifying.front().first.mixHash == work.first) + if (m_verifying.front().verified.info.mixHash == work.first) { // we're next! m_verifying.pop_front(); m_verified.push_back(move(res)); - while (m_verifying.size() && !m_verifying.front().second.empty()) + while (m_verifying.size() && !m_verifying.front().blockData.empty()) { m_verified.push_back(move(m_verifying.front())); m_verifying.pop_front(); @@ -169,7 +122,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.first.mixHash == work.first) + if (i.verified.info.mixHash == work.first) { i = move(res); goto OK; @@ -277,15 +230,15 @@ bool BlockQueue::doneDrain(h256s const& _bad) m_drainingSet.clear(); if (_bad.size()) { - vector> old; + vector old; DEV_GUARDED(m_verification) swap(m_verified, old); for (auto& b: old) { - if (m_knownBad.count(b.first.parentHash)) + if (m_knownBad.count(b.verified.info.parentHash)) { - m_knownBad.insert(b.first.hash()); - m_readySet.erase(b.first.hash()); + m_knownBad.insert(b.verified.info.hash()); + m_readySet.erase(b.verified.info.hash()); } else DEV_GUARDED(m_verification) @@ -348,7 +301,7 @@ QueueStatus BlockQueue::blockStatus(h256 const& _h) const QueueStatus::Unknown; } -void BlockQueue::drain(std::vector>& o_out, unsigned _max) +void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; @@ -364,7 +317,7 @@ void BlockQueue::drain(std::vector>& o_out, unsigned for (auto const& bs: o_out) { // TODO: @optimise use map rather than vector & set. - auto h = bs.first.hash(); + auto h = bs.verified.info.hash(); m_drainingSet.insert(h); m_readySet.erase(h); } diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index 45043559b..0473f173f 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -31,6 +31,7 @@ #include #include #include +#include "VerifiedBlock.h" namespace dev { @@ -81,7 +82,7 @@ public: /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. - void drain(std::vector>& o_out, unsigned _max); + void drain(std::vector& o_out, unsigned _max); /// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them. /// @returns true iff there are additional blocks ready to be processed. @@ -128,8 +129,8 @@ private: mutable Mutex m_verification; ///< Mutex that allows writing to m_verified, m_verifying and m_unverified. std::condition_variable m_moreToVerify; ///< Signaled when m_unverified has a new entry. - std::vector> m_verified; ///< List of blocks, in correct order, verified and ready for chain-import. - std::deque> m_verifying; ///< List of blocks being verified; as long as the second component (bytes) is empty, it's not finished. + std::vector m_verified; ///< List of blocks, in correct order, verified and ready for chain-import. + std::deque m_verifying; ///< List of blocks being verified; as long as the second component (bytes) is empty, it's not finished. std::deque> m_unverified; ///< List of blocks, in correct order, ready for verification. std::vector m_verifiers; ///< Threads who only verify. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 10481cdf0..1caaac9c2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -174,7 +174,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for } Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth"), + Worker("eth", 0), m_vc(_dbPath), m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), m_gp(_gp), diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 5ec5f7313..7acef5cd6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -151,7 +151,8 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co { m_outRef = _p.out; // Save ref to expected output buffer to be used in go() bytes const& c = m_s.code(_p.codeAddress); - m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth); + h256 codeHash = m_s.codeHash(_p.codeAddress); + m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, codeHash, m_depth); } } @@ -171,7 +172,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g // Execute _init. if (!_init.empty()) - m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); + m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), m_depth); m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception); m_s.transferBalance(_sender, m_newAddress, _endowment); diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index babff4edf..853787493 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace { public: /// Full constructor. - ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0): - ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache) + ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, unsigned _depth = 0): + ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache) { m_s.ensureCached(_myAddress, true, true); } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index f40574fde..d694e78f1 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -141,7 +141,7 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequire // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; - enact(&b, _bc, _ir); + enact(BlockChain::verifyBlock(b, _ir), _bc, _ir); } else { @@ -382,7 +382,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { #if ETH_TIMED_ENACTMENTS boost::timer t; @@ -393,8 +393,8 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const #endif // Check family: - BlockInfo biParent = _bc.info(_bi.parentHash); - _bi.verifyParent(biParent); + BlockInfo biParent = _bc.info(_block.info.parentHash); + _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS populateVerify = t.elapsed(); @@ -410,7 +410,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const t.restart(); #endif - sync(_bc, _bi.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo(), _ir); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -592,15 +592,12 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ss.str(); } -u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { // m_currentBlock is assumed to be prepopulated and reset. - - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); - #if !ETH_RELEASE - assert(m_previousBlock.hash() == bi.parentHash); - assert(m_currentBlock.parentHash == bi.parentHash); + assert(m_previousBlock.hash() == _block.info.parentHash); + assert(m_currentBlock.parentHash == _block.info.parentHash); assert(rootHash() == m_previousBlock.stateRoot); #endif @@ -608,32 +605,31 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = bi; - m_currentBlock.verifyInternals(_block); + m_currentBlock = _block.info; m_currentBlock.noteDirty(); // cnote << "playback begins:" << m_state.root(); // cnote << m_state; LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); - RLP rlp(_block); + RLP rlp(_block.block); vector receipts; // All ok with the block generally. Play back the transactions now... unsigned i = 0; - for (auto const& tr: rlp[1]) + for (auto const& tr: _block.transactions) { try { LogOverride o(false); - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + execute(lh, tr); } catch (...) { - badBlock(_block, "Invalid transaction"); + badBlock(_block.block, "Invalid transaction"); cwarn << " Transaction Index:" << i; LogOverride o(true); - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + execute(lh, tr); throw; } @@ -646,7 +642,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement auto receiptsRoot = orderedTrieRoot(receipts); if (receiptsRoot != m_currentBlock.receiptsRoot) { - badBlock(_block, "Bad receipts state root"); + badBlock(_block.block, "Bad receipts state root"); cwarn << " Received: " << toString(m_currentBlock.receiptsRoot); cwarn << " Expected: " << toString(receiptsRoot) << " which is:"; for (unsigned j = 0; j < i; ++j) @@ -657,13 +653,13 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement cwarn << " Hex: " << toHex(b); cwarn << " " << TransactionReceipt(&b); } - cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); + cwarn << " VMTrace:\n" << vmTrace(_block.block, _bc, _ir); BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); } if (m_currentBlock.logBloom != logBloom()) { - badBlock(_block, "Bad log bloom"); + badBlock(_block.block, "Bad log bloom"); cwarn << " Receipt blooms:"; for (unsigned j = 0; j < i; ++j) { @@ -680,7 +676,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) { - badBlock(_block, "Too many uncles"); + badBlock(_block.block, "Too many uncles"); BOOST_THROW_EXCEPTION(TooManyUncles()); } @@ -693,7 +689,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement auto h = sha3(i.data()); if (excluded.count(h)) { - badBlock(_block, "Invalid uncle included"); + badBlock(_block.block, "Invalid uncle included"); BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(excluded)) << errinfo_hash256(sha3(i.data()))); } excluded.insert(h); @@ -702,7 +698,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement BlockInfo uncleParent(_bc.block(uncle.parentHash)); if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) { - badBlock(_block, "Uncle too old"); + badBlock(_block.block, "Uncle too old"); cwarn << " Uncle number: " << uncle.number; cwarn << " Uncle parent number: " << uncleParent.number; cwarn << " Block number: " << m_currentBlock.number; @@ -710,7 +706,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement } else if (uncle.number == m_currentBlock.number) { - badBlock(_block, "Uncle is brother"); + badBlock(_block.block, "Uncle is brother"); cwarn << " Uncle number: " << uncle.number; cwarn << " Uncle parent number: " << uncleParent.number; cwarn << " Block number: " << m_currentBlock.number; @@ -730,12 +726,12 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { - badBlock(_block, "Bad state root"); + badBlock(_block.block, "Bad state root"); cnote << " Given to be:" << m_currentBlock.stateRoot; // TODO: Fix // cnote << SecureTrieDB(&m_db, m_currentBlock.stateRoot); cnote << " Calculated to be:" << rootHash(); - cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); + cwarn << " VMTrace:\n" << vmTrace(_block.block, _bc, _ir); // cnote << m_state; // Rollback the trie. m_db.rollback(); @@ -745,7 +741,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement if (m_currentBlock.gasUsed != gasUsed()) { // Rollback the trie. - badBlock(_block, "Invalid gas used"); + badBlock(_block.block, "Invalid gas used"); m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } @@ -823,7 +819,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(&block.out(), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -1122,6 +1118,8 @@ h256 State::codeHash(Address _contract) const { if (!addressHasCode(_contract)) return EmptySHA3; + if (m_cache[_contract].isFreshCode()) + return sha3(code(_contract)); return m_cache[_contract].codeHash(); } diff --git a/libethereum/State.h b/libethereum/State.h index 55d5cfb4c..c4403b41b 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -48,6 +48,7 @@ namespace eth class BlockChain; class State; +struct VerifiedBlockRef; struct StateChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct StateTrace: public LogChannel { static const char* name(); static const int verbosity = 5; }; @@ -308,7 +309,7 @@ public: /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -349,7 +350,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); diff --git a/libethereum/VerifiedBlock.h b/libethereum/VerifiedBlock.h new file mode 100644 index 000000000..ddd808901 --- /dev/null +++ b/libethereum/VerifiedBlock.h @@ -0,0 +1,53 @@ +/* + 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 VerfiedBlock.h + * @author Gav Wood + * @date 2014 + */ + + +#include +#include + +#pragma once + +namespace dev +{ +namespace eth +{ + +class Transaction; + +/// @brief Verified block info, does not hold block data, but a reference instead +struct VerifiedBlockRef +{ + bytesConstRef block; ///< Block data reference + BlockInfo info; ///< Prepopulated block info + std::vector transactions; ///< Verified list of block transactions +}; + +/// @brief Verified block info, combines block data and verified info/transactions +struct VerifiedBlock +{ + VerifiedBlockRef verified; ///< Verified block structures + bytes blockData; ///< Block data +}; + +using VerifiedBlocks = std::vector; + +} +} diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp index ebef1fdb0..ad419d2a3 100644 --- a/libevm/ExtVMFace.cpp +++ b/libevm/ExtVMFace.cpp @@ -25,7 +25,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): +ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): myAddress(_myAddress), caller(_caller), origin(_origin), @@ -33,6 +33,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 gasPrice(_gasPrice), data(_data), code(_code), + codeHash(_codeHash), lastHashes(_lh), previousBlock(_previousBlock), currentBlock(_currentBlock), diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 6b35094bb..bb102bef3 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -130,7 +130,7 @@ public: ExtVMFace() = default; /// Full constructor. - ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); + ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); virtual ~ExtVMFace() = default; @@ -186,6 +186,7 @@ public: u256 gasPrice; ///< Price of gas (that we already paid). bytesConstRef data; ///< Current input data. bytes code; ///< Current code that is executing. + h256 codeHash; ///< SHA3 hash of the executing code LastHashes lastHashes; ///< Most recent 256 blocks' hashes. BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE BlockInfo currentBlock; ///< The current block's information. diff --git a/libp2p/RLPxFrameIO.h b/libp2p/RLPxFrameIO.h index 0f0504e48..9d4c274be 100644 --- a/libp2p/RLPxFrameIO.h +++ b/libp2p/RLPxFrameIO.h @@ -56,7 +56,7 @@ public: bool isConnected() const { return m_socket.is_open(); } void close() { try { boost::system::error_code ec; m_socket.shutdown(bi::tcp::socket::shutdown_both, ec); if (m_socket.is_open()) m_socket.close(); } catch (...){} } - bi::tcp::endpoint remoteEndpoint() { try { return m_socket.remote_endpoint(); } catch (...){ return bi::tcp::endpoint(); } } + bi::tcp::endpoint remoteEndpoint() { boost::system::error_code ec; return m_socket.remote_endpoint(ec); } bi::tcp::socket& ref() { return m_socket; } protected: @@ -130,4 +130,4 @@ private: }; } -} \ No newline at end of file +} diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index d52c650f9..ec66837e1 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) {