Browse Source

Merge remote-tracking branch 'up/develop' into deploydialog

cl-refactor
yann300 9 years ago
parent
commit
963460b4d8
  1. 15
      CMakeLists.txt
  2. 5
      alethzero/CMakeLists.txt
  3. 105
      alethzero/DownloadView.cpp
  4. 13
      alethzero/DownloadView.h
  5. 10
      alethzero/ExportState.cpp
  6. 16
      alethzero/Main.ui
  7. 25
      alethzero/MainWin.cpp
  8. 1
      alethzero/MainWin.h
  9. 5
      alethzero/OurWebThreeStubServer.cpp
  10. 2
      alethzero/OurWebThreeStubServer.h
  11. 3
      cmake/EthCompilerSettings.cmake
  12. 24
      eth/main.cpp
  13. 39
      ethminer/MinerAux.h
  14. 2
      exp/main.cpp
  15. 35
      libdevcore/Base64.cpp
  16. 2
      libdevcore/Common.cpp
  17. 25
      libdevcore/FixedHash.h
  18. 14
      libdevcore/RangeMask.h
  19. 22
      libdevcore/TrieCommon.h
  20. 162
      libdevcore/TrieDB.h
  21. 18
      libdevcrypto/Common.cpp
  22. 3
      libdevcrypto/Common.h
  23. 1
      libethash-cl/CMakeLists.txt
  24. 68
      libethash-cl/ethash_cl_miner.cpp
  25. 16
      libethash-cl/ethash_cl_miner.h
  26. 16
      libethcore/Common.h
  27. 30
      libethcore/Ethash.cpp
  28. 11
      libethcore/Ethash.h
  29. 14
      libethcore/Transaction.cpp
  30. 4
      libethcore/Transaction.h
  31. 4
      libethereum/Account.h
  32. 66
      libethereum/BlockChain.cpp
  33. 6
      libethereum/BlockChain.h
  34. 14
      libethereum/BlockChainSync.cpp
  35. 5
      libethereum/BlockChainSync.h
  36. 4
      libethereum/BlockDetails.h
  37. 4
      libethereum/BlockQueue.cpp
  38. 8
      libethereum/BlockQueue.h
  39. 13
      libethereum/Client.cpp
  40. 6
      libethereum/Client.h
  41. 46
      libethereum/ClientBase.cpp
  42. 12
      libethereum/ClientBase.h
  43. 10
      libethereum/DownloadMan.cpp
  44. 25
      libethereum/DownloadMan.h
  45. 83
      libethereum/EthereumHost.cpp
  46. 4
      libethereum/EthereumHost.h
  47. 9
      libethereum/Executive.cpp
  48. 4
      libethereum/Executive.h
  49. 18
      libethereum/ExtVM.cpp
  50. 29
      libethereum/Interface.cpp
  51. 13
      libethereum/Interface.h
  52. 30
      libethereum/State.cpp
  53. 2
      libethereum/State.h
  54. 7
      libethereum/Transaction.h
  55. 153
      libethereum/TransactionQueue.cpp
  56. 48
      libethereum/TransactionQueue.h
  57. 2
      libethereum/VerifiedBlock.h
  58. 6
      libevm/ExtVMFace.cpp
  59. 2
      libevm/ExtVMFace.h
  60. 1
      libjsengine/CMakeLists.txt
  61. 5
      libp2p/Host.h
  62. 5
      libp2p/Session.cpp
  63. 4
      libtestutils/StateLoader.cpp
  64. 10
      libweb3jsonrpc/AccountHolder.cpp
  65. 6
      libweb3jsonrpc/AccountHolder.h
  66. 30
      libweb3jsonrpc/JsonHelper.cpp
  67. 3
      libweb3jsonrpc/JsonHelper.h
  68. 27
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  69. 1
      libweb3jsonrpc/WebThreeStubServerBase.h
  70. 6
      libweb3jsonrpc/abstractwebthreestubserver.h
  71. 1
      libweb3jsonrpc/spec.json
  72. 5
      mix/CMakeLists.txt
  73. 3
      mix/ClientModel.cpp
  74. 2
      mix/ClientModel.h
  75. 8
      mix/DebuggingStateWrapper.h
  76. 2
      mix/HttpServer.h
  77. 28
      mix/MixClient.cpp
  78. 9
      mix/MixClient.h
  79. 8
      neth/main.cpp
  80. 4
      test/TestHelper.cpp
  81. 146
      test/libdevcore/FixedHash.cpp
  82. 41
      test/libdevcore/core.cpp
  83. 2
      test/libdevcrypto/AES.cpp
  84. 277
      test/libethereum/BlockchainTestsFiller/bcBlockGasLimitTestFiller.json
  85. 854
      test/libethereum/StateTestsFiller/stPreCompiledContractsTransactionFiller.json
  86. 6
      test/libethereum/blockchain.cpp
  87. 5
      test/libethereum/state.cpp
  88. 248
      test/libsolidity/SolidityWallet.cpp
  89. 10
      test/libweb3jsonrpc/webthreestubclient.h

15
CMakeLists.txt

@ -203,7 +203,9 @@ eth_format_option(ROCKSDB)
eth_format_option(GUI) eth_format_option(GUI)
eth_format_option(TESTS) eth_format_option(TESTS)
eth_format_option(NOBOOST) eth_format_option(NOBOOST)
eth_format_option(ROCKSDB)
eth_format_option(TOOLS) eth_format_option(TOOLS)
eth_format_option(ETHKEY)
eth_format_option(ETHASHCL) eth_format_option(ETHASHCL)
eth_format_option(JSCONSOLE) eth_format_option(JSCONSOLE)
eth_format_option_on_decent_platform(SERPENT) eth_format_option_on_decent_platform(SERPENT)
@ -234,6 +236,15 @@ elseif (BUNDLE STREQUAL "full")
set(TOOLS ON) set(TOOLS ON)
set(TESTS ON) set(TESTS ON)
set(FATDB ON) set(FATDB ON)
elseif (BUNDLE STREQUAL "cli")
set(SERPENT ${DECENT_PLATFORM})
set(SOLIDITY ON)
set(USENPM ON)
set(GUI OFF)
# set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS ON)
set(FATDB ON)
elseif (BUNDLE STREQUAL "core") elseif (BUNDLE STREQUAL "core")
set(SERPENT OFF) set(SERPENT OFF)
set(SOLIDITY ON) set(SOLIDITY ON)
@ -312,6 +323,7 @@ message("-- Hardware identification support ${CPUID_FO
message("-- HTTP Request support ${CURL_FOUND}") message("-- HTTP Request support ${CURL_FOUND}")
message("-- VMTRACE VM execution tracing ${VMTRACE}") message("-- VMTRACE VM execution tracing ${VMTRACE}")
message("-- PROFILING Profiling support ${PROFILING}") message("-- PROFILING Profiling support ${PROFILING}")
message("-- NOBOOST No BOOST macros in test functions ${NOBOOST}")
message("-- FATDB Full database exploring ${FATDB}") message("-- FATDB Full database exploring ${FATDB}")
message("-- JSONRPC JSON-RPC support ${JSONRPC}") message("-- JSONRPC JSON-RPC support ${JSONRPC}")
message("-- USENPM Javascript source building ${USENPM}") message("-- USENPM Javascript source building ${USENPM}")
@ -325,7 +337,6 @@ message("-- SERPENT Build Serpent language components ${SERPENT}
message("-- GUI Build GUI components ${GUI}") message("-- GUI Build GUI components ${GUI}")
message("-- NCURSES Build NCurses components ${NCURSES}") message("-- NCURSES Build NCurses components ${NCURSES}")
message("-- TESTS Build tests ${TESTS}") message("-- TESTS Build tests ${TESTS}")
message("-- NOBOOST No BOOST macros in test functions ${NOBOOST}")
message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}") message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}")
message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}") message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}")
message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}") message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}")
@ -362,8 +373,6 @@ else ()
set(GENERAL 0) set(GENERAL 0)
endif () endif ()
message("GENERAL ${GENERAL}")
add_subdirectory(libdevcore) add_subdirectory(libdevcore)
if (GENERAL) if (GENERAL)
add_subdirectory(libevmcore) add_subdirectory(libevmcore)

5
alethzero/CMakeLists.txt

@ -7,6 +7,11 @@ if (${CMAKE_MAJOR_VERSION} GREATER 2)
cmake_policy(SET CMP0043 OLD) cmake_policy(SET CMP0043 OLD)
endif() endif()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
# Supress warnings for qt headers for clang+ccache
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override")
endif ()
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)

105
alethzero/DownloadView.cpp

@ -30,29 +30,118 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
DownloadView::DownloadView(QWidget* _p): QWidget(_p) SyncView::SyncView(QWidget* _p): QWidget(_p)
{ {
} }
void DownloadView::paintEvent(QPaintEvent*) void SyncView::paintEvent(QPaintEvent*)
{ {
QPainter p(this); QPainter p(this);
p.fillRect(rect(), Qt::white); p.fillRect(rect(), Qt::white);
if (!m_man || m_man->chainEmpty() || !m_man->subCount())
if (!m_client)
return;
DownloadMan const* man = m_client->downloadMan();
BlockQueueStatus bqs = m_client->blockQueueStatus();
SyncStatus sync = m_client->syncStatus();
unsigned syncFrom = m_client->numberFromHash(PendingBlockHash);
unsigned syncImported = syncFrom;
unsigned syncImporting = syncImported + bqs.importing;
unsigned syncVerified = syncImporting + bqs.verified;
unsigned syncVerifying = syncVerified + bqs.verifying;
unsigned syncUnverified = syncVerifying + bqs.unverified;
unsigned syncCount = syncUnverified + bqs.unknown - syncFrom;
// best effort guess. assumes there's no forks.
unsigned downloadFrom = m_client->numberFromHash(m_client->isKnown(man->firstBlock()) ? man->firstBlock() : PendingBlockHash);
unsigned downloadCount = sync.blocksTotal;
DownloadMan::Overview overview = man->overview();
unsigned downloadDone = downloadFrom + overview.total;
unsigned downloadFlank = downloadFrom + overview.firstIncomplete;
unsigned downloadPoint = downloadFrom + overview.lastComplete;
unsigned hashFrom = sync.state == SyncState::Hashes ? m_client->numberFromHash(PendingBlockHash) : downloadFrom;
unsigned hashCount = sync.state == SyncState::Hashes ? sync.hashesTotal : downloadCount;
unsigned hashDone = hashFrom + (sync.state == SyncState::Hashes ? sync.hashesReceived : hashCount);
m_lastFrom = min(syncFrom, m_lastFrom);
m_lastTo = max(max(syncFrom + syncCount, hashFrom + hashCount), m_lastTo);
unsigned from = min(min(hashFrom, downloadFrom), min(syncFrom, m_lastFrom));
unsigned count = max(max(hashFrom + hashCount, downloadFrom + downloadCount), max(syncFrom + syncCount, m_lastTo)) - from;
m_lastFrom = (m_lastFrom * 99 + syncFrom * 1) / 100;
m_lastTo = (m_lastTo * 99 + max(syncFrom + syncCount, hashFrom + hashCount) * 1) / 100;
if (!count)
{
m_lastFrom = m_lastTo = (unsigned)-1;
return;
}
cnote << "Range " << from << "-" << (from + count) << "(" << hashFrom << "+" << hashCount << "," << downloadFrom << "+" << downloadCount << "," << syncFrom << "+" << syncCount << ")";
auto r = [&](unsigned u) {
return toString((u - from) * 100 / count) + "%";
};
if (count)
{
cnote << "Hashes:" << r(hashDone) << " Blocks:" << r(downloadFlank) << r(downloadDone) << r(downloadPoint);
cnote << "Importing:" << r(syncFrom) << r(syncImported) << r(syncImporting) << r(syncVerified) << r(syncVerifying) << r(syncUnverified);
}
float squareSize = min(rect().width(), rect().height());
QPen pen;
pen.setCapStyle(Qt::FlatCap);
pen.setWidthF(squareSize / 20);
auto middle = [&](float x) {
return QRectF(squareSize / 2 - squareSize / 2 * x, 0 + squareSize / 2 - squareSize / 2 * x, squareSize * x, squareSize * x);
};
auto arcLen = [&](unsigned x) {
return x * -5760.f / count;
};
auto arcPos = [&](unsigned x) {
return int(90 * 16.f + arcLen(x - from)) % 5760;
};
p.setPen(Qt::NoPen);
p.setBrush(QColor::fromHsv(0, 0, 210));
pen.setWidthF(0.f);
p.drawPie(middle(0.4f), arcPos(from), arcLen(hashDone - from));
auto progress = [&](unsigned h, unsigned s, unsigned v, float size, float thickness, unsigned nfrom, unsigned ncount) {
p.setBrush(Qt::NoBrush);
pen.setColor(QColor::fromHsv(h, s, v));
pen.setWidthF(squareSize * thickness);
p.setPen(pen);
p.drawArc(middle(size), arcPos(nfrom), arcLen(ncount));
};
progress(0, 50, 170, 0.4f, 0.12f, downloadFlank, downloadPoint - downloadFlank);
progress(0, 0, 150, 0.4f, 0.10f, from, downloadDone - from);
progress(0, 0, 230, 0.7f, 0.090f, from, syncUnverified - from);
progress(60, 25, 210, 0.7f, 0.08f, from, syncVerifying - from);
progress(120, 25, 190, 0.7f, 0.07f, from, syncVerified - from);
progress(0, 0, 220, 0.9f, 0.02f, from, count);
progress(0, 0, 100, 0.9f, 0.04f, from, syncFrom - from);
progress(0, 50, 100, 0.9f, 0.08f, syncFrom, syncImporting - syncFrom);
return; return;
double ratio = (double)rect().width() / rect().height(); double ratio = (double)rect().width() / rect().height();
if (ratio < 1) if (ratio < 1)
ratio = 1 / ratio; ratio = 1 / ratio;
double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chainSize() / ratio))); double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(man->chainSize() / ratio)));
// QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n)); // QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n));
QSizeF area(n, n); QSizeF area(n, n);
QPointF pos(0, 0); QPointF pos(0, 0);
auto bg = m_man->blocksGot(); auto bg = man->blocksGot();
unsigned subCount = m_man->subCount(); unsigned subCount = man->subCount();
if (subCount == 0) if (subCount == 0)
return; return;
unsigned dh = 360 / subCount; unsigned dh = 360 / subCount;
@ -64,7 +153,7 @@ void DownloadView::paintEvent(QPaintEvent*)
else else
{ {
unsigned h = 0; unsigned h = 0;
m_man->foreachSub([&](DownloadSub const& sub) man->foreachSub([&](DownloadSub const& sub)
{ {
if (sub.askedContains(i)) if (sub.askedContains(i))
s = h; s = h;

13
alethzero/DownloadView.h

@ -32,21 +32,24 @@
#endif #endif
namespace dev { namespace eth { namespace dev { namespace eth {
class DownloadMan; class Client;
}} }}
class DownloadView: public QWidget class SyncView: public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
DownloadView(QWidget* _p = nullptr); SyncView(QWidget* _p = nullptr);
void setDownloadMan(dev::eth::DownloadMan const* _man) { m_man = _man; } void setEthereum(dev::eth::Client const* _c) { m_client = _c; }
protected: protected:
virtual void paintEvent(QPaintEvent*); virtual void paintEvent(QPaintEvent*);
private: private:
dev::eth::DownloadMan const* m_man = nullptr; dev::eth::Client const* m_client = nullptr;
unsigned m_lastFrom = (unsigned)-1;
unsigned m_lastTo = (unsigned)-1;
}; };

10
alethzero/ExportState.cpp

@ -127,6 +127,8 @@ void ExportStateDialog::fillContracts()
ui->contracts->clear(); ui->contracts->clear();
ui->accounts->setEnabled(true); ui->accounts->setEnabled(true);
ui->contracts->setEnabled(true); ui->contracts->setEnabled(true);
try
{
for (auto i: ethereum()->addresses(m_block)) for (auto i: ethereum()->addresses(m_block))
{ {
string r = m_main->render(i); string r = m_main->render(i);
@ -134,6 +136,14 @@ void ExportStateDialog::fillContracts()
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
} }
} }
catch (InterfaceNotSupported const&)
{
ui->accounts->setEnabled(false);
ui->contracts->setEnabled(false);
ui->json->setEnabled(false);
ui->json->setText(QString("This feature requires compilation with FATDB support."));
}
}
void ExportStateDialog::generateJSON() void ExportStateDialog::generateJSON()
{ {

16
alethzero/Main.ui

@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>AlethZero Ethereum Client</string> <string>AlethZero ++Ethereum</string>
</property> </property>
<property name="dockNestingEnabled"> <property name="dockNestingEnabled">
<bool>true</bool> <bool>true</bool>
@ -132,7 +132,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1617</width> <width>1617</width>
<height>25</height> <height>24</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menu_File"> <widget class="QMenu" name="menu_File">
@ -199,6 +199,7 @@
<addaction name="usePrivate"/> <addaction name="usePrivate"/>
<addaction name="retryUnknown"/> <addaction name="retryUnknown"/>
<addaction name="confirm"/> <addaction name="confirm"/>
<addaction name="rewindChain"/>
</widget> </widget>
<widget class="QMenu" name="menu_View"> <widget class="QMenu" name="menu_View">
<property name="title"> <property name="title">
@ -707,7 +708,7 @@
</layout> </layout>
</widget> </widget>
</widget> </widget>
<widget class="QDockWidget" name="dockWidget_8"> <widget class="QDockWidget" name="blockChainDockWidget">
<property name="features"> <property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set> <set>QDockWidget::DockWidgetFeatureMask</set>
</property> </property>
@ -1149,7 +1150,7 @@ font-size: 14pt</string>
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="DownloadView" name="downloadView" native="true"/> <widget class="SyncView" name="downloadView" native="true"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1804,6 +1805,11 @@ font-size: 14pt</string>
<string>&amp;Sentinel...</string> <string>&amp;Sentinel...</string>
</property> </property>
</action> </action>
<action name="rewindChain">
<property name="text">
<string>&amp;Rewind Chain...</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>
@ -1814,7 +1820,7 @@ font-size: 14pt</string>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>DownloadView</class> <class>SyncView</class>
<extends>QWidget</extends> <extends>QWidget</extends>
<header>DownloadView.h</header> <header>DownloadView.h</header>
<container>1</container> <container>1</container>

25
alethzero/MainWin.cpp

@ -136,6 +136,12 @@ Main::Main(QWidget *parent) :
QtWebEngine::initialize(); QtWebEngine::initialize();
setWindowFlags(Qt::Window); setWindowFlags(Qt::Window);
ui->setupUi(this); ui->setupUi(this);
if (c_network == eth::Network::Olympic)
setWindowTitle("AlethZero Olympic");
else if (c_network == eth::Network::Frontier)
setWindowTitle("AlethZero Frontier");
g_logPost = [=](string const& s, char const* c) g_logPost = [=](string const& s, char const* c)
{ {
simpleDebugOut(s, c); simpleDebugOut(s, c);
@ -260,6 +266,8 @@ Main::Main(QWidget *parent) :
m_transact->setWindowFlags(Qt::Dialog); m_transact->setWindowFlags(Qt::Dialog);
m_transact->setWindowModality(Qt::WindowModal); m_transact->setWindowModality(Qt::WindowModal);
connect(ui->blockChainDockWidget, &QDockWidget::visibilityChanged, [=]() { refreshBlockChain(); });
#if !ETH_FATDB #if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts); removeDockWidget(ui->dockWidget_accounts);
#endif #endif
@ -1036,6 +1044,17 @@ void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter
void Main::on_vmJIT_triggered() { VMFactory::setKind(VMKind::JIT); } void Main::on_vmJIT_triggered() { VMFactory::setKind(VMKind::JIT); }
void Main::on_vmSmart_triggered() { VMFactory::setKind(VMKind::Smart); } void Main::on_vmSmart_triggered() { VMFactory::setKind(VMKind::Smart); }
void Main::on_rewindChain_triggered()
{
bool ok;
int n = QInputDialog::getInt(this, "Rewind Chain", "Enter the number of the new chain head.", ethereum()->number() * 9 / 10, 1, ethereum()->number(), 1, &ok);
if (ok)
{
ethereum()->rewind(n);
refreshAll();
}
}
void Main::on_urlEdit_returnPressed() void Main::on_urlEdit_returnPressed()
{ {
QString s = ui->urlEdit->text(); QString s = ui->urlEdit->text();
@ -1307,7 +1326,7 @@ void Main::on_turboMining_triggered()
void Main::refreshBlockChain() void Main::refreshBlockChain()
{ {
if (!ui->blocks->isVisible() && isVisible()) if (!(ui->blockChainDockWidget->isVisible() || !tabifiedDockWidgets(ui->blockChainDockWidget).isEmpty()))
return; return;
DEV_TIMED_FUNCTION_ABOVE(500); DEV_TIMED_FUNCTION_ABOVE(500);
@ -1985,12 +2004,12 @@ void Main::on_net_triggered()
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked()); web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
web3()->startNetwork(); web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan()); ui->downloadView->setEthereum(ethereum());
ui->enode->setText(QString::fromStdString(web3()->enode())); ui->enode->setText(QString::fromStdString(web3()->enode()));
} }
else else
{ {
ui->downloadView->setDownloadMan(nullptr); ui->downloadView->setEthereum(nullptr);
writeSettings(); writeSettings();
web3()->stopNetwork(); web3()->stopNetwork();
} }

1
alethzero/MainWin.h

@ -187,6 +187,7 @@ private slots:
void on_vmInterpreter_triggered(); void on_vmInterpreter_triggered();
void on_vmJIT_triggered(); void on_vmJIT_triggered();
void on_vmSmart_triggered(); void on_vmSmart_triggered();
void on_rewindChain_triggered();
// Debugger // Debugger
void on_debugCurrent_triggered(); void on_debugCurrent_triggered();

5
alethzero/OurWebThreeStubServer.cpp

@ -99,10 +99,11 @@ bool OurAccountHolder::showUnknownCallNotice(TransactionSkeleton const& _t, bool
"REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!");
} }
void OurAccountHolder::authenticate(TransactionSkeleton const& _t) h256 OurAccountHolder::authenticate(TransactionSkeleton const& _t)
{ {
Guard l(x_queued); Guard l(x_queued);
m_queued.push(_t); m_queued.push(_t);
return h256();
} }
void OurAccountHolder::doValidations() void OurAccountHolder::doValidations()
@ -130,7 +131,7 @@ void OurAccountHolder::doValidations()
else else
// sign and submit. // sign and submit.
if (Secret s = m_main->retrieveSecret(t.from)) if (Secret s = m_main->retrieveSecret(t.from))
m_main->ethereum()->submitTransaction(s, t); m_main->ethereum()->submitTransaction(t, s);
} }
} }

2
alethzero/OurWebThreeStubServer.h

@ -43,7 +43,7 @@ protected:
// easiest to return keyManager.addresses(); // easiest to return keyManager.addresses();
virtual dev::AddressHash realAccounts() const override; virtual dev::AddressHash realAccounts() const override;
// use web3 to submit a signed transaction to accept // use web3 to submit a signed transaction to accept
virtual void authenticate(dev::eth::TransactionSkeleton const& _t) override; virtual dev::h256 authenticate(dev::eth::TransactionSkeleton const& _t) override;
private: private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text); bool showAuthenticationPopup(std::string const& _title, std::string const& _text);

3
cmake/EthCompilerSettings.cmake

@ -49,7 +49,8 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib # warning LNK4099: pdb was not found with lib
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075") # stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
# windows likes static # windows likes static
if (NOT ETH_STATIC) if (NOT ETH_STATIC)

