Browse Source

Transaction nonce now "sorted". Fixes #1615

cl-refactor
Gav Wood 10 years ago
parent
commit
fd5ea37e55
  1. 2
      libdevcore/Common.h
  2. 6
      libethcore/EthashAux.cpp
  3. 7
      libethereum/ClientBase.cpp
  4. 11
      libethereum/Transaction.h
  5. 49
      libethereum/TransactionQueue.cpp
  6. 7
      libethereum/TransactionQueue.h
  7. 4
      libweb3jsonrpc/WebThreeStubServerBase.cpp

2
libdevcore/Common.h

@ -52,6 +52,8 @@ using byte = uint8_t;
#define DEV_QUOTED_HELPER(s) #s #define DEV_QUOTED_HELPER(s) #s
#define DEV_QUOTED(s) DEV_QUOTED_HELPER(s) #define DEV_QUOTED(s) DEV_QUOTED_HELPER(s)
#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
namespace dev namespace dev
{ {

6
libethcore/EthashAux.cpp

@ -40,8 +40,6 @@ using namespace chrono;
using namespace dev; using namespace dev;
using namespace eth; using namespace eth;
#define ETH_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
EthashAux* dev::eth::EthashAux::s_this = nullptr; EthashAux* dev::eth::EthashAux::s_this = nullptr;
EthashAux::~EthashAux() EthashAux::~EthashAux()
@ -171,8 +169,8 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest, bool
boost::filesystem::rename(oldMemoFile, memoFile); boost::filesystem::rename(oldMemoFile, memoFile);
} }
ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); DEV_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile));
ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); DEV_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info"));
ethash_params p = params(_seedHash); ethash_params p = params(_seedHash);
assert(!_dest || _dest.size() >= p.full_size); // must be big enough. assert(!_dest || _dest.size() >= p.full_size); // must be big enough.

7
libethereum/ClientBase.cpp

