Browse Source

Rewards and uncle checking.

cl-refactor
Gav Wood 11 years ago
parent
commit
9cf6fd38ca
  1. 41
      libethereum/BlockChain.cpp
  2. 6
      libethereum/BlockChain.h
  3. 2
      libethereum/BlockInfo.h
  4. 4
      libethereum/Common.h
  5. 80
      libethereum/State.cpp
  6. 28
      libethereum/State.h
  7. 3
      libethereum/Transaction.h

41
libethereum/BlockChain.cpp

@ -37,6 +37,8 @@ BlockChain::BlockChain()
// Initialise with the genesis as the last block on the longest chain.
m_lastBlockHash = m_genesisHash = BlockInfo::genesis().hash;
m_genesisBlock = BlockInfo::createGenesisBlock();
// TODO: Insert details of genesis block.
}
BlockChain::~BlockChain()
@ -45,8 +47,8 @@ BlockChain::~BlockChain()
h256s BlockChain::blockChain(h256Set const& _earlyExit) const
{
// TODO: return the current valid block chain from most recent to genesis.
// TODO: arguments for specifying a set of early-ends
// Return the current valid block chain from most recent to genesis.
// Arguments for specifying a set of early-ends
h256s ret;
ret.reserve(m_details[m_lastBlockHash].number + 1);
auto i = m_lastBlockHash;
@ -55,7 +57,8 @@ h256s BlockChain::blockChain(h256Set const& _earlyExit) const
ret.push_back(i);
return ret;
}
// _bc.details(m_previousBlock.parentHash).children
// _bc->coinbaseAddress(i)
void BlockChain::import(bytes const& _block)
{
try
@ -77,38 +80,22 @@ void BlockChain::import(bytes const& _block)
return;
// Check family:
BlockInfo bip(block(bi.parentHash));
bi.verifyParent(bip);
BlockInfo biParent(block(bi.parentHash));
bi.verifyParent(biParent);
// Check transactions are valid and that they result in a state equivalent to our state_root.
// this saves us from an embarrassing exit later.
State s(bi.coinbaseAddress);
s.sync(*this, bi.parentHash);
for (auto const& i: RLP(_block)[1])
s.execute(i.data());
if (s.rootHash() != bi.stateRoot)
throw InvalidStateRoot();
// Initalise total difficulty calculation.
u256 td = it->second.totalDifficulty + bi.difficulty;
// Check uncles.
for (auto const& i: RLP(_block)[2])
{
BlockInfo uncle(i.data());
if (it->second.parent != bi.parentHash)
throw InvalidUncle();
uncle.verifyParent(bip);
td += uncle.difficulty;
}
// Get total difficulty increase and update state, checking it.
BlockInfo biGrandParent;
if (it->second.number)
biGrandParent.populate(block(it->second.parent));
u256 td = it->second.totalDifficulty + s.playback(&_block, bi, biParent, biGrandParent);
// All ok - insert into DB
m_details[newHash] = BlockDetails{(uint)it->second.number + 1, bi.parentHash, td};
m_children.insert(make_pair(bi.parentHash, newHash));
m_details[bi.parentHash].children.push_back(newHash);
m_db->Put(m_writeOptions, ldb::Slice(toBigEndianString(newHash)), (ldb::Slice)ref(_block));
// This might be the new last block...

6
libethereum/BlockChain.h

@ -33,9 +33,11 @@ struct BlockDetails
uint number;
u256 totalDifficulty;
h256 parent;
h256s children;
};
static const BlockDetails NullBlockDetails({0, 0, h256()});
static const h256s NullH256s;
/**
* @brief Implements the blockchain database. All data this gives is disk-backed.
@ -68,10 +70,12 @@ public:
/// Get a given block (RLP format).
h256 currentHash() const { return m_lastBlockHash; }
/// Get the coinbase address of a given block.
Address coinbaseAddress(h256 _hash) const;
private:
/// Get fully populated from disk DB.
mutable std::map<h256, BlockDetails> m_details;
mutable std::multimap<h256, h256> m_children;
mutable std::map<h256, std::string> m_cache;

2
libethereum/BlockInfo.h

@ -43,7 +43,7 @@ public:
BlockInfo();
explicit BlockInfo(bytesConstRef _block);
explicit operator bool() { return timestamp != Invalid256; }
explicit operator bool() const { return timestamp != Invalid256; }
bool operator==(BlockInfo const& _cmp) const { return hash == _cmp.hash && parentHash == _cmp.parentHash && nonce == _cmp.nonce; }

4
libethereum/Common.h

@ -95,6 +95,10 @@ using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
using PrivateKey = h256;
using Address = h160;
using Addresses = h160s;
// Map types.
using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>;

80
libethereum/State.cpp

@ -39,8 +39,9 @@ u256 const State::c_extroFee = 0;
u256 const State::c_cryptoFee = 0;
u256 const State::c_newContractFee = 0;
u256 const State::c_txFee = 0;
u256 const State::c_blockReward = 0;
State::State(Address _coinbaseAddress): m_coinbaseAddress(_coinbaseAddress)
State::State(Address _coinbaseAddress): m_ourAddress(_coinbaseAddress)
{
secp256k1_start();
m_previousBlock = BlockInfo::genesis();
@ -137,25 +138,13 @@ void State::sync(TransactionQueue& _tq)
}
}
void State::playback(bytesConstRef _block)
u256 State::playback(bytesConstRef _block)
{
try
{
m_currentBlock.populate(_block);
m_currentBlock.verifyInternals(_block);
if (m_currentBlock.parentHash != m_previousBlock.hash)
throw InvalidParentHash();
// All ok with the block generally. Play back the transactions now...
RLP txs = RLP(_block)[1];
for (auto const& i: txs)
execute(i.data());
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot != rootHash())
throw InvalidStateRoot();
m_previousBlock = m_currentBlock;
return playback(_block, BlockInfo());
}
catch (...)
{
@ -165,9 +154,53 @@ void State::playback(bytesConstRef _block)
}
}
u256 State::playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent)
{
m_currentBlock = _bi;
m_previousBlock = _parent;
return playback(_block, _grandParent);
}
u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent)
{
if (m_currentBlock.parentHash != m_previousBlock.hash)
throw InvalidParentHash();
// All ok with the block generally. Play back the transactions now...
for (auto const& i: RLP(_block)[1])
execute(i.data());
// Initialise total difficulty calculation.
u256 tdIncrease = m_currentBlock.difficulty;
// Check uncles & apply their rewards to state.
Addresses rewarded;
for (auto const& i: RLP(_block)[2])
{
BlockInfo uncle(i.data());
if (m_previousBlock.parentHash != uncle.parentHash)
throw InvalidUncle();
if (_grandParent)
uncle.verifyParent(_grandParent);
tdIncrease += uncle.difficulty;
rewarded.push_back(uncle.coinbaseAddress);
}
applyRewards(rewarded);
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot != rootHash())
throw InvalidStateRoot();
m_previousBlock = m_currentBlock;
m_currentBlock = BlockInfo();
m_currentBlock.coinbaseAddress = m_ourAddress;
return tdIncrease;
}
h256 State::rootHash() const
{
// TODO.
// TODO!
return h256();
}
@ -252,6 +285,17 @@ bool State::execute(bytesConstRef _rlp)
}
}
void State::applyRewards(Addresses const& _uncleAddresses)
{
u256 r = c_blockReward;
for (auto const& i: _uncleAddresses)
{
addBalance(i, c_blockReward * 4 / 3);
r += c_blockReward / 8;
}
addBalance(m_currentBlock.coinbaseAddress, r);
}
void State::execute(Transaction const& _t, Address _sender)
{
// Entry point for a contract-originated transaction.
@ -269,7 +313,7 @@ void State::execute(Transaction const& _t, Address _sender)
{
subBalance(_sender, _t.value + _t.fee);
addBalance(_t.receiveAddress, _t.value);
addBalance(m_coinbaseAddress, _t.fee);
addBalance(m_currentBlock.coinbaseAddress, _t.fee);
if (isContractAddress(_t.receiveAddress))
{
@ -292,7 +336,7 @@ void State::execute(Transaction const& _t, Address _sender)
mem[i] = _t.data[i];
subBalance(_sender, _t.value + _t.fee);
addBalance(newAddress, _t.value);
addBalance(m_coinbaseAddress, _t.fee);
addBalance(m_currentBlock.coinbaseAddress, _t.fee);
}
}

28
libethereum/State.h

@ -105,15 +105,32 @@ public:
/// The hash of the root of our state tree.
h256 rootHash() const;
/// Finalise the block, applying the earned rewards.
void applyRewards(Addresses const& _uncleAddresses);
/// Execute all transactions within a given block.
/// @returns the additional total difficulty.
/// If the _grandParent is passed, it will check the validity of each of the uncles.
/// This might throw.
u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent);
private:
/// Fee-adder on destruction RAII class.
struct MinerFeeAdder
{
~MinerFeeAdder() { state->addBalance(state->m_coinbaseAddress, fee); }
~MinerFeeAdder() { state->addBalance(state->m_currentBlock.coinbaseAddress, fee); }
State* state;
u256 fee;
};
/// Execute the given block on our previous block. This will set up m_currentBlock first, then call the other playback().
/// Any failure will be critical.
u256 playback(bytesConstRef _block);
/// Execute the given block, assuming it corresponds to m_currentBlock. If _grandParent is passed, it will be used to check the uncles.
/// Throws on failure.
u256 playback(bytesConstRef _block, BlockInfo const& _grandParent);
/// Execute a decoded transaction object, given a sender.
/// This will append @a _t to the transaction list and change the state accordingly.
void execute(Transaction const& _t, Address _sender);
@ -121,11 +138,7 @@ private:
/// Execute a contract transaction.
void execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* o_totalFee);
/// Execute all transactions within a given block.
void playback(bytesConstRef _block);
// TODO: std::hash<Address> and then move to unordered_map.
// Will need to sort on hash construction.
// TODO: move over to Trie in leveldb; specify a snapshot for .
std::map<Address, AddressState> m_current; ///< The current state. We work with a C++ hash map rather than a Trie.
std::map<h256, Transaction> m_transactions; ///< The current list of transactions that we've included in the state.
@ -134,7 +147,7 @@ private:
bytes m_currentBytes; ///< The current block.
uint m_currentNumber;
Address m_coinbaseAddress; ///< Our address (i.e. the address to which fees go).
Address m_ourAddress; ///< Our address (i.e. the address to which fees go).
/// The fee structure. Values yet to be agreed on...
static const u256 c_stepFee;
@ -144,6 +157,7 @@ private:
static const u256 c_cryptoFee;
static const u256 c_newContractFee;
static const u256 c_txFee;
static const u256 c_blockReward;
};
}

3
libethereum/Transaction.h

@ -27,9 +27,6 @@
namespace eth
{
using PrivateKey = h256;
using Address = h160;
struct Signature
{
byte v;

Loading…
Cancel
Save