24
eth/main.cpp

@ -37,6 +37,7 @@
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libethereum/BlockChainSync.h>
#include <libethcore/KeyManager.h> #include <libethcore/KeyManager.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
@ -375,6 +376,8 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
cout << "Current block: " << c->blockChain().details().number << endl; cout << "Current block: " << c->blockChain().details().number << endl;
else if (c && cmd == "blockqueue") else if (c && cmd == "blockqueue")
cout << "Current blockqueue status: " << endl << c->blockQueueStatus() << endl; cout << "Current blockqueue status: " << endl << c->blockQueueStatus() << endl;
else if (c && cmd == "sync")
cout << "Current sync status: " << endl << c->syncStatus() << endl;
else if (c && cmd == "hashrate") else if (c && cmd == "hashrate")
cout << "Current hash rate: " << toString(c->hashrate()) << " hashes per second." << endl; cout << "Current hash rate: " << toString(c->hashrate()) << " hashes per second." << endl;
else if (c && cmd == "findblock") else if (c && cmd == "findblock")
@ -1023,9 +1026,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{ {
string path; string path;
iss >> path; iss >> path;
RLPStream config(2); writeFile(path, rlpList(signingKey, beneficiary));
config << signingKey << beneficiary;
writeFile(path, config.out());
} }
else else
cwarn << "Require parameter: exportConfig PATH"; cwarn << "Require parameter: exportConfig PATH";
@ -1468,17 +1469,22 @@ int main(int argc, char** argv)
} }
} }
if (g_logVerbosity > 0)
{
cout << EthGrayBold "(++)Ethereum" EthReset << endl;
if (c_network == eth::Network::Olympic)
cout << "Welcome to Olympic!" << endl;
else if (c_network == eth::Network::Frontier)
cout << "Welcome to the " EthMaroonBold "Frontier" EthReset "!" << endl;
}
m.execute(); m.execute();
KeyManager keyManager; KeyManager keyManager;
for (auto const& s: passwordsToNote) for (auto const& s: passwordsToNote)
keyManager.notePassword(s); keyManager.notePassword(s);
{ writeFile(configFile, rlpList(signingKey, beneficiary));
RLPStream config(2);
config << signingKey << beneficiary;
writeFile(configFile, config.out());
}
if (sessionKey) if (sessionKey)
signingKey = sessionKey; signingKey = sessionKey;
@ -1700,7 +1706,7 @@ int main(int argc, char** argv)
cout << "Transaction Signer: " << signingKey << endl; cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << beneficiary << endl; cout << "Mining Benefactor: " << beneficiary << endl;
if (bootstrap || !remoteHost.empty()) if (bootstrap || !remoteHost.empty() || disableDiscovery)
{ {
web3.startNetwork(); web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl; cout << "Node ID: " << web3.enode() << endl;

39
ethminer/MinerAux.h

@ -128,6 +128,33 @@ public:
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
BOOST_THROW_EXCEPTION(BadArgument()); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--cl-global-work" && i + 1 < argc)
try {
m_globalWorkSizeMultiplier = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
BOOST_THROW_EXCEPTION(BadArgument());
}
else if (arg == "--cl-local-work" && i + 1 < argc)
try {
m_localWorkSize = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
BOOST_THROW_EXCEPTION(BadArgument());
}
else if (arg == "--cl-ms-per-batch" && i + 1 < argc)
try {
m_msPerBatch = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
BOOST_THROW_EXCEPTION(BadArgument());
}
else if (arg == "--list-devices") else if (arg == "--list-devices")
m_shouldListDevices = true; m_shouldListDevices = true;
else if (arg == "--allow-opencl-cpu") else if (arg == "--allow-opencl-cpu")
@ -266,16 +293,16 @@ public:
else if (m_minerType == MinerType::GPU) else if (m_minerType == MinerType::GPU)
{ {
if (!ProofOfWork::GPUMiner::configureGPU( if (!ProofOfWork::GPUMiner::configureGPU(
m_localWorkSize,
m_globalWorkSizeMultiplier,
m_msPerBatch,
m_openclPlatform, m_openclPlatform,
m_openclDevice, m_openclDevice,
m_clAllowCPU, m_clAllowCPU,
m_extraGPUMemory, m_extraGPUMemory,
m_currentBlock m_currentBlock
)) ))
{
cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
exit(1); exit(1);
}
ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); ProofOfWork::GPUMiner::setNumInstances(m_miningThreads);
} }
if (mode == OperationMode::DAGInit) if (mode == OperationMode::DAGInit)
@ -318,6 +345,9 @@ public:
<< " --list-devices List the detected OpenCL devices and exit." << endl << " --list-devices List the detected OpenCL devices and exit." << endl
<< " --current-block Let the miner know the current block number at configuration time. Will help determine DAG size and required GPU memory." << endl << " --current-block Let the miner know the current block number at configuration time. Will help determine DAG size and required GPU memory." << endl
<< " --cl-extragpu-mem Set the memory (in MB) you believe your GPU requires for stuff other than mining. Windows rendering e.t.c.." << endl << " --cl-extragpu-mem Set the memory (in MB) you believe your GPU requires for stuff other than mining. Windows rendering e.t.c.." << endl
<< " --cl-local-work Set the OpenCL local work size. Default is " << toString(dev::eth::Ethash::defaultLocalWorkSize) << endl
<< " --cl-global-work Set the OpenCL global work size as a multiple of the local work size. Default is " << toString(dev::eth::Ethash::defaultGlobalWorkSizeMultiplier) << " * " << toString(dev::eth::Ethash::defaultLocalWorkSize) << endl
<< " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(dev::eth::Ethash::defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl
; ;
} }
@ -506,6 +536,9 @@ private:
unsigned m_miningThreads = UINT_MAX; unsigned m_miningThreads = UINT_MAX;
bool m_shouldListDevices = false; bool m_shouldListDevices = false;
bool m_clAllowCPU = false; bool m_clAllowCPU = false;
unsigned m_globalWorkSizeMultiplier = dev::eth::Ethash::defaultGlobalWorkSizeMultiplier;
unsigned m_localWorkSize = dev::eth::Ethash::defaultLocalWorkSize;
unsigned m_msPerBatch = dev::eth::Ethash::defaultMSPerBatch;
boost::optional<uint64_t> m_currentBlock; boost::optional<uint64_t> m_currentBlock;
// default value is 350MB of GPU memory for other stuff (windows system rendering, e.t.c.) // default value is 350MB of GPU memory for other stuff (windows system rendering, e.t.c.)
unsigned m_extraGPUMemory = 350000000; unsigned m_extraGPUMemory = 350000000;

2
exp/main.cpp

@ -135,7 +135,7 @@ int main()
DownloadSub s0(man); DownloadSub s0(man);
DownloadSub s1(man); DownloadSub s1(man);
DownloadSub s2(man); DownloadSub s2(man);
man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)})); man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)}), 0);
assert((s0.nextFetch(2) == h256Set{(u256)7, (u256)8})); assert((s0.nextFetch(2) == h256Set{(u256)7, (u256)8}));
assert((s1.nextFetch(2) == h256Set{(u256)5, (u256)6})); assert((s1.nextFetch(2) == h256Set{(u256)5, (u256)6}));
assert((s2.nextFetch(2) == h256Set{(u256)3, (u256)4})); assert((s2.nextFetch(2) == h256Set{(u256)3, (u256)4}));

35
libdevcore/Base64.cpp

@ -27,6 +27,8 @@
/// Originally by René Nyffenegger, modified by some other guy and then devified by Gav Wood. /// Originally by René Nyffenegger, modified by some other guy and then devified by Gav Wood.
#include "Base64.h" #include "Base64.h"
using namespace std;
using namespace dev; using namespace dev;
static inline bool is_base64(byte c) static inline bool is_base64(byte c)
@ -44,14 +46,14 @@ static inline byte find_base64_char_index(byte c)
else return 1 + find_base64_char_index('/'); else return 1 + find_base64_char_index('/');
} }
std::string dev::toBase64(bytesConstRef _in) string dev::toBase64(bytesConstRef _in)
{ {
static const char base64_chars[] = static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; "0123456789+/";
std::string ret; string ret;
int i = 0; int i = 0;
int j = 0; int j = 0;
byte char_array_3[3]; byte char_array_3[3];
@ -60,15 +62,17 @@ std::string dev::toBase64(bytesConstRef _in)
auto buf = _in.data(); auto buf = _in.data();
auto bufLen = _in.size(); auto bufLen = _in.size();
while (bufLen--) { while (bufLen--)
{
char_array_3[i++] = *(buf++); char_array_3[i++] = *(buf++);
if (i == 3) { if (i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f; char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++) for (i = 0; i < 4; i++)
ret += base64_chars[char_array_4[i]]; ret += base64_chars[char_array_4[i]];
i = 0; i = 0;
} }
@ -84,28 +88,31 @@ std::string dev::toBase64(bytesConstRef _in)
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f; char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++) for (j = 0; j < i + 1; j++)
ret += base64_chars[char_array_4[j]]; ret += base64_chars[char_array_4[j]];
while((i++ < 3)) while (i++ < 3)
ret += '='; ret += '=';
} }
return ret; return ret;
} }
bytes dev::fromBase64(std::string const& encoded_string) bytes dev::fromBase64(string const& encoded_string)
{ {
auto in_len = encoded_string.size(); auto in_len = encoded_string.size();
int i = 0; int i = 0;
int j = 0; int j = 0;
int in_ = 0; int in_ = 0;
byte char_array_4[4], char_array_3[3]; byte char_array_3[3];
byte char_array_4[4];
bytes ret; bytes ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { while (in_len-- && encoded_string[in_] != '=' && is_base64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++; char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) { if (i == 4)
{
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
char_array_4[i] = find_base64_char_index(char_array_4[i]); char_array_4[i] = find_base64_char_index(char_array_4[i]);
@ -119,7 +126,8 @@ bytes dev::fromBase64(std::string const& encoded_string)
} }
} }
if (i) { if (i)
{
for (j = i; j < 4; j++) for (j = i; j < 4; j++)
char_array_4[j] = 0; char_array_4[j] = 0;
@ -130,7 +138,8 @@ bytes dev::fromBase64(std::string const& encoded_string)
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]); for (j = 0; j < i - 1; j++)
ret.push_back(char_array_3[j]);
} }
return ret; return ret;

2
libdevcore/Common.cpp

@ -28,7 +28,7 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.9.28"; char const* Version = "0.9.29";
const u256 UndefinedU256 = ~(u256)0; const u256 UndefinedU256 = ~(u256)0;

25
libdevcore/FixedHash.h

@ -24,6 +24,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include <cstdint>
#include <random> #include <random>
#include <algorithm> #include <algorithm>
#include "CommonData.h" #include "CommonData.h"
@ -31,6 +32,10 @@
namespace dev namespace dev
{ {
/// Compile-time calculation of Log2 of constant values.
template <unsigned N> struct StaticLog2 { enum { result = 1 + StaticLog2<N/2>::result }; };
template <> struct StaticLog2<1> { enum { result = 0 }; };
extern std::random_device s_fixedHashEngine; extern std::random_device s_fixedHashEngine;
/// Fixed-size raw-byte array container type, with an API optimised for storing hashes. /// Fixed-size raw-byte array container type, with an API optimised for storing hashes.
@ -77,7 +82,7 @@ public:
explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); } explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }
/// Explicitly construct, copying from a string. /// Explicitly construct, copying from a string.
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s) : dev::asBytes(_s), _ht) {} explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : dev::asBytes(_s), _ht) {}
/// Convert to arithmetic type. /// Convert to arithmetic type.
operator Arith() const { return fromBigEndian<Arith>(m_data); } operator Arith() const { return fromBigEndian<Arith>(m_data); }
@ -101,8 +106,9 @@ public:
FixedHash& operator&=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; } FixedHash& operator&=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; }
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; } FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; } FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; }
FixedHash& operator++() { for (unsigned i = size; i > 0 && !++m_data[--i]; ) {} return *this; }
/// @returns true if all bytes in @a _c are set in this object. /// @returns true if all one-bits in @a _c are set in this object.
bool contains(FixedHash const& _c) const { return (*this & _c) == _c; } bool contains(FixedHash const& _c) const { return (*this & _c) == _c; }
/// @returns a particular byte from the hash. /// @returns a particular byte from the hash.
@ -146,7 +152,7 @@ public:
{ {
FixedHash ret; FixedHash ret;
for (auto& i: ret.m_data) for (auto& i: ret.m_data)
i = std::uniform_int_distribution<uint16_t>(0, 255)(_eng); i = (uint8_t)std::uniform_int_distribution<uint16_t>(0, 255)(_eng);
return ret; return ret;
} }
@ -171,18 +177,21 @@ public:
template <unsigned P, unsigned M> inline FixedHash<M> bloomPart() const template <unsigned P, unsigned M> inline FixedHash<M> bloomPart() const
{ {
unsigned const c_bloomBits = M * 8;
unsigned const c_mask = c_bloomBits - 1;
unsigned const c_bloomBytes = (StaticLog2<c_bloomBits>::result + 7) / 8;
static_assert((M & (M - 1)) == 0, "M must be power-of-two"); static_assert((M & (M - 1)) == 0, "M must be power-of-two");
static const unsigned c_bloomBits = M * 8; static_assert(P * c_bloomBytes <= N, "out of range");
unsigned mask = c_bloomBits - 1;
unsigned bloomBytes = (dev::toLog2(c_bloomBits) + 7) / 8;
FixedHash<M> ret; FixedHash<M> ret;
byte const* p = data(); byte const* p = data();
for (unsigned i = 0; i < P; ++i) for (unsigned i = 0; i < P; ++i)
{ {
unsigned index = 0; unsigned index = 0;
for (unsigned j = 0; j < bloomBytes; ++j, ++p) for (unsigned j = 0; j < c_bloomBytes; ++j, ++p)
index = (index << 8) | *p; index = (index << 8) | *p;
index &= mask; index &= c_mask;
ret[M - 1 - index / 8] |= (1 << (index % 8)); ret[M - 1 - index / 8] |= (1 << (index % 8));
} }
return ret; return ret;

14
libdevcore/RangeMask.h

@ -200,6 +200,20 @@ public:
return c; return c;
} }
size_t firstOut() const
{
if (m_ranges.empty() || !m_ranges.count(m_all.first))
return m_all.first;
return m_ranges.at(m_all.first);
}
size_t lastIn() const
{
if (m_ranges.empty())
return m_all.first;
return m_ranges.rbegin()->second - 1;
}
private: private:
/// The ground range. /// The ground range.
UnsignedRange m_all; UnsignedRange m_all;

22
libdevcore/TrieCommon.h

@ -32,26 +32,38 @@ inline byte nibble(bytesConstRef _data, unsigned _i)
return (_i & 1) ? (_data[_i / 2] & 15) : (_data[_i / 2] >> 4); return (_i & 1) ? (_data[_i / 2] & 15) : (_data[_i / 2] >> 4);
} }
inline unsigned sharedNibbles(bytesConstRef _a, unsigned _ab, unsigned _ae, bytesConstRef _b, unsigned _bb, unsigned _be) /// Interprets @a _first and @a _second as vectors of nibbles and returns the length of the longest common
/// prefix of _first[_beginFirst..._endFirst] and _second[_beginSecond..._endSecond].
inline unsigned sharedNibbles(bytesConstRef _first, unsigned _beginFirst, unsigned _endFirst, bytesConstRef _second, unsigned _beginSecond, unsigned _endSecond)
{ {
unsigned ret = 0; unsigned ret = 0;
for (unsigned ai = _ab, bi = _bb; ai < _ae && bi < _be && nibble(_a, ai) == nibble(_b, bi); ++ai, ++bi, ++ret) {} while (_beginFirst < _endFirst && _beginSecond < _endSecond && nibble(_first, _beginFirst) == nibble(_second, _beginSecond))
{
++_beginFirst;
++_beginSecond;
++ret;
}
return ret; return ret;
} }
/**
* Nibble-based view on a bytesConstRef.
*/
struct NibbleSlice struct NibbleSlice
{ {
bytesConstRef data; bytesConstRef data;
unsigned offset; unsigned offset;
NibbleSlice(bytesConstRef _d = bytesConstRef(), unsigned _o = 0): data(_d), offset(_o) {} NibbleSlice(bytesConstRef _data = bytesConstRef(), unsigned _offset = 0): data(_data), offset(_offset) {}
byte operator[](unsigned _index) const { return nibble(data, offset + _index); } byte operator[](unsigned _index) const { return nibble(data, offset + _index); }
unsigned size() const { return data.size() * 2 - offset; } unsigned size() const { return data.size() * 2 - offset; }
bool empty() const { return !size(); } bool empty() const { return !size(); }
NibbleSlice mid(unsigned _index) const { return NibbleSlice(data, offset + _index); } NibbleSlice mid(unsigned _index) const { return NibbleSlice(data, offset + _index); }
void clear() { data.reset(); offset = 0; } void clear() { data.reset(); offset = 0; }
/// @returns true iff _k is a prefix of this.
bool contains(NibbleSlice _k) const { return shared(_k) == _k.size(); } bool contains(NibbleSlice _k) const { return shared(_k) == _k.size(); }
/// @returns the number of shared nibbles at the beginning of this and _k.
unsigned shared(NibbleSlice _k) const { return sharedNibbles(data, offset, offset + size(), _k.data, _k.offset, _k.offset + _k.size()); } unsigned shared(NibbleSlice _k) const { return sharedNibbles(data, offset, offset + size(), _k.data, _k.offset, _k.offset + _k.size()); }
/** /**
* @brief Determine if we, a full key, are situated prior to a particular key-prefix. * @brief Determine if we, a full key, are situated prior to a particular key-prefix.
@ -60,8 +72,8 @@ struct NibbleSlice
*/ */
bool isEarlierThan(NibbleSlice _k) const bool isEarlierThan(NibbleSlice _k) const
{ {
unsigned i; unsigned i = 0;
for (i = 0; i < _k.size() && i < size(); ++i) for (; i < _k.size() && i < size(); ++i)
if (operator[](i) < _k[i]) // Byte is lower - we're earlier.. if (operator[](i) < _k[i]) // Byte is lower - we're earlier..
return true; return true;
else if (operator[](i) > _k[i]) // Byte is higher - we're not earlier. else if (operator[](i) > _k[i]) // Byte is higher - we're not earlier.

162
libdevcore/TrieDB.h

@ -66,7 +66,7 @@ class GenericTrieDB
public: public:
using DB = _DB; using DB = _DB;
GenericTrieDB(DB* _db = nullptr): m_db(_db) {} explicit GenericTrieDB(DB* _db = nullptr): m_db(_db) {}
GenericTrieDB(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { open(_db, _root, _v); } GenericTrieDB(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { open(_db, _root, _v); }
~GenericTrieDB() {} ~GenericTrieDB() {}
@ -96,11 +96,72 @@ public:
/// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty).
bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); } bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); }
h256 const& root() const { if (!node(m_root).size()) BOOST_THROW_EXCEPTION(BadRoot()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly. h256 const& root() const { if (node(m_root).empty()) BOOST_THROW_EXCEPTION(BadRoot()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly.
std::string at(bytes const& _key) const { return at(&_key); }
std::string at(bytesConstRef _key) const;
void insert(bytes const& _key, bytes const& _value) { insert(&_key, &_value); }
void insert(bytesConstRef _key, bytes const& _value) { insert(_key, &_value); }
void insert(bytes const& _key, bytesConstRef _value) { insert(&_key, _value); }
void insert(bytesConstRef _key, bytesConstRef _value);
void remove(bytes const& _key) { remove(&_key); }
void remove(bytesConstRef _key);
bool contains(bytes const& _key) { return contains(&_key); }
bool contains(bytesConstRef _key) { return !at(_key).empty(); }
class iterator
{
public:
using value_type = std::pair<bytesConstRef, bytesConstRef>;
iterator() {}
explicit iterator(GenericTrieDB const* _db);
iterator(GenericTrieDB const* _db, bytesConstRef _key);
iterator& operator++() { next(); return *this; }
value_type operator*() const { return at(); }
value_type operator->() const { return at(); }
bool operator==(iterator const& _c) const { return _c.m_trail == m_trail; }
bool operator!=(iterator const& _c) const { return _c.m_trail != m_trail; }
value_type at() const;
private:
void next();
void next(NibbleSlice _key);
struct Node
{
std::string rlp;
std::string key; // as hexPrefixEncoding.
byte child; // 255 -> entering, 16 -> actually at the node, 17 -> exiting, 0-15 -> actual children.
// 255 -> 16 -> 0 -> 1 -> ... -> 15 -> 17
void setChild(unsigned _i) { child = _i; }
void setFirstChild() { child = 16; }
void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); }
bool operator==(Node const& _c) const { return rlp == _c.rlp && key == _c.key && child == _c.child; }
bool operator!=(Node const& _c) const { return !operator==(_c); }
};
protected:
std::vector<Node> m_trail;
GenericTrieDB<DB> const* m_that;
};
iterator begin() const { return iterator(this); }
iterator end() const { return iterator(); }
iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); }
void debugPrint() {} void debugPrint() {}
void descendKey(h256 _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const /// Used for debugging, scans the whole trie.
void descendKey(h256 const& _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const
{ {
_keyMask.erase(_k); _keyMask.erase(_k);
if (_k == m_root && _k == c_shaNull) // root allowed to be empty if (_k == m_root && _k == c_shaNull) // root allowed to be empty
@ -108,6 +169,7 @@ public:
descendList(RLP(node(_k)), _keyMask, _wasExt, _out, _indent); // if not, it must be a list descendList(RLP(node(_k)), _keyMask, _wasExt, _out, _indent); // if not, it must be a list
} }
/// Used for debugging, scans the whole trie.
void descendEntry(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const void descendEntry(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
{ {
if (_r.isData() && _r.size() == 32) if (_r.isData() && _r.size() == 32)
@ -118,6 +180,7 @@ public:
BOOST_THROW_EXCEPTION(InvalidTrie()); BOOST_THROW_EXCEPTION(InvalidTrie());
} }
/// Used for debugging, scans the whole trie.
void descendList(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const void descendList(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
{ {
if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out)) if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out))
@ -139,6 +202,7 @@ public:
BOOST_THROW_EXCEPTION(InvalidTrie()); BOOST_THROW_EXCEPTION(InvalidTrie());
} }
/// Used for debugging, scans the whole trie.
h256Hash leftOvers(std::ostream* _out = nullptr) const h256Hash leftOvers(std::ostream* _out = nullptr) const
{ {
h256Hash k = m_db->keys(); h256Hash k = m_db->keys();
@ -146,11 +210,14 @@ public:
return k; return k;
} }
/// Used for debugging, scans the whole trie.
void debugStructure(std::ostream& _out) const void debugStructure(std::ostream& _out) const
{ {
leftOvers(&_out); leftOvers(&_out);
} }
/// Used for debugging, scans the whole trie.
/// @param _requireNoLeftOvers if true, requires that all keys are reachable.
bool check(bool _requireNoLeftOvers) const bool check(bool _requireNoLeftOvers) const
{ {
try try
@ -164,66 +231,6 @@ public:
} }
} }
std::string at(bytes const& _key) const { return at(&_key); }
std::string at(bytesConstRef _key) const;
void insert(bytes const& _key, bytes const& _value) { insert(&_key, &_value); }
void insert(bytesConstRef _key, bytes const& _value) { insert(_key, &_value); }
void insert(bytes const& _key, bytesConstRef _value) { insert(&_key, _value); }
void insert(bytesConstRef _key, bytesConstRef _value);
void remove(bytes const& _key) { remove(&_key); }
void remove(bytesConstRef _key);
bool contains(bytes const& _key) { return contains(&_key); }
bool contains(bytesConstRef _key) { return !at(_key).empty(); }
class iterator
{
public:
using value_type = std::pair<bytesConstRef, bytesConstRef>;
iterator() {}
iterator(GenericTrieDB const* _db);
iterator(GenericTrieDB const* _db, bytesConstRef _key);
iterator& operator++() { next(); return *this; }
value_type operator*() const { return at(); }
value_type operator->() const { return at(); }
bool operator==(iterator const& _c) const { return _c.m_trail == m_trail; }
bool operator!=(iterator const& _c) const { return _c.m_trail != m_trail; }
value_type at() const;
private:
void next();
void next(NibbleSlice _key);
struct Node
{
std::string rlp;
std::string key; // as hexPrefixEncoding.
byte child; // 255 -> entering, 16 -> actually at the node, 17 -> exiting, 0-15 -> actual children.
// 255 -> 16 -> 0 -> 1 -> ... -> 15 -> 17
void setChild(unsigned _i) { child = _i; }
void setFirstChild() { child = 16; }
void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); }
bool operator==(Node const& _c) const { return rlp == _c.rlp && key == _c.key && child == _c.child; }
bool operator!=(Node const& _c) const { return !operator==(_c); }
};
protected:
std::vector<Node> m_trail;
GenericTrieDB<DB> const* m_that;
};
iterator begin() const { return this; }
iterator end() const { return iterator(); }
iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); }
protected: protected:
DB* db() const { return m_db; } DB* db() const { return m_db; }
@ -279,12 +286,12 @@ private:
bool isTwoItemNode(RLP const& _n) const; bool isTwoItemNode(RLP const& _n) const;
std::string deref(RLP const& _n) const; std::string deref(RLP const& _n) const;
std::string node(h256 _h) const { return m_db->lookup(_h); } std::string node(h256 const& _h) const { return m_db->lookup(_h); }
// These are low-level node insertion functions that just go straight through into the DB. // These are low-level node insertion functions that just go straight through into the DB.
h256 forceInsertNode(bytesConstRef _v) { auto h = sha3(_v); forceInsertNode(h, _v); return h; } h256 forceInsertNode(bytesConstRef _v) { auto h = sha3(_v); forceInsertNode(h, _v); return h; }
void forceInsertNode(h256 _h, bytesConstRef _v) { m_db->insert(_h, _v); } void forceInsertNode(h256 const& _h, bytesConstRef _v) { m_db->insert(_h, _v); }
void forceKillNode(h256 _h) { m_db->kill(_h); } void forceKillNode(h256 const& _h) { m_db->kill(_h); }
// This are semantically-aware node insertion functions that only kills when the node's // This are semantically-aware node insertion functions that only kills when the node's
// data is < 32 bytes. It can safely be used when pruning the trie but won't work correctly // data is < 32 bytes. It can safely be used when pruning the trie but won't work correctly
@ -305,6 +312,9 @@ std::ostream& operator<<(std::ostream& _out, GenericTrieDB<DB> const& _db)
return _out; return _out;
} }
/**
* Different view on a GenericTrieDB that can use different key types.
*/
template <class Generic, class _KeyType> template <class Generic, class _KeyType>
class SpecificTrieDB: public Generic class SpecificTrieDB: public Generic
{ {
@ -753,14 +763,14 @@ template <class DB> void GenericTrieDB<DB>::insert(bytesConstRef _key, bytesCons
tdebug << "Insert" << toHex(_key.cropped(0, 4)) << "=>" << toHex(_value); tdebug << "Insert" << toHex(_key.cropped(0, 4)) << "=>" << toHex(_value);
#endif #endif
std::string rv = node(m_root); std::string rootValue = node(m_root);
assert(rv.size()); assert(rootValue.size());
bytes b = mergeAt(RLP(rv), m_root, NibbleSlice(_key), _value); bytes b = mergeAt(RLP(rootValue), m_root, NibbleSlice(_key), _value);
// mergeAt won't attempt to delete the node if it's less than 32 bytes // mergeAt won't attempt to delete the node if it's less than 32 bytes
// However, we know it's the root node and thus always hashed. // However, we know it's the root node and thus always hashed.
// So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here. // So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here.
if (rv.size() < 32) if (rootValue.size() < 32)
forceKillNode(m_root); forceKillNode(m_root);
m_root = forceInsertNode(&b); m_root = forceInsertNode(&b);
} }
@ -1066,11 +1076,11 @@ template <class DB> bytes GenericTrieDB<DB>::place(RLP const& _orig, NibbleSlice
killNode(_orig); killNode(_orig);
if (_orig.isEmpty()) if (_orig.isEmpty())
return (RLPStream(2) << hexPrefixEncode(_k, true) << _s).out(); return rlpList(hexPrefixEncode(_k, true), _s);
assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17)); assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17));
if (_orig.itemCount() == 2) if (_orig.itemCount() == 2)
return (RLPStream(2) << _orig[0] << _s).out(); return rlpList(_orig[0], _s);
auto s = RLPStream(17); auto s = RLPStream(17);
for (unsigned i = 0; i < 16; ++i) for (unsigned i = 0; i < 16; ++i)
@ -1152,7 +1162,7 @@ template <class DB> bytes GenericTrieDB<DB>::graft(RLP const& _orig)
} }
assert(n.itemCount() == 2); assert(n.itemCount() == 2);
return (RLPStream(2) << hexPrefixEncode(keyOf(_orig), keyOf(n), isLeaf(n)) << n[1]).out(); return rlpList(hexPrefixEncode(keyOf(_orig), keyOf(n), isLeaf(n)), n[1]);
// auto ret = // auto ret =
// std::cout << keyOf(_orig) << " ++ " << keyOf(n) << " == " << keyOf(RLP(ret)) << std::endl; // std::cout << keyOf(_orig) << " ++ " << keyOf(n) << " == " << keyOf(RLP(ret)) << std::endl;
// return ret; // return ret;
@ -1201,11 +1211,7 @@ template <class DB> bytes GenericTrieDB<DB>::branch(RLP const& _orig)
for (unsigned i = 0; i < 16; ++i) for (unsigned i = 0; i < 16; ++i)
if (i == b) if (i == b)
if (isLeaf(_orig) || k.size() > 1) if (isLeaf(_orig) || k.size() > 1)
{ streamNode(r, rlpList(hexPrefixEncode(k.mid(1), isLeaf(_orig)), _orig[1]));
RLPStream bottom(2);
bottom << hexPrefixEncode(k.mid(1), isLeaf(_orig)) << _orig[1];
streamNode(r, bottom.out());
}
else else
r << _orig[1]; r << _orig[1];
else else

