Browse Source

Merge branch 'develop' into crypto

cl-refactor
subtly 10 years ago
parent
commit
5960dae74d
  1. 87
      alethzero/MainWin.cpp
  2. 10
      alethzero/MainWin.h
  3. 30
      libdevcore/CommonData.h
  4. 4
      libdevcrypto/SHA3.cpp
  5. 1
      libdevcrypto/SHA3.h
  6. 6
      libdevcrypto/TrieDB.h
  7. 10
      libethcore/BlockInfo.cpp
  8. 2
      libethcore/CommonEth.cpp
  9. 4
      libethereum/BlockChain.cpp
  10. 3
      libethereum/Client.cpp
  11. 4
      libethereum/Executive.cpp
  12. 3
      libethereum/Executive.h
  13. 4
      libethereum/ExtVM.h
  14. 20
      libethereum/State.cpp
  15. 14
      libethereum/State.h
  16. 3
      libethereum/Transaction.cpp
  17. 9
      libethereum/Transaction.h
  18. 28
      libevm/ExtVMFace.h
  19. 4
      libevm/FeeStructure.cpp
  20. 4
      libevm/FeeStructure.h
  21. 30
      libevm/VM.h
  22. 6
      libevmface/Instruction.cpp
  23. 3
      libevmface/Instruction.h
  24. 2
      libp2p/Host.cpp
  25. 95
      libqethereum/QEthereum.cpp
  26. 67
      libqethereum/QEthereum.h
  27. 4
      test/MemTrie.cpp
  28. 6
      test/TrieHash.cpp
  29. 3
      test/crypto.cpp
  30. 1
      test/state.cpp
  31. 31
      test/vm.cpp
  32. 2
      test/vm.h
  33. 9
      third/MainWin.cpp
  34. 6
      third/MainWin.h

87
alethzero/MainWin.cpp

@ -131,6 +131,7 @@ Main::Main(QWidget *parent) :
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"}));
m_ldb = new QLDB(this);
connect(ui->webView, &QWebView::loadStarted, [this]() connect(ui->webView, &QWebView::loadStarted, [this]()
{ {
@ -138,8 +139,8 @@ Main::Main(QWidget *parent) :
m_whisper = nullptr; m_whisper = nullptr;
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this); m_dev = new QDev(this);
m_ethereum = new QEthereum(this, ethereum(), owned()); m_ethereum = new QEthereum(this, ethereum(), m_myKeys);
m_whisper = new QWhisper(this, whisper()); m_whisper = new QWhisper(this, whisper(), owned());
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebFrame* f = ui->webView->page()->mainFrame(); QWebFrame* f = ui->webView->page()->mainFrame();
@ -147,8 +148,9 @@ Main::Main(QWidget *parent) :
auto qdev = m_dev; auto qdev = m_dev;
auto qeth = m_ethereum; auto qeth = m_ethereum;
auto qshh = m_whisper; auto qshh = m_whisper;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); auto qldb = m_ldb;
connect(m_whisper, SIGNAL(idsChanged()), this, SLOT(refreshWhisper())); connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb));
connect(m_whisper, SIGNAL(newIdToAdd(QString)), this, SLOT(addNewId(QString)));
}); });
connect(ui->webView, &QWebView::loadFinished, [=]() connect(ui->webView, &QWebView::loadFinished, [=]()
@ -183,11 +185,20 @@ Main::~Main()
// Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor) // Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor)
// *after* the client is dead. // *after* the client is dead.
m_ethereum->clientDieing(); m_ethereum->clientDieing();
m_whisper->faceDieing();
g_logPost = simpleDebugOut; g_logPost = simpleDebugOut;
writeSettings(); writeSettings();
} }
void Main::addNewId(QString _ids)
{
Secret _id = toSecret(_ids);
KeyPair kp(_id);
m_myIdentities.push_back(kp);
m_whisper->setIdentities(owned());
}
dev::p2p::NetworkPreferences Main::netPrefs() const dev::p2p::NetworkPreferences Main::netPrefs() const
{ {
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked()); return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked());
@ -494,15 +505,28 @@ void Main::on_paranoia_triggered()
void Main::writeSettings() void Main::writeSettings()
{ {
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
QByteArray b;
b.resize(sizeof(Secret) * m_myKeys.size());
auto p = b.data();
for (auto i: m_myKeys)
{ {
memcpy(p, &(i.secret()), sizeof(Secret)); QByteArray b;
p += sizeof(Secret); b.resize(sizeof(Secret) * m_myKeys.size());
auto p = b.data();
for (auto i: m_myKeys)
{
memcpy(p, &(i.secret()), sizeof(Secret));
p += sizeof(Secret);
}
s.setValue("address", b);
}
{
QByteArray b;
b.resize(sizeof(Secret) * m_myIdentities.size());
auto p = b.data();
for (auto i: m_myIdentities)
{
memcpy(p, &(i.secret()), sizeof(Secret));
p += sizeof(Secret);
}
s.setValue("identities", b);
} }
s.setValue("address", b);
s.setValue("upnp", ui->upnp->isChecked()); s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forceAddress->text()); s.setValue("forceAddress", ui->forceAddress->text());
@ -538,21 +562,39 @@ void Main::readSettings(bool _skipGeometry)
restoreGeometry(s.value("geometry").toByteArray()); restoreGeometry(s.value("geometry").toByteArray());
restoreState(s.value("windowState").toByteArray()); restoreState(s.value("windowState").toByteArray());
m_myKeys.clear();
QByteArray b = s.value("address").toByteArray();
if (b.isEmpty())
m_myKeys.append(KeyPair::create());
else
{ {
h256 k; m_myKeys.clear();
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) QByteArray b = s.value("address").toByteArray();
if (b.isEmpty())
m_myKeys.append(KeyPair::create());
else
{ {
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); h256 k;
if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
m_myKeys.append(KeyPair(k)); {
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k)))
m_myKeys.append(KeyPair(k));
}
} }
ethereum()->setAddress(m_myKeys.back().address());
} }
ethereum()->setAddress(m_myKeys.back().address());
{
m_myIdentities.clear();
QByteArray b = s.value("identities").toByteArray();
if (!b.isEmpty())
{
h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k)))
m_myIdentities.append(KeyPair(k));
}
}
}
m_peers = s.value("peers").toByteArray(); m_peers = s.value("peers").toByteArray();
ui->upnp->setChecked(s.value("upnp", true).toBool()); ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString()); ui->forceAddress->setText(s.value("forceAddress", "").toString());
@ -1742,6 +1784,7 @@ void Main::on_debug_clicked()
t.gasPrice = gasPrice(); t.gasPrice = gasPrice();
t.gas = ui->gas->value(); t.gas = ui->gas->value();
t.data = m_data; t.data = m_data;
t.type = isCreation() ? Transaction::ContractCreation : Transaction::MessageCall;
t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText());
t.sign(s); t.sign(s);
auto r = t.rlp(); auto r = t.rlp();

