Browse Source

Merge remote-tracking branch 'ethereum/develop' into sol_contractCompiler

Conflicts:
	libsolidity/Types.cpp
cl-refactor
Christian 10 years ago
parent
commit
c98204beab
  1. 257
      alethzero/Main.ui
  2. 317
      alethzero/MainWin.cpp
  3. 15
      alethzero/MainWin.h
  4. 6
      libdevcore/CMakeLists.txt
  5. 2
      libdevcore/Common.cpp
  6. 30
      libdevcore/CommonData.h
  7. 21
      libdevcore/FixedHash.h
  8. 3
      libdevcrypto/All.h
  9. 4
      libdevcrypto/Common.cpp
  10. 6
      libdevcrypto/CryptoPP.h
  11. 8
      libdevcrypto/EC.cpp
  12. 3
      libdevcrypto/SHA3.cpp
  13. 3
      libdevcrypto/TrieDB.cpp
  14. 7
      libdevcrypto/TrieDB.h
  15. 40
      libethcore/BlockInfo.cpp
  16. 13
      libethcore/BlockInfo.h
  17. 2
      libethcore/CommonEth.cpp
  18. 3
      libethcore/Exceptions.h
  19. 7
      libethereum/BlockChain.cpp
  20. 2
      libethereum/BlockDetails.h
  21. 5
      libethereum/Client.cpp
  22. 2
      libethereum/Client.h
  23. 15
      libethereum/Executive.cpp
  24. 3
      libethereum/Executive.h
  25. 4
      libethereum/ExtVM.h
  26. 4
      libethereum/Manifest.cpp
  27. 2
      libethereum/Manifest.h
  28. 4
      libethereum/MessageFilter.cpp
  29. 2
      libethereum/MessageFilter.h
  30. 150
      libethereum/State.cpp
  31. 75
      libethereum/State.h
  32. 5
      libethereum/Transaction.cpp
  33. 17
      libethereum/Transaction.h
  34. 58
      libevm/ExtVMFace.h
  35. 4
      libevm/FeeStructure.cpp
  36. 4
      libevm/FeeStructure.h
  37. 1
      libevm/VM.cpp
  38. 84
      libevm/VM.h
  39. 19
      libevmface/CMakeLists.txt
  40. 16
      libevmface/Instruction.cpp
  41. 9
      libevmface/Instruction.h
  42. 4
      liblll/Assembly.cpp
  43. 6
      liblll/Assembly.h
  44. 46
      libp2p/Host.cpp
  45. 2
      libp2p/Host.h
  46. 1
      libp2p/Session.cpp
  47. 12
      libpyserpent/pyserpent.cpp
  48. 266
      libqethereum/QEthereum.cpp
  49. 95
      libqethereum/QEthereum.h
  50. 32
      libserpent/compiler.cpp
  51. 12
      libserpent/funcs.cpp
  52. 6
      libserpent/funcs.h
  53. 4
      libserpent/opcodes.h
  54. 24
      libserpent/parser.cpp
  55. 60
      libserpent/rewriter.cpp
  56. 3
      libserpent/rewriter.h
  57. 6
      libserpent/util.cpp
  58. 27
      libsolidity/CMakeLists.txt
  59. 1
      libsolidity/Types.cpp
  60. 18
      libwhisper/Common.cpp
  61. 8
      libwhisper/Common.h
  62. 30
      libwhisper/Interface.h
  63. 20
      libwhisper/Message.cpp
  64. 22
      libwhisper/Message.h
  65. 44
      libwhisper/WhisperHost.cpp
  66. 20
      libwhisper/WhisperHost.h
  67. 205
      sc/cmdline.cpp
  68. 17
      solc/CMakeLists.txt
  69. 21
      solc/main.cpp
  70. 4
      test/MemTrie.cpp
  71. 6
      test/TrieHash.cpp
  72. 3
      test/crypto.cpp
  73. 13
      test/genesis.cpp
  74. 13
      test/hexPrefix.cpp
  75. 2
      test/main.cpp
  76. 13
      test/rlp.cpp
  77. 1
      test/state.cpp
  78. 13
      test/trie.cpp
  79. 71
      test/vm.cpp
  80. 36
      test/vm.h
  81. 12
      third/MainWin.cpp
  82. 6
      third/MainWin.h
  83. 6
      windows/LibEthereum.vcxproj
  84. 18
      windows/LibEthereum.vcxproj.filters

257
alethzero/Main.ui

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1711</width>
<height>1138</height>
<width>1617</width>
<height>1371</height>
</rect>
</property>
<property name="windowTitle">
@ -116,7 +116,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1711</width>
<width>1617</width>
<height>25</height>
</rect>
</property>
@ -204,11 +204,18 @@
<addaction name="debugStepBackInto"/>
<addaction name="debugStepBackOut"/>
</widget>
<widget class="QMenu" name="menuWhispe">
<property name="title">
<string>&amp;Whisper</string>
</property>
<addaction name="newIdentity"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_View"/>
<addaction name="menu_Network"/>
<addaction name="menu_Tools"/>
<addaction name="menuDebugger"/>
<addaction name="menuWhispe"/>
<addaction name="menu_Debug"/>
<addaction name="menu_Help"/>
</widget>
@ -1514,6 +1521,242 @@ font-size: 14pt</string>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_14">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Whisper</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_14">
<layout class="QGridLayout" name="gridLayout_4">
<item row="2" column="4">
<widget class="QSpinBox" name="shhWork">
<property name="suffix">
<string> ms</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>50</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Topic</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="3" column="1" colspan="4">
<widget class="QPlainTextEdit" name="shhTopic">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</item>
<item row="5" column="1" colspan="4">
<widget class="QPlainTextEdit" name="shhData">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</item>
<item row="6" column="4">
<widget class="QPushButton" name="post">
<property name="text">
<string>Post</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label5_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>TTL</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label5_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>From</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label5_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>To</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="4">
<widget class="QComboBox" name="shhFrom">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<widget class="QComboBox" name="shhTo">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0" rowspan="2">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Data</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="shhTtl">
<property name="suffix">
<string> seconds</string>
</property>
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>259200</number>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QLabel" name="label5_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Work to Prove</string>
</property>
<property name="buddy">
<cstring>destination</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_15">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Active Whispers</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_15">
<layout class="QHBoxLayout" name="horizontalLayout_11">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="whispers">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="quit">
<property name="text">
<string>&amp;Quit</string>
@ -1789,6 +2032,9 @@ font-size: 14pt</string>
</property>
</action>
<action name="importKeyFile">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Claim Ether Presale &amp;Wallet...</string>
</property>
@ -1798,6 +2044,11 @@ font-size: 14pt</string>
<string>Go!</string>
</property>
</action>
<action name="newIdentity">
<property name="text">
<string>New Identity</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

317
alethzero/MainWin.cpp

@ -131,13 +131,16 @@ Main::Main(QWidget *parent) :
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_ldb = new QLDB(this);
connect(ui->webView, &QWebView::loadStarted, [this]()
{
m_ethereum = nullptr;
m_whisper = nullptr;
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this);
m_ethereum = new QEthereum(this, ethereum(), owned());
m_whisper = new QWhisper(this, whisper());
m_ethereum = new QEthereum(this, ethereum(), m_myKeys);
m_whisper = new QWhisper(this, whisper(), owned());
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebFrame* f = ui->webView->page()->mainFrame();
@ -145,12 +148,15 @@ Main::Main(QWidget *parent) :
auto qdev = m_dev;
auto qeth = m_ethereum;
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(m_whisper, SIGNAL(newIdToAdd(QString)), this, SLOT(addNewId(QString)));
});
connect(ui->webView, &QWebView::loadFinished, [=]()
{
m_ethereum->poll();
m_whisper->poll();
});
connect(ui->webView, &QWebView::titleChanged, [=]()
@ -179,11 +185,20 @@ Main::~Main()
// Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor)
// *after* the client is dead.
m_ethereum->clientDieing();
m_whisper->faceDieing();
g_logPost = simpleDebugOut;
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
{
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked());
@ -331,8 +346,6 @@ void Main::load(QString _s)
}
}
// env.load("/home/gav/eth/init.eth")
void Main::on_loadJS_triggered()
{
QString f = QFileDialog::getOpenFileName(this, "Load Javascript", QString(), "Javascript (*.js);;All files (*)");
@ -387,6 +400,17 @@ void Main::eval(QString const& _js)
ui->jsConsole->setHtml(s);
}
static Public stringToPublic(QString const& _a)
{
string sn = _a.toStdString();
if (_a.size() == sizeof(Public) * 2)
return Public(fromHex(_a.toStdString()));
else if (_a.size() == sizeof(Public) * 2 + 2 && _a.startsWith("0x"))
return Public(fromHex(_a.mid(2).toStdString()));
else
return Public();
}
QString Main::pretty(dev::Address _a) const
{
h256 n;
@ -481,15 +505,28 @@ void Main::on_paranoia_triggered()
void Main::writeSettings()
{
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));
p += sizeof(Secret);
QByteArray b;
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("forceAddress", ui->forceAddress->text());
@ -525,21 +562,39 @@ void Main::readSettings(bool _skipGeometry)
restoreGeometry(s.value("geometry").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;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
m_myKeys.clear();
QByteArray b = s.value("address").toByteArray();
if (b.isEmpty())
m_myKeys.append(KeyPair::create());
else
{
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k)))
m_myKeys.append(KeyPair(k));
h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
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();
ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString());
@ -553,6 +608,8 @@ void Main::readSettings(bool _skipGeometry)
m_enableOptimizer = s.value("enableOptimizer", true).toBool();
ui->enableOptimizer->setChecked(m_enableOptimizer);
ui->clientName->setText(s.value("clientName", "").toString());
if (ui->clientName->text().isEmpty())
ui->clientName->setText(QInputDialog::getText(this, "Enter identity", "Enter a name that will identify you on the peer network"));
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString());
@ -752,7 +809,6 @@ void Main::refreshNetwork()
{
auto ps = web3()->peers();
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
ui->peers->clear();
ui->nodes->clear();
@ -995,12 +1051,15 @@ void Main::timerEvent(QTimerEvent*)
{
interval = 0;
refreshNetwork();
refreshWhispers();
}
else
interval += 100;
if (m_ethereum)
m_ethereum->poll();
if (m_whisper)
m_whisper->poll();
for (auto const& i: m_handlers)
if (ethereum()->checkWatch(i.first))
@ -1168,6 +1227,7 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Nonce: <b>" << info.nonce << "</b>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>";
s << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Log Bloom: <b>" << info.logBloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
if (info.parentHash)
@ -1382,6 +1442,112 @@ void Main::on_destination_currentTextChanged()
// updateFee();
}
static bytes dataFromText(QString _s)
{
bytes ret;
while (_s.size())
{
QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?");
QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?");
QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?");
if (r.exactMatch(_s))
{
for (auto i: r.cap(2))
ret.push_back((byte)i.toLatin1());
if (r.cap(1) != "$")
for (int i = r.cap(2).size(); i < 32; ++i)
ret.push_back(0);
else
ret.push_back(0);
_s = r.cap(3);
}
else if (d.exactMatch(_s))
{
u256 v(d.cap(2).toStdString());
if (d.cap(6) == "szabo")
v *= dev::eth::szabo;
else if (d.cap(5) == "finney")
v *= dev::eth::finney;
else if (d.cap(4) == "ether")
v *= dev::eth::ether;
bytes bs = dev::toCompactBigEndian(v);
if (d.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
ret.push_back(0);
for (auto b: bs)
ret.push_back(b);
_s = d.cap(7);
}
else if (h.exactMatch(_s))
{
bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString());
if (h.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
ret.push_back(0);
for (auto b: bs)
ret.push_back(b);
_s = h.cap(5);
}
else
_s = _s.mid(1);
}
return ret;
}
static shh::Topic topicFromText(QString _s)
{
shh::BuildTopic ret;
while (_s.size())
{
QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?");
QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?");
QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?");
bytes part;
if (r.exactMatch(_s))
{
for (auto i: r.cap(2))
part.push_back((byte)i.toLatin1());
if (r.cap(1) != "$")
for (int i = r.cap(2).size(); i < 32; ++i)
part.push_back(0);
else
part.push_back(0);
_s = r.cap(3);
}
else if (d.exactMatch(_s))
{
u256 v(d.cap(2).toStdString());
if (d.cap(6) == "szabo")
v *= dev::eth::szabo;
else if (d.cap(5) == "finney")
v *= dev::eth::finney;
else if (d.cap(4) == "ether")
v *= dev::eth::ether;
bytes bs = dev::toCompactBigEndian(v);
if (d.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
part.push_back(0);
for (auto b: bs)
part.push_back(b);
_s = d.cap(7);
}
else if (h.exactMatch(_s))
{
bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString());
if (h.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
part.push_back(0);
for (auto b: bs)
part.push_back(b);
_s = h.cap(5);
}
else
_s = _s.mid(1);
ret.shift(part);
}
return ret;
}
void Main::on_data_textChanged()
{
m_pcWarp.clear();
@ -1436,54 +1602,7 @@ void Main::on_data_textChanged()
}
else
{
m_data.clear();
QString s = ui->data->toPlainText();
while (s.size())
{
QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?");
QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?");
QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?");
if (r.exactMatch(s))
{
for (auto i: r.cap(2))
m_data.push_back((byte)i.toLatin1());
if (r.cap(1) != "$")
for (int i = r.cap(2).size(); i < 32; ++i)
m_data.push_back(0);
else
m_data.push_back(0);
s = r.cap(3);
}
else if (d.exactMatch(s))
{
u256 v(d.cap(2).toStdString());
if (d.cap(6) == "szabo")
v *= dev::eth::szabo;
else if (d.cap(5) == "finney")
v *= dev::eth::finney;
else if (d.cap(4) == "ether")
v *= dev::eth::ether;
bytes bs = dev::toCompactBigEndian(v);
if (d.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
m_data.push_back(0);
for (auto b: bs)
m_data.push_back(b);
s = d.cap(7);
}
else if (h.exactMatch(s))
{
bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString());
if (h.cap(1) != "$")
for (auto i = bs.size(); i < 32; ++i)
m_data.push_back(0);
for (auto b: bs)
m_data.push_back(b);
s = h.cap(5);
}
else
s = s.mid(1);
}
m_data = dataFromText(ui->data->toPlainText());
ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true)));
if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size())
{
@ -1666,6 +1785,7 @@ void Main::on_debug_clicked()
t.gasPrice = gasPrice();
t.gas = ui->gas->value();
t.data = m_data;
t.type = isCreation() ? Transaction::ContractCreation : Transaction::MessageCall;
t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText());
t.sign(s);
auto r = t.rlp();
@ -2012,6 +2132,59 @@ void Main::updateDebugger()
}
}
void Main::on_post_clicked()
{
shh::Message m;
m.setTo(stringToPublic(ui->shhTo->currentText()));
m.setPayload(dataFromText(ui->shhData->toPlainText()));
Public f = stringToPublic(ui->shhFrom->currentText());
Secret from;
if (m_whisper->ids().count(f))
from = m_whisper->ids().at(f);
whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value()));
}
void Main::on_newIdentity_triggered()
{
m_whisper->makeIdentity();
}
void Main::refreshWhisper()
{
ui->shhFrom->clear();
for (auto i: m_whisper->ids())
ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref())));
}
void Main::refreshWhispers()
{
ui->whispers->clear();
for (auto const& w: whisper()->all())
{
shh::Envelope const& e = w.second;
shh::Message m;
for (pair<Public, Secret> const& i: m_whisper->ids())
if (!!(m = e.open(i.second)))
break;
if (!m)
m = e.open();
QString msg;
if (m.from())
// Good message.
msg = QString("{%1 -> %2} %3").arg(m.from() ? m.from().abridged().c_str() : "???").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str());
else if (m)
// Maybe message.
msg = QString("{%1 -> %2} %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "???").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str());
time_t ex = e.expiry();
QString t(ctime(&ex));
t.chop(1);
QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg);
ui->whispers->addItem(item);
}
}
// extra bits needed to link on VS
#ifdef _MSC_VER

