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/>Nonce: <b>" << info.nonce << "</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/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</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.
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 <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.
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.

8
libethereum/BlockChain.cpp

@ -59,11 +59,12 @@ BlockDetails::BlockDetails(RLP const& _r)
totalDifficulty = _r[1].toInt<u256>();
parent = _r[2].toHash<h256>();
children = _r[3].toVector<h256>();
bloom = _r[4].isNull() ? ~h256() : _r[4].toHash<h256>();
}
bytes BlockDetails::rlp() const
{
return rlpList(number, totalDifficulty, parent, children);
return rlpList(number, totalDifficulty, parent, children, bloom);
}
std::map<Address, AddressState> 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<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);
}

4
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.

80
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;
}

1
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; }

13
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<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 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<recursive_mutex> l(m_incomingLock);
if (m_incomingBlocks.size())
for (auto it = prev(m_incomingBlocks.end());; --it)
{

6
libethereum/PeerServer.h

@ -21,6 +21,7 @@
#pragma once
#include <mutex>
#include <map>
#include <vector>
#include <set>
@ -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<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
mutable std::recursive_mutex m_incomingLock;
std::vector<bytes> m_unknownParentBlocks;
std::vector<Public> m_freePeers;
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)
{
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++;
}

10
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;

10
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<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.
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.

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)
}

Loading…
Cancel
Save