@ -48,8 +48,11 @@ State ClientBase::asOf(BlockNumber _h) const
void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{ {
prepareForTransaction(); prepareForTransaction();
u256 n = postMine().transactionsFrom(toAddress(_secret)); auto a = toAddress(_secret);
u256 n = postMine().transactionsFrom(a);
cdebug << "submitTx: " << a << "postMine=" << n << "; tq=" << m_tq.maxNonce(a);
n = max<u256>(n, m_tq.maxNonce(a));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
m_tq.import(t.rlp()); m_tq.import(t.rlp());

11
libethereum/Transaction.h

@ -221,19 +221,14 @@ using Transactions = std::vector<Transaction>;
/// Simple human-readable stream-shift operator. /// Simple human-readable stream-shift operator.
inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t)
{ {
_out << "{"; _out << _t.sha3().abridged() << "{";
if (_t.receiveAddress()) if (_t.receiveAddress())
_out << _t.receiveAddress().abridged(); _out << _t.receiveAddress().abridged();
else else
_out << "[CREATE]"; _out << "[CREATE]";
_out << "/" << _t.nonce() << "$" << _t.value() << "+" << _t.gas() << "@" << _t.gasPrice(); _out << "/" << _t.data().size() << "$" << _t.value() << "+" << _t.gas() << "@" << _t.gasPrice();
try _out << "<-" << _t.safeSender().abridged() << " #" << _t.nonce() << "}";
{
_out << "<-" << _t.sender().abridged();
}
catch (...) {}
_out << " #" << _t.data().size() << "}";
return _out; return _out;
} }

49
libethereum/TransactionQueue.cpp

@ -53,7 +53,7 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb
UpgradeGuard ul(l); UpgradeGuard ul(l);
// If valid, append to blocks. // If valid, append to blocks.
m_current[h] = t; insertCurrent_WITH_LOCK(make_pair(h, t));
m_known.insert(h); m_known.insert(h);
if (_cb) if (_cb)
m_callbacks[h] = _cb; m_callbacks[h] = _cb;
@ -74,13 +74,54 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb
return ImportResult::Success; return ImportResult::Success;
} }
u256 TransactionQueue::maxNonce(Address const& _a) const
{
cdebug << "txQ::maxNonce" << _a;
ReadGuard l(m_lock);
u256 ret = 0;
auto r = m_senders.equal_range(_a);
for (auto it = r.first; it != r.second; ++it)
{
cdebug << it->first << "1+" << m_current.at(it->second).nonce();
DEV_IGNORE_EXCEPTIONS(ret = max(ret, m_current.at(it->second).nonce() + 1));
}
return ret;
}
void TransactionQueue::insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p)
{
cdebug << "txQ::insertCurrent" << _p.first << _p.second.sender() << _p.second.nonce();
m_senders.insert(make_pair(_p.second.sender(), _p.first));
m_current.insert(_p);
}
bool TransactionQueue::removeCurrent_WITH_LOCK(h256 const& _txHash)
{
cdebug << "txQ::removeCurrent" << _txHash;
if (m_current.count(_txHash))
{
auto r = m_senders.equal_range(m_current[_txHash].sender());
for (auto it = r.first; it != r.second; ++it)
if (it->second == _txHash)
{
cdebug << "=> sender" << it->first;
m_senders.erase(it);
break;
}
cdebug << "=> nonce" << m_current[_txHash].nonce();
m_current.erase(_txHash);
return true;
}
return false;
}
void TransactionQueue::setFuture(std::pair<h256, Transaction> const& _t) void TransactionQueue::setFuture(std::pair<h256, Transaction> const& _t)
{ {
WriteGuard l(m_lock); WriteGuard l(m_lock);
if (m_current.count(_t.first)) if (m_current.count(_t.first))
{ {
m_current.erase(_t.first);
m_unknown.insert(make_pair(_t.second.sender(), _t)); m_unknown.insert(make_pair(_t.second.sender(), _t));
m_current.erase(_t.first);
} }
} }
@ -104,9 +145,7 @@ void TransactionQueue::drop(h256 const& _txHash)
m_dropped.insert(_txHash); m_dropped.insert(_txHash);
m_known.erase(_txHash); m_known.erase(_txHash);
if (m_current.count(_txHash)) if (!removeCurrent_WITH_LOCK(_txHash))
m_current.erase(_txHash);
else
{ {
for (auto i = m_unknown.begin(); i != m_unknown.end(); ++i) for (auto i = m_unknown.begin(); i != m_unknown.end(); ++i)
if (i->second.first == _txHash) if (i->second.first == _txHash)

7
libethereum/TransactionQueue.h

@ -56,6 +56,7 @@ public:
std::map<h256, Transaction> transactions() const { ReadGuard l(m_lock); return m_current; } std::map<h256, Transaction> transactions() const { ReadGuard l(m_lock); return m_current; }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); } std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); }
u256 maxNonce(Address const& _a) const;
void setFuture(std::pair<h256, Transaction> const& _t); void setFuture(std::pair<h256, Transaction> const& _t);
void noteGood(std::pair<h256, Transaction> const& _t); void noteGood(std::pair<h256, Transaction> const& _t);
@ -64,12 +65,16 @@ public:
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); } template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }
private: private:
mutable SharedMutex m_lock; ///< General lock. void insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p);
bool removeCurrent_WITH_LOCK(h256 const& _txHash);
mutable SharedMutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets. std::set<h256> m_known; ///< Hashes of transactions in both sets.
std::map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx. std::map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. std::multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
std::map<h256, std::function<void(ImportResult)>> m_callbacks; ///< Called once. std::map<h256, std::function<void(ImportResult)>> m_callbacks; ///< Called once.
std::set<h256> m_dropped; ///< Transactions that have previously been dropped. std::set<h256> m_dropped; ///< Transactions that have previously been dropped.
std::multimap<Address, h256> m_senders; ///< Mapping from the sender address to the transaction hash; useful for determining the nonce of a given sender.
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
}; };

4
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -505,7 +505,7 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
if (!t.gasPrice) if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow. t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (!t.gas) if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
if (m_accounts->isRealAccount(t.from)) if (m_accounts->isRealAccount(t.from))
authenticate(t, false); authenticate(t, false);
@ -534,7 +534,7 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json)
if (!t.gasPrice) if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow. t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (!t.gas) if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
if (m_accounts->isRealAccount(t.from)) if (m_accounts->isRealAccount(t.from))
authenticate(t, false); authenticate(t, false);

Loading…
Cancel
Save