15
alethzero/MainWin.h

@ -77,7 +77,7 @@ public:
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
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:
void load(QString _file);
@ -149,9 +149,15 @@ private slots:
void on_turboMining_triggered();
void on_go_triggered();
void on_importKeyFile_triggered();
void on_post_clicked();
void on_newIdentity_triggered();
void refreshWhisper();
void addNewId(QString);
signals:
void poll();
void idsChanged();
private:
dev::p2p::NetworkPreferences netPrefs() const;
@ -175,6 +181,8 @@ private:
void readSettings(bool _skipGeometry = false);
void writeSettings();
void keysChanged();
bool isCreation() const;
dev::u256 fee() const;
dev::u256 total() const;
@ -185,8 +193,6 @@ private:
unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f);
void uninstallWatch(unsigned _w);
void keysChanged();
void onNewPending();
void onNewBlock();
void onNameRegChange();
@ -202,6 +208,7 @@ private:
void refreshNetwork();
void refreshMining();
void refreshWhispers();
void refreshAll();
void refreshPending();
@ -223,6 +230,7 @@ private:
QByteArray m_peers;
QStringList m_servers;
QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities;
QString m_privateChain;
dev::bytes m_data;
dev::Address m_nameReg;
@ -250,4 +258,5 @@ private:
QDev* m_dev = nullptr;
QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr;
QLDB* m_ldb = nullptr;
};

6
libdevcore/CMakeLists.txt

@ -19,8 +19,6 @@ endif()
include_directories(..)
target_link_libraries(${EXECUTABLE} devcore)
if("${TARGET_PLATFORM}" STREQUAL "w64")
include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)
target_link_libraries(${EXECUTABLE} boost_system-mt-s)
@ -37,7 +35,9 @@ elseif (APPLE)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
elseif (UNIX)
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY})
find_package(Boost 1.53 REQUIRED COMPONENTS thread system)
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY})
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
else ()
target_link_libraries(${EXECUTABLE} boost_thread)

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.7.5";
char const* Version = "0.7.7";
}

30
libdevcore/CommonData.h

@ -190,7 +190,7 @@ void pushFront(_T& _t, _U _e)
_t[0] = _e;
}
/// Concatenate two vectors of elements. _T must be POD.
/// Concatenate two vectors of elements of POD types.
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)
{
@ -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>
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);
return ret += _b;
}
/// Concatenate two vectors of elements. _T must be POD.
/// Merge two sets of elements.
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)
_a.push_back(i);
_a.insert(i);
return _a;
}
/// Concatenate two vectors of elements. _T must be POD.
/// Merge two sets of elements.
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;
}

21
libdevcore/FixedHash.h

@ -59,7 +59,7 @@ public:
FixedHash() { m_data.fill(0); }
/// Construct from another hash, filling with zeroes or cropping as necessary.
template <unsigned M> FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; }
template <unsigned M> explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; }
/// Convert from the corresponding arithmetic type.
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
@ -158,6 +158,25 @@ public:
return ret;
}
template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h) { return (*this |= _h.template nbloom<P, N>()); }
template <unsigned P, unsigned M> inline FixedHash<M> nbloom() const
{
static const unsigned c_bloomBytes = (M + 7) / 8;
unsigned mask = (1 << c_bloomBytes) - 1;
FixedHash<M> ret;
byte const* p = data();
for (unsigned i = 0; i < P; ++i)
{
unsigned index = 0;
for (unsigned j = 0; j < c_bloomBytes; ++j, ++p)
index = (index << 8) | *p;
index &= mask;
ret[N - 1 - index / 8] |= (1 << (index % 8));
}
return ret;
}
/// Returns the index of the first bit set to one, or size() * 8 if no bits are set.
inline unsigned firstBitSet() const
{

3
libdevcrypto/All.h

@ -1,9 +1,12 @@
#pragma once
#include "Common.h"
#include "CryptoPP.h"
#include "EC.h"
#include "FileSystem.h"
#include "MemoryDB.h"
#include "OverlayDB.h"
#include "SHA3.h"
#include "SHA3MAC.h"
#include "TrieCommon.h"
#include "TrieDB.h"

4
libdevcrypto/Common.cpp

@ -144,7 +144,9 @@ Public dev::recover(Signature _sig, h256 _message)
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
#endif
return *(Public const*)&(pubkey[1]);
Public ret;
memcpy(&ret, &(pubkey[1]), sizeof(Public));
return ret;
}
inline h256 kFromMessage(h256 _msg, h256 _priv)

6
libdevcrypto/CryptoPP.h

@ -23,12 +23,11 @@
#pragma once
// need to leave this one disabled
//#pragma GCC diagnostic ignored "-Wunused-function"
// need to leave this one disabled for link-time. blame cryptopp.
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma warning(push)
#pragma warning(disable:4100 4244)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-variable"
@ -58,6 +57,7 @@ namespace crypto
namespace pp
{
/// RNG used by CryptoPP
inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; }

8
libdevcrypto/EC.cpp

@ -52,7 +52,7 @@ void dev::crypto::encrypt(Public const& _key, bytes& io_cipher)
c.resize(e.CiphertextLength(plen));
// todo: use StringSource with _plain as input and output.
e.Encrypt(pp::PRNG(), io_cipher.data(), plen, c.data());
bzero(io_cipher.data(), io_cipher.size());
memset(io_cipher.data(), 0, io_cipher.size());
io_cipher = std::move(c);
}
@ -66,7 +66,11 @@ void dev::crypto::decrypt(Secret const& _k, bytes& io_text)
p.resize(d.MaxPlaintextLength(io_text.size()));
// todo: use StringSource with _c as input and output.
DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data());
assert(r.messageLength);
if (!r.isValidCoding)
{
io_text.clear();
return;
}
io_text.resize(r.messageLength);
io_text = std::move(p);
}

3
libdevcrypto/SHA3.cpp

@ -20,8 +20,9 @@
*/
#include "SHA3.h"
#include "CryptoPP.h"
#include <libdevcore/RLP.h>
#include "CryptoPP.h"
using namespace std;
using namespace dev;

3
libdevcrypto/TrieDB.cpp

@ -26,6 +26,7 @@ using namespace dev;
#if !ETH_LANGUAGES
const h256 dev::c_shaNull = sha3(rlp(""));
h256 const dev::c_shaNull = sha3(rlp(""));
h256 const dev::EmptyTrie = c_shaNull;
#endif

7
libdevcrypto/TrieDB.h

