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.
By Gav Wood, 2014.
By Gav Wood et al, 2013, 2014, 2015.
| 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)
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)
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
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](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](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)
@ -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)
### License
See [LICENSE](LICENSE)

4
alethzero/CMakeLists.txt

@ -10,8 +10,8 @@ endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
find_package (Qt5WebEngine QUIET)
@ -63,5 +63,5 @@ if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
endif()
# 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;
namespace dev { namespace eth { class StateDiff; } }
namespace dev { namespace eth { struct StateDiff; } }
#define Small "font-size: small; "
#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;
if (uMax == uMin || !_divisions)
{
*o_from = 0;
*o_delta = 1;
if (o_delta && o_from)
{
*o_from = 0;
*o_delta = 1;
}
return 1;
}
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;
protected:
QPainter* p;
QPainter* p = nullptr;
QRect active;
std::pair<float, float> xRange;
std::pair<float, float> yRange;
float xM;
float xC;
float yM;
float yC;
float xM = 0;
float xC = 0;
float yM = 0;
float yC = 0;
float dx;
float dy;
float dx = 0;
float dy = 0;
std::function<std::string(float _f)> xLabel;
std::function<std::string(float _f)> yLabel;
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.
float xT(float _dataIndex) const { return _dataIndex * xM + xC; }

12
alethzero/Main.ui

@ -157,6 +157,7 @@
<property name="title">
<string>&amp;Special</string>
</property>
<addaction name="natSpec"/>
<addaction name="paranoia"/>
<addaction name="clearPending"/>
<addaction name="killBlockchain"/>
@ -1646,6 +1647,17 @@ font-size: 14pt</string>
<string>New &amp;Transaction...</string>
</property>
</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>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

25
alethzero/MainWin.cpp

@ -199,6 +199,11 @@ Main::~Main()
g_logPost = simpleDebugOut;
}
bool Main::confirm() const
{
return ui->natSpec->isChecked();
}
void Main::on_newIdentity_triggered()
{
KeyPair kp = KeyPair::create();
@ -649,6 +654,7 @@ void Main::writeSettings()
s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("natSpec", ui->natSpec->isChecked());
s.setValue("showAll", ui->showAll->isChecked());
s.setValue("showAllAccounts", ui->showAllAccounts->isChecked());
s.setValue("clientName", ui->clientName->text());
@ -660,7 +666,7 @@ void Main::writeSettings()
s.setValue("jitvm", ui->jitvm->isChecked());
bytes d = m_webThree->saveNetwork();
if (d.size())
if (!d.empty())
m_networkConfig = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_networkConfig);
s.setValue("nameReg", ui->nameReg->text());
@ -718,6 +724,7 @@ void Main::readSettings(bool _skipGeometry)
ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered();
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->showAllAccounts->setChecked(s.value("showAllAccounts", false).toBool());
ui->clientName->setText(s.value("clientName", "").toString());
@ -1158,6 +1165,7 @@ void Main::timerEvent(QTimerEvent*)
interval = 0;
refreshNetwork();
refreshWhispers();
poll();
}
else
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())
{
@ -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()
{
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());
}
@ -1513,11 +1516,11 @@ void Main::on_ourAccounts_doubleClicked()
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
void Main::on_log_doubleClicked()
/*void Main::on_log_doubleClicked()
{
ui->log->setPlainText("");
m_logHistory.clear();
}
}*/
void Main::on_accounts_doubleClicked()
{
@ -1624,7 +1627,7 @@ void Main::on_net_triggered()
{
web3()->setIdealPeerCount(ui->idealPeers->value());
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
// if (m_networkConfig.size()/* && ui->usePast->isChecked()*/)
// 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(); }
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
bool confirm() const;
NatSpecFace* natSpec() { return &m_natSpecDB; }
QString pretty(dev::Address _a) const override;
@ -106,7 +107,7 @@ private slots:
void on_go_triggered();
void on_net_triggered();
void on_connect_triggered();
void on_idealPeers_valueChanged();
void on_idealPeers_valueChanged(int);
// Mining
void on_mine_triggered();
@ -139,7 +140,7 @@ private slots:
void on_blocks_currentItemChanged();
// Logging
void on_log_doubleClicked();
// void on_log_doubleClicked();
void on_verbosity_valueChanged();
// Misc
@ -159,8 +160,8 @@ private slots:
// Debugger
void on_debugCurrent_triggered();
void on_debugDumpState_triggered(int _add = 1);
void on_debugDumpStatePre_triggered();
void on_debugDumpState_triggered() { debugDumpState(1); }
void on_debugDumpStatePre_triggered() { debugDumpState(0); }
// Whisper
void on_newIdentity_triggered();
@ -174,6 +175,8 @@ signals:
void poll();
private:
void debugDumpState(int _add);
dev::p2p::NetworkPreferences netPrefs() 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)
{
}
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)
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)
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;
update();

1
alethzero/NatspecHandler.cpp

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

2
alethzero/NatspecHandler.h

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

78
alethzero/OurWebThreeStubServer.cpp

