/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see .
*/
/** @file Block.h
* @author Gav Wood
* @date 2014
*/
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "Account.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
#include "AccountDiff.h"
#include "GasPricer.h"
#include "State.h"
namespace dev
{
namespace test { class ImportTest; class StateLoader; }
namespace eth
{
class BlockChain;
class State;
class TransactionQueue;
struct VerifiedBlockRef;
struct BlockChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct BlockTrace: public LogChannel { static const char* name(); static const int verbosity = 5; };
struct BlockDetail: public LogChannel { static const char* name(); static const int verbosity = 14; };
struct BlockSafeExceptions: public LogChannel { static const char* name(); static const int verbosity = 21; };
struct PopulationStatistics
{
double verify;
double enact;
};
/**
* @brief Active model of a block within the block chain.
* Keeps track of all transactions, receipts and state for a particular block. Can apply all
* needed transforms of the state for rewards and contains logic for sealing the block.
*/
class Block
{
friend class ExtVM;
friend class dev::test::ImportTest;
friend class dev::test::StateLoader;
friend class Executive;
friend class BlockChain;
public:
/// Default constructor; creates with a blank database prepopulated with the genesis block.
Block(): m_state(OverlayDB(), BaseState::Empty) {}
/// Basic state object from database.
/// Use the default when you already have a database and you just want to make a Block object
/// which uses it. If you have no preexisting database then set BaseState to something other
/// than BaseState::PreExisting in order to prepopulate the Trie.
/// You can also set the beneficiary address.
explicit Block(OverlayDB const& _db, BaseState _bs = BaseState::PreExisting, Address _coinbaseAddress = Address());
/// Copy state object.
Block(Block const& _s);
/// Copy state object.
Block& operator=(Block const& _s);
/// Get the beneficiary address for any transactions we do and rewards we get.
Address beneficiary() const { return m_beneficiary; }
/// Set the beneficiary address for any transactions we do and rewards we get.
/// This causes a complete reset of current block.
void setBeneficiary(Address const& _id) { m_beneficiary = _id; resetCurrent(); }
// Account-getters. All operate on the final state.
/// Get an account's balance.
/// @returns 0 if the address has never been used.
u256 balance(Address const& _address) const { return m_state.balance(_address); }
/// Get the number of transactions a particular address has sent (used for the transaction nonce).
/// @returns 0 if the address has never been used.
u256 transactionsFrom(Address const& _address) const { return m_state.transactionsFrom(_address); }
/// Check if the address is in use.
bool addressInUse(Address const& _address) const { return m_state.addressInUse(_address); }
/// Check if the address contains executable code.
bool addressHasCode(Address const& _address) const { return m_state.addressHasCode(_address); }
/// Get the root of the storage of an account.
h256 storageRoot(Address const& _contract) const { return m_state.storageRoot(_contract); }
/// Get the value of a storage position of an account.
/// @returns 0 if no account exists at that address.
u256 storage(Address const& _contract, u256 const& _memory) const { return m_state.storage(_contract, _memory); }
/// Get the storage of an account.
/// @note This is expensive. Don't use it unless you need to.
/// @returns std::unordered_map if no account exists at that address.
std::unordered_map storage(Address const& _contract) const { return m_state.storage(_contract); }
/// Get the code of an account.
/// @returns bytes() if no account exists at that address.
bytes const& code(Address const& _contract) const { return m_state.code(_contract); }
/// Get the code hash of an account.
/// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address.
h256 codeHash(Address const& _contract) const { return m_state.codeHash(_contract); }
// General information from state
/// Get the backing state object.
State const& state() const { return m_state; }
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary.
OverlayDB const& db() const { return m_state.db(); }
/// The hash of the root of our state tree.
h256 rootHash() const { return m_state.rootHash(); }
/// @returns the set containing all addresses currently in use in Ethereum.
/// @throws InterfaceNotSupported if compiled without ETH_FATDB.
std::unordered_map addresses() const { return m_state.addresses(); }
// For altering accounts behind-the-scenes
/// Get a mutable State object which is backing this block.
/// @warning Only use this is you know what you're doing. If you use it while constructing a
/// normal sealable block, don't expect things to work right.
State& mutableState() { return m_state; }
// Information concerning ongoing transactions
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); }
/// Get the list of pending transactions.
Transactions const& pending() const { return m_transactions; }
/// Get the list of hashes of pending transactions.
h256Hash const& pendingHashes() const { return m_transactionSet; }
/// Get the transaction receipt for the transaction of the given index.
TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; }
/// Get the list of pending transactions.
LogEntries const& log(unsigned _i) const { return m_receipts[_i].log(); }
/// Get the bloom filter of all logs that happened in the block.
LogBloom logBloom() const;
/// Get the bloom filter of a particular transaction that happened in the block.
LogBloom const& logBloom(unsigned _i) const { return m_receipts[_i].bloom(); }
/// 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 == pending().size()) returns the final state of the block, prior to rewards.
State fromPending(unsigned _i) const;
/// @returns the StateDiff caused by the pending transaction of index @a _i.
StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1), true); }
// State-change operations
/// Construct state object from arbitrary point in blockchain.
PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None);
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
/// Sync our transactions, killing those from the queue that we have and assimilating those that we don't.
/// @returns a list of receipts one for each transaction placed from the queue into the state and bool, true iff there are more transactions to be processed.
std::pair sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned _msTimeout = 100);
/// Sync our state with the block chain.
/// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue.
bool sync(BlockChain const& _bc);
/// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block.
bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo());
/// Execute all transactions within a given block.
/// @returns the additional total difficulty.
u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Returns back to a pristine state after having done a playback.
/// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates
/// the block since all state changes are ultimately reversed.
void cleanup(bool _fullCommit);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();
// Sealing
/// Prepares the current state for mining.
/// Commits all transactions into the trie, compiles uncles and transactions list, applies all
/// rewards and populates the current block header with the appropriate hashes.
/// The only thing left to do after this is to actually mine().
///
/// This may be called multiple times and without issue.
void commitToSeal(BlockChain const& _bc, bytes const& _extraData = {});
/// Pass in a solution to the proof-of-work.
/// @returns true iff we were previously committed to mining.
/// TODO: verify it prior to calling this.
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* while (notYetMined)
* {
* // lock
* commitToSeal(_blockChain); // will call uncommitToMine if a repeat.
* completeMine();
* // unlock
* @endcode
*/
bool sealBlock(bytes const& _header) { return sealBlock(&_header); }
bool sealBlock(bytesConstRef _header);
/// Get the complete current block, including valid nonce.
/// Only valid after mine() returns true.
bytes const& blockData() const { return m_currentBytes; }
/// Get the header information on the present block.
BlockInfo const& info() const { return m_currentBlock; }
private:
/// Undo the changes to the state for committing to mine.
void uncommitToMine();
/// Retrieve all information about a given address into the cache.
/// If _requireMemory is true, grab the full memory should it be a contract item.
/// If _forceCreate is true, then insert a default item into the cache, in the case it doesn't
/// exist in the DB.
void ensureCached(Address const& _a, bool _requireCode, bool _forceCreate) const;
/// Retrieve all information about a given address into a cache.
void ensureCached(std::unordered_map& _cache, Address const& _a, bool _requireCode, bool _forceCreate) const;
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Finalise the block, applying the earned rewards.
void applyRewards(std::vector const& _uncleBlockHeaders);
/// @returns gas used by transactions thus far executed.
u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; }
/// Provide a standard VM trace for debugging purposes.
std::string vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir);
State m_state; ///< Our state tree, as an OverlayDB DB.
Transactions m_transactions; ///< The current list of transactions that we've included in the state.
TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts.
h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state.
State m_precommit; ///< State at the point immediately prior to rewards.
BlockInfo m_previousBlock; ///< The previous block's information.
BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block.
bool m_committedToMine = false; ///< Have we committed to mine on the present m_currentBlock?
bytes m_currentTxs; ///< The RLP-encoded block of transactions.
bytes m_currentUncles; ///< The RLP-encoded block of uncles.
Address m_beneficiary; ///< Our address (i.e. the address to which fees go).
u256 m_blockReward;
friend std::ostream& operator<<(std::ostream& _out, Block const& _s);
};
std::ostream& operator<<(std::ostream& _out, Block const& _s);
}
}