@ -45,6 +45,7 @@ struct TrieDBChannel: public LogChannel { static const char* name() { return "-
struct InvalidTrie: virtual dev::Exception {};
extern const h256 c_shaNull;
extern const h256 EmptyTrie;
/**
* @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree.
@ -74,7 +75,7 @@ public:
void init();
void setRoot(h256 _root)
{
m_root = _root == h256() ? c_shaNull : _root;
m_root = _root;
if (m_root == c_shaNull && !m_db->exists(m_root))
init();
@ -82,14 +83,14 @@ public:
if (!node(m_root).size())
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).
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).
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() {}

40
libethcore/BlockInfo.cpp

@ -37,9 +37,9 @@ BlockInfo::BlockInfo(): timestamp(Invalid256)
{
}
BlockInfo::BlockInfo(bytesConstRef _block)
BlockInfo::BlockInfo(bytesConstRef _block, bool _checkNonce)
{
populate(_block);
populate(_block, _checkNonce);
}
BlockInfo BlockInfo::fromHeader(bytesConstRef _block)
@ -52,19 +52,17 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _block)
h256 BlockInfo::headerHashWithoutNonce() const
{
RLPStream s;
fillStream(s, false);
streamRLP(s, false);
return sha3(s.out());
}
auto static const c_sha3EmptyList = sha3(RLPEmptyList);
void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const
void BlockInfo::streamRLP(RLPStream& _s, bool _nonce) const
{
_s.appendList(_nonce ? 13 : 12) << parentHash;
_s.append(sha3Uncles == c_sha3EmptyList ? h256() : sha3Uncles, false, true);
_s << coinbaseAddress;
_s.append(stateRoot, false, true).append(transactionsRoot, false, true);
_s << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData;
_s.appendList(_nonce ? 15 : 14)
<< parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom
<< difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData;
if (_nonce)
_s << nonce;
}
@ -83,22 +81,22 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
{
parentHash = _header[field = 0].toHash<h256>();
sha3Uncles = _header[field = 1].toHash<h256>();
if (sha3Uncles == h256())
sha3Uncles = c_sha3EmptyList;
coinbaseAddress = _header[field = 2].toHash<Address>();
stateRoot = _header[field = 3].toHash<h256>();
transactionsRoot = _header[field = 4].toHash<h256>();
difficulty = _header[field = 5].toInt<u256>();
number = _header[field = 6].toInt<u256>();
minGasPrice = _header[field = 7].toInt<u256>();
gasLimit = _header[field = 8].toInt<u256>();
gasUsed = _header[field = 9].toInt<u256>();
timestamp = _header[field = 10].toInt<u256>();
extraData = _header[field = 11].toBytes();
nonce = _header[field = 12].toHash<h256>();
receiptsRoot = _header[field = 5].toHash<h256>();
logBloom = _header[field = 6].toHash<h512>();
difficulty = _header[field = 7].toInt<u256>();
number = _header[field = 8].toInt<u256>();
minGasPrice = _header[field = 9].toInt<u256>();
gasLimit = _header[field = 10].toInt<u256>();
gasUsed = _header[field = 11].toInt<u256>();
timestamp = _header[field = 12].toInt<u256>();
extraData = _header[field = 13].toBytes();
nonce = _header[field = 14].toHash<h256>();
}
catch (Exception & _e)
catch (Exception const& _e)
{
_e << errinfo_name("invalid block header format") << BadFieldError(field, toHex(_header[field].data().toBytes()));
throw;
@ -144,7 +142,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
{
bytes k = rlp(i);
t.insert(&k, tr.data());
u256 gp = tr[0][1].toInt<u256>();
u256 gp = tr[1].toInt<u256>();
mgp = min(mgp, gp);
++i;
}

13
libethcore/BlockInfo.h

@ -47,7 +47,7 @@ extern u256 c_genesisDifficulty;
* corresponding RLP block created with createGenesisBlock().
*
* The difficulty and gas-limit derivations may be calculated with the calculateDifficulty()
* and calculateGasLimit() and the object serialised to RLP with fillStream. To determine the
* and calculateGasLimit() and the object serialised to RLP with streamRLP. To determine the
* header hash without the nonce (for mining), the method headerHashWithoutNonce() is provided.
*
* The default constructor creates an empty object, which can be tested against with the boolean
@ -62,6 +62,8 @@ public:
Address coinbaseAddress;
h256 stateRoot;
h256 transactionsRoot;
h256 receiptsRoot;
h512 logBloom; // TODO LogBloom - get include
u256 difficulty;
u256 number;
u256 minGasPrice;
@ -73,7 +75,7 @@ public:
BlockInfo();
explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {}
explicit BlockInfo(bytesConstRef _block);
explicit BlockInfo(bytesConstRef _block, bool _checkNonce = true);
static h256 headerHash(bytes const& _block) { return headerHash(&_block); }
static h256 headerHash(bytesConstRef _block);
@ -89,6 +91,8 @@ public:
coinbaseAddress == _cmp.coinbaseAddress &&
stateRoot == _cmp.stateRoot &&
transactionsRoot == _cmp.transactionsRoot &&
receiptsRoot == _cmp.receiptsRoot &&
logBloom == _cmp.logBloom &&
difficulty == _cmp.difficulty &&
number == _cmp.number &&
minGasPrice == _cmp.minGasPrice &&
@ -112,13 +116,14 @@ public:
/// No-nonce sha3 of the header only.
h256 headerHashWithoutNonce() const;
void fillStream(RLPStream& _s, bool _nonce) const;
void streamRLP(RLPStream& _s, bool _nonce) const;
};
inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
{
_out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " <<
_bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce;
_bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " <<
_bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce;
return _out;
}

2
libethcore/CommonEth.cpp

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

3
libethcore/Exceptions.h

@ -57,7 +57,8 @@ struct InvalidDifficulty: virtual dev::Exception {};
class InvalidGasLimit: virtual public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; };
class InvalidMinGasPrice: virtual public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; };
struct InvalidTransactionGasUsed: virtual dev::Exception {};
struct InvalidTransactionStateRoot: virtual dev::Exception {};
struct InvalidTransactionsStateRoot: virtual dev::Exception {};
struct InvalidReceiptsStateRoot: virtual dev::Exception {};
struct InvalidTimestamp: virtual dev::Exception {};
class InvalidNonce: virtual public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; };
class InvalidBlockNonce: virtual public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept; };

7
libethereum/BlockChain.cpp

@ -101,8 +101,9 @@ bytes BlockChain::createGenesisBlock()
stateRoot = state.root();
}
block.appendList(13) << h256() << bytes() << h160();
block.append(stateRoot, false, true) << bytes() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42));
block.appendList(15)
// TODO: maybe make logbloom correct?
<< h256() << EmptySHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42));
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
@ -305,7 +306,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
// Get total difficulty increase and update state, checking it.
State s(bi.coinbaseAddress, _db);
auto tdIncrease = s.enactOn(&_block, bi, *this);
auto b = s.bloom();
auto b = s.oldBloom();
BlockBlooms bb;
BlockTraces bt;
for (unsigned i = 0; i < s.pending().size(); ++i)

2
libethereum/BlockDetails.h

@ -66,7 +66,7 @@ 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(); }
bytes rlp() const { RLPStream s(traces.size()); for (auto const& i: traces) i.streamRLP(s); return s.out(); }
Manifests traces;
};

5
libethereum/Client.cpp

@ -159,7 +159,7 @@ void Client::clearPending()
if (!m_postMine.pending().size())
return;
for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
appendFromNewPending(m_postMine.bloom(i), changeds);
appendFromNewPending(m_postMine.oldBloom(i), changeds);
changeds.insert(PendingChangedFilter);
m_postMine = m_preMine;
}
@ -325,6 +325,7 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.type = Transaction::MessageCall;
t.receiveAddress = _dest;
t.data = _data;
t.sign(_secret);
@ -348,6 +349,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.type = Transaction::ContractCreation;
t.receiveAddress = _dest;
t.data = _data;
t.sign(_secret);
@ -373,6 +375,7 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
t.value = _endowment;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.type = Transaction::ContractCreation;
t.receiveAddress = Address();
t.data = _init;
t.sign(_secret);

2
libethereum/Client.h

@ -285,7 +285,7 @@ private:
State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector<Miner> m_miners;
mutable boost::shared_mutex x_miners;

15
libethereum/Executive.cpp

@ -123,7 +123,11 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
}
else
{
m_endGas = _gas;
if (m_ext)
m_ext->sub.logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes()));
}
return !m_ext;
}
@ -172,6 +176,8 @@ bool Executive::go(OnOpFunc const& _onOp)
try
{
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();
}
catch (StepsDone const&)
@ -187,14 +193,17 @@ bool Executive::go(OnOpFunc const& _onOp)
{
clog(StateChat) << "VM Exception: " << diagnostic_information(_e);
m_endGas = m_vm->gas();
revert = true;
}
catch (Exception const& _e)
{
clog(StateChat) << "Exception in VM: " << diagnostic_information(_e);
// TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does.
cwarn << "Unexpected exception in VM. There may be a bug in this implementation. " << diagnostic_information(_e);
}
catch (std::exception const& _e)
{
clog(StateChat) << "std::exception in VM: " << _e.what();
// TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does.
cwarn << "Unexpected std::exception in VM. This is probably unrecoverable. " << _e.what();
}
cnote << "VM took:" << t.elapsed() << "; gas used: " << (sgas - m_endGas);
@ -236,6 +245,6 @@ void Executive::finalize(OnOpFunc const&)
// Suicides...
if (m_ext)
for (auto a: m_ext->suicides)
for (auto a: m_ext->sub.suicides)
m_s.m_cache[a].kill();
}

3
libethereum/Executive.h

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

4
libethereum/ExtVM.h

@ -61,7 +61,7 @@ public:
m_s.noteSending(myAddress);
if (m_ms)
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)
m_ms->internal.pop_back();
return ret;
@ -72,7 +72,7 @@ public:
{
if (m_ms)
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)
m_ms->internal.pop_back();
return ret;

4
libethereum/Manifest.cpp

@ -37,10 +37,10 @@ Manifest::Manifest(bytesConstRef _r)
internal.emplace_back(i.data());
}
void Manifest::streamOut(RLPStream& _s) const
void Manifest::streamRLP(RLPStream& _s) const
{
_s.appendList(7) << from << to << value << altered << input << output;
_s.appendList(internal.size());
for (auto const& i: internal)
i.streamOut(_s);
i.streamRLP(_s);
}

2
libethereum/Manifest.h

@ -41,7 +41,7 @@ struct Manifest
{
Manifest() {}
Manifest(bytesConstRef _r);
void streamOut(RLPStream& _s) const;
void streamRLP(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; }

4
libethereum/MessageFilter.cpp

@ -27,7 +27,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
void MessageFilter::fillStream(RLPStream& _s) const
void MessageFilter::streamRLP(RLPStream& _s) const
{
_s.appendList(8) << m_from << m_to << m_stateAltered << m_altered << m_earliest << m_latest << m_max << m_skip;
}
@ -35,7 +35,7 @@ void MessageFilter::fillStream(RLPStream& _s) const
h256 MessageFilter::sha3() const
{
RLPStream s;
fillStream(s);
streamRLP(s);
return dev::sha3(s.out());
}

2
libethereum/MessageFilter.h

@ -39,7 +39,7 @@ class MessageFilter
public:
MessageFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {}
void fillStream(RLPStream& _s) const;
void streamRLP(RLPStream& _s) const;
h256 sha3() const;
int earliest() const { return m_earliest; }

150
libethereum/State.cpp

@ -161,6 +161,7 @@ State::State(State const& _s):
m_db(_s.m_db),
m_state(&m_db, _s.m_state.root()),
m_transactions(_s.m_transactions),
m_receipts(_s.m_receipts),
m_transactionSet(_s.m_transactionSet),
m_cache(_s.m_cache),
m_previousBlock(_s.m_previousBlock),
@ -192,6 +193,7 @@ State& State::operator=(State const& _s)
m_db = _s.m_db;
m_state.open(&m_db, _s.m_state.root());
m_transactions = _s.m_transactions;
m_receipts = _s.m_receipts;
m_transactionSet = _s.m_transactionSet;
m_cache = _s.m_cache;
m_previousBlock = _s.m_previousBlock;
@ -353,9 +355,9 @@ void State::ensureCached(std::map<Address, AddressState>& _cache, Address _a, bo
RLP state(stateBack);
AddressState s;
if (state.isNull())
s = AddressState(0, 0, h256(), EmptySHA3);
s = AddressState(0, 0, EmptyTrie, EmptySHA3);
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;
tie(it, ok) = _cache.insert(make_pair(_a, s));
}
@ -484,6 +486,7 @@ map<Address, u256> State::addresses() const
void State::resetCurrent()
{
m_transactions.clear();
m_receipts.clear();
m_transactionSet.clear();
m_cache.clear();
m_currentBlock = BlockInfo();
@ -547,7 +550,7 @@ h256s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
uncommitToMine();
execute(i.second);
ret.push_back(m_transactions.back().changes.bloom());
ret.push_back(m_receipts.back().changes().bloom());
_tq.noteGood(i);
++goodTxs;
}
@ -588,7 +591,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
// m_currentBlock is assumed to be prepopulated and reset.
#if !ETH_RELEASE
BlockInfo bi(_block);
BlockInfo bi(_block, _checkNonce);
assert(m_previousBlock.hash == bi.parentHash);
assert(m_currentBlock.parentHash == bi.parentHash);
assert(rootHash() == m_previousBlock.stateRoot);
@ -605,16 +608,32 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
// cnote << m_state;
MemoryDB tm;
GenericTrieDB<MemoryDB> transactionManifest(&tm);
transactionManifest.init();
GenericTrieDB<MemoryDB> transactionsTrie(&tm);
transactionsTrie.init();
MemoryDB rm;
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
for (auto const& tr: RLP(_block)[1])
{
RLPStream k;
k << i;
RLPStream txrlp;
m_transactions[i].streamRLP(txrlp);
transactionsTrie.insert(&k.out(), tr.data());
// cnote << m_state.root() << m_state;
// cnote << *this;
execute(tr[0].data());
execute(tr.data());
RLPStream receiptrlp;
m_receipts.back().streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
/*
if (tr[1].toHash<h256>() != m_state.root())
{
// Invalid state root
@ -625,15 +644,20 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
}
if (tr[2].toInt<u256>() != gasUsed())
BOOST_THROW_EXCEPTION(InvalidTransactionGasUsed());
bytes k = rlp(i);
transactionManifest.insert(&k, tr.data());
*/
++i;
}
if (m_currentBlock.transactionsRoot && transactionManifest.root() != m_currentBlock.transactionsRoot)
if (transactionsTrie.root() != m_currentBlock.transactionsRoot)
{
cwarn << "Bad transactions state root!";
BOOST_THROW_EXCEPTION(InvalidTransactionStateRoot());
BOOST_THROW_EXCEPTION(InvalidTransactionsStateRoot());
}
if (receiptsTrie.root() != m_currentBlock.receiptsRoot)
{
cwarn << "Bad receipts state root!";
BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
}
// Initialise total difficulty calculation.
@ -713,7 +737,7 @@ void State::uncommitToMine()
if (!m_transactions.size())
m_state.setRoot(m_previousBlock.stateRoot);
else
m_state.setRoot(m_transactions[m_transactions.size() - 1].stateRoot);
m_state.setRoot(m_receipts[m_receipts.size() - 1].stateRoot());
m_db = m_lastTx;
paranoia("Uncommited to mine", true);
m_currentBlock.sha3Uncles = h256();
@ -730,7 +754,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
// Compile block:
RLPStream block;
block.appendList(3);
m_currentBlock.fillStream(block, true);
m_currentBlock.streamRLP(block, true);
block.appendRaw(m_currentTxs);
block.appendRaw(m_currentUncles);
@ -757,11 +781,20 @@ bool State::amIJustParanoid(BlockChain const& _bc)
return false;
}
h256 State::bloom() const
h256 State::oldBloom() const
{
h256 ret = m_currentBlock.coinbaseAddress.bloom();
for (auto const& i: m_transactions)
ret |= i.changes.bloom();
for (auto const& i: m_receipts)
ret |= i.changes().bloom();
return ret;
}
LogBloom State::logBloom() const
{
LogBloom ret;
ret.shiftBloom<3>(sha3(m_currentBlock.coinbaseAddress.ref()));
for (TransactionReceipt const& i: m_receipts)
ret |= i.bloom();
return ret;
}
@ -797,7 +830,7 @@ void State::commitToMine(BlockChain const& _bc)
if (!knownUncles.count(u)) // ignore any uncles/mainline blocks that we know about.
{
BlockInfo ubi(_bc.block(u));
ubi.fillStream(unclesData, true);
ubi.streamRLP(unclesData, true);
++unclesCount;
uncleAddresses.push_back(ubi.coinbaseAddress);
}
@ -805,8 +838,12 @@ void State::commitToMine(BlockChain const& _bc)
}
MemoryDB tm;
GenericTrieDB<MemoryDB> transactionReceipts(&tm);
transactionReceipts.init();
GenericTrieDB<MemoryDB> transactionsTrie(&tm);
transactionsTrie.init();
MemoryDB rm;
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
RLPStream txs;
txs.appendList(m_transactions.size());
@ -815,17 +852,25 @@ void State::commitToMine(BlockChain const& _bc)
{
RLPStream k;
k << i;
RLPStream v;
m_transactions[i].fillStream(v);
transactionReceipts.insert(&k.out(), &v.out());
txs.appendRaw(v.out());
RLPStream receiptrlp;
m_receipts[i].streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
RLPStream txrlp;
m_transactions[i].streamRLP(txrlp);
transactionsTrie.insert(&k.out(), &txrlp.out());
txs.appendRaw(txrlp.out());
}
txs.swapOut(m_currentTxs);
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
m_currentBlock.transactionsRoot = transactionReceipts.root();
m_currentBlock.transactionsRoot = transactionsTrie.root();
m_currentBlock.receiptsRoot = receiptsTrie.root();
m_currentBlock.logBloom = logBloom();
m_currentBlock.sha3Uncles = sha3(m_currentUncles);
// Apply rewards last of all.
@ -853,6 +898,10 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo)
if (!ret.completed)
m_currentBytes.clear();
else
{
cnote << "Completed" << m_currentBlock.headerHashWithoutNonce().abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHashWithoutNonce(), m_currentBlock.nonce, m_currentBlock.difficulty);
}
return ret;
}
@ -865,7 +914,7 @@ void State::completeMine()
// Compile block:
RLPStream ret;
ret.appendList(3);
m_currentBlock.fillStream(ret, true);
m_currentBlock.streamRLP(ret, true);
ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes);
@ -875,6 +924,7 @@ void State::completeMine()
// Quickly reset the transactions.
// TODO: Leave this in a better state than this limbo, or at least record that it's in limbo.
m_transactions.clear();
m_receipts.clear();
m_transactionSet.clear();
m_lastTx = m_db;
}
@ -1114,12 +1164,13 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
// TODO: CHECK TRIE after level DB flush to make sure exactly the same.
// Add to the user-originated transactions that we've executed.
m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed(), ms));
m_transactions.push_back(e.t());
m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs(), ms));
m_transactionSet.insert(e.t().sha3());
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)
_originAddress = _senderAddress;
@ -1154,9 +1205,8 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
{
auto out = vm.go(evm, _onOp);
memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
if (o_sub)
*o_sub += evm.sub;
if (o_ms)
o_ms->output = out.toBytes();
}
@ -1168,6 +1218,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << diagnostic_information(_e);
revert = true;
}
catch (Exception const& _e)
{
@ -1186,10 +1237,16 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
return !revert;
}
else
{
// non-contract call
if (o_sub)
o_sub->logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes()));
}
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)
_origin = _sender;
@ -1218,9 +1275,8 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
out = vm.go(evm, _onOp);
if (o_ms)
o_ms->output = out.toBytes();
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
if (o_sub)
*o_sub += evm.sub;
}
catch (OutOfGas const& /*_e*/)
{
@ -1230,25 +1286,32 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << diagnostic_information(_e);
revert = true;
}
catch (Exception const& _e)
{
clog(StateChat) << "Exception in VM: " << diagnostic_information(_e);
// TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does.
cwarn << "Unexpected exception in VM. There may be a bug in this implementation. " << diagnostic_information(_e);
}
catch (std::exception const& _e)
{
clog(StateChat) << "std::exception in VM: " << _e.what();
// TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does.
cwarn << "Unexpected std::exception in VM. This is probably unrecoverable. " << _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.
if (revert)
{
evm.revert();
// Set code.
if (addressInUse(newAddress))
m_cache[newAddress].setCode(out);
m_cache.erase(newAddress);
newAddress = Address();
}
else
// Set code.
if (addressInUse(newAddress))
m_cache[newAddress].setCode(out);
*_gas = vm.gas();
@ -1263,11 +1326,12 @@ State State::fromPending(unsigned _i) const
if (!_i)
ret.m_state.setRoot(m_previousBlock.stateRoot);
else
ret.m_state.setRoot(m_transactions[_i - 1].stateRoot);
ret.m_state.setRoot(m_receipts[_i - 1].stateRoot());
while (ret.m_transactions.size() > _i)
{
ret.m_transactionSet.erase(ret.m_transactions.back().transaction.sha3());
ret.m_transactionSet.erase(ret.m_transactions.back().sha3());
ret.m_transactions.pop_back();
ret.m_receipts.pop_back();
}
return ret;
}

75
libethereum/State.h

