diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 2c3ef40a8..0529e305e 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -98,7 +98,8 @@ public: /// To be called from main loop every 100ms or so. void process(); - /// Sync the chain with any incoming blocks. All blocks should, if processed in order + /// Sync the chain with any incoming blocks. All blocks should, if processed in order. + /// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting. std::tuple sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 6959aaa81..b4b92c713 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -441,7 +441,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; ETH_WRITE_GUARDED(x_postMine) - newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_postMine.sync(m_bc, m_tq, *m_gp); if (newPendingReceipts.empty()) return; diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 82097995b..83fe22a71 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -420,7 +420,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) if (count > 20 && n == 0) clog(NetWarn) << "all" << count << "unknown blocks requested; peer on different chain?"; else - clog(NetMessageSummary) << n << "blocks known and returned;" << (min(count, c_maxBlocks) - n) << "blocks unknown;" << (c_maxBlocks > count ? c_maxBlocks - count : 0) << "blocks ignored"; + clog(NetMessageSummary) << n << "blocks known and returned;" << (min(count, c_maxBlocks) - n) << "blocks unknown;" << (count > c_maxBlocks ? count - c_maxBlocks : 0) << "blocks ignored"; addRating(0); RLPStream s; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 278002c87..19cec8614 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -461,43 +461,19 @@ void State::resetCurrent() paranoia("begin resetCurrent", true); } -bool State::cull(TransactionQueue& _tq) const -{ - bool ret = false; - auto ts = _tq.transactions(); - for (auto const& i: ts) - { - if (!m_transactionSet.count(i.first)) - { - try - { - if (i.second.nonce() < transactionsFrom(i.second.sender())) - { - _tq.drop(i.first); - ret = true; - } - } - catch (...) - { - _tq.drop(i.first); - ret = true; - } - } - } - return ret; -} - -TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged, unsigned msTimeout) +pair State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned msTimeout) { // TRANSACTIONS - TransactionReceipts ret; + pair ret; + ret.second = false; + auto ts = _tq.transactions(); LastHashes lh; auto deadline = chrono::steady_clock::now() + chrono::milliseconds(msTimeout); - for (int goodTxs = 1; goodTxs && chrono::steady_clock::now() < deadline; ) + for (int goodTxs = 1; goodTxs; ) { goodTxs = 0; for (auto const& i: ts) @@ -511,51 +487,67 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga if (lh.empty()) lh = _bc.lastHashes(); execute(lh, i.second); - ret.push_back(m_receipts.back()); + ret.first.push_back(m_receipts.back()); _tq.noteGood(i); ++goodTxs; // cnote << "TX took:" << t.elapsed() * 1000; } + else if (i.second.gasPrice() < _gp.ask(*this) * 9 / 10) + { + // less than 90% of our ask price for gas. drop. + cnote << i.first.abridged() << "Dropping El Cheapo transaction (<90% of ask price)"; + _tq.drop(i.first); + } } -#if ETH_DEBUG catch (InvalidNonce const& in) { - bigint const* req = boost::get_error_info(in); - bigint const* got = boost::get_error_info(in); + bigint const& req = *boost::get_error_info(in); + bigint const& got = *boost::get_error_info(in); - if (*req > *got) + if (req > got) { // too old + cnote << i.first.abridged() << "Dropping old transaction (nonce too low)"; + _tq.drop(i.first); + } + else if (got > req + 5) + { + // too new + cnote << i.first.abridged() << "Dropping new transaction (> 5 nonces ahead)"; _tq.drop(i.first); - if (o_transactionQueueChanged) - *o_transactionQueueChanged = true; } else _tq.setFuture(i); } catch (BlockGasLimitReached const& e) { - _tq.setFuture(i); + bigint const& got = *boost::get_error_info(e); + if (got > m_currentBlock.gasLimit) + { + cnote << i.first.abridged() << "Dropping over-gassy transaction (gas > block's gas limit)"; + _tq.drop(i.first); + } + else + _tq.setFuture(i); } -#endif catch (Exception const& _e) { // Something else went wrong - drop it. + cnote << i.first.abridged() << "Dropping invalid transaction:" << diagnostic_information(_e); _tq.drop(i.first); - if (o_transactionQueueChanged) - *o_transactionQueueChanged = true; - cnote << "Dropping invalid transaction:"; - cnote << diagnostic_information(_e); } catch (std::exception const&) { // Something else went wrong - drop it. _tq.drop(i.first); - if (o_transactionQueueChanged) - *o_transactionQueueChanged = true; - cnote << "Transaction caused low-level exception :("; + cnote << i.first.abridged() << "Transaction caused low-level exception :("; } } + if (chrono::steady_clock::now() > deadline) + { + ret.second = true; + break; + } } return ret; } diff --git a/libethereum/State.h b/libethereum/State.h index a3e2ddff1..28b005243 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -200,14 +200,9 @@ public: /// Only valid after mine() returns true. bytes const& blockData() const { return m_currentBytes; } - // TODO: Cleaner interface. /// 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. - /// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue - /// changed and the pointer is non-null - TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged = nullptr, unsigned _msTimeout = 100); - /// Like sync but only operate on _tq, killing the invalid/old ones. - bool cull(TransactionQueue& _tq) const; + /// @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); /// Execute a given transaction. /// This will append @a _t to the transaction list and change the state accordingly.