Browse Source

Merge pull request #1128 from arkpar/chromium

Merged develop into chromium
cl-refactor
Gav Wood 10 years ago
parent
commit
f534ee80a7
  1. 9
      README.md
  2. 4
      alethzero/CMakeLists.txt
  3. 2
      alethzero/Context.h
  4. 7
      alethzero/GraphParameters.h
  5. 16
      alethzero/Grapher.h
  6. 12
      alethzero/Main.ui
  7. 25
      alethzero/MainWin.cpp
  8. 11
      alethzero/MainWin.h
  9. 5
      alethzero/MiningView.cpp
  10. 1
      alethzero/NatspecHandler.cpp
  11. 2
      alethzero/NatspecHandler.h
  12. 78
      alethzero/OurWebThreeStubServer.cpp
  13. 20
      alethzero/OurWebThreeStubServer.h
  14. 8
      alethzero/Transact.cpp
  15. 12
      alethzero/Transact.h
  16. 5
      cmake/EthDependencies.cmake
  17. 58
      cmake/EthExecutableHelper.cmake
  18. 10
      cmake/FindMHD.cmake
  19. 6
      eth/CMakeLists.txt
  20. 6
      eth/main.cpp
  21. 7
      evmjit/CMakeLists.txt
  22. 21
      evmjit/LICENSE.md
  23. 43
      evmjit/README.md
  24. 5
      evmjit/libevmjit-cpp/CMakeLists.txt
  25. 21
      evmjit/libevmjit-cpp/Env.cpp
  26. 34
      evmjit/libevmjit-cpp/JitVM.cpp
  27. 4
      evmjit/libevmjit-cpp/JitVM.h
  28. 328
      evmjit/libevmjit/Arith256.cpp
  29. 13
      evmjit/libevmjit/Arith256.h
  30. 19
      evmjit/libevmjit/BasicBlock.cpp
  31. 20
      evmjit/libevmjit/BasicBlock.h
  32. 10
      evmjit/libevmjit/BuildInfo.h.in
  33. 59
      evmjit/libevmjit/CMakeLists.txt
  34. 62
      evmjit/libevmjit/Cache.cpp
  35. 9
      evmjit/libevmjit/Cache.h
  36. 25
      evmjit/libevmjit/Common.h
  37. 94
      evmjit/libevmjit/Compiler.cpp
  38. 9
      evmjit/libevmjit/Compiler.h
  39. 4
      evmjit/libevmjit/CompilerHelper.cpp
  40. 5
      evmjit/libevmjit/CompilerHelper.h
  41. 3
      evmjit/libevmjit/Endianness.cpp
  42. 3
      evmjit/libevmjit/Endianness.h
  43. 97
      evmjit/libevmjit/ExecStats.cpp
  44. 44
      evmjit/libevmjit/ExecStats.h
  45. 169
      evmjit/libevmjit/ExecutionEngine.cpp
  46. 32
      evmjit/libevmjit/ExecutionEngine.h
  47. 31
      evmjit/libevmjit/Ext.cpp
  48. 6
      evmjit/libevmjit/Ext.h
  49. 107
      evmjit/libevmjit/GasMeter.cpp
  50. 3
      evmjit/libevmjit/GasMeter.h
  51. 8
      evmjit/libevmjit/Instruction.cpp
  52. 4
      evmjit/libevmjit/Instruction.h
  53. 499
      evmjit/libevmjit/Memory.cpp
  54. 15
      evmjit/libevmjit/Memory.h
  55. 8
      evmjit/libevmjit/Runtime.cpp
  56. 86
      evmjit/libevmjit/Runtime.h
  57. 4
      evmjit/libevmjit/RuntimeData.h
  58. 56
      evmjit/libevmjit/RuntimeManager.cpp
  59. 17
      evmjit/libevmjit/RuntimeManager.h
  60. 111
      evmjit/libevmjit/Stack.cpp
  61. 9
      evmjit/libevmjit/Stack.h
  62. 11
      evmjit/libevmjit/Type.cpp
  63. 10
      evmjit/libevmjit/Type.h
  64. 1
      evmjit/libevmjit/Utils.cpp
  65. 3
      evmjit/libevmjit/Utils.h
  66. 11
      evmjit/libevmjit/interface.cpp
  67. 7
      evmjit/libevmjit/preprocessor/llvm_includes_end.h
  68. 12
      evmjit/libevmjit/preprocessor/llvm_includes_start.h
  69. 2
      exp/CMakeLists.txt
  70. 6
      exp/main.cpp
  71. 2
      extdep/CMakeLists.txt
  72. 2
      libdevcore/CMakeLists.txt
  73. 2
      libdevcore/Common.cpp
  74. 2
      libdevcore/FixedHash.h
  75. 2
      libdevcore/RLP.cpp
  76. 4
      libdevcore/RLP.h
  77. 2
      libdevcore/Worker.h
  78. 7
      libdevcore/vector_ref.h
  79. 2
      libdevcrypto/CMakeLists.txt
  80. 2
      libdevcrypto/Common.cpp
  81. 3
      libdevcrypto/Common.h
  82. 2
      libdevcrypto/CryptoPP.cpp
  83. 6
      libdevcrypto/TrieDB.h
  84. 6
      libethcore/BlockInfo.cpp
  85. 2
      libethcore/CMakeLists.txt
  86. 2
      libethcore/CommonEth.cpp
  87. 1
      libethcore/Exceptions.h
  88. 2
      libethcore/ProofOfWork.h
  89. 3
      libethereum/BlockChain.cpp
  90. 3
      libethereum/BlockQueue.cpp
  91. 2
      libethereum/CMakeLists.txt
  92. 34
      libethereum/CanonBlockChain.cpp
  93. 14
      libethereum/Client.cpp
  94. 4
      libethereum/Client.h
  95. 2
      libethereum/EthereumHost.h
  96. 40
      libethereum/GenesisInfo.cpp
  97. 32
      libethereum/GenesisInfo.h
  98. 2
      libethereum/Interface.h
  99. 13
      libethereum/State.cpp
  100. 2
      libethereum/State.h

9
README.md

@ -1,12 +1,12 @@
## Ethereum C++ Client. ## Ethereum C++ Client.
By Gav Wood, 2014. By Gav Wood et al, 2013, 2014, 2015.
| Linux | OSX | Windows | Linux | OSX | Windows
----------|---------|-----|-------- ----------|---------|-----|--------
develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1)
master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1)
evmjit | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A evmjit | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A
[![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) [![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum)
@ -24,7 +24,6 @@ To run the tests, make sure you clone the tests repository from github.com/ether
See [TODO](https://github.com/ethereum/cpp-ethereum/wiki/TODO) See [TODO](https://github.com/ethereum/cpp-ethereum/wiki/TODO)
### License ### License
See [LICENSE](LICENSE) See [LICENSE](LICENSE)

4
alethzero/CMakeLists.txt

@ -10,8 +10,8 @@ endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
find_package (Qt5WebEngine QUIET) find_package (Qt5WebEngine QUIET)
@ -63,5 +63,5 @@ if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
endif() endif()
# eth_install_executable is defined in cmake/EthExecutableHelper.cmake # eth_install_executable is defined in cmake/EthExecutableHelper.cmake
eth_install_executable(${EXECUTABLE}) eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE})

2
alethzero/Context.h

@ -29,7 +29,7 @@
class QComboBox; class QComboBox;
namespace dev { namespace eth { class StateDiff; } } namespace dev { namespace eth { struct StateDiff; } }
#define Small "font-size: small; " #define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; " #define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "

7
alethzero/GraphParameters.h

@ -37,8 +37,11 @@ static T graphParameters(T _min, T _max, unsigned _divisions, T* o_from = 0, T*
T uMax = _max / _divisor; T uMax = _max / _divisor;
if (uMax == uMin || !_divisions) if (uMax == uMin || !_divisions)
{ {
*o_from = 0; if (o_delta && o_from)
*o_delta = 1; {
*o_from = 0;
*o_delta = 1;
}
return 1; return 1;
} }
long double l10 = std::log10((uMax - uMin) / T(_divisions) * 5.5f); long double l10 = std::log10((uMax - uMin) / T(_divisions) * 5.5f);

16
alethzero/Grapher.h

@ -76,24 +76,24 @@ public:
void labelYOrderedPoints(std::map<float, float> const& _translatedData, int _maxCount = 20, float _minFactor = .01f) const; void labelYOrderedPoints(std::map<float, float> const& _translatedData, int _maxCount = 20, float _minFactor = .01f) const;
protected: protected:
QPainter* p; QPainter* p = nullptr;
QRect active; QRect active;
std::pair<float, float> xRange; std::pair<float, float> xRange;
std::pair<float, float> yRange; std::pair<float, float> yRange;
float xM; float xM = 0;
float xC; float xC = 0;
float yM; float yM = 0;
float yC; float yC = 0;
float dx; float dx = 0;
float dy; float dy = 0;
std::function<std::string(float _f)> xLabel; std::function<std::string(float _f)> xLabel;
std::function<std::string(float _f)> yLabel; std::function<std::string(float _f)> yLabel;
std::function<std::string(float _x, float _y)> pLabel; std::function<std::string(float _x, float _y)> pLabel;
float fontPixelSize; float fontPixelSize = 0;
// Translate from raw indexed data into x/y graph units. Only relevant for indexed data. // Translate from raw indexed data into x/y graph units. Only relevant for indexed data.
float xT(float _dataIndex) const { return _dataIndex * xM + xC; } float xT(float _dataIndex) const { return _dataIndex * xM + xC; }

12
alethzero/Main.ui

@ -157,6 +157,7 @@
<property name="title"> <property name="title">
<string>&amp;Special</string> <string>&amp;Special</string>
</property> </property>
<addaction name="natSpec"/>
<addaction name="paranoia"/> <addaction name="paranoia"/>
<addaction name="clearPending"/> <addaction name="clearPending"/>
<addaction name="killBlockchain"/> <addaction name="killBlockchain"/>
@ -1646,6 +1647,17 @@ font-size: 14pt</string>
<string>New &amp;Transaction...</string> <string>New &amp;Transaction...</string>
</property> </property>
</action> </action>
<action name="natSpec">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;NatSpec Enabled</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

25
alethzero/MainWin.cpp

@ -199,6 +199,11 @@ Main::~Main()
g_logPost = simpleDebugOut; g_logPost = simpleDebugOut;
} }
bool Main::confirm() const
{
return ui->natSpec->isChecked();
}
void Main::on_newIdentity_triggered() void Main::on_newIdentity_triggered()
{ {
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
@ -649,6 +654,7 @@ void Main::writeSettings()
s.setValue("localNetworking", ui->localNetworking->isChecked()); s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("natSpec", ui->natSpec->isChecked());
s.setValue("showAll", ui->showAll->isChecked()); s.setValue("showAll", ui->showAll->isChecked());
s.setValue("showAllAccounts", ui->showAllAccounts->isChecked()); s.setValue("showAllAccounts", ui->showAllAccounts->isChecked());
s.setValue("clientName", ui->clientName->text()); s.setValue("clientName", ui->clientName->text());
@ -660,7 +666,7 @@ void Main::writeSettings()
s.setValue("jitvm", ui->jitvm->isChecked()); s.setValue("jitvm", ui->jitvm->isChecked());
bytes d = m_webThree->saveNetwork(); bytes d = m_webThree->saveNetwork();
if (d.size()) if (!d.empty())
m_networkConfig = QByteArray((char*)d.data(), (int)d.size()); m_networkConfig = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_networkConfig); s.setValue("peers", m_networkConfig);
s.setValue("nameReg", ui->nameReg->text()); s.setValue("nameReg", ui->nameReg->text());
@ -718,6 +724,7 @@ void Main::readSettings(bool _skipGeometry)
ui->forceMining->setChecked(s.value("forceMining", false).toBool()); ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered(); on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool()); ui->paranoia->setChecked(s.value("paranoia", false).toBool());
ui->natSpec->setChecked(s.value("natSpec", true).toBool());
ui->showAll->setChecked(s.value("showAll", false).toBool()); ui->showAll->setChecked(s.value("showAll", false).toBool());
ui->showAllAccounts->setChecked(s.value("showAllAccounts", false).toBool()); ui->showAllAccounts->setChecked(s.value("showAllAccounts", false).toBool());
ui->clientName->setText(s.value("clientName", "").toString()); ui->clientName->setText(s.value("clientName", "").toString());
@ -1158,6 +1165,7 @@ void Main::timerEvent(QTimerEvent*)
interval = 0; interval = 0;
refreshNetwork(); refreshNetwork();
refreshWhispers(); refreshWhispers();
poll();
} }
else else
interval += 100; interval += 100;
@ -1448,7 +1456,7 @@ void Main::on_debugCurrent_triggered()
} }
} }
void Main::on_debugDumpState_triggered(int _add) void Main::debugDumpState(int _add)
{ {
if (auto item = ui->blocks->currentItem()) if (auto item = ui->blocks->currentItem())
{ {
@ -1469,11 +1477,6 @@ void Main::on_debugDumpState_triggered(int _add)
} }
} }
void Main::on_debugDumpStatePre_triggered()
{
on_debugDumpState_triggered(0);
}
void Main::on_contracts_currentItemChanged() void Main::on_contracts_currentItemChanged()
{ {
ui->contractInfo->clear(); ui->contractInfo->clear();
@ -1501,7 +1504,7 @@ void Main::on_contracts_currentItemChanged()
} }
} }
void Main::on_idealPeers_valueChanged() void Main::on_idealPeers_valueChanged(int)
{ {
m_webThree->setIdealPeerCount(ui->idealPeers->value()); m_webThree->setIdealPeerCount(ui->idealPeers->value());
} }
@ -1513,11 +1516,11 @@ void Main::on_ourAccounts_doubleClicked()
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray()))); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
} }
void Main::on_log_doubleClicked() /*void Main::on_log_doubleClicked()
{ {
ui->log->setPlainText(""); ui->log->setPlainText("");
m_logHistory.clear(); m_logHistory.clear();
} }*/
void Main::on_accounts_doubleClicked() void Main::on_accounts_doubleClicked()
{ {
@ -1624,7 +1627,7 @@ void Main::on_net_triggered()
{ {
web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs()); web3()->setNetworkPreferences(netPrefs());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0); ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
// TODO: p2p // TODO: p2p
// if (m_networkConfig.size()/* && ui->usePast->isChecked()*/) // if (m_networkConfig.size()/* && ui->usePast->isChecked()*/)
// web3()->restoreNetwork(bytesConstRef((byte*)m_networkConfig.data(), m_networkConfig.size())); // web3()->restoreNetwork(bytesConstRef((byte*)m_networkConfig.data(), m_networkConfig.size()));

11
alethzero/MainWin.h

@ -72,6 +72,7 @@ public:
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); } std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
bool confirm() const;
NatSpecFace* natSpec() { return &m_natSpecDB; } NatSpecFace* natSpec() { return &m_natSpecDB; }
QString pretty(dev::Address _a) const override; QString pretty(dev::Address _a) const override;
@ -106,7 +107,7 @@ private slots:
void on_go_triggered(); void on_go_triggered();
void on_net_triggered(); void on_net_triggered();
void on_connect_triggered(); void on_connect_triggered();
void on_idealPeers_valueChanged(); void on_idealPeers_valueChanged(int);
// Mining // Mining
void on_mine_triggered(); void on_mine_triggered();
@ -139,7 +140,7 @@ private slots:
void on_blocks_currentItemChanged(); void on_blocks_currentItemChanged();
// Logging // Logging
void on_log_doubleClicked(); // void on_log_doubleClicked();
void on_verbosity_valueChanged(); void on_verbosity_valueChanged();
// Misc // Misc
@ -159,8 +160,8 @@ private slots:
// Debugger // Debugger
void on_debugCurrent_triggered(); void on_debugCurrent_triggered();
void on_debugDumpState_triggered(int _add = 1); void on_debugDumpState_triggered() { debugDumpState(1); }
void on_debugDumpStatePre_triggered(); void on_debugDumpStatePre_triggered() { debugDumpState(0); }
// Whisper // Whisper
void on_newIdentity_triggered(); void on_newIdentity_triggered();
@ -174,6 +175,8 @@ signals:
void poll(); void poll();
private: private:
void debugDumpState(int _add);
dev::p2p::NetworkPreferences netPrefs() const; dev::p2p::NetworkPreferences netPrefs() const;
QString lookup(QString const& _n) const; QString lookup(QString const& _n) const;

5
alethzero/MiningView.cpp

@ -48,7 +48,6 @@ string sL(float _x, float _y) { return toString(round(_x * 1000)) + "s (" + toSt
MiningView::MiningView(QWidget* _p): QWidget(_p) MiningView::MiningView(QWidget* _p): QWidget(_p)
{ {
} }
void MiningView::appendStats(list<MineInfo> const& _i, MineProgress const& _p) void MiningView::appendStats(list<MineInfo> const& _i, MineProgress const& _p)
@ -86,10 +85,10 @@ void MiningView::appendStats(list<MineInfo> const& _i, MineProgress const& _p)
for (auto& i: m_resets) for (auto& i: m_resets)
i -= o; i -= o;
remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}); m_resets.erase(remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}), m_resets.end());
for (auto& i: m_completes) for (auto& i: m_completes)
i -= o; i -= o;
remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}); m_completes.erase(remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}), m_completes.end());
m_progress = _p; m_progress = _p;
update(); update();

1
alethzero/NatspecHandler.cpp

@ -66,7 +66,6 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran
{ {
Json::Value natspec; Json::Value natspec;
Json::Value userNotice; Json::Value userNotice;
string retStr;
m_reader.parse(json, natspec); m_reader.parse(json, natspec);
FixedHash<4> transactionFunctionHash((bytesConstRef(&_transactionData).cropped(0, 4).toBytes())); FixedHash<4> transactionFunctionHash((bytesConstRef(&_transactionData).cropped(0, 4).toBytes()));

2
alethzero/NatspecHandler.h

@ -54,6 +54,6 @@ class NatspecHandler: public NatSpecFace
private: private:
ldb::ReadOptions m_readOptions; ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions; ldb::WriteOptions m_writeOptions;
ldb::DB* m_db; ldb::DB* m_db = nullptr;
Json::Reader m_reader; Json::Reader m_reader;
}; };

78
alethzero/OurWebThreeStubServer.cpp