10
alethzero/MainWin.h

@ -77,7 +77,7 @@ public:
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); } std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
QList<dev::KeyPair> const& owned() const { return m_myKeys; } QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
public slots: public slots:
void load(QString _file); void load(QString _file);
@ -153,9 +153,11 @@ private slots:
void on_newIdentity_triggered(); void on_newIdentity_triggered();
void refreshWhisper(); void refreshWhisper();
void addNewId(QString);
signals: signals:
void poll(); void poll();
void idsChanged();
private: private:
dev::p2p::NetworkPreferences netPrefs() const; dev::p2p::NetworkPreferences netPrefs() const;
@ -179,6 +181,8 @@ private:
void readSettings(bool _skipGeometry = false); void readSettings(bool _skipGeometry = false);
void writeSettings(); void writeSettings();
void keysChanged();
bool isCreation() const; bool isCreation() const;
dev::u256 fee() const; dev::u256 fee() const;
dev::u256 total() const; dev::u256 total() const;
@ -189,8 +193,6 @@ private:
unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f); unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f);
void uninstallWatch(unsigned _w); void uninstallWatch(unsigned _w);
void keysChanged();
void onNewPending(); void onNewPending();
void onNewBlock(); void onNewBlock();
void onNameRegChange(); void onNameRegChange();
@ -228,6 +230,7 @@ private:
QByteArray m_peers; QByteArray m_peers;
QStringList m_servers; QStringList m_servers;
QList<dev::KeyPair> m_myKeys; QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities;
QString m_privateChain; QString m_privateChain;
dev::bytes m_data; dev::bytes m_data;
dev::Address m_nameReg; dev::Address m_nameReg;
@ -255,4 +258,5 @@ private:
QDev* m_dev = nullptr; QDev* m_dev = nullptr;
QEthereum* m_ethereum = nullptr; QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr; QWhisper* m_whisper = nullptr;
QLDB* m_ldb = nullptr;
}; };

30
libdevcore/CommonData.h

@ -190,7 +190,7 @@ void pushFront(_T& _t, _U _e)
_t[0] = _e; _t[0] = _e;
} }
/// Concatenate two vectors of elements. _T must be POD. /// Concatenate two vectors of elements of POD types.
template <class _T> 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) inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
{ {
@ -201,30 +201,38 @@ inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_p
} }
/// Concatenate two vectors of elements. _T must be POD. /// Concatenate two vectors of elements.
template <class _T> 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) 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.
template <class _T>
inline std::vector<_T> operator+(std::vector<_T> const& _a, std::vector<_T> const& _b)
{ {
std::vector<_T> ret(_a); std::vector<_T> ret(_a);
return ret += _b; return ret += _b;
} }
/// Concatenate two vectors of elements. _T must be POD. /// Merge two sets of elements.
template <class _T> 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) inline std::set<_T>& operator+=(std::set<_T>& _a, std::set<_T> const& _b)
{ {
_a.reserve(_a.size() + _b.size());
for (auto& i: _b) for (auto& i: _b)
_a.push_back(i); _a.insert(i);
return _a; return _a;
} }
/// Concatenate two vectors of elements. _T must be POD. /// Merge two sets of elements.
template <class _T> 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) inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b)
{ {
std::vector<_T> ret(_a); std::set<_T> ret(_a);
return ret += _b; return ret += _b;
} }

4
libdevcrypto/SHA3.cpp

@ -20,8 +20,9 @@
*/ */
#include "SHA3.h" #include "SHA3.h"
#include "CryptoPP.h"
#include <libdevcore/RLP.h>
#include "CryptoPP.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -29,6 +30,7 @@ namespace dev
{ {
h256 EmptySHA3 = sha3(bytesConstRef()); h256 EmptySHA3 = sha3(bytesConstRef());
h256 ZeroRLPSHA3 = sha3(rlp(bytesConstRef()));
std::string sha3(std::string const& _input, bool _hex) std::string sha3(std::string const& _input, bool _hex)
{ {

1
libdevcrypto/SHA3.h

@ -57,6 +57,7 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
extern h256 EmptySHA3; extern h256 EmptySHA3;
extern h256 ZeroRLPSHA3;
// Other crypto convenience routines // Other crypto convenience routines

6
libdevcrypto/TrieDB.h

@ -74,7 +74,7 @@ public:
void init(); void init();
void setRoot(h256 _root) void setRoot(h256 _root)
{ {
m_root = _root == h256() ? c_shaNull : _root; m_root = _root;
if (m_root == c_shaNull && !m_db->exists(m_root)) if (m_root == c_shaNull && !m_db->exists(m_root))
init(); init();
@ -82,14 +82,14 @@ public:
if (!node(m_root).size()) if (!node(m_root).size())
BOOST_THROW_EXCEPTION(RootNotFound()); BOOST_THROW_EXCEPTION(RootNotFound());
} }
bool haveRoot(h256 _root, bool _enforceRefs = true) { return _root == h256() ? true : m_db->lookup(_root, _enforceRefs).size(); } bool haveRoot(h256 _root, bool _enforceRefs = true) { return _root == c_shaNull ? true : m_db->lookup(_root, _enforceRefs).size(); }
/// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node).
bool isNull() const { return !node(m_root).size(); } bool isNull() const { return !node(m_root).size(); }
/// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty).
bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); } bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); }
h256 root() const { assert(node(m_root).size()); h256 ret = (m_root == c_shaNull ? h256() : m_root); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return ret; } // patch the root in the case of the empty trie. TODO: handle this properly. h256 root() const { assert(node(m_root).size()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly.
void debugPrint() {} void debugPrint() {}

10
libethcore/BlockInfo.cpp