@ -33,9 +33,11 @@ using namespace dev;
using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3,
vector<KeyPair> const& _accounts, Main* main):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main)
{}
vector<KeyPair> const& _accounts, Main* _main):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main)
{
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
}
string OurWebThreeStubServer::shh_newIdentity()
{
@ -44,29 +46,44 @@ string OurWebThreeStubServer::shh_newIdentity()
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;
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;
if (!m_main->confirm())
{
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!",
"ÐApp is attempting to call into an unknown contract at address " +
m_main->pretty(_t.to).toStdString() +
".\n\nCall involves sending " +
m_main->pretty(_t.to).toStdString() + ".\n\n" +
(_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.gas * _t.gasPrice) +
"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!");
}
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)
{
// recipient has no code - nothing special about this transaction, show basic value transfer info
return showCreationNotice(_t);
// show notice concerning the creation code. TODO: this needs entering into natspec.
return showCreationNotice(_t, _toProxy);
}
h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to);
if (contractCodeHash == EmptySHA3)
{
// 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);
if (userNotice.empty())
return showUnknownCallNotice(_t);
return showUnknownCallNotice(_t, _toProxy);
NatspecExpressionEvaluator evaluator;
userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString();
@ -104,11 +139,12 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
"ÐApp attempting to conduct contract interaction with " +
m_main->pretty(_t.to).toStdString() +
": <b>" + userNotice + "</b>.\n\n" +
(_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") +
(_t.value > 0 ?
"In addition, ÐApp is attempting to send " +
formatBalance(_t.value) + " to said recipient, with additional network fees of up to " +
formatBalance(_t.gas * _t.gasPrice) + " = <b>" +
formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>."
formatBalance(_t.gas * _t.gasPrice) + " = " +
formatBalance(_t.value + _t.gas * _t.gasPrice) + "."
:
"Additional network fees are at most" +
formatBalance(_t.gas * _t.gasPrice) + ".")

20
alethzero/OurWebThreeStubServer.h

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

8
alethzero/Transact.cpp

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

5
cmake/EthDependencies.cmake

@ -128,6 +128,11 @@ if (NOT HEADLESS)
set (MACDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/macdeployqt)
message(" - macdeployqt path: ${MACDEPLOYQT_APP}")
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
find_program(ETH_NODE node)

58
cmake/EthExecutableHelper.cmake

@ -56,14 +56,14 @@ macro(eth_install_executable EXECUTABLE)
set (extra_macro_args ${ARGN})
set (options)
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}")
if (ETH_INSTALL_EXECUTABLE_QMLDIR)
if (APPLE)
set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}")
elseif (WIN32)
set(eth_qml_dir --qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR})
set(eth_qml_dir "--qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}")
endif()
message(STATUS "${EXECUTABLE} qmldir: ${eth_qml_dir}")
endif()
@ -88,48 +88,30 @@ macro(eth_install_executable EXECUTABLE)
set(BU_CHMOD_BUNDLE_ITEMS 1)
verify_app(\"${APP_BUNDLE_PATH}\")
" COMPONENT RUNTIME )
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# copy all dlls to executable directory
# TODO improve that by copying only required dlls
file (GLOB DLLS ${ETH_DEPENDENCY_INSTALL_DIR}/bin/*.dll)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
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
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()
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND cmake -E copy_directory
"${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms"
$<TARGET_FILE_DIR:${EXECUTABLE}>/platforms
)
# 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}
)
#workaround for https://bugreports.qt.io/browse/QTBUG-42083
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM
)
endif()
install( DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms
DESTINATION bin
COMPONENT ${EXECUTABLE}
#copy additional dlls
foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS})
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E copy ${dll} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
)
file (GLOB QMLS ${ETH_DEPENDENCY_INSTALL_DIR}/qml/*)
foreach(QML ${QMLS})
install( DIRECTORY ${QML}
DESTINATION bin
COMPONENT ${EXECUTABLE}
)
endforeach()
endforeach(dll)
install( TARGETS ${EXECUTABLE} RUNTIME
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"
# official MHD project actually uses _d suffix
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(
MHD_LIBRARY_DEBUG
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d
DOC "mhd debug library"
)
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
# always use release for now
#string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG})
#set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
endif()

6
eth/CMakeLists.txt

@ -3,9 +3,9 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE eth)
@ -28,5 +28,9 @@ endif()
target_link_libraries(${EXECUTABLE} webthree)
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 )

6
eth/main.cpp

@ -749,7 +749,7 @@ int main(int argc, char** argv)
else if (format == "standard+")
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);
if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
for (auto const& i: ext->state().storage(ext->myAddress))
@ -898,7 +898,9 @@ int main(int argc, char** argv)
while (!g_exit)
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;
}

7
evmjit/CMakeLists.txt

@ -3,13 +3,14 @@ cmake_minimum_required(VERSION 2.8.12)
project(evmjit)
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()
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()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
# Do not allow unresovled symbols in shared library (default on linux)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
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})
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})
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 <libevm/FeeStructure.h>
#include <libevm/ExtVMFace.h>
@ -46,23 +47,22 @@ extern "C"
*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);
if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{
_env->subBalance(endowment);
auto gas = llvm2eth(*io_gas);
OnOpFunc onOp {}; // TODO: Handle that thing
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight);
*io_gas = eth2llvm(gas);
u256 gas = *io_gas;
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight);
*io_gas = static_cast<int64_t>(gas);
*o_address = address;
}
else
*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);
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
@ -70,12 +70,11 @@ extern "C"
_env->subBalance(value);
auto receiveAddress = right160(*_receiveAddress);
auto inRef = bytesConstRef{_inBeg, _inSize};
auto outRef = bytesConstRef{_outBeg, _outSize};
OnOpFunc onOp {}; // TODO: Handle that thing
auto outRef = bytesRef{_outBeg, _outSize};
auto codeAddress = right160(*_codeAddress);
auto gas = llvm2eth(*io_gas);
auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress);
*io_gas = eth2llvm(gas);
u256 gas = *io_gas;
auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress);
*io_gas = static_cast<int64_t>(gas);
return ret;
}

34
evmjit/libevmjit-cpp/JitVM.cpp

@ -1,6 +1,9 @@
#pragma GCC diagnostic ignored "-Wconversion"
#include "JitVM.h"
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libdevcrypto/SHA3.h>
#include <evmjit/libevmjit/ExecutionEngine.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
bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
{
using namespace jit;
if (m_gas > std::numeric_limits<decltype(m_data.gas)>::max())
BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that
if (_ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max())
BOOST_THROW_EXCEPTION(OutOfGas());
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());
auto rejected = false;
// 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)
rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max();
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 (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.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.code = _ext.code.data();
m_data.codeSize = _ext.code.size();
m_data.codeHash = eth2llvm(sha3(_ext.code));
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)
{
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;
enum Kind: bool { Interpreter, JIT };
static std::unique_ptr<VMFace> create(Kind, u256 _gas = 0);
private:
friend class VMFactory;
explicit JitVM(u256 _gas = 0) : VMFace(_gas) {}
jit::RuntimeData m_data;
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 "Runtime.h"
#include "Type.h"
#include "Endianness.h"
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>
#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
{
@ -16,29 +19,102 @@ namespace jit
Arith256::Arith256(llvm::IRBuilder<>& _builder) :
CompilerHelper(_builder)
{
using namespace llvm;
{}
m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result");
m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1");
m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2");
m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3");
void Arith256::debug(llvm::Value* _value, char _c)
{
if (!m_debug)
{
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()};
m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule());
auto i512 = m_builder.getIntNTy(512);
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)
@ -85,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type)
auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0");
auto shlBy0 = m_builder.CreateICmpEQ(i0, zero);
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
m_builder.CreateBr(loopBB);
@ -135,7 +220,7 @@ llvm::Function* Arith256::getExpFunc()
if (!m_exp)
{
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();
base->setName("base");
@ -159,9 +244,6 @@ llvm::Function* Arith256::getExpFunc()
auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp);
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.SetInsertPoint(headerBB);
@ -176,20 +258,14 @@ llvm::Function* Arith256::getExpFunc()
m_builder.CreateCondBr(eOdd, updateBB, continueBB);
m_builder.SetInsertPoint(updateBB);
m_builder.CreateStore(r, a1);
m_builder.CreateStore(b, a2);
createCall(m_mul, {a1, a2, a3});
auto r0 = m_builder.CreateLoad(a3, "r0");
auto r0 = createCall(getMulFunc(), {r, b});
m_builder.CreateBr(continueBB);
m_builder.SetInsertPoint(continueBB);
auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1");
r1->addIncoming(r, bodyBB);
r1->addIncoming(r0, updateBB);
m_builder.CreateStore(b, a1);
m_builder.CreateStore(b, a2);
createCall(m_mul, {a1, a2, a3});
auto b1 = m_builder.CreateLoad(a3, "b1");
auto b1 = createCall(getMulFunc(), {b, b});
auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1");
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());
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();
x->setName("x");
auto y = x->getNextNode();
@ -258,32 +331,19 @@ llvm::Function* Arith256::getMulModFunc()
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod);
m_builder.SetInsertPoint(entryBB);
auto a1 = m_builder.CreateAlloca(Type::Word);
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 p = createCall(getMul512Func(), {x, y});
auto m = m_builder.CreateZExt(mod, i512Ty, "m");
auto d = createCall(getDivFunc(i512Ty), {p, m});
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;
}
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)
{
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)
@ -331,157 +391,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu
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"
{
using namespace dev::eth::jit;
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;
}
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);
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";
}
}

13
evmjit/libevmjit/Arith256.h

@ -24,26 +24,21 @@ public:
void debug(llvm::Value* _value, char _c);
private:
llvm::Function* getMulFunc();
llvm::Function* getMul512Func();
llvm::Function* getDivFunc(llvm::Type* _type);
llvm::Function* getExpFunc();
llvm::Function* getAddModFunc();
llvm::Function* getMulModFunc();
llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2);
llvm::Function* m_mul;
llvm::Function* m_mul = nullptr;
llvm::Function* m_mul512 = nullptr;
llvm::Function* m_div = nullptr;
llvm::Function* m_div512 = nullptr;
llvm::Function* m_exp = nullptr;
llvm::Function* m_addmod = nullptr;
llvm::Function* m_mulmod = 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 <iostream>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/CFG.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/Support/raw_os_ostream.h>
#include "preprocessor/llvm_includes_end.h"
#include "Type.h"
@ -18,13 +19,14 @@ namespace eth
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_end(_end),
// TODO: Add begin index to name
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)),
m_stack(*this),
m_builder(_builder),
m_isJumpDest(isJumpDest)
@ -43,6 +45,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) :
void BasicBlock::LocalStack::push(llvm::Value* _value)
{
assert(_value->getType() == Type::Word);
m_bblock.m_currentStack.push_back(_value);
m_bblock.m_tosOffset += 1;
}
@ -139,7 +142,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
auto endIter = m_currentStack.end();
// 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, --idx)
{
@ -306,7 +309,7 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
auto& initialStack = bblock.m_initialStack;
initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems);
// 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
@ -319,7 +322,7 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
auto& exitStack = bblock.m_currentStack;
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
#include <vector>
#include <llvm/IR/BasicBlock.h>
#include "Common.h"
#include "Stack.h"
@ -11,7 +12,7 @@ namespace eth
namespace jit
{
using ProgramCounter = uint64_t; // TODO: Rename
using instr_idx = uint64_t;
class BasicBlock
{
@ -50,10 +51,7 @@ public:
BasicBlock& m_bblock;
};
/// Basic block name prefix. The rest is instruction index.
static const char* NamePrefix;
explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, 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;
@ -61,8 +59,9 @@ public:
llvm::BasicBlock* llvm() { return m_llvmBB; }
bytes::const_iterator begin() { return m_begin; }
bytes::const_iterator end() { return m_end; }
instr_idx firstInstrIdx() const { return m_firstInstrIdx; }
code_iterator begin() const { return m_begin; }
code_iterator end() const { return m_end; }
bool isJumpDest() const { return m_isJumpDest; }
@ -84,8 +83,9 @@ public:
void dump(std::ostream& os, bool _dotOutput = false);
private:
bytes::const_iterator const m_begin;
bytes::const_iterator const m_end;
instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block
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;

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 ${SOURCES})
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# Disable rtti for Cache as LLVM has no rtti
set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif()
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always
OUTPUT_VARIABLE EVMJIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
set(EVMJIT_VERSION "0.0.0")
set(EVMJIT_VERSION_MAJOR 0)
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()
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()
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})
set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} FOLDER "libs")
add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h)
set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs")
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen)
target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS})
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
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 <unordered_map>
#include <cassert>
#include <iostream>
#include <cassert>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h>
#include "preprocessor/llvm_includes_end.h"
#include "ExecutionEngine.h"
#include "Utils.h"
namespace dev
{
@ -15,23 +22,31 @@ namespace eth
namespace jit
{
//#define LOG(...) std::cerr << "CACHE "
#define LOG(...) std::ostream(nullptr)
//#define CACHE_LOG std::cerr << "CACHE "
#define CACHE_LOG std::ostream(nullptr)
ObjectCache* Cache::getObjectCache()
namespace
{
static ObjectCache objectCache;
return &objectCache;
llvm::MemoryBuffer* g_lastObject;
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)
{
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::sys::path::system_temp_directory(false, cachePath);
llvm::sys::path::append(cachePath, "evm_objs", id);
@ -51,22 +66,31 @@ std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
#endif
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))
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()));
auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false);
llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
CACHE_LOG << id << ": found\n";
auto&& context = llvm::getGlobalContext();
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;
}
void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object)
{
if (g_listener)
g_listener->stateChanged(ExecState::CacheWrite);
auto&& id = _module->getModuleIdentifier();
llvm::SmallString<256> 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);
CACHE_LOG << id << ": write\n";
std::string error;
llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None);
cacheFile << _object->getBuffer();
}
llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*)
llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
{
auto o = lastObject;
lastObject = nullptr;
CACHE_LOG << _module->getModuleIdentifier() << ": use\n";
auto o = g_lastObject;
g_lastObject = nullptr;
return o;
}

9
evmjit/libevmjit/Cache.h

@ -1,9 +1,8 @@
#pragma once
#include <memory>
#include <unordered_map>
#include <llvm/ExecutionEngine/ObjectCache.h>
#include <llvm/ExecutionEngine/ObjectCache.h>
namespace dev
{
@ -11,6 +10,7 @@ namespace eth
{
namespace jit
{
class ExecutionEngineListener;
class ObjectCache : public llvm::ObjectCache
{
@ -23,16 +23,13 @@ public:
/// not available. The caller owns both the MemoryBuffer returned by this
/// and the memory it references.
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
{
public:
static ObjectCache* getObjectCache();
static ObjectCache* getObjectCache(ExecutionEngineListener* _listener);
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 bytes = std::vector<byte>;
using bytes_ref = std::tuple<byte const*, size_t>;
using code_iterator = byte const*;
struct NoteChannel {}; // FIXME: Use some log library?
enum class ReturnCode
{
Stop = 0,
Return = 1,
// Success codes
Stop = 0,
Return = 1,
Suicide = 2,
OutOfGas = -1,
BadJumpDestination = -2,
StackTooSmall = -3,
BadInstruction = -4,
// Standard error codes
OutOfGas = -1,
StackTooSmall = -2,
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,
LLVMCompileError = -6,
LLVMLinkError = -7,
// Internal error codes
LLVMConfigError = -101,
LLVMCompileError = -102,
LLVMLinkError = -103,
UnexpectedException = -8,
UnexpectedException = -111,
LinkerWorkaround = -299,
};

94
evmjit/libevmjit/Compiler.cpp

@ -1,4 +1,3 @@
#include "Compiler.h"
#include <functional>
@ -6,13 +5,15 @@
#include <chrono>
#include <sstream>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/ADT/PostOrderIterator.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/MDBuilder.h>
#include <llvm/PassManager.h>
#include <llvm/Transforms/Scalar.h>
#include "preprocessor/llvm_includes_end.h"
#include "Instruction.h"
#include "Type.h"
@ -39,10 +40,10 @@ Compiler::Compiler(Options const& _options):
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)
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 push32 = static_cast<size_t>(Instruction::PUSH32);
@ -52,11 +53,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode)
return _curr + offset;
};
auto begin = _bytecode.begin();
auto begin = _codeBegin; // begin of current block
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;
switch (Instruction(*curr))
@ -77,22 +78,19 @@ void Compiler::createBasicBlocks(bytes const& _bytecode)
break;
}
assert(next <= _bytecode.end());
if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST)
assert(next <= _codeEnd);
if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST)
isEnd = true;
if (isEnd)
{
auto beginIdx = begin - _bytecode.begin();
auto beginIdx = begin - _codeBegin;
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;
begin = next;
}
}
// TODO: Create Stop basic block on demand
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
}
llvm::BasicBlock* Compiler::getJumpTableBlock()
@ -125,7 +123,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock()
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 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->getArgumentList().front().setName("rt");
// Create the basic blocks.
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc);
// Create entry basic block
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc);
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.
RuntimeManager runtimeManager(m_builder);
RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end);
GasMeter gasMeter(m_builder, runtimeManager);
Memory memory(runtimeManager, gasMeter);
Ext ext(runtimeManager, memory);
Stack stack(m_builder, runtimeManager);
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)
{
@ -157,7 +174,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
auto iterCopy = basicBlockPairIt;
++iterCopy;
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:
@ -165,6 +182,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
m_builder.SetInsertPoint(m_stopBB);
m_builder.CreateRet(Constant::get(ReturnCode::Stop));
m_builder.SetInsertPoint(abortBB);
m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas));
removeDeadBlocks();
// 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)
{
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:
{
auto value = Constant::get(it - _bytecode.begin());
auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx());
stack.push(value);
break;
}
@ -631,7 +651,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::GAS:
{
_gasMeter.commitCostBlock();
stack.push(_runtimeManager.getGas());
stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word));
break;
}
@ -741,10 +761,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
_memory.require(initOff, initSize);
_gasMeter.commitCostBlock();
auto gas = _runtimeManager.getGas();
auto address = _ext.create(gas, endowment, initOff, initSize);
_runtimeManager.setGas(gas);
auto address = _ext.create(endowment, initOff, initSize);
stack.push(address);
break;
}
@ -752,7 +769,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::CALL:
case Instruction::CALLCODE:
{
auto gas = stack.pop();
auto callGas256 = stack.pop();
auto codeAddress = stack.pop();
auto value = stack.pop();
auto inOff = stack.pop();
@ -770,9 +787,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
if (inst == Instruction::CALLCODE)
receiveAddress = _runtimeManager.get(RuntimeData::Address);
_gasMeter.count(gas);
auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress);
_gasMeter.giveBack(gas);
auto gas = _runtimeManager.getGas();
_gasMeter.count(callGas256);
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);
break;
}
@ -825,12 +846,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
break;
}
default: // Invalid instruction - runtime exception
{
// TODO: Replace with return statement
_runtimeManager.raiseException(ReturnCode::BadInstruction);
}
default: // Invalid instruction - abort
m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction));
it = _basicBlock.end() - 1; // finish block compilation
}
}

9
evmjit/libevmjit/Compiler.h

@ -1,8 +1,5 @@
#pragma once
#include <llvm/IR/IRBuilder.h>
#include "Common.h"
#include "BasicBlock.h"
@ -33,13 +30,13 @@ public:
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:
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();

4
evmjit/libevmjit/CompilerHelper.cpp

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

5
evmjit/libevmjit/CompilerHelper.h

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

3
evmjit/libevmjit/Endianness.cpp

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

3
evmjit/libevmjit/Endianness.h

@ -1,7 +1,8 @@
#pragma once
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IRBuilder.h>
#include "preprocessor/llvm_includes_end.h"
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 <chrono>
#include <array>
#include <cstdlib> // env options
#include <iostream>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.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/SectionMemoryManager.h>
#pragma warning(pop)
#pragma GCC diagnostic pop
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h>
#include "preprocessor/llvm_includes_end.h"
#include "Runtime.h"
#include "Compiler.h"
#include "Cache.h"
#include "ExecStats.h"
#include "Utils.h"
#include "BuildInfo.gen.h"
namespace dev
{
@ -31,34 +32,20 @@ namespace
{
using EntryFuncPtr = ReturnCode(*)(Runtime*);
ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime)
std::string codeHash(i256 const& _hash)
{
// That function uses long jumps to handle "execeptions".
// Do not create any non-POD objects here
ReturnCode returnCode{};
auto sj = setjmp(_runtime->getJmpBuf());
if (sj == 0)
returnCode = _mainFunc(_runtime);
else
returnCode = static_cast<ReturnCode>(sj);
return returnCode;
}
std::string codeHash(bytes const& _code)
{
uint32_t hash = 0;
for (auto b : _code)
static const auto size = sizeof(_hash);
static const auto hexChars = "0123456789abcdef";
std::string str;
str.resize(size * 2);
auto outIt = str.rbegin(); // reverse for BE
auto& arr = *(std::array<byte, size>*)&_hash;
for (auto b : arr)
{
hash += b;
hash += (hash << 10);
hash ^= (hash >> 6);
*(outIt++) = hexChars[b & 0xf];
*(outIt++) = hexChars[b >> 4];
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return std::to_string(hash);
return str;
}
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;
}
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 objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true);
static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false);
static auto infoShown = showInfo();
(void) infoShown;
auto mainFuncName = codeHash(_code);
EntryFuncPtr entryFuncPtr{};
Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls
std::unique_ptr<ExecStats> listener{new ExecStats};
listener->stateChanged(ExecState::Started);
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;
std::unique_ptr<llvm::Module> module;
if (objectCache)
module = Cache::getObject(mainFuncName);
auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
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)
{
ee->addModule(module.get());
module.release();
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
}
listener->stateChanged(ExecState::Compilation);
assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code?
module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, 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)
{
returnData = runtime.getReturnData(); // Save reference to return data
std::swap(m_memory, runtime.getMemory()); // Take ownership of memory
}
listener->stateChanged(ExecState::Finished);
auto executionEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(executionEndTime - executionStartTime).count() << " ms\n";
if (statsCollectingEnabled)
statsCollector.stats.push_back(std::move(listener));
return returnCode;
}

32
evmjit/libevmjit/ExecutionEngine.h

@ -1,5 +1,7 @@
#pragma once
#include <memory>
#include "RuntimeData.h"
namespace dev
@ -9,14 +11,40 @@ namespace eth
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
{
public:
ExecutionEngine() = default;
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)
bytes_ref returnData;

31
evmjit/libevmjit/Ext.cpp

@ -1,9 +1,8 @@
#include "Ext.h"
#include <llvm/IR/Function.h>
#include <llvm/IR/TypeBuilder.h>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "RuntimeManager.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_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, 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_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, 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::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_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
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()
{
auto& a = m_argAllocas[m_argCounter++];
auto& a = m_argAllocas[m_argCounter];
if (!a)
{
// FIXME: Improve order and names
InsertPointGuard g{getBuilder()};
getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI());
a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg");
auto allocaIt = getMainFunction()->front().begin();
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;
}
@ -124,30 +125,26 @@ llvm::Value* Ext::blockhash(llvm::Value* _number)
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 begin = m_memoryMan.getBytePtr(_initOff);
auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size");
createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret});
_gas = m_builder.CreateLoad(gas); // Return gas
createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret});
llvm::Value* address = m_builder.CreateLoad(ret);
address = Endianness::toNative(m_builder, 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 inBeg = m_memoryMan.getBytePtr(_inOff);
auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size");
auto outBeg = m_memoryMan.getBytePtr(_outOff);
auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size");
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)});
_gas = m_builder.CreateLoad(gas); // Return gas
auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)});
return m_builder.CreateZExt(ret, Type::Word, "ret");
}

6
evmjit/libevmjit/Ext.h

@ -1,7 +1,7 @@
#pragma once
#include <array>
#include "CompilerHelper.h"
namespace dev
@ -50,8 +50,8 @@ public:
llvm::Value* balance(llvm::Value* _address);
llvm::Value* calldataload(llvm::Value* _index);
llvm::Value* create(llvm::Value*& _gas, 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* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize);
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* sha3(llvm::Value* _inOff, llvm::Value* _inSize);

107
evmjit/libevmjit/GasMeter.cpp

@ -1,11 +1,9 @@
#include "GasMeter.h"
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "Type.h"
#include "Ext.h"
#include "RuntimeManager.h"
@ -19,29 +17,29 @@ namespace jit
namespace // Helper functions
{
uint64_t const c_stepGas = 1;
uint64_t const c_balanceGas = 20;
uint64_t const c_sha3Gas = 10;
uint64_t const c_sha3WordGas = 10;
uint64_t const c_sloadGas = 20;
uint64_t const c_sstoreSetGas = 300;
uint64_t const c_sstoreResetGas = 100;
uint64_t const c_sstoreRefundGas = 100;
uint64_t const c_createGas = 100;
uint64_t const c_createDataGas = 5;
uint64_t const c_callGas = 20;
uint64_t const c_expGas = 1;
uint64_t const c_expByteGas = 1;
uint64_t const c_memoryGas = 1;
uint64_t const c_txDataZeroGas = 1;
uint64_t const c_txDataNonZeroGas = 5;
uint64_t const c_txGas = 500;
uint64_t const c_logGas = 32;
uint64_t const c_logDataGas = 1;
uint64_t const c_logTopicGas = 32;
uint64_t const c_copyGas = 1;
uint64_t getStepCost(Instruction inst)
int64_t const c_stepGas = 1;
int64_t const c_balanceGas = 20;
int64_t const c_sha3Gas = 10;
int64_t const c_sha3WordGas = 10;
int64_t const c_sloadGas = 20;
int64_t const c_sstoreSetGas = 300;
int64_t const c_sstoreResetGas = 100;
int64_t const c_sstoreRefundGas = 100;
int64_t const c_createGas = 100;
int64_t const c_createDataGas = 5;
int64_t const c_callGas = 20;
int64_t const c_expGas = 1;
int64_t const c_expByteGas = 1;
int64_t const c_memoryGas = 1;
int64_t const c_txDataZeroGas = 1;
int64_t const c_txDataNonZeroGas = 5;
int64_t const c_txGas = 500;
int64_t const c_logGas = 32;
int64_t const c_logDataGas = 1;
int64_t const c_logTopicGas = 32;
int64_t const c_copyGas = 1;
int64_t getStepCost(Instruction inst)
{
switch (inst)
{
@ -72,7 +70,7 @@ uint64_t getStepCost(Instruction inst)
case Instruction::LOG3:
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;
}
}
@ -86,7 +84,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
{
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);
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 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);
auto arg = m_gasCheckFunc->arg_begin();
arg->setName("rt");
++arg;
arg->setName("cost");
auto cost = arg;
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.SetInsertPoint(outOfGasBB);
m_runtimeManager.raiseException(ReturnCode::OutOfGas);
m_runtimeManager.abort();
m_builder.CreateUnreachable();
m_builder.SetInsertPoint(updateBB);
gas = m_builder.CreateSub(gas, cost);
m_runtimeManager.setGas(gas);
m_builder.CreateRetVoid();
}
@ -119,7 +117,7 @@ void GasMeter::count(Instruction _inst)
if (!m_checkCall)
{
// 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);
@ -127,6 +125,15 @@ void GasMeter::count(Instruction _inst)
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});
}
@ -136,12 +143,13 @@ void GasMeter::countExp(llvm::Value* _exponent)
// lz - leading zeros
// 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 lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
auto sigBits = m_builder.CreateSub(Constant::get(256), lz);
auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8));
auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
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);
}
@ -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 isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete");
auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost");
auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost");
count(cost);
}
@ -173,17 +181,16 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength)
assert(m_blockCost > 0); // SHA3 instruction is already counted
// 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");
auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision);
auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32));
auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas);
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 cost = getBuilder().CreateZExt(cost64, Type::Word);
count(cost);
count(cost64);
}
void GasMeter::giveBack(llvm::Value* _gas)
{
assert(_gas->getType() == Type::Gas);
m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas));
}
@ -199,7 +206,7 @@ void GasMeter::commitCostBlock()
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_blockCost = 0;
}

3
evmjit/libevmjit/GasMeter.h

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

8
evmjit/libevmjit/Instruction.cpp

@ -1,6 +1,8 @@
#include "Instruction.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/ADT/APInt.h>
#include "preprocessor/llvm_includes_end.h"
namespace dev
{
@ -9,7 +11,7 @@ namespace eth
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;
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;
}
void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
void skipPushData(code_iterator& _curr, code_iterator _end)
{
auto pushInst = *_curr;
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
/// Reading out of bytecode means reading 0
/// @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.
/// @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: \
case Instruction::PUSH2: \

499
evmjit/libevmjit/Memory.cpp

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

86
evmjit/libevmjit/Runtime.h

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

4
evmjit/libevmjit/RuntimeData.h

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

56
evmjit/libevmjit/RuntimeManager.cpp

@ -1,12 +1,8 @@
#include "RuntimeManager.h"
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>
#include "RuntimeData.h"
#include "Instruction.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
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
auto rtPtr = getRuntimePtr();
@ -161,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _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)
@ -191,14 +196,14 @@ llvm::Value* RuntimeManager::getCallData()
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()
{
auto value = get(RuntimeData::CodeSize);
assert(value->getType() == Type::Size);
return getBuilder().CreateZExt(value, Type::Word);
return Constant::get(m_codeEnd - m_codeBegin);
}
llvm::Value* RuntimeManager::getCallDataSize()
@ -208,23 +213,28 @@ llvm::Value* RuntimeManager::getCallDataSize()
return getBuilder().CreateZExt(value, Type::Word);
}
llvm::Value* RuntimeManager::getJmpBuf()
llvm::Value* RuntimeManager::getJmpBufExt()
{
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr");
return getBuilder().CreateLoad(ptr, "jmpbuf");
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2);
return getBuilder().CreateLoad(ptr, "jmpBufExt");
}
llvm::Value* RuntimeManager::getGas()
{
auto value = get(RuntimeData::Gas);
assert(value->getType() == Type::Size);
return getBuilder().CreateZExt(value, Type::Word);
auto gas = get(RuntimeData::Gas);
assert(gas->getType() == Type::Gas);
return gas;
}
llvm::Value* RuntimeManager::getGasPtr()
{
return getPtr(RuntimeData::Gas);
}
void RuntimeManager::setGas(llvm::Value* _gas)
{
auto newGas = getBuilder().CreateTrunc(_gas, Type::Size);
set(RuntimeData::Gas, newGas);
assert(_gas->getType() == Type::Gas);
set(RuntimeData::Gas, _gas);
}
}

17
evmjit/libevmjit/RuntimeManager.h

@ -15,25 +15,28 @@ namespace jit
class RuntimeManager: public CompilerHelper
{
public:
RuntimeManager(llvm::IRBuilder<>& _builder);
RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd);
llvm::Value* getRuntimePtr();
llvm::Value* getDataPtr();
llvm::Value* getEnvPtr(); // TODO: Can we make it const?
llvm::Value* getEnvPtr();
llvm::Value* get(RuntimeData::Index _index);
llvm::Value* get(Instruction _inst);
llvm::Value* getGas(); // TODO: Remove
llvm::Value* getGas();
llvm::Value* getGasPtr();
llvm::Value* getCallData();
llvm::Value* getCode();
llvm::Value* getCodeSize();
llvm::Value* getCallDataSize();
llvm::Value* getJmpBuf() { return m_jmpBuf; }
void setGas(llvm::Value* _gas);
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
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* getRuntimeDataType();
@ -41,11 +44,15 @@ public:
private:
llvm::Value* getPtr(RuntimeData::Index _index);
void set(RuntimeData::Index _index, llvm::Value* _value);
llvm::Value* getJmpBuf();
llvm::Value* getJmpBufExt();
llvm::Function* m_longjmp = nullptr;
llvm::Value* const m_jmpBuf;
llvm::Value* m_dataPtr = 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 "RuntimeManager.h"
#include "Runtime.h"
#include "Type.h"
#include "preprocessor/llvm_includes_start.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
{
@ -27,18 +28,87 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager):
llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr};
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};
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);
}
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)
{
m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
return m_builder.CreateLoad(m_arg);
auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()});
return m_builder.CreateLoad(valuePtr);
}
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)
{
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)
@ -69,13 +139,14 @@ extern "C"
{
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();
if (stack.size() < _count)
longjmp(_rt->getJmpBuf(), static_cast<int>(ReturnCode::StackTooSmall));
return false;
stack.erase(stack.end() - _count, stack.end());
return true;
}
EXPORT void stack_push(Runtime* _rt, i256 const* _word)
@ -87,22 +158,18 @@ extern "C"
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();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(_rt->getJmpBuf(), static_cast<int>(ReturnCode::StackTooSmall));
*o_ret = *(stack.rbegin() + _index);
return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr;
}
EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word)
{
auto& stack = _rt->getStack();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(_rt->getJmpBuf(), static_cast<int>(ReturnCode::StackTooSmall));
assert(_index < stack.size());
if (_index >= stack.size())
return;
*(stack.rbegin() + _index) = *_word;
}

9
evmjit/libevmjit/Stack.h

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

11
evmjit/libevmjit/Type.cpp

@ -1,8 +1,4 @@
#include "Type.h"
#include <llvm/IR/DerivedTypes.h>
#include "RuntimeManager.h"
namespace dev
@ -17,6 +13,8 @@ llvm::PointerType* Type::WordPtr;
llvm::IntegerType* Type::lowPrecision;
llvm::IntegerType* Type::Bool;
llvm::IntegerType* Type::Size;
llvm::IntegerType* Type::Gas;
llvm::PointerType* Type::GasPtr;
llvm::IntegerType* Type::Byte;
llvm::PointerType* Type::BytePtr;
llvm::Type* Type::Void;
@ -24,6 +22,7 @@ llvm::IntegerType* Type::MainReturn;
llvm::PointerType* Type::EnvPtr;
llvm::PointerType* Type::RuntimeDataPtr;
llvm::PointerType* Type::RuntimePtr;
llvm::ConstantInt* Constant::gasMax;
void Type::init(llvm::LLVMContext& _context)
{
@ -35,6 +34,8 @@ void Type::init(llvm::LLVMContext& _context)
// TODO: Size should be architecture-dependent
Bool = llvm::Type::getInt1Ty(_context);
Size = llvm::Type::getInt64Ty(_context);
Gas = Size;
GasPtr = Gas->getPointerTo();
Byte = llvm::Type::getInt8Ty(_context);
BytePtr = Byte->getPointerTo();
Void = llvm::Type::getVoidTy(_context);
@ -43,6 +44,8 @@ void Type::init(llvm::LLVMContext& _context)
EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo();
RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->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
#include "preprocessor/llvm_includes_start.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"
namespace dev
@ -23,6 +25,8 @@ struct Type
static llvm::IntegerType* Bool;
static llvm::IntegerType* Size;
static llvm::IntegerType* Gas;
static llvm::PointerType* GasPtr;
static llvm::IntegerType* Byte;
static llvm::PointerType* BytePtr;
@ -41,6 +45,8 @@ struct Type
struct Constant
{
static llvm::ConstantInt* gasMax;
/// Returns word-size constant
static llvm::ConstantInt* get(int64_t _n);
static llvm::ConstantInt* get(llvm::APInt const& _n);

1
evmjit/libevmjit/Utils.cpp

@ -1,4 +1,3 @@
#include "Utils.h"
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::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
{
// TODO: Make sure ExecutionEngine constructor does not throw
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
{
if (!_engine || !_data)
return static_cast<int>(ReturnCode::UnexpectedException);
try
{
auto codePtr = _data->code;
auto codeSize = _data->codeSize;
bytes bytecode;
bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize);
auto returnCode = _engine->run(bytecode, _data, _env);
auto returnCode = _engine->run(_data, _env);
return static_cast<int>(returnCode);
}
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)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE exp)

6
exp/main.cpp

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

2
extdep/CMakeLists.txt

@ -7,7 +7,7 @@ include(eth_download.cmake)
# all dependencies will be installed into this directory, separated by platform
string(TOLOWER ${CMAKE_SYSTEM_NAME} _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}/include)
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)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE devcore)

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using 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); }
/// @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.
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())
{
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;
if (m_listStack.back().first)
break;

4
libdevcore/RLP.h

@ -242,7 +242,9 @@ public:
AllowNonCanon = 1,
ThrowOnFail = 4,
FailIfTooBig = 8,
FailIfTooSmall = 16,
Strict = ThrowOnFail | FailIfTooBig,
VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall,
LaisezFaire = AllowNonCanon
};
@ -269,7 +271,7 @@ public:
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)
BOOST_THROW_EXCEPTION(BadCast());
else

2
libdevcore/Worker.h

@ -64,7 +64,7 @@ protected:
private:
std::string m_name;
unsigned m_idleWaitMs;
unsigned m_idleWaitMs = 0;
mutable Mutex x_work; ///< Lock for the network existance.
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(_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::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {}
#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); }
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)); }
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; }
size_t count() const { return m_count; }

2
libdevcrypto/CMakeLists.txt

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

2
libdevcrypto/Common.cpp

@ -44,6 +44,8 @@ bool dev::SignatureStruct::isValid() const
return true;
}
Address dev::ZeroAddress = Address();
Public dev::toPublic(Secret const& _secret)
{
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.
using Address = h160;
/// The zero address.
extern Address ZeroAddress;
/// A vector of Ethereum addresses.
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)
{
// 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)

6
libdevcrypto/TrieDB.h

@ -161,7 +161,7 @@ public:
std::string at(bytesConstRef _key) const;
void insert(bytesConstRef _key, bytesConstRef _value);
void remove(bytesConstRef _key);
void contains(bytesConstRef _key) { return !at(_key).empty(); }
bool contains(bytesConstRef _key) { return !at(_key).empty(); }
class iterator
{
@ -809,7 +809,10 @@ template <class DB> bytes GenericTrieDB<DB>::deleteAt(RLP const& _orig, NibbleSl
// exactly our node - return null.
if (k == _k && isLeaf(_orig))
{
killNode(_orig);
return RLPNull;
}
// partial key is our key - move down.
if (_k.contains(k))
@ -917,7 +920,6 @@ template <class DB> bytes GenericTrieDB<DB>::place(RLP const& _orig, NibbleSlice
tdebug << "place " << _orig << _k;
#endif
killNode(_orig);
if (_orig.isEmpty())
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];
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);
if (!root[1].isList())
@ -157,8 +157,8 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
{
bytes k = rlp(i);
t.insert(&k, tr.data());
u256 gp = tr[1].toInt<u256>();
mgp = min(mgp, gp);
u256 gasprice = tr[1].toInt<u256>();
mgp = min(mgp, gasprice); // the minimum gas price is not used for anything //TODO delete?
++i;
}
if (transactionsRoot != t.root())

2
libethcore/CMakeLists.txt

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

2
libethcore/CommonEth.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 53;
const unsigned c_protocolVersion = 54;
const unsigned c_databaseVersion = 5;
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; };
struct DuplicateUncleNonce: 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; };
struct InvalidTransaction: 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> 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));
bigint d = (bigint(1) << 256) / _difficulty;

3
libethereum/BlockChain.cpp

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

3
libethereum/BlockQueue.cpp

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

34
libethereum/CanonBlockChain.cpp

@ -21,6 +21,7 @@
#include "CanonBlockChain.h"
#include <test/JsonSpiritHeaders.h>
#include <boost/filesystem.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
@ -29,13 +30,13 @@
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
#include <liblll/Compiler.h>
#include <libsolidity/CompilerStack.h>
#include "GenesisInfo.h"
#include "State.h"
#include "Defaults.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::solidity;
namespace js = json_spirit;
#define ETH_CATCH 1
@ -45,20 +46,25 @@ std::map<Address, Account> const& dev::eth::genesisState()
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(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;
}

14
libethereum/Client.cpp

@ -714,6 +714,20 @@ BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
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 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 <> 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<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)
{
@ -229,6 +229,8 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); }
virtual Transaction transaction(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.
using Interface::diff;

2
libethereum/EthereumHost.h

@ -94,7 +94,7 @@ private:
h256Set neededBlocks(h256Set const& _exclude);
/// 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.
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 Transaction transaction(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]:

13
libethereum/State.cpp

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

2
libethereum/State.h

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

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

Loading…
Cancel
Save