diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 89f4c49da..7789d6b32 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -191,16 +191,19 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const if (!parentHash) return c_genesisDifficulty; else - return max(1024, timestamp >= _parent.timestamp + (c_protocolVersion == 49 ? 5 : 8) ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10))); + return max(2048, timestamp >= _parent.timestamp + (c_protocolVersion == 49 ? 5 : 8) ? _parent.difficulty - (_parent.difficulty / 2048) : (_parent.difficulty + (_parent.difficulty / 2048))); } +template inline N diff(N const& _a, N const& _b) { return max(_a, _b) - min(_a, _b); } + void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check difficulty is correct given the two timestamps. if (difficulty != calculateDifficulty(_parent)) BOOST_THROW_EXCEPTION(InvalidDifficulty()); - if (gasLimit != calculateGasLimit(_parent)) - BOOST_THROW_EXCEPTION(InvalidGasLimit(gasLimit, calculateGasLimit(_parent))); + if (diff(gasLimit, _parent.gasLimit) <= _parent.gasLimit / 1024) + BOOST_THROW_EXCEPTION(InvalidGasLimit(gasLimit, calculateGasLimit(_parent), diff(gasLimit, _parent.gasLimit), _parent.gasLimit / 1024)); + // Check timestamp is after previous timestamp. if (parentHash) diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index 9b07743c5..c4628f4aa 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -39,7 +39,7 @@ static boost::thread_specific_ptr g_exceptionMessage; const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); } -const char* InvalidGasLimit::what() const noexcept { ETH_RETURN_STRING("Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")"); } +const char* InvalidGasLimit::what() const noexcept { ETH_RETURN_STRING("Invalid gas limit (provided: " + toString(provided) + " default:" + toString(valid) + " givenDiff:" + toString(givenDiff) + " maxDiff:" + toString(maxDiff) + ")"); } const char* InvalidMinGasPrice::what() const noexcept { ETH_RETURN_STRING("Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")"); } const char* InvalidNonce::what() const noexcept { ETH_RETURN_STRING("Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")"); } const char* InvalidBlockNonce::what() const noexcept { ETH_RETURN_STRING("Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")"); } diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 3fd62afbd..4679c1961 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -47,6 +47,7 @@ struct InvalidSignature: virtual dev::Exception {}; class InvalidBlockFormat: virtual public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual const char* what() const noexcept; }; struct InvalidUnclesHash: virtual dev::Exception {}; struct InvalidUncle: virtual dev::Exception {}; +struct TooManyUncles: virtual dev::Exception {}; struct UncleTooOld: virtual dev::Exception {}; class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; }; struct DuplicateUncleNonce: virtual dev::Exception {}; @@ -55,7 +56,7 @@ struct InvalidGasUsed: virtual dev::Exception {}; class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; }; struct InvalidTransaction: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {}; -class InvalidGasLimit: virtual public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; }; +class InvalidGasLimit: virtual public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0, u256 _gD = 0, u256 _mD = 0): provided(_provided), valid(_valid), givenDiff(_gD), maxDiff(_mD) {} u256 provided; u256 valid; u256 givenDiff; u256 maxDiff; virtual const char* what() const noexcept; }; class InvalidMinGasPrice: virtual public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; }; struct InvalidTransactionGasUsed: virtual dev::Exception {}; struct InvalidTransactionsStateRoot: virtual dev::Exception {}; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 6b594e7a5..a9837d118 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -486,10 +486,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) receiptsTrie.init(); LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number); + RLP rlp(_block); // All ok with the block generally. Play back the transactions now... unsigned i = 0; - for (auto const& tr: RLP(_block)[1]) + for (auto const& tr: rlp[1]) { RLPStream k; k << i; @@ -503,17 +504,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) ++i; } - if (transactionsTrie.root() != m_currentBlock.transactionsRoot) - { - cwarn << "Bad transactions state root!"; - BOOST_THROW_EXCEPTION(InvalidTransactionsStateRoot()); - } - if (receiptsTrie.root() != m_currentBlock.receiptsRoot) { cwarn << "Bad receipts state root."; cwarn << "Block:" << toHex(_block); - cwarn << "Block RLP:" << RLP(_block); + cwarn << "Block RLP:" << rlp; cwarn << "Calculated: " << receiptsTrie.root(); for (unsigned j = 0; j < i; ++j) { @@ -548,10 +543,14 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) u256 tdIncrease = m_currentBlock.difficulty; // Check uncles & apply their rewards to state. + if (rlp[2].itemCount() > 2) + BOOST_THROW_EXCEPTION(TooManyUncles()); + set nonces = { m_currentBlock.nonce }; Addresses rewarded; set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); - for (auto const& i: RLP(_block)[2]) + + for (auto const& i: rlp[2]) { if (knownUncles.count(sha3(i.data()))) BOOST_THROW_EXCEPTION(UncleInChain(knownUncles, sha3(i.data()) )); @@ -699,7 +698,7 @@ void State::commitToMine(BlockChain const& _bc) // cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); auto p = m_previousBlock.parentHash; - for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash(); ++gen, p = _bc.details(p).parent) + for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! @@ -710,6 +709,8 @@ void State::commitToMine(BlockChain const& _bc) ubi.streamRLP(unclesData, WithNonce); ++unclesCount; uncleAddresses.push_back(ubi.coinbaseAddress); + if (unclesCount == 2) + break; } } }