@ -52,25 +52,37 @@ struct StateChat: public LogChannel { static const char* name() { return "-S-";
struct StateTrace: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 7; };
struct StateDetail: public LogChannel { static const char* name() { return "/S/"; } static const int verbosity = 14; };
struct TransactionReceipt
class TransactionReceipt
{
TransactionReceipt(Transaction const& _t, h256 _root, u256 _gasUsed, Manifest const& _ms): transaction(_t), stateRoot(_root), gasUsed(_gasUsed), changes(_ms) {}
public:
TransactionReceipt(h256 _root, u256 _gasUsed, LogEntries const& _log, Manifest const& _ms): m_stateRoot(_root), m_gasUsed(_gasUsed), m_bloom(eth::bloom(_log)), m_log(_log), m_changes(_ms) {}
Manifest const& changes() const { return m_changes; }
// Manifest const& changes() const { return changes; }
h256 const& stateRoot() const { return m_stateRoot; }
u256 const& gasUsed() const { return m_gasUsed; }
LogBloom const& bloom() const { return m_bloom; }
LogEntries const& log() const { return m_log; }
void fillStream(RLPStream& _s) const
void streamRLP(RLPStream& _s) const
{
_s.appendList(3);
transaction.fillStream(_s);
_s.append(stateRoot, false, true) << gasUsed;
_s.appendList(4) << m_stateRoot << m_gasUsed << m_bloom;
_s.appendList(m_log.size());
for (LogEntry const& l: m_log)
l.streamRLP(_s);
}
Transaction transaction;
h256 stateRoot;
u256 gasUsed;
Manifest changes;
private:
h256 m_stateRoot;
u256 m_gasUsed;
LogBloom m_bloom;
LogEntries m_log;
Manifest m_changes; ///< TODO: PoC-7: KILL
};
using TransactionReceipts = std::vector<TransactionReceipt>;
struct PrecompiledAddress
{
unsigned gas;
@ -226,16 +238,28 @@ public:
h256 rootHash() const { return m_state.root(); }
/// Get the list of pending transactions.
Transactions pending() const { Transactions ret; for (auto const& t: m_transactions) ret.push_back(t.transaction); return ret; }
Transactions const& pending() const { return m_transactions; }
/// Get the list of pending transactions. TODO: PoC-7: KILL
Manifest changesFromPending(unsigned _i) const { return m_receipts[_i].changes(); }
/// Get the bloom filter of all changes happened in the block. TODO: PoC-7: KILL
h256 oldBloom() const;
/// Get the bloom filter of a particular transaction that happened in the block. TODO: PoC-7: KILL
h256 oldBloom(unsigned _i) const { return m_receipts[_i].changes().bloom(); }
/// Get the transaction receipt for the transaction of the given index.
TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; }
/// Get the list of pending transactions.
Manifest changesFromPending(unsigned _i) const { return m_transactions[_i].changes; }
LogEntries const& log(unsigned _i) const { return m_receipts[_i].log(); }
/// Get the bloom filter of all changes happened in the block.
h256 bloom() const;
/// Get the bloom filter of all logs that happened in the block.
LogBloom logBloom() 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(); }
LogBloom const& logBloom(unsigned _i) const { return m_receipts[_i].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.
@ -288,12 +312,12 @@ private:
// We assume all instrinsic fees are paid up before this point.
/// 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.
/// @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.
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).
void resetCurrent();
@ -304,14 +328,15 @@ private:
void refreshManifest(RLPStream* _txs = nullptr);
/// @returns gas used by transactions thus far executed.
u256 gasUsed() const { return m_transactions.size() ? m_transactions.back().gasUsed : 0; }
u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; }
bool isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const;
void paranoia(std::string const& _when, bool _enforceRefs = false) const;
OverlayDB m_db; ///< Our overlay for the state tree.
TrieDB<Address, OverlayDB> m_state; ///< Our state tree, as an OverlayDB DB.
std::vector<TransactionReceipt> m_transactions; ///< The current list of transactions that we've included in the state.
Transactions m_transactions; ///< The current list of transactions that we've included in the state.
TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts.
std::set<h256> m_transactionSet; ///< The set of transaction hashes that we've included in the state.
OverlayDB m_lastTx;
@ -367,16 +392,10 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
{
h256 ch = sha3(i.second.code());
_db.insert(ch, &i.second.code());
if (i.second.code().size())
s << ch;
else
s << "";
s << ch;
}
else
if (i.second.codeHash() == EmptySHA3)
s << "";
else
s << i.second.codeHash();
s << i.second.codeHash();
_state.insert(i.first, &s.out());
}

5
libethereum/Transaction.cpp

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

17
libethereum/Transaction.h

@ -32,13 +32,20 @@ namespace eth
struct Transaction
{
enum Type
{
ContractCreation,
MessageCall
};
Transaction() {}
Transaction(bytesConstRef _rlp, bool _checkSender = false);
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); }
Type type; ///< True if this is a contract-creation transaction. F
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.
Address receiveAddress; ///< The receiving address of the transaction.
@ -57,11 +64,11 @@ struct Transaction
static h256 kFromMessage(h256 _msg, h256 _priv);
void fillStream(RLPStream& _s, bool _sig = true) const;
bytes rlp(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return s.out(); }
void streamRLP(RLPStream& _s, bool _sig = true) const;
bytes rlp(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return s.out(); }
std::string rlpString(bool _sig = true) const { return asString(rlp(_sig)); }
h256 sha3(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3(s.out()); }
bytes sha3Bytes(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3Bytes(s.out()); }
h256 sha3(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3(s.out()); }
bytes sha3Bytes(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3Bytes(s.out()); }
private:
mutable Address m_sender;

58
libevm/ExtVMFace.h

@ -24,6 +24,9 @@
#include <set>
#include <functional>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
#include <libevmface/Instruction.h>
#include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h>
@ -33,13 +36,53 @@ namespace dev
namespace eth
{
struct Post
using LogBloom = h512;
struct LogEntry
{
LogEntry() {}
LogEntry(RLP const& _r) { from = (Address)_r[0]; topics = (h256s)_r[1]; data = (bytes)_r[2]; }
LogEntry(Address const& _f, h256s&& _ts, bytes&& _d): from(_f), topics(std::move(_ts)), data(std::move(_d)) {}
void streamRLP(RLPStream& _s) const { _s.appendList(3) << from << topics << data; }
LogBloom bloom() const
{
LogBloom ret;
ret.shiftBloom<3, 32>(sha3(from.ref()));
for (auto t: topics)
ret.shiftBloom<3, 32>(sha3(t.ref()));
return ret;
}
Address from;
Address to;
u256 value;
h256s topics;
bytes data;
u256 gas;
};
using LogEntries = std::vector<LogEntry>;
inline LogBloom bloom(LogEntries const& _logs)
{
LogBloom ret;
for (auto const& l: _logs)
ret |= l.bloom();
return ret;
}
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*)>;
@ -80,7 +123,7 @@ public:
virtual u256 txCount(Address) { return 0; }
/// 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.
virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); }
@ -88,6 +131,9 @@ public:
/// Make a new message call.
virtual bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; }
/// Revert any changes made (by any of the other calls).
virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); }
/// Revert any changes made (by any of the other calls).
virtual void revert() {}
@ -103,7 +149,7 @@ public:
bytesConstRef code; ///< Current code that is executing.
BlockInfo previousBlock; ///< The previous 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.
};

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_sha3Gas = 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_callGas = 20;
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_sha3Gas; ///< Once per SHA3 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_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.

1
libevm/VM.cpp

@ -29,4 +29,5 @@ void VM::reset(u256 _gas)
{
m_gas = _gas;
m_curPC = 0;
m_jumpDests.clear();
}

84
libevm/VM.h

@ -41,7 +41,7 @@ struct BreakPointHit: virtual VMException {};
struct BadInstruction: virtual VMException {};
struct BadJumpDestination: virtual VMException {};
struct OutOfGas: virtual VMException {};
class StackTooSmall: virtual public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
struct StackTooSmall: virtual public VMException { StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash.
// Currently we just pull out the right (low-order in BE) 160-bits.
@ -84,6 +84,7 @@ private:
u256 m_curPC = 0;
bytes m_temp;
u256s m_stack;
std::set<unsigned> m_jumpDests;
};
}
@ -93,6 +94,16 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
{
auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? _offset + _size : 0; };
if (m_jumpDests.empty())
{
m_jumpDests.insert(0);
for (unsigned i = 1; i < _ext.code.size(); ++i)
if (_ext.code[i] == (byte)Instruction::JUMPDEST)
m_jumpDests.insert(i + 1);
else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32)
i += _ext.code[i] - (int)Instruction::PUSH1 + 1;
}
u256 nextPC = m_curPC + 1;
auto osteps = _steps;
for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1)
@ -117,11 +128,14 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::SSTORE:
require(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])
{
runGas = 0;
_ext.sub.refunds += c_sstoreRefundGas;
}
else
runGas = c_sstoreGas;
runGas = c_sstoreResetGas;
break;
case Instruction::SLOAD:
@ -169,6 +183,18 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
runGas = c_balanceGas;
break;
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
case Instruction::LOG3:
case Instruction::LOG4:
{
unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0;
require(n + 2);
newTempSize = memNeed(m_stack[m_stack.size() - 1 - n], m_stack[m_stack.size() - 2 - n]);
break;
}
case Instruction::CALL:
case Instruction::CALLCODE:
require(7);
@ -236,7 +262,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::PUSH31:
case Instruction::PUSH32:
break;
case Instruction::NEG:
case Instruction::BNOT:
case Instruction::NOT:
case Instruction::CALLDATALOAD:
case Instruction::EXTCODESIZE:
@ -262,6 +288,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::XOR:
case Instruction::BYTE:
case Instruction::JUMPI:
case Instruction::SIGNEXTEND:
require(2);
break;
case Instruction::ADDMOD:
@ -368,8 +395,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);
break;
}
case Instruction::NEG:
m_stack.back() = ~(m_stack.back() - 1);
case Instruction::BNOT:
m_stack.back() = ~m_stack.back();
break;
case Instruction::LT:
m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0;
@ -420,6 +447,17 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.pop_back();
m_stack.pop_back();
break;
case Instruction::SIGNEXTEND:
{
unsigned k = m_stack.back();
m_stack.pop_back();
auto& b = m_stack.back();
if (k <= 31)
if ((b >> (k * 8)) & 0x80)
for (int i = 31; i > k; --i)
b |= (u256(0xff) << i);
break;
}
case Instruction::SHA3:
{
unsigned inOff = (unsigned)m_stack.back();
@ -646,7 +684,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
case Instruction::JUMP:
nextPC = m_stack.back();
if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST)
if (!m_jumpDests.count((unsigned)nextPC))
BOOST_THROW_EXCEPTION(BadJumpDestination());
m_stack.pop_back();
break;
@ -654,7 +692,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (m_stack[m_stack.size() - 2])
{
nextPC = m_stack.back();
if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST)
if (!m_jumpDests.count((unsigned)nextPC))
BOOST_THROW_EXCEPTION(BadJumpDestination());
}
m_stack.pop_back();
@ -671,6 +709,36 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
case Instruction::JUMPDEST:
break;
/* case Instruction::LOG0:
_ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
break;
case Instruction::LOG1:
_ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3]));
break;
case Instruction::LOG2:
_ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4]));
break;
case Instruction::LOG3:
_ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5]));
break;
case Instruction::LOG4:
_ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6]));
break;*/
case Instruction::LOG0:
_ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
break;
case Instruction::LOG1:
_ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
break;
case Instruction::LOG2:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
break;
case Instruction::LOG3:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
break;
case Instruction::LOG4:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
break;
case Instruction::CREATE:
{
u256 endowment = m_stack.back();

19
libevmface/CMakeLists.txt

@ -17,25 +17,6 @@ include_directories(..)
target_link_libraries(${EXECUTABLE} devcore)
if("${TARGET_PLATFORM}" STREQUAL "w64")
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} ws2_32)
target_link_libraries(${EXECUTABLE} mswsock)
target_link_libraries(${EXECUTABLE} shlwapi)
elseif (APPLE)
# Latest mavericks boost libraries only come with -mt
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
elseif (UNIX)
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY})
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
else ()
target_link_libraries(${EXECUTABLE} boost_thread)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

16
libevmface/Instruction.cpp

@ -39,7 +39,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "MOD", Instruction::MOD },
{ "SMOD", Instruction::SMOD },
{ "EXP", Instruction::EXP },
{ "NEG", Instruction::NEG },
{ "BNOT", Instruction::BNOT },
{ "LT", Instruction::LT },
{ "GT", Instruction::GT },
{ "SLT", Instruction::SLT },
@ -52,6 +52,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "BYTE", Instruction::BYTE },
{ "ADDMOD", Instruction::ADDMOD },
{ "MULMOD", Instruction::MULMOD },
{ "SIGNEXTEND", Instruction::SIGNEXTEND },
{ "SHA3", Instruction::SHA3 },
{ "ADDRESS", Instruction::ADDRESS },
{ "BALANCE", Instruction::BALANCE },
@ -148,6 +149,11 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "SWAP14", Instruction::SWAP14 },
{ "SWAP15", Instruction::SWAP15 },
{ "SWAP16", Instruction::SWAP16 },
{ "LOG0", Instruction::LOG0 },
{ "LOG1", Instruction::LOG1 },
{ "LOG2", Instruction::LOG2 },
{ "LOG3", Instruction::LOG3 },
{ "LOG4", Instruction::LOG4 },
{ "CREATE", Instruction::CREATE },
{ "CALL", Instruction::CALL },
{ "CALLCODE", Instruction::CALLCODE },
@ -166,7 +172,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::MOD, { "MOD", 0, 2, 1 } },
{ Instruction::SMOD, { "SMOD", 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::GT, { "GT", 0, 2, 1 } },
{ Instruction::SLT, { "SLT", 0, 2, 1 } },
@ -179,6 +185,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::BYTE, { "BYTE", 0, 2, 1 } },
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1 } },
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1 } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1 } },
{ Instruction::SHA3, { "SHA3", 0, 2, 1 } },
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } },
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1 } },
@ -275,6 +282,11 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::SWAP14, { "SWAP14", 0, 15, 15 } },
{ Instruction::SWAP15, { "SWAP15", 0, 16, 16 } },
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17 } },
{ Instruction::LOG0, { "LOG0", 0, 1, 0 } },
{ Instruction::LOG1, { "LOG1", 0, 2, 0 } },
{ Instruction::LOG2, { "LOG2", 0, 3, 0 } },
{ Instruction::LOG3, { "LOG3", 0, 4, 0 } },
{ Instruction::LOG4, { "LOG4", 0, 5, 0 } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } },
{ Instruction::CALL, { "CALL", 0, 7, 1 } },
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } },

9
libevmface/Instruction.h

@ -44,7 +44,7 @@ enum class Instruction: uint8_t
MOD, ///< modulo remainder operation
SMOD, ///< signed modulo remainder operation
EXP, ///< exponential operation
NEG, ///< negation operation
BNOT, ///< bitwise not
LT, ///< less-than comparision
GT, ///< greater-than comparision
SLT, ///< signed less-than comparision
@ -58,6 +58,7 @@ enum class Instruction: uint8_t
BYTE, ///< retrieve single byte from word
ADDMOD, ///< unsigned modular addition
MULMOD, ///< unsigned modular multiplication
SIGNEXTEND, ///< extend length of signed integer
SHA3 = 0x20, ///< compute SHA3-256 hash
ADDRESS = 0x30, ///< get address of currently executing account
@ -161,6 +162,12 @@ enum class Instruction: uint8_t
SWAP15, ///< swaps the highest and 16th highest value on the stack
SWAP16, ///< swaps the highest and 17th highest value on the stack
LOG0 = 0xa0, ///< Makes a log entry; no topics.
LOG1, ///< Makes a log entry; 1 topic.
LOG2, ///< Makes a log entry; 2 topics.
LOG3, ///< Makes a log entry; 3 topics.
LOG4, ///< Makes a log entry; 4 topics.
CREATE = 0xf0, ///< create a new account with associated code
CALL, ///< message-call into an account
RETURN, ///< halt execution returning output data

4
liblll/Assembly.cpp

@ -147,7 +147,7 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i)
return _out;
}
ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const
ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const
{
_out << _prefix << ".code:" << endl;
for (AssemblyItem const& i: m_items)
@ -189,7 +189,7 @@ ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const
for (auto const& i: m_subs)
{
_out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl;
i.second.streamOut(_out, _prefix + " ");
i.second.streamRLP(_out, _prefix + " ");
}
}
return _out;