@ -33,9 +33,11 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3,
vector<KeyPair> const& _accounts, Main* main): vector<KeyPair> const& _accounts, Main* _main):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main) WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main)
{} {
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
}
string OurWebThreeStubServer::shh_newIdentity() string OurWebThreeStubServer::shh_newIdentity()
{ {
@ -44,29 +46,44 @@ string OurWebThreeStubServer::shh_newIdentity()
return toJS(kp.pub()); return toJS(kp.pub());
} }
bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text)
{ {
int button; if (!m_main->confirm())
QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); {
return button == QMessageBox::Ok; cnote << "Skipping confirmation step for: " << _title << "\n" << _text;
return true;
}
QMessageBox userInput;
userInput.setText(QString::fromStdString(_title));
userInput.setInformativeText(QString::fromStdString(_text));
userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
userInput.button(QMessageBox::Ok)->setText("Allow");
userInput.button(QMessageBox::Cancel)->setText("Reject");
userInput.setDefaultButton(QMessageBox::Cancel);
return userInput.exec() == QMessageBox::Ok;
//QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text)));
//return button == QMessageBox::Ok;
} }
bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t) const bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Contract Creation Transaction", "ÐApp is attemping to create a contract; to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>."); return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t) const bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>."); return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") +
", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) const bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!",
"ÐApp is attempting to call into an unknown contract at address " + "ÐApp is attempting to call into an unknown contract at address " +
m_main->pretty(_t.to).toStdString() + m_main->pretty(_t.to).toStdString() + ".\n\n" +
".\n\nCall involves sending " + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") +
"Call involves sending " +
formatBalance(_t.value) + " to the recipient, with additional network fees of up to " + formatBalance(_t.value) + " to the recipient, with additional network fees of up to " +
formatBalance(_t.gas * _t.gasPrice) + formatBalance(_t.gas * _t.gasPrice) +
"However, this also does other stuff which we don't understand, and does so in your name.\n\n" + "However, this also does other stuff which we don't understand, and does so in your name.\n\n" +
@ -76,25 +93,43 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t)
"REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!");
} }
bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t) void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy)
{
Guard l(x_queued);
m_queued.push(make_pair(_t, _toProxy));
}
void OurWebThreeStubServer::doValidations()
{
Guard l(x_queued);
while (!m_queued.empty())
{
auto q = m_queued.front();
m_queued.pop();
if (validateTransaction(q.first, q.second))
WebThreeStubServerBase::authenticate(q.first, q.second);
}
}
bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, bool _toProxy)
{ {
if (_t.creation) if (_t.creation)
{ {
// recipient has no code - nothing special about this transaction, show basic value transfer info // show notice concerning the creation code. TODO: this needs entering into natspec.
return showCreationNotice(_t); return showCreationNotice(_t, _toProxy);
} }
h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to);
if (contractCodeHash == EmptySHA3) if (contractCodeHash == EmptySHA3)
{ {
// recipient has no code - nothing special about this transaction, show basic value transfer info // recipient has no code - nothing special about this transaction, show basic value transfer info
return showSendNotice(_t); return showSendNotice(_t, _toProxy);
} }
string userNotice = m_main->natSpec()->getUserNotice(contractCodeHash, _t.data); string userNotice = m_main->natSpec()->getUserNotice(contractCodeHash, _t.data);
if (userNotice.empty()) if (userNotice.empty())
return showUnknownCallNotice(_t); return showUnknownCallNotice(_t, _toProxy);
NatspecExpressionEvaluator evaluator; NatspecExpressionEvaluator evaluator;
userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString(); userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString();
@ -104,11 +139,12 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
"ÐApp attempting to conduct contract interaction with " + "ÐApp attempting to conduct contract interaction with " +
m_main->pretty(_t.to).toStdString() + m_main->pretty(_t.to).toStdString() +
": <b>" + userNotice + "</b>.\n\n" + ": <b>" + userNotice + "</b>.\n\n" +
(_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") +
(_t.value > 0 ? (_t.value > 0 ?
"In addition, ÐApp is attempting to send " + "In addition, ÐApp is attempting to send " +
formatBalance(_t.value) + " to said recipient, with additional network fees of up to " + formatBalance(_t.value) + " to said recipient, with additional network fees of up to " +
formatBalance(_t.gas * _t.gasPrice) + " = <b>" + formatBalance(_t.gas * _t.gasPrice) + " = " +
formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>." formatBalance(_t.value + _t.gas * _t.gasPrice) + "."
: :
"Additional network fees are at most" + "Additional network fees are at most" +
formatBalance(_t.gas * _t.gasPrice) + ".") formatBalance(_t.gas * _t.gasPrice) + ".")

20
alethzero/OurWebThreeStubServer.h

@ -19,7 +19,9 @@
* @date 2014 * @date 2014
*/ */
#include <queue>
#include <QtCore/QObject> #include <QtCore/QObject>
#include <libdevcore/Guards.h>
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
@ -35,16 +37,24 @@ public:
std::vector<dev::KeyPair> const& _accounts, Main* main); std::vector<dev::KeyPair> const& _accounts, Main* main);
virtual std::string shh_newIdentity() override; virtual std::string shh_newIdentity() override;
virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
signals: signals:
void onNewId(QString _s); void onNewId(QString _s);
public slots:
void doValidations();
private: private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; bool showAuthenticationPopup(std::string const& _title, std::string const& _text);
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t) const; bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
bool showSendNotice(dev::eth::TransactionSkeleton const& _t) const; bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t) const; bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
std::queue<std::pair<dev::eth::TransactionSkeleton, bool>> m_queued;
dev::Mutex x_queued;
dev::WebThreeDirect* m_web3; dev::WebThreeDirect* m_web3;
Main* m_main; Main* m_main;

8
alethzero/Transact.cpp

@ -55,7 +55,7 @@ Transact::Transact(Context* _c, QWidget* _parent):
ui->valueUnits->setCurrentIndex(6); ui->valueUnits->setCurrentIndex(6);
ui->gasPriceUnits->setCurrentIndex(4); ui->gasPriceUnits->setCurrentIndex(4);
ui->gasPrice->setValue(10); ui->gasPrice->setValue(10);
on_destination_currentTextChanged(); on_destination_currentTextChanged(QString());
} }
Transact::~Transact() Transact::~Transact()
@ -147,7 +147,7 @@ string Transact::getFunctionHashes(dev::solidity::CompilerStack const& _compiler
return ret; return ret;
} }
void Transact::on_destination_currentTextChanged() void Transact::on_destination_currentTextChanged(QString)
{ {
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)") if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)")
if (Address a = m_context->fromString(ui->destination->currentText())) if (Address a = m_context->fromString(ui->destination->currentText()))
@ -169,9 +169,7 @@ void Transact::rejigData()
QString lll; QString lll;
QString solidity; QString solidity;
if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0) if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0)
{
m_data = fromHex(src); m_data = fromHex(src);
}
else if (sourceIsSolidity(src)) else if (sourceIsSolidity(src))
{ {
dev::solidity::CompilerStack compiler; dev::solidity::CompilerStack compiler;
@ -204,7 +202,7 @@ void Transact::rejigData()
for (auto& i: errors) for (auto& i: errors)
i = "(LLL " + i + ")"; i = "(LLL " + i + ")";
} }
catch (string err) catch (string const& err)
{ {
errors.push_back("Serpent " + err); errors.push_back("Serpent " + err);
} }

12
alethzero/Transact.h

@ -44,12 +44,12 @@ public:
void setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); void setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB);
private slots: private slots:
void on_destination_currentTextChanged(); void on_destination_currentTextChanged(QString);
void on_value_valueChanged() { updateFee(); } void on_value_valueChanged(int) { updateFee(); }
void on_gas_valueChanged() { updateFee(); } void on_gas_valueChanged(int) { updateFee(); }
void on_valueUnits_currentIndexChanged() { updateFee(); } void on_valueUnits_currentIndexChanged(int) { updateFee(); }
void on_gasPriceUnits_currentIndexChanged() { updateFee(); } void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); }
void on_gasPrice_valueChanged() { updateFee(); } void on_gasPrice_valueChanged(int) { updateFee(); }
void on_data_textChanged() { rejigData(); } void on_data_textChanged() { rejigData(); }
void on_optimize_clicked() { rejigData(); } void on_optimize_clicked() { rejigData(); }
void on_send_clicked(); void on_send_clicked();

5
cmake/EthDependencies.cmake

@ -128,6 +128,11 @@ if (NOT HEADLESS)
set (MACDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/macdeployqt) set (MACDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/macdeployqt)
message(" - macdeployqt path: ${MACDEPLOYQT_APP}") message(" - macdeployqt path: ${MACDEPLOYQT_APP}")
endif() endif()
# we need to find path to windeployqt on windows
if (WIN32)
set (WINDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/windeployqt)
message(" - windeployqt path: ${WINDEPLOYQT_APP}")
endif()
# TODO check node && npm version # TODO check node && npm version
find_program(ETH_NODE node) find_program(ETH_NODE node)

58
cmake/EthExecutableHelper.cmake

