From ce55c017996cc27faee9b95dcc37c444e5f70e5b Mon Sep 17 00:00:00 2001 From: caktux Date: Tue, 22 Jul 2014 00:35:05 -0400 Subject: [PATCH 1/5] neth: use c.start() and fixes --- neth/main.cpp | 59 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/neth/main.cpp b/neth/main.cpp index 70107d604..3ac715db5 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -417,6 +417,7 @@ int main(int argc, char** argv) if (!clientName.empty()) clientName += "/"; Client c("NEthereum(++)/" + clientName + "v" + eth::EthVersion + "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath); + c.start(); cout << credits(); std::ostringstream ccout; @@ -853,14 +854,23 @@ int main(int argc, char** argv) string s = "# " + std::to_string(d.number) + ' ' + toString(h); // .abridged(); mvwaddnstr(blockswin, y++, x, s.c_str(), qwidth); - for (auto const& i: RLP(bc.block(h))[1]) + auto b = bc.block(h); + for (auto const& i: RLP(b)[1]) { Transaction t(i[0].data()); - string ss; - ss = t.receiveAddress ? - " " + toString(toHex(t.safeSender().asArray())) + " " + (st.addressHasCode(t.receiveAddress) ? '*' : '-') + "> " + toString(t.receiveAddress) + ": " + toString(formatBalance(t.value)) + " [" + toString((unsigned)t.nonce) + "]": - " " + toString(toHex(t.safeSender().asArray())) + " +> " + toString(right160(t.sha3())) + ": " + toString(formatBalance(t.value)) + " [" + toString((unsigned)t.nonce) + "]"; - mvwaddnstr(blockswin, y++, x, ss.c_str(), qwidth - 2); + auto s = t.receiveAddress ? + boost::format(" %1% %2%> %3%: %4% [%5%]") % + toString(t.safeSender()) % + (st.addressHasCode(t.receiveAddress) ? '*' : '-') % + toString(t.receiveAddress) % + toString(formatBalance(t.value)) % + toString((unsigned)t.nonce) : + boost::format(" %1% +> %2%: %3% [%4%]") % + toString(t.safeSender()) % + toString(right160(sha3(rlpList(t.safeSender(), t.nonce)))) % + toString(formatBalance(t.value)) % + toString((unsigned)t.nonce); + mvwaddnstr(blockswin, y++, x, s.str().c_str(), qwidth - 2); if (y > qheight - 2) break; } @@ -874,12 +884,20 @@ int main(int argc, char** argv) auto aps = c.pending(); for (auto const& t: aps) { - string ss; if (t.receiveAddress) - ss = toString(toHex(t.safeSender().asArray())) + " " + (st.addressHasCode(t.receiveAddress) ? '*' : '-') + "> " + toString(t.receiveAddress) + ": " + toString(formatBalance(t.value)) + " " + " [" + toString((unsigned)t.nonce) + "]"; + auto s = boost::format("%1% %2%> %3%: %4% [%5%]") % + toString(t.safeSender()) % + (st.addressHasCode(t.receiveAddress) ? '*' : '-') % + toString(t.receiveAddress) % + toString(formatBalance(t.value)) % + toString((unsigned)t.nonce); else - ss = toString(toHex(t.safeSender().asArray())) + " +> " + toString(right160(t.sha3())) + ": " + toString(formatBalance(t.value)) + "[" + toString((unsigned)t.nonce) + "]"; - mvwaddnstr(pendingwin, y++, x, ss.c_str(), qwidth); + auto s = boost::format("%1% +> %2%: %3% [%4%]") % + toString(t.safeSender()) % + toString(right160(sha3(rlpList(t.safeSender(), t.nonce)))) % + toString(formatBalance(t.value)) % + toString((unsigned)t.nonce); + mvwaddnstr(pendingwin, y++, x, s.c_str(), qwidth); if (y > qheight - 4) break; } @@ -893,18 +911,25 @@ int main(int argc, char** argv) { auto r = i.first; - string ss; - ss = toString(r) + pretty(r, st) + " : " + toString(formatBalance(i.second)) + " [" + toString((unsigned)st.transactionsFrom(i.first)) + "]"; - mvwaddnstr(addswin, y++, x, ss.c_str(), width / 2 - 4); - scrollok(addswin, true); - if (st.addressHasCode(r)) { - ss = toString(r) + " : " + toString(formatBalance(i.second)) + " [" + toString((unsigned)st.transactionsFrom(i.first)) + "]"; - mvwaddnstr(contractswin, cc++, x, ss.c_str(), qwidth); + auto s = boost::format("%1%%2% : %3% [%4%]") % + toString(r) % + pretty(r, st) % + toString(formatBalance(i.second)) % + toString((unsigned)st.transactionsFrom(i.first)); + mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth); if (cc > qheight - 2) break; } + else { + auto s = boost::format("%1%%2% : %3% [%4%]") % + toString(r) % + pretty(r, st) % + toString(formatBalance(i.second)) % + toString((unsigned)st.transactionsFrom(i.first)); + mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); + } if (y > height * 2 / 5 - 2) break; } From 09d5704aa0f217b9e61a21a982dfb442e477910a Mon Sep 17 00:00:00 2001 From: caktux Date: Tue, 22 Jul 2014 01:12:14 -0400 Subject: [PATCH 2/5] neth: fill addresses --- neth/main.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/neth/main.cpp b/neth/main.cpp index 3ac715db5..01199b7fc 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -898,7 +898,7 @@ int main(int argc, char** argv) toString(formatBalance(t.value)) % toString((unsigned)t.nonce); mvwaddnstr(pendingwin, y++, x, s.c_str(), qwidth); - if (y > qheight - 4) + if (y > height * 1 / 5 - 4) break; } @@ -922,16 +922,20 @@ int main(int argc, char** argv) if (cc > qheight - 2) break; } - else { + } + for (auto const& i: acs) + { + auto r = i.first; + if (!st.addressHasCode(r)) { auto s = boost::format("%1%%2% : %3% [%4%]") % toString(r) % pretty(r, st) % toString(formatBalance(i.second)) % toString((unsigned)st.transactionsFrom(i.first)); mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); + if (y > height * 3 / 5 - 4) + break; } - if (y > height * 2 / 5 - 2) - break; } // Peers From 0c5dbd7defd7f49982b0f901c0c7f5807751c277 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 22 Jul 2014 11:27:05 +0200 Subject: [PATCH 3/5] Bloom filters for blocks. --- alethzero/MainWin.cpp | 1 + libethential/FixedHash.h | 9 +++++ libethereum/BlockChain.cpp | 8 ++-- libethereum/BlockChain.h | 4 +- libethereum/Client.cpp | 80 ++++++++++++++++++++++++++++++------- libethereum/Client.h | 1 + libethereum/PeerServer.cpp | 13 +++++- libethereum/PeerServer.h | 6 +++ libethereum/PeerSession.cpp | 3 +- libethereum/State.cpp | 10 ++++- libethereum/State.h | 10 +---- libqethereum/QEthereum.cpp | 2 +- 12 files changed, 113 insertions(+), 34 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 810fea580..918a28916 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -883,6 +883,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/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..004b28454 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -59,11 +59,12 @@ BlockDetails::BlockDetails(RLP const& _r) totalDifficulty = _r[1].toInt(); parent = _r[2].toHash(); children = _r[3].toVector(); + bloom = _r[4].isNull() ? ~h256() : _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() @@ -133,7 +134,7 @@ 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)); } @@ -238,6 +239,7 @@ 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(); s.cleanup(true); td = pd.totalDifficulty + tdIncrease; @@ -247,7 +249,7 @@ 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); } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index ffab54ddd..025181396 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,7 +37,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,7 +48,7 @@ struct BlockDetails u256 totalDifficulty; h256 parent; h256s children; - // TODO: add trace bloom + h256 bloom; }; // TODO: DB for full traces. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 2faa4d425..f4f59530e 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -335,8 +335,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; @@ -388,29 +425,42 @@ PastTransactions Client::transactions(TransactionFilter const& _f) const 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 - { - State st(m_stateDB, m_bc, h); - for (unsigned i = st.pending().size(); i-- && ret.size() != m;) - if (_f.matches(st, i)) - { - if (s) - s--; - else - ret.insert(ret.begin(), PastTransaction(st.pending()[i], h, i, BlockInfo(m_bc.block(h)).timestamp, cn - n + 2)); - } - } - catch (...) + auto d = m_bc.details(h); + if (_f.matches(d.bloom)) { - // Gaa. bad state. not good at all. bury head in sand for now. + 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(), PastTransaction(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. + } } + 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..6908de228 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -88,6 +88,7 @@ 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; TransactionFilter from(Address _a) { m_from.insert(_a); return *this; } 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 #include #include @@ -85,6 +86,10 @@ public: void restorePeers(bytesConstRef _b); private: + /// Session wants to pass us a block that we might not have. + /// @returns true if we didn't have it. + bool noteBlock(h256 _hash, bytesConstRef _data); + void seal(bytes& _b); void populateAddresses(); void determinePublic(std::string const& _publicAddress, bool _upnp); @@ -116,6 +121,7 @@ private: std::vector m_incomingTransactions; std::vector m_incomingBlocks; + mutable std::recursive_mutex m_incomingLock; std::vector m_unknownParentBlocks; std::vector m_freePeers; std::map> m_incomingPeers; diff --git a/libethereum/PeerSession.cpp b/libethereum/PeerSession.cpp index 5f16884d6..957252e4a 100644 --- a/libethereum/PeerSession.cpp +++ b/libethereum/PeerSession.cpp @@ -235,9 +235,8 @@ bool PeerSession::interpret(RLP const& _r) for (unsigned i = 1; i < _r.itemCount(); ++i) { auto h = sha3(_r[i].data()); - if (!m_server->m_chain->details(h)) + if (!m_server->noteBlock(h, _r[i].data())) { - m_server->m_incomingBlocks.push_back(_r[i].data().toBytes()); m_knownBlocks.insert(h); used++; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 56fe2c6e2..ab184b2ce 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -672,6 +672,14 @@ bool State::amIJustParanoid(BlockChain const& _bc) return false; } +h256 State::bloom() const +{ + h256 ret; + for (auto const& i: m_transactions) + ret |= i.changes.bloom(); + return ret; +} + // @returns the block that represents the difference between m_previousBlock and m_currentBlock. // (i.e. all the transactions we executed). void State::commitToMine(BlockChain const& _bc) @@ -713,11 +721,9 @@ void State::commitToMine(BlockChain const& _bc) RLPStream txs; txs.appendList(m_transactions.size()); - m_bloom = h256(); for (unsigned i = 0; i < m_transactions.size(); ++i) { - m_bloom |= m_transactions[i].changes.bloom(); RLPStream k; k << i; RLPStream v; diff --git a/libethereum/State.h b/libethereum/State.h index 1ce887110..1df4b6cc9 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -245,8 +245,8 @@ public: /// Get the list of pending transactions. Manifest changesFromPending(unsigned _i) const { return m_transactions[_i].changes; } - /// Get the bloom filter of all changes happened in the block. Only good once commitToMine() is called. - u256 bloom() const { return m_bloom; } + /// Get the bloom filter of all changes happened in the block. + h256 bloom() const; /// Get the State immediately after the given number of pending transactions have been applied. /// If (_i == 0) returns the initial state of the block. @@ -276,12 +276,7 @@ public: bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. - /// @warning We must already have been sync()ed with said block. /// @returns the additional total difficulty. - /// If the @a _grandParent is passed, it will check the validity of each of the uncles. - /// @throws if there are any validation errors. - u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent = BlockInfo()); - u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. @@ -340,7 +335,6 @@ private: std::set m_transactionSet; ///< The set of transaction hashes that we've included in the state. // GenericTrieDB m_transactionManifest; ///< The transactions trie; saved from the last commitToMine, or invalid/empty if commitToMine was never called. OverlayDB m_lastTx; - h256 m_bloom; ///< Bloom filter of changed addresses/locations in the block. mutable std::map m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 981c8aa20..0e1767625 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -241,7 +241,7 @@ QEthereum::~QEthereum() { } -void QEthereum::setup(QWebFrame* _e) +void QEthereum::setup(QWebFrame*) { // Alex: JS codes moved to mainwin until qtwebkit bugs are resolved (#245) } From a5ab06078d8972007e1fa95c46a642121d822aa0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 22 Jul 2014 21:20:20 +0200 Subject: [PATCH 4/5] New database format - caches transaction blooms and changelogs: *much* faster querying. One or two bugs squashed. Updated stdserv.js. --- alethzero/MainWin.cpp | 3 +- libethcore/CommonEth.cpp | 1 + libethcore/CommonEth.h | 3 + libethential/CommonData.h | 19 ++++++ libethereum/BlockChain.cpp | 98 +++++++++++++++++++++++++---- libethereum/BlockChain.h | 41 +++++++++++- libethereum/Client.cpp | 121 ++++++++++++++++++++++++++++++++---- libethereum/Client.h | 40 +++++++----- libethereum/Executive.cpp | 1 + libethereum/Executive.h | 19 +----- libethereum/Manifest.cpp | 45 ++++++++++++++ libethereum/Manifest.h | 53 ++++++++++++++++ libethereum/PeerSession.cpp | 8 +-- libethereum/State.cpp | 2 + libethereum/State.h | 3 + libqethereum/QEthereum.cpp | 19 +++--- stdserv.js | 7 ++- 17 files changed, 406 insertions(+), 77 deletions(-) create mode 100644 libethereum/Manifest.cpp create mode 100644 libethereum/Manifest.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 918a28916..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() 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/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/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 004b28454..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,7 +59,7 @@ BlockDetails::BlockDetails(RLP const& _r) totalDifficulty = _r[1].toInt(); parent = _r[2].toHash(); children = _r[3].toVector(); - bloom = _r[4].isNull() ? ~h256() : _r[4].toHash(); + bloom = _r[4].toHash(); } bytes BlockDetails::rlp() const @@ -124,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; @@ -136,14 +136,14 @@ BlockChain::BlockChain(std::string _path, bool _killExisting) // Insert details of genesis block. 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; @@ -152,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; } @@ -182,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) { @@ -240,6 +253,13 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db) 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; @@ -251,11 +271,15 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db) lock_guard l(m_lock); 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(); @@ -275,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 @@ -288,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) { @@ -321,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]; } @@ -347,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; @@ -359,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 025181396..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; @@ -50,11 +51,34 @@ struct BlockDetails h256s children; 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 f4f59530e..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); } @@ -399,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(); @@ -412,14 +464,30 @@ 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; @@ -433,9 +501,35 @@ PastTransactions Client::transactions(TransactionFilter const& _f) const for (; ret.size() != m && n != end; n--, h = m_bc.details(h).parent) { auto d = m_bc.details(h); + int total = 0; if (_f.matches(d.bloom)) { - try + // 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])) + { + // 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; @@ -445,7 +539,7 @@ PastTransactions Client::transactions(TransactionFilter const& _f) const if (s) s--; else - ret.insert(ret.begin(), PastTransaction(st.pending()[i], h, i, BlockInfo(m_bc.block(h)).timestamp, cn - n + 2)); + 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++; @@ -454,6 +548,7 @@ PastTransactions Client::transactions(TransactionFilter const& _f) const { // Gaa. bad state. not good at all. bury head in sand for now. } +*/ } else skipped++; diff --git a/libethereum/Client.h b/libethereum/Client.h index 6908de228..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: @@ -90,6 +110,7 @@ public: 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; } @@ -101,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; @@ -111,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. */ @@ -193,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/PeerSession.cpp b/libethereum/PeerSession.cpp index 957252e4a..a80cc6b27 100644 --- a/libethereum/PeerSession.cpp +++ b/libethereum/PeerSession.cpp @@ -235,7 +235,7 @@ bool PeerSession::interpret(RLP const& _r) for (unsigned i = 1; i < _r.itemCount(); ++i) { auto h = sha3(_r[i].data()); - if (!m_server->noteBlock(h, _r[i].data())) + if (m_server->noteBlock(h, _r[i].data())) { m_knownBlocks.insert(h); used++; @@ -289,11 +289,11 @@ bool PeerSession::interpret(RLP const& _r) // try to find parent in our blockchain // todo: add some delta() fn to blockchain - BlockDetails f_parent = m_server->m_chain->details(parent); - if (f_parent) + BlockDetails fParent = m_server->m_chain->details(parent); + if (fParent) { latestNumber = m_server->m_chain->number(latest); - parentNumber = f_parent.number; + parentNumber = fParent.number; uint count = min(latestNumber - parentNumber, baseCount); clogS(NetAllDetail) << "Requires " << dec << (latestNumber - parentNumber) << " blocks from " << latestNumber << " to " << parentNumber; clogS(NetAllDetail) << latest << " - " << parent; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ab184b2ce..66dec31e7 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1044,6 +1044,7 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u { o_ms->from = _senderAddress; o_ms->to = _receiveAddress; + o_ms->value = _value; o_ms->input = _data.toBytes(); } @@ -1101,6 +1102,7 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, { o_ms->from = _sender; o_ms->to = Address(); + o_ms->value = _endowment; o_ms->input = _code.toBytes(); } diff --git a/libethereum/State.h b/libethereum/State.h index 1df4b6cc9..3618b9a9a 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -248,6 +248,9 @@ public: /// Get the bloom filter of all changes happened in the block. h256 bloom() const; + /// Get the bloom filter of a particular transaction that happened in the block. + h256 bloom(unsigned _i) const { return m_transactions[_i].changes.bloom(); } + /// Get the State immediately after the given number of pending transactions have been applied. /// If (_i == 0) returns the initial state of the block. /// If (_i == pending().size()) returns the final state of the block, prior to rewards. diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 0e1767625..bbc7268da 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -415,19 +415,20 @@ QString QEthereum::getTransactions(QString _a) const } QJsonArray ret; - for (eth::PastTransaction const& t: m_client->transactions(filter)) + for (eth::PastMessage const& t: m_client->transactions(filter)) { QJsonObject v; - v["data"] = ::fromBinary(t.data); - v["gas"] = toQJS(t.gas); - v["gasPrice"] = toQJS(t.gasPrice); - v["nonce"] = (int)t.nonce; - v["to"] = toQJS(t.receiveAddress); - v["value"] = toQJS(t.value); - v["from"] = toQJS(t.sender()); + v["input"] = ::fromBinary(t.input); + v["output"] = ::fromBinary(t.output); + v["to"] = toQJS(t.to); + v["from"] = toQJS(t.from); + v["origin"] = toQJS(t.origin); v["timestamp"] = (int)t.timestamp; v["block"] = toQJS(t.block); - v["index"] = (int)t.index; + QJsonArray path; + for (int i: t.path) + path.append(i); + v["path"] = path; v["age"] = (int)t.age; ret.append(v); } diff --git a/stdserv.js b/stdserv.js index 188ab781a..92f075a1b 100644 --- a/stdserv.js +++ b/stdserv.js @@ -119,8 +119,11 @@ var gavCoinCode = eth.lll(" (set 'n @@0x42) (when (&& (|| (= $0 'mine) (! (calldatasize))) (> (number) @n)) { - [[(coinbase)]] (+ @@(coinbase) 1024) - [[0x42]] (+ @n 1) + (set 'b (- (number) @n)) + [[(coinbase)]] (+ @@(coinbase) (* 1000 @b)) + [[(caller)]] (+ @@(caller) (* 1000 @b)) + [[0x42]] (number) + (return @b) }) (return @@ $0) From d26588752e88bb534d18b2c7c481fcccafda1c23 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 22 Jul 2014 21:35:04 +0200 Subject: [PATCH 5/5] Version bump. --- libethential/Common.cpp | 2 +- libqethereum/QEthereum.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index bbc7268da..520547f64 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -418,6 +418,7 @@ QString QEthereum::getTransactions(QString _a) const for (eth::PastMessage const& t: m_client->transactions(filter)) { QJsonObject v; + v["data"] = ::fromBinary(t.input); v["input"] = ::fromBinary(t.input); v["output"] = ::fromBinary(t.output); v["to"] = toQJS(t.to);