6
liblll/Assembly.h

@ -104,11 +104,11 @@ public:
void injectStart(AssemblyItem const& _i);
std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); }
std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); }
int deposit() const { return m_deposit; }
bytes assemble() const;
Assembly& optimise(bool _enable);
std::ostream& streamOut(std::ostream& _out, std::string const& _prefix = "") const;
std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "") const;
private:
void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
@ -127,7 +127,7 @@ private:
inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a)
{
_a.streamOut(_out);
_a.streamRLP(_out);
return _out;
}

46
libp2p/Host.cpp

@ -143,6 +143,9 @@ void Host::stop()
void Host::quit()
{
// called to force io_service to kill any remaining tasks it might have -
// such tasks may involve socket reads from Capabilities that maintain references
// to resources we're about to free.
stop();
m_ioService.reset();
// m_acceptor & m_socket are DANGEROUS now.
@ -249,17 +252,27 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p);
else
{
m_public = bi::tcp::endpoint(bi::address::from_string(_publicAddress.empty() ? eip : _publicAddress), (unsigned short)p);
bi::address adr = adr = bi::address::from_string(eip);
try
{
adr = bi::address::from_string(_publicAddress);
}
catch (...) {}
m_public = bi::tcp::endpoint(adr, (unsigned short)p);
m_addresses.push_back(m_public.address());
}
}
else
{
// No UPnP - fallback on given public address or, if empty, the assumed peer address.
m_public = bi::tcp::endpoint(_publicAddress.size() ? bi::address::from_string(_publicAddress)
: m_peerAddresses.size() ? m_peerAddresses[0]
: bi::address(), m_listenPort);
m_addresses.push_back(m_public.address());
bi::address adr = m_peerAddresses.size() ? m_peerAddresses[0] : bi::address();
try
{
adr = bi::address::from_string(_publicAddress);
}
catch (...) {}
m_public = bi::tcp::endpoint(adr, m_listenPort);
m_addresses.push_back(adr);
}
}
@ -366,7 +379,7 @@ void Host::populateAddresses()
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{
RecursiveGuard l(x_peers);
if (_a.port() < 30300 && _a.port() > 30303)
if (_a.port() < 30300 || _a.port() > 30303)
cwarn << "Wierd port being recorded!";
if (_a.port() >= /*49152*/32768)
@ -648,23 +661,26 @@ void Host::prunePeers()
{
RecursiveGuard l(x_peers);
// We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
for (unsigned old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
while (m_peers.size() > m_idealPeerCount)
set<NodeId> dc;
for (unsigned old = 15000; m_peers.size() - dc.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
if (m_peers.size() - dc.size() > m_idealPeerCount)
{
// look for worst peer to kick off
// first work out how many are old enough to kick off.
shared_ptr<Session> worst;
unsigned agedPeers = 0;
for (auto i: m_peers)
if (auto p = i.second.lock())
if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones
worst = p;
}
if (!dc.count(i.first))
if (auto p = i.second.lock())
if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones
worst = p;
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
dc.insert(worst->id());
worst->disconnect(TooManyPeers);
}

2
libp2p/Host.h

@ -203,7 +203,7 @@ private:
/// This won't touch alter the blockchain.
virtual void doWork();
std::shared_ptr<Node> noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = h256());
std::shared_ptr<Node> noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId());
Nodes potentialPeers(RangeMask<unsigned> const& _known);
std::string m_clientVersion; ///< Our version string.

1
libp2p/Session.cpp

@ -475,7 +475,6 @@ void Session::drop(DisconnectReason _reason)
{
if (m_dropped)
return;
cerr << (void*)this << " dropped" << endl;
if (m_socket.is_open())
try
{

12
libpyserpent/pyserpent.cpp

@ -120,11 +120,15 @@ std::vector<Node> cppifyNodeList(PyObject* o) {
}
PYMETHOD(ps_compile, FROMSTR, compile, pyifyString)
PYMETHOD(ps_compile_chunk, FROMSTR, compileChunk, pyifyString)
PYMETHOD(ps_compile_to_lll, FROMSTR, compileToLLL, pyifyNode)
PYMETHOD(ps_compile_chunk_to_lll, FROMSTR, compileChunkToLLL, pyifyNode)
PYMETHOD(ps_compile_lll, FROMNODE, compileLLL, pyifyString)
PYMETHOD(ps_parse, FROMSTR, parseSerpent, pyifyNode)
PYMETHOD(ps_rewrite, FROMNODE, rewrite, pyifyNode)
PYMETHOD(ps_rewrite_chunk, FROMNODE, rewriteChunk, pyifyNode)
PYMETHOD(ps_pretty_compile, FROMSTR, prettyCompile, pyifyNodeList)
PYMETHOD(ps_pretty_compile_chunk, FROMSTR, prettyCompileChunk, pyifyNodeList)
PYMETHOD(ps_pretty_compile_lll, FROMNODE, prettyCompileLLL, pyifyNodeList)
PYMETHOD(ps_serialize, FROMLIST, serialize, pyifyString)
PYMETHOD(ps_deserialize, FROMSTR, deserialize, pyifyNodeList)
@ -134,16 +138,24 @@ PYMETHOD(ps_parse_lll, FROMSTR, parseLLL, pyifyNode)
static PyMethodDef PyextMethods[] = {
{"compile", ps_compile, METH_VARARGS,
"Compile code."},
{"compile_chunk", ps_compile_chunk, METH_VARARGS,
"Compile code chunk (no wrappers)."},
{"compile_to_lll", ps_compile_to_lll, METH_VARARGS,
"Compile code to LLL."},
{"compile_chunk_to_lll", ps_compile_chunk_to_lll, METH_VARARGS,
"Compile code chunk to LLL (no wrappers)."},
{"compile_lll", ps_compile_lll, METH_VARARGS,
"Compile LLL to EVM."},
{"parse", ps_parse, METH_VARARGS,
"Parse serpent"},
{"rewrite", ps_rewrite, METH_VARARGS,
"Rewrite parsed serpent to LLL"},
{"rewrite_chunk", ps_rewrite_chunk, METH_VARARGS,
"Rewrite parsed serpent to LLL (no wrappers)"},
{"pretty_compile", ps_pretty_compile, METH_VARARGS,
"Compile to EVM opcodes"},
{"pretty_compile_chunk", ps_pretty_compile_chunk, METH_VARARGS,
"Compile chunk to EVM opcodes (no wrappers)"},
{"pretty_compile_lll", ps_pretty_compile_lll, METH_VARARGS,
"Compile LLL to EVM opcodes"},
{"serialize", ps_serialize, METH_VARARGS,

266
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 <QtWebKitWidgets/QWebFrame>
#include <libdevcrypto/FileSystem.h>
@ -5,6 +27,8 @@
#include <liblll/Compiler.h>
#include <libethereum/Client.h>
#include <libethereum/EthereumHost.h>
#include <libwhisper/Message.h>
#include <libwhisper/WhisperHost.h>
#include "QEthereum.h"
using namespace std;
using namespace dev;
@ -21,7 +45,7 @@ dev::bytes toBytes(QString const& _s)
else
{
// Binary
cwarn << "THIS FUNCTIONALITY IS DEPRECATED. DO NOT ASSUME ASCII/BINARY-STRINGS WILL BE ACCEPTED. USE eth.fromAscii().";
cwarn << "'" << _s.toStdString() << "': Unrecognised format for number/hash. USE eth.fromAscii() if you mean to convert from ASCII.";
return asBytes(_s);
}
}
@ -534,8 +558,9 @@ void QEthereum::poll()
// 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()
@ -558,37 +583,250 @@ void QWhisper::faceDieing()
}
void QWhisper::send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload)
static shh::Message toMessage(QString _json)
{
(void)_dest;
(void)_from;
(void)_topic;
(void)_payload;
shh::Message ret;
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("from"))
ret.setFrom(toPublic(f["from"].toString()));
if (f.contains("to"))
ret.setTo(toPublic(f["to"].toString()));
if (f.contains("payload"))
ret.setPayload(toBytes(f["payload"].toString()));
return ret;
}
unsigned QWhisper::newWatch(QString _json)
static shh::Envelope toSealed(QString _json, shh::Message const& _m, Secret _from)
{
(void)_json;
return 0;
unsigned ttl = 50;
unsigned workToProve = 50;
shh::BuildTopic bt;
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("ttl"))
ttl = f["ttl"].toInt();
if (f.contains("workToProve"))
workToProve = f["workToProve"].toInt();
if (f.contains("topic"))
{
if (f["topic"].isString())
bt.shift(asBytes(padded(f["topic"].toString(), 32)));
else if (f["topic"].isArray())
for (auto i: f["topic"].toArray())
bt.shift(asBytes(padded(i.toString(), 32)));
}
return _m.seal(_from, bt, ttl, workToProve);
}
QString QWhisper::watchMessages(unsigned _w)
void QWhisper::doPost(QString _json)
{
(void)_w;
return "";
shh::Message m = toMessage(_json);
Secret from;
if (m.from() && m_ids.count(m.from()))
{
cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here.";
// TODO: insert validification hook here.
from = m_ids[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)
{
shh::BuildTopicMask bt(shh::BuildTopicMask::Empty);
Public to;
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("to"))
to = toPublic(f["to"].toString());
if (f.contains("topic"))
{
if (f["topic"].isString())
bt.shift(asBytes(padded(f["topic"].toString(), 32)));
else if (f["topic"].isArray())
for (auto i: f["topic"].toArray())
if (i.isString())
bt.shift(asBytes(padded(i.toString(), 32)));
else
bt.shift();
}
return make_pair(bt.toTopicMask(), to);
}
// _json contains
// topic: the topic as an array of components, some may be null.
// to: specifies the id to which the message is encrypted. null if broadcast.
unsigned QWhisper::newWatch(QString _json)
{
auto w = toWatch(_json);
auto ret = face()->installWatch(w.first);
m_watches.insert(make_pair(ret, w.second));
return ret;
}
void QWhisper::killWatch(unsigned _w)
{
(void)_w;
face()->uninstallWatch(_w);
m_watches.erase(_w);
}
void QWhisper::clearWatches()
{
for (auto i: m_watches)
face()->uninstallWatch(i.first);
m_watches.clear();
}
static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m)
{
QJsonObject v;
v["hash"] = toQJS(_h);
v["expiry"] = (int)_e.expiry();
v["sent"] = (int)_e.sent();
v["ttl"] = (int)_e.ttl();
v["workProved"] = (int)_e.workProved();
v["topic"] = toQJS(_e.topic());
v["payload"] = toQJS(_m.payload());
v["from"] = toQJS(_m.from());
v["to"] = toQJS(_m.to());
return QString::fromUtf8(QJsonDocument(v).toJson());
}
QString QWhisper::watchMessages(unsigned _w)
{
QString ret = "[";
auto wit = m_watches.find(_w);
if (wit == m_watches.end())
{
cwarn << "watchMessages called with invalid watch id" << _w;
return "";
}
Public p = wit->second;
if (!p || m_ids.count(p))
for (h256 const& h: face()->watchMessages(_w))
{
auto e = face()->envelope(h);
shh::Message m;
if (p)
{
cwarn << "Silently decrypting message from identity" << p.abridged() << ": User validation hook goes here.";
m = e.open(m_ids[p]);
}
else
m = e.open();
ret.append((ret == "[" ? "" : ",") + toJson(h, e, m));
}
return ret + "]";
}
QString QWhisper::newIdentity()
{
return toQJS(makeIdentity());
}
Public QWhisper::makeIdentity()
{
KeyPair kp = KeyPair::create();
emit newIdToAdd(toQJS(kp.sec()));
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()
{
for (auto const& w: m_watches)
if (!w.second || m_ids.count(w.second))
for (h256 const& h: face()->checkWatch(w.first))
{
auto e = face()->envelope(h);
shh::Message m;
if (w.second)
{
cwarn << "Silently decrypting message from identity" << w.second.abridged() << ": User validation hook goes here.";
m = e.open(m_ids[w.second]);
if (!m)
continue;
}
else
m = e.open();
emit watchChanged(w.first, toJson(h, e, m));
}
}
#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

95
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 warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <QtCore/QObject>
#include <QtCore/QStringList>
#include <QtCore/QList>
#include <libdevcore/CommonIO.h>
#include <libethcore/CommonEth.h>
namespace ldb = leveldb;
namespace dev {
namespace eth {
class Interface;
@ -59,8 +87,9 @@ template <unsigned N> dev::FixedHash<N> toFixed(QString const& _s)
template <unsigned N> inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> toInt(QString const& _s);
inline dev::Address toAddress(QString const& _s) { return toFixed<20>(_s); }
inline dev::Secret toSecret(QString const& _s) { return toFixed<32>(_s); }
inline dev::Address toAddress(QString const& _s) { return toFixed<sizeof(dev::Address)>(_s); }
inline dev::Public toPublic(QString const& _s) { return toFixed<sizeof(dev::Public)>(_s); }
inline dev::Secret toSecret(QString const& _s) { return toFixed<sizeof(dev::Secret)>(_s); }
inline dev::u256 toU256(QString const& _s) { return toInt<32>(_s); }
template <unsigned S> QString toQJS(dev::FixedHash<S> const& _h) { return QString::fromStdString("0x" + toHex(_h.ref())); }
@ -213,26 +242,36 @@ class QWhisper: public QObject
Q_OBJECT
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();
std::shared_ptr<dev::shh::Interface> face() const;
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.
void faceDieing();
Q_INVOKABLE QWhisper* self() { return this; }
/// Basic message send.
Q_INVOKABLE void send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload);
Q_INVOKABLE void doPost(QString _json);
// Watches interface
Q_INVOKABLE QString newIdentity();
Q_INVOKABLE bool haveIdentity(QString _id) { return m_ids.count(toPublic(_id)); }
Q_INVOKABLE QString newGroup(QString _id, QString _who);
Q_INVOKABLE QString addToGroup(QString _group, QString _who);
// Watches interface
Q_INVOKABLE unsigned newWatch(QString _json);
Q_INVOKABLE QString watchMessages(unsigned _w);
Q_INVOKABLE void killWatch(unsigned _w);
void clearWatches();
Q_INVOKABLE void clearWatches();
Q_INVOKABLE QString watchMessages(unsigned _w);
dev::Public makeIdentity();
std::map<dev::Public, dev::Secret> const& ids() const { return m_ids; }
public slots:
/// Check to see if anything has changed, fire off signals if so.
@ -240,23 +279,52 @@ public slots:
void poll();
signals:
void watchChanged(unsigned _w);
void watchChanged(unsigned _w, QString _envelopeJson);
void idsChanged();
void newIdToAdd(QString _id);
private:
std::weak_ptr<dev::shh::Interface> m_face;
std::vector<unsigned> m_watches;
std::map<unsigned, dev::Public> m_watches;
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
#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->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_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) \
{ \
_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.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; }"); \
@ -269,8 +337,9 @@ private:
if (_shh) \
{ \
_frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \
_frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(a) { var ww = _web3_dot_shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.changed = function(f) { _web3_dot_shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_shh.watchMessages(this.w)) }; return ret; }"); \
_frame->evaluateJavaScript("_web3_dot_shh.watch = function(a) { return _web3_dot_shh.makeWatch(JSON.stringify(a)) }"); \
_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.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \
_frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \
} \
}

32
libserpent/compiler.cpp

@ -123,9 +123,10 @@ programData opcodeify(Node node,
token("$begincode"+symb+".endcode"+symb, m), token("DUP1", m),
token("$begincode"+symb, m), sub.code, token("CODECOPY", m),
token("$endcode"+symb, m), token("JUMP", m),
token("~begincode"+symb, m), code, token("~endcode"+symb, m)
token("~begincode"+symb, m), code, token("~endcode"+symb, m),
token("JUMPDEST", m)
};
return pd(sub.aux, multiToken(nodelist, 10, m), 1);
return pd(sub.aux, multiToken(nodelist, 11, m), 1);
}
// Stack variables
if (node.val == "with") {
@ -171,9 +172,9 @@ programData opcodeify(Node node,
cond.code,
token("$endif"+symb, m), token("JUMPI", m),
action.code,
token("~endif"+symb, m)
token("~endif"+symb, m), token("JUMPDEST", m)
};
return pd(aux, multiToken(nodelist, 5, m), 0);
return pd(aux, multiToken(nodelist, 6, m), 0);
}
// 3-part conditional
else if (node.val == "if" && node.args.size() == 3) {
@ -190,13 +191,15 @@ programData opcodeify(Node node,
if (elsed.outs > outs) elsed.code = popwrap(elsed.code);
Node nodelist[] = {
ifd.code,
token("NOT", m), token("$else"+symb, m), token("JUMPI", m),
token("NOT", m),
token("$else"+symb, m), token("JUMPI", m),
thend.code,
token("$endif"+symb, m), token("JUMP", m), token("~else"+symb, m),
token("$endif"+symb, m), token("JUMP", m),
token("~else"+symb, m), token("JUMPDEST", m),
elsed.code,
token("~endif"+symb, m)
token("~endif"+symb, m), token("JUMPDEST", m)
};
return pd(aux, multiToken(nodelist, 10, m), outs);
return pd(aux, multiToken(nodelist, 12, m), outs);
}
// While (rewritten to this in rewrites)
else if (node.val == "until") {
@ -207,13 +210,14 @@ programData opcodeify(Node node,
err("Condition of while/until loop has arity 0", m);
if (action.outs) action.code = popwrap(action.code);
Node nodelist[] = {
token("~beg"+symb, m),
token("~beg"+symb, m), token("JUMPDEST", m),
cond.code,
token("$end"+symb, m), token("JUMPI", m),
action.code,
token("$beg"+symb, m), token("JUMP", m), token("~end"+symb, m)
token("$beg"+symb, m), token("JUMP", m),
token("~end"+symb, m), token("JUMPDEST", m)
};
return pd(aux, multiToken(nodelist, 8, m));
return pd(aux, multiToken(nodelist, 10, m));
}
// Memory allocations
else if (node.val == "alloc") {
@ -298,7 +302,7 @@ Node finalize(programData c) {
Metadata m = c.code.metadata;
// If we are using both alloc and variables, we need to pre-zfill
// some memory
if (c.aux.allocUsed && c.aux.vars.size() > 0) {
if ((c.aux.allocUsed || c.aux.calldataUsed) && c.aux.vars.size() > 0) {
Node nodelist[] = {
token("0", m),
token(unsignedToDecimal(c.aux.vars.size() * 32 - 1)),
@ -309,8 +313,8 @@ Node finalize(programData c) {
// If msg.data is being used as an array, then we need to copy it
if (c.aux.calldataUsed) {
Node nodelist[] = {
token("MSIZE", m), token("CALLDATASIZE", m), token("MSIZE", m),
token("0", m), token("CALLDATACOPY", m),
token("MSIZE", m), token("CALLDATASIZE", m), token("0", m),
token("MSIZE", m), token("CALLDATACOPY", m),
token(c.aux.vars["'msg.data"], m), token("MSTORE", m)
};
bottom.push_back(multiToken(nodelist, 7, m));

12
libserpent/funcs.cpp

@ -14,6 +14,10 @@ Node compileToLLL(std::string input) {
return rewrite(parseSerpent(input));
}
Node compileChunkToLLL(std::string input) {
return rewriteChunk(parseSerpent(input));
}
std::string compile(std::string input) {
return compileLLL(compileToLLL(input));
}
@ -21,3 +25,11 @@ std::string compile(std::string input) {
std::vector<Node> prettyCompile(std::string input) {
return prettyCompileLLL(compileToLLL(input));
}
std::string compileChunk(std::string input) {
return compileLLL(compileChunkToLLL(input));
}
std::vector<Node> prettyCompileChunk(std::string input) {
return prettyCompileLLL(compileChunkToLLL(input));
}

6
libserpent/funcs.h

@ -24,6 +24,12 @@
Node compileToLLL(std::string input);
Node compileChunkToLLL(std::string input);
std::string compile(std::string input);
std::vector<Node> prettyCompile(std::string input);
std::string compileChunk(std::string input);
std::vector<Node> prettyCompileChunk(std::string input);

4
libserpent/opcodes.h

@ -72,11 +72,11 @@ Mapping mapping[] = {
Mapping("PC", 0x5a, 0, 1),
Mapping("MSIZE", 0x5b, 0, 1),
Mapping("GAS", 0x5c, 0, 1),
Mapping("JUMPDEST", 0x5d, 0, 0),
Mapping("CREATE", 0xf0, 3, 1),
Mapping("CALL", 0xf1, 7, 1),
Mapping("RETURN", 0xf2, 2, 0),
Mapping("POST", 0xf3, 5, 0),
Mapping("CALL_STATELESS", 0xf4, 7, 1),
Mapping("CALL_CODE", 0xf3, 7, 1),
Mapping("SUICIDE", 0xff, 1, 0),
Mapping("---END---", 0x00, 0, 0),
};

24
libserpent/parser.cpp

@ -32,7 +32,7 @@ int toktype(Node tok) {
if (v == "(" || v == "[" || v == "{") return LPAREN;
else if (v == ")" || v == "]" || v == "}") return RPAREN;
else if (v == ",") return COMMA;
else if (v == "!" || v == "not") return UNARY_OP;
else if (v == "!" || v == "not" || v == "neg") return UNARY_OP;
else if (precedence(tok) >= 0) return BINARY_OP;
if (tok.val[0] != '"' && tok.val[0] != '\'') {
for (unsigned i = 0; i < tok.val.length(); i++) {
@ -91,17 +91,19 @@ std::vector<Node> shuntingYard(std::vector<Node> tokens) {
// If binary op, keep popping from stack while higher bedmas precedence
else if (toktyp == BINARY_OP) {
if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) {
oq.push_back(token("0", tok.metadata));
stack.push_back(token("neg", tok.metadata));
}
int prec = precedence(tok);
while (stack.size()
&& (toktype(stack.back()) == BINARY_OP
|| toktype(stack.back()) == UNARY_OP)
&& precedence(stack.back()) <= prec) {
oq.push_back(stack.back());
stack.pop_back();
else {
int prec = precedence(tok);
while (stack.size()
&& (toktype(stack.back()) == BINARY_OP
|| toktype(stack.back()) == UNARY_OP)
&& precedence(stack.back()) <= prec) {
oq.push_back(stack.back());
stack.pop_back();
}
stack.push_back(tok);
}
stack.push_back(tok);
}
// Comma means finish evaluating the argument
else if (toktyp == COMMA) {
@ -153,10 +155,10 @@ Node treefy(std::vector<Node> stream) {
else if (typ == RPAREN) {
std::vector<Node> args;
while (1) {
if (!oq.size()) err("Bracket without matching", tok.metadata);
if (toktype(oq.back()) == LPAREN) break;
args.push_back(oq.back());
oq.pop_back();
if (!oq.size()) err("Bracket without matching", tok.metadata);
}
oq.pop_back();
args.push_back(oq.back());

60
libserpent/rewriter.cpp

@ -17,9 +17,7 @@ std::string valid[][3] = {
{ "alloc", "1", "1" },
{ "array", "1", "1" },
{ "call", "2", "4" },
{ "call_stateless", "2", "4" },
{ "post", "4", "5" },
{ "postcall", "3", "4" },
{ "call_code", "2", "4" },
{ "create", "1", "4" },
{ "msg", "4", "6" },
{ "msg_stateless", "4", "6" },
@ -28,6 +26,8 @@ std::string valid[][3] = {
{ "sha3", "1", "2" },
{ "return", "1", "2" },
{ "inset", "1", "1" },
{ "min", "2", "2" },
{ "max", "2", "2" },
{ "array_lit", "0", tt256 },
{ "seq", "0", tt256 },
{ "---END---", "", "" } //Keep this line at the end of the list
@ -70,6 +70,14 @@ std::string macros[][2] = {
"(!= $a $b)",
"(not (eq $a $b))"
},
{
"(min a b)",
"(with $1 a (with $2 b (if (lt $1 $2) $1 $2)))"
},
{
"(max a b)",
"(with $1 a (with $2 b (if (lt $1 $2) $2 $1)))"
},
{
"(if $cond $do (else $else))",
"(if $cond $do $else)"
@ -134,22 +142,6 @@ std::string macros[][2] = {
"(send $to $value)",
"(call (sub (gas) 25) $to $value 0 0 0 0)"
},
{
"(post $gas $to $value $datain $datainsz)",
"(~post $gas $to $value $datain (mul $datainsz 32))"
},
{
"(post $gas $to $value $datain)",
"(seq (set $1 $datain) (~post $gas $to $value (ref $1) 32))"
},
{
"(postcall $gas $to $datain)",
"(post $gas $to 0 $datain)",
},
{
"(postcall $gas $to $datain $datainsz)",
"(post $gas $to 0 $datain $datainsz)",
},
{
"(send $gas $to $value)",
"(call $gas $to $value 0 0 0 0)"
@ -229,32 +221,32 @@ std::string macros[][2] = {
},
{
"(msg $gas $to $val $inp $inpsz $outsz)",
"(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))"
"(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (seq (call $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2))))"
},
// Call stateless and msg stateless
{
"(call_stateless $f $dataval)",
"(msg_stateless (sub (gas) 45) $f 0 $dataval)"
"(call_code $f $dataval)",
"(msg_code (sub (gas) 45) $f 0 $dataval)"
},
{
"(call_stateless $f $inp $inpsz)",
"(msg_stateless (sub (gas) 25) $f 0 $inp $inpsz)"
"(call_code $f $inp $inpsz)",
"(msg_code (sub (gas) 25) $f 0 $inp $inpsz)"
},
{
"(call_stateless $f $inp $inpsz $outsz)",
"(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call_stateless (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))"
"(call_code $f $inp $inpsz $outsz)",
"(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call_code (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))"
},
{
"(msg_stateless $gas $to $val $inp $inpsz)",
"(seq (call_stateless $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))"
"(msg_code $gas $to $val $inp $inpsz)",
"(seq (call_code $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))"
},
{
"(msg_stateless $gas $to $val $dataval)",
"(seq (set $1 $dataval) (call_stateless $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))"
"(msg_code $gas $to $val $dataval)",
"(seq (set $1 $dataval) (call_code $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))"
},
{
"(msg_stateless $gas $to $val $inp $inpsz $outsz)",
"(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call_stateless $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))"
"(msg_code $gas $to $val $inp $inpsz $outsz)",
"(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call_code $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))"
},
// Wrappers
{
@ -561,4 +553,8 @@ Node rewrite(Node inp) {
return optimize(apply_rules(validate(preprocess(inp))));
}
Node rewriteChunk(Node inp) {
return optimize(apply_rules(validate(inp)));
}
using namespace std;

3
libserpent/rewriter.h

@ -10,4 +10,7 @@
// Applies rewrite rules
Node rewrite(Node inp);
// Applies rewrite rules adding without wrapper
Node rewriteChunk(Node inp);
#endif

6
libserpent/util.cpp

@ -137,7 +137,7 @@ std::string strToNumeric(std::string inp) {
}
else if (inp.substr(0,2) == "0x") {
for (unsigned i = 2; i < inp.length(); i++) {
int dig = std::string("0123456789abcdef").find(inp[i]);
int dig = std::string("0123456789abcdef0123456789ABCDEF").find(inp[i]) % 16;
if (dig < 0) return "";
o = decimalAdd(decimalMul(o,"16"), unsignedToDecimal(dig));
}
@ -219,8 +219,8 @@ void err(std::string errtext, Metadata met) {
std::string err = "Error (file \"" + met.file + "\", line " +
unsignedToDecimal(met.ln + 1) + ", char " + unsignedToDecimal(met.ch) +
"): " + errtext;
std::cerr << err << "\n";
throw(err);
std::cerr << err << "\n";
throw(err);
}
//Bin to hex

27
libsolidity/CMakeLists.txt

@ -16,33 +16,8 @@ file(GLOB HEADERS "*.h")
include_directories(..)
target_link_libraries(${EXECUTABLE} evmface)
target_link_libraries(${EXECUTABLE} devcore)
if("${TARGET_PLATFORM}" STREQUAL "w64")
target_link_libraries(${EXECUTABLE} boost_system-mt-s)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} ws2_32)
target_link_libraries(${EXECUTABLE} mswsock)
target_link_libraries(${EXECUTABLE} shlwapi)
elseif (APPLE)
# Latest mavericks boost libraries only come with -mt
target_link_libraries(${EXECUTABLE} boost_system-mt)
target_link_libraries(${EXECUTABLE} boost_thread-mt)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
elseif (UNIX)
target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY})
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY})
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
else ()
target_link_libraries(${EXECUTABLE} boost_system)
target_link_libraries(${EXECUTABLE} boost_thread)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
target_link_libraries(${EXECUTABLE} evmface)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

1
libsolidity/Types.cpp

@ -53,6 +53,7 @@ std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
return std::make_shared<BoolType>();
else
assert(false); // @todo add other tyes
return std::shared_ptr<Type>();
}
std::shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)

18
libwhisper/Common.cpp

@ -36,17 +36,23 @@ BuildTopic& BuildTopic::shiftBytes(bytes const& _b)
h256 TopicFilter::sha3() const
{
RLPStream s;
fillStream(s);
streamRLP(s);
return dev::sha3(s.out());
}
TopicMask BuildTopicMask::toTopicMask() const
{
TopicMask ret;
for (auto i = 0; i < 32; ++i)
{
ret.first[i] = m_parts[i * m_parts.size() / 32][i];
ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0;
}
if (m_parts.size())
for (auto i = 0; i < 32; ++i)
{
ret.first[i] = m_parts[i * m_parts.size() / 32][i];
ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0;
}
return ret;
}
/*
web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); })
k = web3.shh.newIdentity()
web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")})
*/

8
libwhisper/Common.h

@ -64,6 +64,7 @@ using Topic = h256;
class BuildTopic
{
public:
BuildTopic() {}
template <class T> BuildTopic(T const& _t) { shift(_t); }
template <class T> BuildTopic& shift(T const& _r) { return shiftBytes(RLPStream().append(_r).out()); }
@ -75,8 +76,6 @@ public:
Topic toTopic() const { Topic ret; for (auto i = 0; i < 32; ++i) ret[i] = m_parts[i * m_parts.size() / 32][i]; return ret; }
protected:
BuildTopic() {}
BuildTopic& shiftBytes(bytes const& _b);
h256s m_parts;
@ -93,7 +92,7 @@ public:
TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {}
TopicFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {}
void fillStream(RLPStream& _s) const { _s << m_topicMasks; }
void streamRLP(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const;
bool matches(Envelope const& _m) const;
@ -105,7 +104,10 @@ private:
class BuildTopicMask: BuildTopic
{
public:
enum EmptyType { Empty };
BuildTopicMask() { shift(); }
BuildTopicMask(EmptyType) {}
template <class T> BuildTopicMask(T const& _t) { shift(_t); }
template <class T> BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; }

30
libwhisper/Interface.h

@ -43,6 +43,8 @@ namespace shh
Topic mask;
};*/
class Watch;
struct InstalledFilter
{
InstalledFilter(TopicFilter const& _f): filter(_f) {}
@ -73,13 +75,14 @@ public:
virtual void uninstallWatch(unsigned _watchId) = 0;
virtual h256s peekWatch(unsigned _watchId) const = 0;
virtual h256s checkWatch(unsigned _watchId) = 0;
virtual h256s watchMessages(unsigned _watchId) = 0;
virtual Envelope envelope(h256 _m) const = 0;
void post(bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topic, _ttl, _workToProve)); }
void post(Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_to, _topic, _ttl, _workToProve)); }
void post(Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topic, _ttl, _workToProve)); }
void post(Secret _from, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topic, _ttl, _workToProve)); }
void post(Secret _from, Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _to, _topic, _ttl, _workToProve)); }
void post(Secret _from, Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topic, _ttl, _workToProve)); }
};
struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; };
@ -87,9 +90,11 @@ struct WatshhChannel: public dev::LogChannel { static const char* name() { retur
}
}
/*
namespace std { void swap(shh::Watch& _a, shh::Watch& _b); }
namespace std { void swap(dev::shh::Watch& _a, dev::shh::Watch& _b); }
namespace dev
{
namespace shh
{
@ -99,28 +104,29 @@ class Watch: public boost::noncopyable
public:
Watch() {}
Watch(Whisper& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {}
Watch(Whisper& _c, TopicFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {}
Watch(Interface& _c, TopicMask const& _f): m_c(&_c), m_id(_c.installWatch(_f)) {}
Watch(Interface& _c, TopicFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {}
~Watch() { if (m_c) m_c->uninstallWatch(m_id); }
bool check() { return m_c ? m_c->checkWatch(m_id) : false; }
bool peek() { return m_c ? m_c->peekWatch(m_id) : false; }
h256s check() { return m_c ? m_c->checkWatch(m_id) : h256s(); }
h256s peek() { return m_c ? m_c->peekWatch(m_id) : h256s(); }
private:
Whisper* m_c;
Interface* m_c;
unsigned m_id;
};
}
}
namespace shh
namespace std
{
inline void swap(shh::Watch& _a, shh::Watch& _b)
inline void swap(dev::shh::Watch& _a, dev::shh::Watch& _b)
{
swap(_a.m_c, _b.m_c);
swap(_a.m_id, _b.m_id);
}
}
*/

20
libwhisper/Message.cpp

@ -34,33 +34,36 @@ Message::Message(Envelope const& _e, Secret const& _s)
if (_s)
if (!decrypt(_s, &(_e.data()), b))
return;
populate(_s ? b : _e.data());
m_to = KeyPair(_s).pub();
if (populate(_s ? b : _e.data()))
m_to = KeyPair(_s).pub();
}
catch (...) // Invalid secret? TODO: replace ... with InvalidSecret
{
}
}
void Message::populate(bytes const& _data)
bool Message::populate(bytes const& _data)
{
if (!_data.size())
return;
return false;
byte flags = _data[0];
if (!!(flags & ContainsSignature) && _data.size() > sizeof(Signature) + 1) // has a signature
if (!!(flags & ContainsSignature) && _data.size() >= sizeof(Signature) + 1) // has a signature
{
bytesConstRef payload = bytesConstRef(&_data).cropped(1, _data.size() - sizeof(Signature) - 1);
h256 h = sha3(payload);
Signature const& sig = *(Signature const*)&(_data[1 + payload.size()]);
m_from = recover(sig, h);
if (!m_from)
return false;
m_payload = payload.toBytes();
}
else
m_payload = bytesConstRef(&_data).cropped(1).toBytes();
return true;
}
Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve)
Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) const
{
Envelope ret(time(0) + _ttl, _ttl, _topic);
@ -91,11 +94,6 @@ Message Envelope::open(Secret const& _s) const
return Message(*this, _s);
}
Message Envelope::open() const
{
return Message(*this);
}
unsigned Envelope::workProved() const
{
h256 d[2];

22
libwhisper/Message.h

@ -55,9 +55,9 @@ public:
operator bool() const { return !!m_expiry; }
void streamOut(RLPStream& _s, bool _withNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; }
h256 sha3() const { RLPStream s; streamOut(s, true); return dev::sha3(s.out()); }
h256 sha3NoNonce() const { RLPStream s; streamOut(s, false); return dev::sha3(s.out()); }
void streamRLP(RLPStream& _s, bool _withNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; }
h256 sha3() const { RLPStream s; streamRLP(s, true); return dev::sha3(s.out()); }
h256 sha3NoNonce() const { RLPStream s; streamRLP(s, false); return dev::sha3(s.out()); }
unsigned sent() const { return m_expiry - m_ttl; }
unsigned expiry() const { return m_expiry; }
@ -65,8 +65,7 @@ public:
Topic const& topic() const { return m_topic; }
bytes const& data() const { return m_data; }
Message open(Secret const& _s) const;
Message open() const;
Message open(Secret const& _s = Secret()) const;
unsigned workProved() const;
void proveWork(unsigned _ms);
@ -102,19 +101,22 @@ public:
Public to() const { return m_to; }
bytes const& payload() const { return m_payload; }
void setFrom(Public _from) { m_from = _from; }
void setTo(Public _to) { m_to = _to; }
void setPayload(bytes const& _payload) { m_payload = _payload; }
void setPayload(bytes&& _payload) { swap(m_payload, _payload); }
operator bool() const { return !!m_payload.size() || m_from || m_to; }
/// Turn this message into a ditributable Envelope.
Envelope seal(Secret _from, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50);
Envelope seal(Secret _from, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) const;
// Overloads for skipping _from or specifying _to.
Envelope seal(Topic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { return seal(Secret(), _topic, _workToProve, _ttl); }
Envelope seal(Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(Secret(), _topic, _workToProve, _ttl); }
Envelope seal(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); }
Envelope seal(Topic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topic, _workToProve, _ttl); }
Envelope sealTo(Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(Secret(), _topic, _workToProve, _ttl); }
Envelope sealTo(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); }
private:
void populate(bytes const& _data);
bool populate(bytes const& _data);
Public m_from;
Public m_to;

