Browse Source

Fast block hash from number.

cl-refactor
Gav Wood 10 years ago
parent
commit
90bb001cf9
  1. 9
      libethcore/Common.cpp
  2. 79
      libethereum/BlockChain.cpp
  3. 52
      libethereum/BlockChain.h
  4. 11
      libethereum/BlockDetails.h
  5. 11
      libethereum/Client.cpp
  6. 1
      libethereum/Client.h
  7. 3
      libethereum/Miner.h

9
libethcore/Common.cpp

@ -33,13 +33,14 @@ namespace eth
{ {
const unsigned c_protocolVersion = 56; const unsigned c_protocolVersion = 56;
const unsigned c_databaseVersion = 6 + const unsigned c_databaseBaseVersion = 7;
#if ETH_FATDB #if ETH_FATDB
1000 const unsigned c_databaseVersionModifier = 1000;
#else #else
0 const unsigned c_databaseVersionModifier = 0;
#endif #endif
;
const unsigned c_databaseVersion = c_databaseBaseVersion + c_databaseVersionModifier;
vector<pair<u256, string>> const& units() vector<pair<u256, string>> const& units()
{ {

79
libethereum/BlockChain.cpp

@ -45,7 +45,7 @@ namespace js = json_spirit;
std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
{ {
string cmp = toBigEndianString(_bc.currentHash()); string cmp = toBigEndianString(_bc.currentHash());
auto it = _bc.m_db->NewIterator(_bc.m_readOptions); auto it = _bc.m_blocksDB->NewIterator(_bc.m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next()) for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().ToString() != "best") if (it->key().ToString() != "best")
{ {
@ -102,9 +102,9 @@ void BlockChain::open(std::string _path, bool _killExisting)
ldb::Options o; ldb::Options o;
o.create_if_missing = true; o.create_if_missing = true;
ldb::DB::Open(o, _path + "/blocks", &m_db); ldb::DB::Open(o, _path + "/blocks", &m_blocksDB);
ldb::DB::Open(o, _path + "/details", &m_extrasDB); ldb::DB::Open(o, _path + "/details", &m_extrasDB);
if (!m_db) if (!m_blocksDB)
BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen()); BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen());
if (!m_extrasDB) if (!m_extrasDB)
BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen()); BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen());
@ -132,10 +132,10 @@ void BlockChain::close()
{ {
cnote << "Closing blockchain DB"; cnote << "Closing blockchain DB";
delete m_extrasDB; delete m_extrasDB;
delete m_db; delete m_blocksDB;
m_lastBlockHash = m_genesisHash; m_lastBlockHash = m_genesisHash;
m_details.clear(); m_details.clear();
m_cache.clear(); m_blocks.clear();
} }
template <class T, class V> template <class T, class V>
@ -294,6 +294,23 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}); m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {});
m_details[bi.parentHash].children.push_back(newHash); m_details[bi.parentHash].children.push_back(newHash);
} }
{
WriteGuard l(x_blockHashes);
m_blockHashes[h256(bi.number)].value = newHash;
}
// Collate transaction hashes and remember who they were.
h256s tas;
{
RLP blockRLP(_block);
TransactionAddress ta;
ta.blockHash = newHash;
WriteGuard l(x_transactionAddresses);
for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index)
{
tas.push_back(sha3(blockRLP[1][ta.index].data()));
m_transactionAddresses[tas.back()] = ta;
}
}
{ {
WriteGuard l(x_logBlooms); WriteGuard l(x_logBlooms);
m_logBlooms[newHash] = blb; m_logBlooms[newHash] = blb;
@ -303,17 +320,14 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
m_receipts[newHash] = br; m_receipts[newHash] = br;
} }
m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)dev::ref(m_details[newHash].rlp())); m_blocksDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block));
m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[newHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, 3), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, 4), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(h256(bi.number), ExtraBlockHash), (ldb::Slice)dev::ref(m_blockHashes[h256(bi.number)].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, 4), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); for (auto const& h: tas)
m_db->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); m_extrasDB->Put(m_writeOptions, toSlice(h, ExtraTransactionAddress), (ldb::Slice)dev::ref(m_transactionAddresses[h].rlp()));
RLP blockRLP(_block); m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp()));
TransactionAddress ta; m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[newHash].rlp()));
ta.blockHash = newHash;
for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index)
m_extrasDB->Put(m_writeOptions, toSlice(sha3(blockRLP[1][ta.index].data()), 5), (ldb::Slice)dev::ref(ta.rlp()));
#if ETH_PARANOIA #if ETH_PARANOIA
checkConsistency(); checkConsistency();
@ -406,7 +420,7 @@ void BlockChain::checkConsistency()
WriteGuard l(x_details); WriteGuard l(x_details);
m_details.clear(); m_details.clear();
} }
ldb::Iterator* it = m_db->NewIterator(m_readOptions); ldb::Iterator* it = m_blocksDB->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next()) for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().size() == 32) if (it->key().size() == 32)
{ {
@ -449,12 +463,12 @@ bool BlockChain::isKnown(h256 _hash) const
if (_hash == m_genesisHash) if (_hash == m_genesisHash)
return true; return true;
{ {
ReadGuard l(x_cache); ReadGuard l(x_blocks);
if (m_cache.count(_hash)) if (m_blocks.count(_hash))
return true; return true;
} }
string d; string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d); m_blocksDB->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
return !!d.size(); return !!d.size();
} }
@ -464,14 +478,14 @@ bytes BlockChain::block(h256 _hash) const
return m_genesisBlock; return m_genesisBlock;
{ {
ReadGuard l(x_cache); ReadGuard l(x_blocks);
auto it = m_cache.find(_hash); auto it = m_blocks.find(_hash);
if (it != m_cache.end()) if (it != m_blocks.end())
return it->second; return it->second;
} }
string d; string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d); m_blocksDB->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
if (!d.size()) if (!d.size())
{ {
@ -479,18 +493,9 @@ bytes BlockChain::block(h256 _hash) const
return bytes(); return bytes();
} }
WriteGuard l(x_cache); WriteGuard l(x_blocks);
m_cache[_hash].resize(d.size()); m_blocks[_hash].resize(d.size());
memcpy(m_cache[_hash].data(), d.data(), d.size()); memcpy(m_blocks[_hash].data(), d.data(), d.size());
return m_cache[_hash];
}
h256 BlockChain::numberHash(unsigned _n) const return m_blocks[_hash];
{
if (!_n)
return genesisHash();
h256 ret = currentHash();
for (; _n < details().number; ++_n, ret = details(ret).parent) {}
return ret;
} }

