From 34ab7e82315b1e9dfbbd36b8e4286762e74e7922 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 26 Jul 2014 12:31:24 +0200 Subject: [PATCH] Avoid recursion in TransactionQueue. --- libethereum/BlockQueue.cpp | 24 +++++++++++---------- libethereum/Transaction.cpp | 37 ++++++++++++++++++-------------- libethereum/Transaction.h | 11 ++++++---- libethereum/TransactionQueue.cpp | 12 +++++------ 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b688ae186..da21e6929 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -85,18 +85,20 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) return true; } -void BlockQueue::noteReadyWithoutWriteGuard(h256 _b) +void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) { - auto r = m_future.equal_range(_b); - h256s good; - for (auto it = r.first; it != r.second; ++it) + h256s goodQueue(1, _good); + while (goodQueue.size()) { - m_futureSet.erase(it->second.first); - m_ready.push_back(it->second.second); - m_readySet.erase(it->second.first); - good.push_back(it->second.first); + auto r = m_future.equal_range(goodQueue.back()); + goodQueue.pop_back(); + for (auto it = r.first; it != r.second; ++it) + { + m_futureSet.erase(it->second.first); + m_ready.push_back(it->second.second); + m_readySet.erase(it->second.first); + goodQueue.push_back(it->second.first); + } + m_future.erase(r.first, r.second); } - m_future.erase(r.first, r.second); - for (auto g: good) - noteReadyWithoutWriteGuard(g); } diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index b60cf115e..887458a63 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -29,7 +29,7 @@ using namespace eth; #define ETH_ADDRESS_DEBUG 0 -Transaction::Transaction(bytesConstRef _rlpData) +Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) { int field = 0; RLP rlp(_rlpData); @@ -42,6 +42,8 @@ Transaction::Transaction(bytesConstRef _rlpData) value = rlp[field = 4].toInt(); data = rlp[field = 5].toBytes(); vrs = Signature{ rlp[field = 6].toInt(), rlp[field = 7].toInt(), rlp[field = 8].toInt() }; + if (_checkSender) + m_sender = sender(); } catch (RLPException const&) { @@ -63,27 +65,30 @@ Address Transaction::safeSender() const noexcept Address Transaction::sender() const { - secp256k1_start(); + if (!m_sender) + { + secp256k1_start(); - h256 sig[2] = { vrs.r, vrs.s }; - h256 msg = sha3(false); + h256 sig[2] = { vrs.r, vrs.s }; + h256 msg = sha3(false); - byte pubkey[65]; - int pubkeylen = 65; - if (!secp256k1_ecdsa_recover_compact(msg.data(), 32, sig[0].data(), pubkey, &pubkeylen, 0, (int)vrs.v - 27)) - throw InvalidSignature(); + byte pubkey[65]; + int pubkeylen = 65; + if (!secp256k1_ecdsa_recover_compact(msg.data(), 32, sig[0].data(), pubkey, &pubkeylen, 0, (int)vrs.v - 27)) + throw InvalidSignature(); - // TODO: check right160 is correct and shouldn't be left160. - auto ret = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + // TODO: check right160 is correct and shouldn't be left160. + m_sender = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG - cout << "---- RECOVER -------------------------------" << endl; - cout << "MSG: " << msg << endl; - cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(vrs.v - 27) << "+27" << endl; - cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; - cout << "ADR: " << ret << endl; + cout << "---- RECOVER -------------------------------" << endl; + cout << "MSG: " << msg << endl; + cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(vrs.v - 27) << "+27" << endl; + cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; + cout << "ADR: " << ret << endl; #endif - return ret; + } + return m_sender; } void Transaction::sign(Secret _priv) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index e3384c540..9e0ab3009 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -38,8 +38,8 @@ struct Signature struct Transaction { Transaction() {} - Transaction(bytesConstRef _rlp); - Transaction(bytes const& _rlp): Transaction(&_rlp) {} + Transaction(bytesConstRef _rlp, bool _checkSender = false); + Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} bool operator==(Transaction const& _c) const { return receiveAddress == _c.receiveAddress && value == _c.value && data == _c.data; } bool operator!=(Transaction const& _c) const { return !operator==(_c); } @@ -55,8 +55,8 @@ struct Transaction Signature vrs; ///< The signature of the transaction. Encodes the sender. Address safeSender() const noexcept; ///< Like sender() but will never throw. - Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). - void sign(Secret _priv); ///< Sign the transaction. + Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). + void sign(Secret _priv); ///< Sign the transaction. bool isCreation() const { return !receiveAddress; } @@ -67,6 +67,9 @@ struct Transaction std::string rlpString(bool _sig = true) const { return asString(rlp(_sig)); } h256 sha3(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return eth::sha3(s.out()); } bytes sha3Bytes(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return eth::sha3Bytes(s.out()); } + +private: + mutable Address m_sender; }; using Transactions = std::vector; diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 750243de2..0181f7ba0 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -27,22 +27,22 @@ using namespace std; using namespace eth; -bool TransactionQueue::import(bytesConstRef _block) +bool TransactionQueue::import(bytesConstRef _transactionRLP) { // Check if we already know this transaction. - h256 h = sha3(_block); + h256 h = sha3(_transactionRLP); if (m_known.count(h)) return false; try { - // Check validity of _block as a transaction. To do this we just deserialise and attempt to determine the sender. If it doesn't work, the signature is bad. + // Check validity of _transactionRLP as a transaction. To do this we just deserialise and attempt to determine the sender. + // If it doesn't work, the signature is bad. // The transaction's nonce may yet be invalid (or, it could be "valid" but we may be missing a marginally older transaction). - Transaction t(_block); - auto s = t.sender(); + Transaction t(_transactionRLP, true); // If valid, append to blocks. - m_current[h] = _block.toBytes(); + m_current[h] = _transactionRLP.toBytes(); } catch (InvalidTransactionFormat const& _e) {