diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 1f845ad20..4c71353d6 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -166,7 +166,7 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const if (!parentHash) return c_genesisDifficulty; else - return timestamp >= _parent.timestamp + 42 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10)); + return timestamp >= _parent.timestamp + 9 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10)); } void BlockInfo::verifyParent(BlockInfo const& _parent) const diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 475ab1f05..9fb80d8c6 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -20,7 +20,8 @@ class InvalidBlockFormat: public Exception { public: InvalidBlockFormat(int _f, class InvalidBlockHeaderFormat: public Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } }; class InvalidUnclesHash: public Exception {}; class InvalidUncle: public Exception {}; -class UncleNotAnUncle: public Exception {}; +class UncleTooOld: public Exception {}; +class UncleInChain: public Exception {}; class DuplicateUncleNonce: public Exception {}; class InvalidStateRoot: public Exception {}; class InvalidTransactionsHash: public Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref()); } }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 842343480..06117c01b 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -386,6 +386,20 @@ void BlockChain::checkConsistency() delete it; } +h256Set BlockChain::allUnclesFrom(h256 _parent) const +{ + // Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5). + h256Set ret; + h256 p = _parent; + for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent) + { + ret.insert(sha3(RLP(block(p))[0].data())); + for (auto i: RLP(block(p))[2]) + ret.insert(sha3(i.data())); + } + return ret; +} + bytes BlockChain::block(h256 _hash) const { if (_hash == m_genesisHash) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index d13ef7614..8fcf09691 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -107,6 +107,11 @@ public: /// 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). + /// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5 + /// togther with all their quoted uncles. + h256Set allUnclesFrom(h256 _parent) const; + /// @returns the genesis block header. static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); (s_genesis = new BlockInfo)->populate(&gb); } return *s_genesis; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 105c725f6..7b46228b4 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -390,7 +390,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const sync(_bc, _bi.parentHash); resetCurrent(); m_previousBlock = biParent; - return enact(_block, biGrandParent); + return enact(_block, &_bc); } map State::addresses() const @@ -499,7 +499,7 @@ h256s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged) return ret; } -u256 State::enact(bytesConstRef _block, BlockInfo const& _grandParent, bool _checkNonce) +u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) { // m_currentBlock is assumed to be prepopulated and reset. @@ -558,16 +558,21 @@ u256 State::enact(bytesConstRef _block, BlockInfo const& _grandParent, bool _che // Check uncles & apply their rewards to state. set nonces = { m_currentBlock.nonce }; Addresses rewarded; + set knownUncles = _bc ? _bc->allUnclesFrom(m_currentBlock.parentHash) : set(); for (auto const& i: RLP(_block)[2]) { BlockInfo uncle = BlockInfo::fromHeader(i.data()); - - if (m_previousBlock.parentHash != uncle.parentHash) - throw UncleNotAnUncle(); if (nonces.count(uncle.nonce)) throw DuplicateUncleNonce(); - if (_grandParent) - uncle.verifyParent(_grandParent); + if (_bc) + { + BlockInfo uncleParent(_bc->block(uncle.parentHash)); + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) // TODO: check 6. might be 7 or something... + throw UncleTooOld(); + if (knownUncles.count(uncle.hash)) + throw UncleInChain(); + uncle.verifyParent(uncleParent); + } nonces.insert(uncle.nonce); tdIncrease += uncle.difficulty; @@ -651,7 +656,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(&block.out(), BlockInfo(), false); // don't check nonce for this since we haven't mined it yet. + s.enact(&block.out(), &_bc, false); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -694,6 +699,7 @@ void State::commitToMine(BlockChain const& _bc) if (m_previousBlock != BlockChain::genesis()) { + // TODO: find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. // Find uncles if we're not a direct child of the genesis. // cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; auto us = _bc.details(m_previousBlock.parentHash).children; @@ -1181,8 +1187,8 @@ void State::applyRewards(Addresses const& _uncleAddresses) u256 r = m_blockReward; for (auto const& i: _uncleAddresses) { - addBalance(i, m_blockReward * 3 / 4); - r += m_blockReward / 8; + addBalance(i, m_blockReward * 15 / 16); + r += m_blockReward / 32; } addBalance(m_currentBlock.coinbaseAddress, r); } diff --git a/libethereum/State.h b/libethereum/State.h index c8fd27e01..c605ce42e 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -299,9 +299,9 @@ private: /// Commit all changes waiting in the address cache to the DB. void commit(); - /// Execute the given block, assuming it corresponds to m_currentBlock. If _grandParent is passed, it will be used to check the uncles. + /// Execute the given block, assuming it corresponds to m_currentBlock. If _bc is passed, it will be used to check the uncles. /// Throws on failure. - u256 enact(bytesConstRef _block, BlockInfo const& _grandParent = BlockInfo(), bool _checkNonce = true); + u256 enact(bytesConstRef _block, BlockChain const* _bc = nullptr, bool _checkNonce = true); // Two priviledged entry points for the VM (these don't get added to the Transaction lists): // We assume all instrinsic fees are paid up before this point.