diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 810fea580..b3cef47e7 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -126,6 +126,7 @@ Main::Main(QWidget *parent) :
cerr << "Block RLP: " << RLP(BlockChain::createGenesisBlock()) << endl;
cerr << "Block Hex: " << toHex(BlockChain::createGenesisBlock()) << endl;
cerr << "Network protocol version: " << eth::c_protocolVersion << endl;
+ cerr << "Client database version: " << eth::c_databaseVersion << endl;
ui->configDock->close();
on_verbosity_valueChanged();
@@ -514,7 +515,7 @@ void Main::updateBlockCount()
{
auto d = m_client->blockChain().details();
auto diff = BlockInfo(m_client->blockChain().block()).difficulty;
- ui->blockCount->setText(QString("#%1 @%3 T%2 N%4").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(eth::c_protocolVersion));
+ ui->blockCount->setText(QString("#%1 @%3 T%2 N%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(eth::c_protocolVersion).arg(eth::c_databaseVersion));
}
void Main::on_blockChainFilter_textChanged()
@@ -883,6 +884,7 @@ void Main::on_blocks_currentItemChanged()
s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress;
s << "
Nonce: " << info.nonce << "";
s << "
Parent: " << info.parentHash << "";
+ s << "
Bloom: " << details.bloom << "";
s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "";
s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "";
s << "
Pre: " << BlockInfo(m_client->blockChain().block(info.parentHash)).stateRoot << "";
diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp
index 45f4e70bc..e88de28e1 100644
--- a/libethcore/CommonEth.cpp
+++ b/libethcore/CommonEth.cpp
@@ -30,6 +30,7 @@ using namespace eth;
//#define ETH_ADDRESS_DEBUG 1
const unsigned eth::c_protocolVersion = 23;
+const unsigned eth::c_databaseVersion = 1;
static const vector> g_units =
{
diff --git a/libethcore/CommonEth.h b/libethcore/CommonEth.h
index 6b28261f1..d336165cb 100644
--- a/libethcore/CommonEth.h
+++ b/libethcore/CommonEth.h
@@ -32,6 +32,9 @@ namespace eth
/// Current protocol version.
extern const unsigned c_protocolVersion;
+/// Current database version.
+extern const unsigned c_databaseVersion;
+
/// A secret key: 32 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Secret = h256;
diff --git a/libethential/Common.cpp b/libethential/Common.cpp
index 48202250d..50ce71a40 100644
--- a/libethential/Common.cpp
+++ b/libethential/Common.cpp
@@ -27,6 +27,6 @@ using namespace eth;
namespace eth
{
-char const* EthVersion = "0.5.16";
+char const* EthVersion = "0.6.0";
}
diff --git a/libethential/CommonData.h b/libethential/CommonData.h
index ac9541a0b..6840194fc 100644
--- a/libethential/CommonData.h
+++ b/libethential/CommonData.h
@@ -204,4 +204,23 @@ inline std::vector<_T> operator+(std::vector
+inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b)
+{
+ _a.reserve(_a.size() + _b.size());
+ for (auto& i: _b)
+ _a.push_back(i);
+ return _a;
+
+}
+
+/// Concatenate two vectors of elements. _T must be POD.
+template
+inline std::vector<_T> operator+(std::vector::value, _T>::type> const& _a, std::vector<_T> const& _b)
+{
+ std::vector<_T> ret(_a);
+ return ret += _b;
+}
+
}
diff --git a/libethential/FixedHash.h b/libethential/FixedHash.h
index 55d8a5cc8..f792e378d 100644
--- a/libethential/FixedHash.h
+++ b/libethential/FixedHash.h
@@ -50,9 +50,15 @@ public:
/// Method to convert from a string.
enum ConstructFromStringType { FromHex, FromBinary };
+ /// Method to convert from a string.
+ enum ConstructFromHashType { AlignLeft, AlignRight };
+
/// Construct an empty hash.
FixedHash() { m_data.fill(0); }
+ /// Construct from another hash, filling with zeroes or cropping as necessary.
+ template FixedHash(FixedHash const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; }
+
/// Convert from the corresponding arithmetic type.
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
@@ -85,6 +91,9 @@ public:
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; }
+ /// @returns true if all bytes in @a _c are set in this object.
+ bool contains(FixedHash const& _c) const { return (*this & _c) == _c; }
+
/// @returns a particular byte from the hash.
byte& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash.
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index 8b09f5fae..660bf3498 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -41,7 +41,7 @@ namespace eth
std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc)
{
string cmp = toBigEndianString(_bc.m_lastBlockHash);
- auto it = _bc.m_detailsDB->NewIterator(_bc.m_readOptions);
+ auto it = _bc.m_extrasDB->NewIterator(_bc.m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().ToString() != "best")
{
@@ -59,11 +59,12 @@ BlockDetails::BlockDetails(RLP const& _r)
totalDifficulty = _r[1].toInt();
parent = _r[2].toHash();
children = _r[3].toVector();
+ bloom = _r[4].toHash();
}
bytes BlockDetails::rlp() const
{
- return rlpList(number, totalDifficulty, parent, children);
+ return rlpList(number, totalDifficulty, parent, children, bloom);
}
std::map const& eth::genesisState()
@@ -123,8 +124,8 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
o.create_if_missing = true;
auto s = ldb::DB::Open(o, _path + "/blocks", &m_db);
assert(m_db);
- s = ldb::DB::Open(o, _path + "/details", &m_detailsDB);
- assert(m_detailsDB);
+ s = ldb::DB::Open(o, _path + "/details", &m_extrasDB);
+ assert(m_extrasDB);
// Initialise with the genesis as the last block on the longest chain.
m_genesisHash = BlockChain::genesis().hash;
@@ -133,16 +134,16 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
if (!details(m_genesisHash))
{
// Insert details of genesis block.
- m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {});
+ m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {}, h256());
auto r = m_details[m_genesisHash].rlp();
- m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&m_genesisHash, 32), (ldb::Slice)eth::ref(r));
+ m_extrasDB->Put(m_writeOptions, ldb::Slice((char const*)&m_genesisHash, 32), (ldb::Slice)eth::ref(r));
}
checkConsistency();
// TODO: Implement ability to rebuild details map from DB.
std::string l;
- m_detailsDB->Get(m_readOptions, ldb::Slice("best"), &l);
+ m_extrasDB->Get(m_readOptions, ldb::Slice("best"), &l);
m_lastBlockHash = l.empty() ? m_genesisHash : *(h256*)l.data();
cnote << "Opened blockchain DB. Latest: " << m_lastBlockHash;
@@ -151,7 +152,7 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
BlockChain::~BlockChain()
{
cnote << "Closing blockchain DB";
- delete m_detailsDB;
+ delete m_extrasDB;
delete m_db;
}
@@ -181,6 +182,19 @@ bool BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB)
#endif
}
+inline ldb::Slice toSlice(h256 _h, unsigned _sub = 0)
+{
+#if ALL_COMPILERS_ARE_CPP11_COMPLIANT
+ static thread_local h256 h = _h ^ h256(u256(_sub));
+ return ldb::Slice((char const*)&h, 32);
+#else
+ static boost::thread_specific_ptr t_h;
+ if (!t_h.get())
+ t_h.reset(new h256);
+ *t_h = _h ^ h256(u256(_sub));
+ return ldb::Slice((char const*)t_h.get(), 32);
+#endif
+}
void BlockChain::import(bytes const& _block, OverlayDB const& _db)
{
@@ -238,6 +252,14 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db)
// Get total difficulty increase and update state, checking it.
State s(bi.coinbaseAddress, _db);
auto tdIncrease = s.enactOn(&_block, bi, *this);
+ auto b = s.bloom();
+ BlockBlooms bb;
+ BlockTraces bt;
+ for (unsigned i = 0; i < s.pending().size(); ++i)
+ {
+ bt.traces.push_back(s.changesFromPending(i));
+ bb.blooms.push_back(s.changesFromPending(i).bloom());
+ }
s.cleanup(true);
td = pd.totalDifficulty + tdIncrease;
@@ -247,13 +269,17 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db)
// All ok - insert into DB
{
lock_guard l(m_lock);
- m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {});
+ m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {}, b);
m_details[bi.parentHash].children.push_back(newHash);
+ m_blooms[newHash] = bb;
+ m_traces[newHash] = bt;
}
- m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)eth::ref(m_details[newHash].rlp()));
- m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&bi.parentHash, 32), (ldb::Slice)eth::ref(m_details[bi.parentHash].rlp()));
- m_db->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)ref(_block));
+ m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)eth::ref(m_details[newHash].rlp()));
+ m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)eth::ref(m_details[bi.parentHash].rlp()));
+ m_extrasDB->Put(m_writeOptions, toSlice(newHash, 1), (ldb::Slice)eth::ref(m_blooms[newHash].rlp()));
+ m_extrasDB->Put(m_writeOptions, toSlice(newHash, 2), (ldb::Slice)eth::ref(m_traces[newHash].rlp()));
+ m_db->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block));
#if ETH_PARANOIA
checkConsistency();
@@ -273,7 +299,7 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db)
if (td > details(m_lastBlockHash).totalDifficulty)
{
m_lastBlockHash = newHash;
- m_detailsDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
+ m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
clog(BlockChainNote) << " Imported and best. Has" << (details(bi.parentHash).children.size() - 1) << "siblings.";
}
else
@@ -286,7 +312,7 @@ void BlockChain::checkConsistency()
{
lock_guard l(m_lock);
m_details.clear();
- ldb::Iterator* it = m_detailsDB->NewIterator(m_readOptions);
+ ldb::Iterator* it = m_db->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().size() == 32)
{
@@ -319,6 +345,10 @@ bytes BlockChain::block(h256 _hash) const
m_cache[_hash].resize(d.size());
memcpy(m_cache[_hash].data(), d.data(), d.size());
+
+ if (!d.size())
+ cwarn << "Couldn't find requested block:" << _hash;
+
return m_cache[_hash];
}
@@ -345,7 +375,7 @@ BlockDetails BlockChain::details(h256 _h) const
return it->second;
std::string s;
- m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s);
+ m_extrasDB->Get(m_readOptions, toSlice(_h), &s);
if (s.empty())
{
// cout << "Not found in DB: " << _h << endl;
@@ -357,3 +387,47 @@ BlockDetails BlockChain::details(h256 _h) const
}
return it->second;
}
+
+BlockBlooms BlockChain::blooms(h256 _h) const
+{
+ lock_guard l(m_lock);
+
+ BlockBloomsHash::const_iterator it = m_blooms.find(_h);
+ if (it != m_blooms.end())
+ return it->second;
+
+ std::string s;
+ m_extrasDB->Get(m_readOptions, toSlice(_h, 1), &s);
+ if (s.empty())
+ {
+// cout << "Not found in DB: " << _h << endl;
+ return NullBlockBlooms;
+ }
+ {
+ bool ok;
+ tie(it, ok) = m_blooms.insert(std::make_pair(_h, BlockBlooms(RLP(s))));
+ }
+ return it->second;
+}
+
+BlockTraces BlockChain::traces(h256 _h) const
+{
+ lock_guard l(m_lock);
+
+ BlockTracesHash::const_iterator it = m_traces.find(_h);
+ if (it != m_traces.end())
+ return it->second;
+
+ std::string s;
+ m_extrasDB->Get(m_readOptions, toSlice(_h, 2), &s);
+ if (s.empty())
+ {
+// cout << "Not found in DB: " << _h << endl;
+ return NullBlockTraces;
+ }
+ {
+ bool ok;
+ tie(it, ok) = m_traces.insert(std::make_pair(_h, BlockTraces(RLP(s))));
+ }
+ return it->second;
+}
diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h
index ffab54ddd..2eeda53c0 100644
--- a/libethereum/BlockChain.h
+++ b/libethereum/BlockChain.h
@@ -25,6 +25,7 @@
#include
#include
#include
+#include "Manifest.h"
#include "AddressState.h"
namespace ldb = leveldb;
@@ -37,7 +38,7 @@ class RLPStream;
struct BlockDetails
{
BlockDetails(): number(0), totalDifficulty(0) {}
- BlockDetails(uint _n, u256 _tD, h256 _p, h256s _c): number(_n), totalDifficulty(_tD), parent(_p), children(_c) {}
+ BlockDetails(uint _n, u256 _tD, h256 _p, h256s _c, h256 _bloom): number(_n), totalDifficulty(_tD), parent(_p), children(_c), bloom(_bloom) {}
BlockDetails(RLP const& _r);
bytes rlp() const;
@@ -48,13 +49,36 @@ struct BlockDetails
u256 totalDifficulty;
h256 parent;
h256s children;
- // TODO: add trace bloom
+ h256 bloom;
};
-// TODO: DB for full traces.
+
+struct BlockBlooms
+{
+ BlockBlooms() {}
+ BlockBlooms(RLP const& _r) { blooms = _r.toVector(); }
+ bytes rlp() const { RLPStream s; s << blooms; return s.out(); }
+
+ h256s blooms;
+};
+
+struct BlockTraces
+{
+ BlockTraces() {}
+ BlockTraces(RLP const& _r) { for (auto const& i: _r) traces.emplace_back(i.data()); }
+ bytes rlp() const { RLPStream s(traces.size()); for (auto const& i: traces) i.streamOut(s); return s.out(); }
+
+ Manifests traces;
+};
+
typedef std::map BlockDetailsHash;
+typedef std::map BlockBloomsHash;
+typedef std::map BlockTracesHash;
static const BlockDetails NullBlockDetails;
+static const BlockBlooms NullBlockBlooms;
+static const BlockTraces NullBlockTraces;
+
static const h256s NullH256s;
class State;
@@ -92,10 +116,18 @@ public:
/// Import block into disk-backed DB
void import(bytes const& _block, OverlayDB const& _stateDB);
- /// Get the number of the last block of the longest chain.
+ /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 _hash) const;
BlockDetails details() const { return details(currentHash()); }
+ /// Get the transactions' bloom filters of a block (or the most recent mined if none given). Thread-safe.
+ BlockBlooms blooms(h256 _hash) const;
+ BlockBlooms blooms() const { return blooms(currentHash()); }
+
+ /// Get the transactions' trace manifests of a block (or the most recent mined if none given). Thread-safe.
+ BlockTraces traces(h256 _hash) const;
+ BlockTraces traces() const { return traces(currentHash()); }
+
/// Get a given block (RLP format). Thread-safe.
bytes block(h256 _hash) const;
bytes block() const { return block(currentHash()); }
@@ -124,6 +156,9 @@ private:
/// Get fully populated from disk DB.
mutable BlockDetailsHash m_details;
+ mutable BlockBloomsHash m_blooms;
+ mutable BlockTracesHash m_traces;
+
mutable std::map m_cache;
mutable std::recursive_mutex m_lock;
@@ -132,7 +167,7 @@ private:
std::vector> m_interestQueue;
ldb::DB* m_db;
- ldb::DB* m_detailsDB;
+ ldb::DB* m_extrasDB;
/// Hash of the last (valid) block on the longest chain.
h256 m_lastBlockHash;
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 2faa4d425..c09704e39 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -30,11 +30,10 @@
using namespace std;
using namespace eth;
-VersionChecker::VersionChecker(string const& _dbPath, unsigned _protocolVersion):
- m_path(_dbPath.size() ? _dbPath : Defaults::dbPath()),
- m_protocolVersion(_protocolVersion)
+VersionChecker::VersionChecker(string const& _dbPath):
+ m_path(_dbPath.size() ? _dbPath : Defaults::dbPath())
{
- m_ok = RLP(contents(m_path + "/protocol")).toInt(RLP::LaisezFaire) == _protocolVersion;
+ m_ok = RLP(contents(m_path + "/protocol")).toInt(RLP::LaisezFaire) == c_protocolVersion && RLP(contents(m_path + "/database")).toInt(RLP::LaisezFaire) == c_databaseVersion;
}
void VersionChecker::setOk()
@@ -46,13 +45,14 @@ void VersionChecker::setOk()
boost::filesystem::create_directory(m_path);
}
catch (...) {}
- writeFile(m_path + "/protocol", rlp(m_protocolVersion));
+ writeFile(m_path + "/protocol", rlp(c_protocolVersion));
+ writeFile(m_path + "/database", rlp(c_databaseVersion));
}
}
Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath, bool _forceClean):
m_clientVersion(_clientVersion),
- m_vc(_dbPath, PeerServer::protocolVersion()),
+ m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(_us, m_stateDB),
@@ -92,6 +92,7 @@ Client::~Client()
void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHost, unsigned short _port, NodeMode _mode, unsigned _peers, string const& _publicIP, bool _upnp)
{
+ ClientGuard l(this);
if (m_net.get())
return;
try
@@ -112,16 +113,19 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
std::vector Client::peers()
{
+ ClientGuard l(this);
return m_net ? m_net->peers() : std::vector();
}
size_t Client::peerCount() const
{
+ ClientGuard l(this);
return m_net ? m_net->peerCount() : 0;
}
void Client::connect(std::string const& _seedHost, unsigned short _port)
{
+ ClientGuard l(this);
if (!m_net.get())
return;
m_net->connect(_seedHost, _port);
@@ -129,6 +133,7 @@ void Client::connect(std::string const& _seedHost, unsigned short _port)
void Client::stopNetwork()
{
+ ClientGuard l(this);
m_net.reset(nullptr);
}
@@ -335,8 +340,45 @@ bytes Client::codeAt(Address _a, int _block) const
return asOf(_block).code(_a);
}
+bool TransactionFilter::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 TransactionFilter::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;
@@ -362,11 +404,58 @@ bool TransactionFilter::matches(State const& _s, unsigned _i) const
return true;
}
-PastTransactions Client::transactions(TransactionFilter const& _f) const
+PastMessages TransactionFilter::matches(Manifest const& _m, unsigned _i) const
+{
+ PastMessages ret;
+ matches(_m, vector(1, _i), _m.from, PastMessages(), ret);
+ return ret;
+}
+
+bool TransactionFilter::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::transactions(TransactionFilter const& _f) const
{
ClientGuard l(this);
- PastTransactions ret;
+ PastMessages ret;
unsigned begin = numberOf(_f.latest());
unsigned end = min(begin, numberOf(_f.earliest()));
unsigned m = _f.max();
@@ -375,42 +464,98 @@ PastTransactions Client::transactions(TransactionFilter const& _f) const
// Handle pending transactions differently as they're not on the block chain.
if (_f.latest() == 0)
{
- for (unsigned i = m_postMine.pending().size(); i-- && ret.size() != m;)
+ for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
+ {
+ // Might have a transaction that contains a matching message.
+ Manifest const& ms = m_postMine.changesFromPending(i);
+ PastMessages pm = _f.matches(ms, i);
+ if (pm.size())
+ {
+ auto ts = time(0);
+ for (unsigned j = 0; j < pm.size() && ret.size() != m; ++j)
+ if (s)
+ s--;
+ else
+ // Have a transaction that contains a matching message.
+ ret.insert(ret.begin(), pm[j].polish(h256(), ts, 0));
+ }
+ }
+/* for (unsigned i = m_postMine.pending().size(); i-- && ret.size() != m;)
if (_f.matches(m_postMine, i))
{
if (s)
s--;
else
- ret.insert(ret.begin(), PastTransaction(m_postMine.pending()[i], h256(), i, time(0), 0));
- }
+ ret.insert(ret.begin(), PastMessage(m_postMine.pending()[i], h256(), i, time(0), 0));
+ }*/
// Early exit here since we can't rely on begin/end, being out of the blockchain as we are.
if (_f.earliest() == 0)
return ret;
}
+ unsigned skipped = 0;
+ unsigned falsePos = 0;
auto cn = m_bc.number();
auto h = m_bc.numberHash(begin);
- for (unsigned n = begin; ret.size() != m && n != end; n--, h = m_bc.details(h).parent)
+ unsigned n = begin;
+ for (; ret.size() != m && n != end; n--, h = m_bc.details(h).parent)
{
- try
+ auto d = m_bc.details(h);
+ int total = 0;
+ if (_f.matches(d.bloom))
{
- State st(m_stateDB, m_bc, h);
- for (unsigned i = st.pending().size(); i-- && ret.size() != m;)
- if (_f.matches(st, i))
+ // Might have a block that contains a transaction that contains a matching message.
+ auto bs = m_bc.blooms(h).blooms;
+ Manifests ms;
+ for (unsigned i = 0; i < bs.size(); ++i)
+ if (_f.matches(bs[i]))
{
- if (s)
- s--;
- else
- ret.insert(ret.begin(), PastTransaction(st.pending()[i], h, i, BlockInfo(m_bc.block(h)).timestamp, cn - n + 2));
+ // Might have a transaction that contains a matching message.
+ if (ms.empty())
+ ms = m_bc.traces(h).traces;
+ Manifest const& changes = ms[i];
+ PastMessages pm = _f.matches(changes, i);
+ if (pm.size())
+ {
+ total += pm.size();
+ auto ts = BlockInfo(m_bc.block(h)).timestamp;
+ for (unsigned j = 0; j < pm.size() && ret.size() != m; ++j)
+ if (s)
+ s--;
+ else
+ // Have a transaction that contains a matching message.
+ ret.insert(ret.begin(), pm[j].polish(h, ts, cn - n + 2));
+ }
}
+ if (!total)
+ falsePos++;
+/* try
+ {
+ State st(m_stateDB, m_bc, h);
+ unsigned os = s;
+ for (unsigned i = st.pending().size(); i-- && ret.size() != m;)
+ if (_f.matches(st, i))
+ {
+ if (s)
+ s--;
+ else
+ ret.insert(ret.begin(), PastMessage(st.pending()[i], h, i, BlockInfo(m_bc.block(h)).timestamp, cn - n + 2));
+ }
+ if (os - s == st.pending().size())
+ falsePos++;
+ }
+ catch (...)
+ {
+ // Gaa. bad state. not good at all. bury head in sand for now.
+ }
+*/
}
- catch (...)
- {
- // Gaa. bad state. not good at all. bury head in sand for now.
- }
+ else
+ skipped++;
if (n == end)
break;
}
+ cdebug << (begin - n) << "searched; " << skipped << "skipped; " << falsePos << "false +ves";
return ret;
}
diff --git a/libethereum/Client.h b/libethereum/Client.h
index cbfdcd6e5..387282935 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -66,7 +66,7 @@ enum ClientWorkState
class VersionChecker
{
public:
- VersionChecker(std::string const& _dbPath, unsigned _protocolVersion);
+ VersionChecker(std::string const& _dbPath);
void setOk();
bool ok() const { return m_ok; }
@@ -74,11 +74,31 @@ public:
private:
bool m_ok;
std::string m_path;
- unsigned m_protocolVersion;
};
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, int _a) { block = _b; timestamp = _ts; age = _a; 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.
+ h256 block; ///< Block hash.
+ u256 timestamp; ///< Block timestamp.
+ int age; ///< Transaction age.
+};
+
+typedef std::vector PastMessages;
+
class TransactionFilter
{
public:
@@ -88,7 +108,9 @@ public:
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;
TransactionFilter from(Address _a) { m_from.insert(_a); return *this; }
TransactionFilter to(Address _a) { m_to.insert(_a); return *this; }
@@ -100,6 +122,8 @@ public:
TransactionFilter 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;
@@ -110,17 +134,6 @@ private:
unsigned m_skip;
};
-struct PastTransaction: public Transaction
-{
- PastTransaction(Transaction const& _t, h256 _b, u256 _i, u256 _ts, int _age): Transaction(_t), block(_b), index(_i), timestamp(_ts), age(_age) {}
- h256 block;
- u256 index;
- u256 timestamp;
- int age;
-};
-
-typedef std::vector PastTransactions;
-
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@@ -192,7 +205,7 @@ public:
u256 countAt(Address _a, int _block = -1) const;
u256 stateAt(Address _a, u256 _l, int _block = -1) const;
bytes codeAt(Address _a, int _block = -1) const;
- PastTransactions transactions(TransactionFilter const& _f) const;
+ PastMessages transactions(TransactionFilter const& _f) const;
// Misc stuff:
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index fefcd55af..1fff722eb 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -98,6 +98,7 @@ bool Executive::setup(bytesConstRef _rlp)
{
m_ms->from = m_sender;
m_ms->to = m_t.receiveAddress;
+ m_ms->value = m_t.value;
m_ms->input = m_t.data;
}
diff --git a/libethereum/Executive.h b/libethereum/Executive.h
index 63528f47d..0d3a5288f 100644
--- a/libethereum/Executive.h
+++ b/libethereum/Executive.h
@@ -27,6 +27,7 @@
#include
#include
#include "Transaction.h"
+#include "Manifest.h"
namespace eth
{
@@ -35,26 +36,8 @@ class VM;
class ExtVM;
class State;
-struct Manifest;
-using Manifests = std::vector;
-
struct VMTraceChannel: public LogChannel { static const char* name() { return "EVM"; } static const int verbosity = 11; };
-/**
- * @brief A record of the state-interaction of a transaction/call/create.
- */
-struct Manifest
-{
- h256 bloom() const { h256 ret = from.bloom() | to.bloom(); for (auto const& i: internal) ret |= i.bloom(); for (auto const& i: altered) ret |= h256(i).bloom(); return ret; }
-
- Address from;
- Address to;
- u256s altered;
- bytes input;
- bytes output;
- Manifests internal;
-};
-
class Executive
{
public:
diff --git a/libethereum/Manifest.cpp b/libethereum/Manifest.cpp
new file mode 100644
index 000000000..d5d7e2df9
--- /dev/null
+++ b/libethereum/Manifest.cpp
@@ -0,0 +1,45 @@
+/*
+ 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 Manifest.cpp
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#include "Manifest.h"
+using namespace std;
+using namespace eth;
+
+Manifest::Manifest(bytesConstRef _r)
+{
+ RLP r(_r);
+ from = r[0].toHash();
+ to = r[1].toHash();
+ value = r[2].toInt();
+ altered = r[3].toVector();
+ input = r[4].toBytes();
+ output = r[5].toBytes();
+ for (auto const& i: r[6])
+ internal.emplace_back(i.data());
+}
+
+void Manifest::streamOut(RLPStream& _s) const
+{
+ _s.appendList(7) << from << to << value << altered << input << output;
+ _s.appendList(internal.size());
+ for (auto const& i: internal)
+ i.streamOut(_s);
+}
diff --git a/libethereum/Manifest.h b/libethereum/Manifest.h
new file mode 100644
index 000000000..94ecd1496
--- /dev/null
+++ b/libethereum/Manifest.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 Manifest.h
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#pragma once
+
+#include
+#include
+
+namespace eth
+{
+
+struct Manifest;
+using Manifests = std::vector;
+
+/**
+ * @brief A record of the state-interaction of a transaction/call/create.
+ */
+struct Manifest
+{
+ Manifest() {}
+ Manifest(bytesConstRef _r);
+ void streamOut(RLPStream& _s) const;
+
+ h256 bloom() const { h256 ret = from.bloom() | to.bloom(); for (auto const& i: internal) ret |= i.bloom(); for (auto const& i: altered) ret |= h256(i).bloom(); return ret; }
+
+ Address from;
+ Address to;
+ u256 value;
+ u256s altered;
+ bytes input;
+ bytes output;
+ Manifests internal;
+};
+
+}
diff --git a/libethereum/PeerServer.cpp b/libethereum/PeerServer.cpp
index 49d897bb4..275d9ace7 100644
--- a/libethereum/PeerServer.cpp
+++ b/libethereum/PeerServer.cpp
@@ -339,6 +339,17 @@ bool PeerServer::ensureInitialised(BlockChain& _bc, TransactionQueue& _tq)
return false;
}
+bool PeerServer::noteBlock(h256 _hash, bytesConstRef _data)
+{
+ if (!m_chain->details(_hash))
+ {
+ lock_guard l(m_incomingLock);
+ m_incomingBlocks.push_back(_data.toBytes());
+ return true;
+ }
+ return false;
+}
+
bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, OverlayDB& _o)
{
bool ret = ensureInitialised(_bc, _tq);
@@ -404,7 +415,7 @@ bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, OverlayDB& _o)
for (int accepted = 1, n = 0; accepted; ++n)
{
accepted = 0;
-
+ lock_guard l(m_incomingLock);
if (m_incomingBlocks.size())
for (auto it = prev(m_incomingBlocks.end());; --it)
{
diff --git a/libethereum/PeerServer.h b/libethereum/PeerServer.h
index ec67b8469..6e44d2ea4 100644
--- a/libethereum/PeerServer.h
+++ b/libethereum/PeerServer.h
@@ -21,6 +21,7 @@
#pragma once
+#include
#include