44
libwhisper/WhisperHost.cpp

@ -47,12 +47,19 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
if (m_messages.count(_m))
{
UpgradeGuard ll(l);
m_messages.at(_m).streamOut(_s, true);
auto const& m = m_messages.at(_m);
cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data());
m.streamRLP(_s, true);
}
}
void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p)
{
cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data());
if (_m.expiry() <= time(0))
return;
auto h = _m.sha3();
{
UpgradableGuard l(x_messages);
@ -60,9 +67,10 @@ void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p)
return;
UpgradeGuard ll(l);
m_messages[h] = _m;
m_expiryQueue[_m.expiry()] = h;
}
if (_p)
// if (_p)
{
Guard l(m_filterLock);
for (auto const& f: m_filters)
@ -107,6 +115,28 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f)
return installWatchOnId(h);
}
h256s WhisperHost::watchMessages(unsigned _watchId)
{
cleanup();
h256s ret;
auto wit = m_watches.find(_watchId);
if (wit == m_watches.end())
return ret;
TopicFilter f;
{
Guard l(m_filterLock);
auto fit = m_filters.find(wit->second.id);
if (fit == m_filters.end())
return ret;
f = fit->second.filter;
}
ReadGuard l(x_messages);
for (auto const& m: m_messages)
if (f.matches(m.second))
ret.push_back(m.first);
return ret;
}
void WhisperHost::uninstallWatch(unsigned _i)
{
cwatshh << "XXX" << _i;
@ -124,3 +154,13 @@ void WhisperHost::uninstallWatch(unsigned _i)
if (!--fit->second.refCount)
m_filters.erase(fit);
}
void WhisperHost::cleanup()
{
// remove old messages.
// should be called every now and again.
auto now = time(0);
WriteGuard l(x_messages);
for (auto it = m_expiryQueue.begin(); it != m_expiryQueue.end() && it->first <= now; it = m_expiryQueue.erase(it))
m_messages.erase(it->second);
}

