diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 9c4576919..e3fcfc8d7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -30,18 +30,6 @@ using namespace std; using namespace eth; -void MessageFilter::fillStream(RLPStream& _s) const -{ - _s.appendList(8) << m_from << m_to << m_stateAltered << m_altered << m_earliest << m_latest << m_max << m_skip; -} - -h256 MessageFilter::sha3() const -{ - RLPStream s; - fillStream(s); - return eth::sha3(s.out()); -} - VersionChecker::VersionChecker(string const& _dbPath): m_path(_dbPath.size() ? _dbPath : Defaults::dbPath()) { @@ -425,6 +413,8 @@ void Client::workNet() void Client::work() { + // TODO: Use condition variable rather than polling. + cworkin << "WORK"; h256Set changeds; @@ -588,117 +578,6 @@ bytes Client::codeAt(Address _a, int _block) const return asOf(_block).code(_a); } -bool MessageFilter::matches(h256 _bloom) const -{ - auto have = [=](Address const& a) { return _bloom.contains(a.bloom()); }; - if (m_from.size()) - { - for (auto i: m_from) - if (have(i)) - goto OK1; - return false; - } - OK1: - if (m_to.size()) - { - for (auto i: m_to) - if (have(i)) - goto OK2; - return false; - } - OK2: - if (m_stateAltered.size() || m_altered.size()) - { - for (auto i: m_altered) - if (have(i)) - goto OK3; - for (auto i: m_stateAltered) - if (have(i.first) && _bloom.contains(h256(i.second).bloom())) - goto OK3; - return false; - } - OK3: - return true; -} - -bool MessageFilter::matches(State const& _s, unsigned _i) const -{ - h256 b = _s.changesFromPending(_i).bloom(); - if (!matches(b)) - return false; - - Transaction t = _s.pending()[_i]; - if (!m_to.empty() && !m_to.count(t.receiveAddress)) - return false; - if (!m_from.empty() && !m_from.count(t.sender())) - return false; - if (m_stateAltered.empty() && m_altered.empty()) - return true; - StateDiff d = _s.pendingDiff(_i); - if (!m_altered.empty()) - { - for (auto const& s: m_altered) - if (d.accounts.count(s)) - return true; - return false; - } - if (!m_stateAltered.empty()) - { - for (auto const& s: m_stateAltered) - if (d.accounts.count(s.first) && d.accounts.at(s.first).storage.count(s.second)) - return true; - return false; - } - return true; -} - -PastMessages MessageFilter::matches(Manifest const& _m, unsigned _i) const -{ - PastMessages ret; - matches(_m, vector(1, _i), _m.from, PastMessages(), ret); - return ret; -} - -bool MessageFilter::matches(Manifest const& _m, vector _p, Address _o, PastMessages _limbo, PastMessages& o_ret) const -{ - bool ret; - - if ((m_from.empty() || m_from.count(_m.from)) && (m_to.empty() || m_to.count(_m.to))) - _limbo.push_back(PastMessage(_m, _p, _o)); - - // Handle limbos, by checking against all addresses in alteration. - bool alters = m_altered.empty() && m_stateAltered.empty(); - alters = alters || m_altered.count(_m.from) || m_altered.count(_m.to); - - if (!alters) - for (auto const& i: _m.altered) - if (m_altered.count(_m.to) || m_stateAltered.count(make_pair(_m.to, i))) - { - alters = true; - break; - } - // If we do alter stuff, - if (alters) - { - o_ret += _limbo; - _limbo.clear(); - ret = true; - } - - _p.push_back(0); - for (auto const& m: _m.internal) - { - if (matches(m, _p, _o, _limbo, o_ret)) - { - _limbo.clear(); - ret = true; - } - _p.back()++; - } - - return ret; -} - PastMessages Client::messages(MessageFilter const& _f) const { PastMessages ret; diff --git a/libethereum/Client.h b/libethereum/Client.h index 66601c656..453a03210 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -35,6 +35,8 @@ #include "TransactionQueue.h" #include "State.h" #include "PeerNetwork.h" +#include "PastMessage.h" +#include "MessageFilter.h" #include "Miner.h" namespace eth @@ -64,66 +66,6 @@ private: static const int GenesisBlock = INT_MIN; -struct PastMessage -{ - PastMessage(Manifest const& _m, std::vector _path, Address _o): to(_m.to), from(_m.from), value(_m.value), input(_m.input), output(_m.output), path(_path), origin(_o) {} - - PastMessage& polish(h256 _b, u256 _ts, unsigned _n, Address _coinbase) { block = _b; timestamp = _ts; number = _n; coinbase = _coinbase; return *this; } - - Address to; ///< The receiving address of the transaction. Address() in the case of a creation. - Address from; ///< The receiving address of the transaction. Address() in the case of a creation. - u256 value; ///< The value associated with the call. - bytes input; ///< The data associated with the message, or the initialiser if it's a creation transaction. - bytes output; ///< The data returned by the message, or the body code if it's a creation transaction. - - std::vector path; ///< Call path into the block transaction. size() is always > 0. First item is the transaction index in the block. - Address origin; ///< Originating sender of the transaction. - Address coinbase; ///< Block coinbase. - h256 block; ///< Block hash. - u256 timestamp; ///< Block timestamp. - unsigned number; ///< Block number. -}; - -typedef std::vector PastMessages; - -class MessageFilter -{ -public: - MessageFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {} - - void fillStream(RLPStream& _s) const; - h256 sha3() const; - - int earliest() const { return m_earliest; } - int latest() const { return m_latest; } - unsigned max() const { return m_max; } - unsigned skip() const { return m_skip; } - bool matches(h256 _bloom) const; - bool matches(State const& _s, unsigned _i) const; - PastMessages matches(Manifest const& _m, unsigned _i) const; - - MessageFilter from(Address _a) { m_from.insert(_a); return *this; } - MessageFilter to(Address _a) { m_to.insert(_a); return *this; } - MessageFilter altered(Address _a, u256 _l) { m_stateAltered.insert(std::make_pair(_a, _l)); return *this; } - MessageFilter altered(Address _a) { m_altered.insert(_a); return *this; } - MessageFilter withMax(unsigned _m) { m_max = _m; return *this; } - MessageFilter withSkip(unsigned _m) { m_skip = _m; return *this; } - MessageFilter withEarliest(int _e) { m_earliest = _e; return *this; } - MessageFilter withLatest(int _e) { m_latest = _e; return *this; } - -private: - bool matches(Manifest const& _m, std::vector _p, Address _o, PastMessages _limbo, PastMessages& o_ret) const; - - std::set
m_from; - std::set
m_to; - std::set> m_stateAltered; - std::set
m_altered; - int m_earliest = 0; - int m_latest = -1; - unsigned m_max; - unsigned m_skip; -}; - struct InstalledFilter { InstalledFilter(MessageFilter const& _f): filter(_f) {} diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp new file mode 100644 index 000000000..786440775 --- /dev/null +++ b/libethereum/MessageFilter.cpp @@ -0,0 +1,150 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file MessageFilter.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "MessageFilter.h" + +#include +#include "State.h" +using namespace std; +using namespace eth; + +void MessageFilter::fillStream(RLPStream& _s) const +{ + _s.appendList(8) << m_from << m_to << m_stateAltered << m_altered << m_earliest << m_latest << m_max << m_skip; +} + +h256 MessageFilter::sha3() const +{ + RLPStream s; + fillStream(s); + return eth::sha3(s.out()); +} + +bool MessageFilter::matches(h256 _bloom) const +{ + auto have = [=](Address const& a) { return _bloom.contains(a.bloom()); }; + if (m_from.size()) + { + for (auto i: m_from) + if (have(i)) + goto OK1; + return false; + } + OK1: + if (m_to.size()) + { + for (auto i: m_to) + if (have(i)) + goto OK2; + return false; + } + OK2: + if (m_stateAltered.size() || m_altered.size()) + { + for (auto i: m_altered) + if (have(i)) + goto OK3; + for (auto i: m_stateAltered) + if (have(i.first) && _bloom.contains(h256(i.second).bloom())) + goto OK3; + return false; + } + OK3: + return true; +} + +bool MessageFilter::matches(State const& _s, unsigned _i) const +{ + h256 b = _s.changesFromPending(_i).bloom(); + if (!matches(b)) + return false; + + Transaction t = _s.pending()[_i]; + if (!m_to.empty() && !m_to.count(t.receiveAddress)) + return false; + if (!m_from.empty() && !m_from.count(t.sender())) + return false; + if (m_stateAltered.empty() && m_altered.empty()) + return true; + StateDiff d = _s.pendingDiff(_i); + if (!m_altered.empty()) + { + for (auto const& s: m_altered) + if (d.accounts.count(s)) + return true; + return false; + } + if (!m_stateAltered.empty()) + { + for (auto const& s: m_stateAltered) + if (d.accounts.count(s.first) && d.accounts.at(s.first).storage.count(s.second)) + return true; + return false; + } + return true; +} + +PastMessages MessageFilter::matches(Manifest const& _m, unsigned _i) const +{ + PastMessages ret; + matches(_m, vector(1, _i), _m.from, PastMessages(), ret); + return ret; +} + +bool MessageFilter::matches(Manifest const& _m, vector _p, Address _o, PastMessages _limbo, PastMessages& o_ret) const +{ + bool ret; + + if ((m_from.empty() || m_from.count(_m.from)) && (m_to.empty() || m_to.count(_m.to))) + _limbo.push_back(PastMessage(_m, _p, _o)); + + // Handle limbos, by checking against all addresses in alteration. + bool alters = m_altered.empty() && m_stateAltered.empty(); + alters = alters || m_altered.count(_m.from) || m_altered.count(_m.to); + + if (!alters) + for (auto const& i: _m.altered) + if (m_altered.count(_m.to) || m_stateAltered.count(make_pair(_m.to, i))) + { + alters = true; + break; + } + // If we do alter stuff, + if (alters) + { + o_ret += _limbo; + _limbo.clear(); + ret = true; + } + + _p.push_back(0); + for (auto const& m: _m.internal) + { + if (matches(m, _p, _o, _limbo, o_ret)) + { + _limbo.clear(); + ret = true; + } + _p.back()++; + } + + return ret; +} diff --git a/libethereum/MessageFilter.h b/libethereum/MessageFilter.h new file mode 100644 index 000000000..55d40d270 --- /dev/null +++ b/libethereum/MessageFilter.h @@ -0,0 +1,73 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file MessageFilter.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include "PastMessage.h" + +namespace eth +{ + +class Manifest; +class State; + +class MessageFilter +{ +public: + MessageFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {} + + void fillStream(RLPStream& _s) const; + h256 sha3() const; + + int earliest() const { return m_earliest; } + int latest() const { return m_latest; } + unsigned max() const { return m_max; } + unsigned skip() const { return m_skip; } + bool matches(h256 _bloom) const; + bool matches(State const& _s, unsigned _i) const; + PastMessages matches(Manifest const& _m, unsigned _i) const; + + MessageFilter from(Address _a) { m_from.insert(_a); return *this; } + MessageFilter to(Address _a) { m_to.insert(_a); return *this; } + MessageFilter altered(Address _a, u256 _l) { m_stateAltered.insert(std::make_pair(_a, _l)); return *this; } + MessageFilter altered(Address _a) { m_altered.insert(_a); return *this; } + MessageFilter withMax(unsigned _m) { m_max = _m; return *this; } + MessageFilter withSkip(unsigned _m) { m_skip = _m; return *this; } + MessageFilter withEarliest(int _e) { m_earliest = _e; return *this; } + MessageFilter withLatest(int _e) { m_latest = _e; return *this; } + +private: + bool matches(Manifest const& _m, std::vector _p, Address _o, PastMessages _limbo, PastMessages& o_ret) const; + + std::set
m_from; + std::set
m_to; + std::set> m_stateAltered; + std::set
m_altered; + int m_earliest = 0; + int m_latest = -1; + unsigned m_max; + unsigned m_skip; +}; + +} diff --git a/libethereum/PastMessage.cpp b/libethereum/PastMessage.cpp new file mode 100644 index 000000000..852d4a4bd --- /dev/null +++ b/libethereum/PastMessage.cpp @@ -0,0 +1,24 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file PastMessage.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "PastMessage.h" +using namespace std; +using namespace eth; diff --git a/libethereum/PastMessage.h b/libethereum/PastMessage.h new file mode 100644 index 000000000..789ce350a --- /dev/null +++ b/libethereum/PastMessage.h @@ -0,0 +1,53 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file PastMessage.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include "Manifest.h" + +namespace eth +{ + +struct PastMessage +{ + PastMessage(Manifest const& _m, std::vector _path, Address _o): to(_m.to), from(_m.from), value(_m.value), input(_m.input), output(_m.output), path(_path), origin(_o) {} + + PastMessage& polish(h256 _b, u256 _ts, unsigned _n, Address _coinbase) { block = _b; timestamp = _ts; number = _n; coinbase = _coinbase; return *this; } + + Address to; ///< The receiving address of the transaction. Address() in the case of a creation. + Address from; ///< The receiving address of the transaction. Address() in the case of a creation. + u256 value; ///< The value associated with the call. + bytes input; ///< The data associated with the message, or the initialiser if it's a creation transaction. + bytes output; ///< The data returned by the message, or the body code if it's a creation transaction. + + std::vector path; ///< Call path into the block transaction. size() is always > 0. First item is the transaction index in the block. + Address origin; ///< Originating sender of the transaction. + Address coinbase; ///< Block coinbase. + h256 block; ///< Block hash. + u256 timestamp; ///< Block timestamp. + unsigned number; ///< Block number. +}; + +typedef std::vector PastMessages; + +}