18
libdevcrypto/Common.cpp

@ -22,6 +22,7 @@
#include "Common.h" #include "Common.h"
#include <random> #include <random>
#include <cstdint>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@ -29,6 +30,7 @@
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libdevcore/RLP.h>
#if ETH_HAVE_SECP256K1 #if ETH_HAVE_SECP256K1
#include <secp256k1/secp256k1.h> #include <secp256k1/secp256k1.h>
#endif #endif
@ -90,6 +92,11 @@ Address dev::toAddress(Secret const& _secret)
return toAddress(p); return toAddress(p);
} }
Address dev::toAddress(Address const& _from, u256 const& _nonce)
{
return right160(sha3(rlpList(_from, _nonce)));
}
void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher) void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{ {
bytes io = _plain.toBytes(); bytes io = _plain.toBytes();
@ -256,16 +263,9 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin
KeyPair KeyPair::create() KeyPair KeyPair::create()
{ {
static boost::thread_specific_ptr<mt19937_64> s_eng;
static unsigned s_id = 0;
if (!s_eng.get())
s_eng.reset(new mt19937_64(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count() + ++s_id));
uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i) for (int i = 0; i < 100; ++i)
{ {
KeyPair ret(FixedHash<32>::random(*s_eng.get())); KeyPair ret(FixedHash<32>::random());
if (ret.address()) if (ret.address())
return ret; return ret;
} }
@ -347,7 +347,7 @@ void Nonce::initialiseIfNeeded()
std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count()); std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
std::uniform_int_distribution<uint16_t> d(0, 255); std::uniform_int_distribution<uint16_t> d(0, 255);
for (unsigned i = 0; i < 32; ++i) for (unsigned i = 0; i < 32; ++i)
m_value[i] = byte(d(s_eng)); m_value[i] = (uint8_t)d(s_eng);
} }
if (!m_value) if (!m_value)
BOOST_THROW_EXCEPTION(InvalidState()); BOOST_THROW_EXCEPTION(InvalidState());

3
libdevcrypto/Common.h

@ -85,6 +85,9 @@ Address toAddress(Public const& _public);
/// @returns 0 if it's not a valid secret key. /// @returns 0 if it's not a valid secret key.
Address toAddress(Secret const& _secret); Address toAddress(Secret const& _secret);
// Convert transaction from and nonce to address.
Address toAddress(Address const& _from, u256 const& _nonce);
/// Encrypts plain text using Public key. /// Encrypts plain text using Public key.
void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher); void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher);

1
libethash-cl/CMakeLists.txt

@ -20,6 +20,7 @@ file(GLOB OUR_HEADERS "*.h")
set(HEADERS ${OUR_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) set(HEADERS ${OUR_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${OpenCL_INCLUDE_DIRS}) include_directories(${OpenCL_INCLUDE_DIRS})
include_directories(..) include_directories(..)
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})

68
libethash-cl/ethash_cl_miner.cpp

@ -33,6 +33,7 @@
#include <vector> #include <vector>
#include <libethash/util.h> #include <libethash/util.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
#include <libethcore/Ethash.h>
#include <libethash/internal.h> #include <libethash/internal.h>
#include "ethash_cl_miner.h" #include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h" #include "ethash_cl_miner_kernel.h"
@ -49,6 +50,7 @@
#undef max #undef max
using namespace std; using namespace std;
using namespace dev::eth;
// TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel // TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel
#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl #define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl
@ -140,11 +142,17 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId)
bool ethash_cl_miner::configureGPU( bool ethash_cl_miner::configureGPU(
unsigned _platformId, unsigned _platformId,
unsigned _localWorkSize,
unsigned _globalWorkSize,
unsigned _msPerBatch,
bool _allowCPU, bool _allowCPU,
unsigned _extraGPUMemory, unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock boost::optional<uint64_t> _currentBlock
) )
{ {
s_workgroupSize = _localWorkSize;
s_initialGlobalWorkSize = _globalWorkSize;
s_msPerBatch = _msPerBatch;
s_allowCPU = _allowCPU; s_allowCPU = _allowCPU;
s_extraRequiredGPUMem = _extraGPUMemory; s_extraRequiredGPUMem = _extraGPUMemory;
// by default let's only consider the DAG of the first epoch // by default let's only consider the DAG of the first epoch
@ -175,6 +183,9 @@ bool ethash_cl_miner::configureGPU(
bool ethash_cl_miner::s_allowCPU = false; bool ethash_cl_miner::s_allowCPU = false;
unsigned ethash_cl_miner::s_extraRequiredGPUMem; unsigned ethash_cl_miner::s_extraRequiredGPUMem;
unsigned ethash_cl_miner::s_msPerBatch = Ethash::defaultMSPerBatch;
unsigned ethash_cl_miner::s_workgroupSize = Ethash::defaultLocalWorkSize;
unsigned ethash_cl_miner::s_initialGlobalWorkSize = Ethash::defaultGlobalWorkSizeMultiplier * Ethash::defaultLocalWorkSize;
bool ethash_cl_miner::searchForAllDevices(function<bool(cl::Device const&)> _callback) bool ethash_cl_miner::searchForAllDevices(function<bool(cl::Device const&)> _callback)
{ {
@ -254,7 +265,6 @@ void ethash_cl_miner::finish()
bool ethash_cl_miner::init( bool ethash_cl_miner::init(
uint8_t const* _dag, uint8_t const* _dag,
uint64_t _dagSize, uint64_t _dagSize,
unsigned _workgroupSize,
unsigned _platformId, unsigned _platformId,
unsigned _deviceId unsigned _deviceId
) )
@ -299,14 +309,18 @@ bool ethash_cl_miner::init(
m_context = cl::Context(vector<cl::Device>(&device, &device + 1)); m_context = cl::Context(vector<cl::Device>(&device, &device + 1));
m_queue = cl::CommandQueue(m_context, device); m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8 // make sure that global work size is evenly divisible by the local workgroup size
m_workgroupSize = ((_workgroupSize + 7) / 8) * 8; m_globalWorkSize = s_initialGlobalWorkSize;
if (m_globalWorkSize % s_workgroupSize != 0)
m_globalWorkSize = ((m_globalWorkSize / s_workgroupSize) + 1) * s_workgroupSize;
// remember the device's address bits
m_deviceBits = device.getInfo<CL_DEVICE_ADDRESS_BITS>();
// patch source code // patch source code
// note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled // note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled
// into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime // into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime
string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
addDefinition(code, "GROUP_SIZE", m_workgroupSize); addDefinition(code, "GROUP_SIZE", s_workgroupSize);
addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES));
addDefinition(code, "ACCESSES", ETHASH_ACCESSES); addDefinition(code, "ACCESSES", ETHASH_ACCESSES);
addDefinition(code, "MAX_OUTPUTS", c_maxSearchResults); addDefinition(code, "MAX_OUTPUTS", c_maxSearchResults);
@ -323,7 +337,7 @@ bool ethash_cl_miner::init(
ETHCL_LOG("Printing program log"); ETHCL_LOG("Printing program log");
ETHCL_LOG(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str()); ETHCL_LOG(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str());
} }
catch (cl::Error const& err) catch (cl::Error const&)
{ {
ETHCL_LOG(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str()); ETHCL_LOG(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str());
return false; return false;
@ -415,9 +429,8 @@ bool ethash_cl_miner::init(
return true; return true;
} }
void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook, unsigned _msPerBatch) void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook)
{ {
(void)_msPerBatch;
try try
{ {
struct pending_batch struct pending_batch
@ -454,10 +467,9 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
unsigned buf = 0; unsigned buf = 0;
random_device engine; random_device engine;
uint64_t start_nonce = uniform_int_distribution<uint64_t>()(engine); uint64_t start_nonce = uniform_int_distribution<uint64_t>()(engine);
for (;; start_nonce += m_batchSize) for (;; start_nonce += m_globalWorkSize)
{ {
// chrono::high_resolution_clock::time_point t = chrono::high_resolution_clock::now(); auto t = chrono::high_resolution_clock::now();
// supply output buffer to kernel // supply output buffer to kernel
m_searchKernel.setArg(0, m_searchBuffer[buf]); m_searchKernel.setArg(0, m_searchBuffer[buf]);
if (m_dagChunksCount == 1) if (m_dagChunksCount == 1)
@ -466,7 +478,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
m_searchKernel.setArg(6, start_nonce); m_searchKernel.setArg(6, start_nonce);
// execute it! // execute it!
m_queue.enqueueNDRangeKernel(m_searchKernel, cl::NullRange, m_batchSize, m_workgroupSize); m_queue.enqueueNDRangeKernel(m_searchKernel, cl::NullRange, m_globalWorkSize, s_workgroupSize);
pending.push({ start_nonce, buf }); pending.push({ start_nonce, buf });
buf = (buf + 1) % c_bufferCount; buf = (buf + 1) % c_bufferCount;
@ -486,7 +498,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
m_queue.enqueueUnmapMemObject(m_searchBuffer[batch.buf], results); m_queue.enqueueUnmapMemObject(m_searchBuffer[batch.buf], results);
bool exit = num_found && hook.found(nonces, num_found); bool exit = num_found && hook.found(nonces, num_found);
exit |= hook.searched(batch.start_nonce, m_batchSize); // always report searched before exit exit |= hook.searched(batch.start_nonce, m_globalWorkSize); // always report searched before exit
if (exit) if (exit)
break; break;
@ -497,19 +509,31 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
pending.pop(); pending.pop();
} }
/* chrono::high_resolution_clock::duration d = chrono::high_resolution_clock::now() - t; // adjust global work size depending on last search time
if (d > chrono::milliseconds(_msPerBatch * 10 / 9)) if (s_msPerBatch)
{
// Global work size must be:
// - less than or equal to 2 ^ DEVICE_BITS - 1
// - divisible by lobal work size (workgroup size)
auto d = chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - t);
if (d != chrono::milliseconds(0)) // if duration is zero, we did not get in the actual searh/or search not finished
{
if (d > chrono::milliseconds(s_msPerBatch * 10 / 9))
{ {
cerr << "Batch of" << m_batchSize << "took" << chrono::duration_cast<chrono::milliseconds>(d).count() << "ms, >>" << _msPerBatch << "ms."; // cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast<chrono::milliseconds>(d).count() << " ms, >> " << _msPerBatch << " ms." << endl;
m_batchSize = max<unsigned>(128, m_batchSize * 9 / 10); m_globalWorkSize = max<unsigned>(128, m_globalWorkSize + s_workgroupSize);
cerr << "New batch size" << m_batchSize; // cerr << "New global work size" << m_globalWorkSize << endl;
} }
else if (d < chrono::milliseconds(_msPerBatch * 9 / 10)) else if (d < chrono::milliseconds(s_msPerBatch * 9 / 10))
{ {
cerr << "Batch of" << m_batchSize << "took" << chrono::duration_cast<chrono::milliseconds>(d).count() << "ms, <<" << _msPerBatch << "ms."; // cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast<chrono::milliseconds>(d).count() << " ms, << " << _msPerBatch << " ms." << endl;
m_batchSize = m_batchSize * 10 / 9; m_globalWorkSize = min<unsigned>(pow(2, m_deviceBits) - 1, m_globalWorkSize - s_workgroupSize);
cerr << "New batch size" << m_batchSize; // Global work size should never be less than the workgroup size
}*/ m_globalWorkSize = max<unsigned>(s_workgroupSize, m_globalWorkSize);
// cerr << "New global work size" << m_globalWorkSize << endl;
}
}
}
} }
// not safe to return until this is ready // not safe to return until this is ready

16
libethash-cl/ethash_cl_miner.h

@ -45,6 +45,9 @@ public:
static void listDevices(); static void listDevices();
static bool configureGPU( static bool configureGPU(
unsigned _platformId, unsigned _platformId,
unsigned _localWorkSize,
unsigned _globalWorkSize,
unsigned _msPerBatch,
bool _allowCPU, bool _allowCPU,
unsigned _extraGPUMemory, unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock boost::optional<uint64_t> _currentBlock
@ -53,12 +56,11 @@ public:
bool init( bool init(
uint8_t const* _dag, uint8_t const* _dag,
uint64_t _dagSize, uint64_t _dagSize,
unsigned _workgroupSize = 64,
unsigned _platformId = 0, unsigned _platformId = 0,
unsigned _deviceId = 0 unsigned _deviceId = 0
); );
void finish(); void finish();
void search(uint8_t const* _header, uint64_t _target, search_hook& _hook, unsigned _msPerBatch = 100); void search(uint8_t const* _header, uint64_t _target, search_hook& _hook);
void hash_chunk(uint8_t* _ret, uint8_t const* _header, uint64_t _nonce, unsigned _count); void hash_chunk(uint8_t* _ret, uint8_t const* _header, uint64_t _nonce, unsigned _count);
void search_chunk(uint8_t const*_header, uint64_t _target, search_hook& _hook); void search_chunk(uint8_t const*_header, uint64_t _target, search_hook& _hook);
@ -76,10 +78,16 @@ private:
cl::Buffer m_header; cl::Buffer m_header;
cl::Buffer m_hashBuffer[c_bufferCount]; cl::Buffer m_hashBuffer[c_bufferCount];
cl::Buffer m_searchBuffer[c_bufferCount]; cl::Buffer m_searchBuffer[c_bufferCount];
unsigned m_workgroupSize; unsigned m_globalWorkSize;
unsigned m_batchSize = c_searchBatchSize;
bool m_openclOnePointOne; bool m_openclOnePointOne;
unsigned m_deviceBits;
/// The local work size for the search
static unsigned s_workgroupSize;
/// The initial global work size for the searches
static unsigned s_initialGlobalWorkSize;
/// The target milliseconds per batch for the search. If 0, then no adjustment will happen
static unsigned s_msPerBatch;
/// Allow CPU to appear as an OpenCL device or not. Default is false /// Allow CPU to appear as an OpenCL device or not. Default is false
static bool s_allowCPU; static bool s_allowCPU;
/// GPU memory required for other things, like window rendering e.t.c. /// GPU memory required for other things, like window rendering e.t.c.

16
libethcore/Common.h

@ -97,10 +97,13 @@ enum class RelativeBlock: BlockNumber
Pending = PendingBlock Pending = PendingBlock
}; };
class Transaction;
struct ImportRoute struct ImportRoute
{ {
h256s deadBlocks; h256s deadBlocks;
h256s liveBlocks; h256s liveBlocks;
std::vector<Transaction> goodTranactions;
}; };
enum class ImportResult enum class ImportResult
@ -129,10 +132,10 @@ struct ImportRequirements
}; };
/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. /// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight.
class Signal template<typename... Args> class Signal
{ {
public: public:
using Callback = std::function<void()>; using Callback = std::function<void(Args...)>;
class HandlerAux class HandlerAux
{ {
@ -141,7 +144,7 @@ public:
public: public:
~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); m_s = nullptr; } ~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); m_s = nullptr; }
void reset() { m_s = nullptr; } void reset() { m_s = nullptr; }
void fire() { m_h(); } void fire(Args&&... _args) { m_h(std::forward<Args>(_args)...); }
private: private:
HandlerAux(unsigned _i, Signal* _s, Callback const& _h): m_i(_i), m_s(_s), m_h(_h) {} HandlerAux(unsigned _i, Signal* _s, Callback const& _h): m_i(_i), m_s(_s), m_h(_h) {}
@ -165,13 +168,13 @@ public:
return h; return h;
} }
void operator()() { for (auto const& f: m_fire) f.second->fire(); } void operator()(Args&... _args) { for (auto const& f: m_fire) f.second->fire(std::forward<Args>(_args)...); }
private: private:
std::map<unsigned, std::shared_ptr<Signal::HandlerAux>> m_fire; std::map<unsigned, std::shared_ptr<typename Signal::HandlerAux>> m_fire;
}; };
using Handler = std::shared_ptr<Signal::HandlerAux>; template<class... Args> using Handler = std::shared_ptr<typename Signal<Args...>::HandlerAux>;
struct TransactionSkeleton struct TransactionSkeleton
{ {
@ -182,6 +185,7 @@ struct TransactionSkeleton
bytes data; bytes data;
u256 gas = UndefinedU256; u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256; u256 gasPrice = UndefinedU256;
u256 nonce = UndefinedU256;
}; };
void badBlock(bytesConstRef _header, std::string const& _err); void badBlock(bytesConstRef _header, std::string const& _err);

30
libethcore/Ethash.cpp

