Browse Source

New database format - caches transaction blooms and changelogs:

*much* faster querying.
One or two bugs squashed.
Updated stdserv.js.
cl-refactor
Gav Wood 11 years ago
parent
commit
a5ab06078d
  1. 3
      alethzero/MainWin.cpp
  2. 1
      libethcore/CommonEth.cpp
  3. 3
      libethcore/CommonEth.h
  4. 19
      libethential/CommonData.h
  5. 98
      libethereum/BlockChain.cpp
  6. 41
      libethereum/BlockChain.h
  7. 121
      libethereum/Client.cpp
  8. 40
      libethereum/Client.h
  9. 1
      libethereum/Executive.cpp
  10. 19
      libethereum/Executive.h
  11. 45
      libethereum/Manifest.cpp
  12. 53
      libethereum/Manifest.h
  13. 8
      libethereum/PeerSession.cpp
  14. 2
      libethereum/State.cpp
  15. 3
      libethereum/State.h
  16. 19
      libqethereum/QEthereum.cpp
  17. 7
      stdserv.js

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

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;

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

98
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<u256>();
parent = _r[2].toHash<h256>();
children = _r[3].toVector<h256>();
bloom = _r[4].isNull() ? ~h256() : _r[4].toHash<h256>();
bloom = _r[4].toHash<h256>();
}
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<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)
{
@ -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<recursive_mutex> 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<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)
{
@ -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<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;
}

41
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;
@ -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<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;

121
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);
}
@ -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<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();
@ -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++;

40
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:
@ -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<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;
@ -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<PastTransaction> 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:

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

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

2
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();
}

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

19
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);
}

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