@ -60,11 +60,9 @@ auto static const c_sha3EmptyList = sha3(RLPEmptyList);
void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const
{ {
_s.appendList(_nonce ? 13 : 12) << parentHash; _s.appendList(_nonce ? 13 : 12)
_s.append(sha3Uncles == c_sha3EmptyList ? h256() : sha3Uncles, false, true); << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot
_s << coinbaseAddress; << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData;
_s.append(stateRoot, false, true).append(transactionsRoot, false, true);
_s << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData;
if (_nonce) if (_nonce)
_s << nonce; _s << nonce;
} }
@ -83,8 +81,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
{ {
parentHash = _header[field = 0].toHash<h256>(); parentHash = _header[field = 0].toHash<h256>();
sha3Uncles = _header[field = 1].toHash<h256>(); sha3Uncles = _header[field = 1].toHash<h256>();
if (sha3Uncles == h256())
sha3Uncles = c_sha3EmptyList;
coinbaseAddress = _header[field = 2].toHash<Address>(); coinbaseAddress = _header[field = 2].toHash<Address>();
stateRoot = _header[field = 3].toHash<h256>(); stateRoot = _header[field = 3].toHash<h256>();
transactionsRoot = _header[field = 4].toHash<h256>(); transactionsRoot = _header[field = 4].toHash<h256>();

2
libethcore/CommonEth.cpp

@ -34,7 +34,7 @@ namespace dev
namespace eth namespace eth
{ {
const unsigned c_protocolVersion = 36; const unsigned c_protocolVersion = 37;
const unsigned c_databaseVersion = 3; const unsigned c_databaseVersion = 3;
static const vector<pair<u256, string>> g_units = static const vector<pair<u256, string>> g_units =

4
libethereum/BlockChain.cpp

@ -101,8 +101,8 @@ bytes BlockChain::createGenesisBlock()
stateRoot = state.root(); stateRoot = state.root();
} }
block.appendList(13) << h256() << bytes() << h160(); block.appendList(13)
block.append(stateRoot, false, true) << bytes() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); << h256() << c_shaNull << h160() << stateRoot << c_shaNull << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42));
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
return block.out(); return block.out();

3
libethereum/Client.cpp

@ -325,6 +325,7 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
t.value = _value; t.value = _value;
t.gasPrice = _gasPrice; t.gasPrice = _gasPrice;
t.gas = _gas; t.gas = _gas;
t.type = Transaction::MessageCall;
t.receiveAddress = _dest; t.receiveAddress = _dest;
t.data = _data; t.data = _data;
t.sign(_secret); t.sign(_secret);
@ -348,6 +349,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
t.value = _value; t.value = _value;
t.gasPrice = _gasPrice; t.gasPrice = _gasPrice;
t.gas = _gas; t.gas = _gas;
t.type = Transaction::ContractCreation;
t.receiveAddress = _dest; t.receiveAddress = _dest;
t.data = _data; t.data = _data;
t.sign(_secret); t.sign(_secret);
@ -373,6 +375,7 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
t.value = _endowment; t.value = _endowment;
t.gasPrice = _gasPrice; t.gasPrice = _gasPrice;
t.gas = _gas; t.gas = _gas;
t.type = Transaction::ContractCreation;
t.receiveAddress = Address(); t.receiveAddress = Address();
t.data = _init; t.data = _init;
t.sign(_secret); t.sign(_secret);

4
libethereum/Executive.cpp

@ -172,6 +172,8 @@ bool Executive::go(OnOpFunc const& _onOp)
try try
{ {
m_out = m_vm->go(*m_ext, _onOp); m_out = m_vm->go(*m_ext, _onOp);
if (m_ext)
m_endGas += min((m_t.gas - m_endGas) / 2, m_ext->sub.refunds);
m_endGas = m_vm->gas(); m_endGas = m_vm->gas();
} }
catch (StepsDone const&) catch (StepsDone const&)
@ -236,6 +238,6 @@ void Executive::finalize(OnOpFunc const&)
// Suicides... // Suicides...
if (m_ext) if (m_ext)
for (auto a: m_ext->suicides) for (auto a: m_ext->sub.suicides)
m_s.m_cache[a].kill(); m_s.m_cache[a].kill();
} }

3
libethereum/Executive.h

@ -61,6 +61,7 @@ public:
bytesConstRef out() const { return m_out; } bytesConstRef out() const { return m_out; }
h160 newAddress() const { return m_newAddress; } h160 newAddress() const { return m_newAddress; }
LogEntries const& logs() const { return m_logs; }
VM const& vm() const { return *m_vm; } VM const& vm() const { return *m_vm; }
State const& state() const { return m_s; } State const& state() const { return m_s; }
@ -77,6 +78,8 @@ private:
Transaction m_t; Transaction m_t;
Address m_sender; Address m_sender;
u256 m_endGas; u256 m_endGas;
LogEntries m_logs;
}; };
} }

4
libethereum/ExtVM.h

@ -61,7 +61,7 @@ public:
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
if (m_ms) if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1); m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1); auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from) if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back(); m_ms->internal.pop_back();
return ret; return ret;
@ -72,7 +72,7 @@ public:
{ {
if (m_ms) if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1); m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1); auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from) if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back(); m_ms->internal.pop_back();
return ret; return ret;

20
libethereum/State.cpp

@ -353,9 +353,9 @@ void State::ensureCached(std::map<Address, AddressState>& _cache, Address _a, bo
RLP state(stateBack); RLP state(stateBack);
AddressState s; AddressState s;
if (state.isNull()) if (state.isNull())
s = AddressState(0, 0, h256(), EmptySHA3); s = AddressState(0, 0, ZeroRLPSHA3, EmptySHA3);
else else
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>(), state[3].isEmpty() ? EmptySHA3 : state[3].toHash<h256>()); s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>(), state[3].toHash<h256>());
bool ok; bool ok;
tie(it, ok) = _cache.insert(make_pair(_a, s)); tie(it, ok) = _cache.insert(make_pair(_a, s));
} }
@ -1119,7 +1119,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
return e.gasUsed(); return e.gasUsed();
} }
bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{ {
if (!_originAddress) if (!_originAddress)
_originAddress = _senderAddress; _originAddress = _senderAddress;
@ -1154,9 +1154,8 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
{ {
auto out = vm.go(evm, _onOp); auto out = vm.go(evm, _onOp);
memcpy(_out.data(), out.data(), std::min(out.size(), _out.size())); memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
if (o_suicides) if (o_sub)
for (auto i: evm.suicides) *o_sub += evm.sub;
o_suicides->insert(i);
if (o_ms) if (o_ms)
o_ms->output = out.toBytes(); o_ms->output = out.toBytes();
} }
@ -1189,7 +1188,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
return true; return true;
} }
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{ {
if (!_origin) if (!_origin)
_origin = _sender; _origin = _sender;
@ -1218,9 +1217,8 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
out = vm.go(evm, _onOp); out = vm.go(evm, _onOp);
if (o_ms) if (o_ms)
o_ms->output = out.toBytes(); o_ms->output = out.toBytes();
if (o_suicides) if (o_sub)
for (auto i: evm.suicides) *o_sub += evm.sub;
o_suicides->insert(i);
} }
catch (OutOfGas const& /*_e*/) catch (OutOfGas const& /*_e*/)
{ {
@ -1240,7 +1238,7 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
clog(StateChat) << "std::exception in VM: " << _e.what(); clog(StateChat) << "std::exception in VM: " << _e.what();
} }
// TODO: CHECK: IS THIS CORRECT?! (esp. given account created prior to revertion init.) // TODO: CHECK: AUDIT: IS THIS CORRECT?! (esp. given account created prior to revertion init.)
// Write state out only in the case of a non-out-of-gas transaction. // Write state out only in the case of a non-out-of-gas transaction.
if (revert) if (revert)