@ -54,6 +54,9 @@ namespace dev
namespace eth namespace eth
{ {
const unsigned Ethash::defaultLocalWorkSize = 64;
const unsigned Ethash::defaultGlobalWorkSizeMultiplier = 512; // * CL_DEFAULT_LOCAL_WORK_SIZE
const unsigned Ethash::defaultMSPerBatch = 0;
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage();
std::string Ethash::name() std::string Ethash::name()
@ -373,7 +376,7 @@ void Ethash::GPUMiner::workLoop()
this_thread::sleep_for(chrono::milliseconds(500)); this_thread::sleep_for(chrono::milliseconds(500));
} }
bytesConstRef dagData = dag->data(); bytesConstRef dagData = dag->data();
m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device); m_miner->init(dagData.data(), dagData.size(), s_platformId, device);
} }
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
@ -409,6 +412,9 @@ void Ethash::GPUMiner::listDevices()
} }
bool Ethash::GPUMiner::configureGPU( bool Ethash::GPUMiner::configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId, unsigned _platformId,
unsigned _deviceId, unsigned _deviceId,
bool _allowCPU, bool _allowCPU,
@ -418,7 +424,27 @@ bool Ethash::GPUMiner::configureGPU(
{ {
s_platformId = _platformId; s_platformId = _platformId;
s_deviceId = _deviceId; s_deviceId = _deviceId;
return ethash_cl_miner::configureGPU(_platformId, _allowCPU, _extraGPUMemory, _currentBlock);
if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128)
{
cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64, or 128" << endl;
return false;
}
if (!ethash_cl_miner::configureGPU(
_platformId,
_localWorkSize,
_globalWorkSizeMultiplier * _localWorkSize,
_msPerBatch,
_allowCPU,
_extraGPUMemory,
_currentBlock)
)
{
cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
return false;
}
return true;
} }
#endif #endif

11
libethcore/Ethash.h

@ -88,7 +88,7 @@ public:
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo(); static std::string platformInfo();
static void listDevices() {} static void listDevices() {}
static bool configureGPU(unsigned, unsigned, bool, unsigned, boost::optional<uint64_t>) { return false; } static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, boost::optional<uint64_t>) { return false; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); } static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); }
protected: protected:
void kickOff() override void kickOff() override
@ -118,6 +118,9 @@ public:
static unsigned getNumDevices(); static unsigned getNumDevices();
static void listDevices(); static void listDevices();
static bool configureGPU( static bool configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId, unsigned _platformId,
unsigned _deviceId, unsigned _deviceId,
bool _allowCPU, bool _allowCPU,
@ -147,6 +150,12 @@ public:
#else #else
using GPUMiner = CPUMiner; using GPUMiner = CPUMiner;
#endif #endif
/// Default value of the local work size. Also known as workgroup size.
static const unsigned defaultLocalWorkSize;
/// Default value of the global work size as a multiplier of the local work size
static const unsigned defaultGlobalWorkSizeMultiplier;
/// Default value of the milliseconds per global work size (per batch)
static const unsigned defaultMSPerBatch;
}; };
} }

14
libethcore/Transaction.cpp

@ -29,6 +29,20 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
TransactionBase::TransactionBase(TransactionSkeleton const& _ts, Secret const& _s):
m_type(_ts.creation ? ContractCreation : MessageCall),
m_nonce(_ts.nonce),
m_value(_ts.value),
m_receiveAddress(_ts.to),
m_gasPrice(_ts.gasPrice),
m_gas(_ts.gas),
m_data(_ts.data),
m_sender(_ts.from)
{
if (_s)
sign(_s);
}
TransactionBase::TransactionBase(bytesConstRef _rlpData, CheckTransaction _checkSig) TransactionBase::TransactionBase(bytesConstRef _rlpData, CheckTransaction _checkSig)
{ {
int field = 0; int field = 0;

4
libethcore/Transaction.h

@ -51,6 +51,9 @@ public:
/// Constructs a null transaction. /// Constructs a null transaction.
TransactionBase() {} TransactionBase() {}
/// Constructs a transaction from a transaction skeleton & optional secret.
TransactionBase(TransactionSkeleton const& _ts, Secret const& _s = Secret());
/// Constructs a signed message-call transaction. /// Constructs a signed message-call transaction.
TransactionBase(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce, Secret const& _secret): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } TransactionBase(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce, Secret const& _secret): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); }
@ -69,7 +72,6 @@ public:
/// Constructs a transaction from the given RLP. /// Constructs a transaction from the given RLP.
explicit TransactionBase(bytes const& _rlp, CheckTransaction _checkSig): TransactionBase(&_rlp, _checkSig) {} explicit TransactionBase(bytes const& _rlp, CheckTransaction _checkSig): TransactionBase(&_rlp, _checkSig) {}
/// Checks equality of transactions. /// Checks equality of transactions.
bool operator==(TransactionBase const& _c) const { return m_type == _c.m_type && (m_type == ContractCreation || m_receiveAddress == _c.m_receiveAddress) && m_value == _c.m_value && m_data == _c.m_data; } bool operator==(TransactionBase const& _c) const { return m_type == _c.m_type && (m_type == ContractCreation || m_receiveAddress == _c.m_receiveAddress) && m_value == _c.m_value && m_data == _c.m_data; }
/// Checks inequality of transactions. /// Checks inequality of transactions.

4
libethereum/Account.h

@ -152,8 +152,7 @@ public:
h256 codeHash() const { assert(!isFreshCode()); return m_codeHash; } h256 codeHash() const { assert(!isFreshCode()); return m_codeHash; }
/// Sets the code of the account. Must only be called when isFreshCode() returns true. /// Sets the code of the account. Must only be called when isFreshCode() returns true.
void setCode(bytes&& _code) { assert(isFreshCode()); m_codeCache = _code; changed(); } void setCode(bytes&& _code) { assert(isFreshCode()); m_codeCache = std::move(_code); changed(); }
void setCode(bytes const& _code) { assert(isFreshCode()); m_codeCache = _code; changed(); }
/// @returns true if the account's code is available through code(). /// @returns true if the account's code is available through code().
bool codeCacheValid() const { return m_codeHash == EmptySHA3 || m_codeHash == c_contractConceptionCodeHash || m_codeCache.size(); } bool codeCacheValid() const { return m_codeHash == EmptySHA3 || m_codeHash == c_contractConceptionCodeHash || m_codeCache.size(); }
@ -206,4 +205,3 @@ private:
} }
} }

66
libethereum/BlockChain.cpp

@ -273,7 +273,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
h256 lastHash = m_lastBlockHash; h256 lastHash = m_lastBlockHash;
Timer t; Timer t;
for (unsigned d = 1; d < originalNumber; ++d) for (unsigned d = 1; d <= originalNumber; ++d)
{ {
if (!(d % 1000)) if (!(d % 1000))
{ {
@ -337,6 +337,7 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
h256s fresh; h256s fresh;
h256s dead; h256s dead;
h256s badBlocks; h256s badBlocks;
Transactions goodTransactions;
unsigned count = 0; unsigned count = 0;
for (VerifiedBlock const& block: blocks) for (VerifiedBlock const& block: blocks)
if (!badBlocks.empty()) if (!badBlocks.empty())
@ -351,6 +352,7 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
fresh += r.liveBlocks; fresh += r.liveBlocks;
dead += r.deadBlocks; dead += r.deadBlocks;
goodTransactions += r.goodTranactions;
++count; ++count;
} }
catch (dev::eth::UnknownParent) catch (dev::eth::UnknownParent)
@ -377,7 +379,7 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
badBlocks.push_back(block.verified.info.hash()); badBlocks.push_back(block.verified.info.hash());
} }
} }
return make_tuple(ImportRoute{dead, fresh}, _bq.doneDrain(badBlocks), count); return make_tuple(ImportRoute{dead, fresh, goodTransactions}, _bq.doneDrain(badBlocks), count);
} }
pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
@ -497,6 +499,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
BlockReceipts br; BlockReceipts br;
u256 td; u256 td;
Transactions goodTransactions;
#if ETH_CATCH #if ETH_CATCH
try try
#endif #endif
@ -510,6 +513,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
{ {
blb.blooms.push_back(s.receipt(i).bloom()); blb.blooms.push_back(s.receipt(i).bloom());
br.receipts.push_back(s.receipt(i)); br.receipts.push_back(s.receipt(i));
goodTransactions.push_back(s.pending()[i]);
} }
s.cleanup(true); s.cleanup(true);
@ -750,7 +754,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
dead.push_back(h); dead.push_back(h);
else else
fresh.push_back(h); fresh.push_back(h);
return ImportRoute{dead, fresh}; return ImportRoute{dead, fresh, move(goodTransactions)};
} }
void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)
@ -795,6 +799,25 @@ void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)
} }
} }
void BlockChain::rewind(unsigned _newHead)
{
DEV_WRITE_GUARDED(x_lastBlockHash)
{
if (_newHead >= m_lastBlockNumber)
return;
m_lastBlockHash = numberHash(_newHead);
m_lastBlockNumber = _newHead;
auto o = m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&m_lastBlockHash, 32));
if (!o.ok())
{
cwarn << "Error writing to extras database: " << o.ToString();
cout << "Put" << toHex(bytesConstRef(ldb::Slice("best"))) << "=>" << toHex(bytesConstRef(ldb::Slice((char const*)&m_lastBlockHash, 32)));
cwarn << "Fail writing to extras database. Bombing out.";
exit(-1);
}
}
}
tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const& _to, bool _common, bool _pre, bool _post) const tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const& _to, bool _common, bool _pre, bool _post) const
{ {
// cdebug << "treeRoute" << _from << "..." << _to; // cdebug << "treeRoute" << _from << "..." << _to;
@ -867,34 +890,22 @@ template <class T> static unsigned getHashSize(unordered_map<h256, T> const& _ma
void BlockChain::updateStats() const void BlockChain::updateStats() const
{ {
{
ReadGuard l(x_blocks);
m_lastStats.memBlocks = 0; m_lastStats.memBlocks = 0;
DEV_READ_GUARDED(x_blocks)
for (auto const& i: m_blocks) for (auto const& i: m_blocks)
m_lastStats.memBlocks += i.second.size() + 64; m_lastStats.memBlocks += i.second.size() + 64;
} DEV_READ_GUARDED(x_details)
{
ReadGuard l(x_details);
m_lastStats.memDetails = getHashSize(m_details); m_lastStats.memDetails = getHashSize(m_details);
} DEV_READ_GUARDED(x_logBlooms)
{ DEV_READ_GUARDED(x_blocksBlooms)
ReadGuard l1(x_logBlooms);
ReadGuard l2(x_blocksBlooms);
m_lastStats.memLogBlooms = getHashSize(m_logBlooms) + getHashSize(m_blocksBlooms); m_lastStats.memLogBlooms = getHashSize(m_logBlooms) + getHashSize(m_blocksBlooms);
} DEV_READ_GUARDED(x_receipts)
{
ReadGuard l(x_receipts);
m_lastStats.memReceipts = getHashSize(m_receipts); m_lastStats.memReceipts = getHashSize(m_receipts);
} DEV_READ_GUARDED(x_blockHashes)
{
ReadGuard l(x_blockHashes);
m_lastStats.memBlockHashes = getHashSize(m_blockHashes); m_lastStats.memBlockHashes = getHashSize(m_blockHashes);
} DEV_READ_GUARDED(x_transactionAddresses)
{
ReadGuard l(x_transactionAddresses);
m_lastStats.memTransactionAddresses = getHashSize(m_transactionAddresses); m_lastStats.memTransactionAddresses = getHashSize(m_transactionAddresses);
} }
}
void BlockChain::garbageCollect(bool _force) void BlockChain::garbageCollect(bool _force)
{ {
@ -950,10 +961,8 @@ void BlockChain::garbageCollect(bool _force)
void BlockChain::checkConsistency() void BlockChain::checkConsistency()
{ {
{ DEV_WRITE_GUARDED(x_details)
WriteGuard l(x_details);
m_details.clear(); m_details.clear();
}
ldb::Iterator* it = m_blocksDB->NewIterator(m_readOptions); ldb::Iterator* it = m_blocksDB->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next()) for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().size() == 32) if (it->key().size() == 32)
@ -965,15 +974,11 @@ void BlockChain::checkConsistency()
{ {
auto dp = details(p); auto dp = details(p);
if (asserts(contains(dp.children, h))) if (asserts(contains(dp.children, h)))
{
cnote << "Apparently the database is corrupt. Not much we can do at this stage..."; cnote << "Apparently the database is corrupt. Not much we can do at this stage...";
}
if (assertsEqual(dp.number, dh.number - 1)) if (assertsEqual(dp.number, dh.number - 1))
{
cnote << "Apparently the database is corrupt. Not much we can do at this stage..."; cnote << "Apparently the database is corrupt. Not much we can do at this stage...";
} }
} }
}
delete it; delete it;
} }
@ -1084,7 +1089,8 @@ bool BlockChain::isKnown(h256 const& _hash) const
if (d.empty()) if (d.empty())
return false; return false;
} }
return true; // return true;
return details(_hash).number <= m_lastBlockNumber; // to allow rewind functionality.
} }
bytes BlockChain::block(h256 const& _hash) const bytes BlockChain::block(h256 const& _hash) const

6
libethereum/BlockChain.h