20
libwhisper/WhisperHost.h

@ -48,16 +48,21 @@ public:
unsigned protocolVersion() const { return 0; }
virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr);
virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override;
using Interface::installWatch;
virtual unsigned installWatch(TopicFilter const& _filter);
virtual unsigned installWatchOnId(h256 _filterId);
virtual void uninstallWatch(unsigned _watchId);
virtual h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } }
virtual h256s checkWatch(unsigned _watchId) { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; }
virtual unsigned installWatch(TopicFilter const& _filter) override;
virtual unsigned installWatchOnId(h256 _filterId) override;
virtual void uninstallWatch(unsigned _watchId) override;
virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } }
virtual h256s checkWatch(unsigned _watchId) override { cleanup(); dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; }
virtual h256s watchMessages(unsigned _watchId) override;
virtual Envelope envelope(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } }
virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } }
std::map<h256, Envelope> all() const { ReadGuard l(x_messages); return m_messages; }
void cleanup();
private:
void streamMessage(h256 _m, RLPStream& _s) const;
@ -66,6 +71,7 @@ private:
mutable dev::SharedMutex x_messages;
std::map<h256, Envelope> m_messages;
std::map<unsigned, h256> m_expiryQueue;
mutable dev::Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;

205
sc/cmdline.cpp

@ -3,100 +3,117 @@
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <libserpent/funcs.h>
#include <libdevcore/Exceptions.h>
int main(int argv, char** argc)
{
if (argv == 1)
{
std::cerr << "Must provide a command and arguments! Try parse, rewrite, compile, assemble\n";
return 0;
}
std::string flag = "";
std::string command = argc[1];
std::string input;
std::string secondInput;
if (std::string(argc[1]) == "-s")
{
flag = command.substr(1);
command = argc[2];
input = "";
std::string line;
while (std::getline(std::cin, line))
{
input += line + "\n";
}
secondInput = argv == 3 ? "" : argc[3];
}
else
{
if (argv == 2)
{
std::cerr << "Not enough arguments for serpent cmdline\n";
BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Not enough arguments for serpent cmdline"));
}
input = argc[2];
secondInput = argv == 3 ? "" : argc[3];
}
bool haveSec = secondInput.length() > 0;
if (command == "parse" || command == "parse_serpent")
std::cout << printAST(parseSerpent(input), haveSec) << "\n";
else if (command == "rewrite")
std::cout << printAST(rewrite(parseLLL(input, true)), haveSec) << "\n";
else if (command == "compile_to_lll")
std::cout << printAST(compileToLLL(input), haveSec) << "\n";
else if (command == "build_fragtree")
std::cout << printAST(buildFragmentTree(parseLLL(input, true))) << "\n";
else if (command == "compile_lll")
std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n";
else if (command == "dereference")
std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n";
else if (command == "pretty_assemble")
std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n";
else if (command == "pretty_compile_lll")
std::cout << printTokens(prettyCompileLLL(parseLLL(input, true))) << "\n";
else if (command == "pretty_compile")
std::cout << printTokens(prettyCompile(input)) << "\n";
else if (command == "assemble")
std::cout << assemble(parseLLL(input, true)) << "\n";
else if (command == "serialize")
std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n";
else if (command == "flatten")
std::cout << printTokens(flatten(parseLLL(input, true))) << "\n";
else if (command == "deserialize")
std::cout << printTokens(deserialize(hexToBin(input))) << "\n";
else if (command == "compile")
std::cout << binToHex(compile(input)) << "\n";
else if (command == "encode_datalist")
{
std::vector<Node> tokens = tokenize(input);
std::vector<std::string> o;
for (int i = 0; i < (int)tokens.size(); i++)
o.push_back(tokens[i].val);
std::cout << binToHex(encodeDatalist(o)) << "\n";
}
else if (command == "decode_datalist")
{
std::vector<std::string> o = decodeDatalist(hexToBin(input));
std::vector<Node> tokens;
for (int i = 0; i < (int)o.size(); i++)
tokens.push_back(token(o[i]));
std::cout << printTokens(tokens) << "\n";
}
else if (command == "tokenize")
std::cout << printTokens(tokenize(input));
else if (command == "biject")
{
if (argv == 3)
std::cerr << "Not enough arguments for biject\n";
int pos = decimalToUnsigned(secondInput);
std::vector<Node> n = prettyCompile(input);
if (pos >= (int)n.size())
std::cerr << "Code position too high\n";
Metadata m = n[pos].metadata;
std::cout << "Opcode: " << n[pos].val << ", file: " << m.file <<
", line: " << m.ln << ", char: " << m.ch << "\n";
}
int main(int argv, char** argc) {
if (argv == 1) {
std::cerr << "Must provide a command and arguments! Try parse, rewrite, compile, assemble\n";
return 0;
}
std::string flag = "";
std::string command = argc[1];
std::string input;
std::string secondInput;
if (std::string(argc[1]) == "-s") {
flag = command.substr(1);
command = argc[2];
input = "";
std::string line;
while (std::getline(std::cin, line)) {
input += line + "\n";
}
secondInput = argv == 3 ? "" : argc[3];
}
else {
if (argv == 2) {
std::cerr << "Not enough arguments for serpent cmdline\n";
throw(0);
}
input = argc[2];
secondInput = argv == 3 ? "" : argc[3];
}
bool haveSec = secondInput.length() > 0;
if (command == "parse" || command == "parse_serpent") {
std::cout << printAST(parseSerpent(input), haveSec) << "\n";
}
else if (command == "rewrite") {
std::cout << printAST(rewrite(parseLLL(input, true)), haveSec) << "\n";
}
else if (command == "compile_to_lll") {
std::cout << printAST(compileToLLL(input), haveSec) << "\n";
}
else if (command == "rewrite_chunk") {
std::cout << printAST(rewriteChunk(parseLLL(input, true)), haveSec) << "\n";
}
else if (command == "compile_chunk_to_lll") {
std::cout << printAST(compileChunkToLLL(input), haveSec) << "\n";
}
else if (command == "build_fragtree") {
std::cout << printAST(buildFragmentTree(parseLLL(input, true))) << "\n";
}
else if (command == "compile_lll") {
std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n";
}
else if (command == "dereference") {
std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n";
}
else if (command == "pretty_assemble") {
std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n";
}
else if (command == "pretty_compile_lll") {
std::cout << printTokens(prettyCompileLLL(parseLLL(input, true))) << "\n";
}
else if (command == "pretty_compile") {
std::cout << printTokens(prettyCompile(input)) << "\n";
}
else if (command == "pretty_compile_chunk") {
std::cout << printTokens(prettyCompileChunk(input)) << "\n";
}
else if (command == "assemble") {
std::cout << assemble(parseLLL(input, true)) << "\n";
}
else if (command == "serialize") {
std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n";
}
else if (command == "flatten") {
std::cout << printTokens(flatten(parseLLL(input, true))) << "\n";
}
else if (command == "deserialize") {
std::cout << printTokens(deserialize(hexToBin(input))) << "\n";
}
else if (command == "compile") {
std::cout << binToHex(compile(input)) << "\n";
}
else if (command == "compile_chunk") {
std::cout << binToHex(compileChunk(input)) << "\n";
}
else if (command == "encode_datalist") {
std::vector<Node> tokens = tokenize(input);
std::vector<std::string> o;
for (int i = 0; i < (int)tokens.size(); i++) {
o.push_back(tokens[i].val);
}
std::cout << binToHex(encodeDatalist(o)) << "\n";
}
else if (command == "decode_datalist") {
std::vector<std::string> o = decodeDatalist(hexToBin(input));
std::vector<Node> tokens;
for (int i = 0; i < (int)o.size(); i++)
tokens.push_back(token(o[i]));
std::cout << printTokens(tokens) << "\n";
}
else if (command == "tokenize") {
std::cout << printTokens(tokenize(input));
}
else if (command == "biject") {
if (argv == 3)
std::cerr << "Not enough arguments for biject\n";
int pos = decimalToUnsigned(secondInput);
std::vector<Node> n = prettyCompile(input);
if (pos >= (int)n.size())
std::cerr << "Code position too high\n";
Metadata m = n[pos].metadata;
std::cout << "Opcode: " << n[pos].val << ", file: " << m.file <<
", line: " << m.ln << ", char: " << m.ch << "\n";
}
}

17
solc/CMakeLists.txt

@ -9,23 +9,6 @@ set(EXECUTABLE solc)
add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} solidity)
target_link_libraries(${EXECUTABLE} devcore)
if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
target_link_libraries(${EXECUTABLE} gcc)
target_link_libraries(${EXECUTABLE} gdi32)
target_link_libraries(${EXECUTABLE} ws2_32)
target_link_libraries(${EXECUTABLE} mswsock)
target_link_libraries(${EXECUTABLE} shlwapi)
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
else ()
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
install( TARGETS ${EXECUTABLE} DESTINATION bin )