52
libethereum/BlockChain.h

@ -62,8 +62,17 @@ std::map<Address, Account> const& genesisState();
ldb::Slice toSlice(h256 _h, unsigned _sub = 0); ldb::Slice toSlice(h256 _h, unsigned _sub = 0);
using BlocksHash = std::map<h256, bytes>;
using TransactionHashes = h256s; using TransactionHashes = h256s;
enum {
ExtraDetails = 0,
ExtraBlockHash,
ExtraTransactionAddress,
ExtraLogBlooms,
ExtraReceipts
};
/** /**
* @brief Implements the blockchain database. All data this gives is disk-backed. * @brief Implements the blockchain database. All data this gives is disk-backed.
* @threadsafe * @threadsafe
@ -99,28 +108,31 @@ public:
BlockInfo info(h256 _hash) const { return BlockInfo(block(_hash)); } BlockInfo info(h256 _hash) const { return BlockInfo(block(_hash)); }
BlockInfo info() const { return BlockInfo(block()); } BlockInfo info() const { return BlockInfo(block()); }
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
bytes block(h256 _hash) const;
bytes block() const { return block(currentHash()); }
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); } BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); } BlockDetails details() const { return details(currentHash()); }
/// Get the transactions' log blooms of a block (or the most recent mined if none given). Thread-safe. /// Get the transactions' log blooms of a block (or the most recent mined if none given). Thread-safe.
BlockLogBlooms logBlooms(h256 _hash) const { return queryExtras<BlockLogBlooms, 3>(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); } BlockLogBlooms logBlooms(h256 _hash) const { return queryExtras<BlockLogBlooms, ExtraLogBlooms>(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); }
BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); } BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); }
/// Get the transactions' receipts of a block (or the most recent mined if none given). Thread-safe. /// Get the transactions' receipts of a block (or the most recent mined if none given). Thread-safe.
BlockReceipts receipts(h256 _hash) const { return queryExtras<BlockReceipts, 4>(_hash, m_receipts, x_receipts, NullBlockReceipts); } BlockReceipts receipts(h256 _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts() const { return receipts(currentHash()); } BlockReceipts receipts() const { return receipts(currentHash()); }
/// Get a list of transaction hashes for a given block. Thread-safe. /// Get a list of transaction hashes for a given block. Thread-safe.
TransactionHashes transactionHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; } TransactionHashes transactionHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); } TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); }
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. /// Get a list of transaction hashes for a given block. Thread-safe.
bytes block(h256 _hash) const; h256 numberHash(u256 _index) const { if (!_index) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(_index), m_blockHashes, x_blockHashes, NullBlockHash).value; }
bytes block() const { return block(currentHash()); }
/// Get a transaction from its hash. Thread-safe. /// Get a transaction from its hash. Thread-safe.
bytes transaction(h256 _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, 5>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); } bytes transaction(h256 _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); }
/// Get a block's transaction (RLP format) for the given block hash (or the most recent mined if none given) & index. Thread-safe. /// Get a block's transaction (RLP format) for the given block hash (or the most recent mined if none given) & index. Thread-safe.
bytes transaction(h256 _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); } bytes transaction(h256 _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); }
@ -136,9 +148,6 @@ public:
/// Get the hash of the genesis block. Thread-safe. /// Get the hash of the genesis block. Thread-safe.
h256 genesisHash() const { return m_genesisHash; } h256 genesisHash() const { return m_genesisHash; }
/// Get the hash of a block of a given number. Slow; try not to use it too much.
h256 numberHash(unsigned _n) const;
/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5). /// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5 /// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
/// togther with all their quoted uncles. /// togther with all their quoted uncles.
@ -160,6 +169,21 @@ public:
*/ */
h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const; h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
struct Statistics
{
unsigned memDetails;
unsigned memLogBlooms;
unsigned memReceipts;
unsigned memTransactionAddresses;
unsigned memCache;
};
/// @returns statistics about memory usage.
Statistics usage() const;
/// Deallocate unused data.
void garbageCollect();
private: private:
void open(std::string _path, bool _killExisting = false); void open(std::string _path, bool _killExisting = false);
void close(); void close();
@ -189,6 +213,8 @@ private:
void checkConsistency(); void checkConsistency();
/// The caches of the disk DB and their locks. /// The caches of the disk DB and their locks.
mutable boost::shared_mutex x_blocks;
mutable BlocksHash m_blocks;
mutable boost::shared_mutex x_details; mutable boost::shared_mutex x_details;
mutable BlockDetailsHash m_details; mutable BlockDetailsHash m_details;
mutable boost::shared_mutex x_logBlooms; mutable boost::shared_mutex x_logBlooms;
@ -197,11 +223,11 @@ private:
mutable BlockReceiptsHash m_receipts; mutable BlockReceiptsHash m_receipts;
mutable boost::shared_mutex x_transactionAddresses; mutable boost::shared_mutex x_transactionAddresses;
mutable TransactionAddressHash m_transactionAddresses; mutable TransactionAddressHash m_transactionAddresses;
mutable boost::shared_mutex x_cache; mutable boost::shared_mutex x_blockHashes;
mutable std::map<h256, bytes> m_cache; mutable BlockHashHash m_blockHashes;
/// The disk DBs. Thread-safe, so no need for locks. /// The disk DBs. Thread-safe, so no need for locks.
ldb::DB* m_db; ldb::DB* m_blocksDB;
ldb::DB* m_extrasDB; ldb::DB* m_extrasDB;
/// Hash of the last (valid) block on the longest chain. /// Hash of the last (valid) block on the longest chain.