@ -142,6 +142,9 @@ public:
BlockReceipts receipts(h256 const& _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); } BlockReceipts receipts(h256 const& _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts() const { return receipts(currentHash()); } BlockReceipts receipts() const { return receipts(currentHash()); }
/// Get the transaction receipt by transaction hash. Thread-safe.
TransactionReceipt transactionReceipt(h256 const& _transactionHash) const {TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return receipts(ta.blockHash).receipts[ta.index]; }
/// Get a list of transaction hashes for a given block. Thread-safe. /// Get a list of transaction hashes for a given block. Thread-safe.
TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; } TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); } TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); }
@ -212,6 +215,9 @@ public:
/// Will call _progress with the progress in this operation first param done, second total. /// Will call _progress with the progress in this operation first param done, second total.
void rebuild(std::string const& _path, ProgressCallback const& _progress = std::function<void(unsigned, unsigned)>(), bool _prepPoW = false); void rebuild(std::string const& _path, ProgressCallback const& _progress = std::function<void(unsigned, unsigned)>(), bool _prepPoW = false);
/// Alter the head of the chain to some prior block along it.
void rewind(unsigned _newHead);
/** @returns a tuple of: /** @returns a tuple of:
* - an vector of hashes of all blocks between @a _from and @a _to, all blocks are ordered first by a number of * - an vector of hashes of all blocks between @a _from and @a _to, all blocks are ordered first by a number of
* blocks that are parent-to-child, then two sibling blocks, then a number of blocks that are child-to-parent; * blocks that are parent-to-child, then two sibling blocks, then a number of blocks that are child-to-parent;

14
libethereum/BlockChainSync.cpp

@ -41,6 +41,17 @@ using namespace p2p;
unsigned const c_chainReorgSize = 30000; /// Added to estimated hashes to account for potential chain reorganiation unsigned const c_chainReorgSize = 30000; /// Added to estimated hashes to account for potential chain reorganiation
unsigned const c_hashSubchainSize = 8192; /// PV61 subchain size unsigned const c_hashSubchainSize = 8192; /// PV61 subchain size
std::ostream& dev::eth::operator<<(std::ostream& _out, SyncStatus const& _sync)
{
_out << "protocol: " << _sync.protocolVersion << endl;
_out << "state: " << EthereumHost::stateName(_sync.state) << " ";
if (_sync.state == SyncState::Hashes)
_out << _sync.hashesReceived << "/" << (_sync.hashesEstimated ? "~" : "") << _sync.hashesTotal;
if (_sync.state == SyncState::Blocks || _sync.state == SyncState::NewBlocks)
_out << _sync.blocksReceived << "/" << _sync.blocksTotal;
return _out;
}
BlockChainSync::BlockChainSync(EthereumHost& _host): BlockChainSync::BlockChainSync(EthereumHost& _host):
m_host(_host) m_host(_host)
{ {
@ -69,7 +80,7 @@ DownloadMan& BlockChainSync::downloadMan()
void BlockChainSync::abortSync() void BlockChainSync::abortSync()
{ {
downloadMan().resetToChain(h256s()); downloadMan().reset();
} }
void BlockChainSync::onPeerStatus(std::shared_ptr<EthereumPeer> _peer) void BlockChainSync::onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
@ -386,7 +397,6 @@ void PV60Sync::transition(std::shared_ptr<EthereumPeer> _peer, SyncState _s, boo
if (m_state == SyncState::Idle && _s != SyncState::Idle) if (m_state == SyncState::Idle && _s != SyncState::Idle)
_peer->m_requireTransactions = true; _peer->m_requireTransactions = true;
RLPStream s;
if (_s == SyncState::Hashes) if (_s == SyncState::Hashes)
{ {
if (m_state == SyncState::Idle || m_state == SyncState::Hashes) if (m_state == SyncState::Idle || m_state == SyncState::Hashes)

5
libethereum/BlockChainSync.h

@ -114,7 +114,7 @@ protected:
void requestBlocks(std::shared_ptr<EthereumPeer> _peer); void requestBlocks(std::shared_ptr<EthereumPeer> _peer);
protected: protected:
Handler m_bqRoomAvailable; ///< Triggered once block queue Handler<> m_bqRoomAvailable; ///< Triggered once block queue
mutable RecursiveMutex x_sync; mutable RecursiveMutex x_sync;
SyncState m_state = SyncState::Idle; ///< Current sync state SyncState m_state = SyncState::Idle; ///< Current sync state
unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only.
@ -316,5 +316,8 @@ private:
unsigned m_syncingBlockNumber = 0; ///< Current subchain marker unsigned m_syncingBlockNumber = 0; ///< Current subchain marker
bool m_hashScanComplete = false; ///< True if leading peer completed hashchain scan and we have a list of subchains ready bool m_hashScanComplete = false; ///< True if leading peer completed hashchain scan and we have a list of subchains ready
}; };
std::ostream& operator<<(std::ostream& _out, SyncStatus const& _sync);
} }
} }

4
libethereum/BlockDetails.h

@ -59,7 +59,7 @@ struct BlockLogBlooms
{ {
BlockLogBlooms() {} BlockLogBlooms() {}
BlockLogBlooms(RLP const& _r) { blooms = _r.toVector<LogBloom>(); size = _r.data().size(); } BlockLogBlooms(RLP const& _r) { blooms = _r.toVector<LogBloom>(); size = _r.data().size(); }
bytes rlp() const { RLPStream s; s << blooms; size = s.out().size(); return s.out(); } bytes rlp() const { bytes r = dev::rlp(blooms); size = r.size(); return r; }
LogBlooms blooms; LogBlooms blooms;
mutable unsigned size; mutable unsigned size;
@ -69,7 +69,7 @@ struct BlocksBlooms
{ {
BlocksBlooms() {} BlocksBlooms() {}
BlocksBlooms(RLP const& _r) { blooms = _r.toArray<LogBloom, c_bloomIndexSize>(); size = _r.data().size(); } BlocksBlooms(RLP const& _r) { blooms = _r.toArray<LogBloom, c_bloomIndexSize>(); size = _r.data().size(); }
bytes rlp() const { RLPStream s; s << blooms; size = s.out().size(); return s.out(); } bytes rlp() const { bytes r = dev::rlp(blooms); size = r.size(); return r; }
std::array<LogBloom, c_bloomIndexSize> blooms; std::array<LogBloom, c_bloomIndexSize> blooms;
mutable unsigned size; mutable unsigned size;

4
libethereum/BlockQueue.cpp

@ -215,8 +215,10 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
return ImportResult::Malformed; return ImportResult::Malformed;
} }
clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash;
// Check block doesn't already exist first! // Check block doesn't already exist first!
if (_bc.details(h)) if (_bc.isKnown(h))
{ {
cblockq << "Already known in chain."; cblockq << "Already known in chain.";
return ImportResult::AlreadyInChain; return ImportResult::AlreadyInChain;

8
libethereum/BlockQueue.h

@ -111,8 +111,8 @@ public:
/// Get some infomration on the given block's status regarding us. /// Get some infomration on the given block's status regarding us.
QueueStatus blockStatus(h256 const& _h) const; QueueStatus blockStatus(h256 const& _h) const;
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); } template <class T> Handler<> onReady(T const& _t) { return m_onReady.add(_t); }
template <class T> Handler onRoomAvailable(T const& _t) { return m_onRoomAvailable.add(_t); } template <class T> Handler<> onRoomAvailable(T const& _t) { return m_onRoomAvailable.add(_t); }
template <class T> void setOnBad(T const& _t) { m_onBad = _t; } template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
@ -145,8 +145,8 @@ private:
std::unordered_multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears. std::unordered_multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
h256Hash m_knownBad; ///< Set of blocks that we know will never be valid. h256Hash m_knownBad; ///< Set of blocks that we know will never be valid.
std::multimap<unsigned, std::pair<h256, bytes>> m_future; ///< Set of blocks that are not yet valid. Ordered by timestamp std::multimap<unsigned, std::pair<h256, bytes>> m_future; ///< Set of blocks that are not yet valid. Ordered by timestamp
Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast. Signal<> m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
Signal m_onRoomAvailable; ///< Called when space for new blocks becomes availabe after a drain. Be nice and exit fast. Signal<> m_onRoomAvailable; ///< Called when space for new blocks becomes availabe after a drain. Be nice and exit fast.
mutable Mutex m_verification; ///< Mutex that allows writing to m_verified, m_verifying and m_unverified. mutable Mutex m_verification; ///< Mutex that allows writing to m_verified, m_verifying and m_unverified.
std::condition_variable m_moreToVerify; ///< Signaled when m_unverified has a new entry. std::condition_variable m_moreToVerify; ///< Signaled when m_unverified has a new entry.

13
libethereum/Client.cpp

@ -604,19 +604,18 @@ void Client::onChainChanged(ImportRoute const& _ir)
for (auto const& t: m_bc.transactions(h)) for (auto const& t: m_bc.transactions(h))
{ {
clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry); m_tq.import(t, IfDropped::Retry);
} }
} }
// remove transactions from m_tq nicely rather than relying on out of date nonce later on. // remove transactions from m_tq nicely rather than relying on out of date nonce later on.
for (auto const& h: _ir.liveBlocks) for (auto const& h: _ir.liveBlocks)
{
clog(ClientTrace) << "Live block:" << h; clog(ClientTrace) << "Live block:" << h;
for (auto const& th: m_bc.transactionHashes(h))
for (auto const& t: _ir.goodTranactions)
{ {
clog(ClientTrace) << "Safely dropping transaction " << th; clog(ClientTrace) << "Safely dropping transaction " << t.sha3();
m_tq.drop(th); m_tq.dropGood(t);
}
} }
if (auto h = m_host.lock()) if (auto h = m_host.lock())
@ -651,7 +650,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
for (auto const& t: m_postMine.pending()) for (auto const& t: m_postMine.pending())
{ {
clog(ClientTrace) << "Resubmitting post-mine transaction " << t; clog(ClientTrace) << "Resubmitting post-mine transaction " << t;
auto ir = m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry); auto ir = m_tq.import(t, IfDropped::Retry);
if (ir != ImportResult::Success) if (ir != ImportResult::Success)
onTransactionQueueReady(); onTransactionQueueReady();
} }

6
libethereum/Client.h

@ -217,6 +217,8 @@ public:
std::string const& sentinel() const { return m_sentinel; } std::string const& sentinel() const { return m_sentinel; }
/// Set the extra data that goes into mined blocks. /// Set the extra data that goes into mined blocks.
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head.
void rewind(unsigned _n) { m_bc.rewind(_n); }
protected: protected:
/// InterfaceStub methods /// InterfaceStub methods
@ -310,8 +312,8 @@ private:
GenericFarm<ProofOfWork> m_farm; ///< Our mining farm. GenericFarm<ProofOfWork> m_farm; ///< Our mining farm.
Handler m_tqReady; Handler<> m_tqReady;
Handler m_bqReady; Handler<> m_bqReady;
bool m_wouldMine = false; ///< True if we /should/ be mining. bool m_wouldMine = false; ///< True if we /should/ be mining.
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.

46
libethereum/ClientBase.cpp

@ -45,48 +45,21 @@ State ClientBase::asOf(BlockNumber _h) const
return asOf(bc().numberHash(_h)); return asOf(bc().numberHash(_h));
} }
void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce) pair<h256, Address> ClientBase::submitTransaction(TransactionSkeleton const& _t, Secret const& _secret)
{ {
prepareForTransaction(); prepareForTransaction();
Transaction t(_value, _gasPrice, _gas, _dest, _data, _nonce, _secret); TransactionSkeleton ts(_t);
m_tq.import(t.rlp()); ts.from = toAddress(_secret);
if (_t.nonce == UndefinedU256)
ts.nonce = max<u256>(postMine().transactionsFrom(ts.from), m_tq.maxNonce(ts.from));
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); Transaction t(ts, _secret);
cnote << "New transaction " << t;
}
Address ClientBase::submitTransaction(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce)
{
prepareForTransaction();
Transaction t(_value, _gasPrice, _gas, _data, _nonce, _secret);
m_tq.import(t.rlp()); m_tq.import(t.rlp());
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t; cnote << "New transaction " << t;
return right160(sha3(rlpList(t.sender(), t.nonce()))); return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));
}
void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
auto a = toAddress(_secret);
submitTransaction(_secret, _value, _dest, _data, _gas, _gasPrice, max<u256>(postMine().transactionsFrom(a), m_tq.maxNonce(a)));
}
Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
prepareForTransaction();
u256 n = postMine().transactionsFrom(toAddress(_secret));
Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
m_tq.import(t.rlp());
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t;
return right160(sha3(rlpList(t.sender(), t.nonce())));
} }
// TODO: remove try/catch, allow exceptions // TODO: remove try/catch, allow exceptions
@ -354,6 +327,11 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
return Transaction(); return Transaction();
} }
TransactionReceipt ClientBase::transactionReceipt(h256 const& _transactionHash) const
{
return bc().transactionReceipt(_transactionHash);
}
pair<h256, unsigned> ClientBase::transactionLocation(h256 const& _transactionHash) const pair<h256, unsigned> ClientBase::transactionLocation(h256 const& _transactionHash) const
{ {
return bc().transactionLocation(_transactionHash); return bc().transactionLocation(_transactionHash);

12
libethereum/ClientBase.h

@ -75,14 +75,9 @@ public:
ClientBase() {} ClientBase() {}
virtual ~ClientBase() {} virtual ~ClientBase() {}
/// Submits the given message-call transaction. /// Submits the given transaction.
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce); /// @returns the new transaction's hash.
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; virtual std::pair<h256, Address> submitTransaction(TransactionSkeleton const& _t, Secret const& _secret) override;
/// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, u256 _nonce);
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
using Interface::submitTransaction; using Interface::submitTransaction;
/// Makes the given call. Nothing is recorded into the state. /// Makes the given call. Nothing is recorded into the state.
@ -124,6 +119,7 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const override; virtual BlockDetails blockDetails(h256 _hash) const override;
virtual Transaction transaction(h256 _transactionHash) const override; virtual Transaction transaction(h256 _transactionHash) const override;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const override; virtual Transaction transaction(h256 _blockHash, unsigned _i) const override;
virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const override;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const override; virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const override;
virtual Transactions transactions(h256 _blockHash) const override; virtual Transactions transactions(h256 _blockHash) const override;
virtual TransactionHashes transactionHashes(h256 _blockHash) const override; virtual TransactionHashes transactionHashes(h256 _blockHash) const override;

10
libethereum/DownloadMan.cpp

@ -24,6 +24,16 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
DownloadMan::Overview DownloadMan::overview() const
{
ReadGuard l(m_lock);
Overview ret;
ret.firstIncomplete = m_blocksGot.firstOut();
ret.lastComplete = ret.lastStarted = m_blocksGot.lastIn();// TODO: lastStarted properly
ret.total = m_blocksGot.size();
return ret;
}
DownloadSub::DownloadSub(DownloadMan& _man): m_man(&_man) DownloadSub::DownloadSub(DownloadMan& _man): m_man(&_man)
{ {
WriteGuard l(m_man->x_subs); WriteGuard l(m_man->x_subs);

25
libethereum/DownloadMan.h

@ -82,6 +82,14 @@ class DownloadMan
friend class DownloadSub; friend class DownloadSub;
public: public:
struct Overview
{
size_t total;
size_t firstIncomplete;
size_t lastComplete;
size_t lastStarted;
};
~DownloadMan() ~DownloadMan()
{ {
for (auto i: m_subs) for (auto i: m_subs)
@ -97,11 +105,9 @@ public:
void resetToChain(h256s const& _chain) void resetToChain(h256s const& _chain)
{ {
{ DEV_READ_GUARDED(x_subs)
ReadGuard l(x_subs);
for (auto i: m_subs) for (auto i: m_subs)
i->resetFetch(); i->resetFetch();
}
WriteGuard l(m_lock); WriteGuard l(m_lock);
m_chain.clear(); m_chain.clear();
m_chain.reserve(_chain.size()); m_chain.reserve(_chain.size());
@ -112,11 +118,9 @@ public:
void reset() void reset()
{ {
{ DEV_READ_GUARDED(x_subs)
ReadGuard l(x_subs);
for (auto i: m_subs) for (auto i: m_subs)
i->resetFetch(); i->resetFetch();
}
WriteGuard l(m_lock); WriteGuard l(m_lock);
m_chain.clear(); m_chain.clear();
m_blocksGot.reset(); m_blocksGot.reset();
@ -127,11 +131,9 @@ public:
ReadGuard l(m_lock); ReadGuard l(m_lock);
auto ret = m_blocksGot; auto ret = m_blocksGot;
if (!_desperate) if (!_desperate)
{ DEV_READ_GUARDED(x_subs)
ReadGuard l(x_subs);
for (auto i: m_subs) for (auto i: m_subs)
ret += i->m_asked; ret += i->m_asked;
}
return ret; return ret;
} }
@ -144,12 +146,15 @@ public:
h256s remaining() const h256s remaining() const
{ {
h256s ret; h256s ret;
ReadGuard l(m_lock); DEV_READ_GUARDED(m_lock)
for (auto i: m_blocksGot.inverted()) for (auto i: m_blocksGot.inverted())
ret.push_back(m_chain[i]); ret.push_back(m_chain[i]);
return ret; return ret;
} }
h256 firstBlock() const { return m_chain.empty() ? h256() : m_chain[0]; }
Overview overview() const;
size_t chainSize() const { ReadGuard l(m_lock); return m_chain.size(); } size_t chainSize() const { ReadGuard l(m_lock); return m_chain.size(); }
size_t chainEmpty() const { ReadGuard l(m_lock); return m_chain.empty(); } size_t chainEmpty() const { ReadGuard l(m_lock); return m_chain.empty(); }
void foreachSub(std::function<void(DownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); } void foreachSub(std::function<void(DownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); }

83
libethereum/EthereumHost.cpp

@ -45,6 +45,12 @@ static unsigned const c_maxSendTransactions = 256;
char const* const EthereumHost::s_stateNames[static_cast<int>(SyncState::Size)] = {"Idle", "Waiting", "Hashes", "Blocks", "NewBlocks" }; char const* const EthereumHost::s_stateNames[static_cast<int>(SyncState::Size)] = {"Idle", "Waiting", "Hashes", "Blocks", "NewBlocks" };
#ifdef _WIN32
const char* EthereumHostTrace::name() { return EthPurple "^" EthGray " "; }
#else
const char* EthereumHostTrace::name() { return EthPurple "" EthGray " "; }
#endif
EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId): EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
HostCapability<EthereumPeer>(), HostCapability<EthereumPeer>(),
Worker ("ethsync"), Worker ("ethsync"),
@ -54,6 +60,7 @@ EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQu
m_networkId (_networkId) m_networkId (_networkId)
{ {
m_latestBlockSent = _ch.currentHash(); m_latestBlockSent = _ch.currentHash();
m_tq.onImport([this](ImportResult _ir, h256 const& _h, h512 const& _nodeId) { onTransactionImported(_ir, _h, _nodeId); });
} }
EthereumHost::~EthereumHost() EthereumHost::~EthereumHost()
@ -66,8 +73,9 @@ bool EthereumHost::ensureInitialised()
{ {
// First time - just initialise. // First time - just initialise.
m_latestBlockSent = m_chain.currentHash(); m_latestBlockSent = m_chain.currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent; clog(EthereumHostTrace) << "Initialising: latest=" << m_latestBlockSent;
Guard l(x_transactions);
m_transactionsSent = m_tq.knownTransactions(); m_transactionsSent = m_tq.knownTransactions();
return true; return true;
} }
@ -82,6 +90,7 @@ void EthereumHost::reset()
m_sync.reset(); m_sync.reset();
m_latestBlockSent = h256(); m_latestBlockSent = h256();
Guard tl(x_transactions);
m_transactionsSent.clear(); m_transactionsSent.clear();
} }
@ -116,6 +125,8 @@ void EthereumHost::maintainTransactions()
// Send any new transactions. // Send any new transactions.
unordered_map<std::shared_ptr<EthereumPeer>, std::vector<size_t>> peerTransactions; unordered_map<std::shared_ptr<EthereumPeer>, std::vector<size_t>> peerTransactions;
auto ts = m_tq.topTransactions(c_maxSendTransactions); auto ts = m_tq.topTransactions(c_maxSendTransactions);
{
Guard l(x_transactions);
for (size_t i = 0; i < ts.size(); ++i) for (size_t i = 0; i < ts.size(); ++i)
{ {
auto const& t = ts[i]; auto const& t = ts[i];
@ -126,6 +137,7 @@ void EthereumHost::maintainTransactions()
} }
for (auto const& t: ts) for (auto const& t: ts)
m_transactionsSent.insert(t.sha3()); m_transactionsSent.insert(t.sha3());
}
foreachPeer([&](shared_ptr<EthereumPeer> _p) foreachPeer([&](shared_ptr<EthereumPeer> _p)
{ {
bytes b; bytes b;
@ -144,7 +156,7 @@ void EthereumHost::maintainTransactions()
RLPStream ts; RLPStream ts;
_p->prep(ts, TransactionsPacket, n).appendRaw(b, n); _p->prep(ts, TransactionsPacket, n).appendRaw(b, n);
_p->sealAndSend(ts); _p->sealAndSend(ts);
cnote << "Sent" << n << "transactions to " << _p->session()->info().clientVersion; clog(EthereumHostTrace) << "Sent" << n << "transactions to " << _p->session()->info().clientVersion;
} }
_p->m_requireTransactions = false; _p->m_requireTransactions = false;
return true; return true;
@ -200,11 +212,15 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash)
if (diff(detailsFrom.number, detailsTo.number) < 20) if (diff(detailsFrom.number, detailsTo.number) < 20)
{ {
// don't be sending more than 20 "new" blocks. if there are any more we were probably waaaay behind. // don't be sending more than 20 "new" blocks. if there are any more we were probably waaaay behind.
clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; clog(EthereumHostTrace) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true)); h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true));
auto s = randomSelection(25, [&](EthereumPeer* p){ DEV_GUARDED(p->x_knownBlocks) return !p->m_knownBlocks.count(_currentHash); return false; }); auto s = randomSelection(25, [&](EthereumPeer* p){
DEV_GUARDED(p->x_knownBlocks)
return !p->m_knownBlocks.count(_currentHash);
return false;
});
for (shared_ptr<EthereumPeer> const& p: get<0>(s)) for (shared_ptr<EthereumPeer> const& p: get<0>(s))
for (auto const& b: blocks) for (auto const& b: blocks)
{ {
@ -286,33 +302,12 @@ void EthereumHost::onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP c
{ {
if (_peer->isCriticalSyncing()) if (_peer->isCriticalSyncing())
{ {
clog(NetAllDetail) << "Ignoring transaction from peer we are syncing with"; clog(EthereumHostTrace) << "Ignoring transaction from peer we are syncing with";
return; return;
} }
unsigned itemCount = _r.itemCount(); unsigned itemCount = _r.itemCount();
clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)"; clog(EthereumHostTrace) << "Transactions (" << dec << itemCount << "entries)";
Guard l(_peer->x_knownTransactions); m_tq.enqueue(_r, _peer->session()->id());
for (unsigned i = 0; i < min<unsigned>(itemCount, 32); ++i) // process 256 transactions at most. TODO: much better solution.
{
auto h = sha3(_r[i].data());
_peer->m_knownTransactions.insert(h);
ImportResult ir = m_tq.import(_r[i].data());
switch (ir)
{
case ImportResult::Malformed:
_peer->addRating(-100);
break;
case ImportResult::AlreadyKnown:
// if we already had the transaction, then don't bother sending it on.
m_transactionsSent.insert(h);
_peer->addRating(0);
break;
case ImportResult::Success:
_peer->addRating(100);
break;
default:;
}
}
} }
void EthereumHost::onPeerAborting() void EthereumHost::onPeerAborting()
@ -344,3 +339,35 @@ SyncStatus EthereumHost::status() const
return SyncStatus(); return SyncStatus();
return m_sync->status(); return m_sync->status();
} }
void EthereumHost::onTransactionImported(ImportResult _ir, h256 const& _h, h512 const& _nodeId)
{
auto session = host()->peerSession(_nodeId);
if (!session)
return;
std::shared_ptr<EthereumPeer> peer = session->cap<EthereumPeer>();
if (!peer)
peer = session->cap<EthereumPeer>(c_oldProtocolVersion);
if (!peer)
return;
Guard l(peer->x_knownTransactions);
peer->m_knownTransactions.insert(_h);
switch (_ir)
{
case ImportResult::Malformed:
peer->addRating(-100);
break;
case ImportResult::AlreadyKnown:
// if we already had the transaction, then don't bother sending it on.
DEV_GUARDED(x_transactions)
m_transactionsSent.insert(_h);
peer->addRating(0);
break;
case ImportResult::Success:
peer->addRating(100);
break;
default:;
}
}

4
libethereum/EthereumHost.h

@ -49,6 +49,8 @@ class TransactionQueue;
class BlockQueue; class BlockQueue;
class BlockChainSync; class BlockChainSync;
struct EthereumHostTrace: public LogChannel { static const char* name(); static const int verbosity = 6; };
/** /**
* @brief The EthereumHost class * @brief The EthereumHost class
* @warning None of this is thread-safe. You have been warned. * @warning None of this is thread-safe. You have been warned.
@ -105,6 +107,7 @@ private:
void maintainTransactions(); void maintainTransactions();
void maintainBlocks(h256 const& _currentBlock); void maintainBlocks(h256 const& _currentBlock);
void onTransactionImported(ImportResult _ir, h256 const& _h, h512 const& _nodeId);
/// Check to see if the network peer-state initialisation has happened. /// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return (bool)m_latestBlockSent; } bool isInitialised() const { return (bool)m_latestBlockSent; }
@ -132,6 +135,7 @@ private:
bool m_newBlocks = false; bool m_newBlocks = false;
mutable Mutex x_sync; mutable Mutex x_sync;
mutable Mutex x_transactions;
DownloadMan m_man; DownloadMan m_man;
std::unique_ptr<BlockChainSync> m_sync; std::unique_ptr<BlockChainSync> m_sync;
}; };

9
libethereum/Executive.cpp

@ -153,6 +153,11 @@ u256 Executive::gasUsed() const
return m_t.gas() - m_gas; return m_t.gas() - m_gas;
} }
u256 Executive::gasUsedNoRefunds() const
{
return m_t.gas() - m_gas + m_refunded;
}
void Executive::accrueSubState(SubState& _parentContext) void Executive::accrueSubState(SubState& _parentContext)
{ {
if (m_ext) if (m_ext)
@ -391,8 +396,8 @@ void Executive::finalize()
// SSTORE refunds... // SSTORE refunds...
// must be done before the miner gets the fees. // must be done before the miner gets the fees.
if (m_ext) m_refunded = m_ext ? min((m_t.gas() - m_gas) / 2, m_ext->sub.refunds) : 0;
m_gas += min((m_t.gas() - m_gas) / 2, m_ext->sub.refunds); m_gas += m_refunded;
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice());

4
libethereum/Executive.h

@ -110,6 +110,9 @@ public:
/// @returns total gas used in the transaction/operation. /// @returns total gas used in the transaction/operation.
/// @warning Only valid after finalise(). /// @warning Only valid after finalise().
u256 gasUsed() const; u256 gasUsed() const;
/// @returns total gas used in the transaction/operation, excluding anything refunded.
/// @warning Only valid after finalise().
u256 gasUsedNoRefunds() const;
/// Set up the executive for evaluating a bare CREATE (contract-creation) operation. /// Set up the executive for evaluating a bare CREATE (contract-creation) operation.
/// @returns false iff go() must be called (and thus a VM execution in required). /// @returns false iff go() must be called (and thus a VM execution in required).
@ -154,6 +157,7 @@ private:
bool m_isCreation = false; ///< True if the transaction creates a contract, or if create() is called. bool m_isCreation = false; ///< True if the transaction creates a contract, or if create() is called.
TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception. TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception.
u256 m_gas = 0; ///< The gas for EVM code execution. Initial amount before go() execution, final amount after go() execution. u256 m_gas = 0; ///< The gas for EVM code execution. Initial amount before go() execution, final amount after go() execution.
u256 m_refunded = 0; ///< The amount of gas refunded.
Transaction m_t; ///< The original transaction. Set by setup(). Transaction m_t; ///< The original transaction. Set by setup().
LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize(). LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize().

18
libethereum/ExtVM.cpp

@ -33,13 +33,21 @@ namespace
static unsigned const c_depthLimit = 1024; static unsigned const c_depthLimit = 1024;
/// Upper bound of stack space needed by single CALL/CREATE execution. Set experimentally. /// Upper bound of stack space needed by single CALL/CREATE execution. Set experimentally.
static size_t const c_singleExecutionStackSize = 12 * 1024; static size_t const c_singleExecutionStackSize =
#ifdef NDEBUG
12 * 1024;
#else
33 * 1024;
#endif
/// Standard OSX thread stack limit. Should be reasonable for other platforms too. /// Standard OSX thread stack limit. Should be reasonable for other platforms too.
static size_t const c_defaultStackSize = 512 * 1024; static size_t const c_defaultStackSize = 512 * 1024;
/// Stack overhead prior to allocation.
static size_t const c_entryOverhead = 128 * 1024;
/// On what depth execution should be offloaded to additional separated stack space. /// On what depth execution should be offloaded to additional separated stack space.
static unsigned const c_offloadPoint = c_defaultStackSize / c_singleExecutionStackSize; static unsigned const c_offloadPoint = (c_defaultStackSize - c_entryOverhead) / c_singleExecutionStackSize;
void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp) void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp)
{ {
@ -70,6 +78,7 @@ void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp)
// Current stack is too small to handle more CALL/CREATE executions. // Current stack is too small to handle more CALL/CREATE executions.
// It needs to be done only once as newly allocated stack space it enough to handle // It needs to be done only once as newly allocated stack space it enough to handle
// the rest of the calls up to the depth limit (c_depthLimit). // the rest of the calls up to the depth limit (c_depthLimit).
if (_depth == c_offloadPoint) if (_depth == c_offloadPoint)
goOnOffloadedStack(_e, _onOp); goOnOffloadedStack(_e, _onOp);
else else
@ -82,7 +91,11 @@ bool ExtVM::call(CallParameters& _p)
Executive e(m_s, lastHashes, depth + 1); Executive e(m_s, lastHashes, depth + 1);
if (!e.call(_p, gasPrice, origin)) if (!e.call(_p, gasPrice, origin))
{ {
#if __clang__ // Enabled for clang only as the problem affects OSX
go(depth, e, _p.onOp); go(depth, e, _p.onOp);
#else
e.go(_p.onOp);
#endif
e.accrueSubState(sub); e.accrueSubState(sub);
} }
_p.gas = e.gas(); _p.gas = e.gas();
@ -104,4 +117,3 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc
io_gas = e.gas(); io_gas = e.gas();
return e.newAddress(); return e.newAddress();
} }

29
libethereum/Interface.cpp

@ -20,6 +20,31 @@
*/ */
#include "Interface.h" #include "Interface.h"
using namespace std;
using namespace dev;
using namespace eth;
#pragma GCC diagnostic ignored "-Wunused-variable" void Interface::submitTransaction(Secret const& _secret, u256 const& _value, Address const& _dest, bytes const& _data, u256 const& _gas, u256 const& _gasPrice, u256 const& _nonce)
namespace { char dummy; } {
TransactionSkeleton ts;
ts.creation = false;
ts.value = _value;
ts.to = _dest;
ts.data = _data;
ts.gas = _gas;
ts.gasPrice = _gasPrice;
ts.nonce = _nonce;
submitTransaction(ts, _secret);
}
Address Interface::submitTransaction(Secret const& _secret, u256 const& _endowment, bytes const& _init, u256 const& _gas, u256 const& _gasPrice, u256 const& _nonce)
{
TransactionSkeleton ts;
ts.creation = true;
ts.value = _endowment;
ts.data = _init;
ts.gas = _gas;
ts.gasPrice = _gasPrice;
ts.nonce = _nonce;
return submitTransaction(ts, _secret).second;
}

13
libethereum/Interface.h

@ -65,16 +65,16 @@ public:
// [TRANSACTION API] // [TRANSACTION API]
/// Submits the given message-call transaction. /// Submits a new transaction.
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0; /// @returns the transaction's hash.
virtual std::pair<h256, Address> submitTransaction(TransactionSkeleton const& _t, Secret const& _secret) = 0;
/// Submits a new contract-creation transaction. /// Submits the given message-call transaction.
/// @returns the new contract's address (assuming it all goes through). void submitTransaction(Secret const& _secret, u256 const& _value, Address const& _dest, bytes const& _data = bytes(), u256 const& _gas = 10000, u256 const& _gasPrice = 10 * szabo, u256 const& _nonce = UndefinedU256);
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0;
/// Submits a new contract-creation transaction. /// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through). /// @returns the new contract's address (assuming it all goes through).
Address submitTransaction(Secret const& _secret, TransactionSkeleton const& _t) { if (_t.creation) return submitTransaction(_secret, _t.value, _t.data, _t.gas, _t.gasPrice); submitTransaction(_secret, _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); return Address(); } Address submitTransaction(Secret const& _secret, u256 const& _endowment, bytes const& _init, u256 const& _gas = 10000, u256 const& _gasPrice = 10 * szabo, u256 const& _nonce = UndefinedU256);
/// Blocks until all pending transactions have been processed. /// Blocks until all pending transactions have been processed.
virtual void flushTransactions() = 0; virtual void flushTransactions() = 0;
@ -135,6 +135,7 @@ public:
virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0; virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0;
virtual Transaction transaction(h256 _transactionHash) const = 0; virtual Transaction transaction(h256 _transactionHash) const = 0;
virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const = 0;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const = 0; virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const = 0;
virtual h256 hashFromNumber(BlockNumber _number) const = 0; virtual h256 hashFromNumber(BlockNumber _number) const = 0;
virtual BlockNumber numberFromHash(h256 _blockHash) const = 0; virtual BlockNumber numberFromHash(h256 _blockHash) const = 0;

30
libethereum/State.cpp