21
solc/main.cpp

@ -1,3 +1,24 @@
/*
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/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity commandline compiler.
*/
#include <string>
#include <iostream>

4
test/MemTrie.cpp

@ -437,12 +437,12 @@ MemTrie::~MemTrie()
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
{
return m_root ? m_root->rlp() : bytes();
return m_root ? m_root->rlp() : dev::rlp(bytesConstRef());
}
void MemTrie::debugPrint()

6
test/TrieHash.cpp

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

3
test/crypto.cpp

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

13
test/genesis.cpp

@ -35,9 +35,20 @@ namespace js = json_spirit;
BOOST_AUTO_TEST_CASE(genesis_tests)
{
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
cnote << "Testing Genesis block...";
js::mValue v;
string s = asString(contents("../../../tests/genesishashestest.json"));
string s = asString(contents(testPath + "/genesishashestest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'genesishashestest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);

13
test/hexPrefix.cpp

@ -33,9 +33,20 @@ namespace js = json_spirit;
BOOST_AUTO_TEST_CASE(hexPrefix_test)
{
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
cnote << "Testing Hex-Prefix-Encode...";
js::mValue v;
string s = asString(contents("../../../tests/hexencodetest.json"));
string s = asString(contents(testPath + "/hexencodetest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content from 'hexencodetest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
for (auto& i: v.get_obj())

2
test/main.cpp

@ -44,7 +44,7 @@ using namespace dev::eth;
BOOST_AUTO_TEST_CASE(basic_tests)
{
/* RLPStream s;
BlockInfo::genesis().fillStream(s, false);
BlockInfo::genesis().streamRLP(s, false);
std::cout << RLP(s.out()) << std::endl;
std::cout << toHex(s.out()) << std::endl;
std::cout << sha3(s.out()) << std::endl;*/

13
test/rlp.cpp

@ -61,7 +61,18 @@ namespace dev
static void getRLPTestCases(js::mValue& v)
{
string s = asString(contents("../../../tests/rlptest.json"));
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
string s = asString(contents(testPath + "/rlptest.json"));
BOOST_REQUIRE_MESSAGE( s.length() > 0,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);

1
test/state.cpp

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

13
test/trie.cpp

@ -49,9 +49,20 @@ static unsigned fac(unsigned _i)
BOOST_AUTO_TEST_CASE(trie_tests)
{
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
cnote << "Testing Trie...";
js::mValue v;
string s = asString(contents("../../../tests/trietest.json"));
string s = asString(contents(testPath + "/trietest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
for (auto& i: v.get_obj())

71
test/vm.cpp

@ -20,9 +20,8 @@
* vm test functions.
*/
#include "vm.h"
#include <libdevcore/CommonIO.h>
#include <boost/filesystem/path.hpp>
#include "vm.h"
//#define FILL_TESTS
@ -45,7 +44,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
m_s.noteSending(myAddress);
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)
m_ms.internal.pop_back();
@ -56,14 +55,13 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
get<3>(addresses[ret]) = m_s.code(ret);
}
t.receiveAddress = ret;
t.type = eth::Transaction::ContractCreation;
callcreates.push_back(t);
return ret;
}
bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride)
{
u256 contractgas = 0xffff;
Transaction t;
@ -71,6 +69,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
t.gasPrice = gasPrice;
t.gas = *_gas;
t.data = _data.toVector();
t.type = eth::Transaction::MessageCall;
t.receiveAddress = _receiveAddress;
callcreates.push_back(t);
@ -91,7 +90,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!m_s.addresses().count(myAddress))
{
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)
m_ms.internal.pop_back();
if (na != myAddress)
@ -116,7 +115,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{
m_s.noteSending(myAddress);
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)
m_ms.internal.pop_back();
@ -131,7 +130,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
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()), simpleTrace<ExtVM>(), 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
@ -146,12 +145,15 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!ret)
return false;
// TODO: @CJentzsch refund SSTORE stuff.
// TODO: @CJentzsch test logs.
// do suicides
for (auto const& f: suicides)
for (auto const& f: sub.suicides)
addresses.erase(f);
// 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))
{
@ -357,9 +359,9 @@ void FakeExtVM::importExec(mObject& _o)
code = &thisTxCode;
if (_o["code"].type() == str_type)
if (_o["code"].get_str().find_first_of("0x") == 0)
thisTxCode = compileLLL(_o["code"].get_str());
else
thisTxCode = fromHex(_o["code"].get_str().substr(2));
else
thisTxCode = compileLLL(_o["code"].get_str());
else if (_o["code"].type() == array_type)
for (auto const& j: _o["code"].get_array())
thisTxCode.push_back(toByte(j));
@ -384,7 +386,7 @@ mArray FakeExtVM::exportCallCreates()
for (Transaction const& tx: callcreates)
{
mObject o;
o["destination"] = toString(tx.receiveAddress);
o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress);
push(o, "gasLimit", tx.gas);
push(o, "value", tx.value);
o["data"] = "0x" + toHex(tx.data);
@ -403,6 +405,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
BOOST_REQUIRE(tx.count("destination") > 0);
BOOST_REQUIRE(tx.count("gasLimit") > 0);
Transaction t;
t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall;
t.receiveAddress = Address(tx["destination"].get_str());
t.value = toInt(tx["value"]);
t.gas = toInt(tx["gasLimit"]);
@ -418,8 +421,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)
_origin = _sender;
@ -445,9 +451,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
out = vm.go(evm, _onOp);
if (o_ms)
o_ms->output = out.toBytes();
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
// TODO: deal with evm.sub
}
catch (OutOfGas const& /*_e*/)
{
@ -482,8 +486,6 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
return _newAddress;
}
namespace dev { namespace test {
void doTests(json_spirit::mValue& v, bool _fillin)
@ -515,7 +517,7 @@ void doTests(json_spirit::mValue& v, bool _fillin)
VM vm(fev.gas);
try
{
output = vm.go(fev).toVector();
output = vm.go(fev, fev.simpleTrace<FakeExtVM>()).toVector();
}
catch (Exception const& _e)
{
@ -751,3 +753,32 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest)
{
dev::test::executeTests("vmSystemOperationsTest");
}
BOOST_AUTO_TEST_CASE(userDefinedFile)
{
if (boost::unit_test::framework::master_test_suite().argc == 2)
{
string filename = boost::unit_test::framework::master_test_suite().argv[1];
int currentVerbosity = g_logVerbosity;
g_logVerbosity = 12;
try
{
cnote << "Testing VM..." << "user defined test";
json_spirit::mValue v;
string s = asString(contents(filename));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v);
dev::test::doTests(v, false);
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e));
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed VM Test with Exception: " << _e.what());
}
g_logVerbosity = currentVerbosity;
}
}

36
test/vm.h

@ -28,6 +28,7 @@ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
#include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h"
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h>
#include <libevm/ExtVMFace.h>
#include <libevm/VM.h>
@ -44,7 +45,7 @@ class FakeState: public eth::State
{
public:
/// 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_sub = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0);
};
class FakeExtVM: public eth::ExtVMFace
@ -80,6 +81,11 @@ public:
json_spirit::mArray exportCallCreates();
void importCallCreates(json_spirit::mArray& _callcreates);
template<typename ExtVMType>
eth::OnOpFunc simpleTrace();
FakeState state() const { return m_s; }
std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes>> addresses;
eth::Transactions callcreates;
bytes thisTxData;
@ -91,4 +97,32 @@ private:
eth::Manifest m_ms;
};
template<typename ExtVMType>
eth::OnOpFunc FakeExtVM::simpleTrace()
{
return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt)
{
ExtVMType const& ext = *(ExtVMType const*)voidExt;
eth::VM& vm = *(eth::VM*)voidVM;
std::ostringstream o;
o << std::endl << " STACK" << std::endl;
for (auto i: vm.stack())
o << (h256)i << std::endl;
o << " MEMORY" << std::endl << memDump(vm.memory());
o << " STORAGE" << std::endl;
for (auto const& i: ext.state().storage(ext.myAddress))
o << std::showbase << std::hex << i.first << ": " << i.second << std::endl;
dev::LogOutputStream<eth::VMTraceChannel, false>(true) << o.str();
dev::LogOutputStream<eth::VMTraceChannel, false>(false) << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]";
if (eth::VMTraceChannel::verbosity <= g_logVerbosity)
{
std::ofstream f;
f.open("./vmtrace.log", std::ofstream::app);
f << o.str();
f << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32";
}
};
}
} } // Namespace Close

12
third/MainWin.cpp

@ -102,24 +102,28 @@ Main::Main(QWidget *parent) :
m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"}));
m_web3->connect(Host::pocHost());
m_ldb = new QLDB(this);
connect(ui->webView, &QWebView::loadStarted, [this]()
{
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this);
m_ethereum = new QEthereum(this, ethereum(), owned());
m_whisper = new QWhisper(this, whisper());
m_ethereum = new QEthereum(this, ethereum(), m_myKeys);
m_whisper = new QWhisper(this, whisper(), owned());
QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qdev = m_dev;
auto qeth = m_ethereum;
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, [=]()
{
m_ethereum->poll();
m_whisper->poll();
});
connect(ui->webView, &QWebView::titleChanged, [=]()
@ -522,6 +526,8 @@ void Main::timerEvent(QTimerEvent*)
if (m_ethereum)
m_ethereum->poll();
if (m_whisper)
m_whisper->poll();
for (auto const& i: m_handlers)
if (ethereum()->checkWatch(i.first))

6
third/MainWin.h

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

6
windows/LibEthereum.vcxproj

@ -69,10 +69,13 @@
</ClCompile>
<ClCompile Include="..\libdevcore\_libdevcore.cpp" />
<ClCompile Include="..\libdevcrypto\Common.cpp" />
<ClCompile Include="..\libdevcrypto\CryptoPP.cpp" />
<ClCompile Include="..\libdevcrypto\EC.cpp" />
<ClCompile Include="..\libdevcrypto\FileSystem.cpp" />
<ClCompile Include="..\libdevcrypto\MemoryDB.cpp" />
<ClCompile Include="..\libdevcrypto\OverlayDB.cpp" />
<ClCompile Include="..\libdevcrypto\SHA3.cpp" />
<ClCompile Include="..\libdevcrypto\SHA3MAC.cpp" />
<ClCompile Include="..\libdevcrypto\TrieCommon.cpp" />
<ClCompile Include="..\libdevcrypto\TrieDB.cpp" />
<ClCompile Include="..\libethcore\BlockInfo.cpp">
@ -270,10 +273,13 @@
<ClInclude Include="..\libdevcrypto\All.h" />
<ClInclude Include="..\libdevcrypto\Common.h" />
<ClInclude Include="..\libdevcrypto\CryptoHeaders.h" />
<ClInclude Include="..\libdevcrypto\CryptoPP.h" />
<ClInclude Include="..\libdevcrypto\EC.h" />
<ClInclude Include="..\libdevcrypto\FileSystem.h" />
<ClInclude Include="..\libdevcrypto\MemoryDB.h" />
<ClInclude Include="..\libdevcrypto\OverlayDB.h" />
<ClInclude Include="..\libdevcrypto\SHA3.h" />
<ClInclude Include="..\libdevcrypto\SHA3MAC.h" />
<ClInclude Include="..\libdevcrypto\TrieCommon.h" />
<ClInclude Include="..\libdevcrypto\TrieDB.h" />
<ClInclude Include="..\libethcore\All.h">

18
windows/LibEthereum.vcxproj.filters

@ -193,6 +193,15 @@
<ClCompile Include="..\libethcore\Exceptions.cpp">
<Filter>libethcore</Filter>
</ClCompile>
<ClCompile Include="..\libdevcrypto\CryptoPP.cpp">
<Filter>libdevcrypto</Filter>
</ClCompile>
<ClCompile Include="..\libdevcrypto\EC.cpp">
<Filter>libdevcrypto</Filter>
</ClCompile>
<ClCompile Include="..\libdevcrypto\SHA3MAC.cpp">
<Filter>libdevcrypto</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@ -417,6 +426,15 @@
<ClInclude Include="..\libwebthree\webthree.h">
<Filter>libwebthree</Filter>
</ClInclude>
<ClInclude Include="..\libdevcrypto\CryptoPP.h">
<Filter>libdevcrypto</Filter>
</ClInclude>
<ClInclude Include="..\libdevcrypto\EC.h">
<Filter>libdevcrypto</Filter>
</ClInclude>
<ClInclude Include="..\libdevcrypto\SHA3MAC.h">
<Filter>libdevcrypto</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Windows">

Loading…
Cancel
Save