Browse Source

Bloom filters for blocks.

cl-refactor
Gav Wood 11 years ago
parent
commit
0c5dbd7def
  1. 1
      alethzero/MainWin.cpp
  2. 9
      libethential/FixedHash.h
  3. 8
      libethereum/BlockChain.cpp
  4. 4
      libethereum/BlockChain.h
  5. 80
      libethereum/Client.cpp
  6. 1
      libethereum/Client.h
  7. 13
      libethereum/PeerServer.cpp
  8. 6
      libethereum/PeerServer.h
  9. 3
      libethereum/PeerSession.cpp
  10. 10
      libethereum/State.cpp
  11. 10
      libethereum/State.h
  12. 2
      libqethereum/QEthereum.cpp

1
alethzero/MainWin.cpp

@ -883,6 +883,7 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress; s << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress;
s << "<br/>Nonce: <b>" << info.nonce << "</b>"; s << "<br/>Nonce: <b>" << info.nonce << "</b>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>"; s << "<br/>Parent: <b>" << info.parentHash << "</b>";
s << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>"; s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>"; s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
s << "<br/>Pre: <b>" << BlockInfo(m_client->blockChain().block(info.parentHash)).stateRoot << "</b>"; s << "<br/>Pre: <b>" << BlockInfo(m_client->blockChain().block(info.parentHash)).stateRoot << "</b>";

9
libethential/FixedHash.h

@ -50,9 +50,15 @@ public:
/// Method to convert from a string. /// Method to convert from a string.
enum ConstructFromStringType { FromHex, FromBinary }; enum ConstructFromStringType { FromHex, FromBinary };
/// Method to convert from a string.
enum ConstructFromHashType { AlignLeft, AlignRight };
/// Construct an empty hash. /// Construct an empty hash.
FixedHash() { m_data.fill(0); } FixedHash() { m_data.fill(0); }
/// Construct from another hash, filling with zeroes or cropping as necessary.
template <unsigned M> FixedHash(FixedHash<M> 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. /// Convert from the corresponding arithmetic type.
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } 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&(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; } 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. /// @returns a particular byte from the hash.
byte& operator[](unsigned _i) { return m_data[_i]; } byte& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash. /// @returns a particular byte from the hash.

8
libethereum/BlockChain.cpp

@ -59,11 +59,12 @@ BlockDetails::BlockDetails(RLP const& _r)
totalDifficulty = _r[1].toInt<u256>(); totalDifficulty = _r[1].toInt<u256>();
parent = _r[2].toHash<h256>(); parent = _r[2].toHash<h256>();
children = _r[3].toVector<h256>(); children = _r[3].toVector<h256>();
bloom = _r[4].isNull() ? ~h256() : _r[4].toHash<h256>();
} }
bytes BlockDetails::rlp() const bytes BlockDetails::rlp() const
{ {
return rlpList(number, totalDifficulty, parent, children); return rlpList(number, totalDifficulty, parent, children, bloom);
} }
std::map<Address, AddressState> const& eth::genesisState() std::map<Address, AddressState> const& eth::genesisState()
@ -133,7 +134,7 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
if (!details(m_genesisHash)) if (!details(m_genesisHash))
{ {
// Insert details of genesis block. // 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(); auto r = m_details[m_genesisHash].rlp();
m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&m_genesisHash, 32), (ldb::Slice)eth::ref(r)); 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. // Get total difficulty increase and update state, checking it.
State s(bi.coinbaseAddress, _db); State s(bi.coinbaseAddress, _db);
auto tdIncrease = s.enactOn(&_block, bi, *this); auto tdIncrease = s.enactOn(&_block, bi, *this);
auto b = s.bloom();
s.cleanup(true); s.cleanup(true);
td = pd.totalDifficulty + tdIncrease; td = pd.totalDifficulty + tdIncrease;
@ -247,7 +249,7 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db)
// All ok - insert into DB // All ok - insert into DB
{ {
lock_guard<recursive_mutex> l(m_lock); lock_guard<recursive_mutex> 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); m_details[bi.parentHash].children.push_back(newHash);
} }

4
libethereum/BlockChain.h

@ -37,7 +37,7 @@ class RLPStream;
struct BlockDetails struct BlockDetails
{ {
BlockDetails(): number(0), totalDifficulty(0) {} 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); BlockDetails(RLP const& _r);
bytes rlp() const; bytes rlp() const;
@ -48,7 +48,7 @@ struct BlockDetails
u256 totalDifficulty; u256 totalDifficulty;
h256 parent; h256 parent;
h256s children; h256s children;
// TODO: add trace bloom h256 bloom;
}; };
// TODO: DB for full traces. // TODO: DB for full traces.

80
libethereum/Client.cpp

@ -335,8 +335,45 @@ bytes Client::codeAt(Address _a, int _block) const
return asOf(_block).code(_a); 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 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]; Transaction t = _s.pending()[_i];
if (!m_to.empty() && !m_to.count(t.receiveAddress)) if (!m_to.empty() && !m_to.count(t.receiveAddress))
return false; return false;
@ -388,29 +425,42 @@ PastTransactions Client::transactions(TransactionFilter const& _f) const
return ret; return ret;
} }
unsigned skipped = 0;
unsigned falsePos = 0;
auto cn = m_bc.number(); auto cn = m_bc.number();
auto h = m_bc.numberHash(begin); 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 auto d = m_bc.details(h);
{ if (_f.matches(d.bloom))
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 (...)
{ {
// 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) if (n == end)
break; break;
} }
cdebug << (begin - n) << "searched; " << skipped << "skipped; " << falsePos << "false +ves";
return ret; return ret;
} }

