Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Return size of block (in bytes) from web3.eth.getBlock RPC function #5829

Merged
merged 9 commits into from
Dec 4, 2019
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- Fixed: [#5826](https://github.com/ethereum/aleth/pull/5826) Fix blocking bug in database rebuild functionality - users can now rebuild their databases via Aleth's '-R' switch.
- Fixed: [#5827](https://github.com/ethereum/aleth/pull/5827) Detect database upgrades and automatically rebuild the database when they occur.
- Fixed: [#5852](https://github.com/ethereum/aleth/pull/5852) Output correct original opcodes instead of synthetic `PUSHC`/`JUMPC`/`JUMPCI` in VM trace.
- Fixed: [#5829](https://github.com/ethereum/aleth/pull/5829) web3.eth.getBlock now returns block size in bytes. This requires a (automatic) database rebuild which can take a while depending on how many blocks are in the local chain.

## [1.7.2] - 2019-11-22

Expand Down
4 changes: 2 additions & 2 deletions libethcore/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ namespace eth

const unsigned c_protocolVersion = 63;
#if ETH_FATDB
const unsigned c_databaseMinorVersion = 3;
const unsigned c_databaseMinorVersion = 4;
const unsigned c_databaseBaseVersion = 9;
const unsigned c_databaseVersionModifier = 1;
#else
const unsigned c_databaseMinorVersion = 2;
const unsigned c_databaseMinorVersion = 3;
const unsigned c_databaseBaseVersion = 9;
const unsigned c_databaseVersionModifier = 0;
#endif
Expand Down
2 changes: 2 additions & 0 deletions libethcore/Exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ DEV_SIMPLE_EXCEPTION(UnknownError);
DEV_SIMPLE_EXCEPTION(InvalidDatabaseKind);
DEV_SIMPLE_EXCEPTION(DatabaseAlreadyOpen);
DEV_SIMPLE_EXCEPTION(DatabaseCorruption);
DEV_SIMPLE_EXCEPTION(DatabaseExists);
DEV_SIMPLE_EXCEPTION(DatabaseRebuildFailed);

DEV_SIMPLE_EXCEPTION(DAGCreationFailure);
DEV_SIMPLE_EXCEPTION(DAGComputeFailure);
Expand Down
9 changes: 5 additions & 4 deletions libethereum/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,8 @@ u256 Block::enact(VerifiedBlockRef const& _block, BlockChain const& _bc)
// cB.p^6 -----------/ 6
// cB.p^7 -------------/
// cB.p^8
auto expectedUncleParent = _bc.details(m_currentBlock.parentHash()).parent;
for (unsigned i = 1; i < depth; expectedUncleParent = _bc.details(expectedUncleParent).parent, ++i) {}
auto expectedUncleParent = _bc.details(m_currentBlock.parentHash()).parentHash;
for (unsigned i = 1; i < depth; expectedUncleParent = _bc.details(expectedUncleParent).parentHash, ++i) {}
if (expectedUncleParent != uncleParent.hash())
{
UncleParentNotInChain ex;
Expand Down Expand Up @@ -720,9 +720,10 @@ void Block::commitToSeal(BlockChain const& _bc, bytes const& _extraData)
<< ", parent = " << m_previousBlock.parentHash();
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6);
auto p = m_previousBlock.parentHash();
for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent)
for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2;
++gen, p = _bc.details(p).parentHash)
{
auto us = _bc.details(p).children;
auto us = _bc.details(p).childHashes;
assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent!
for (auto const& u: us)
if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about.
Expand Down
199 changes: 118 additions & 81 deletions libethereum/BlockChain.cpp

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions libethereum/BlockChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@
#include "BlockDetails.h"
#include "BlockQueue.h"
#include "ChainParams.h"
#include "DatabasePaths.h"
#include "LastBlockHashesFace.h"
#include "State.h"
#include "Transaction.h"
#include "VerifiedBlock.h"
#include <libdevcore/db.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/Log.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcore/db.h>
#include <libethcore/BlockHeader.h>
#include <libethcore/Common.h>
#include <libethcore/SealEngine.h>
#include <boost/filesystem/path.hpp>
#include <chrono>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <boost/filesystem/path.hpp>

namespace std
{
Expand Down Expand Up @@ -232,7 +233,8 @@ class BlockChain

/// Run through database and verify all blocks by reevaluating.
/// Will call _progress with the progress in this operation first param done, second total.
void rebuild(boost::filesystem::path const& _path, ProgressCallback const& _progress = std::function<void(unsigned, unsigned)>());
void rebuild(boost::filesystem::path const& _path,
ProgressCallback const& _progress = std::function<void(unsigned, unsigned)>());

/// Alter the head of the chain to some prior block along it.
void rewind(unsigned _newHead);
Expand Down Expand Up @@ -407,11 +409,11 @@ class BlockChain
mutable bytes m_genesisHeaderBytes; // mutable because they're effectively memos.
mutable h256 m_genesisHash; // mutable because they're effectively memos.

std::unique_ptr<DatabasePaths> m_dbPaths; // Paths for various databases (e.g. blocks, extras)

std::function<void(Exception&)> m_onBad; ///< Called if we have a block that doesn't verify.
std::function<void(BlockHeader const&)> m_onBlockImport; ///< Called if we have imported a new block into the db

boost::filesystem::path m_dbPath;

mutable Logger m_logger{createLogger(VerbosityDebug, "chain")};
mutable Logger m_loggerDetail{createLogger(VerbosityTrace, "chain")};
mutable Logger m_loggerWarn{createLogger(VerbosityWarning, "chain")};
Expand Down
18 changes: 10 additions & 8 deletions libethereum/BlockDetails.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@ using namespace dev::eth;

BlockDetails::BlockDetails(RLP const& _r)
{
number = _r[0].toInt<unsigned>();
totalDifficulty = _r[1].toInt<u256>();
parent = _r[2].toHash<h256>();
children = _r[3].toVector<h256>();
size = _r.size();
number = _r[0].toInt<unsigned>();
totalDifficulty = _r[1].toInt<u256>();
parentHash = _r[2].toHash<h256>();
childHashes = _r[3].toVector<h256>();
size = _r.size();
blockSizeBytes = _r[4].toInt<size_t>();
}

bytes BlockDetails::rlp() const
{
auto ret = rlpList(number, totalDifficulty, parent, children);
size = ret.size();
return ret;
auto const detailsRlp =
rlpList(number, totalDifficulty, parentHash, childHashes, blockSizeBytes);
size = detailsRlp.size();
return detailsRlp;
}
102 changes: 57 additions & 45 deletions libethereum/BlockDetails.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,82 +17,94 @@ namespace eth

// TODO: OPTIMISE: constructors take bytes, RLP used only in necessary classes.

static const unsigned c_bloomIndexSize = 16;
static const unsigned c_bloomIndexLevels = 2;
constexpr unsigned c_bloomIndexSize = 16;
constexpr unsigned c_bloomIndexLevels = 2;

static const unsigned c_invalidNumber = (unsigned)-1;
constexpr unsigned c_invalidNumber = (unsigned)-1;

struct BlockDetails
{
BlockDetails(): number(c_invalidNumber), totalDifficulty(Invalid256) {}
BlockDetails(unsigned _n, u256 _tD, h256 _p, h256s _c): number(_n), totalDifficulty(_tD), parent(_p), children(_c) {}
BlockDetails(RLP const& _r);
bytes rlp() const;

bool isNull() const { return number == c_invalidNumber; }
explicit operator bool() const { return !isNull(); }

unsigned number = c_invalidNumber;
u256 totalDifficulty = Invalid256;
h256 parent;
h256s children;

mutable unsigned size;
BlockDetails(): number(c_invalidNumber), totalDifficulty(Invalid256) {}
BlockDetails(unsigned _number, u256 const& _totalDifficulty, h256 const& _parentHash, h256s const& _childHashes,
size_t _blockSizeBytes)
: number{_number},
totalDifficulty{_totalDifficulty},
parentHash{_parentHash},
childHashes{_childHashes},
blockSizeBytes{_blockSizeBytes}
{}
BlockDetails(RLP const& _r);
bytes rlp() const;

bool isNull() const { return number == c_invalidNumber; }
explicit operator bool() const { return !isNull(); }

unsigned number = c_invalidNumber;
u256 totalDifficulty = Invalid256;
h256 parentHash;
h256s childHashes;

// Size of the BlockDetails RLP (in bytes). Used for computing blockchain memory usage
// statistics. Field name must be 'size' as BlockChain::getHashSize depends on this
mutable unsigned size;
gumb0 marked this conversation as resolved.
Show resolved Hide resolved

// Size of the block RLP data in bytes
size_t blockSizeBytes;
};

struct BlockLogBlooms
{
BlockLogBlooms() {}
BlockLogBlooms(RLP const& _r) { blooms = _r.toVector<LogBloom>(); size = _r.data().size(); }
bytes rlp() const { bytes r = dev::rlp(blooms); size = r.size(); return r; }
BlockLogBlooms() {}
BlockLogBlooms(RLP const& _r) { blooms = _r.toVector<LogBloom>(); size = _r.data().size(); }
bytes rlp() const { bytes r = dev::rlp(blooms); size = r.size(); return r; }

LogBlooms blooms;
mutable unsigned size;
LogBlooms blooms;
mutable unsigned size;
};

struct BlocksBlooms
{
BlocksBlooms() {}
BlocksBlooms(RLP const& _r) { blooms = _r.toArray<LogBloom, c_bloomIndexSize>(); size = _r.data().size(); }
bytes rlp() const { bytes r = dev::rlp(blooms); size = r.size(); return r; }
BlocksBlooms() {}
BlocksBlooms(RLP const& _r) { blooms = _r.toArray<LogBloom, c_bloomIndexSize>(); size = _r.data().size(); }
bytes rlp() const { bytes r = dev::rlp(blooms); size = r.size(); return r; }

std::array<LogBloom, c_bloomIndexSize> blooms;
mutable unsigned size;
std::array<LogBloom, c_bloomIndexSize> blooms;
mutable unsigned size;
};

struct BlockReceipts
{
BlockReceipts() {}
BlockReceipts(RLP const& _r) { for (auto const& i: _r) receipts.emplace_back(i.data()); size = _r.data().size(); }
bytes rlp() const { RLPStream s(receipts.size()); for (TransactionReceipt const& i: receipts) i.streamRLP(s); size = s.out().size(); return s.out(); }
BlockReceipts() {}
BlockReceipts(RLP const& _r) { for (auto const& i: _r) receipts.emplace_back(i.data()); size = _r.data().size(); }
bytes rlp() const { RLPStream s(receipts.size()); for (TransactionReceipt const& i: receipts) i.streamRLP(s); size = s.out().size(); return s.out(); }

TransactionReceipts receipts;
mutable unsigned size = 0;
TransactionReceipts receipts;
mutable unsigned size = 0;
};

struct BlockHash
{
BlockHash() {}
BlockHash(h256 const& _h): value(_h) {}
BlockHash(RLP const& _r) { value = _r.toHash<h256>(); }
bytes rlp() const { return dev::rlp(value); }
BlockHash() {}
BlockHash(h256 const& _h): value(_h) {}
BlockHash(RLP const& _r) { value = _r.toHash<h256>(); }
bytes rlp() const { return dev::rlp(value); }

h256 value;
static const unsigned size = 65;
h256 value;
static const unsigned size = 65;
};

struct TransactionAddress
{
TransactionAddress() {}
TransactionAddress(RLP const& _rlp) { blockHash = _rlp[0].toHash<h256>(); index = _rlp[1].toInt<unsigned>(); }
bytes rlp() const { RLPStream s(2); s << blockHash << index; return s.out(); }
TransactionAddress() {}
TransactionAddress(RLP const& _rlp) { blockHash = _rlp[0].toHash<h256>(); index = _rlp[1].toInt<unsigned>(); }
bytes rlp() const { RLPStream s(2); s << blockHash << index; return s.out(); }

explicit operator bool() const { return !!blockHash; }
explicit operator bool() const { return !!blockHash; }

h256 blockHash;
unsigned index = 0;
h256 blockHash;
unsigned index = 0;

static const unsigned size = 67;
static const unsigned size = 67;
};

using BlockDetailsHash = std::unordered_map<h256, BlockDetails>;
Expand Down
8 changes: 5 additions & 3 deletions libethereum/ClientBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,11 @@ BlockHeader ClientBase::pendingInfo() const

BlockDetails ClientBase::pendingDetails() const
{
auto pm = postSeal().info();
auto li = Interface::blockDetails(LatestBlock);
return BlockDetails((unsigned)pm.number(), li.totalDifficulty + pm.difficulty(), pm.parentHash(), h256s{});
auto const pendingHeader = postSeal().info();
auto const latestDetails = Interface::blockDetails(LatestBlock);
return BlockDetails{static_cast<unsigned>(pendingHeader.number()),
latestDetails.totalDifficulty + pendingHeader.difficulty(), pendingHeader.parentHash(),
h256s{} /* children */, postSeal().blockData().size()};
}

Addresses ClientBase::addresses(BlockNumber _block) const
Expand Down
64 changes: 64 additions & 0 deletions libethereum/DatabasePaths.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Aleth: Ethereum C++ client, tools and libraries.
// Copyright 2014-2019 Aleth Authors.
// Licensed under the GNU General Public License, Version 3.

#include "DatabasePaths.h"
#include "libdevcore/CommonIO.h"
#include "libethcore/Common.h"

namespace dev
{
namespace eth
{
namespace fs = boost::filesystem;

DatabasePaths::DatabasePaths(fs::path const& _rootPath, h256 const& _genesisHash) noexcept
{
// Allow an empty root path and empty genesis hash since they are required by the tests
m_rootPath = _rootPath;
m_chainPath = m_rootPath / fs::path(toHex(_genesisHash.ref().cropped(0, 4)));
m_statePath = m_chainPath / fs::path("state");
m_blocksPath = m_chainPath / fs::path("blocks");

auto const extrasRootPath = m_chainPath / fs::path(toString(c_databaseVersion));
m_extrasPath = extrasRootPath / fs::path("extras");
m_extrasTemporaryPath = extrasRootPath / fs::path("extras.old");
m_extrasMinorVersionPath = m_extrasPath / fs::path("minor");
}

fs::path const& DatabasePaths::rootPath() const noexcept
{
return m_rootPath;
}

fs::path const& DatabasePaths::chainPath() const noexcept
{
return m_chainPath;
}

fs::path const& DatabasePaths::statePath() const noexcept
{
return m_statePath;
}

fs::path const& DatabasePaths::blocksPath() const noexcept
{
return m_blocksPath;
}

fs::path const& DatabasePaths::extrasPath() const noexcept
{
return m_extrasPath;
}

fs::path const& DatabasePaths::extrasTemporaryPath() const noexcept
{
return m_extrasTemporaryPath;
}

fs::path const& DatabasePaths::extrasMinorVersionPath() const noexcept
{
return m_extrasMinorVersionPath;
}
} // namespace eth
} // namespace dev
36 changes: 36 additions & 0 deletions libethereum/DatabasePaths.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Aleth: Ethereum C++ client, tools and libraries.
// Copyright 2014-2019 Aleth Authors.
// Licensed under the GNU General Public License, Version 3.

#pragma once

#include "libdevcore/FixedHash.h"
#include <boost/filesystem/path.hpp>

namespace dev
{
namespace eth
{
class DatabasePaths
{
public:
DatabasePaths(boost::filesystem::path const& _rootPath, h256 const& _genesisHash) noexcept;
boost::filesystem::path const& rootPath() const noexcept;
boost::filesystem::path const& chainPath() const noexcept;
boost::filesystem::path const& blocksPath() const noexcept;
boost::filesystem::path const& statePath() const noexcept;
boost::filesystem::path const& extrasPath() const noexcept;
boost::filesystem::path const& extrasTemporaryPath() const noexcept;
boost::filesystem::path const& extrasMinorVersionPath() const noexcept;

private:
boost::filesystem::path m_rootPath;
boost::filesystem::path m_chainPath;
boost::filesystem::path m_blocksPath;
boost::filesystem::path m_statePath;
boost::filesystem::path m_extrasPath;
boost::filesystem::path m_extrasTemporaryPath;
boost::filesystem::path m_extrasMinorVersionPath;
};
} // namespace eth
} // namespace dev
Loading