14
libethereum/State.h

@ -288,12 +288,12 @@ private:
// We assume all instrinsic fees are paid up before this point. // We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction. /// Execute a contract-creation transaction.
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Execute a call. /// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly. /// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
/// @returns false if the call ran out of gas before completion. true otherwise. /// @returns false if the call ran out of gas before completion. true otherwise.
bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock). /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent(); void resetCurrent();
@ -367,16 +367,10 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
{ {
h256 ch = sha3(i.second.code()); h256 ch = sha3(i.second.code());
_db.insert(ch, &i.second.code()); _db.insert(ch, &i.second.code());
if (i.second.code().size()) s << ch;
s << ch;
else
s << "";
} }
else else
if (i.second.codeHash() == EmptySHA3) s << i.second.codeHash();
s << "";
else
s << i.second.codeHash();
_state.insert(i.first, &s.out()); _state.insert(i.first, &s.out());
} }

3
libethereum/Transaction.cpp

@ -39,6 +39,7 @@ Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender)
nonce = rlp[field = 0].toInt<u256>(); nonce = rlp[field = 0].toInt<u256>();
gasPrice = rlp[field = 1].toInt<u256>(); gasPrice = rlp[field = 1].toInt<u256>();
gas = rlp[field = 2].toInt<u256>(); gas = rlp[field = 2].toInt<u256>();
type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall;
receiveAddress = rlp[field = 3].toHash<Address>(); receiveAddress = rlp[field = 3].toHash<Address>();
value = rlp[field = 4].toInt<u256>(); value = rlp[field = 4].toInt<u256>();
data = rlp[field = 5].toBytes(); data = rlp[field = 5].toBytes();
@ -88,7 +89,7 @@ void Transaction::fillStream(RLPStream& _s, bool _sig) const
{ {
_s.appendList((_sig ? 3 : 0) + 6); _s.appendList((_sig ? 3 : 0) + 6);
_s << nonce << gasPrice << gas; _s << nonce << gasPrice << gas;
if (receiveAddress) if (type == MessageCall)
_s << receiveAddress; _s << receiveAddress;
else else
_s << ""; _s << "";

9
libethereum/Transaction.h

@ -32,13 +32,20 @@ namespace eth
struct Transaction struct Transaction
{ {
enum Type
{
ContractCreation,
MessageCall
};
Transaction() {} Transaction() {}
Transaction(bytesConstRef _rlp, bool _checkSender = false); Transaction(bytesConstRef _rlp, bool _checkSender = false);
Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {}
bool operator==(Transaction const& _c) const { return receiveAddress == _c.receiveAddress && value == _c.value && data == _c.data; } bool operator==(Transaction const& _c) const { return type == _c.type && (type == ContractCreation || receiveAddress == _c.receiveAddress) && value == _c.value && data == _c.data; }
bool operator!=(Transaction const& _c) const { return !operator==(_c); } bool operator!=(Transaction const& _c) const { return !operator==(_c); }
Type type; ///< True if this is a contract-creation transaction. F
u256 nonce; ///< The transaction-count of the sender. u256 nonce; ///< The transaction-count of the sender.
u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions.
Address receiveAddress; ///< The receiving address of the transaction. Address receiveAddress; ///< The receiving address of the transaction.

28
libevm/ExtVMFace.h

@ -24,6 +24,7 @@
#include <set> #include <set>
#include <functional> #include <functional>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libevmface/Instruction.h> #include <libevmface/Instruction.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
@ -33,13 +34,28 @@ namespace dev
namespace eth namespace eth
{ {
struct Post struct LogEntry
{ {
Address from; Address from;
Address to; h256 topics;
u256 value;
bytes data; bytes data;
u256 gas; };
using LogEntries = std::vector<LogEntry>;
struct SubState
{
std::set<Address> suicides; ///< Any accounts that have suicided.
LogEntries logs; ///< Any logs.
u256 refunds; ///< Refund counter of SSTORE nonzero->zero.
SubState& operator+=(SubState const& _s)
{
suicides += _s.suicides;
refunds += _s.refunds;
suicides += _s.suicides;
return *this;
}
}; };
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, void/*VM*/*, void/*ExtVM*/ const*)>; using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, void/*VM*/*, void/*ExtVM*/ const*)>;
@ -80,7 +96,7 @@ public:
virtual u256 txCount(Address) { return 0; } virtual u256 txCount(Address) { return 0; }
/// Suicide the associated contract and give proceeds to the given address. /// Suicide the associated contract and give proceeds to the given address.
virtual void suicide(Address) { suicides.insert(myAddress); } virtual void suicide(Address) { sub.suicides.insert(myAddress); }
/// Create a new (contract) account. /// Create a new (contract) account.
virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); } virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); }
@ -103,7 +119,7 @@ public:
bytesConstRef code; ///< Current code that is executing. bytesConstRef code; ///< Current code that is executing.
BlockInfo previousBlock; ///< The previous block's information. BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information. BlockInfo currentBlock; ///< The current block's information.
std::set<Address> suicides; ///< Any accounts that have suicided. SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth; ///< Depth of the present call. unsigned depth; ///< Depth of the present call.
}; };

4
libevm/FeeStructure.cpp

@ -29,7 +29,9 @@ u256 const dev::eth::c_stepGas = 1;
u256 const dev::eth::c_balanceGas = 20; u256 const dev::eth::c_balanceGas = 20;
u256 const dev::eth::c_sha3Gas = 20; u256 const dev::eth::c_sha3Gas = 20;
u256 const dev::eth::c_sloadGas = 20; u256 const dev::eth::c_sloadGas = 20;
u256 const dev::eth::c_sstoreGas = 100; u256 const dev::eth::c_sstoreSetGas = 300;
u256 const dev::eth::c_sstoreResetGas = 100;
u256 const dev::eth::c_sstoreRefundGas = 100;
u256 const dev::eth::c_createGas = 100; u256 const dev::eth::c_createGas = 100;
u256 const dev::eth::c_callGas = 20; u256 const dev::eth::c_callGas = 20;
u256 const dev::eth::c_memoryGas = 1; u256 const dev::eth::c_memoryGas = 1;