@ -38,6 +38,7 @@
#include "Executive.h" #include "Executive.h"
#include "CachedAddressState.h" #include "CachedAddressState.h"
#include "CanonBlockChain.h" #include "CanonBlockChain.h"
#include "TransactionQueue.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
@ -444,7 +445,8 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor
#if ETH_TIMED_ENACTMENTS #if ETH_TIMED_ENACTMENTS
enactment = t.elapsed(); enactment = t.elapsed();
cnote << "popVer/popGrand/syncReset/enactment = " << populateVerify << "/" << populateGrand << "/" << syncReset << "/" << enactment; if (populateVerify + populateGrand + syncReset + enactment > 0.5)
clog(StateChat) << "popVer/popGrand/syncReset/enactment = " << populateVerify << "/" << populateGrand << "/" << syncReset << "/" << enactment;
#endif #endif
return ret; return ret;
} }
@ -522,8 +524,7 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
} }
else if (t.gasPrice() < _gp.ask(*this) * 9 / 10) else if (t.gasPrice() < _gp.ask(*this) * 9 / 10)
{ {
// less than 90% of our ask price for gas. drop. clog(StateTrace) << t.sha3() << "Dropping El Cheapo transaction (<90% of ask price)";
cnote << t.sha3() << "Dropping El Cheapo transaction (<90% of ask price)";
_tq.drop(t.sha3()); _tq.drop(t.sha3());
} }
} }
@ -535,22 +536,13 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
if (req > got) if (req > got)
{ {
// too old // too old
for (Transaction const& mt: m_transactions) clog(StateTrace) << t.sha3() << "Dropping old transaction (nonce too low)";
{
if (mt.from() == t.from())
{
if (mt.nonce() < t.nonce())
cnote << t.sha3() << "Dropping old transaction (nonce too low)";
else if (mt.nonce() == t.nonce() && mt.gasPrice() <= t.gasPrice())
cnote << t.sha3() << "Dropping old transaction (gas price lower)";
}
}
_tq.drop(t.sha3()); _tq.drop(t.sha3());
} }
else if (got > req + _tq.waiting(t.sender())) else if (got > req + _tq.waiting(t.sender()))
{ {
// too new // too new
cnote << t.sha3() << "Dropping new transaction (too many nonces ahead)"; clog(StateTrace) << t.sha3() << "Dropping new transaction (too many nonces ahead)";
_tq.drop(t.sha3()); _tq.drop(t.sha3());
} }
else else
@ -561,7 +553,7 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
bigint const& got = *boost::get_error_info<errinfo_got>(e); bigint const& got = *boost::get_error_info<errinfo_got>(e);
if (got > m_currentBlock.gasLimit) if (got > m_currentBlock.gasLimit)
{ {
cnote << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)";
_tq.drop(t.sha3()); _tq.drop(t.sha3());
} }
else else
@ -575,14 +567,14 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
catch (Exception const& _e) catch (Exception const& _e)
{ {
// Something else went wrong - drop it. // Something else went wrong - drop it.
cnote << t.sha3() << "Dropping invalid transaction:" << diagnostic_information(_e); clog(StateTrace) << t.sha3() << "Dropping invalid transaction:" << diagnostic_information(_e);
_tq.drop(t.sha3()); _tq.drop(t.sha3());
} }
catch (std::exception const&) catch (std::exception const&)
{ {
// Something else went wrong - drop it. // Something else went wrong - drop it.
_tq.drop(t.sha3()); _tq.drop(t.sha3());
cnote << t.sha3() << "Transaction caused low-level exception :("; cwarn << t.sha3() << "Transaction caused low-level exception :(";
} }
} }
if (chrono::steady_clock::now() > deadline) if (chrono::steady_clock::now() > deadline)
@ -964,6 +956,8 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
m_currentBlock.stateRoot = m_state.root(); m_currentBlock.stateRoot = m_state.root();
m_currentBlock.parentHash = m_previousBlock.hash(); m_currentBlock.parentHash = m_previousBlock.hash();
m_currentBlock.extraData = _extraData; m_currentBlock.extraData = _extraData;
if (m_currentBlock.extraData.size() > 32)
m_currentBlock.extraData.resize(32);
m_committedToMine = true; m_committedToMine = true;
} }
@ -1218,7 +1212,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
uncommitToMine(); uncommitToMine();
// OK - transaction looks valid - execute. // OK - transaction looks valid - execute.
u256 startGasUsed = gasUsed(); u256 startGasUsed = e.gasUsed();
#if ETH_PARANOIA #if ETH_PARANOIA
ctrace << "Executing" << e.t() << "on" << h; ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp()); ctrace << toHex(e.t().rlp());

2
libethereum/State.h

@ -32,7 +32,6 @@
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libethcore/Miner.h> #include <libethcore/Miner.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include "TransactionQueue.h"
#include "Account.h" #include "Account.h"
#include "Transaction.h" #include "Transaction.h"
#include "TransactionReceipt.h" #include "TransactionReceipt.h"
@ -67,6 +66,7 @@ using LogBloomRequirementError = boost::tuple<errinfo_required_LogBloom, errinfo
class BlockChain; class BlockChain;
class State; class State;
class TransactionQueue;
struct VerifiedBlockRef; struct VerifiedBlockRef;
struct StateChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct StateChat: public LogChannel { static const char* name(); static const int verbosity = 4; };

7
libethereum/Transaction.h

@ -85,6 +85,9 @@ public:
/// Constructs a null transaction. /// Constructs a null transaction.
Transaction() {} Transaction() {}
/// Constructs from a transaction skeleton & optional secret.
Transaction(TransactionSkeleton const& _ts, Secret const& _s = Secret()): TransactionBase(_ts, _s) {}
/// Constructs a signed message-call transaction. /// Constructs a signed message-call transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce, Secret const& _secret): Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce, Secret const& _secret):
TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce, _secret) TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce, _secret)
@ -96,12 +99,12 @@ public:
{} {}
/// Constructs an unsigned message-call transaction. /// Constructs an unsigned message-call transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce = 0): Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce = UndefinedU256):
TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce) TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce)
{} {}
/// Constructs an unsigned contract-creation transaction. /// Constructs an unsigned contract-creation transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = 0): Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = UndefinedU256):
TransactionBase(_value, _gasPrice, _gas, _data, _nonce) TransactionBase(_value, _gasPrice, _gas, _data, _nonce)
{} {}

153
libethereum/TransactionQueue.cpp

@ -31,7 +31,28 @@ using namespace dev::eth;
const char* TransactionQueueChannel::name() { return EthCyan "┉┅▶"; } const char* TransactionQueueChannel::name() { return EthCyan "┉┅▶"; }
const char* TransactionQueueTraceChannel::name() { return EthCyan " ┅▶"; } const char* TransactionQueueTraceChannel::name() { return EthCyan " ┅▶"; }
ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb, IfDropped _ik) TransactionQueue::TransactionQueue(unsigned _limit, unsigned _futureLimit):
m_current(PriorityCompare { *this }),
m_limit(_limit),
m_futureLimit(_futureLimit)
{
unsigned verifierThreads = std::max(thread::hardware_concurrency(), 3U) - 2U;
for (unsigned i = 0; i < verifierThreads; ++i)
m_verifiers.emplace_back([=](){
setThreadName("txcheck" + toString(i));
this->verifierBody();
});
}
TransactionQueue::~TransactionQueue()
{
m_aborting = true;
m_queueReady.notify_all();
for (auto& i: m_verifiers)
i.join();
}
ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, IfDropped _ik)
{ {
// Check if we already know this transaction. // Check if we already know this transaction.
h256 h = sha3(_transactionRLP); h256 h = sha3(_transactionRLP);
@ -49,14 +70,13 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb
{ {
t = Transaction(_transactionRLP, CheckTransaction::Everything); t = Transaction(_transactionRLP, CheckTransaction::Everything);
UpgradeGuard ul(l); UpgradeGuard ul(l);
ir = manageImport_WITH_LOCK(h, t, _cb); ir = manageImport_WITH_LOCK(h, t);
} }
catch (...) catch (...)
{ {
return ImportResult::Malformed; return ImportResult::Malformed;
} }
} }
// cdebug << "import-END: Nonce of" << t.sender() << "now" << maxNonce(t.sender());
return ir; return ir;
} }
@ -71,27 +91,24 @@ ImportResult TransactionQueue::check_WITH_LOCK(h256 const& _h, IfDropped _ik)
return ImportResult::Success; return ImportResult::Success;
} }
ImportResult TransactionQueue::import(Transaction const& _transaction, ImportCallback const& _cb, IfDropped _ik) ImportResult TransactionQueue::import(Transaction const& _transaction, IfDropped _ik)
{ {
// Check if we already know this transaction. // Check if we already know this transaction.
h256 h = _transaction.sha3(WithSignature); h256 h = _transaction.sha3(WithSignature);
// cdebug << "import-BEGIN: Nonce of sender" << maxNonce(_transaction.sender());
ImportResult ret; ImportResult ret;
{ {
UpgradableGuard l(m_lock); UpgradableGuard l(m_lock);
// TODO: keep old transactions around and check in State for nonce validity // TODO: keep old transactions around and check in State for nonce validity
auto ir = check_WITH_LOCK(h, _ik); auto ir = check_WITH_LOCK(h, _ik);
if (ir != ImportResult::Success) if (ir != ImportResult::Success)
return ir; return ir;
{ {
UpgradeGuard ul(l); UpgradeGuard ul(l);
ret = manageImport_WITH_LOCK(h, _transaction, _cb); ret = manageImport_WITH_LOCK(h, _transaction);
} }
} }
// cdebug << "import-END: Nonce of" << _transaction.sender() << "now" << maxNonce(_transaction.sender());
return ret; return ret;
} }
@ -111,7 +128,7 @@ h256Hash TransactionQueue::knownTransactions() const
return m_known; return m_known;
} }
ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction, ImportCallback const& _cb) ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction)
{ {
try try
{ {
@ -149,10 +166,8 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
} }
} }
} }
// If valid, append to blocks. // If valid, append to transactions.
insertCurrent_WITH_LOCK(make_pair(_h, _transaction)); insertCurrent_WITH_LOCK(make_pair(_h, _transaction));
if (_cb)
m_callbacks[_h] = _cb;
clog(TransactionQueueTraceChannel) << "Queued vaguely legit-looking transaction" << _h; clog(TransactionQueueTraceChannel) << "Queued vaguely legit-looking transaction" << _h;
while (m_current.size() > m_limit) while (m_current.size() > m_limit)
@ -179,7 +194,6 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
u256 TransactionQueue::maxNonce(Address const& _a) const u256 TransactionQueue::maxNonce(Address const& _a) const
{ {
// cdebug << "txQ::maxNonce" << _a;
ReadGuard l(m_lock); ReadGuard l(m_lock);
return maxNonce_WITH_LOCK(_a); return maxNonce_WITH_LOCK(_a);
} }
@ -212,29 +226,7 @@ void TransactionQueue::insertCurrent_WITH_LOCK(std::pair<h256, Transaction> cons
m_currentByHash[_p.first] = handle; m_currentByHash[_p.first] = handle;
// Move following transactions from future to current // Move following transactions from future to current
auto fs = m_future.find(t.from()); makeCurrent_WITH_LOCK(t);
if (fs != m_future.end())
{
u256 nonce = t.nonce() + 1;
auto fb = fs->second.find(nonce);
if (fb != fs->second.end())
{
auto ft = fb;
while (ft != fs->second.end() && ft->second.transaction.nonce() == nonce)
{
inserted = m_currentByAddressAndNonce[t.from()].insert(std::make_pair(ft->second.transaction.nonce(), PriorityQueue::iterator()));
PriorityQueue::iterator handle = m_current.emplace(move(ft->second));
inserted.first->second = handle;
m_currentByHash[(*handle).transaction.sha3()] = handle;
--m_futureSize;
++ft;
++nonce;
}
fs->second.erase(fb, ft);
if (fs->second.empty())
m_future.erase(t.from());
}
}
m_known.insert(_p.first); m_known.insert(_p.first);
} }
@ -296,6 +288,44 @@ void TransactionQueue::setFuture(h256 const& _txHash)
m_currentByAddressAndNonce.erase(from); m_currentByAddressAndNonce.erase(from);
} }
void TransactionQueue::makeCurrent_WITH_LOCK(Transaction const& _t)
{
auto fs = m_future.find(_t.from());
if (fs != m_future.end())
{
u256 nonce = _t.nonce() + 1;
auto fb = fs->second.find(nonce);
if (fb != fs->second.end())
{
auto ft = fb;
while (ft != fs->second.end() && ft->second.transaction.nonce() == nonce)
{
auto inserted = m_currentByAddressAndNonce[_t.from()].insert(std::make_pair(ft->second.transaction.nonce(), PriorityQueue::iterator()));
PriorityQueue::iterator handle = m_current.emplace(move(ft->second));
inserted.first->second = handle;
m_currentByHash[(*handle).transaction.sha3()] = handle;
--m_futureSize;
++ft;
++nonce;
}
fs->second.erase(fb, ft);
if (fs->second.empty())
m_future.erase(_t.from());
}
}
while (m_futureSize > m_futureLimit)
{
// TODO: priority queue for future transactions
// For now just drop random chain end
--m_futureSize;
clog(TransactionQueueTraceChannel) << "Dropping out of bounds future transaction" << m_future.begin()->second.rbegin()->second.transaction.sha3();
m_future.begin()->second.erase(--m_future.begin()->second.end());
if (m_future.begin()->second.empty())
m_future.erase(m_future.begin());
}
}
void TransactionQueue::drop(h256 const& _txHash) void TransactionQueue::drop(h256 const& _txHash)
{ {
UpgradableGuard l(m_lock); UpgradableGuard l(m_lock);
@ -305,9 +335,17 @@ void TransactionQueue::drop(h256 const& _txHash)
UpgradeGuard ul(l); UpgradeGuard ul(l);
m_dropped.insert(_txHash); m_dropped.insert(_txHash);
remove_WITH_LOCK(_txHash); remove_WITH_LOCK(_txHash);
}
void TransactionQueue::dropGood(Transaction const& _t)
{
WriteGuard l(m_lock);
makeCurrent_WITH_LOCK(_t);
if (!m_known.count(_t.sha3()))
return;
m_dropped.insert(_t.sha3());
remove_WITH_LOCK(_t.sha3());
} }
void TransactionQueue::clear() void TransactionQueue::clear()
@ -320,3 +358,44 @@ void TransactionQueue::clear()
m_future.clear(); m_future.clear();
m_futureSize = 0; m_futureSize = 0;
} }
void TransactionQueue::enqueue(RLP const& _data, h512 const& _nodeId)
{
{
Guard l(x_queue);
unsigned itemCount = _data.itemCount();
for (unsigned i = 0; i < itemCount; ++i)
m_unverified.emplace_back(UnverifiedTransaction(_data[i].data(), _nodeId));
}
m_queueReady.notify_all();
}
void TransactionQueue::verifierBody()
{
while (!m_aborting)
{
UnverifiedTransaction work;
{
unique_lock<Mutex> l(x_queue);
m_queueReady.wait(l, [&](){ return !m_unverified.empty() || m_aborting; });
if (m_aborting)
return;
work = move(m_unverified.front());
m_unverified.pop_front();
}
try
{
Transaction t(work.transaction, CheckTransaction::Cheap); //Signature will be checked later
ImportResult ir = import(t);
m_onImport(ir, t.sha3(), work.nodeId);
}
catch (...)
{
// should not happen as exceptions are handled in import.
cwarn << "Bad transaction:" << boost::current_exception_diagnostic_information();
}
}
}

48
libethereum/TransactionQueue.h

@ -22,6 +22,9 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <condition_variable>
#include <thread>
#include <deque>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
@ -49,15 +52,14 @@ enum class IfDropped { Ignore, Retry };
class TransactionQueue class TransactionQueue
{ {
public: public:
using ImportCallback = std::function<void(ImportResult)>;
/// @brief TransactionQueue /// @brief TransactionQueue
/// @param _limit Maximum number of pending transactions in the queue /// @param _limit Maximum number of pending transactions in the queue
/// @param _futureLimit Maximum number of future nonce transactions /// @param _futureLimit Maximum number of future nonce transactions
TransactionQueue(unsigned _limit = 1024, unsigned _futureLimit = 1024): m_current(PriorityCompare { *this }), m_limit(_limit), m_futureLimit(_futureLimit) {} TransactionQueue(unsigned _limit = 1024, unsigned _futureLimit = 1024);
ImportResult import(Transaction const& _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore); ~TransactionQueue();
ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore) { return import(&_tx, _cb, _ik); } void enqueue(RLP const& _data, h512 const& _nodeId);
ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore); ImportResult import(bytes const& _tx, IfDropped _ik = IfDropped::Ignore) { return import(&_tx, _ik); }
ImportResult import(Transaction const& _tx, IfDropped _ik = IfDropped::Ignore);
void drop(h256 const& _txHash); void drop(h256 const& _txHash);
@ -66,9 +68,11 @@ public:
h256Hash knownTransactions() const; h256Hash knownTransactions() const;
u256 maxNonce(Address const& _a) const; u256 maxNonce(Address const& _a) const;
void setFuture(h256 const& _t); void setFuture(h256 const& _t);
void dropGood(Transaction const& _t);
void clear(); void clear();
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); } template <class T> Handler<> onReady(T const& _t) { return m_onReady.add(_t); }
template <class T> Handler<ImportResult, h256 const&, h512 const&> onImport(T const& _t) { return m_onImport.add(_t); }
private: private:
struct VerifiedTransaction struct VerifiedTransaction
@ -77,11 +81,25 @@ private:
VerifiedTransaction(VerifiedTransaction&& _t): transaction(std::move(_t.transaction)) {} VerifiedTransaction(VerifiedTransaction&& _t): transaction(std::move(_t.transaction)) {}
VerifiedTransaction(VerifiedTransaction const&) = delete; VerifiedTransaction(VerifiedTransaction const&) = delete;
VerifiedTransaction operator=(VerifiedTransaction const&) = delete; VerifiedTransaction& operator=(VerifiedTransaction const&) = delete;
Transaction transaction; Transaction transaction;
}; };
struct UnverifiedTransaction
{
UnverifiedTransaction() {}
UnverifiedTransaction(bytesConstRef const& _t, h512 const& _nodeId): transaction(_t.toBytes()), nodeId(_nodeId) {}
UnverifiedTransaction(UnverifiedTransaction&& _t): transaction(std::move(_t.transaction)) {}
UnverifiedTransaction& operator=(UnverifiedTransaction&& _other) { transaction = std::move(_other.transaction); nodeId = std::move(_other.nodeId); return *this; }
UnverifiedTransaction(UnverifiedTransaction const&) = delete;
UnverifiedTransaction& operator=(UnverifiedTransaction const&) = delete;
bytes transaction;
h512 nodeId;
};
struct PriorityCompare struct PriorityCompare
{ {
TransactionQueue& queue; TransactionQueue& queue;
@ -96,12 +114,15 @@ private:
// Use a set with dynamic comparator for minmax priority queue. The comparator takes into account min account nonce. Updating it does not affect the order. // Use a set with dynamic comparator for minmax priority queue. The comparator takes into account min account nonce. Updating it does not affect the order.
using PriorityQueue = std::multiset<VerifiedTransaction, PriorityCompare>; using PriorityQueue = std::multiset<VerifiedTransaction, PriorityCompare>;
ImportResult import(bytesConstRef _tx, IfDropped _ik = IfDropped::Ignore);
ImportResult check_WITH_LOCK(h256 const& _h, IfDropped _ik); ImportResult check_WITH_LOCK(h256 const& _h, IfDropped _ik);
ImportResult manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction, ImportCallback const& _cb); ImportResult manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction);
void insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p); void insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p);
void makeCurrent_WITH_LOCK(Transaction const& _t);
bool remove_WITH_LOCK(h256 const& _txHash); bool remove_WITH_LOCK(h256 const& _txHash);
u256 maxNonce_WITH_LOCK(Address const& _a) const; u256 maxNonce_WITH_LOCK(Address const& _a) const;
void verifierBody();
mutable SharedMutex m_lock; ///< General lock. mutable SharedMutex m_lock; ///< General lock.
h256Hash m_known; ///< Hashes of transactions in both sets. h256Hash m_known; ///< Hashes of transactions in both sets.
@ -114,10 +135,17 @@ private:
std::unordered_map<Address, std::map<u256, PriorityQueue::iterator>> m_currentByAddressAndNonce; ///< Transactions grouped by account and nonce std::unordered_map<Address, std::map<u256, PriorityQueue::iterator>> m_currentByAddressAndNonce; ///< Transactions grouped by account and nonce
std::unordered_map<Address, std::map<u256, VerifiedTransaction>> m_future; /// Future transactions std::unordered_map<Address, std::map<u256, VerifiedTransaction>> m_future; /// Future transactions
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. Signal<> m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
Signal<ImportResult, h256 const&, h512 const&> m_onImport; ///< Called for each import attempt. Arguments are result, transaction id an node id. Be nice and exit fast.
unsigned m_limit; ///< Max number of pending transactions unsigned m_limit; ///< Max number of pending transactions
unsigned m_futureLimit; ///< Max number of future transactions unsigned m_futureLimit; ///< Max number of future transactions
unsigned m_futureSize = 0; ///< Current number of future transactions unsigned m_futureSize = 0; ///< Current number of future transactions
std::condition_variable m_queueReady; ///< Signaled when m_unverified has a new entry.
std::vector<std::thread> m_verifiers;
std::deque<UnverifiedTransaction> m_unverified; ///< Pending verification queue
mutable Mutex x_queue; ///< Verification queue mutex
bool m_aborting = false; ///< Exit condition for verifier.
}; };
} }

2
libethereum/VerifiedBlock.h

@ -47,7 +47,7 @@ struct VerifiedBlock
VerifiedBlock(BlockInfo&& _bi) VerifiedBlock(BlockInfo&& _bi)
{ {
verified.info = _bi; verified.info = std::move(_bi);
} }
VerifiedBlock(VerifiedBlock&& _other): VerifiedBlock(VerifiedBlock&& _other):

6
libevm/ExtVMFace.cpp

@ -21,22 +21,20 @@
#include "ExtVMFace.h" #include "ExtVMFace.h"
using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth):
myAddress(_myAddress), myAddress(_myAddress),
caller(_caller), caller(_caller),
origin(_origin), origin(_origin),
value(_value), value(_value),
gasPrice(_gasPrice), gasPrice(_gasPrice),
data(_data), data(_data),
code(_code), code(std::move(_code)),
codeHash(_codeHash), codeHash(_codeHash),
lastHashes(_lh), lastHashes(_lh),
previousBlock(_previousBlock), previousBlock(_previousBlock),
currentBlock(_currentBlock), currentBlock(_currentBlock),
depth(_depth) depth(_depth)
{} {}

2
libevm/ExtVMFace.h

@ -161,7 +161,7 @@ public:
ExtVMFace() = default; ExtVMFace() = default;
/// Full constructor. /// Full constructor.
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth);
virtual ~ExtVMFace() = default; virtual ~ExtVMFace() = default;

1
libjsengine/CMakeLists.txt

@ -19,7 +19,6 @@ file(GLOB HEADERS "*.h")
include(EthUtils) include(EthUtils)
eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" "JSRES") eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" "JSRES")
message(STATUS "HERE!!! ${JSRES}")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES}) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
# macos brew version of v8 needs to be compiled with libstdc++ # macos brew version of v8 needs to be compiled with libstdc++

5
libp2p/Host.h

@ -202,6 +202,9 @@ public:
/// Validates and starts peer session, taking ownership of _io. Disconnects and returns false upon error. /// Validates and starts peer session, taking ownership of _io. Disconnects and returns false upon error.
void startPeerSession(Public const& _id, RLP const& _hello, RLPXFrameCoder* _io, std::shared_ptr<RLPXSocket> const& _s); void startPeerSession(Public const& _id, RLP const& _hello, RLPXFrameCoder* _io, std::shared_ptr<RLPXSocket> const& _s);
/// Get session by id
std::shared_ptr<Session> peerSession(NodeId const& _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? m_sessions[_id].lock() : std::shared_ptr<Session>(); }
protected: protected:
void onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e); void onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e);
@ -211,7 +214,7 @@ protected:
private: private:
enum PeerSlotRatio { Egress = 2, Ingress = 9 }; enum PeerSlotRatio { Egress = 2, Ingress = 9 };
bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; } bool havePeerSession(NodeId const& _id) { return !!peerSession(_id); }
/// Determines and sets m_tcpPublic to publicly advertised address. /// Determines and sets m_tcpPublic to publicly advertised address.
void determinePublic(); void determinePublic();