11
libethereum/BlockDetails.h

@ -70,6 +70,15 @@ struct BlockReceipts
TransactionReceipts receipts; TransactionReceipts receipts;
}; };
struct BlockHash
{
BlockHash() {}
BlockHash(RLP const& _r) { value = _r.toHash<h256>(); }
bytes rlp() const { return dev::rlp(value); }
h256 value;
};
struct TransactionAddress struct TransactionAddress
{ {
TransactionAddress() {} TransactionAddress() {}
@ -86,11 +95,13 @@ using BlockDetailsHash = std::map<h256, BlockDetails>;
using BlockLogBloomsHash = std::map<h256, BlockLogBlooms>; using BlockLogBloomsHash = std::map<h256, BlockLogBlooms>;
using BlockReceiptsHash = std::map<h256, BlockReceipts>; using BlockReceiptsHash = std::map<h256, BlockReceipts>;
using TransactionAddressHash = std::map<h256, TransactionAddress>; using TransactionAddressHash = std::map<h256, TransactionAddress>;
using BlockHashHash = std::map<h256, BlockHash>;
static const BlockDetails NullBlockDetails; static const BlockDetails NullBlockDetails;
static const BlockLogBlooms NullBlockLogBlooms; static const BlockLogBlooms NullBlockLogBlooms;
static const BlockReceipts NullBlockReceipts; static const BlockReceipts NullBlockReceipts;
static const TransactionAddress NullTransactionAddress; static const TransactionAddress NullTransactionAddress;
static const BlockHash NullBlockHash;
} }
} }