4
libevm/FeeStructure.h

@ -32,7 +32,9 @@ extern u256 const c_stepGas; ///< Once per operation, except for SSTORE, SLOAD
extern u256 const c_balanceGas; ///< Once per BALANCE operation. extern u256 const c_balanceGas; ///< Once per BALANCE operation.
extern u256 const c_sha3Gas; ///< Once per SHA3 operation. extern u256 const c_sha3Gas; ///< Once per SHA3 operation.
extern u256 const c_sloadGas; ///< Once per SLOAD operation. extern u256 const c_sloadGas; ///< Once per SLOAD operation.
extern u256 const c_sstoreGas; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once). extern u256 const c_sstoreSetGas; ///< Once per SSTORE operation if the zeroness changes from zero.
extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeroness doesn't change.
extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operation if the zeroness changes to zero.
extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction. extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
extern u256 const c_callGas; ///< Once per CALL operation & message call transaction. extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.

30
libevm/VM.h

@ -117,11 +117,14 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::SSTORE: case Instruction::SSTORE:
require(2); require(2);
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
runGas = c_sstoreGas * 2; runGas = c_sstoreSetGas;
else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
{
runGas = 0; runGas = 0;
_ext.sub.refunds += c_sstoreRefundGas;
}
else else
runGas = c_sstoreGas; runGas = c_sstoreResetGas;
break; break;
case Instruction::SLOAD: case Instruction::SLOAD:
@ -236,7 +239,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::PUSH31: case Instruction::PUSH31:
case Instruction::PUSH32: case Instruction::PUSH32:
break; break;
case Instruction::NEG: case Instruction::BNOT:
case Instruction::NOT: case Instruction::NOT:
case Instruction::CALLDATALOAD: case Instruction::CALLDATALOAD:
case Instruction::EXTCODESIZE: case Instruction::EXTCODESIZE:
@ -262,6 +265,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::XOR: case Instruction::XOR:
case Instruction::BYTE: case Instruction::BYTE:
case Instruction::JUMPI: case Instruction::JUMPI:
case Instruction::SIGNEXTEND:
require(2); require(2);
break; break;
case Instruction::ADDMOD: case Instruction::ADDMOD:
@ -368,8 +372,8 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256);
break; break;
} }
case Instruction::NEG: case Instruction::BNOT:
m_stack.back() = ~(m_stack.back() - 1); m_stack.back() = ~m_stack.back();
break; break;
case Instruction::LT: case Instruction::LT:
m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0;
@ -420,6 +424,22 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.pop_back(); m_stack.pop_back();
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::SIGNEXTEND:
{
unsigned k = m_stack[m_stack.size() - 2];
if (k > 31)
m_stack[m_stack.size() - 2] = m_stack.back();
else
{
u256 b = m_stack.back();
if ((b >> (k * 8)) & 0x80)
for (int i = 31; i > k; --i)
b |= (u256(0xff) << i);
m_stack[m_stack.size() - 2] = b;
}
m_stack.pop_back();
break;
}
case Instruction::SHA3: case Instruction::SHA3:
{ {
unsigned inOff = (unsigned)m_stack.back(); unsigned inOff = (unsigned)m_stack.back();

6
libevmface/Instruction.cpp

@ -39,7 +39,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "MOD", Instruction::MOD }, { "MOD", Instruction::MOD },
{ "SMOD", Instruction::SMOD }, { "SMOD", Instruction::SMOD },
{ "EXP", Instruction::EXP }, { "EXP", Instruction::EXP },
{ "NEG", Instruction::NEG }, { "BNOT", Instruction::BNOT },
{ "LT", Instruction::LT }, { "LT", Instruction::LT },
{ "GT", Instruction::GT }, { "GT", Instruction::GT },
{ "SLT", Instruction::SLT }, { "SLT", Instruction::SLT },
@ -52,6 +52,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "BYTE", Instruction::BYTE }, { "BYTE", Instruction::BYTE },
{ "ADDMOD", Instruction::ADDMOD }, { "ADDMOD", Instruction::ADDMOD },
{ "MULMOD", Instruction::MULMOD }, { "MULMOD", Instruction::MULMOD },
{ "SIGNEXTEND", Instruction::SIGNEXTEND },
{ "SHA3", Instruction::SHA3 }, { "SHA3", Instruction::SHA3 },
{ "ADDRESS", Instruction::ADDRESS }, { "ADDRESS", Instruction::ADDRESS },
{ "BALANCE", Instruction::BALANCE }, { "BALANCE", Instruction::BALANCE },
@ -166,7 +167,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::MOD, { "MOD", 0, 2, 1 } }, { Instruction::MOD, { "MOD", 0, 2, 1 } },
{ Instruction::SMOD, { "SMOD", 0, 2, 1 } }, { Instruction::SMOD, { "SMOD", 0, 2, 1 } },
{ Instruction::EXP, { "EXP", 0, 2, 1 } }, { Instruction::EXP, { "EXP", 0, 2, 1 } },
{ Instruction::NEG, { "NEG", 0, 1, 1 } }, { Instruction::BNOT, { "BNOT", 0, 1, 1 } },
{ Instruction::LT, { "LT", 0, 2, 1 } }, { Instruction::LT, { "LT", 0, 2, 1 } },
{ Instruction::GT, { "GT", 0, 2, 1 } }, { Instruction::GT, { "GT", 0, 2, 1 } },
{ Instruction::SLT, { "SLT", 0, 2, 1 } }, { Instruction::SLT, { "SLT", 0, 2, 1 } },
@ -179,6 +180,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::BYTE, { "BYTE", 0, 2, 1 } }, { Instruction::BYTE, { "BYTE", 0, 2, 1 } },
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1 } }, { Instruction::ADDMOD, { "ADDMOD", 0, 3, 1 } },
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1 } }, { Instruction::MULMOD, { "MULMOD", 0, 3, 1 } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1 } },
{ Instruction::SHA3, { "SHA3", 0, 2, 1 } }, { Instruction::SHA3, { "SHA3", 0, 2, 1 } },
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } }, { Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } },
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1 } }, { Instruction::BALANCE, { "BALANCE", 0, 1, 1 } },

