diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 810fea580..918a28916 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -883,6 +883,7 @@ void Main::on_blocks_currentItemChanged() s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress; s << "
Nonce: " << info.nonce << ""; s << "
Parent: " << info.parentHash << ""; + s << "
Bloom: " << details.bloom << ""; s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << ""; s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << ""; s << "
Pre: " << BlockInfo(m_client->blockChain().block(info.parentHash)).stateRoot << ""; diff --git a/libethential/FixedHash.h b/libethential/FixedHash.h index 55d8a5cc8..f792e378d 100644 --- a/libethential/FixedHash.h +++ b/libethential/FixedHash.h @@ -50,9 +50,15 @@ public: /// Method to convert from a string. enum ConstructFromStringType { FromHex, FromBinary }; + /// Method to convert from a string. + enum ConstructFromHashType { AlignLeft, AlignRight }; + /// Construct an empty hash. FixedHash() { m_data.fill(0); } + /// Construct from another hash, filling with zeroes or cropping as necessary. + template FixedHash(FixedHash const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; } + /// Convert from the corresponding arithmetic type. FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } @@ -85,6 +91,9 @@ public: FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; } FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; } + /// @returns true if all bytes in @a _c are set in this object. + bool contains(FixedHash const& _c) const { return (*this & _c) == _c; } + /// @returns a particular byte from the hash. byte& operator[](unsigned _i) { return m_data[_i]; } /// @returns a particular byte from the hash. diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 8b09f5fae..004b28454 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -59,11 +59,12 @@ BlockDetails::BlockDetails(RLP const& _r) totalDifficulty = _r[1].toInt(); parent = _r[2].toHash(); children = _r[3].toVector(); + bloom = _r[4].isNull() ? ~h256() : _r[4].toHash(); } bytes BlockDetails::rlp() const { - return rlpList(number, totalDifficulty, parent, children); + return rlpList(number, totalDifficulty, parent, children, bloom); } std::map const& eth::genesisState() @@ -133,7 +134,7 @@ BlockChain::BlockChain(std::string _path, bool _killExisting) if (!details(m_genesisHash)) { // Insert details of genesis block. - m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {}); + m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {}, h256()); auto r = m_details[m_genesisHash].rlp(); m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&m_genesisHash, 32), (ldb::Slice)eth::ref(r)); } @@ -238,6 +239,7 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db) // Get total difficulty increase and update state, checking it. State s(bi.coinbaseAddress, _db); auto tdIncrease = s.enactOn(&_block, bi, *this); + auto b = s.bloom(); s.cleanup(true); td = pd.totalDifficulty + tdIncrease; @@ -247,7 +249,7 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db) // All ok - insert into DB { lock_guard l(m_lock); - m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {}); + m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {}, b); m_details[bi.parentHash].children.push_back(newHash); } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index ffab54ddd..025181396 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,7 +37,7 @@ class RLPStream; struct BlockDetails { BlockDetails(): number(0), totalDifficulty(0) {} - BlockDetails(uint _n, u256 _tD, h256 _p, h256s _c): number(_n), totalDifficulty(_tD), parent(_p), children(_c) {} + BlockDetails(uint _n, u256 _tD, h256 _p, h256s _c, h256 _bloom): number(_n), totalDifficulty(_tD), parent(_p), children(_c), bloom(_bloom) {} BlockDetails(RLP const& _r); bytes rlp() const; @@ -48,7 +48,7 @@ struct BlockDetails u256 totalDifficulty; h256 parent; h256s children; - // TODO: add trace bloom + h256 bloom; }; // TODO: DB for full traces. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 2faa4d425..f4f59530e 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -335,8 +335,45 @@ bytes Client::codeAt(Address _a, int _block) const return asOf(_block).code(_a); } +bool TransactionFilter::matches(h256 _bloom) const +{ + auto have = [=](Address const& a) { return _bloom.contains(a.bloom()); }; + if (m_from.size()) + { + for (auto i: m_from) + if (have(i)) + goto OK1; + return false; + } + OK1: + if (m_to.size()) + { + for (auto i: m_to) + if (have(i)) + goto OK2; + return false; + } + OK2: + if (m_stateAltered.size() || m_altered.size()) + { + for (auto i: m_altered) + if (have(i)) + goto OK3; + for (auto i: m_stateAltered) + if (have(i.first) && _bloom.contains(h256(i.second).bloom())) + goto OK3; + return false; + } + OK3: + return true; +} + bool TransactionFilter::matches(State const& _s, unsigned _i) const { + h256 b = _s.changesFromPending(_i).bloom(); + if (!matches(b)) + return false; + Transaction t = _s.pending()[_i]; if (!m_to.empty() && !m_to.count(t.receiveAddress)) return false; @@ -388,29 +425,42 @@ PastTransactions Client::transactions(TransactionFilter const& _f) const return ret; } + unsigned skipped = 0; + unsigned falsePos = 0; auto cn = m_bc.number(); auto h = m_bc.numberHash(begin); - for (unsigned n = begin; ret.size() != m && n != end; n--, h = m_bc.details(h).parent) + unsigned n = begin; + for (; ret.size() != m && n != end; n--, h = m_bc.details(h).parent) { - try - { - State st(m_stateDB, m_bc, h); - for (unsigned i = st.pending().size(); i-- && ret.size() != m;) - if (_f.matches(st, i)) - { - if (s) - s--; - else - ret.insert(ret.begin(), PastTransaction(st.pending()[i], h, i, BlockInfo(m_bc.block(h)).timestamp, cn - n + 2)); - } - } - catch (...) + auto d = m_bc.details(h); + if (_f.matches(d.bloom)) { - // Gaa. bad state. not good at all. bury head in sand for now. + try + { + State st(m_stateDB, m_bc, h); + unsigned os = s; + for (unsigned i = st.pending().size(); i-- && ret.size() != m;) + if (_f.matches(st, i)) + { + if (s) + s--; + else + ret.insert(ret.begin(), PastTransaction(st.pending()[i], h, i, BlockInfo(m_bc.block(h)).timestamp, cn - n + 2)); + } + if (os - s == st.pending().size()) + falsePos++; + } + catch (...) + { + // Gaa. bad state. not good at all. bury head in sand for now. + } } + else + skipped++; if (n == end) break; } + cdebug << (begin - n) << "searched; " << skipped << "skipped; " << falsePos << "false +ves"; return ret; } diff --git a/libethereum/Client.h b/libethereum/Client.h index cbfdcd6e5..6908de228 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -88,6 +88,7 @@ public: int latest() const { return m_latest; } unsigned max() const { return m_max; } unsigned skip() const { return m_skip; } + bool matches(h256 _bloom) const; bool matches(State const& _s, unsigned _i) const; TransactionFilter from(Address _a) { m_from.insert(_a); return *this; } diff --git a/libethereum/PeerServer.cpp b/libethereum/PeerServer.cpp index 49d897bb4..275d9ace7 100644 --- a/libethereum/PeerServer.cpp +++ b/libethereum/PeerServer.cpp @@ -339,6 +339,17 @@ bool PeerServer::ensureInitialised(BlockChain& _bc, TransactionQueue& _tq) return false; } +bool PeerServer::noteBlock(h256 _hash, bytesConstRef _data) +{ + if (!m_chain->details(_hash)) + { + lock_guard l(m_incomingLock); + m_incomingBlocks.push_back(_data.toBytes()); + return true; + } + return false; +} + bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, OverlayDB& _o) { bool ret = ensureInitialised(_bc, _tq); @@ -404,7 +415,7 @@ bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, OverlayDB& _o) for (int accepted = 1, n = 0; accepted; ++n) { accepted = 0; - + lock_guard l(m_incomingLock); if (m_incomingBlocks.size()) for (auto it = prev(m_incomingBlocks.end());; --it) { diff --git a/libethereum/PeerServer.h b/libethereum/PeerServer.h index ec67b8469..6e44d2ea4 100644 --- a/libethereum/PeerServer.h +++ b/libethereum/PeerServer.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -85,6 +86,10 @@ public: void restorePeers(bytesConstRef _b); private: + /// Session wants to pass us a block that we might not have. + /// @returns true if we didn't have it. + bool noteBlock(h256 _hash, bytesConstRef _data); + void seal(bytes& _b); void populateAddresses(); void determinePublic(std::string const& _publicAddress, bool _upnp); @@ -116,6 +121,7 @@ private: std::vector m_incomingTransactions; std::vector m_incomingBlocks; + mutable std::recursive_mutex m_incomingLock; std::vector m_unknownParentBlocks; std::vector m_freePeers; std::map> m_incomingPeers; diff --git a/libethereum/PeerSession.cpp b/libethereum/PeerSession.cpp index 5f16884d6..957252e4a 100644 --- a/libethereum/PeerSession.cpp +++ b/libethereum/PeerSession.cpp @@ -235,9 +235,8 @@ bool PeerSession::interpret(RLP const& _r) for (unsigned i = 1; i < _r.itemCount(); ++i) { auto h = sha3(_r[i].data()); - if (!m_server->m_chain->details(h)) + if (!m_server->noteBlock(h, _r[i].data())) { - m_server->m_incomingBlocks.push_back(_r[i].data().toBytes()); m_knownBlocks.insert(h); used++; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 56fe2c6e2..ab184b2ce 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -672,6 +672,14 @@ bool State::amIJustParanoid(BlockChain const& _bc) return false; } +h256 State::bloom() const +{ + h256 ret; + for (auto const& i: m_transactions) + ret |= i.changes.bloom(); + return ret; +} + // @returns the block that represents the difference between m_previousBlock and m_currentBlock. // (i.e. all the transactions we executed). void State::commitToMine(BlockChain const& _bc) @@ -713,11 +721,9 @@ void State::commitToMine(BlockChain const& _bc) RLPStream txs; txs.appendList(m_transactions.size()); - m_bloom = h256(); for (unsigned i = 0; i < m_transactions.size(); ++i) { - m_bloom |= m_transactions[i].changes.bloom(); RLPStream k; k << i; RLPStream v; diff --git a/libethereum/State.h b/libethereum/State.h index 1ce887110..1df4b6cc9 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -245,8 +245,8 @@ public: /// Get the list of pending transactions. Manifest changesFromPending(unsigned _i) const { return m_transactions[_i].changes; } - /// Get the bloom filter of all changes happened in the block. Only good once commitToMine() is called. - u256 bloom() const { return m_bloom; } + /// Get the bloom filter of all changes happened in the block. + h256 bloom() const; /// Get the State immediately after the given number of pending transactions have been applied. /// If (_i == 0) returns the initial state of the block. @@ -276,12 +276,7 @@ public: bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. - /// @warning We must already have been sync()ed with said block. /// @returns the additional total difficulty. - /// If the @a _grandParent is passed, it will check the validity of each of the uncles. - /// @throws if there are any validation errors. - u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent = BlockInfo()); - u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. @@ -340,7 +335,6 @@ private: std::set m_transactionSet; ///< The set of transaction hashes that we've included in the state. // GenericTrieDB m_transactionManifest; ///< The transactions trie; saved from the last commitToMine, or invalid/empty if commitToMine was never called. OverlayDB m_lastTx; - h256 m_bloom; ///< Bloom filter of changed addresses/locations in the block. mutable std::map m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 981c8aa20..0e1767625 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -241,7 +241,7 @@ QEthereum::~QEthereum() { } -void QEthereum::setup(QWebFrame* _e) +void QEthereum::setup(QWebFrame*) { // Alex: JS codes moved to mainwin until qtwebkit bugs are resolved (#245) }