Browse Source

Merge branch 'develop'

cl-refactor
Gav Wood 11 years ago
parent
commit
00aad9bc6a
  1. 4
      alethzero/MainWin.cpp
  2. 1
      libethcore/CommonEth.cpp
  3. 3
      libethcore/CommonEth.h
  4. 2
      libethential/Common.cpp
  5. 19
      libethential/CommonData.h
  6. 9
      libethential/FixedHash.h
  7. 104
      libethereum/BlockChain.cpp
  8. 45
      libethereum/BlockChain.h
  9. 193
      libethereum/Client.cpp
  10. 41
      libethereum/Client.h
  11. 1
      libethereum/Executive.cpp
  12. 19
      libethereum/Executive.h
  13. 45
      libethereum/Manifest.cpp
  14. 53
      libethereum/Manifest.h
  15. 13
      libethereum/PeerServer.cpp
  16. 6
      libethereum/PeerServer.h
  17. 9
      libethereum/PeerSession.cpp
  18. 12
      libethereum/State.cpp
  19. 13
      libethereum/State.h
  20. 22
      libqethereum/QEthereum.cpp
  21. 69
      neth/main.cpp
  22. 7
      stdserv.js

4
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 << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress;
s << "<br/>Nonce: <b>" << info.nonce << "</b>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>";
s << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
s << "<br/>Pre: <b>" << BlockInfo(m_client->blockChain().block(info.parentHash)).stateRoot << "</b>";

1
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<pair<u256, string>> g_units =
{

3
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;

2
libethential/Common.cpp

@ -27,6 +27,6 @@ using namespace eth;
namespace eth
{
char const* EthVersion = "0.5.16";
char const* EthVersion = "0.6.0";
}

19
libethential/CommonData.h

@ -204,4 +204,23 @@ inline std::vector<_T> operator+(std::vector<typename std::enable_if<std::is_pod
return ret += _b;
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<!std::is_pod<_T>::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 <class _T>
inline std::vector<_T> operator+(std::vector<typename std::enable_if<!std::is_pod<_T>::value, _T>::type> const& _a, std::vector<_T> const& _b)
{
std::vector<_T> ret(_a);
return ret += _b;
}
}

9
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 <unsigned M> FixedHash(FixedHash<M> 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.

104
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<u256>();
parent = _r[2].toHash<h256>();
children = _r[3].toVector<h256>();
bloom = _r[4].toHash<h256>();
}
bytes BlockDetails::rlp() const
{
return rlpList(number, totalDifficulty, parent, children);
return rlpList(number, totalDifficulty, parent, children, bloom);
}
std::map<Address, AddressState> 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<h256> 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<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> 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;
}

45
libethereum/BlockChain.h

@ -25,6 +25,7 @@
#include <libethential/Log.h>
#include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h>
#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<h256>(); }
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<h256, BlockDetails> BlockDetailsHash;
typedef std::map<h256, BlockBlooms> BlockBloomsHash;
typedef std::map<h256, BlockTraces> 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<h256, bytes> m_cache;
mutable std::recursive_mutex m_lock;
@ -132,7 +167,7 @@ private:
std::vector<std::pair<Address, AddressState>> 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;

193
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<unsigned>(RLP::LaisezFaire) == _protocolVersion;
m_ok = RLP(contents(m_path + "/protocol")).toInt<unsigned>(RLP::LaisezFaire) == c_protocolVersion && RLP(contents(m_path + "/database")).toInt<unsigned>(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<PeerInfo> Client::peers()
{
ClientGuard l(this);
return m_net ? m_net->peers() : std::vector<PeerInfo>();
}
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<unsigned>(1, _i), _m.from, PastMessages(), ret);
return ret;
}
bool TransactionFilter::matches(Manifest const& _m, vector<unsigned> _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;
}

41
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<unsigned> _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<unsigned> 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<PastMessage> 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<unsigned> _p, Address _o, PastMessages _limbo, PastMessages& o_ret) const;
std::set<Address> m_from;
std::set<Address> m_to;
std::set<std::pair<Address, u256>> 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<PastTransaction> 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:

1
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;
}

19
libethereum/Executive.h

@ -27,6 +27,7 @@
#include <libethcore/CommonEth.h>
#include <libevm/ExtVMFace.h>
#include "Transaction.h"
#include "Manifest.h"
namespace eth
{
@ -35,26 +36,8 @@ class VM;
class ExtVM;
class State;
struct Manifest;
using Manifests = std::vector<Manifest>;
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:

45
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 <http://www.gnu.org/licenses/>.
*/
/** @file Manifest.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Manifest.h"
using namespace std;
using namespace eth;
Manifest::Manifest(bytesConstRef _r)
{
RLP r(_r);
from = r[0].toHash<Address>();
to = r[1].toHash<Address>();
value = r[2].toInt<u256>();
altered = r[3].toVector<u256>();
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);
}

53
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 <http://www.gnu.org/licenses/>.
*/
/** @file Manifest.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libethential/RLP.h>
#include <libethcore/CommonEth.h>
namespace eth
{
struct Manifest;
using Manifests = std::vector<Manifest>;
/**
* @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;
};
}

13
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<recursive_mutex> 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<recursive_mutex> l(m_incomingLock);
if (m_incomingBlocks.size())
for (auto it = prev(m_incomingBlocks.end());; --it)
{

6
libethereum/PeerServer.h

@ -21,6 +21,7 @@
#pragma once
#include <mutex>
#include <map>
#include <vector>
#include <set>
@ -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<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
mutable std::recursive_mutex m_incomingLock;
std::vector<bytes> m_unknownParentBlocks;
std::vector<Public> m_freePeers;
std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers;

9
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++;
}
@ -290,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<uint>(latestNumber - parentNumber, baseCount);
clogS(NetAllDetail) << "Requires " << dec << (latestNumber - parentNumber) << " blocks from " << latestNumber << " to " << parentNumber;
clogS(NetAllDetail) << latest << " - " << parent;

12
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;
@ -1038,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();
}
@ -1095,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();
}

13
libethereum/State.h

@ -245,8 +245,11 @@ 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 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.
@ -276,12 +279,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 +338,6 @@ private:
std::set<h256> m_transactionSet; ///< The set of transaction hashes that we've included in the state.
// GenericTrieDB<OverlayDB> 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<Address, AddressState> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.

22
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)
}
@ -415,19 +415,21 @@ 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["data"] = ::fromBinary(t.input);
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);
}

69
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,13 +884,21 @@ 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);
if (y > qheight - 4)
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 > height * 1 / 5 - 4)
break;
}
@ -893,20 +911,31 @@ 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;
}
if (y > height * 2 / 5 - 2)
break;
}
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;
}
}
// Peers

7
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)

Loading…
Cancel
Save