3
libevmface/Instruction.h

@ -44,7 +44,7 @@ enum class Instruction: uint8_t
MOD, ///< modulo remainder operation MOD, ///< modulo remainder operation
SMOD, ///< signed modulo remainder operation SMOD, ///< signed modulo remainder operation
EXP, ///< exponential operation EXP, ///< exponential operation
NEG, ///< negation operation BNOT, ///< bitwise not
LT, ///< less-than comparision LT, ///< less-than comparision
GT, ///< greater-than comparision GT, ///< greater-than comparision
SLT, ///< signed less-than comparision SLT, ///< signed less-than comparision
@ -58,6 +58,7 @@ enum class Instruction: uint8_t
BYTE, ///< retrieve single byte from word BYTE, ///< retrieve single byte from word
ADDMOD, ///< unsigned modular addition ADDMOD, ///< unsigned modular addition
MULMOD, ///< unsigned modular multiplication MULMOD, ///< unsigned modular multiplication
SIGNEXTEND, ///< extend length of signed integer
SHA3 = 0x20, ///< compute SHA3-256 hash SHA3 = 0x20, ///< compute SHA3-256 hash
ADDRESS = 0x30, ///< get address of currently executing account ADDRESS = 0x30, ///< get address of currently executing account

2
libp2p/Host.cpp