5
libp2p/Session.cpp

@ -256,9 +256,8 @@ bool Session::checkPacket(bytesConstRef _msg)
void Session::send(bytes&& _msg) void Session::send(bytes&& _msg)
{ {
clog(NetLeft) << RLP(bytesConstRef(&_msg).cropped(1));
bytesConstRef msg(&_msg); bytesConstRef msg(&_msg);
clog(NetLeft) << RLP(msg.cropped(1));
if (!checkPacket(msg)) if (!checkPacket(msg))
clog(NetWarn) << "INVALID PACKET CONSTRUCTED!"; clog(NetWarn) << "INVALID PACKET CONSTRUCTED!";
@ -268,7 +267,7 @@ void Session::send(bytes&& _msg)
bool doWrite = false; bool doWrite = false;
{ {
Guard l(x_writeQueue); Guard l(x_writeQueue);
m_writeQueue.push_back(_msg); m_writeQueue.push_back(std::move(_msg));
doWrite = (m_writeQueue.size() == 1); doWrite = (m_writeQueue.size() == 1);
} }

4
libtestutils/StateLoader.cpp

@ -36,10 +36,10 @@ StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath):
Address address = Address(name); Address address = Address(name);
bytes code = fromHex(o["code"].asString().substr(2)); bytes code = fromHex(o["code"].asString().substr(2));
if (code.size()) if (!code.empty())
{ {
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::ContractConception); m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::ContractConception);
m_state.m_cache[address].setCode(code); m_state.m_cache[address].setCode(std::move(code));
} }
else else
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::NormalCreation); m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::NormalCreation);

10
libweb3jsonrpc/AccountHolder.cpp

@ -106,20 +106,22 @@ AddressHash SimpleAccountHolder::realAccounts() const
return m_keyManager.accountsHash(); return m_keyManager.accountsHash();
} }
void SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t) h256 SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
{ {
if (isRealAccount(_t.from)) if (isRealAccount(_t.from))
m_client()->submitTransaction(m_keyManager.secret(_t.from, [&](){ return m_getPassword(_t.from); }), _t); return m_client()->submitTransaction(_t, m_keyManager.secret(_t.from, [&](){ return m_getPassword(_t.from); })).first;
else if (isProxyAccount(_t.from)) else if (isProxyAccount(_t.from))
queueTransaction(_t); queueTransaction(_t);
return h256();
} }
void FixedAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t) h256 FixedAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
{ {
if (isRealAccount(_t.from)) if (isRealAccount(_t.from))
m_client()->submitTransaction(m_accounts[_t.from], _t); return m_client()->submitTransaction(_t, m_accounts[_t.from]).first;
else if (isProxyAccount(_t.from)) else if (isProxyAccount(_t.from))
queueTransaction(_t); queueTransaction(_t);
return h256();
} }

6
libweb3jsonrpc/AccountHolder.h

@ -51,7 +51,7 @@ public:
virtual AddressHash realAccounts() const = 0; virtual AddressHash realAccounts() const = 0;
// use m_web3's submitTransaction // use m_web3's submitTransaction
// or use AccountHolder::queueTransaction(_t) to accept // or use AccountHolder::queueTransaction(_t) to accept
virtual void authenticate(dev::eth::TransactionSkeleton const& _t) = 0; virtual h256 authenticate(dev::eth::TransactionSkeleton const& _t) = 0;
Addresses allAccounts() const; Addresses allAccounts() const;
bool isRealAccount(Address const& _account) const { return realAccounts().count(_account) > 0; } bool isRealAccount(Address const& _account) const { return realAccounts().count(_account) > 0; }
@ -85,7 +85,7 @@ public:
{} {}
AddressHash realAccounts() const override; AddressHash realAccounts() const override;
void authenticate(dev::eth::TransactionSkeleton const& _t) override; h256 authenticate(dev::eth::TransactionSkeleton const& _t) override;
private: private:
std::function<std::string(Address)> m_getPassword; std::function<std::string(Address)> m_getPassword;
@ -117,7 +117,7 @@ public:
// use m_web3's submitTransaction // use m_web3's submitTransaction
// or use AccountHolder::queueTransaction(_t) to accept // or use AccountHolder::queueTransaction(_t) to accept
void authenticate(dev::eth::TransactionSkeleton const& _t) override; h256 authenticate(dev::eth::TransactionSkeleton const& _t) override;
private: private:
std::unordered_map<dev::Address, dev::Secret> m_accounts; std::unordered_map<dev::Address, dev::Secret> m_accounts;

30
libweb3jsonrpc/JsonHelper.cpp

@ -182,6 +182,33 @@ Json::Value toJson(dev::eth::TransactionReceipt const& _t)
return res; return res;
} }
Json::Value toJson(dev::eth::TransactionReceipt const& _tr, std::pair<h256, unsigned> _location, BlockNumber _blockNumber, Transaction const& _t)
{
Json::Value res;
h256 h = _t.sha3();
res["transactionHash"] = toJS(h);
res["transactionIndex"] = _location.second;
res["blockHash"] = toJS(_location.first);
res["blockNumber"] = _blockNumber;
res["cumulativeGasUsed"] = toJS(_tr.gasUsed()); // TODO: check if this is fine
res["gasUsed"] = toJS(_tr.gasUsed());
res["contractAddress"] = toJS(toAddress(_t.from(), _t.nonce()));
res["logs"] = Json::Value(Json::arrayValue);
for (unsigned i = 0; i < _tr.log().size(); i++)
{
LogEntry e = _tr.log()[i];
Json::Value l = toJson(e);
l["type"] = "mined";
l["blockNumber"] = _blockNumber;
l["blockHash"] = toJS(_location.first);
l["logIndex"] = i;
l["transactionHash"] = toJS(h);
l["transactionIndex"] = _location.second;
res["logs"].append(l);
}
return res;
}
Json::Value toJson(dev::eth::Transaction const& _t) Json::Value toJson(dev::eth::Transaction const& _t)
{ {
Json::Value res; Json::Value res;
@ -269,6 +296,9 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json)
if (!_json["code"].empty()) if (!_json["code"].empty())
ret.data = jsToBytes(_json["code"].asString()); ret.data = jsToBytes(_json["code"].asString());
if (!_json["nonce"].empty())
ret.nonce = jsToU256(_json["nonce"].asString());
return ret; return ret;
} }

3
libweb3jsonrpc/JsonHelper.h

@ -50,12 +50,15 @@ using UncleHashes = h256s;
using TransactionHashes = h256s; using TransactionHashes = h256s;
Json::Value toJson(BlockInfo const& _bi); Json::Value toJson(BlockInfo const& _bi);
//TODO: wrap these params into one structure eg. "LocalisedTransaction"
Json::Value toJson(Transaction const& _t, std::pair<h256, unsigned> _location, BlockNumber _blockNumber); Json::Value toJson(Transaction const& _t, std::pair<h256, unsigned> _location, BlockNumber _blockNumber);
Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, Transactions const& _ts); Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, Transactions const& _ts);
Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, TransactionHashes const& _ts); Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, TransactionHashes const& _ts);
Json::Value toJson(TransactionSkeleton const& _t); Json::Value toJson(TransactionSkeleton const& _t);
Json::Value toJson(Transaction const& _t); Json::Value toJson(Transaction const& _t);
Json::Value toJson(TransactionReceipt const& _t); Json::Value toJson(TransactionReceipt const& _t);
//TODO: wrap these params into one structure eg. "LocalisedTransactionReceipt"
Json::Value toJson(TransactionReceipt const& _tr, std::pair<h256, unsigned> _location, BlockNumber _blockNumber, Transaction const& _t);
Json::Value toJson(LocalisedLogEntry const& _e); Json::Value toJson(LocalisedLogEntry const& _e);
Json::Value toJson(LogEntry const& _e); Json::Value toJson(LogEntry const& _e);
TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); TransactionSkeleton toTransactionSkeleton(Json::Value const& _json);

27
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -242,21 +242,16 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
{ {
try try
{ {
string ret;
TransactionSkeleton t = toTransactionSkeleton(_json); TransactionSkeleton t = toTransactionSkeleton(_json);
if (!t.from) if (!t.from)
t.from = m_ethAccounts->defaultTransactAccount(); t.from = m_ethAccounts->defaultTransactAccount();
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (t.gasPrice == UndefinedU256) if (t.gasPrice == UndefinedU256)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow. t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (t.gas == UndefinedU256) if (t.gas == UndefinedU256)
t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice); t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
m_ethAccounts->authenticate(t); return toJS(m_ethAccounts->authenticate(t));
return ret;
} }
catch (...) catch (...)
{ {
@ -268,13 +263,10 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json)
{ {
try try
{ {
string ret;
TransactionSkeleton t = toTransactionSkeleton(_json); TransactionSkeleton t = toTransactionSkeleton(_json);
if (!t.from) if (!t.from)
t.from = m_ethAccounts->defaultTransactAccount(); t.from = m_ethAccounts->defaultTransactAccount();
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (t.gasPrice == UndefinedU256) if (t.gasPrice == UndefinedU256)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow. t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (t.gas == UndefinedU256) if (t.gas == UndefinedU256)
@ -427,6 +419,23 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockNumberAndIndex(stri
} }
} }
Json::Value WebThreeStubServerBase::eth_getTransactionReceipt(string const& _transactionHash)
{
try
{
h256 h = jsToFixed<32>(_transactionHash);
if (!client()->isKnownTransaction(h))
return Json::Value(Json::nullValue);
auto l = client()->transactionLocation(h);
return toJson(client()->transactionReceipt(h), l, client()->numberFromHash(l.first), client()->transaction(h));
}
catch (...)
{
BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS));
}
}
Json::Value WebThreeStubServerBase::eth_getUncleByBlockHashAndIndex(string const& _blockHash, string const& _uncleIndex) Json::Value WebThreeStubServerBase::eth_getUncleByBlockHashAndIndex(string const& _blockHash, string const& _uncleIndex)
{ {
try try

1
libweb3jsonrpc/WebThreeStubServerBase.h

@ -119,6 +119,7 @@ public:
virtual Json::Value eth_getTransactionByHash(std::string const& _transactionHash); virtual Json::Value eth_getTransactionByHash(std::string const& _transactionHash);
virtual Json::Value eth_getTransactionByBlockHashAndIndex(std::string const& _blockHash, std::string const& _transactionIndex); virtual Json::Value eth_getTransactionByBlockHashAndIndex(std::string const& _blockHash, std::string const& _transactionIndex);
virtual Json::Value eth_getTransactionByBlockNumberAndIndex(std::string const& _blockNumber, std::string const& _transactionIndex); virtual Json::Value eth_getTransactionByBlockNumberAndIndex(std::string const& _blockNumber, std::string const& _transactionIndex);
virtual Json::Value eth_getTransactionReceipt(std::string const& _transactionHash);
virtual Json::Value eth_getUncleByBlockHashAndIndex(std::string const& _blockHash, std::string const& _uncleIndex); virtual Json::Value eth_getUncleByBlockHashAndIndex(std::string const& _blockHash, std::string const& _uncleIndex);
virtual Json::Value eth_getUncleByBlockNumberAndIndex(std::string const& _blockNumber, std::string const& _uncleIndex); virtual Json::Value eth_getUncleByBlockNumberAndIndex(std::string const& _blockNumber, std::string const& _uncleIndex);
virtual Json::Value eth_getCompilers(); virtual Json::Value eth_getCompilers();

6
libweb3jsonrpc/abstractwebthreestubserver.h

@ -40,6 +40,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionByHashI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionByBlockHashAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionByBlockHashAndIndexI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionByBlockHashAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionByBlockHashAndIndexI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionByBlockNumberAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionByBlockNumberAndIndexI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionByBlockNumberAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionByBlockNumberAndIndexI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionReceipt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionReceiptI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleByBlockHashAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleByBlockHashAndIndexI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleByBlockHashAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleByBlockHashAndIndexI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleByBlockNumberAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleByBlockNumberAndIndexI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleByBlockNumberAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleByBlockNumberAndIndexI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getCompilers", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getCompilersI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getCompilers", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getCompilersI);
@ -224,6 +225,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{ {
response = this->eth_getTransactionByBlockNumberAndIndex(request[0u].asString(), request[1u].asString()); response = this->eth_getTransactionByBlockNumberAndIndex(request[0u].asString(), request[1u].asString());
} }
inline virtual void eth_getTransactionReceiptI(const Json::Value &request, Json::Value &response)
{
response = this->eth_getTransactionReceipt(request[0u].asString());
}
inline virtual void eth_getUncleByBlockHashAndIndexI(const Json::Value &request, Json::Value &response) inline virtual void eth_getUncleByBlockHashAndIndexI(const Json::Value &request, Json::Value &response)
{ {
response = this->eth_getUncleByBlockHashAndIndex(request[0u].asString(), request[1u].asString()); response = this->eth_getUncleByBlockHashAndIndex(request[0u].asString(), request[1u].asString());
@ -489,6 +494,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual Json::Value eth_getTransactionByHash(const std::string& param1) = 0; virtual Json::Value eth_getTransactionByHash(const std::string& param1) = 0;
virtual Json::Value eth_getTransactionByBlockHashAndIndex(const std::string& param1, const std::string& param2) = 0; virtual Json::Value eth_getTransactionByBlockHashAndIndex(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value eth_getTransactionByBlockNumberAndIndex(const std::string& param1, const std::string& param2) = 0; virtual Json::Value eth_getTransactionByBlockNumberAndIndex(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value eth_getTransactionReceipt(const std::string& param1) = 0;
virtual Json::Value eth_getUncleByBlockHashAndIndex(const std::string& param1, const std::string& param2) = 0; virtual Json::Value eth_getUncleByBlockHashAndIndex(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value eth_getUncleByBlockNumberAndIndex(const std::string& param1, const std::string& param2) = 0; virtual Json::Value eth_getUncleByBlockNumberAndIndex(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value eth_getCompilers() = 0; virtual Json::Value eth_getCompilers() = 0;

1
libweb3jsonrpc/spec.json

@ -29,6 +29,7 @@
{ "name": "eth_getTransactionByHash", "params": [""], "order": [], "returns": {}}, { "name": "eth_getTransactionByHash", "params": [""], "order": [], "returns": {}},
{ "name": "eth_getTransactionByBlockHashAndIndex", "params": ["", ""], "order": [], "returns": {}}, { "name": "eth_getTransactionByBlockHashAndIndex", "params": ["", ""], "order": [], "returns": {}},
{ "name": "eth_getTransactionByBlockNumberAndIndex", "params": ["", ""], "order": [], "returns": {}}, { "name": "eth_getTransactionByBlockNumberAndIndex", "params": ["", ""], "order": [], "returns": {}},
{ "name": "eth_getTransactionReceipt", "params": [""], "order": [], "returns": {}},
{ "name": "eth_getUncleByBlockHashAndIndex", "params": ["", ""], "order": [], "returns": {}}, { "name": "eth_getUncleByBlockHashAndIndex", "params": ["", ""], "order": [], "returns": {}},
{ "name": "eth_getUncleByBlockNumberAndIndex", "params": ["", ""], "order": [], "returns": {}}, { "name": "eth_getUncleByBlockNumberAndIndex", "params": ["", ""], "order": [], "returns": {}},
{ "name": "eth_getCompilers", "params": [], "order": [], "returns": []}, { "name": "eth_getCompilers", "params": [], "order": [], "returns": []},

5
mix/CMakeLists.txt

@ -15,6 +15,11 @@ include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
# Supress warnings for qt headers for clang+ccache
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override")
endif ()
find_package (Qt5WebEngine QUIET) find_package (Qt5WebEngine QUIET)
qt5_add_resources(UI_RESOURCES res.qrc qml.qrc) qt5_add_resources(UI_RESOURCES res.qrc qml.qrc)

3
mix/ClientModel.cpp

@ -673,8 +673,7 @@ void ClientModel::debugRecord(unsigned _index)
Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction) Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction)
{ {
Address newAddress = m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice, _ctrTransaction.gasAuto); return m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice, _ctrTransaction.gasAuto);
return newAddress;
} }
void ClientModel::callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) void ClientModel::callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)

2
mix/ClientModel.h

@ -252,7 +252,7 @@ private:
QVariantMap contractAddresses() const; QVariantMap contractAddresses() const;
QVariantList gasCosts() const; QVariantList gasCosts() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence); void executeSequence(std::vector<TransactionSettings> const& _sequence);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
void onNewTransaction(); void onNewTransaction();
void onStateReset(); void onStateReset();

8
mix/DebuggingStateWrapper.h

@ -69,7 +69,7 @@ class QSolState: public QObject
public: public:
QSolState(QObject* _parent, QVariantMap&& _storage, QVariantList&& _callStack, QVariantMap&& _locals, int _start, int _end, QString _sourceName): QSolState(QObject* _parent, QVariantMap&& _storage, QVariantList&& _callStack, QVariantMap&& _locals, int _start, int _end, QString _sourceName):
QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end), m_sourceName(_sourceName) QObject(_parent), m_storage(std::move(_storage)), m_callStack(std::move(_callStack)), m_locals(std::move(_locals)), m_start(_start), m_end(_end), m_sourceName(_sourceName)
{ } { }
private: private:
@ -92,7 +92,7 @@ class QCode: public QObject
Q_PROPERTY(QString documentId MEMBER m_document CONSTANT) Q_PROPERTY(QString documentId MEMBER m_document CONSTANT)
public: public:
QCode(QObject* _owner, QString const& _address, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions), m_address(_address) {} QCode(QObject* _owner, QString const& _address, QVariantList&& _instrunctions): QObject(_owner), m_instructions(std::move(_instrunctions)), m_address(_address) {}
void setDocument(QString const& _documentId) { m_document = _documentId; } void setDocument(QString const& _documentId) { m_document = _documentId; }
private: private:
@ -110,7 +110,7 @@ class QCallData: public QObject
Q_PROPERTY(QVariantList items MEMBER m_items CONSTANT) Q_PROPERTY(QVariantList items MEMBER m_items CONSTANT)
public: public:
QCallData(QObject* _owner, QVariantList&& _items): QObject(_owner), m_items(_items) {} QCallData(QObject* _owner, QVariantList&& _items): QObject(_owner), m_items(std::move(_items)) {}
private: private:
QVariantList m_items; QVariantList m_items;
@ -126,7 +126,7 @@ class QDebugData: public QObject
public: public:
QDebugData() { } QDebugData() { }
void setStates(QVariantList&& _states) { m_states = _states; } void setStates(QVariantList&& _states) { m_states = std::move(_states); }
private: private:
QVariantList m_states; QVariantList m_states;

2
mix/HttpServer.h

@ -46,7 +46,7 @@ class HttpRequest: public QObject
private: private:
HttpRequest(QObject* _parent, QUrl&& _url, QString&& _content, QVariantMap&& _headers): HttpRequest(QObject* _parent, QUrl&& _url, QString&& _content, QVariantMap&& _headers):
QObject(_parent), m_url(_url), m_content(_content), m_headers(_headers) QObject(_parent), m_url(std::move(_url)), m_content(std::move(_content)), m_headers(std::move(_headers))
{ {
} }

28
mix/MixClient.cpp

@ -303,22 +303,14 @@ State MixClient::asOf(h256 const& _block) const
return ret; return ret;
} }
void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto) pair<h256, Address> MixClient::submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto)
{ {
WriteGuard l(x_state); WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret)); TransactionSkeleton ts = _ts;
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); ts.nonce = m_state.transactionsFrom(toAddress(_secret));
eth::Transaction t(ts, _secret);
executeTransaction(t, m_state, false, _gasAuto, _secret); executeTransaction(t, m_state, false, _gasAuto, _secret);
} return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));
Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto)
{
WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret));
eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
executeTransaction(t, m_state, false, _gasAuto, _secret);
Address address = right160(sha3(rlpList(t.sender(), t.nonce())));
return address;
} }
dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff) dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff)
@ -335,16 +327,6 @@ dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Add
return lastExecution().result; return lastExecution().result;
} }
void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
submitTransaction(_secret, _value, _dest, _data, _gas, _gasPrice, false);
}
Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
return submitTransaction(_secret, _endowment, _init, _gas, _gasPrice, false);
}
dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
{ {
return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff); return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff);

9
mix/MixClient.h

@ -54,14 +54,12 @@ public:
ExecutionResult lastExecution() const; ExecutionResult lastExecution() const;
ExecutionResult execution(unsigned _index) const; ExecutionResult execution(unsigned _index) const;
void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override;
Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override;
dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override;
dev::eth::ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; dev::eth::ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override;
using ClientBase::submitTransaction; using ClientBase::submitTransaction;
void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto); virtual std::pair<h256, Address> submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret) override { return submitTransaction(_ts, _secret, false); }
Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto); std::pair<h256, Address> submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto);
dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict);
void setAddress(Address _us) override; void setAddress(Address _us) override;
@ -78,6 +76,9 @@ public:
using Interface::blockInfo; // to remove warning about hiding virtual function using Interface::blockInfo; // to remove warning about hiding virtual function
eth::BlockInfo blockInfo() const; eth::BlockInfo blockInfo() const;
/// return the new address generated by the last tr (if creation). returns empty address if other cases.
Address lastCreatedContractAddr() const;
protected: protected:
/// ClientBase methods /// ClientBase methods
using ClientBase::asOf; using ClientBase::asOf;

8
neth/main.cpp

@ -363,11 +363,7 @@ int main(int argc, char** argv)
coinbase = config[1].toHash<Address>(); coinbase = config[1].toHash<Address>();
} }
else else
{ writeFile(configFile, rlpList(us.secret(), coinbase));
RLPStream config(2);
config << us.secret() << coinbase;
writeFile(configFile, config.out());
}
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
{ {
@ -1061,11 +1057,9 @@ int main(int argc, char** argv)
else if (gas < minGas) else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas; cwarn << "Minimum gas amount is" << minGas;
else else
{
c->submitTransaction(us.secret(), endowment, init, gas); c->submitTransaction(us.secret(), endowment, init, gas);
} }
} }
}
else if (c && cmd == "inspect") else if (c && cmd == "inspect")
{ {
string rechex; string rechex;

4
test/TestHelper.cpp

@ -199,10 +199,10 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
stateOptions.m_bHasCode = true; stateOptions.m_bHasCode = true;
} }
if (code.size()) if (!code.empty())
{ {
_state.m_cache[address] = Account(balance, Account::ContractConception); _state.m_cache[address] = Account(balance, Account::ContractConception);
_state.m_cache[address].setCode(code); _state.m_cache[address].setCode(std::move(code));
} }
else else
_state.m_cache[address] = Account(balance, Account::NormalCreation); _state.m_cache[address] = Account(balance, Account::NormalCreation);

146
test/libdevcore/FixedHash.cpp