1
libethereum/Client.h

@ -88,6 +88,7 @@ public:
int latest() const { return m_latest; } int latest() const { return m_latest; }
unsigned max() const { return m_max; } unsigned max() const { return m_max; }
unsigned skip() const { return m_skip; } unsigned skip() const { return m_skip; }
bool matches(h256 _bloom) const;
bool matches(State const& _s, unsigned _i) const; bool matches(State const& _s, unsigned _i) const;
TransactionFilter from(Address _a) { m_from.insert(_a); return *this; } TransactionFilter from(Address _a) { m_from.insert(_a); return *this; }

13
libethereum/PeerServer.cpp

@ -339,6 +339,17 @@ bool PeerServer::ensureInitialised(BlockChain& _bc, TransactionQueue& _tq)
return false; return false;
} }
bool PeerServer::noteBlock(h256 _hash, bytesConstRef _data)
{
if (!m_chain->details(_hash))
{
lock_guard<recursive_mutex> l(m_incomingLock);
m_incomingBlocks.push_back(_data.toBytes());
return true;
}
return false;
}
bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, OverlayDB& _o) bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, OverlayDB& _o)
{ {
bool ret = ensureInitialised(_bc, _tq); 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) for (int accepted = 1, n = 0; accepted; ++n)
{ {
accepted = 0; accepted = 0;
lock_guard<recursive_mutex> l(m_incomingLock);
if (m_incomingBlocks.size()) if (m_incomingBlocks.size())
for (auto it = prev(m_incomingBlocks.end());; --it) for (auto it = prev(m_incomingBlocks.end());; --it)
{ {

6
libethereum/PeerServer.h

@ -21,6 +21,7 @@
#pragma once #pragma once
#include <mutex>
#include <map> #include <map>
#include <vector> #include <vector>
#include <set> #include <set>
@ -85,6 +86,10 @@ public:
void restorePeers(bytesConstRef _b); void restorePeers(bytesConstRef _b);
private: 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 seal(bytes& _b);
void populateAddresses(); void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp); void determinePublic(std::string const& _publicAddress, bool _upnp);
@ -116,6 +121,7 @@ private:
std::vector<bytes> m_incomingTransactions; std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks; std::vector<bytes> m_incomingBlocks;
mutable std::recursive_mutex m_incomingLock;
std::vector<bytes> m_unknownParentBlocks; std::vector<bytes> m_unknownParentBlocks;
std::vector<Public> m_freePeers; std::vector<Public> m_freePeers;
std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers; std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers;

3
libethereum/PeerSession.cpp

@ -235,9 +235,8 @@ bool PeerSession::interpret(RLP const& _r)
for (unsigned i = 1; i < _r.itemCount(); ++i) for (unsigned i = 1; i < _r.itemCount(); ++i)
{ {
auto h = sha3(_r[i].data()); 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); m_knownBlocks.insert(h);
used++; used++;
} }

10
libethereum/State.cpp

@ -672,6 +672,14 @@ bool State::amIJustParanoid(BlockChain const& _bc)
return false; 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. // @returns the block that represents the difference between m_previousBlock and m_currentBlock.
// (i.e. all the transactions we executed). // (i.e. all the transactions we executed).
void State::commitToMine(BlockChain const& _bc) void State::commitToMine(BlockChain const& _bc)
@ -713,11 +721,9 @@ void State::commitToMine(BlockChain const& _bc)
RLPStream txs; RLPStream txs;
txs.appendList(m_transactions.size()); txs.appendList(m_transactions.size());
m_bloom = h256();
for (unsigned i = 0; i < m_transactions.size(); ++i) for (unsigned i = 0; i < m_transactions.size(); ++i)
{ {
m_bloom |= m_transactions[i].changes.bloom();
RLPStream k; RLPStream k;
k << i; k << i;
RLPStream v; RLPStream v;

10
libethereum/State.h

@ -245,8 +245,8 @@ public:
/// Get the list of pending transactions. /// Get the list of pending transactions.
Manifest changesFromPending(unsigned _i) const { return m_transactions[_i].changes; } 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. /// Get the bloom filter of all changes happened in the block.
u256 bloom() const { return m_bloom; } h256 bloom() const;
/// Get the State immediately after the given number of pending transactions have been applied. /// Get the State immediately after the given number of pending transactions have been applied.
/// If (_i == 0) returns the initial state of the block. /// 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()); bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo());
/// Execute all transactions within a given block. /// Execute all transactions within a given block.
/// @warning We must already have been sync()ed with said block.
/// @returns the additional total difficulty. /// @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); u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc);
/// Returns back to a pristine state after having done a playback. /// Returns back to a pristine state after having done a playback.
@ -340,7 +335,6 @@ private:
std::set<h256> m_transactionSet; ///< The set of transaction hashes that we've included in the state. std::set<h256> m_transactionSet; ///< The set of transaction hashes that we've included in the state.
// GenericTrieDB<OverlayDB> m_transactionManifest; ///< The transactions trie; saved from the last commitToMine, or invalid/empty if commitToMine was never called. // GenericTrieDB<OverlayDB> m_transactionManifest; ///< The transactions trie; saved from the last commitToMine, or invalid/empty if commitToMine was never called.
OverlayDB m_lastTx; OverlayDB m_lastTx;
h256 m_bloom; ///< Bloom filter of changed addresses/locations in the block.
mutable std::map<Address, AddressState> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. mutable std::map<Address, AddressState> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.

2
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) // Alex: JS codes moved to mainwin until qtwebkit bugs are resolved (#245)
} }

Loading…
Cancel
Save