@ -56,14 +56,14 @@ macro(eth_install_executable EXECUTABLE)
set (extra_macro_args ${ARGN}) set (extra_macro_args ${ARGN})
set (options) set (options)
set (one_value_args QMLDIR) set (one_value_args QMLDIR)
set (multi_value_args) set (multi_value_args DLLS)
cmake_parse_arguments (ETH_INSTALL_EXECUTABLE "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}") cmake_parse_arguments (ETH_INSTALL_EXECUTABLE "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}")
if (ETH_INSTALL_EXECUTABLE_QMLDIR) if (ETH_INSTALL_EXECUTABLE_QMLDIR)
if (APPLE) if (APPLE)
set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}") set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}")
elseif (WIN32) elseif (WIN32)
set(eth_qml_dir --qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}) set(eth_qml_dir "--qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}")
endif() endif()
message(STATUS "${EXECUTABLE} qmldir: ${eth_qml_dir}") message(STATUS "${EXECUTABLE} qmldir: ${eth_qml_dir}")
endif() endif()
@ -88,48 +88,30 @@ macro(eth_install_executable EXECUTABLE)
set(BU_CHMOD_BUNDLE_ITEMS 1) set(BU_CHMOD_BUNDLE_ITEMS 1)
verify_app(\"${APP_BUNDLE_PATH}\") verify_app(\"${APP_BUNDLE_PATH}\")
" COMPONENT RUNTIME ) " COMPONENT RUNTIME )
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# copy all dlls to executable directory elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# TODO improve that by copying only required dlls
file (GLOB DLLS ${ETH_DEPENDENCY_INSTALL_DIR}/bin/*.dll)
foreach(DLL ${DLLS}) get_target_property(TARGET_LIBS ${EXECUTABLE} INTERFACE_LINK_LIBRARIES)
string(REGEX MATCH "Qt5::Core" HAVE_QT ${TARGET_LIBS})
if ("${HAVE_QT}" STREQUAL "Qt5::Core")
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND cmake -E copy "${DLL}" "$<TARGET_FILE_DIR:${EXECUTABLE}>" COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}"
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
) )
endforeach() #workaround for https://bugreports.qt.io/browse/QTBUG-42083
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf"
COMMAND cmake -E copy_directory WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM
"${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms" )
$<TARGET_FILE_DIR:${EXECUTABLE}>/platforms endif()
)
# ugly way, improve that
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND cmake -E copy_directory
"${ETH_DEPENDENCY_INSTALL_DIR}/qml"
$<TARGET_FILE_DIR:${EXECUTABLE}>
)
install( FILES ${DLLS}
DESTINATION bin
COMPONENT ${EXECUTABLE}
)
install( DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms #copy additional dlls
DESTINATION bin foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS})
COMPONENT ${EXECUTABLE} add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E copy ${dll} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
) )
endforeach(dll)
file (GLOB QMLS ${ETH_DEPENDENCY_INSTALL_DIR}/qml/*)
foreach(QML ${QMLS})
install( DIRECTORY ${QML}
DESTINATION bin
COMPONENT ${EXECUTABLE}
)
endforeach()
install( TARGETS ${EXECUTABLE} RUNTIME install( TARGETS ${EXECUTABLE} RUNTIME
DESTINATION bin DESTINATION bin

10
cmake/FindMHD.cmake

@ -29,13 +29,19 @@ set(MHD_LIBRARIES ${MHD_LIBRARY})
# boost is using the same "hack" as us with "optimized" and "debug" # boost is using the same "hack" as us with "optimized" and "debug"
# official MHD project actually uses _d suffix # official MHD project actually uses _d suffix
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
#TODO: place dlls into CMAKE_CFG_INTDIR subfolders
string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY})
string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE})
find_library( find_library(
MHD_LIBRARY_DEBUG MHD_LIBRARY_DEBUG
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d
DOC "mhd debug library" DOC "mhd debug library"
) )
# always use release for now
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) #string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG})
#set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
endif() endif()

6
eth/CMakeLists.txt

@ -3,9 +3,9 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE eth) set(EXECUTABLE eth)
@ -28,5 +28,9 @@ endif()
target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} secp256k1)
if (WIN32)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin ) install( TARGETS ${EXECUTABLE} DESTINATION bin )

6
eth/main.cpp

@ -749,7 +749,7 @@ int main(int argc, char** argv)
else if (format == "standard+") else if (format == "standard+")
oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
{ {
dev::eth::VM* vm = (VM*)vvm; dev::eth::VM* vm = vvm;
dev::eth::ExtVM const* ext = static_cast<ExtVM const*>(vextVM); dev::eth::ExtVM const* ext = static_cast<ExtVM const*>(vextVM);
if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
for (auto const& i: ext->state().storage(ext->myAddress)) for (auto const& i: ext->state().storage(ext->myAddress))
@ -898,7 +898,9 @@ int main(int argc, char** argv)
while (!g_exit) while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000)); this_thread::sleep_for(chrono::milliseconds(1000));
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", web3.saveNetwork()); auto netData = web3.saveNetwork();
if (!netData.empty())
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData);
return 0; return 0;
} }

7
evmjit/CMakeLists.txt

@ -3,13 +3,14 @@ cmake_minimum_required(VERSION 2.8.12)
project(evmjit) project(evmjit)
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_AUTOMOC OFF)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
else() else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas")
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
# Do not allow unresovled symbols in shared library (default on linux) # Do not allow unresovled symbols in shared library (default on linux)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
endif() endif()

21
evmjit/LICENSE.md

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Paweł Bylica <chfast@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

43
evmjit/README.md

@ -0,0 +1,43 @@
# The Ethereum EVM JIT
EVM JIT is a library for just-in-time compilation of Ethereum EVM code.
It can be used to substitute classic interpreter-like EVM Virtual Machine in Ethereum client.
## Build
### Linux / Ubuntu
1. Install llvm-3.5-dev package
1. For Ubuntu 14.04 using LLVM deb packages source: http://llvm.org/apt
2. For Ubuntu 14.10 using Ubuntu packages
2. Build library with cmake
1. `mkdir build && cd $_`
2. `cmake .. && make`
3. Install library
1. `sudo make install`
2. `sudo ldconfig`
### OSX
1. Install llvm35
1. `brew install llvm35 --disable-shared --HEAD`
2. Build library with cmake
1. `mkdir build && cd $_`
2. `cmake -DLLVM_DIR=/usr/local/lib/llvm-3.5/share/llvm/cmake .. && make`
3. Install library
1. `make install` (with admin rights?)
### Windows
Ask me.
## Options
Options to evmjit library can be passed by environmental variables, e.g. `EVMJIT_CACHE=0 testeth --jit`.
Option | Default value | Description
------------- | ------------- | ----------------------------------------------
EVMJIT_CACHE | 1 | Enables on disk cache for compiled EVM objects
EVMJIT_DUMP | 0 | Dumps generated LLVM module to standard output

5
evmjit/libevmjit-cpp/CMakeLists.txt

@ -9,6 +9,11 @@ set(SOURCES
) )
source_group("" FILES ${SOURCES}) source_group("" FILES ${SOURCES})
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive
endif()
add_library(${TARGET_NAME} ${SOURCES}) add_library(${TARGET_NAME} ${SOURCES})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")

21
evmjit/libevmjit-cpp/Env.cpp

@ -1,4 +1,5 @@
#pragma GCC diagnostic ignored "-Wconversion"
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libevm/FeeStructure.h> #include <libevm/FeeStructure.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
@ -46,23 +47,22 @@ extern "C"
*o_hash = _env->blockhash(llvm2eth(*_number)); *o_hash = _env->blockhash(llvm2eth(*_number));
} }
EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address)
{ {
auto endowment = llvm2eth(*_endowment); auto endowment = llvm2eth(*_endowment);
if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{ {
_env->subBalance(endowment); _env->subBalance(endowment);
auto gas = llvm2eth(*io_gas); u256 gas = *io_gas;
OnOpFunc onOp {}; // TODO: Handle that thing h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight);
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); *io_gas = static_cast<int64_t>(gas);
*io_gas = eth2llvm(gas);
*o_address = address; *o_address = address;
} }
else else
*o_address = {}; *o_address = {};
} }
EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress)
{ {
auto value = llvm2eth(*_value); auto value = llvm2eth(*_value);
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
@ -70,12 +70,11 @@ extern "C"
_env->subBalance(value); _env->subBalance(value);
auto receiveAddress = right160(*_receiveAddress); auto receiveAddress = right160(*_receiveAddress);
auto inRef = bytesConstRef{_inBeg, _inSize}; auto inRef = bytesConstRef{_inBeg, _inSize};
auto outRef = bytesConstRef{_outBeg, _outSize}; auto outRef = bytesRef{_outBeg, _outSize};
OnOpFunc onOp {}; // TODO: Handle that thing
auto codeAddress = right160(*_codeAddress); auto codeAddress = right160(*_codeAddress);
auto gas = llvm2eth(*io_gas); u256 gas = *io_gas;
auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress);
*io_gas = eth2llvm(gas); *io_gas = static_cast<int64_t>(gas);
return ret; return ret;
} }

34
evmjit/libevmjit-cpp/JitVM.cpp

@ -1,6 +1,9 @@
#pragma GCC diagnostic ignored "-Wconversion"
#include "JitVM.h" #include "JitVM.h"
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libdevcrypto/SHA3.h>
#include <evmjit/libevmjit/ExecutionEngine.h> #include <evmjit/libevmjit/ExecutionEngine.h>
#include "Utils.h" #include "Utils.h"
@ -11,22 +14,26 @@ namespace eth
extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below
bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
{ {
using namespace jit; using namespace jit;
if (m_gas > std::numeric_limits<decltype(m_data.gas)>::max()) auto rejected = false;
BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope
rejected |= m_gas > std::numeric_limits<decltype(m_data.gas)>::max(); // Do not accept requests with gas > 2^63 (int64 max)
if (_ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max()) rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max();
BOOST_THROW_EXCEPTION(OutOfGas()); rejected |= _ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max();
rejected |= _ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max();
if (_ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max())
BOOST_THROW_EXCEPTION(OutOfGas());
if (_ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max())
BOOST_THROW_EXCEPTION(OutOfGas());
if (rejected)
{
UNTESTED;
std::cerr << "Rejected\n";
VMFactory::setKind(VMKind::Interpreter);
m_fallbackVM = VMFactory::create(m_gas);
VMFactory::setKind(VMKind::JIT);
return m_fallbackVM->go(_ext, _onOp, _step);
}
m_data.gas = static_cast<decltype(m_data.gas)>(m_gas); m_data.gas = static_cast<decltype(m_data.gas)>(m_gas);
m_data.gasPrice = static_cast<decltype(m_data.gasPrice)>(_ext.gasPrice); m_data.gasPrice = static_cast<decltype(m_data.gasPrice)>(_ext.gasPrice);
@ -43,9 +50,10 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
m_data.timestamp = static_cast<decltype(m_data.timestamp)>(_ext.currentBlock.timestamp); m_data.timestamp = static_cast<decltype(m_data.timestamp)>(_ext.currentBlock.timestamp);
m_data.code = _ext.code.data(); m_data.code = _ext.code.data();
m_data.codeSize = _ext.code.size(); m_data.codeSize = _ext.code.size();
m_data.codeHash = eth2llvm(sha3(_ext.code));
auto env = reinterpret_cast<Env*>(&_ext); auto env = reinterpret_cast<Env*>(&_ext);
auto exitCode = m_engine.run(_ext.code, &m_data, env); auto exitCode = m_engine.run(&m_data, env);
switch (exitCode) switch (exitCode)
{ {
case ReturnCode::Suicide: case ReturnCode::Suicide:

4
evmjit/libevmjit-cpp/JitVM.h

@ -12,15 +12,13 @@ class JitVM: public VMFace
{ {
virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
enum Kind: bool { Interpreter, JIT };
static std::unique_ptr<VMFace> create(Kind, u256 _gas = 0);
private: private:
friend class VMFactory; friend class VMFactory;
explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} explicit JitVM(u256 _gas = 0) : VMFace(_gas) {}
jit::RuntimeData m_data; jit::RuntimeData m_data;
jit::ExecutionEngine m_engine; jit::ExecutionEngine m_engine;
std::unique_ptr<VMFace> m_fallbackVM; ///< VM used in case of input data rejected by JIT
}; };

328
evmjit/libevmjit/Arith256.cpp

@ -1,11 +1,14 @@
#include "Arith256.h" #include "Arith256.h"
#include "Runtime.h"
#include "Type.h"
#include "Endianness.h"
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>
#include <iostream> #include <iostream>
#include <iomanip>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "Type.h"
#include "Endianness.h"
namespace dev namespace dev
{ {
@ -16,29 +19,102 @@ namespace jit
Arith256::Arith256(llvm::IRBuilder<>& _builder) : Arith256::Arith256(llvm::IRBuilder<>& _builder) :
CompilerHelper(_builder) CompilerHelper(_builder)
{ {}
using namespace llvm;
m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); void Arith256::debug(llvm::Value* _value, char _c)
m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); {
m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); if (!m_debug)
m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); {
llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()};
m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule());
}
createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)});
}
using Linkage = GlobalValue::LinkageTypes; llvm::Function* Arith256::getMulFunc()
{
auto& func = m_mul;
if (!func)
{
llvm::Type* argTypes[] = {Type::Word, Type::Word};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule());
llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; auto x = &func->getArgumentList().front();
x->setName("x");
auto y = x->getNextNode();
y->setName("y");
m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); InsertPointGuard guard{m_builder};
auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
m_builder.SetInsertPoint(bb);
auto i64 = Type::Size;
auto i128 = m_builder.getIntNTy(128);
auto i256 = Type::Word;
auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo");
auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo");
auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64);
auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64);
auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128);
auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128);
auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128));
auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128));
auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi);
auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128));
auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128));
auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi);
auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128));
auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128));
auto p = m_builder.CreateZExt(t1, i256);
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192)));
m_builder.CreateRet(p);
}
return func;
} }
void Arith256::debug(llvm::Value* _value, char _c) llvm::Function* Arith256::getMul512Func()
{ {
if (!m_debug) auto& func = m_mul512;
if (!func)
{ {
llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; auto i512 = m_builder.getIntNTy(512);
m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); llvm::Type* argTypes[] = {Type::Word, Type::Word};
func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule());
auto x = &func->getArgumentList().front();
x->setName("x");
auto y = x->getNextNode();
y->setName("y");
InsertPointGuard guard{m_builder};
auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
m_builder.SetInsertPoint(bb);
auto i128 = m_builder.getIntNTy(128);
auto i256 = Type::Word;
auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256);
auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256);
auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256);
auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256);
auto t1 = createCall(getMulFunc(), {x_lo, y_lo});
auto t2 = createCall(getMulFunc(), {x_lo, y_hi});
auto t3 = createCall(getMulFunc(), {x_hi, y_lo});
auto t4 = createCall(getMulFunc(), {x_hi, y_hi});
auto p = m_builder.CreateZExt(t1, i512);
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256)));
m_builder.CreateRet(p);
} }
createCall(m_debug, {_value, m_builder.getInt8(_c)}); return func;
} }
llvm::Function* Arith256::getDivFunc(llvm::Type* _type) llvm::Function* Arith256::getDivFunc(llvm::Type* _type)
@ -85,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type)
auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0");
auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto shlBy0 = m_builder.CreateICmpEQ(i0, zero);
auto y0 = m_builder.CreateShl(yArg, i0); auto y0 = m_builder.CreateShl(yArg, i0);
if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts
{
const auto treshold = m_builder.getIntN(512, 128);
auto highShift = m_builder.CreateICmpUGT(i0, treshold);
auto s = m_builder.CreateNUWSub(i0, treshold);
auto yhs = m_builder.CreateShl(yArg, treshold);
yhs = m_builder.CreateShl(yhs, s);
y0 = m_builder.CreateSelect(highShift, yhs, y0);
}
y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result
m_builder.CreateBr(loopBB); m_builder.CreateBr(loopBB);
@ -135,7 +220,7 @@ llvm::Function* Arith256::getExpFunc()
if (!m_exp) if (!m_exp)
{ {
llvm::Type* argTypes[] = {Type::Word, Type::Word}; llvm::Type* argTypes[] = {Type::Word, Type::Word};
m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "arith.exp", getModule()); m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule());
auto base = &m_exp->getArgumentList().front(); auto base = &m_exp->getArgumentList().front();
base->setName("base"); base->setName("base");
@ -159,9 +244,6 @@ llvm::Function* Arith256::getExpFunc()
auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp);
m_builder.SetInsertPoint(entryBB); m_builder.SetInsertPoint(entryBB);
auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1");
auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2");
auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3");
m_builder.CreateBr(headerBB); m_builder.CreateBr(headerBB);
m_builder.SetInsertPoint(headerBB); m_builder.SetInsertPoint(headerBB);
@ -176,20 +258,14 @@ llvm::Function* Arith256::getExpFunc()
m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.CreateCondBr(eOdd, updateBB, continueBB);
m_builder.SetInsertPoint(updateBB); m_builder.SetInsertPoint(updateBB);
m_builder.CreateStore(r, a1); auto r0 = createCall(getMulFunc(), {r, b});
m_builder.CreateStore(b, a2);
createCall(m_mul, {a1, a2, a3});
auto r0 = m_builder.CreateLoad(a3, "r0");
m_builder.CreateBr(continueBB); m_builder.CreateBr(continueBB);
m_builder.SetInsertPoint(continueBB); m_builder.SetInsertPoint(continueBB);
auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1");
r1->addIncoming(r, bodyBB); r1->addIncoming(r, bodyBB);
r1->addIncoming(r0, updateBB); r1->addIncoming(r0, updateBB);
m_builder.CreateStore(b, a1); auto b1 = createCall(getMulFunc(), {b, b});
m_builder.CreateStore(b, a2);
createCall(m_mul, {a1, a2, a3});
auto b1 = m_builder.CreateLoad(a3, "b1");
auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1");
m_builder.CreateBr(headerBB); m_builder.CreateBr(headerBB);
@ -244,9 +320,6 @@ llvm::Function* Arith256::getMulModFunc()
m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule());
auto i512Ty = m_builder.getIntNTy(512); auto i512Ty = m_builder.getIntNTy(512);
llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()};
auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule());
auto x = &m_mulmod->getArgumentList().front(); auto x = &m_mulmod->getArgumentList().front();
x->setName("x"); x->setName("x");
auto y = x->getNextNode(); auto y = x->getNextNode();
@ -258,32 +331,19 @@ llvm::Function* Arith256::getMulModFunc()
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod);
m_builder.SetInsertPoint(entryBB); m_builder.SetInsertPoint(entryBB);
auto a1 = m_builder.CreateAlloca(Type::Word); auto p = createCall(getMul512Func(), {x, y});
auto a2 = m_builder.CreateAlloca(Type::Word);
auto a3 = m_builder.CreateAlloca(i512Ty);
m_builder.CreateStore(x, a1);
m_builder.CreateStore(y, a2);
createCall(mul512, {a1, a2, a3});
auto p = m_builder.CreateLoad(a3, "p");
auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto m = m_builder.CreateZExt(mod, i512Ty, "m");
auto d = createCall(getDivFunc(i512Ty), {p, m}); auto d = createCall(getDivFunc(i512Ty), {p, m});
auto r = m_builder.CreateExtractValue(d, 1, "r"); auto r = m_builder.CreateExtractValue(d, 1, "r");
m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); r = m_builder.CreateTrunc(r, Type::Word);
m_builder.CreateRet(r);
} }
return m_mulmod; return m_mulmod;
} }
llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2)
{
m_builder.CreateStore(_arg1, m_arg1);
m_builder.CreateStore(_arg2, m_arg2);
m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result);
return m_builder.CreateLoad(m_result);
}
llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
{ {
return binaryOp(m_mul, _arg1, _arg2); return createCall(getMulFunc(), {_arg1, _arg2});
} }
std::pair<llvm::Value*, llvm::Value*> Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) std::pair<llvm::Value*, llvm::Value*> Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2)
@ -331,157 +391,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu
return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); return createCall(getMulModFunc(), {_arg1, _arg2, _arg3});
} }
namespace
{
#ifdef __SIZEOF_INT128__
using uint128 = __uint128_t;
#else
struct uint128
{
uint64_t lo = 0;
uint64_t hi = 0;
uint128(uint64_t lo) : lo(lo) {}
uint128 operator+(uint128 a)
{
uint128 r = 0;
bool overflow = lo > std::numeric_limits<uint64_t>::max() - a.lo;
r.lo = lo + a.lo;
r.hi = hi + a.hi + overflow;
return r;
}
uint128 operator>>(int s)
{
assert(s == 64);
return hi;
}
uint128 operator<<(int s)
{
assert(s == 64);
uint128 r = 0;
r.hi = lo;
return r;
}
explicit operator uint64_t() { return lo; }
static uint128 mul(uint64_t a, uint64_t b)
{
auto x_lo = 0xFFFFFFFF & a;
auto y_lo = 0xFFFFFFFF & b;
auto x_hi = a >> 32;
auto y_hi = b >> 32;
auto t1 = x_lo * y_lo;
auto t2 = x_lo * y_hi;
auto t3 = x_hi * y_lo;
auto t4 = x_hi * y_hi;
auto lo = (uint32_t)t1;
auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3;
auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32);
uint128 r = 0;
r.lo = (uint64_t)lo + (mid << 32);
r.hi = hi;
return r;
}
uint128 operator*(uint128 a)
{
auto t1 = mul(lo, a.lo);
auto t2 = mul(lo, a.hi);
auto t3 = mul(hi, a.lo);
return t1 + (t2 << 64) + (t3 << 64);
}
};
#endif
struct uint256
{
uint64_t lo = 0;
uint64_t mid = 0;
uint128 hi = 0;
uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {}
uint256(uint128 n)
{
lo = (uint64_t) n;
mid = (uint64_t) (n >> 64);
}
explicit operator uint128()
{
uint128 r = lo;
r = (r + ((uint128) mid)) << 64;
return r;
}
uint256 operator+(uint256 a)
{
auto _lo = (uint128) lo + a.lo;
auto _mid = (uint128) mid + a.mid + (_lo >> 64);
auto _hi = hi + a.hi + (_mid >> 64);
return {(uint64_t)_lo, (uint64_t)_mid, _hi};
}
uint256 lo2hi()
{
hi = (uint128)*this;
lo = 0;
mid = 0;
return *this;
}
};
struct uint512
{
uint128 lo;
uint128 mid;
uint256 hi;
};
uint256 mul(uint256 x, uint256 y)
{
auto t1 = (uint128) x.lo * y.lo;
auto t2 = (uint128) x.lo * y.mid;
auto t3 = (uint128) x.lo * y.hi;
auto t4 = (uint128) x.mid * y.lo;
auto t5 = (uint128) x.mid * y.mid;
auto t6 = (uint128) x.mid * y.hi;
auto t7 = x.hi * y.lo;
auto t8 = x.hi * y.mid;
auto lo = (uint64_t) t1;
auto m1 = (t1 >> 64) + (uint64_t) t2;
auto m2 = (uint64_t) m1;
auto mid = (uint128) m2 + (uint64_t) t4;
auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7
+ (t8 << 64) + (m1 >> 64) + (mid >> 64);
return {lo, (uint64_t)mid, hi};
}
uint512 mul512(uint256 x, uint256 y)
{
auto x_lo = (uint128) x;
auto y_lo = (uint128) y;
auto t1 = mul(x_lo, y_lo);
auto t2 = mul(x_lo, y.hi);
auto t3 = mul(x.hi, y_lo);
auto t4 = mul(x.hi, y.hi);
auto lo = (uint128) t1;
auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3;
auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi;
return {lo, (uint128)mid, hi};
}
}
} }
} }
@ -489,20 +398,9 @@ namespace
extern "C" extern "C"
{ {
using namespace dev::eth::jit;
EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z)
{ {
std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a
} << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n";
EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result)
{
*o_result = mul(*_arg1, *_arg2);
}
EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result)
{
*o_result = mul512(*_arg1, *_arg2);
} }
} }

13
evmjit/libevmjit/Arith256.h

@ -24,26 +24,21 @@ public:
void debug(llvm::Value* _value, char _c); void debug(llvm::Value* _value, char _c);
private: private:
llvm::Function* getMulFunc();
llvm::Function* getMul512Func();
llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getDivFunc(llvm::Type* _type);
llvm::Function* getExpFunc(); llvm::Function* getExpFunc();
llvm::Function* getAddModFunc(); llvm::Function* getAddModFunc();
llvm::Function* getMulModFunc(); llvm::Function* getMulModFunc();
llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); llvm::Function* m_mul = nullptr;
llvm::Function* m_mul512 = nullptr;
llvm::Function* m_mul;
llvm::Function* m_div = nullptr; llvm::Function* m_div = nullptr;
llvm::Function* m_div512 = nullptr; llvm::Function* m_div512 = nullptr;
llvm::Function* m_exp = nullptr; llvm::Function* m_exp = nullptr;
llvm::Function* m_addmod = nullptr; llvm::Function* m_addmod = nullptr;
llvm::Function* m_mulmod = nullptr; llvm::Function* m_mulmod = nullptr;
llvm::Function* m_debug = nullptr; llvm::Function* m_debug = nullptr;
llvm::Value* m_arg1;
llvm::Value* m_arg2;
llvm::Value* m_arg3;
llvm::Value* m_result;
}; };

19
evmjit/libevmjit/BasicBlock.cpp

@ -1,13 +1,14 @@
#include "BasicBlock.h" #include "BasicBlock.h"
#include <iostream> #include <iostream>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/CFG.h> #include <llvm/IR/CFG.h>
#include <llvm/IR/Function.h> #include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h> #include <llvm/IR/Instructions.h>
#include <llvm/IR/IRBuilder.h> #include <llvm/IR/IRBuilder.h>
#include <llvm/Support/raw_os_ostream.h> #include <llvm/Support/raw_os_ostream.h>
#include "preprocessor/llvm_includes_end.h"
#include "Type.h" #include "Type.h"
@ -18,13 +19,14 @@ namespace eth
namespace jit namespace jit
{ {
const char* BasicBlock::NamePrefix = "Instr."; static const char* jumpDestName = "JmpDst.";
static const char* basicBlockName = "Instr.";
BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
m_firstInstrIdx{_firstInstrIdx},
m_begin(_begin), m_begin(_begin),
m_end(_end), m_end(_end),
// TODO: Add begin index to name m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)),
m_stack(*this), m_stack(*this),
m_builder(_builder), m_builder(_builder),
m_isJumpDest(isJumpDest) m_isJumpDest(isJumpDest)
@ -43,6 +45,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) :
void BasicBlock::LocalStack::push(llvm::Value* _value) void BasicBlock::LocalStack::push(llvm::Value* _value)
{ {
assert(_value->getType() == Type::Word);
m_bblock.m_currentStack.push_back(_value); m_bblock.m_currentStack.push_back(_value);
m_bblock.m_tosOffset += 1; m_bblock.m_tosOffset += 1;
} }
@ -139,7 +142,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
auto endIter = m_currentStack.end(); auto endIter = m_currentStack.end();
// Update (emit set()) changed values // Update (emit set()) changed values
for (int idx = m_currentStack.size() - 1 - m_tosOffset; for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset;
currIter < endIter && idx >= 0; currIter < endIter && idx >= 0;
++currIter, --idx) ++currIter, --idx)
{ {
@ -306,7 +309,7 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
auto& initialStack = bblock.m_initialStack; auto& initialStack = bblock.m_initialStack;
initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems);
// Initial stack shrinks, so the size difference grows: // Initial stack shrinks, so the size difference grows:
bblock.m_tosOffset += info.inputItems; bblock.m_tosOffset += (int)info.inputItems;
} }
// We must account for the items that were pushed directly to successor // We must account for the items that were pushed directly to successor
@ -319,7 +322,7 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
auto& exitStack = bblock.m_currentStack; auto& exitStack = bblock.m_currentStack;
exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); exitStack.erase(exitStack.end() - info.outputItems, exitStack.end());
bblock.m_tosOffset -= info.outputItems; bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types
} }
} }

20
evmjit/libevmjit/BasicBlock.h

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <llvm/IR/BasicBlock.h>
#include "Common.h" #include "Common.h"
#include "Stack.h" #include "Stack.h"
@ -11,7 +12,7 @@ namespace eth
namespace jit namespace jit
{ {
using ProgramCounter = uint64_t; // TODO: Rename using instr_idx = uint64_t;
class BasicBlock class BasicBlock
{ {
@ -50,10 +51,7 @@ public:
BasicBlock& m_bblock; BasicBlock& m_bblock;
}; };
/// Basic block name prefix. The rest is instruction index. explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
static const char* NamePrefix;
explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
BasicBlock(const BasicBlock&) = delete; BasicBlock(const BasicBlock&) = delete;
@ -61,8 +59,9 @@ public:
llvm::BasicBlock* llvm() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; }
bytes::const_iterator begin() { return m_begin; } instr_idx firstInstrIdx() const { return m_firstInstrIdx; }
bytes::const_iterator end() { return m_end; } code_iterator begin() const { return m_begin; }
code_iterator end() const { return m_end; }
bool isJumpDest() const { return m_isJumpDest; } bool isJumpDest() const { return m_isJumpDest; }
@ -84,8 +83,9 @@ public:
void dump(std::ostream& os, bool _dotOutput = false); void dump(std::ostream& os, bool _dotOutput = false);
private: private:
bytes::const_iterator const m_begin; instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block
bytes::const_iterator const m_end; code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block
code_iterator const m_end = {}; ///< Iterator pointing code end of the block
llvm::BasicBlock* const m_llvmBB; llvm::BasicBlock* const m_llvmBB;

10
evmjit/libevmjit/BuildInfo.h.in

@ -0,0 +1,10 @@
#define EVMJIT_VERSION "${EVMJIT_VERSION}"
#define EVMJIT_VERSION_MAJOR ${EVMJIT_VERSION_MAJOR}
#define EVMJIT_VERSION_MINOR ${EVMJIT_VERSION_MINOR}
#define EVMJIT_VERSION_PATCH ${EVMJIT_VERSION_PATCH}
#define EVMJIT_VERSION_PRERELEASE "${EVMJIT_VERSION_PRERELEASE}"
#define EVMJIT_VERSION_FULL "${EVMJIT_VERSION_FULL}"
#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}"
#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}"

59
evmjit/libevmjit/CMakeLists.txt

@ -6,30 +6,63 @@ set(INTERFACE_HEADERS interface.h)
source_group("" FILES ${HEADERS}) source_group("" FILES ${HEADERS})
source_group("" FILES ${SOURCES}) source_group("" FILES ${SOURCES})
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
# Disable rtti for Cache as LLVM has no rtti else()
set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif() endif()
find_package(Git)
if(GIT_FOUND) set(EVMJIT_VERSION "0.0.0")
execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always set(EVMJIT_VERSION_MAJOR 0)
OUTPUT_VARIABLE EVMJIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) set(EVMJIT_VERSION_MINOR 0)
set(EVMJIT_VERSION_PATCH 0)
set(EVMJIT_VERSION_FULL "v0.0.0-nogit")
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always --match v*
OUTPUT_VARIABLE EVMJIT_VERSION_FULL OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+")
string(SUBSTRING ${EVMJIT_VERSION_FULL} 1 -1 EVMJIT_VERSION_FULL) # skip "v"
string(REPLACE "-" ";" VERSION_COMPONENTS ${EVMJIT_VERSION_FULL})
list(LENGTH VERSION_COMPONENTS NUM_VERSION_COMPONENTS)
list(GET VERSION_COMPONENTS 0 EVMJIT_VERSION)
string(REPLACE "." ";" VERSION_NUMBERS ${EVMJIT_VERSION})
list(LENGTH VERSION_NUMBERS NUM_VERSION_NUMBERS)
list(GET VERSION_NUMBERS 0 EVMJIT_VERSION_MAJOR)
list(GET VERSION_NUMBERS 1 EVMJIT_VERSION_MINOR)
if(${NUM_VERSION_NUMBERS} GREATER 2)
list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional
endif()
if(${NUM_VERSION_COMPONENTS} GREATER 1)
list(GET VERSION_COMPONENTS 1 VERSION_PRERELEASE_CANDIDATE)
string(REGEX MATCH "^[a-zA-Z]+.*" EVMJIT_VERSION_PRERELEASE ${VERSION_PRERELEASE_CANDIDATE}) # prerelease starts with letter
endif()
endif() endif()
if(NOT EVMJIT_VERSION)
set(EVMJIT_VERSION "unknown") if(${EVMJIT_VERSION_MAJOR} EQUAL 0)
set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}")
else()
set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR})
endif() endif()
message("EVM JIT version: ${EVMJIT_VERSION}") configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h)
message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})")
add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h)
set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} FOLDER "libs") set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs")
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen)
target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS})
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin)
#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) #install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME})

62
evmjit/libevmjit/Cache.cpp

@ -1,12 +1,19 @@
#include "Cache.h" #include "Cache.h"
#include <unordered_map>
#include <cassert>
#include <iostream> #include <iostream>
#include <cassert>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/Path.h> #include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h> #include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h> #include <llvm/Support/raw_os_ostream.h>
#include "preprocessor/llvm_includes_end.h"
#include "ExecutionEngine.h"
#include "Utils.h"
namespace dev namespace dev
{ {
@ -15,23 +22,31 @@ namespace eth
namespace jit namespace jit
{ {
//#define LOG(...) std::cerr << "CACHE " //#define CACHE_LOG std::cerr << "CACHE "
#define LOG(...) std::ostream(nullptr) #define CACHE_LOG std::ostream(nullptr)
ObjectCache* Cache::getObjectCache() namespace
{ {
static ObjectCache objectCache; llvm::MemoryBuffer* g_lastObject;
return &objectCache; ExecutionEngineListener* g_listener;
} }
namespace ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener)
{ {
llvm::MemoryBuffer* lastObject; static ObjectCache objectCache;
g_listener = _listener;
return &objectCache;
} }
std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id) std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
{ {
assert(!lastObject); if (g_listener)
g_listener->stateChanged(ExecState::CacheLoad);
CACHE_LOG << id << ": search\n";
if (!CHECK(!g_lastObject))
g_lastObject = nullptr;
llvm::SmallString<256> cachePath; llvm::SmallString<256> cachePath;
llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::system_temp_directory(false, cachePath);
llvm::sys::path::append(cachePath, "evm_objs", id); llvm::sys::path::append(cachePath, "evm_objs", id);
@ -51,22 +66,31 @@ std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
#endif #endif
if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
std::cerr << r.getError().message(); // TODO: Add log std::cerr << r.getError().message(); // TODO: Add log
if (lastObject) // if object found create fake module if (g_lastObject) // if object found create fake module
{ {
auto module = std::unique_ptr<llvm::Module>(new llvm::Module(id, llvm::getGlobalContext())); CACHE_LOG << id << ": found\n";
auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); auto&& context = llvm::getGlobalContext();
llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); auto module = std::unique_ptr<llvm::Module>(new llvm::Module(id, context));
auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false);
auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
auto bb = llvm::BasicBlock::Create(context, {}, mainFunc);
bb->getInstList().push_back(new llvm::UnreachableInst{context});
return module;
} }
CACHE_LOG << id << ": not found\n";
return nullptr; return nullptr;
} }
void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object)
{ {
if (g_listener)
g_listener->stateChanged(ExecState::CacheWrite);
auto&& id = _module->getModuleIdentifier(); auto&& id = _module->getModuleIdentifier();
llvm::SmallString<256> cachePath; llvm::SmallString<256> cachePath;
llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::system_temp_directory(false, cachePath);
@ -77,15 +101,17 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory
llvm::sys::path::append(cachePath, id); llvm::sys::path::append(cachePath, id);
CACHE_LOG << id << ": write\n";
std::string error; std::string error;
llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None);
cacheFile << _object->getBuffer(); cacheFile << _object->getBuffer();
} }
llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
{ {
auto o = lastObject; CACHE_LOG << _module->getModuleIdentifier() << ": use\n";
lastObject = nullptr; auto o = g_lastObject;
g_lastObject = nullptr;
return o; return o;
} }

9
evmjit/libevmjit/Cache.h

@ -1,9 +1,8 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <unordered_map>
#include <llvm/ExecutionEngine/ObjectCache.h>
#include <llvm/ExecutionEngine/ObjectCache.h>
namespace dev namespace dev
{ {
@ -11,6 +10,7 @@ namespace eth
{ {
namespace jit namespace jit
{ {
class ExecutionEngineListener;
class ObjectCache : public llvm::ObjectCache class ObjectCache : public llvm::ObjectCache
{ {
@ -23,16 +23,13 @@ public:
/// not available. The caller owns both the MemoryBuffer returned by this /// not available. The caller owns both the MemoryBuffer returned by this
/// and the memory it references. /// and the memory it references.
virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override;
private:
std::unordered_map<std::string, std::unique_ptr<llvm::MemoryBuffer>> m_map;
}; };
class Cache class Cache
{ {
public: public:
static ObjectCache* getObjectCache(); static ObjectCache* getObjectCache(ExecutionEngineListener* _listener);
static std::unique_ptr<llvm::Module> getObject(std::string const& id); static std::unique_ptr<llvm::Module> getObject(std::string const& id);
}; };

25
evmjit/libevmjit/Common.h

@ -20,25 +20,30 @@ namespace jit
using byte = uint8_t; using byte = uint8_t;
using bytes = std::vector<byte>; using bytes = std::vector<byte>;
using bytes_ref = std::tuple<byte const*, size_t>; using bytes_ref = std::tuple<byte const*, size_t>;
using code_iterator = byte const*;
struct NoteChannel {}; // FIXME: Use some log library? struct NoteChannel {}; // FIXME: Use some log library?
enum class ReturnCode enum class ReturnCode
{ {
Stop = 0, // Success codes
Return = 1, Stop = 0,
Return = 1,
Suicide = 2, Suicide = 2,
OutOfGas = -1, // Standard error codes
BadJumpDestination = -2, OutOfGas = -1,
StackTooSmall = -3, StackTooSmall = -2,
BadInstruction = -4, BadJumpDestination = -3,
BadInstruction = -4,
Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected
LLVMConfigError = -5, // Internal error codes
LLVMCompileError = -6, LLVMConfigError = -101,
LLVMLinkError = -7, LLVMCompileError = -102,
LLVMLinkError = -103,
UnexpectedException = -8, UnexpectedException = -111,
LinkerWorkaround = -299, LinkerWorkaround = -299,
}; };

94
evmjit/libevmjit/Compiler.cpp

@ -1,4 +1,3 @@
#include "Compiler.h" #include "Compiler.h"
#include <functional> #include <functional>
@ -6,13 +5,15 @@
#include <chrono> #include <chrono>
#include <sstream> #include <sstream>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/ADT/PostOrderIterator.h> #include <llvm/ADT/PostOrderIterator.h>
#include <llvm/IR/CFG.h> #include <llvm/IR/CFG.h>
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/MDBuilder.h>
#include <llvm/PassManager.h> #include <llvm/PassManager.h>
#include <llvm/Transforms/Scalar.h> #include <llvm/Transforms/Scalar.h>
#include "preprocessor/llvm_includes_end.h"
#include "Instruction.h" #include "Instruction.h"
#include "Type.h" #include "Type.h"
@ -39,10 +40,10 @@ Compiler::Compiler(Options const& _options):
Type::init(m_builder.getContext()); Type::init(m_builder.getContext());
} }
void Compiler::createBasicBlocks(bytes const& _bytecode) void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd)
{ {
/// Helper function that skips push data and finds next iterator (can be the end) /// Helper function that skips push data and finds next iterator (can be the end)
auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end) auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end)
{ {
static const auto push1 = static_cast<size_t>(Instruction::PUSH1); static const auto push1 = static_cast<size_t>(Instruction::PUSH1);
static const auto push32 = static_cast<size_t>(Instruction::PUSH32); static const auto push32 = static_cast<size_t>(Instruction::PUSH32);
@ -52,11 +53,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode)
return _curr + offset; return _curr + offset;
}; };
auto begin = _bytecode.begin(); auto begin = _codeBegin; // begin of current block
bool nextJumpDest = false; bool nextJumpDest = false;
for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) for (auto curr = begin, next = begin; curr != _codeEnd; curr = next)
{ {
next = skipPushDataAndGetNext(curr, _bytecode.end()); next = skipPushDataAndGetNext(curr, _codeEnd);
bool isEnd = false; bool isEnd = false;
switch (Instruction(*curr)) switch (Instruction(*curr))
@ -77,22 +78,19 @@ void Compiler::createBasicBlocks(bytes const& _bytecode)
break; break;
} }
assert(next <= _bytecode.end()); assert(next <= _codeEnd);
if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST)
isEnd = true; isEnd = true;
if (isEnd) if (isEnd)
{ {
auto beginIdx = begin - _bytecode.begin(); auto beginIdx = begin - _codeBegin;
m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx),
std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest));
nextJumpDest = false; nextJumpDest = false;
begin = next; begin = next;
} }
} }
// TODO: Create Stop basic block on demand
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
} }
llvm::BasicBlock* Compiler::getJumpTableBlock() llvm::BasicBlock* Compiler::getJumpTableBlock()
@ -125,7 +123,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock()
return m_badJumpBlock->llvm(); return m_badJumpBlock->llvm();
} }
std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::string const& _id) std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id)
{ {
auto compilationStartTime = std::chrono::high_resolution_clock::now(); auto compilationStartTime = std::chrono::high_resolution_clock::now();
auto module = std::unique_ptr<llvm::Module>(new llvm::Module(_id, m_builder.getContext())); auto module = std::unique_ptr<llvm::Module>(new llvm::Module(_id, m_builder.getContext()));
@ -135,21 +133,40 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get());
m_mainFunc->getArgumentList().front().setName("rt"); m_mainFunc->getArgumentList().front().setName("rt");
// Create the basic blocks. // Create entry basic block
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc);
m_builder.SetInsertPoint(entryBlock); m_builder.SetInsertPoint(entryBlock);
createBasicBlocks(_bytecode); auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words");
auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress);
auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp");
m_builder.CreateStore(fp, jmpBufWords);
auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave);
auto sp = m_builder.CreateCall(stacksave, "sp");
auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp");
m_builder.CreateStore(sp, jmpBufSp);
auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp);
auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf");
auto r = m_builder.CreateCall(setjmp, jmpBuf);
auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0));
createBasicBlocks(_begin, _end);
// Init runtime structures. // Init runtime structures.
RuntimeManager runtimeManager(m_builder); RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end);
GasMeter gasMeter(m_builder, runtimeManager); GasMeter gasMeter(m_builder, runtimeManager);
Memory memory(runtimeManager, gasMeter); Memory memory(runtimeManager, gasMeter);
Ext ext(runtimeManager, memory); Ext ext(runtimeManager, memory);
Stack stack(m_builder, runtimeManager); Stack stack(m_builder, runtimeManager);
Arith256 arith(m_builder); Arith256 arith(m_builder);
m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); // TODO: Create Stop basic block on demand
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc);
auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm();
auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0);
m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue);
for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt)
{ {
@ -157,7 +174,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
auto iterCopy = basicBlockPairIt; auto iterCopy = basicBlockPairIt;
++iterCopy; ++iterCopy;
auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock);
} }
// Code for special blocks: // Code for special blocks:
@ -165,6 +182,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
m_builder.SetInsertPoint(m_stopBB); m_builder.SetInsertPoint(m_stopBB);
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); m_builder.CreateRet(Constant::get(ReturnCode::Stop));
m_builder.SetInsertPoint(abortBB);
m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas));
removeDeadBlocks(); removeDeadBlocks();
// Link jump table target index // Link jump table target index
@ -224,7 +244,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
} }
void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager,
Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock)
{ {
if (!_nextBasicBlock) // this is the last block in the code if (!_nextBasicBlock) // this is the last block in the code
@ -623,7 +643,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::PC: case Instruction::PC:
{ {
auto value = Constant::get(it - _bytecode.begin()); auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx());
stack.push(value); stack.push(value);
break; break;
} }
@ -631,7 +651,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::GAS: case Instruction::GAS:
{ {
_gasMeter.commitCostBlock(); _gasMeter.commitCostBlock();
stack.push(_runtimeManager.getGas()); stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word));
break; break;
} }
@ -741,10 +761,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
_memory.require(initOff, initSize); _memory.require(initOff, initSize);
_gasMeter.commitCostBlock(); _gasMeter.commitCostBlock();
auto address = _ext.create(endowment, initOff, initSize);
auto gas = _runtimeManager.getGas();
auto address = _ext.create(gas, endowment, initOff, initSize);
_runtimeManager.setGas(gas);
stack.push(address); stack.push(address);
break; break;
} }
@ -752,7 +769,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::CALL: case Instruction::CALL:
case Instruction::CALLCODE: case Instruction::CALLCODE:
{ {
auto gas = stack.pop(); auto callGas256 = stack.pop();
auto codeAddress = stack.pop(); auto codeAddress = stack.pop();
auto value = stack.pop(); auto value = stack.pop();
auto inOff = stack.pop(); auto inOff = stack.pop();
@ -770,9 +787,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
if (inst == Instruction::CALLCODE) if (inst == Instruction::CALLCODE)
receiveAddress = _runtimeManager.get(RuntimeData::Address); receiveAddress = _runtimeManager.get(RuntimeData::Address);
_gasMeter.count(gas); auto gas = _runtimeManager.getGas();
auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); _gasMeter.count(callGas256);
_gasMeter.giveBack(gas); auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas);
auto gasLeft = m_builder.CreateNSWSub(gas, callGas);
_runtimeManager.setGas(callGas);
auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress);
_gasMeter.giveBack(gasLeft);
stack.push(ret); stack.push(ret);
break; break;
} }
@ -825,12 +846,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
break; break;
} }
default: // Invalid instruction - runtime exception default: // Invalid instruction - abort
{ m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction));
// TODO: Replace with return statement it = _basicBlock.end() - 1; // finish block compilation
_runtimeManager.raiseException(ReturnCode::BadInstruction);
}
} }
} }

9
evmjit/libevmjit/Compiler.h

@ -1,8 +1,5 @@
#pragma once #pragma once
#include <llvm/IR/IRBuilder.h>
#include "Common.h" #include "Common.h"
#include "BasicBlock.h" #include "BasicBlock.h"
@ -33,13 +30,13 @@ public:
Compiler(Options const& _options); Compiler(Options const& _options);
std::unique_ptr<llvm::Module> compile(bytes const& _bytecode, std::string const& _id); std::unique_ptr<llvm::Module> compile(code_iterator _begin, code_iterator _end, std::string const& _id);
private: private:
void createBasicBlocks(bytes const& _bytecode); void createBasicBlocks(code_iterator _begin, code_iterator _end);
void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock);
llvm::BasicBlock* getJumpTableBlock(); llvm::BasicBlock* getJumpTableBlock();

4
evmjit/libevmjit/CompilerHelper.cpp

@ -1,8 +1,8 @@
#include "CompilerHelper.h" #include "CompilerHelper.h"
#include <llvm/IR/Function.h> #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include "preprocessor/llvm_includes_end.h"
#include "RuntimeManager.h" #include "RuntimeManager.h"

5
evmjit/libevmjit/CompilerHelper.h

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IRBuilder.h> #include <llvm/IR/IRBuilder.h>
#include "preprocessor/llvm_includes_end.h"
namespace dev namespace dev
@ -19,7 +20,7 @@ protected:
CompilerHelper(llvm::IRBuilder<>& _builder); CompilerHelper(llvm::IRBuilder<>& _builder);
CompilerHelper(const CompilerHelper&) = delete; CompilerHelper(const CompilerHelper&) = delete;
void operator=(CompilerHelper) = delete; CompilerHelper& operator=(CompilerHelper) = delete;
/// Reference to the IR module being compiled /// Reference to the IR module being compiled
llvm::Module* getModule(); llvm::Module* getModule();

3
evmjit/libevmjit/Endianness.cpp

@ -1,7 +1,8 @@
#include "Endianness.h" #include "Endianness.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "Type.h" #include "Type.h"

3
evmjit/libevmjit/Endianness.h

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IRBuilder.h> #include <llvm/IR/IRBuilder.h>
#include "preprocessor/llvm_includes_end.h"
namespace dev namespace dev
{ {

97
evmjit/libevmjit/ExecStats.cpp

@ -0,0 +1,97 @@
#include "ExecStats.h"
#include <iostream>
#include <iomanip>
#include <cassert>
#include "Utils.h"
namespace dev
{
namespace eth
{
namespace jit
{
void ExecStats::stateChanged(ExecState _state)
{
if (!CHECK(m_state != ExecState::Finished))
return;
auto now = clock::now();
if (_state != ExecState::Started)
{
assert(time[(int)m_state] == ExecStats::duration::zero());
time[(int)m_state] = now - m_tp;
}
m_state = _state;
m_tp = now;
}
namespace
{
struct StatsAgg
{
using unit = std::chrono::microseconds;
ExecStats::duration tot = ExecStats::duration::zero();
ExecStats::duration min = ExecStats::duration::max();
ExecStats::duration max = ExecStats::duration::zero();
size_t count = 0;
void update(ExecStats::duration _d)
{
++count;
tot += _d;
min = _d < min ? _d : min;
max = _d > max ? _d : max;
}
void output(char const* _name, std::ostream& _os)
{
auto avg = tot / count;
_os << std::setfill(' ')
<< std::setw(12) << std::left << _name
<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(tot).count()
<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(avg).count()
<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(min).count()
<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(max).count()
<< std::endl;
}
};
char const* getExecStateName(ExecState _state)
{
switch (_state)
{
case ExecState::Started: return "Start";
case ExecState::CacheLoad: return "CacheLoad";
case ExecState::CacheWrite: return "CacheWrite";
case ExecState::Compilation: return "Compilation";
case ExecState::CodeGen: return "CodeGen";
case ExecState::Execution: return "Execution";
case ExecState::Return: return "Return";
case ExecState::Finished: return "Finish";
}
return nullptr;
}
}
StatsCollector::~StatsCollector()
{
if (stats.empty())
return;
std::cout << " [us] total avg min max\n";
for (int i = 0; i < (int)ExecState::Finished; ++i)
{
StatsAgg agg;
for (auto&& s : stats)
agg.update(s->time[i]);
agg.output(getExecStateName(ExecState(i)), std::cout);
}
}
}
}
}

44
evmjit/libevmjit/ExecStats.h

@ -0,0 +1,44 @@
#pragma once
#include <string>
#include <chrono>
#include "ExecutionEngine.h"
namespace dev
{
namespace eth
{
namespace jit
{
class ExecStats : public ExecutionEngineListener
{
public:
using clock = std::chrono::high_resolution_clock;
using duration = clock::duration;
using time_point = clock::time_point;
std::string id;
duration time[(int)ExecState::Finished] = {};
void stateChanged(ExecState _state) override;
private:
ExecState m_state = {};
time_point m_tp = {};
};
class StatsCollector
{
public:
std::vector<std::unique_ptr<ExecStats>> stats;
~StatsCollector();
};
}
}
}

169
evmjit/libevmjit/ExecutionEngine.cpp

@ -1,24 +1,25 @@
#include "ExecutionEngine.h" #include "ExecutionEngine.h"
#include <chrono> #include <array>
#include <cstdlib> // env options #include <cstdlib> // env options
#include <iostream>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h> #include <llvm/ADT/Triple.h>
#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <llvm/ExecutionEngine/ExecutionEngine.h> #include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h> #include <llvm/ExecutionEngine/SectionMemoryManager.h>
#pragma warning(pop)
#pragma GCC diagnostic pop
#include <llvm/ExecutionEngine/MCJIT.h> #include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h> #include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h> #include <llvm/Support/Host.h>
#include "preprocessor/llvm_includes_end.h"
#include "Runtime.h" #include "Runtime.h"
#include "Compiler.h" #include "Compiler.h"
#include "Cache.h" #include "Cache.h"
#include "ExecStats.h"
#include "Utils.h"
#include "BuildInfo.gen.h"
namespace dev namespace dev
{ {
@ -31,34 +32,20 @@ namespace
{ {
using EntryFuncPtr = ReturnCode(*)(Runtime*); using EntryFuncPtr = ReturnCode(*)(Runtime*);
ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) std::string codeHash(i256 const& _hash)
{ {
// That function uses long jumps to handle "execeptions". static const auto size = sizeof(_hash);
// Do not create any non-POD objects here static const auto hexChars = "0123456789abcdef";
std::string str;
ReturnCode returnCode{}; str.resize(size * 2);
auto sj = setjmp(_runtime->getJmpBuf()); auto outIt = str.rbegin(); // reverse for BE
if (sj == 0) auto& arr = *(std::array<byte, size>*)&_hash;
returnCode = _mainFunc(_runtime); for (auto b : arr)
else
returnCode = static_cast<ReturnCode>(sj);
return returnCode;
}
std::string codeHash(bytes const& _code)
{
uint32_t hash = 0;
for (auto b : _code)
{ {
hash += b; *(outIt++) = hexChars[b & 0xf];
hash += (hash << 10); *(outIt++) = hexChars[b >> 4];
hash ^= (hash >> 6);
} }
hash += (hash << 3); return str;
hash ^= (hash >> 11);
hash += (hash << 15);
return std::to_string(hash);
} }
bool getEnvOption(char const* _name, bool _default) bool getEnvOption(char const* _name, bool _default)
@ -69,82 +56,94 @@ bool getEnvOption(char const* _name, bool _default)
return std::strtol(var, nullptr, 10) != 0; return std::strtol(var, nullptr, 10) != 0;
} }
bool showInfo()
{
auto show = getEnvOption("EVMJIT_INFO", false);
if (show)
{
std::cout << "The Ethereum EVM JIT " EVMJIT_VERSION_FULL " LLVM " LLVM_VERSION << std::endl;
}
return show;
} }
ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) }
ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
{ {
static std::unique_ptr<llvm::ExecutionEngine> ee; // TODO: Use Managed Objects from LLVM?
static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false);
static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true);
static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false);
static auto infoShown = showInfo();
(void) infoShown;
auto mainFuncName = codeHash(_code); std::unique_ptr<ExecStats> listener{new ExecStats};
EntryFuncPtr entryFuncPtr{}; listener->stateChanged(ExecState::Started);
Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls
if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr;
static std::unique_ptr<llvm::ExecutionEngine> ee;
if (!ee)
{ {
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
auto module = std::unique_ptr<llvm::Module>(new llvm::Module({}, llvm::getGlobalContext()));
llvm::EngineBuilder builder(module.get());
builder.setEngineKind(llvm::EngineKind::JIT);
builder.setUseMCJIT(true);
builder.setOptLevel(llvm::CodeGenOpt::None);
auto triple = llvm::Triple(llvm::sys::getProcessTriple());
if (triple.getOS() == llvm::Triple::OSType::Win32)
triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format
module->setTargetTriple(triple.str());
ee.reset(builder.create());
if (!CHECK(ee))
return ReturnCode::LLVMConfigError;
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
ee->setObjectCache(objectCache);
} }
else
static StatsCollector statsCollector;
auto mainFuncName = codeHash(_data->codeHash);
Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls
auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
if (!entryFuncPtr)
{ {
auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
std::unique_ptr<llvm::Module> module;
if (objectCache)
module = Cache::getObject(mainFuncName);
if (!module) if (!module)
module = Compiler({}).compile(_code, mainFuncName);
if (debugDumpModule)
module->dump();
if (!ee)
{
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::EngineBuilder builder(module.get());
builder.setEngineKind(llvm::EngineKind::JIT);
builder.setUseMCJIT(true);
std::unique_ptr<llvm::SectionMemoryManager> memoryManager(new llvm::SectionMemoryManager);
builder.setMCJITMemoryManager(memoryManager.get());
builder.setOptLevel(llvm::CodeGenOpt::None);
auto triple = llvm::Triple(llvm::sys::getProcessTriple());
if (triple.getOS() == llvm::Triple::OSType::Win32)
triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format
module->setTargetTriple(triple.str());
ee.reset(builder.create());
if (!ee)
return ReturnCode::LLVMConfigError;
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
memoryManager.release(); // and memory manager
if (objectCache)
ee->setObjectCache(objectCache);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
}
else
{ {
if (!entryFuncPtr) listener->stateChanged(ExecState::Compilation);
{ assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code?
ee->addModule(module.get()); module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName);
module.release();
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
}
} }
if (debugDumpModule)
module->dump();
ee->addModule(module.get());
module.release();
listener->stateChanged(ExecState::CodeGen);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
} }
assert(entryFuncPtr); if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
auto executionStartTime = std::chrono::high_resolution_clock::now(); listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&runtime);
listener->stateChanged(ExecState::Return);
auto returnCode = runEntryFunc(entryFuncPtr, &runtime);
if (returnCode == ReturnCode::Return) if (returnCode == ReturnCode::Return)
{ {
returnData = runtime.getReturnData(); // Save reference to return data returnData = runtime.getReturnData(); // Save reference to return data
std::swap(m_memory, runtime.getMemory()); // Take ownership of memory std::swap(m_memory, runtime.getMemory()); // Take ownership of memory
} }
listener->stateChanged(ExecState::Finished);
auto executionEndTime = std::chrono::high_resolution_clock::now(); if (statsCollectingEnabled)
clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(executionEndTime - executionStartTime).count() << " ms\n"; statsCollector.stats.push_back(std::move(listener));
return returnCode; return returnCode;
} }

32
evmjit/libevmjit/ExecutionEngine.h

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <memory>
#include "RuntimeData.h" #include "RuntimeData.h"
namespace dev namespace dev
@ -9,14 +11,40 @@ namespace eth
namespace jit namespace jit
{ {
enum class ExecState
{
Started,
CacheLoad,
CacheWrite,
Compilation,
CodeGen,
Execution,
Return,
Finished
};
class ExecutionEngineListener
{
public:
ExecutionEngineListener() = default;
ExecutionEngineListener(ExecutionEngineListener const&) = delete;
ExecutionEngineListener& operator=(ExecutionEngineListener) = delete;
virtual ~ExecutionEngineListener() {}
virtual void executionStarted() {}
virtual void executionEnded() {}
virtual void stateChanged(ExecState) {}
};
class ExecutionEngine class ExecutionEngine
{ {
public: public:
ExecutionEngine() = default; ExecutionEngine() = default;
ExecutionEngine(ExecutionEngine const&) = delete; ExecutionEngine(ExecutionEngine const&) = delete;
void operator=(ExecutionEngine) = delete; ExecutionEngine& operator=(ExecutionEngine) = delete;
EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); EXPORT ReturnCode run(RuntimeData* _data, Env* _env);
/// Reference to returned data (RETURN opcode used) /// Reference to returned data (RETURN opcode used)
bytes_ref returnData; bytes_ref returnData;

31
evmjit/libevmjit/Ext.cpp

@ -1,9 +1,8 @@
#include "Ext.h" #include "Ext.h"
#include <llvm/IR/Function.h> #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/TypeBuilder.h>
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "RuntimeManager.h" #include "RuntimeManager.h"
#include "Memory.h" #include "Memory.h"
@ -41,8 +40,8 @@ std::array<FuncDesc, sizeOf<EnvFunc>::value> const& getEnvFuncDescs()
FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})},
@ -60,14 +59,16 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module)
llvm::Value* Ext::getArgAlloca() llvm::Value* Ext::getArgAlloca()
{ {
auto& a = m_argAllocas[m_argCounter++]; auto& a = m_argAllocas[m_argCounter];
if (!a) if (!a)
{ {
// FIXME: Improve order and names
InsertPointGuard g{getBuilder()}; InsertPointGuard g{getBuilder()};
getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); auto allocaIt = getMainFunction()->front().begin();
a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); std::advance(allocaIt, m_argCounter); // Skip already created allocas
getBuilder().SetInsertPoint(allocaIt);
a = getBuilder().CreateAlloca(Type::Word, nullptr, {"a.", std::to_string(m_argCounter)});
} }
++m_argCounter;
return a; return a;
} }
@ -124,30 +125,26 @@ llvm::Value* Ext::blockhash(llvm::Value* _number)
return Endianness::toNative(getBuilder(), hash); return Endianness::toNative(getBuilder(), hash);
} }
llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize)
{ {
auto gas = byPtr(_gas);
auto ret = getArgAlloca(); auto ret = getArgAlloca();
auto begin = m_memoryMan.getBytePtr(_initOff); auto begin = m_memoryMan.getBytePtr(_initOff);
auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size");
createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret});
_gas = m_builder.CreateLoad(gas); // Return gas
llvm::Value* address = m_builder.CreateLoad(ret); llvm::Value* address = m_builder.CreateLoad(ret);
address = Endianness::toNative(m_builder, address); address = Endianness::toNative(m_builder, address);
return address; return address;
} }
llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress)
{ {
auto gas = byPtr(_gas);
auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress);
auto inBeg = m_memoryMan.getBytePtr(_inOff); auto inBeg = m_memoryMan.getBytePtr(_inOff);
auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size");
auto outBeg = m_memoryMan.getBytePtr(_outOff); auto outBeg = m_memoryMan.getBytePtr(_outOff);
auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size");
auto codeAddress = Endianness::toBE(m_builder, _codeAddress); auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)});
_gas = m_builder.CreateLoad(gas); // Return gas
return m_builder.CreateZExt(ret, Type::Word, "ret"); return m_builder.CreateZExt(ret, Type::Word, "ret");
} }

6
evmjit/libevmjit/Ext.h

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include "CompilerHelper.h" #include "CompilerHelper.h"
namespace dev namespace dev
@ -50,8 +50,8 @@ public:
llvm::Value* balance(llvm::Value* _address); llvm::Value* balance(llvm::Value* _address);
llvm::Value* calldataload(llvm::Value* _index); llvm::Value* calldataload(llvm::Value* _index);
llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize);
llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress);
llvm::Value* blockhash(llvm::Value* _number); llvm::Value* blockhash(llvm::Value* _number);
llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize);

107
evmjit/libevmjit/GasMeter.cpp

@ -1,11 +1,9 @@
#include "GasMeter.h" #include "GasMeter.h"
#include <llvm/IR/GlobalVariable.h> #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "Type.h"
#include "Ext.h" #include "Ext.h"
#include "RuntimeManager.h" #include "RuntimeManager.h"
@ -19,29 +17,29 @@ namespace jit
namespace // Helper functions namespace // Helper functions
{ {
uint64_t const c_stepGas = 1; int64_t const c_stepGas = 1;
uint64_t const c_balanceGas = 20; int64_t const c_balanceGas = 20;
uint64_t const c_sha3Gas = 10; int64_t const c_sha3Gas = 10;
uint64_t const c_sha3WordGas = 10; int64_t const c_sha3WordGas = 10;
uint64_t const c_sloadGas = 20; int64_t const c_sloadGas = 20;
uint64_t const c_sstoreSetGas = 300; int64_t const c_sstoreSetGas = 300;
uint64_t const c_sstoreResetGas = 100; int64_t const c_sstoreResetGas = 100;
uint64_t const c_sstoreRefundGas = 100; int64_t const c_sstoreRefundGas = 100;
uint64_t const c_createGas = 100; int64_t const c_createGas = 100;
uint64_t const c_createDataGas = 5; int64_t const c_createDataGas = 5;
uint64_t const c_callGas = 20; int64_t const c_callGas = 20;
uint64_t const c_expGas = 1; int64_t const c_expGas = 1;
uint64_t const c_expByteGas = 1; int64_t const c_expByteGas = 1;
uint64_t const c_memoryGas = 1; int64_t const c_memoryGas = 1;
uint64_t const c_txDataZeroGas = 1; int64_t const c_txDataZeroGas = 1;
uint64_t const c_txDataNonZeroGas = 5; int64_t const c_txDataNonZeroGas = 5;
uint64_t const c_txGas = 500; int64_t const c_txGas = 500;
uint64_t const c_logGas = 32; int64_t const c_logGas = 32;
uint64_t const c_logDataGas = 1; int64_t const c_logDataGas = 1;
uint64_t const c_logTopicGas = 32; int64_t const c_logTopicGas = 32;
uint64_t const c_copyGas = 1; int64_t const c_copyGas = 1;
uint64_t getStepCost(Instruction inst) int64_t getStepCost(Instruction inst)
{ {
switch (inst) switch (inst)
{ {
@ -72,7 +70,7 @@ uint64_t getStepCost(Instruction inst)
case Instruction::LOG3: case Instruction::LOG3:
case Instruction::LOG4: case Instruction::LOG4:
{ {
auto numTopics = static_cast<uint64_t>(inst) - static_cast<uint64_t>(Instruction::LOG0); auto numTopics = static_cast<int64_t>(inst) - static_cast<int64_t>(Instruction::LOG0);
return c_logGas + numTopics * c_logTopicGas; return c_logGas + numTopics * c_logTopicGas;
} }
} }
@ -86,7 +84,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
{ {
auto module = getModule(); auto module = getModule();
llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas};
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module);
InsertPointGuard guard(m_builder); InsertPointGuard guard(m_builder);
@ -94,22 +92,22 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);
auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);
auto rt = &m_gasCheckFunc->getArgumentList().front();
rt->setName("rt");
auto cost = rt->getNextNode();
cost->setName("cost");
m_builder.SetInsertPoint(checkBB); m_builder.SetInsertPoint(checkBB);
auto arg = m_gasCheckFunc->arg_begin();
arg->setName("rt");
++arg;
arg->setName("cost");
auto cost = arg;
auto gas = m_runtimeManager.getGas(); auto gas = m_runtimeManager.getGas();
auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated");
auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions
m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
m_builder.SetInsertPoint(outOfGasBB); m_builder.SetInsertPoint(outOfGasBB);
m_runtimeManager.raiseException(ReturnCode::OutOfGas); m_runtimeManager.abort();
m_builder.CreateUnreachable(); m_builder.CreateUnreachable();
m_builder.SetInsertPoint(updateBB); m_builder.SetInsertPoint(updateBB);
gas = m_builder.CreateSub(gas, cost);
m_runtimeManager.setGas(gas); m_runtimeManager.setGas(gas);
m_builder.CreateRetVoid(); m_builder.CreateRetVoid();
} }
@ -119,7 +117,7 @@ void GasMeter::count(Instruction _inst)
if (!m_checkCall) if (!m_checkCall)
{ {
// Create gas check call with mocked block cost at begining of current cost-block // Create gas check call with mocked block cost at begining of current cost-block
m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)}); m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)});
} }
m_blockCost += getStepCost(_inst); m_blockCost += getStepCost(_inst);
@ -127,6 +125,15 @@ void GasMeter::count(Instruction _inst)
void GasMeter::count(llvm::Value* _cost) void GasMeter::count(llvm::Value* _cost)
{ {
if (_cost->getType() == Type::Word)
{
auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word);
auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh");
auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas);
_cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost");
}
assert(_cost->getType() == Type::Gas);
createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost});
} }
@ -136,12 +143,13 @@ void GasMeter::countExp(llvm::Value* _exponent)
// lz - leading zeros // lz - leading zeros
// cost = ((256 - lz) + 7) / 8 // cost = ((256 - lz) + 7) / 8
// OPT: All calculations can be done on 32/64 bits // OPT: Can gas update be done in exp algorithm?
auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
auto sigBits = m_builder.CreateSub(Constant::get(256), lz); auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits");
auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8));
count(sigBytes); count(sigBytes);
} }
@ -154,8 +162,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete");
auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost");
count(cost); count(cost);
} }
@ -173,17 +181,16 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength)
assert(m_blockCost > 0); // SHA3 instruction is already counted assert(m_blockCost > 0); // SHA3 instruction is already counted
// TODO: This round ups to 32 happens in many places // TODO: This round ups to 32 happens in many places
// FIXME: 64-bit arith used, but not verified
static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter");
auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas);
auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32));
auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64);
auto cost = getBuilder().CreateZExt(cost64, Type::Word); count(cost64);
count(cost);
} }
void GasMeter::giveBack(llvm::Value* _gas) void GasMeter::giveBack(llvm::Value* _gas)
{ {
assert(_gas->getType() == Type::Gas);
m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas));
} }
@ -199,7 +206,7 @@ void GasMeter::commitCostBlock()
return; return;
} }
m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call
m_checkCall = nullptr; // End cost-block m_checkCall = nullptr; // End cost-block
m_blockCost = 0; m_blockCost = 0;
} }

3
evmjit/libevmjit/GasMeter.h

@ -1,4 +1,3 @@
#pragma once #pragma once
#include "CompilerHelper.h" #include "CompilerHelper.h"
@ -50,7 +49,7 @@ public:
private: private:
/// Cumulative gas cost of a block of instructions /// Cumulative gas cost of a block of instructions
/// @TODO Handle overflow /// @TODO Handle overflow
uint64_t m_blockCost = 0; int64_t m_blockCost = 0;
llvm::CallInst* m_checkCall = nullptr; llvm::CallInst* m_checkCall = nullptr;
llvm::Function* m_gasCheckFunc = nullptr; llvm::Function* m_gasCheckFunc = nullptr;

8
evmjit/libevmjit/Instruction.cpp

@ -1,6 +1,8 @@
#include "Instruction.h" #include "Instruction.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/ADT/APInt.h> #include <llvm/ADT/APInt.h>
#include "preprocessor/llvm_includes_end.h"
namespace dev namespace dev
{ {
@ -9,7 +11,7 @@ namespace eth
namespace jit namespace jit
{ {
llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) llvm::APInt readPushData(code_iterator& _curr, code_iterator _end)
{ {
auto pushInst = *_curr; auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
@ -26,7 +28,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en
return value; return value;
} }
void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) void skipPushData(code_iterator& _curr, code_iterator _end)
{ {
auto pushInst = *_curr; auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);

4
evmjit/libevmjit/Instruction.h

@ -161,11 +161,11 @@ enum class Instruction: uint8_t
/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it
/// Reading out of bytecode means reading 0 /// Reading out of bytecode means reading 0
/// @param _curr is updated and points the last real byte read /// @param _curr is updated and points the last real byte read
llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); llvm::APInt readPushData(code_iterator& _curr, code_iterator _end);
/// Skips PUSH data in pointed fragment of bytecode. /// Skips PUSH data in pointed fragment of bytecode.
/// @param _curr is updated and points the last real byte skipped /// @param _curr is updated and points the last real byte skipped
void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); void skipPushData(code_iterator& _curr, code_iterator _end);
#define ANY_PUSH PUSH1: \ #define ANY_PUSH PUSH1: \
case Instruction::PUSH2: \ case Instruction::PUSH2: \

499
evmjit/libevmjit/Memory.cpp

@ -1,239 +1,260 @@
#include "Memory.h" #include "Memory.h"
#include <vector> #include "preprocessor/llvm_includes_start.h"
#include <iostream> #include <llvm/IR/IntrinsicInst.h>
#include <iomanip> #include "preprocessor/llvm_includes_end.h"
#include <cstdint>
#include <cassert> #include "Type.h"
#include "Runtime.h"
#include <llvm/IR/GlobalVariable.h> #include "GasMeter.h"
#include <llvm/IR/Function.h> #include "Endianness.h"
#include <llvm/IR/IntrinsicInst.h> #include "RuntimeManager.h"
#include "Type.h" namespace dev
#include "Runtime.h" {
#include "GasMeter.h" namespace eth
#include "Endianness.h" {
#include "RuntimeManager.h" namespace jit
{
namespace dev
{ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
namespace eth RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed
{ m_gasMeter(_gasMeter)
namespace jit {}
{
llvm::Function* Memory::getRequireFunc()
Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): {
RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed auto& func = m_require;
m_gasMeter(_gasMeter) if (!func)
{ {
llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word};
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
llvm::AttrBuilder attrBuilder; auto rt = func->arg_begin();
attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); rt->setName("rt");
m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); auto offset = rt->getNextNode();
offset->setName("offset");
m_require = createRequireFunc(_gasMeter); auto size = offset->getNextNode();
m_loadWord = createFunc(false, Type::Word, _gasMeter); size->setName("size");
m_storeWord = createFunc(true, Type::Word, _gasMeter);
m_storeByte = createFunc(true, Type::Byte, _gasMeter); llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
} auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule());
llvm::AttrBuilder attrBuilder;
llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
{ resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder));
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func);
auto rt = func->arg_begin(); auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
rt->setName("rt"); auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
auto offset = rt->getNextNode(); auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);
offset->setName("offset");
auto size = offset->getNextNode(); InsertPointGuard guard(m_builder); // Restores insert point at function exit
size->setName("size");
// BB "Pre": Ignore checks with size 0
auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); m_builder.SetInsertPoint(preBB);
auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0));
auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB);
auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);
// BB "Check"
InsertPointGuard guard(m_builder); // Restores insert point at function exit m_builder.SetInsertPoint(checkBB);
auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word);
// BB "Pre": Ignore checks with size 0 auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
m_builder.SetInsertPoint(preBB); auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); auto rtPtr = getRuntimeManager().getRuntimePtr();
auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
// BB "Check" auto currSize = m_builder.CreateLoad(sizePtr, "currSize");
m_builder.SetInsertPoint(checkBB); auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall");
auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?
auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); // BB "Resize"
auto rtPtr = getRuntimeManager().getRuntimePtr(); m_builder.SetInsertPoint(resizeBB);
auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); // Check gas first
auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
// BB "Resize" wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
m_builder.SetInsertPoint(resizeBB); sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
// Check gas first auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k
uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); m_gasMeter.countMemory(newWords);
auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); // Resize
auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); m_builder.CreateStore(sizeRequired, sizePtr);
wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData");
wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); m_builder.CreateStore(newData, dataPtr);
auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k m_builder.CreateBr(returnBB);
auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.countMemory(newWords); // BB "Return"
// Resize m_builder.SetInsertPoint(returnBB);
m_builder.CreateStore(sizeRequired, sizePtr); m_builder.CreateRetVoid();
auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); }
auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); return func;
m_builder.CreateStore(newData, dataPtr); }
m_builder.CreateBr(returnBB);
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
// BB "Return" {
m_builder.SetInsertPoint(returnBB); auto isWord = _valueType == Type::Word;
m_builder.CreateRetVoid();
return func; llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType};
} llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word};
auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
{ auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());
auto isWord = _valueType == Type::Word;
InsertPointGuard guard(m_builder); // Restores insert point at function exit
llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType};
llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; auto rt = func->arg_begin();
auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); rt->setName("rt");
auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); auto index = rt->getNextNode();
index->setName("index");
InsertPointGuard guard(m_builder); // Restores insert point at function exit
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); this->require(index, Constant::get(valueSize));
auto rt = func->arg_begin(); auto ptr = getBytePtr(index);
rt->setName("rt"); if (isWord)
auto index = rt->getNextNode(); ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
index->setName("index"); if (_isStore)
{
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; llvm::Value* value = index->getNextNode();
this->require(index, Constant::get(valueSize)); value->setName("value");
auto ptr = getBytePtr(index); if (isWord)
if (isWord) value = Endianness::toBE(m_builder, value);
ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); m_builder.CreateStore(value, ptr);
if (_isStore) m_builder.CreateRetVoid();
{ }
llvm::Value* value = index->getNextNode(); else
value->setName("value"); {
if (isWord) llvm::Value* ret = m_builder.CreateLoad(ptr);
value = Endianness::toBE(m_builder, value); ret = Endianness::toNative(m_builder, ret);
m_builder.CreateStore(value, ptr); m_builder.CreateRet(ret);
m_builder.CreateRetVoid(); }
}
else return func;
{ }
llvm::Value* ret = m_builder.CreateLoad(ptr);
ret = Endianness::toNative(m_builder, ret); llvm::Function* Memory::getLoadWordFunc()
m_builder.CreateRet(ret); {
} auto& func = m_loadWord;
if (!func)
return func; func = createFunc(false, Type::Word, m_gasMeter);
} return func;
}
llvm::Value* Memory::loadWord(llvm::Value* _addr) llvm::Function* Memory::getStoreWordFunc()
{ {
return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); auto& func = m_storeWord;
} if (!func)
func = createFunc(true, Type::Word, m_gasMeter);
void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) return func;
{ }
createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word});
} llvm::Function* Memory::getStoreByteFunc()
{
void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) auto& func = m_storeByte;
{ if (!func)
auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); func = createFunc(true, Type::Byte, m_gasMeter);
createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); return func;
} }
llvm::Value* Memory::getData()
{ llvm::Value* Memory::loadWord(llvm::Value* _addr)
auto rtPtr = getRuntimeManager().getRuntimePtr(); {
auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr});
return m_builder.CreateLoad(dataPtr, "data"); }
}
void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
llvm::Value* Memory::getSize() {
{ createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word});
auto rtPtr = getRuntimeManager().getRuntimePtr(); }
auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
return m_builder.CreateLoad(sizePtr, "size"); void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
} {
auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
llvm::Value* Memory::getBytePtr(llvm::Value* _index) createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte});
{ }
auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64
return m_builder.CreateGEP(getData(), idx, "ptr"); llvm::Value* Memory::getData()
} {
auto rtPtr = getRuntimeManager().getRuntimePtr();
void Memory::require(llvm::Value* _offset, llvm::Value* _size) auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
{ return m_builder.CreateLoad(dataPtr, "data");
createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); }
}
llvm::Value* Memory::getSize()
void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, {
llvm::Value* _destMemIdx, llvm::Value* _reqBytes) auto rtPtr = getRuntimeManager().getRuntimePtr();
{ auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
require(_destMemIdx, _reqBytes); return m_builder.CreateLoad(sizePtr, "size");
}
// Additional copy cost
// TODO: This round ups to 32 happens in many places llvm::Value* Memory::getBytePtr(llvm::Value* _index)
auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); {
m_gasMeter.countCopy(copyWords); auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64
return m_builder.CreateGEP(getData(), idx, "ptr");
// Algorithm: }
// isOutsideData = idx256 >= size256
// idx64 = trunc idx256 void Memory::require(llvm::Value* _offset, llvm::Value* _size)
// size64 = trunc size256 {
// dataLeftSize = size64 - idx64 // safe if not isOutsideData if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(_size))
// reqBytes64 = trunc _reqBytes // require() handles large values {
// bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min if (!constant->getValue())
// bytesToCopy = select(isOutsideData, 0, bytesToCopy0) return;
}
auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size});
auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); }
auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision);
auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); {
auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); require(_destMemIdx, _reqBytes);
auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants
auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); // Additional copy cost
// TODO: This round ups to 32 happens in many places
auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas);
auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32));
auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); m_gasMeter.countCopy(copyWords);
m_builder.CreateMemCpy(dst, src, bytesToCopy, 0);
} // Algorithm:
// isOutsideData = idx256 >= size256
} // idx64 = trunc idx256
} // size64 = trunc size256
} // dataLeftSize = size64 - idx64 // safe if not isOutsideData
// reqBytes64 = trunc _reqBytes // require() handles large values
// bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min
extern "C" // bytesToCopy = select(isOutsideData, 0, bytesToCopy0)
{
using namespace dev::eth::jit; auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize);
auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size);
EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size);
{ auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64);
auto size = _size->a; // Trunc to 64-bit auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize);
auto& memory = _rt->getMemory(); auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes);
memory.resize(size); auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner);
return memory.data();
} auto src = m_builder.CreateGEP(_srcPtr, idx64, "src");
} auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64
auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst");
m_builder.CreateMemCpy(dst, src, bytesToCopy, 0);
}
}
}
}
extern "C"
{
using namespace dev::eth::jit;
EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR
{
auto size = _size->a; // Trunc to 64-bit
auto& memory = _rt->getMemory();
memory.resize(size);
return memory.data();
}
}

15
evmjit/libevmjit/Memory.h

@ -31,13 +31,16 @@ private:
GasMeter& m_gasMeter; GasMeter& m_gasMeter;
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter);
llvm::Function* createRequireFunc(GasMeter& _gasMeter);
llvm::Function* m_resize; llvm::Function* getRequireFunc();
llvm::Function* m_require; llvm::Function* getLoadWordFunc();
llvm::Function* m_loadWord; llvm::Function* getStoreWordFunc();
llvm::Function* m_storeWord; llvm::Function* getStoreByteFunc();
llvm::Function* m_storeByte;
llvm::Function* m_require = nullptr;
llvm::Function* m_loadWord = nullptr;
llvm::Function* m_storeWord = nullptr;
llvm::Function* m_storeByte = nullptr;
}; };
} }

8
evmjit/libevmjit/Runtime.cpp

@ -1,9 +1,6 @@
#include "Runtime.h" #include "Runtime.h"
#include <llvm/IR/GlobalVariable.h> #include <cassert>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>
namespace dev namespace dev
{ {
@ -14,8 +11,7 @@ namespace jit
Runtime::Runtime(RuntimeData* _data, Env* _env) : Runtime::Runtime(RuntimeData* _data, Env* _env) :
m_data(*_data), m_data(*_data),
m_env(*_env), m_env(*_env)
m_currJmpBuf(m_jmpBuf)
{} {}
bytes_ref Runtime::getReturnData() const bytes_ref Runtime::getReturnData() const

86
evmjit/libevmjit/Runtime.h

@ -1,46 +1,40 @@
#pragma once
#pragma once
#include "RuntimeData.h"
#include <csetjmp>
#include "RuntimeData.h" namespace dev
{
namespace dev namespace eth
{ {
namespace eth namespace jit
{ {
namespace jit
{ using StackImpl = std::vector<i256>;
using MemoryImpl = bytes;
using StackImpl = std::vector<i256>;
using MemoryImpl = bytes; class Runtime
using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); {
public:
class Runtime Runtime(RuntimeData* _data, Env* _env);
{
public: Runtime(const Runtime&) = delete;
Runtime(RuntimeData* _data, Env* _env); Runtime& operator=(const Runtime&) = delete;
Runtime(const Runtime&) = delete; StackImpl& getStack() { return m_stack; }
Runtime& operator=(const Runtime&) = delete; MemoryImpl& getMemory() { return m_memory; }
StackImpl& getStack() { return m_stack; } bytes_ref getReturnData() const;
MemoryImpl& getMemory() { return m_memory; }
Env* getEnvPtr() { return &m_env; } private:
RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract.
bytes_ref getReturnData() const; Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract.
jmp_buf_ref getJmpBuf() { return m_jmpBuf; } void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract.
byte* m_memoryData = nullptr;
private: i256 m_memorySize;
RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. StackImpl m_stack;
Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. MemoryImpl m_memory;
jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. };
byte* m_memoryData = nullptr;
i256 m_memorySize; }
std::jmp_buf m_jmpBuf; }
StackImpl m_stack; }
MemoryImpl m_memory;
};
}
}
}

4
evmjit/libevmjit/RuntimeData.h

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "Utils.h" #include "Common.h"
namespace dev namespace dev
{ {
@ -50,6 +49,7 @@ struct RuntimeData
int64_t timestamp = 0; int64_t timestamp = 0;
byte const* code = nullptr; byte const* code = nullptr;
uint64_t codeSize = 0; uint64_t codeSize = 0;
i256 codeHash;
}; };
/// VM Environment (ExtVM) opaque type /// VM Environment (ExtVM) opaque type

56
evmjit/libevmjit/RuntimeManager.cpp

@ -1,12 +1,8 @@
#include "RuntimeManager.h" #include "RuntimeManager.h"
#include <llvm/IR/GlobalVariable.h> #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Function.h> #include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/IntrinsicInst.h> #include "preprocessor/llvm_includes_end.h"
#include "RuntimeData.h"
#include "Instruction.h"
namespace dev namespace dev
{ {
@ -87,9 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index)
} }
} }
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd):
CompilerHelper(_builder),
m_jmpBuf(_jmpBuf),
m_codeBegin(_codeBegin),
m_codeEnd(_codeEnd)
{ {
m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
// save jmpBuf to be used in helper functions
auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2);
m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt");
// Unpack data // Unpack data
auto rtPtr = getRuntimePtr(); auto rtPtr = getRuntimePtr();
@ -161,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress)
set(RuntimeData::SuicideDestAddress, _balanceAddress); set(RuntimeData::SuicideDestAddress, _balanceAddress);
} }
void RuntimeManager::raiseException(ReturnCode _returnCode) void RuntimeManager::abort(llvm::Value* _jmpBuf)
{ {
m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
createCall(longjmp, {_jmpBuf});
} }
llvm::Value* RuntimeManager::get(Instruction _inst) llvm::Value* RuntimeManager::get(Instruction _inst)
@ -191,14 +196,14 @@ llvm::Value* RuntimeManager::getCallData()
llvm::Value* RuntimeManager::getCode() llvm::Value* RuntimeManager::getCode()
{ {
return get(RuntimeData::Code); // OPT Check what is faster
//return get(RuntimeData::Code);
return m_builder.CreateGlobalStringPtr({reinterpret_cast<char const*>(m_codeBegin), static_cast<size_t>(m_codeEnd - m_codeBegin)}, "code");
} }
llvm::Value* RuntimeManager::getCodeSize() llvm::Value* RuntimeManager::getCodeSize()
{ {
auto value = get(RuntimeData::CodeSize); return Constant::get(m_codeEnd - m_codeBegin);
assert(value->getType() == Type::Size);
return getBuilder().CreateZExt(value, Type::Word);
} }
llvm::Value* RuntimeManager::getCallDataSize() llvm::Value* RuntimeManager::getCallDataSize()
@ -208,23 +213,28 @@ llvm::Value* RuntimeManager::getCallDataSize()
return getBuilder().CreateZExt(value, Type::Word); return getBuilder().CreateZExt(value, Type::Word);
} }
llvm::Value* RuntimeManager::getJmpBuf() llvm::Value* RuntimeManager::getJmpBufExt()
{ {
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2);
return getBuilder().CreateLoad(ptr, "jmpbuf"); return getBuilder().CreateLoad(ptr, "jmpBufExt");
} }
llvm::Value* RuntimeManager::getGas() llvm::Value* RuntimeManager::getGas()
{ {
auto value = get(RuntimeData::Gas); auto gas = get(RuntimeData::Gas);
assert(value->getType() == Type::Size); assert(gas->getType() == Type::Gas);
return getBuilder().CreateZExt(value, Type::Word); return gas;
}
llvm::Value* RuntimeManager::getGasPtr()
{
return getPtr(RuntimeData::Gas);
} }
void RuntimeManager::setGas(llvm::Value* _gas) void RuntimeManager::setGas(llvm::Value* _gas)
{ {
auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); assert(_gas->getType() == Type::Gas);
set(RuntimeData::Gas, newGas); set(RuntimeData::Gas, _gas);
} }
} }

17
evmjit/libevmjit/RuntimeManager.h

@ -15,25 +15,28 @@ namespace jit
class RuntimeManager: public CompilerHelper class RuntimeManager: public CompilerHelper
{ {
public: public:
RuntimeManager(llvm::IRBuilder<>& _builder); RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd);
llvm::Value* getRuntimePtr(); llvm::Value* getRuntimePtr();
llvm::Value* getDataPtr(); llvm::Value* getDataPtr();
llvm::Value* getEnvPtr(); // TODO: Can we make it const? llvm::Value* getEnvPtr();
llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(RuntimeData::Index _index);
llvm::Value* get(Instruction _inst); llvm::Value* get(Instruction _inst);
llvm::Value* getGas(); // TODO: Remove llvm::Value* getGas();
llvm::Value* getGasPtr();
llvm::Value* getCallData(); llvm::Value* getCallData();
llvm::Value* getCode(); llvm::Value* getCode();
llvm::Value* getCodeSize(); llvm::Value* getCodeSize();
llvm::Value* getCallDataSize(); llvm::Value* getCallDataSize();
llvm::Value* getJmpBuf() { return m_jmpBuf; }
void setGas(llvm::Value* _gas); void setGas(llvm::Value* _gas);
void registerReturnData(llvm::Value* _index, llvm::Value* _size); void registerReturnData(llvm::Value* _index, llvm::Value* _size);
void registerSuicide(llvm::Value* _balanceAddress); void registerSuicide(llvm::Value* _balanceAddress);
void raiseException(ReturnCode _returnCode); void abort(llvm::Value* _jmpBuf);
void abort() { abort(getJmpBufExt()); }
static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeType();
static llvm::StructType* getRuntimeDataType(); static llvm::StructType* getRuntimeDataType();
@ -41,11 +44,15 @@ public:
private: private:
llvm::Value* getPtr(RuntimeData::Index _index); llvm::Value* getPtr(RuntimeData::Index _index);
void set(RuntimeData::Index _index, llvm::Value* _value); void set(RuntimeData::Index _index, llvm::Value* _value);
llvm::Value* getJmpBuf(); llvm::Value* getJmpBufExt();
llvm::Function* m_longjmp = nullptr; llvm::Function* m_longjmp = nullptr;
llvm::Value* const m_jmpBuf;
llvm::Value* m_dataPtr = nullptr; llvm::Value* m_dataPtr = nullptr;
llvm::Value* m_envPtr = nullptr; llvm::Value* m_envPtr = nullptr;
code_iterator m_codeBegin = {};
code_iterator m_codeEnd = {};
}; };
} }

111
evmjit/libevmjit/Stack.cpp

@ -1,10 +1,11 @@
#include "Stack.h" #include "Stack.h"
#include "RuntimeManager.h"
#include "Runtime.h"
#include "Type.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Function.h> #include <llvm/IR/Function.h>
#include <llvm/IR/TypeBuilder.h> #include "preprocessor/llvm_includes_end.h"
#include "RuntimeManager.h"
#include "Runtime.h"
namespace dev namespace dev
{ {
@ -27,18 +28,87 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager):
llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr};
m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module);
llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size};
m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module);
llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr};
m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module);
m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module);
} }
llvm::Function* Stack::getPopFunc()
{
auto& func = m_pop;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule());
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size};
auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule());
auto rt = &func->getArgumentList().front();
rt->setName("rt");
auto index = rt->getNextNode();
index->setName("index");
auto jmpBuf = index->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func);
auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func);
m_builder.SetInsertPoint(entryBB);
auto ok = createCall(extPopFunc, {rt, index});
m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight
m_builder.SetInsertPoint(underflowBB);
m_runtimeManager.abort(jmpBuf);
m_builder.CreateUnreachable();
m_builder.SetInsertPoint(returnBB);
m_builder.CreateRetVoid();
}
return func;
}
llvm::Function* Stack::getGetFunc()
{
auto& func = m_get;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule());
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size};
auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule());
auto rt = &func->getArgumentList().front();
rt->setName("rt");
auto index = rt->getNextNode();
index->setName("index");
auto jmpBuf = index->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func);
auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func);
m_builder.SetInsertPoint(entryBB);
auto valuePtr = createCall(extGetFunc, {rt, index});
auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr));
m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight
m_builder.SetInsertPoint(underflowBB);
m_runtimeManager.abort(jmpBuf);
m_builder.CreateUnreachable();
m_builder.SetInsertPoint(returnBB);
m_builder.CreateRet(valuePtr);
}
return func;
}
llvm::Value* Stack::get(size_t _index) llvm::Value* Stack::get(size_t _index)
{ {
m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()});
return m_builder.CreateLoad(m_arg); return m_builder.CreateLoad(valuePtr);
} }
void Stack::set(size_t _index, llvm::Value* _value) void Stack::set(size_t _index, llvm::Value* _value)
@ -49,7 +119,7 @@ void Stack::set(size_t _index, llvm::Value* _value)
void Stack::pop(size_t _count) void Stack::pop(size_t _count)
{ {
m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()});
} }
void Stack::push(llvm::Value* _value) void Stack::push(llvm::Value* _value)
@ -69,13 +139,14 @@ extern "C"
{ {
using namespace dev::eth::jit; using namespace dev::eth::jit;
EXPORT void stack_pop(Runtime* _rt, uint64_t _count) EXPORT bool stack_pop(Runtime* _rt, uint64_t _count)
{ {
auto& stack = _rt->getStack(); auto& stack = _rt->getStack();
if (stack.size() < _count) if (stack.size() < _count)
longjmp(_rt->getJmpBuf(), static_cast<int>(ReturnCode::StackTooSmall)); return false;
stack.erase(stack.end() - _count, stack.end()); stack.erase(stack.end() - _count, stack.end());
return true;
} }
EXPORT void stack_push(Runtime* _rt, i256 const* _word) EXPORT void stack_push(Runtime* _rt, i256 const* _word)
@ -87,22 +158,18 @@ extern "C"
Stack::maxStackSize = stack.size(); Stack::maxStackSize = stack.size();
} }
EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) EXPORT i256* stack_get(Runtime* _rt, uint64_t _index)
{ {
auto& stack = _rt->getStack(); auto& stack = _rt->getStack();
// TODO: encode _index and stack size in the return code return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr;
if (stack.size() <= _index)
longjmp(_rt->getJmpBuf(), static_cast<int>(ReturnCode::StackTooSmall));
*o_ret = *(stack.rbegin() + _index);
} }
EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word)
{ {
auto& stack = _rt->getStack(); auto& stack = _rt->getStack();
// TODO: encode _index and stack size in the return code assert(_index < stack.size());
if (stack.size() <= _index) if (_index >= stack.size())
longjmp(_rt->getJmpBuf(), static_cast<int>(ReturnCode::StackTooSmall)); return;
*(stack.rbegin() + _index) = *_word; *(stack.rbegin() + _index) = *_word;
} }

9
evmjit/libevmjit/Stack.h

@ -2,8 +2,6 @@
#include "CompilerHelper.h" #include "CompilerHelper.h"
#include <llvm/IR/Module.h>
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -25,11 +23,14 @@ public:
static size_t maxStackSize; static size_t maxStackSize;
private: private:
llvm::Function* getPopFunc();
llvm::Function* getGetFunc();
RuntimeManager& m_runtimeManager; RuntimeManager& m_runtimeManager;
llvm::Function* m_pop = nullptr;
llvm::Function* m_push; llvm::Function* m_push;
llvm::Function* m_pop; llvm::Function* m_get = nullptr;
llvm::Function* m_get;
llvm::Function* m_set; llvm::Function* m_set;
llvm::Value* m_arg; llvm::Value* m_arg;

11
evmjit/libevmjit/Type.cpp

@ -1,8 +1,4 @@
#include "Type.h" #include "Type.h"
#include <llvm/IR/DerivedTypes.h>
#include "RuntimeManager.h" #include "RuntimeManager.h"
namespace dev namespace dev
@ -17,6 +13,8 @@ llvm::PointerType* Type::WordPtr;
llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::lowPrecision;
llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Bool;
llvm::IntegerType* Type::Size; llvm::IntegerType* Type::Size;
llvm::IntegerType* Type::Gas;
llvm::PointerType* Type::GasPtr;
llvm::IntegerType* Type::Byte; llvm::IntegerType* Type::Byte;
llvm::PointerType* Type::BytePtr; llvm::PointerType* Type::BytePtr;
llvm::Type* Type::Void; llvm::Type* Type::Void;
@ -24,6 +22,7 @@ llvm::IntegerType* Type::MainReturn;
llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::EnvPtr;
llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimeDataPtr;
llvm::PointerType* Type::RuntimePtr; llvm::PointerType* Type::RuntimePtr;
llvm::ConstantInt* Constant::gasMax;
void Type::init(llvm::LLVMContext& _context) void Type::init(llvm::LLVMContext& _context)
{ {
@ -35,6 +34,8 @@ void Type::init(llvm::LLVMContext& _context)
// TODO: Size should be architecture-dependent // TODO: Size should be architecture-dependent
Bool = llvm::Type::getInt1Ty(_context); Bool = llvm::Type::getInt1Ty(_context);
Size = llvm::Type::getInt64Ty(_context); Size = llvm::Type::getInt64Ty(_context);
Gas = Size;
GasPtr = Gas->getPointerTo();
Byte = llvm::Type::getInt8Ty(_context); Byte = llvm::Type::getInt8Ty(_context);
BytePtr = Byte->getPointerTo(); BytePtr = Byte->getPointerTo();
Void = llvm::Type::getVoidTy(_context); Void = llvm::Type::getVoidTy(_context);
@ -43,6 +44,8 @@ void Type::init(llvm::LLVMContext& _context)
EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo();
RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo();
RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo();
Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits<int64_t>::max());
} }
} }

10
evmjit/libevmjit/Type.h

@ -1,8 +1,10 @@
#pragma once #pragma once
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Type.h> #include <llvm/IR/Type.h>
#include <llvm/IR/Constants.h> #include <llvm/IR/Constants.h>
#include "preprocessor/llvm_includes_end.h"
#include "Common.h" #include "Common.h"
namespace dev namespace dev
@ -23,6 +25,8 @@ struct Type
static llvm::IntegerType* Bool; static llvm::IntegerType* Bool;
static llvm::IntegerType* Size; static llvm::IntegerType* Size;
static llvm::IntegerType* Gas;
static llvm::PointerType* GasPtr;
static llvm::IntegerType* Byte; static llvm::IntegerType* Byte;
static llvm::PointerType* BytePtr; static llvm::PointerType* BytePtr;
@ -41,6 +45,8 @@ struct Type
struct Constant struct Constant
{ {
static llvm::ConstantInt* gasMax;
/// Returns word-size constant /// Returns word-size constant
static llvm::ConstantInt* get(int64_t _n); static llvm::ConstantInt* get(int64_t _n);
static llvm::ConstantInt* get(llvm::APInt const& _n); static llvm::ConstantInt* get(llvm::APInt const& _n);

1
evmjit/libevmjit/Utils.cpp

@ -1,4 +1,3 @@
#include "Utils.h" #include "Utils.h"
namespace dev namespace dev

3
evmjit/libevmjit/Utils.h

@ -16,6 +16,9 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } };
//#define clog(CHANNEL) std::cerr //#define clog(CHANNEL) std::cerr
#define clog(CHANNEL) std::ostream(nullptr) #define clog(CHANNEL) std::ostream(nullptr)
// The same as assert, but expression is always evaluated and result returned
#define CHECK(expr) (assert(expr), expr)
} }
} }
} }

11
evmjit/libevmjit/interface.cpp

@ -12,6 +12,7 @@ using namespace dev::eth::jit;
EXPORT void* evmjit_create() noexcept EXPORT void* evmjit_create() noexcept
{ {
// TODO: Make sure ExecutionEngine constructor does not throw
return new(std::nothrow) ExecutionEngine; return new(std::nothrow) ExecutionEngine;
} }
@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept
EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept
{ {
if (!_engine || !_data)
return static_cast<int>(ReturnCode::UnexpectedException);
try try
{ {
auto codePtr = _data->code; auto returnCode = _engine->run(_data, _env);
auto codeSize = _data->codeSize;
bytes bytecode;
bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize);
auto returnCode = _engine->run(bytecode, _data, _env);
return static_cast<int>(returnCode); return static_cast<int>(returnCode);
} }
catch(...) catch(...)

7
evmjit/libevmjit/preprocessor/llvm_includes_end.h

@ -0,0 +1,7 @@
#if defined(_MSC_VER)
#pragma warning(pop)
#elif defined(__clang__)
#pragma clang diagnostic pop
#else
#pragma GCC diagnostic pop
#endif

12
evmjit/libevmjit/preprocessor/llvm_includes_start.h

@ -0,0 +1,12 @@
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4267 4244 4800)
#elif defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wconversion"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wconversion"
#endif

2
exp/CMakeLists.txt

@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE exp) set(EXECUTABLE exp)

6
exp/main.cpp

@ -26,6 +26,7 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include <libethereum/DownloadMan.h> #include <libethereum/DownloadMan.h>
@ -33,11 +34,13 @@
#include <liblll/All.h> #include <liblll/All.h>
#include <libwhisper/WhisperPeer.h> #include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h> #include <libwhisper/WhisperHost.h>
#include <test/JsonSpiritHeaders.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using namespace dev::p2p; using namespace dev::p2p;
using namespace dev::shh; using namespace dev::shh;
namespace js = json_spirit;
#if 0 #if 0
int main() int main()
@ -98,8 +101,7 @@ int main()
#else #else
int main() int main()
{ {
cnote << KeyPair(Secret("0000000000000000000000000000000000000000000000000000000000000000")).address(); return 0;
cnote << KeyPair(Secret("1111111111111111111111111111111111111111111111111111111111111111")).address();
} }
#endif #endif

2
extdep/CMakeLists.txt

@ -7,7 +7,7 @@ include(eth_download.cmake)
# all dependencies will be installed into this directory, separated by platform # all dependencies will be installed into this directory, separated by platform
string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name)
set(ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/install/${_system_name}") set(ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/install/${_system_name}")
set(ETH_DEPENDENCY_SERVER "http://build.ethdev.com/builds/${_system_name}-precompiled") set(ETH_DEPENDENCY_SERVER "https://build.ethdev.com/builds/${_system_name}-precompiled")
file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/lib) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/lib)
file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/include) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/include)
file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/bin) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/bin)

2
libdevcore/CMakeLists.txt

@ -12,8 +12,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE devcore) set(EXECUTABLE devcore)

2
libdevcore/Common.cpp

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

2
libdevcore/FixedHash.h

@ -80,7 +80,7 @@ public:
operator Arith() const { return fromBigEndian<Arith>(m_data); } operator Arith() const { return fromBigEndian<Arith>(m_data); }
/// @returns true iff this is the empty hash. /// @returns true iff this is the empty hash.
operator bool() const { return ((Arith)*this) != 0; } explicit operator bool() const { return ((Arith)*this) != 0; }
// The obvious comparison operators. // The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; } bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }

2
libdevcore/RLP.cpp

@ -177,7 +177,7 @@ void RLPStream::noteAppended(unsigned _itemCount)
while (m_listStack.size()) while (m_listStack.size())
{ {
if (m_listStack.back().first < _itemCount) if (m_listStack.back().first < _itemCount)
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large")); BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount));
m_listStack.back().first -= _itemCount; m_listStack.back().first -= _itemCount;
if (m_listStack.back().first) if (m_listStack.back().first)
break; break;

4
libdevcore/RLP.h

@ -242,7 +242,9 @@ public:
AllowNonCanon = 1, AllowNonCanon = 1,
ThrowOnFail = 4, ThrowOnFail = 4,
FailIfTooBig = 8, FailIfTooBig = 8,
FailIfTooSmall = 16,
Strict = ThrowOnFail | FailIfTooBig, Strict = ThrowOnFail | FailIfTooBig,
VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall,
LaisezFaire = AllowNonCanon LaisezFaire = AllowNonCanon
}; };
@ -269,7 +271,7 @@ public:
template <class _N> _N toHash(int _flags = Strict) const template <class _N> _N toHash(int _flags = Strict) const
{ {
if (!isData() || (length() > _N::size && (_flags & FailIfTooBig))) if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall)))
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast()); BOOST_THROW_EXCEPTION(BadCast());
else else

2
libdevcore/Worker.h

@ -64,7 +64,7 @@ protected:
private: private:
std::string m_name; std::string m_name;
unsigned m_idleWaitMs; unsigned m_idleWaitMs = 0;
mutable Mutex x_work; ///< Lock for the network existance. mutable Mutex x_work; ///< Lock for the network existance.
std::unique_ptr<std::thread> m_work; ///< The network thread. std::unique_ptr<std::thread> m_work; ///< The network thread.

7
libdevcore/vector_ref.h

@ -19,7 +19,7 @@ public:
vector_ref(): m_data(nullptr), m_count(0) {} vector_ref(): m_data(nullptr), m_count(0) {}
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type _data): m_data((_T*)_data->data()), m_count(_data->size() / sizeof(_T)) {} vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {} vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {}
#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ #ifdef STORAGE_LEVELDB_INCLUDE_DB_H_
@ -29,9 +29,10 @@ public:
bool contentsEqual(std::vector<mutable_value_type> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); } bool contentsEqual(std::vector<mutable_value_type> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); }
std::vector<mutable_value_type> toVector() const { return std::vector<mutable_value_type>(m_data, m_data + m_count); } std::vector<mutable_value_type> toVector() const { return std::vector<mutable_value_type>(m_data, m_data + m_count); }
std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>((unsigned char const*)m_data, (unsigned char const*)m_data + m_count * sizeof(_T)); } std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), reinterpret_cast<unsigned char const*>(m_data) + m_count * sizeof(_T)); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); }
template <class _T2> operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); } template <class _T2> explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); }
operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); }
_T* data() const { return m_data; } _T* data() const { return m_data; }
size_t count() const { return m_count; } size_t count() const { return m_count; }

2
libdevcrypto/CMakeLists.txt

@ -9,10 +9,10 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE devcrypto) set(EXECUTABLE devcrypto)

2
libdevcrypto/Common.cpp

@ -44,6 +44,8 @@ bool dev::SignatureStruct::isValid() const
return true; return true;
} }
Address dev::ZeroAddress = Address();
Public dev::toPublic(Secret const& _secret) Public dev::toPublic(Secret const& _secret)
{ {
Public p; Public p;

3
libdevcrypto/Common.h

@ -62,6 +62,9 @@ struct SignatureStruct
/// @NOTE This is not endian-specific; it's just a bunch of bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Address = h160; using Address = h160;
/// The zero address.
extern Address ZeroAddress;
/// A vector of Ethereum addresses. /// A vector of Ethereum addresses.
using Addresses = h160s; using Addresses = h160s;

2
libdevcrypto/CryptoPP.cpp

@ -134,7 +134,7 @@ bool Secp256k1::verify(Signature const& _signature, bytesConstRef _message)
bool Secp256k1::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) bool Secp256k1::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed)
{ {
// todo: verify w/o recovery (if faster) // todo: verify w/o recovery (if faster)
return _p == _hashed ? recover(_sig, _message) : recover(_sig, sha3(_message).ref()); return (bool)_p == _hashed ? (bool)recover(_sig, _message) : (bool)recover(_sig, sha3(_message).ref());
} }
Public Secp256k1::recover(Signature _signature, bytesConstRef _message) Public Secp256k1::recover(Signature _signature, bytesConstRef _message)

6
libdevcrypto/TrieDB.h

@ -161,7 +161,7 @@ public:
std::string at(bytesConstRef _key) const; std::string at(bytesConstRef _key) const;
void insert(bytesConstRef _key, bytesConstRef _value); void insert(bytesConstRef _key, bytesConstRef _value);
void remove(bytesConstRef _key); void remove(bytesConstRef _key);
void contains(bytesConstRef _key) { return !at(_key).empty(); } bool contains(bytesConstRef _key) { return !at(_key).empty(); }
class iterator class iterator
{ {
@ -809,7 +809,10 @@ template <class DB> bytes GenericTrieDB<DB>::deleteAt(RLP const& _orig, NibbleSl
// exactly our node - return null. // exactly our node - return null.
if (k == _k && isLeaf(_orig)) if (k == _k && isLeaf(_orig))
{
killNode(_orig);
return RLPNull; return RLPNull;
}
// partial key is our key - move down. // partial key is our key - move down.
if (_k.contains(k)) if (_k.contains(k))
@ -917,7 +920,6 @@ template <class DB> bytes GenericTrieDB<DB>::place(RLP const& _orig, NibbleSlice
tdebug << "place " << _orig << _k; tdebug << "place " << _orig << _k;
#endif #endif
killNode(_orig); killNode(_orig);
if (_orig.isEmpty()) if (_orig.isEmpty())
return (RLPStream(2) << hexPrefixEncode(_k, true) << _s).out(); return (RLPStream(2) << hexPrefixEncode(_k, true) << _s).out();

6
libethcore/BlockInfo.cpp

@ -134,7 +134,7 @@ void BlockInfo::populate(bytesConstRef _block, bool _checkNonce)
RLP header = root[0]; RLP header = root[0];
if (!header.isList()) if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data())); BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data()) << errinfo_comment("block header needs to be a list"));
populateFromHeader(header, _checkNonce); populateFromHeader(header, _checkNonce);
if (!root[1].isList()) if (!root[1].isList())
@ -157,8 +157,8 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
{ {
bytes k = rlp(i); bytes k = rlp(i);
t.insert(&k, tr.data()); t.insert(&k, tr.data());
u256 gp = tr[1].toInt<u256>(); u256 gasprice = tr[1].toInt<u256>();
mgp = min(mgp, gp); mgp = min(mgp, gasprice); // the minimum gas price is not used for anything //TODO delete?
++i; ++i;
} }
if (transactionsRoot != t.root()) if (transactionsRoot != t.root())

2
libethcore/CMakeLists.txt

@ -9,8 +9,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE ethcore) set(EXECUTABLE ethcore)

2
libethcore/CommonEth.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth namespace eth
{ {
const unsigned c_protocolVersion = 53; const unsigned c_protocolVersion = 54;
const unsigned c_databaseVersion = 5; const unsigned c_databaseVersion = 5;
vector<pair<u256, string>> const& units() vector<pair<u256, string>> const& units()

1
libethcore/Exceptions.h

@ -51,6 +51,7 @@ struct UncleTooOld: virtual dev::Exception {};
class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; }; class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; };
struct DuplicateUncleNonce: virtual dev::Exception {}; struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {}; struct InvalidStateRoot: virtual dev::Exception {};
struct InvalidGasUsed: virtual dev::Exception {};
class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; }; class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; };
struct InvalidTransaction: virtual dev::Exception {}; struct InvalidTransaction: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {};

2
libethcore/ProofOfWork.h

@ -82,7 +82,7 @@ template <class Evaluator>
std::pair<MineInfo, h256> ProofOfWorkEngine<Evaluator>::mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo) std::pair<MineInfo, h256> ProofOfWorkEngine<Evaluator>::mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
{ {
std::pair<MineInfo, h256> ret; std::pair<MineInfo, h256> ret;
static std::mt19937_64 s_eng((time(0) + (unsigned)m_last)); static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data())));
u256 s = (m_last = h256::random(s_eng)); u256 s = (m_last = h256::random(s_eng));
bigint d = (bigint(1) << 256) / _difficulty; bigint d = (bigint(1) << 256) / _difficulty;

3
libethereum/BlockChain.cpp

@ -22,6 +22,7 @@
#include "BlockChain.h" #include "BlockChain.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <test/JsonSpiritHeaders.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
@ -29,11 +30,13 @@
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include "GenesisInfo.h"
#include "State.h" #include "State.h"
#include "Defaults.h" #include "Defaults.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
namespace js = json_spirit;
#define ETH_CATCH 1 #define ETH_CATCH 1

3
libethereum/BlockQueue.cpp

@ -59,7 +59,6 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
catch (Exception const& _e) catch (Exception const& _e)
{ {
cwarn << "Ignoring malformed block: " << diagnostic_information(_e); cwarn << "Ignoring malformed block: " << diagnostic_information(_e);
return false;
return ImportResult::Malformed; return ImportResult::Malformed;
} }
#endif #endif
@ -128,7 +127,7 @@ void BlockQueue::drain(std::vector<bytes>& o_out)
void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) void BlockQueue::noteReadyWithoutWriteGuard(h256 _good)
{ {
list<h256> goodQueue(1, _good); list<h256> goodQueue(1, _good);
while (goodQueue.size()) while (!goodQueue.empty())
{ {
auto r = m_unknown.equal_range(goodQueue.front()); auto r = m_unknown.equal_range(goodQueue.front());
goodQueue.pop_front(); goodQueue.pop_front();

2
libethereum/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE ethereum) set(EXECUTABLE ethereum)

34
libethereum/CanonBlockChain.cpp

@ -21,6 +21,7 @@
#include "CanonBlockChain.h" #include "CanonBlockChain.h"
#include <test/JsonSpiritHeaders.h>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
@ -29,13 +30,13 @@
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libsolidity/CompilerStack.h> #include "GenesisInfo.h"
#include "State.h" #include "State.h"
#include "Defaults.h" #include "Defaults.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using namespace dev::solidity; namespace js = json_spirit;
#define ETH_CATCH 1 #define ETH_CATCH 1
@ -45,20 +46,25 @@ std::map<Address, Account> const& dev::eth::genesisState()
if (s_ret.empty()) if (s_ret.empty())
{ {
// Initialise.
for (auto i: vector<string>({
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
"e6716f9544a56c530d868e4bfbacb172315bdead",
"b9c015918bdaba24b4ff057a92a3873d6eb201be",
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
"2ef47100e0787b915105fd5e3f4ff6752079d5cb",
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
"6c386a4b26f73c802f34673f7248bb118f97424a",
"e4157b34ea9615cfbde6b4fda419828124b70c78"
}))
s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation);
s_ret[Address(1)] = Account(0, Account::ContractConception); s_ret[Address(1)] = Account(0, Account::ContractConception);
s_ret[Address(2600)].setCode(fromHex("60e060020a60003504806301984892146100ba5780631c83171b146100cf578063449c2090146100e05780635d574e32146100fe5780635fd4b08a14610112578063618242da146101275780636be16bed1461013c5780636c4489b41461014d5780637d2e3ce914610180578063994d29cc146101935780639e71f357146101a8578063b8202c18146101bc578063c284bc2a146101d0578063e50f599a146101e1578063e5811b35146101f8578063ec7b92001461021657005b6100c5600435610652565b8060005260206000f35b6100da600435610446565b60006000f35b6100eb600435610426565b80600160a060020a031660005260206000f35b61010c600435602435610324565b60006000f35b61011d600435610375565b8060005260206000f35b610132600435610612565b8060005260206000f35b6101476004356105f2565b60006000f35b61015860043561037c565b84600160a060020a031660005283600160a060020a0316602052816040528060605260806000f35b61018d60043560006102d3565b60006000f35b61019e600435610632565b8060005260206000f35b6101b6600435602435610234565b60006000f35b6101ca600435602435610282565b60006000f35b6101db600435610513565b60006000f35b6101f2600435602435604435610495565b60006000f35b61020360043561048e565b80600160a060020a031660005260206000f35b610221600435610409565b80600160a060020a031660005260206000f35b33600160a060020a03166001600084815260200190815260200160002054600160a060020a0316146102655761027e565b8060016000848152602001908152602001600020819055505b5050565b33600160a060020a03166001600084815260200190815260200160002054600160a060020a0316146102b3576102cf565b8060016000848152602001908152602001600020600401819055505b5050565b33600160a060020a03166001600084815260200190815260200160002054600160a060020a03161461030457610320565b8060016000848152602001908152602001600020600201819055505b5050565b33600160a060020a03166001600084815260200190815260200160002054600160a060020a03161461035557610371565b8060016000848152602001908152602001600020600301819055505b5050565b6000919050565b60006000600060006000600160008781526020019081526020016000205494506001600087815260200190815260200160002060010154935060016000878152602001908152602001600020600201549250600160008781526020019081526020016000206003015491506001600087815260200190815260200160002060040154905091939590929450565b600060016000838152602001908152602001600020549050919050565b600060016000838152602001908152602001600020600101549050919050565b6001600082815260200190815260200160002054600160a060020a031660001461046f5761048b565b3360016000838152602001908152602001600020600101819055505b50565b6000919050565b33600160a060020a03166001600085815260200190815260200160002054600160a060020a0316146104c65761050e565b816001600085815260200190815260200160002060010181905550806104eb5761050d565b826000600084600160a060020a03168152602001908152602001600020819055505b5b505050565b33600160a060020a03166001600083815260200190815260200160002054600160a060020a031614610544576105ef565b80600060006001600085815260200190815260200160002060010154600160a060020a031681526020019081526020016000205414610582576105bb565b6000600060006001600085815260200190815260200160002060010154600160a060020a03168152602001908152602001600020819055505b6001600082815260200190815260200160002060008155600101600081556001016000815560010160008155600101600090555b50565b600060016000838152602001908152602001600020600201549050919050565b600060016000838152602001908152602001600020600301549050919050565b600060016000838152602001908152602001600020600401549050919050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056")); s_ret[Address(2600)].setCode(fromHex("60e060020a60003504806301984892146100ba5780631c83171b146100cf578063449c2090146100e05780635d574e32146100fe5780635fd4b08a14610112578063618242da146101275780636be16bed1461013c5780636c4489b41461014d5780637d2e3ce914610180578063994d29cc146101935780639e71f357146101a8578063b8202c18146101bc578063c284bc2a146101d0578063e50f599a146101e1578063e5811b35146101f8578063ec7b92001461021657005b6100c5600435610652565b8060005260206000f35b6100da600435610446565b60006000f35b6100eb600435610426565b80600160a060020a031660005260206000f35b61010c600435602435610324565b60006000f35b61011d600435610375565b8060005260206000f35b610132600435610612565b8060005260206000f35b6101476004356105f2565b60006000f35b61015860043561037c565b84600160a060020a031660005283600160a060020a0316602052816040528060605260806000f35b61018d60043560006102d3565b60006000f35b61019e600435610632565b8060005260206000f35b6101b6600435602435610234565b60006000f35b6101ca600435602435610282565b60006000f35b6101db600435610513565b60006000f35b6101f2600435602435604435610495565b60006000f35b61020360043561048e565b80600160a060020a031660005260206000f35b610221600435610409565b80600160a060020a031660005260206000f35b33600160a060020a03166001600084815260200190815260200160002054600160a060020a0316146102655761027e565b8060016000848152602001908152602001600020819055505b5050565b33600160a060020a03166001600084815260200190815260200160002054600160a060020a0316146102b3576102cf565b8060016000848152602001908152602001600020600401819055505b5050565b33600160a060020a03166001600084815260200190815260200160002054600160a060020a03161461030457610320565b8060016000848152602001908152602001600020600201819055505b5050565b33600160a060020a03166001600084815260200190815260200160002054600160a060020a03161461035557610371565b8060016000848152602001908152602001600020600301819055505b5050565b6000919050565b60006000600060006000600160008781526020019081526020016000205494506001600087815260200190815260200160002060010154935060016000878152602001908152602001600020600201549250600160008781526020019081526020016000206003015491506001600087815260200190815260200160002060040154905091939590929450565b600060016000838152602001908152602001600020549050919050565b600060016000838152602001908152602001600020600101549050919050565b6001600082815260200190815260200160002054600160a060020a031660001461046f5761048b565b3360016000838152602001908152602001600020600101819055505b50565b6000919050565b33600160a060020a03166001600085815260200190815260200160002054600160a060020a0316146104c65761050e565b816001600085815260200190815260200160002060010181905550806104eb5761050d565b826000600084600160a060020a03168152602001908152602001600020819055505b5b505050565b33600160a060020a03166001600083815260200190815260200160002054600160a060020a031614610544576105ef565b80600060006001600085815260200190815260200160002060010154600160a060020a031681526020019081526020016000205414610582576105bb565b6000600060006001600085815260200190815260200160002060010154600160a060020a03168152602001908152602001600020819055505b6001600082815260200190815260200160002060008155600101600081556001016000815560010160008155600101600090555b50565b600060016000838152602001908152602001600020600201549050919050565b600060016000838152602001908152602001600020600301549050919050565b600060016000838152602001908152602001600020600401549050919050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056"));
js::mValue val;
json_spirit::read_string(c_genesisInfo, val);
for (auto account: val.get_obj())
{
u256 balance;
if (account.second.get_obj().count("wei"))
balance = u256(account.second.get_obj()["wei"].get_str());
else
balance = u256(account.second.get_obj()["finney"].get_str()) * finney;
if (account.second.get_obj().count("code"))
{
s_ret[Address(fromHex(account.first))] = Account(balance, Account::ContractConception);
s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str()));
}
else
s_ret[Address(fromHex(account.first))] = Account(balance, Account::NormalCreation);
}
} }
return s_ret; return s_ret;
} }

14
libethereum/Client.cpp

@ -714,6 +714,20 @@ BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
return BlockInfo(); return BlockInfo();
} }
unsigned Client::transactionCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[1].itemCount();
}
unsigned Client::uncleCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[2].itemCount();
}
LocalisedLogEntries Client::logs(LogFilter const& _f) const LocalisedLogEntries Client::logs(LogFilter const& _f) const
{ {
LocalisedLogEntries ret; LocalisedLogEntries ret;

4
libethereum/Client.h

@ -127,7 +127,7 @@ template <class T> struct ABIDeserialiser {};
template <unsigned N> struct ABIDeserialiser<FixedHash<N>> { static FixedHash<N> deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash<N> ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; template <unsigned N> struct ABIDeserialiser<FixedHash<N>> { static FixedHash<N> deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash<N> ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } };
template <> struct ABIDeserialiser<u256> { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian<u256>(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser<u256> { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian<u256>(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } };
template <> struct ABIDeserialiser<u160> { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian<u160>(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser<u160> { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian<u160>(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } };
template <> struct ABIDeserialiser<string32> { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref<char>(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser<string32> { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(bytesRef((byte*)ret.data(), 32)); io_t = io_t.cropped(32); return ret; } };
template <class T> T abiOut(bytes const& _data) template <class T> T abiOut(bytes const& _data)
{ {
@ -229,6 +229,8 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); } virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); }
virtual Transaction transaction(h256 _blockHash, unsigned _i) const; virtual Transaction transaction(h256 _blockHash, unsigned _i) const;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const;
virtual unsigned transactionCount(h256 _blockHash) const;
virtual unsigned uncleCount(h256 _blockHash) const;
/// Differences between transactions. /// Differences between transactions.
using Interface::diff; using Interface::diff;

2
libethereum/EthereumHost.h

@ -94,7 +94,7 @@ private:
h256Set neededBlocks(h256Set const& _exclude); h256Set neededBlocks(h256Set const& _exclude);
/// Check to see if the network peer-state initialisation has happened. /// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return m_latestBlockSent; } bool isInitialised() const { return (bool)m_latestBlockSent; }
/// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first. /// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(); bool ensureInitialised();

40
libethereum/GenesisInfo.cpp

@ -0,0 +1,40 @@
/*
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 GenesisInfo.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "GenesisInfo.h"
std::string const dev::eth::c_genesisInfo =
R"ETHEREUM(
{
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"e6716f9544a56c530d868e4bfbacb172315bdead": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"b9c015918bdaba24b4ff057a92a3873d6eb201be": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"6c386a4b26f73c802f34673f7248bb118f97424a": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" },
"b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" },
"f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" },
"cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" },
"b7576e9d314df41ec5506494293afb1bd5d3f65d": { "finney": "69423399" },
}
)ETHEREUM";

32
libethereum/GenesisInfo.h

@ -0,0 +1,32 @@
/*
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 GenesisInfo.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <string>
namespace dev {
namespace eth {
extern std::string const c_genesisInfo;
}
}

2
libethereum/Interface.h

@ -103,6 +103,8 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0;
virtual unsigned transactionCount(h256 _blockHash) const = 0;
virtual unsigned uncleCount(h256 _blockHash) const = 0;
// [EXTRA API]: // [EXTRA API]:

13
libethereum/State.cpp

@ -537,7 +537,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
cwarn << "Hex: " << toHex(b); cwarn << "Hex: " << toHex(b);
cwarn << TransactionReceipt(&b); cwarn << TransactionReceipt(&b);
} }
cwarn << "Recorded: " << m_currentBlock.receiptsRoot; cwarn << "Recorded: " << m_currentBlock.receiptsRoot;
auto rs = _bc.receipts(m_currentBlock.hash); auto rs = _bc.receipts(m_currentBlock.hash);
for (unsigned j = 0; j < rs.receipts.size(); ++j) for (unsigned j = 0; j < rs.receipts.size(); ++j)
{ {
@ -600,6 +600,13 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
BOOST_THROW_EXCEPTION(InvalidStateRoot()); BOOST_THROW_EXCEPTION(InvalidStateRoot());
} }
if (m_currentBlock.gasUsed != gasUsed())
{
// Rollback the trie.
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
}
return tdIncrease; return tdIncrease;
} }
@ -1192,11 +1199,11 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
else if (j.second) else if (j.second)
cached.insert(j.first); cached.insert(j.first);
} }
if (delta.size()) if (!delta.empty())
lead = (lead == " . ") ? "*.* " : "*** "; lead = (lead == " . ") ? "*.* " : "*** ";
contout << " @:"; contout << " @:";
if (delta.size()) if (!delta.empty())
contout << "???"; contout << "???";
else else
contout << r[2].toHash<h256>(); contout << r[2].toHash<h256>();

2
libethereum/State.h

@ -132,7 +132,7 @@ public:
* commitToMine(_blockChain); // will call uncommitToMine if a repeat. * commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* // unlock * // unlock
* MineInfo info; * MineInfo info;
* for (info.complete = false; !info.complete; info = mine()) {} * for (info.completed = false; !info.completed; info = mine()) {}
* } * }
* // lock * // lock
* completeMine(); * completeMine();

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save