@ -369,7 +369,7 @@ void Host::populateAddresses()
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{ {
RecursiveGuard l(x_peers); RecursiveGuard l(x_peers);
if (_a.port() < 30300 && _a.port() > 30303) if (_a.port() < 30300 || _a.port() > 30303)
cwarn << "Wierd port being recorded!"; cwarn << "Wierd port being recorded!";
if (_a.port() >= /*49152*/32768) if (_a.port() >= /*49152*/32768)

95
libqethereum/QEthereum.cpp

@ -1,3 +1,25 @@
/*
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 QEthereum.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <boost/filesystem.hpp>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <QtWebKitWidgets/QWebFrame> #include <QtWebKitWidgets/QWebFrame>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
@ -536,8 +558,9 @@ void QEthereum::poll()
// TODO: repot and hook all these up. // TODO: repot and hook all these up.
QWhisper::QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c): QObject(_p), m_face(_c) QWhisper::QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c, QList<dev::KeyPair> _ids): QObject(_p), m_face(_c)
{ {
setIdentities(_ids);
} }
QWhisper::~QWhisper() QWhisper::~QWhisper()
@ -613,6 +636,14 @@ void QWhisper::doPost(QString _json)
face()->inject(toSealed(_json, m, from)); face()->inject(toSealed(_json, m, from));
} }
void QWhisper::setIdentities(QList<dev::KeyPair> const& _l)
{
m_ids.clear();
for (auto i: _l)
m_ids[i.pub()] = i.secret();
emit idsChanged();
}
static pair<shh::TopicMask, Public> toWatch(QString _json) static pair<shh::TopicMask, Public> toWatch(QString _json)
{ {
shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); shh::BuildTopicMask bt(shh::BuildTopicMask::Empty);
@ -714,11 +745,24 @@ QString QWhisper::newIdentity()
Public QWhisper::makeIdentity() Public QWhisper::makeIdentity()
{ {
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
m_ids[kp.pub()] = kp.sec(); emit newIdToAdd(toQJS(kp.sec()));
emit idsChanged();
return kp.pub(); return kp.pub();
} }
QString QWhisper::newGroup(QString _me, QString _others)
{
(void)_me;
(void)_others;
return "";
}
QString QWhisper::addToGroup(QString _group, QString _who)
{
(void)_group;
(void)_who;
return "";
}
void QWhisper::poll() void QWhisper::poll()
{ {
for (auto const& w: m_watches) for (auto const& w: m_watches)
@ -740,6 +784,51 @@ void QWhisper::poll()
} }
} }
#include <libdevcrypto/FileSystem.h>
QLDB::QLDB(QObject* _p): QObject(_p)
{
auto path = getDataDir() + "/.web3";
boost::filesystem::create_directories(path);
ldb::Options o;
o.create_if_missing = true;
ldb::DB::Open(o, path, &m_db);
}
QLDB::~QLDB()
{
}
void QLDB::put(QString _p, QString _k, QString _v)
{
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes();
bytes v = toBytes(_v);
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
}
QString QLDB::get(QString _p, QString _k)
{
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes();
string ret;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
return toQJS(dev::asBytes(ret));
}
void QLDB::putString(QString _p, QString _k, QString _v)
{
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes();
string v = _v.toStdString();
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
}
QString QLDB::getString(QString _p, QString _k)
{
bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes();
string ret;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
return QString::fromStdString(ret);
}
// extra bits needed to link on VS // extra bits needed to link on VS
#ifdef _MSC_VER #ifdef _MSC_VER

67
libqethereum/QEthereum.h

@ -1,11 +1,39 @@
/*
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 QEthereum.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once #pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QList> #include <QtCore/QList>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
namespace ldb = leveldb;
namespace dev { namespace dev {
namespace eth { namespace eth {
class Interface; class Interface;
@ -214,12 +242,14 @@ class QWhisper: public QObject
Q_OBJECT Q_OBJECT
public: public:
QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c); QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c, QList<dev::KeyPair> _ids);
virtual ~QWhisper(); virtual ~QWhisper();
std::shared_ptr<dev::shh::Interface> face() const; std::shared_ptr<dev::shh::Interface> face() const;
void setFace(std::shared_ptr<dev::shh::Interface> const& _c) { m_face = _c; } void setFace(std::shared_ptr<dev::shh::Interface> const& _c) { m_face = _c; }
void setIdentities(QList<dev::KeyPair> const& _l);
/// Call when the face() is going to be deleted to make this object useless but safe. /// Call when the face() is going to be deleted to make this object useless but safe.
void faceDieing(); void faceDieing();
@ -230,6 +260,9 @@ public:
Q_INVOKABLE QString newIdentity(); Q_INVOKABLE QString newIdentity();
Q_INVOKABLE QString newGroup(QString _id, QString _who);
Q_INVOKABLE QString addToGroup(QString _group, QString _who);
// Watches interface // Watches interface
Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE unsigned newWatch(QString _json);
Q_INVOKABLE void killWatch(unsigned _w); Q_INVOKABLE void killWatch(unsigned _w);
@ -247,6 +280,7 @@ public slots:
signals: signals:
void watchChanged(unsigned _w, QString _envelopeJson); void watchChanged(unsigned _w, QString _envelopeJson);
void idsChanged(); void idsChanged();
void newIdToAdd(QString _id);
private: private:
std::weak_ptr<dev::shh::Interface> m_face; std::weak_ptr<dev::shh::Interface> m_face;
@ -255,16 +289,41 @@ private:
std::map<dev::Public, dev::Secret> m_ids; std::map<dev::Public, dev::Secret> m_ids;
}; };
class QLDB: public QObject
{
Q_OBJECT
public:
QLDB(QObject* _p);
~QLDB();
Q_INVOKABLE void put(QString _name, QString _key, QString _value);
Q_INVOKABLE QString get(QString _name, QString _key);
Q_INVOKABLE void putString(QString _name, QString _key, QString _value);
Q_INVOKABLE QString getString(QString _name, QString _key);
private:
ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions;
ldb::DB* m_db;
};
// TODO: add p2p object // TODO: add p2p object
#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh) [_frame, _env, _web3, _eth, _shh]() \ #define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh, _ldb) [_frame, _env, _web3, _eth, _shh, _ldb]() \
{ \ { \
_frame->disconnect(); \ _frame->disconnect(); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->addToJavaScriptWindowObject("web3", _web3, QWebFrame::ScriptOwnership); \ _frame->addToJavaScriptWindowObject("web3", _web3, QWebFrame::ScriptOwnership); \
if (_ldb) \
{ \
_frame->addToJavaScriptWindowObject("_web3_dot_db", _ldb, QWebFrame::QtOwnership); \
_frame->evaluateJavaScript("web3.db = _web3_dot_db"); \
} \
if (_eth) \ if (_eth) \
{ \ { \
_frame->addToJavaScriptWindowObject("_web3_dot_eth", _eth, QWebFrame::ScriptOwnership); \ _frame->addToJavaScriptWindowObject("_web3_dot_eth", _eth, QWebFrame::ScriptOwnership); \
_frame->evaluateJavaScript("_web3_dot_eth.makeWatch = function(a) { var ww = _web3_dot_eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_eth.killWatch(w); }; ret.changed = function(f) { _web3_dot_eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_eth.watchMessages(this.w)) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_eth.makeWatch = function(a) { var ww = _web3_dot_eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_eth.killWatch(this.w); }; ret.changed = function(f) { _web3_dot_eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_eth.watchMessages(this.w)) }; return ret; }"); \
_frame->evaluateJavaScript("_web3_dot_eth.watch = function(a) { return _web3_dot_eth.makeWatch(JSON.stringify(a)) }"); \ _frame->evaluateJavaScript("_web3_dot_eth.watch = function(a) { return _web3_dot_eth.makeWatch(JSON.stringify(a)) }"); \
_frame->evaluateJavaScript("_web3_dot_eth.transact = function(a, f) { var r = _web3_dot_eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ _frame->evaluateJavaScript("_web3_dot_eth.transact = function(a, f) { var r = _web3_dot_eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \
_frame->evaluateJavaScript("_web3_dot_eth.call = function(a, f) { var ret = _web3_dot_eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_eth.call = function(a, f) { var ret = _web3_dot_eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \
@ -277,7 +336,7 @@ private:
if (_shh) \ if (_shh) \
{ \ { \
_frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \ _frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \
_frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(ww)); for (var e in existing) f(existing[e]) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(this.w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(this.w)); for (var e in existing) f(existing[e]) }; return ret; }"); \
_frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \ _frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \
_frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \ _frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \
_frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \ _frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \

4
test/MemTrie.cpp

@ -437,12 +437,12 @@ MemTrie::~MemTrie()
h256 MemTrie::hash256() const h256 MemTrie::hash256() const
{ {
return m_root ? m_root->hash256() : h256(); return m_root ? m_root->hash256() : sha3(dev::rlp(bytesConstRef()));
} }
bytes MemTrie::rlp() const bytes MemTrie::rlp() const
{ {
return m_root ? m_root->rlp() : bytes(); return m_root ? m_root->rlp() : dev::rlp(bytesConstRef());
} }
void MemTrie::debugPrint() void MemTrie::debugPrint()

6
test/TrieHash.cpp

@ -162,7 +162,7 @@ h256 hash256(StringMap const& _s)
{ {
// build patricia tree. // build patricia tree.
if (_s.empty()) if (_s.empty())
return h256(); return sha3(rlp(""));
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
@ -175,7 +175,7 @@ bytes rlp256(StringMap const& _s)
{ {
// build patricia tree. // build patricia tree.
if (_s.empty()) if (_s.empty())
return bytes(); return rlp("");
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
@ -188,7 +188,7 @@ h256 hash256(u256Map const& _s)
{ {
// build patricia tree. // build patricia tree.
if (_s.empty()) if (_s.empty())
return h256(); return sha3(rlp(""));
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second)); hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second));

3
test/crypto.cpp

@ -377,6 +377,7 @@ BOOST_AUTO_TEST_CASE(eth_keypairs)
{ {
eth::Transaction t; eth::Transaction t;
t.nonce = 0; t.nonce = 0;
t.type = eth::Transaction::MessageCall;
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000; t.value = 1000;
auto rlp = t.rlp(false); auto rlp = t.rlp(false);
@ -405,6 +406,7 @@ int cryptoTest()
{ {
eth::Transaction t; eth::Transaction t;
t.nonce = 0; t.nonce = 0;
t.type = eth::Transaction::MessageCall;
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000; t.value = 1000;
auto rlp = t.rlp(false); auto rlp = t.rlp(false);
@ -433,6 +435,7 @@ int cryptoTest()
Transaction t; Transaction t;
t.nonce = 0; t.nonce = 0;
t.value = 1; // 1 wei. t.value = 1; // 1 wei.
t.type = eth::Transaction::MessageCall;
t.receiveAddress = toAddress(sha3("123")); t.receiveAddress = toAddress(sha3("123"));
bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s); bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s);

1
test/state.cpp

@ -68,6 +68,7 @@ int stateTest()
Transaction t; Transaction t;
t.nonce = s.transactionsFrom(myMiner.address()); t.nonce = s.transactionsFrom(myMiner.address());
t.value = 1000; // 1e3 wei. t.value = 1000; // 1e3 wei.
t.type = eth::Transaction::MessageCall;
t.receiveAddress = me.address(); t.receiveAddress = me.address();
t.sign(myMiner.secret()); t.sign(myMiner.secret());
assert(t.sender() == myMiner.address()); assert(t.sender() == myMiner.address());

31
test/vm.cpp

@ -45,7 +45,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
@ -56,14 +56,13 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
get<3>(addresses[ret]) = m_s.code(ret); get<3>(addresses[ret]) = m_s.code(ret);
} }
t.receiveAddress = ret; t.type = eth::Transaction::ContractCreation;
callcreates.push_back(t); callcreates.push_back(t);
return ret; return ret;
} }
bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride) bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride)
{ {
u256 contractgas = 0xffff; u256 contractgas = 0xffff;
Transaction t; Transaction t;
@ -71,6 +70,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
t.gasPrice = gasPrice; t.gasPrice = gasPrice;
t.gas = *_gas; t.gas = *_gas;
t.data = _data.toVector(); t.data = _data.toVector();
t.type = eth::Transaction::MessageCall;
t.receiveAddress = _receiveAddress; t.receiveAddress = _receiveAddress;
callcreates.push_back(t); callcreates.push_back(t);
@ -91,7 +91,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!m_s.addresses().count(myAddress)) if (!m_s.addresses().count(myAddress))
{ {
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
if (na != myAddress) if (na != myAddress)
@ -116,7 +116,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{ {
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
@ -131,7 +131,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
m_ms.internal.resize(m_ms.internal.size() + 1); m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1); auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), OnOpFunc(), 1);
if (!m_ms.internal.back().from) if (!m_ms.internal.back().from)
m_ms.internal.pop_back(); m_ms.internal.pop_back();
@ -146,12 +146,15 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!ret) if (!ret)
return false; return false;
// TODO: @CJentzsch refund SSTORE stuff.
// TODO: @CJentzsch test logs.
// do suicides // do suicides
for (auto const& f: suicides) for (auto const& f: sub.suicides)
addresses.erase(f); addresses.erase(f);
// get storage // get storage
if ((get<0>(addresses[myAddress]) >= _value) && (suicides.find(_receiveAddress) == suicides.end())) if ((get<0>(addresses[myAddress]) >= _value) && (sub.suicides.find(_receiveAddress) == sub.suicides.end()))
{ {
for (auto const& j: m_s.storage(_receiveAddress)) for (auto const& j: m_s.storage(_receiveAddress))
{ {
@ -384,7 +387,7 @@ mArray FakeExtVM::exportCallCreates()
for (Transaction const& tx: callcreates) for (Transaction const& tx: callcreates)
{ {
mObject o; mObject o;
o["destination"] = toString(tx.receiveAddress); o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress);
push(o, "gasLimit", tx.gas); push(o, "gasLimit", tx.gas);
push(o, "value", tx.value); push(o, "value", tx.value);
o["data"] = "0x" + toHex(tx.data); o["data"] = "0x" + toHex(tx.data);
@ -403,6 +406,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("destination") > 0);
BOOST_REQUIRE(tx.count("gasLimit") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0);
Transaction t; Transaction t;
t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall;
t.receiveAddress = Address(tx["destination"].get_str()); t.receiveAddress = Address(tx["destination"].get_str());
t.value = toInt(tx["value"]); t.value = toInt(tx["value"]);
t.gas = toInt(tx["gasLimit"]); t.gas = toInt(tx["gasLimit"]);
@ -418,8 +422,11 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
} }
} }
h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) // THIS IS BROKEN AND NEEDS TO BE REMOVED.
h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{ {
(void)o_sub;
if (!_origin) if (!_origin)
_origin = _sender; _origin = _sender;
@ -445,9 +452,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
out = vm.go(evm, _onOp); out = vm.go(evm, _onOp);
if (o_ms) if (o_ms)
o_ms->output = out.toBytes(); o_ms->output = out.toBytes();
if (o_suicides) // TODO: deal with evm.sub
for (auto i: evm.suicides)
o_suicides->insert(i);
} }
catch (OutOfGas const& /*_e*/) catch (OutOfGas const& /*_e*/)
{ {

2
test/vm.h

@ -44,7 +44,7 @@ class FakeState: public eth::State
{ {
public: public:
/// Execute a contract-creation transaction. /// Execute a contract-creation transaction.
h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, std::set<Address>* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0); h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0);
}; };
class FakeExtVM: public eth::ExtVMFace class FakeExtVM: public eth::ExtVMFace

9
third/MainWin.cpp

@ -102,19 +102,22 @@ Main::Main(QWidget *parent) :
m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"})); m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"}));
m_web3->connect(Host::pocHost()); m_web3->connect(Host::pocHost());
m_ldb = new QLDB(this);
connect(ui->webView, &QWebView::loadStarted, [this]() connect(ui->webView, &QWebView::loadStarted, [this]()
{ {
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this); m_dev = new QDev(this);
m_ethereum = new QEthereum(this, ethereum(), owned()); m_ethereum = new QEthereum(this, ethereum(), m_myKeys);
m_whisper = new QWhisper(this, whisper()); m_whisper = new QWhisper(this, whisper(), owned());
QWebFrame* f = ui->webView->page()->mainFrame(); QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qdev = m_dev; auto qdev = m_dev;
auto qeth = m_ethereum; auto qeth = m_ethereum;
auto qshh = m_whisper; auto qshh = m_whisper;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); auto qldb = m_ldb;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb));
}); });
connect(ui->webView, &QWebView::loadFinished, [=]() connect(ui->webView, &QWebView::loadFinished, [=]()

6
third/MainWin.h

@ -61,8 +61,8 @@ public:
dev::eth::Client* ethereum() const; dev::eth::Client* ethereum() const;
std::shared_ptr<dev::shh::WhisperHost> whisper() const; std::shared_ptr<dev::shh::WhisperHost> whisper() const;
QList<dev::KeyPair> const& owned() const { return m_myKeys; } QList<dev::KeyPair> owned() const { return m_myKeys + m_myIdentities; }
public slots: public slots:
void note(QString _entry); void note(QString _entry);
void debug(QString _entry); void debug(QString _entry);
@ -121,6 +121,7 @@ private:
std::unique_ptr<dev::WebThreeDirect> m_web3; std::unique_ptr<dev::WebThreeDirect> m_web3;
QList<dev::KeyPair> m_myKeys; QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities;
std::map<unsigned, std::function<void()>> m_handlers; std::map<unsigned, std::function<void()>> m_handlers;
unsigned m_nameRegFilter = (unsigned)-1; unsigned m_nameRegFilter = (unsigned)-1;
@ -135,4 +136,5 @@ private:
QDev* m_dev = nullptr; QDev* m_dev = nullptr;
QEthereum* m_ethereum = nullptr; QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr; QWhisper* m_whisper = nullptr;
QLDB* m_ldb = nullptr;
}; };

Loading…
Cancel
Save