11
libethereum/Client.cpp

@ -516,9 +516,18 @@ void Client::doWork()
{ {
if (m.isComplete()) if (m.isComplete())
{ {
cwork << "CHAIN <== postSTATE"; // TODO: enable a short-circuit option since we mined it. will need to get the end state from the miner.
auto lm = dynamic_cast<LocalMiner*>(&m);
h256s hs; h256s hs;
if (false && lm && !m_verifyOwnBlocks)
{ {
// TODO: implement
//m_bc.attemptImport(m_blockData(), m_stateDB, lm->state());
// TODO: derive hs from lm->state()
}
else
{
cwork << "CHAIN <== postSTATE";
WriteGuard l(x_stateDB); WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB); hs = m_bc.attemptImport(m.blockData(), m_stateDB);
} }

1
libethereum/Client.h

@ -359,6 +359,7 @@ private:
bool m_paranoia = false; ///< Should we be paranoid about our state? bool m_paranoia = false; ///< Should we be paranoid about our state?
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending? bool m_forceMining = false; ///< Mine even when there are no transactions pending?
bool m_verifyOwnBlocks = true; ///< Shoudl be verify blocks that we mined?
mutable Mutex m_filterLock; mutable Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters; std::map<h256, InstalledFilter> m_filters;

3
libethereum/Miner.h

@ -130,6 +130,9 @@ public:
/// Get and clear the mining history. /// Get and clear the mining history.
std::list<MineInfo> miningHistory() { Guard l(x_mineInfo); auto ret = m_mineHistory; m_mineHistory.clear(); return ret; } std::list<MineInfo> miningHistory() { Guard l(x_mineInfo); auto ret = m_mineHistory; m_mineHistory.clear(); return ret; }
/// @returns the state on which we mined.
State const& state() const { return m_mineState; }
private: private:
/// Do some work on the mining. /// Do some work on the mining.
virtual void doWork(); virtual void doWork();

Loading…
Cancel
Save