@ -0,0 +1,146 @@
/*
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 FixedHash.cpp
* @author Lefterus <lefteris@ethdev.com>
* @date 2015
*/
#include <libdevcore/FixedHash.h>
#include "../TestHelper.h"
using namespace std;
using namespace dev;
namespace dev
{
namespace test
{
BOOST_AUTO_TEST_SUITE(FixedHashTests)
BOOST_AUTO_TEST_CASE(FixedHashComparisons)
{
FixedHash<4> h1(sha3("abcd"));
FixedHash<4> h2(sha3("abcd"));
FixedHash<4> h3(sha3("aadd"));
FixedHash<4> h4(0xBAADF00D);
FixedHash<4> h5(0xAAAAAAAA);
FixedHash<4> h6(0xBAADF00D);
BOOST_CHECK(h1 == h2);
BOOST_CHECK(h2 != h3);
BOOST_CHECK(h4 > h5);
BOOST_CHECK(h5 < h4);
BOOST_CHECK(h6 <= h4);
BOOST_CHECK(h6 >= h4);
}
BOOST_AUTO_TEST_CASE(FixedHashXOR)
{
FixedHash<2> h1("0xAAAA");
FixedHash<2> h2("0xBBBB");
BOOST_CHECK((h1 ^ h2) == FixedHash<2>("0x1111"));
h1 ^= h2;
BOOST_CHECK(h1 == FixedHash<2>("0x1111"));
}
BOOST_AUTO_TEST_CASE(FixedHashOR)
{
FixedHash<4> h1("0xD3ADB33F");
FixedHash<4> h2("0xBAADF00D");
FixedHash<4> res("0xFBADF33F");
BOOST_CHECK((h1 | h2) == res);
h1 |= h2;
BOOST_CHECK(h1 == res);
}
BOOST_AUTO_TEST_CASE(FixedHashAND)
{
FixedHash<4> h1("0xD3ADB33F");
FixedHash<4> h2("0xBAADF00D");
FixedHash<4> h3("0x92aDB00D");
BOOST_CHECK((h1 & h2) == h3);
h1 &= h2;
BOOST_CHECK(h1 = h3);
}
BOOST_AUTO_TEST_CASE(FixedHashInvert)
{
FixedHash<4> h1("0xD3ADB33F");
FixedHash<4> h2("0x2C524CC0");
BOOST_CHECK(~h1 == h2);
}
BOOST_AUTO_TEST_CASE(FixedHashContains)
{
FixedHash<4> h1("0xD3ADB331");
FixedHash<4> h2("0x0000B331");
FixedHash<4> h3("0x0000000C");
BOOST_CHECK(h1.contains(h2));
BOOST_CHECK(!h1.contains(h3));
}
void incrementSingleIteration(unsigned seed)
{
unsigned next = seed + 1;
FixedHash<4> h1(seed);
FixedHash<4> h2 = h1;
FixedHash<4> h3(next);
FixedHash<32> hh1(seed);
FixedHash<32> hh2 = hh1;
FixedHash<32> hh3(next);
BOOST_CHECK_EQUAL(++h2, h3);
BOOST_CHECK_EQUAL(++hh2, hh3);
BOOST_CHECK(h2 > h1);
BOOST_CHECK(hh2 > hh1);
unsigned reverse1 = ((FixedHash<4>::Arith)h2).convert_to<unsigned>();
unsigned reverse2 = ((FixedHash<32>::Arith)hh2).convert_to<unsigned>();
BOOST_CHECK_EQUAL(next, reverse1);
BOOST_CHECK_EQUAL(next, reverse2);
}
BOOST_AUTO_TEST_CASE(FixedHashIncrement)
{
incrementSingleIteration(0);
incrementSingleIteration(1);
incrementSingleIteration(0xBAD);
incrementSingleIteration(0xBEEF);
incrementSingleIteration(0xFFFF);
incrementSingleIteration(0xFEDCBA);
incrementSingleIteration(0x7FFFFFFF);
FixedHash<4> h(0xFFFFFFFF);
FixedHash<4> zero;
BOOST_CHECK_EQUAL(++h, zero);
}
BOOST_AUTO_TEST_SUITE_END()
}
}

41
test/libdevcore/core.cpp

@ -0,0 +1,41 @@
/*
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 core.cpp
* @author Dimitry Khokhlov <winsvega@mail.ru>
* @date 2014
* CORE test functions.
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/CommonIO.h>
#include <test/TestHelper.h>
BOOST_AUTO_TEST_SUITE(CoreLibTests)
BOOST_AUTO_TEST_CASE(byteRef)
{
cnote << "bytesRef copyTo and toString...";
dev::bytes originalSequence = dev::fromHex("0102030405060708091011121314151617181920212223242526272829303132");
dev::bytesRef out(&originalSequence.at(0), 32);
dev::h256 hash32("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347");
hash32.ref().copyTo(out);
BOOST_CHECK_MESSAGE(out.size() == 32, "Error wrong result size when h256::ref().copyTo(dev::bytesRef out)");
BOOST_CHECK_MESSAGE(out.toBytes() == originalSequence, "Error when h256::ref().copyTo(dev::bytesRef out)");
}
BOOST_AUTO_TEST_SUITE_END()

2
test/libdevcrypto/AES.cpp

@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(AuthenticatedStreamConstructor)
{ {
cout << "AuthenticatedStreamConstructor" << endl; cout << "AuthenticatedStreamConstructor" << endl;
Secret const sec("test"); Secret const sec(dev::sha3("test"));
crypto::aes::AuthenticatedStream as(crypto::aes::Encrypt, sec, 0); crypto::aes::AuthenticatedStream as(crypto::aes::Encrypt, sec, 0);
BOOST_CHECK(as.getMacInterval() == 0); BOOST_CHECK(as.getMacInterval() == 0);
as.adjustInterval(1); as.adjustInterval(1);

277
test/libethereum/BlockchainTestsFiller/bcBlockGasLimitTestFiller.json

@ -0,0 +1,277 @@
{
"SuicideTransaction" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "131072",
"extraData" : "0x42",
"gasLimit" : "125000",
"gasUsed" : "0",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "90000000000000000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"storage": {}
}
},
"blocks" : [
{
"transactions" : [
{
"data" : "",
"gasLimit" : "100000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
}
],
"uncleHeaders" : [
]
}
]
},
"GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideLast" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "131072",
"extraData" : "0x42",
"gasLimit" : "147000",
"gasUsed" : "0",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "90000000000000000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"storage": {}
}
},
"blocks" : [
{
"transactions" : [
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "1",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "2",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "3",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "4",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "5",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "22000",
"gasPrice" : "10",
"nonce" : "6",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
}
],
"uncleHeaders" : [
]
}
]
},
"GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideFirst" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "131072",
"extraData" : "0x42",
"gasLimit" : "147000",
"gasUsed" : "0",
"mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"nonce" : "0x0102030405060708",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"expect" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000"
}
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "90000000000000000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"aaaf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"storage": {}
}
},
"blocks" : [
{
"transactions" : [
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "6",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "1",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "2",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "3",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "4",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "21000",
"gasPrice" : "10",
"nonce" : "5",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
},
{
"data" : "",
"gasLimit" : "22000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "aaaf5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
}
],
"uncleHeaders" : [
]
}
]
}
}

854
test/libethereum/StateTestsFiller/stPreCompiledContractsTransactionFiller.json

File diff suppressed because one or more lines are too long

6
test/libethereum/blockchain.cpp

@ -24,6 +24,7 @@
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libdevcore/TransientDirectory.h> #include <libdevcore/TransientDirectory.h>
#include <libethereum/CanonBlockChain.h> #include <libethereum/CanonBlockChain.h>
#include <libethereum/TransactionQueue.h>
#include <test/TestHelper.h> #include <test/TestHelper.h>
using namespace std; using namespace std;
@ -836,6 +837,11 @@ BOOST_AUTO_TEST_CASE(bcBruncleTest)
dev::test::executeTests("bcBruncleTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); dev::test::executeTests("bcBruncleTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests);
} }
BOOST_AUTO_TEST_CASE(bcBlockGasLimitTest)
{
dev::test::executeTests("bcBlockGasLimitTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests);
}
BOOST_AUTO_TEST_CASE(bcWalletTest) BOOST_AUTO_TEST_CASE(bcWalletTest)
{ {
if (test::Options::get().wallet) if (test::Options::get().wallet)

5
test/libethereum/state.cpp

@ -129,11 +129,6 @@ BOOST_AUTO_TEST_CASE(stPreCompiledContracts)
dev::test::executeTests("stPreCompiledContracts", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); dev::test::executeTests("stPreCompiledContracts", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stPreCompiledContractsTransaction)
{
dev::test::executeTests("stPreCompiledContractsTransaction", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);
}
BOOST_AUTO_TEST_CASE(stLogTests) BOOST_AUTO_TEST_CASE(stLogTests)
{ {
dev::test::executeTests("stLogTests", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); dev::test::executeTests("stLogTests", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);

248
test/libsolidity/SolidityWallet.cpp

@ -47,12 +47,18 @@ static char const* walletCode = R"DELIMITER(
// some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the // some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the
// interior is executed. // interior is executed.
contract multiowned { contract multiowned {
// TYPES
// struct for the status of a pending operation. // struct for the status of a pending operation.
struct PendingState { struct PendingState {
uint yetNeeded; uint yetNeeded;
uint ownersDone; uint ownersDone;
uint index; uint index;
} }
// EVENTS
// this contract only has five types of events: it can accept a confirmation, in which case // this contract only has five types of events: it can accept a confirmation, in which case
// we record owner and operation (hash) alongside it. // we record owner and operation (hash) alongside it.
event Confirmation(address owner, bytes32 operation); event Confirmation(address owner, bytes32 operation);
@ -63,14 +69,9 @@ contract multiowned {
event OwnerRemoved(address oldOwner); event OwnerRemoved(address oldOwner);
// the last one is emitted if the required signatures change // the last one is emitted if the required signatures change
event RequirementChanged(uint newRequirement); event RequirementChanged(uint newRequirement);
// constructor is given number of sigs required to do protected "onlymanyowners" transactions
// as well as the selection of addresses capable of confirming them. // MODIFIERS
function multiowned() {
m_required = 1;
m_numOwners = 1;
m_owners[m_numOwners] = uint(msg.sender);
m_ownerIndex[uint(msg.sender)] = m_numOwners;
}
// simple single-sig function modifier. // simple single-sig function modifier.
modifier onlyowner { modifier onlyowner {
if (isOwner(msg.sender)) if (isOwner(msg.sender))
@ -80,9 +81,21 @@ contract multiowned {
// that later attempts can be realised as the same underlying operation and // that later attempts can be realised as the same underlying operation and
// thus count as confirmations. // thus count as confirmations.
modifier onlymanyowners(bytes32 _operation) { modifier onlymanyowners(bytes32 _operation) {
if (confirmed(_operation)) if (confirmAndCheck(_operation))
_ _
} }
// METHODS
// constructor is given number of sigs required to do protected "onlymanyowners" transactions
// as well as the selection of addresses capable of confirming them.
function multiowned() {
m_required = 1;
m_numOwners = 1;
m_owners[m_numOwners] = uint(msg.sender);
m_ownerIndex[uint(msg.sender)] = m_numOwners;
}
// Revokes a prior confirmation of the given operation // Revokes a prior confirmation of the given operation
function revoke(bytes32 _operation) external { function revoke(bytes32 _operation) external {
uint ownerIndex = m_ownerIndex[uint(msg.sender)]; uint ownerIndex = m_ownerIndex[uint(msg.sender)];
@ -96,7 +109,75 @@ contract multiowned {
Revoke(msg.sender, _operation); Revoke(msg.sender, _operation);
} }
} }
function confirmed(bytes32 _operation) internal returns (bool) {
// Replaces an owner `_from` with another `_to`.
function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data, block.number)) external {
if (isOwner(_to)) return;
uint ownerIndex = m_ownerIndex[uint(_from)];
if (ownerIndex == 0) return;
clearPending();
m_owners[ownerIndex] = uint(_to);
m_ownerIndex[uint(_from)] = 0;
m_ownerIndex[uint(_to)] = ownerIndex;
OwnerChanged(_from, _to);
}
function addOwner(address _owner) onlymanyowners(sha3(msg.data, block.number)) external {
if (isOwner(_owner)) return;
clearPending();
if (m_numOwners >= c_maxOwners)
reorganizeOwners();
if (m_numOwners >= c_maxOwners)
return;
m_numOwners++;
m_owners[m_numOwners] = uint(_owner);
m_ownerIndex[uint(_owner)] = m_numOwners;
OwnerAdded(_owner);
}
function removeOwner(address _owner) onlymanyowners(sha3(msg.data, block.number)) external {
uint ownerIndex = m_ownerIndex[uint(_owner)];
if (ownerIndex == 0) return;
if (m_required > m_numOwners - 1) return;
m_owners[ownerIndex] = 0;
m_ownerIndex[uint(_owner)] = 0;
clearPending();
reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot
OwnerRemoved(_owner);
}
function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data, block.number)) external {
if (_newRequired > m_numOwners) return;
m_required = _newRequired;
clearPending();
RequirementChanged(_newRequired);
}
function isOwner(address _addr) returns (bool) {
return m_ownerIndex[uint(_addr)] > 0;
}
function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) {
var pending = m_pending[_operation];
uint ownerIndex = m_ownerIndex[uint(_owner)];
// make sure they're an owner
if (ownerIndex == 0) return false;
// determine the bit to set for this owner.
uint ownerIndexBit = 2**ownerIndex;
if (pending.ownersDone & ownerIndexBit == 0) {
return false;
} else {
return true;
}
}
// INTERNAL METHODS
function confirmAndCheck(bytes32 _operation) internal returns (bool) {
// determine what index the present sender is: // determine what index the present sender is:
uint ownerIndex = m_ownerIndex[uint(msg.sender)]; uint ownerIndex = m_ownerIndex[uint(msg.sender)];
// make sure they're an owner // make sure they're an owner
@ -132,42 +213,7 @@ contract multiowned {
} }
} }
} }
// Replaces an owner `_from` with another `_to`.
function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external {
if (isOwner(_to)) return;
uint ownerIndex = m_ownerIndex[uint(_from)];
if (ownerIndex == 0) return;
clearPending();
m_owners[ownerIndex] = uint(_to);
m_ownerIndex[uint(_from)] = 0;
m_ownerIndex[uint(_to)] = ownerIndex;
OwnerChanged(_from, _to);
}
function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
if (isOwner(_owner)) return;
clearPending();
if (m_numOwners >= c_maxOwners)
reorganizeOwners();
if (m_numOwners >= c_maxOwners)
return;
m_numOwners++;
m_owners[m_numOwners] = uint(_owner);
m_ownerIndex[uint(_owner)] = m_numOwners;
OwnerAdded(_owner);
}
function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
uint ownerIndex = m_ownerIndex[uint(_owner)];
if (ownerIndex == 0) return;
if (m_required > m_numOwners - 1) return;
m_owners[ownerIndex] = 0;
m_ownerIndex[uint(_owner)] = 0;
clearPending();
reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot
OwnerRemoved(_owner);
}
function reorganizeOwners() private returns (bool) { function reorganizeOwners() private returns (bool) {
uint free = 1; uint free = 1;
while (free < m_numOwners) while (free < m_numOwners)
@ -182,6 +228,7 @@ contract multiowned {
} }
} }
} }
function clearPending() internal { function clearPending() internal {
uint length = m_pendingIndex.length; uint length = m_pendingIndex.length;
for (uint i = 0; i < length; ++i) for (uint i = 0; i < length; ++i)
@ -189,46 +236,54 @@ contract multiowned {
delete m_pending[m_pendingIndex[i]]; delete m_pending[m_pendingIndex[i]];
delete m_pendingIndex; delete m_pendingIndex;
} }
function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external {
if (_newRequired > m_numOwners) return; // FIELDS
m_required = _newRequired;
clearPending();
RequirementChanged(_newRequired);
}
function isOwner(address _addr) returns (bool) {
return m_ownerIndex[uint(_addr)] > 0;
}
// the number of owners that must confirm the same operation before it is run. // the number of owners that must confirm the same operation before it is run.
uint public m_required; uint public m_required;
// pointer used to find a free slot in m_owners // pointer used to find a free slot in m_owners
uint public m_numOwners; uint public m_numOwners;
// list of owners // list of owners
uint[256] public m_owners; uint[256] m_owners;
uint constant c_maxOwners = 250; uint constant c_maxOwners = 250;
// index on the list of owners to allow reverse lookup // index on the list of owners to allow reverse lookup
mapping(uint => uint) public m_ownerIndex; mapping(uint => uint) m_ownerIndex;
// the ongoing operations. // the ongoing operations.
mapping(bytes32 => PendingState) public m_pending; mapping(bytes32 => PendingState) m_pending;
bytes32[] public m_pendingIndex; bytes32[] m_pendingIndex;
} }
// inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable) // inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable)
// on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method // on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method
// uses is specified in the modifier. // uses is specified in the modifier.
contract daylimit is multiowned { contract daylimit is multiowned {
// MODIFIERS
// simple modifier for daily limit.
modifier limitedDaily(uint _value) {
if (underLimit(_value))
_
}
// METHODS
// constructor - just records the present day's index. // constructor - just records the present day's index.
function daylimit() { function daylimit() {
m_lastDay = today(); m_lastDay = today();
} }
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external { function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data, block.number)) external {
m_dailyLimit = _newLimit; m_dailyLimit = _newLimit;
} }
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
function resetSpentToday() onlymanyowners(sha3(msg.data)) external { function resetSpentToday() onlymanyowners(sha3(msg.data, block.number)) external {
m_spentToday = 0; m_spentToday = 0;
} }
// INTERNAL METHODS
// checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and
// returns true. otherwise just returns false. // returns true. otherwise just returns false.
function underLimit(uint _value) internal onlyowner returns (bool) { function underLimit(uint _value) internal onlyowner returns (bool) {
@ -244,60 +299,76 @@ contract daylimit is multiowned {
} }
return false; return false;
} }
// simple modifier for daily limit.
modifier limitedDaily(uint _value) {
if (underLimit(_value))
_
}
// determines today's index. // determines today's index.
function today() private constant returns (uint) { return now / 1 days; } function today() private constant returns (uint) { return now / 1 days; }
uint public m_spentToday;
// FIELDS
uint public m_dailyLimit; uint public m_dailyLimit;
uint public m_lastDay; uint m_spentToday;
uint m_lastDay;
} }
// interface contract for multisig proxy contracts; see below for docs. // interface contract for multisig proxy contracts; see below for docs.
contract multisig { contract multisig {
// EVENTS
// logged events:
// Funds has arrived into the wallet (record how much).
event Deposit(address from, uint value); event Deposit(address from, uint value);
// Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going).
event SingleTransact(address owner, uint value, address to, bytes data); event SingleTransact(address owner, uint value, address to, bytes data);
// Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going).
event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data); event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data);
// Confirmation still needed for a transaction.
event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data);
// FUNCTIONS
// TODO: document
function changeOwner(address _from, address _to) external; function changeOwner(address _from, address _to) external;
function execute(address _to, uint _value, bytes _data) external returns (bytes32); function execute(address _to, uint _value, bytes _data) external returns (bytes32);
function confirm(bytes32 _h) returns (bool); function confirm(bytes32 _h) returns (bool);
} }
// usage: // usage:
// bytes32 h = Wallet(w).from(oneOwner).transact(to, value, data); // bytes32 h = Wallet(w).from(oneOwner).transact(to, value, data);
// Wallet(w).from(anotherOwner).confirm(h); // Wallet(w).from(anotherOwner).confirm(h);
contract Wallet is multisig, multiowned, daylimit { contract Wallet is multisig, multiowned, daylimit {
// TYPES
// Transaction structure to remember details of transaction lest it need be saved for a later call. // Transaction structure to remember details of transaction lest it need be saved for a later call.
struct Transaction { struct Transaction {
address to; address to;
uint value; uint value;
bytes data; bytes data;
} }
/*
// logged events: // EVENTS
// Funds has arrived into the wallet (record how much).
event Deposit(address from, uint value); event Created(bytes32 indexed identifier);
// Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going).
event SingleTransact(address owner, uint value, address to, bytes data); // METHODS
// Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going).
event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data);*/
// constructor - just pass on the owner arra to the multiowned. // constructor - just pass on the owner arra to the multiowned.
event Created(); function Wallet(bytes32 identifier) {
function Wallet() { Created(identifier);
Created();
} }
// kills the contract sending everything to `_to`. // kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data)) external { function kill(address _to) onlymanyowners(sha3(msg.data, block.number)) external {
suicide(_to); suicide(_to);
} }
// gets called when no other function matches // gets called when no other function matches
function() { function() {
// just being sent some cash? // just being sent some cash?
if (msg.value > 0) if (msg.value > 0)
Deposit(msg.sender, msg.value); Deposit(msg.sender, msg.value);
} }
// Outside-visible transact entry point. Executes transacion immediately if below daily spend limit. // Outside-visible transact entry point. Executes transacion immediately if below daily spend limit.
// If not, goes into multisig process. We provide a hash on return to allow the sender to provide // If not, goes into multisig process. We provide a hash on return to allow the sender to provide
// shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value
@ -311,7 +382,7 @@ contract Wallet is multisig, multiowned, daylimit {
return 0; return 0;
} }
// determine our operation hash. // determine our operation hash.
_r = sha3(msg.data); _r = sha3(msg.data, block.number);
if (!confirm(_r) && m_txs[_r].to == 0) { if (!confirm(_r) && m_txs[_r].to == 0) {
m_txs[_r].to = _to; m_txs[_r].to = _to;
m_txs[_r].value = _value; m_txs[_r].value = _value;
@ -319,6 +390,7 @@ contract Wallet is multisig, multiowned, daylimit {
ConfirmationNeeded(_r, msg.sender, _value, _to, _data); ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
} }
} }
// confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order // confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order
// to determine the body of the transaction from the hash provided. // to determine the body of the transaction from the hash provided.
function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) { function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
@ -329,20 +401,20 @@ contract Wallet is multisig, multiowned, daylimit {
return true; return true;
} }
} }
// INTERNAL METHODS
function clearPending() internal { function clearPending() internal {
uint length = m_pendingIndex.length; uint length = m_pendingIndex.length;
for (uint i = 0; i < length; ++i) for (uint i = 0; i < length; ++i)
delete m_txs[m_pendingIndex[i]]; delete m_txs[m_pendingIndex[i]];
super.clearPending(); super.clearPending();
} }
// // internally confirm transaction with all of the info. returns true iff confirmed good and executed.
// function confirmVerbose(bytes32 _h, address _to, uint _value, bytes _data) private onlymanyowners(_h) returns (bool) { // FIELDS
// _to.call.value(_value)(_data);
// MultiTransact("out", msg.sender, _h, _value, _to);
// return true;
// }
// pending transactions we have at present. // pending transactions we have at present.
mapping (bytes32 => Transaction) public m_txs; mapping (bytes32 => Transaction) m_txs;
} }
)DELIMITER"; )DELIMITER";
@ -443,7 +515,7 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer)
// 4 owners, set required to 3 // 4 owners, set required to 3
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
// check that balance is and stays zero at destination address // check that balance is and stays zero at destination address
h256 opHash("f916231db11c12e0142dc51f23632bc655de87c63f83fc928c443e90f7aa364a"); h256 opHash("8f27f478ebcfaf28b0c354f4809ace8087000d668b89c8bc3b1b608bfdbe6654");
BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
m_sender = Address(0x12); m_sender = Address(0x12);
BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));

10
test/libweb3jsonrpc/webthreestubclient.h

@ -302,6 +302,16 @@ class WebThreeStubClient : public jsonrpc::Client
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
Json::Value eth_getTransactionReceipt(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_getTransactionReceipt",p);
if (result.isObject())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value eth_getUncleByBlockHashAndIndex(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) Json::Value eth_getUncleByBlockHashAndIndex(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;

Loading…
Cancel
Save