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

5
alethzero/CMakeLists.txt

@ -7,6 +7,11 @@ if (${CMAKE_MAJOR_VERSION} GREATER 2)
cmake_policy(SET CMP0043 OLD)
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)
aux_source_directory(. SRC_LIST)

105
alethzero/DownloadView.cpp

@ -30,29 +30,118 @@ using namespace std;
using namespace dev;
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);
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;
double ratio = (double)rect().width() / rect().height();
if (ratio < 1)
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(n, n);
QPointF pos(0, 0);
auto bg = m_man->blocksGot();
unsigned subCount = m_man->subCount();
auto bg = man->blocksGot();
unsigned subCount = man->subCount();
if (subCount == 0)
return;
unsigned dh = 360 / subCount;
@ -64,7 +153,7 @@ void DownloadView::paintEvent(QPaintEvent*)
else
{
unsigned h = 0;
m_man->foreachSub([&](DownloadSub const& sub)
man->foreachSub([&](DownloadSub const& sub)
{
if (sub.askedContains(i))
s = h;

13
alethzero/DownloadView.h

@ -32,21 +32,24 @@
#endif
namespace dev { namespace eth {
class DownloadMan;
class Client;
}}
class DownloadView: public QWidget
class SyncView: public QWidget
{
Q_OBJECT
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:
virtual void paintEvent(QPaintEvent*);
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,12 +127,22 @@ void ExportStateDialog::fillContracts()
ui->contracts->clear();
ui->accounts->setEnabled(true);
ui->contracts->setEnabled(true);
try
{
for (auto i: ethereum()->addresses(m_block))
{
string r = m_main->render(i);
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), ethereum()->codeAt(i).empty() ? ui->accounts : ui->contracts))
->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()

16
alethzero/Main.ui

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

25
alethzero/MainWin.cpp

@ -136,6 +136,12 @@ Main::Main(QWidget *parent) :
QtWebEngine::initialize();
setWindowFlags(Qt::Window);
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)
{
simpleDebugOut(s, c);
@ -260,6 +266,8 @@ Main::Main(QWidget *parent) :
m_transact->setWindowFlags(Qt::Dialog);
m_transact->setWindowModality(Qt::WindowModal);
connect(ui->blockChainDockWidget, &QDockWidget::visibilityChanged, [=]() { refreshBlockChain(); });
#if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts);
#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_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()
{
QString s = ui->urlEdit->text();
@ -1307,7 +1326,7 @@ void Main::on_turboMining_triggered()
void Main::refreshBlockChain()
{
if (!ui->blocks->isVisible() && isVisible())
if (!(ui->blockChainDockWidget->isVisible() || !tabifiedDockWidgets(ui->blockChainDockWidget).isEmpty()))
return;
DEV_TIMED_FUNCTION_ABOVE(500);
@ -1985,12 +2004,12 @@ void Main::on_net_triggered()
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
ui->downloadView->setEthereum(ethereum());
ui->enode->setText(QString::fromStdString(web3()->enode()));
}
else
{
ui->downloadView->setDownloadMan(nullptr);
ui->downloadView->setEthereum(nullptr);
writeSettings();
web3()->stopNetwork();
}

1
alethzero/MainWin.h

@ -187,6 +187,7 @@ private slots:
void on_vmInterpreter_triggered();
void on_vmJIT_triggered();
void on_vmSmart_triggered();
void on_rewindChain_triggered();
// Debugger
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!");
}
void OurAccountHolder::authenticate(TransactionSkeleton const& _t)
h256 OurAccountHolder::authenticate(TransactionSkeleton const& _t)
{
Guard l(x_queued);
m_queued.push(_t);
return h256();
}
void OurAccountHolder::doValidations()
@ -130,7 +131,7 @@ void OurAccountHolder::doValidations()
else
// sign and submit.
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();
virtual dev::AddressHash realAccounts() const override;
// 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:
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")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# 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
if (NOT ETH_STATIC)

24
eth/main.cpp

@ -37,6 +37,7 @@
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
#include <libethereum/BlockChainSync.h>
#include <libethcore/KeyManager.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;
else if (c && cmd == "blockqueue")
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")
cout << "Current hash rate: " << toString(c->hashrate()) << " hashes per second." << endl;
else if (c && cmd == "findblock")
@ -1023,9 +1026,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{
string path;
iss >> path;
RLPStream config(2);
config << signingKey << beneficiary;
writeFile(path, config.out());
writeFile(path, rlpList(signingKey, beneficiary));
}
else
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();
KeyManager keyManager;
for (auto const& s: passwordsToNote)
keyManager.notePassword(s);
{
RLPStream config(2);
config << signingKey << beneficiary;
writeFile(configFile, config.out());
}
writeFile(configFile, rlpList(signingKey, beneficiary));
if (sessionKey)
signingKey = sessionKey;
@ -1700,7 +1706,7 @@ int main(int argc, char** argv)
cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << beneficiary << endl;
if (bootstrap || !remoteHost.empty())
if (bootstrap || !remoteHost.empty() || disableDiscovery)
{
web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl;

39
ethminer/MinerAux.h

@ -128,6 +128,33 @@ public:
cerr << "Bad " << arg << " option: " << argv[i] << endl;
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")
m_shouldListDevices = true;
else if (arg == "--allow-opencl-cpu")
@ -266,16 +293,16 @@ public:
else if (m_minerType == MinerType::GPU)
{
if (!ProofOfWork::GPUMiner::configureGPU(
m_localWorkSize,
m_globalWorkSizeMultiplier,
m_msPerBatch,
m_openclPlatform,
m_openclDevice,
m_clAllowCPU,
m_extraGPUMemory,
m_currentBlock
))
{
cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
exit(1);
}
ProofOfWork::GPUMiner::setNumInstances(m_miningThreads);
}
if (mode == OperationMode::DAGInit)
@ -318,6 +345,9 @@ public:
<< " --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
<< " --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;
bool m_shouldListDevices = 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;
// default value is 350MB of GPU memory for other stuff (windows system rendering, e.t.c.)
unsigned m_extraGPUMemory = 350000000;

2
exp/main.cpp

@ -135,7 +135,7 @@ int main()
DownloadSub s0(man);
DownloadSub s1(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((s1.nextFetch(2) == h256Set{(u256)5, (u256)6}));
assert((s2.nextFetch(2) == h256Set{(u256)3, (u256)4}));

37
libdevcore/Base64.cpp

@ -27,6 +27,8 @@
/// Originally by René Nyffenegger, modified by some other guy and then devified by Gav Wood.
#include "Base64.h"
using namespace std;
using namespace dev;
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('/');
}
std::string dev::toBase64(bytesConstRef _in)
string dev::toBase64(bytesConstRef _in)
{
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::string ret;
string ret;
int i = 0;
int j = 0;
byte char_array_3[3];
@ -60,15 +62,17 @@ std::string dev::toBase64(bytesConstRef _in)
auto buf = _in.data();
auto bufLen = _in.size();
while (bufLen--) {
while (bufLen--)
{
char_array_3[i++] = *(buf++);
if (i == 3) {
if (i == 3)
{
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[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
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]];
i = 0;
}
@ -76,7 +80,7 @@ std::string dev::toBase64(bytesConstRef _in)
if (i)
{
for(j = i; j < 3; j++)
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
@ -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[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]];
while((i++ < 3))
while (i++ < 3)
ret += '=';
}
return ret;
}
bytes dev::fromBase64(std::string const& encoded_string)
bytes dev::fromBase64(string const& encoded_string)
{
auto in_len = encoded_string.size();
int i = 0;
int j = 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;
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_++;
if (i == 4) {
if (i == 4)
{
for (i = 0; i < 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++)
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[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;

2
libdevcore/Common.cpp

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

25
libdevcore/FixedHash.h

@ -24,6 +24,7 @@
#pragma once
#include <array>
#include <cstdint>
#include <random>
#include <algorithm>
#include "CommonData.h"
@ -31,6 +32,10 @@
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;
/// 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); }
/// 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.
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) 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++() { 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; }
/// @returns a particular byte from the hash.
@ -146,7 +152,7 @@ public:
{
FixedHash ret;
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;
}
@ -171,18 +177,21 @@ public:
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 const unsigned c_bloomBits = M * 8;
unsigned mask = c_bloomBits - 1;
unsigned bloomBytes = (dev::toLog2(c_bloomBits) + 7) / 8;
static_assert(P * c_bloomBytes <= N, "out of range");
FixedHash<M> ret;
byte const* p = data();
for (unsigned i = 0; i < P; ++i)
{
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 &= mask;
index &= c_mask;
ret[M - 1 - index / 8] |= (1 << (index % 8));
}
return ret;

14
libdevcore/RangeMask.h

@ -200,6 +200,20 @@ public:
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:
/// The ground range.
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);
}
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;
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;
}
/**
* Nibble-based view on a bytesConstRef.
*/
struct NibbleSlice
{
bytesConstRef data;
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); }
unsigned size() const { return data.size() * 2 - offset; }
bool empty() const { return !size(); }
NibbleSlice mid(unsigned _index) const { return NibbleSlice(data, offset + _index); }
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(); }
/// @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()); }
/**
* @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
{
unsigned i;
for (i = 0; i < _k.size() && i < size(); ++i)
unsigned i = 0;
for (; i < _k.size() && i < size(); ++i)
if (operator[](i) < _k[i]) // Byte is lower - we're earlier..
return true;
else if (operator[](i) > _k[i]) // Byte is higher - we're not earlier.

162
libdevcore/TrieDB.h

@ -66,7 +66,7 @@ class GenericTrieDB
public:
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() {}
@ -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).
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 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);
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
}
/// Used for debugging, scans the whole trie.
void descendEntry(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
{
if (_r.isData() && _r.size() == 32)
@ -118,6 +180,7 @@ public:
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
{
if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out))
@ -139,6 +202,7 @@ public:
BOOST_THROW_EXCEPTION(InvalidTrie());
}
/// Used for debugging, scans the whole trie.
h256Hash leftOvers(std::ostream* _out = nullptr) const
{
h256Hash k = m_db->keys();
@ -146,11 +210,14 @@ public:
return k;
}
/// Used for debugging, scans the whole trie.
void debugStructure(std::ostream& _out) const
{
leftOvers(&_out);
}
/// Used for debugging, scans the whole trie.
/// @param _requireNoLeftOvers if true, requires that all keys are reachable.
bool check(bool _requireNoLeftOvers) const
{
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:
DB* db() const { return m_db; }
@ -279,12 +286,12 @@ private:
bool isTwoItemNode(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.
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 forceKillNode(h256 _h) { m_db->kill(_h); }
void forceInsertNode(h256 const& _h, bytesConstRef _v) { m_db->insert(_h, _v); }
void forceKillNode(h256 const& _h) { m_db->kill(_h); }
// 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
@ -305,6 +312,9 @@ std::ostream& operator<<(std::ostream& _out, GenericTrieDB<DB> const& _db)
return _out;
}
/**
* Different view on a GenericTrieDB that can use different key types.
*/
template <class Generic, class _KeyType>
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);
#endif
std::string rv = node(m_root);
assert(rv.size());
bytes b = mergeAt(RLP(rv), m_root, NibbleSlice(_key), _value);
std::string rootValue = node(m_root);
assert(rootValue.size());
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
// 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.
if (rv.size() < 32)
if (rootValue.size() < 32)
forceKillNode(m_root);
m_root = forceInsertNode(&b);
}
@ -1066,11 +1076,11 @@ template <class DB> bytes GenericTrieDB<DB>::place(RLP const& _orig, NibbleSlice
killNode(_orig);
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));
if (_orig.itemCount() == 2)
return (RLPStream(2) << _orig[0] << _s).out();
return rlpList(_orig[0], _s);
auto s = RLPStream(17);
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);
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 =
// std::cout << keyOf(_orig) << " ++ " << keyOf(n) << " == " << keyOf(RLP(ret)) << std::endl;
// return ret;
@ -1201,11 +1211,7 @@ template <class DB> bytes GenericTrieDB<DB>::branch(RLP const& _orig)
for (unsigned i = 0; i < 16; ++i)
if (i == b)
if (isLeaf(_orig) || k.size() > 1)
{
RLPStream bottom(2);
bottom << hexPrefixEncode(k.mid(1), isLeaf(_orig)) << _orig[1];
streamNode(r, bottom.out());
}
streamNode(r, rlpList(hexPrefixEncode(k.mid(1), isLeaf(_orig)), _orig[1]));
else
r << _orig[1];
else

18
libdevcrypto/Common.cpp

@ -22,6 +22,7 @@
#include "Common.h"
#include <random>
#include <cstdint>
#include <chrono>
#include <thread>
#include <mutex>
@ -29,6 +30,7 @@
#include <libdevcore/Guards.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/FileSystem.h>
#include <libdevcore/RLP.h>
#if ETH_HAVE_SECP256K1
#include <secp256k1/secp256k1.h>
#endif
@ -90,6 +92,11 @@ Address dev::toAddress(Secret const& _secret)
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)
{
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()
{
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)
{
KeyPair ret(FixedHash<32>::random(*s_eng.get()));
KeyPair ret(FixedHash<32>::random());
if (ret.address())
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::uniform_int_distribution<uint16_t> d(0, 255);
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)
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.
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.
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)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${OpenCL_INCLUDE_DIRS})
include_directories(..)
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})

68
libethash-cl/ethash_cl_miner.cpp

@ -33,6 +33,7 @@
#include <vector>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include <libethcore/Ethash.h>
#include <libethash/internal.h>
#include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h"
@ -49,6 +50,7 @@
#undef max
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
#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl
@ -140,11 +142,17 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId)
bool ethash_cl_miner::configureGPU(
unsigned _platformId,
unsigned _localWorkSize,
unsigned _globalWorkSize,
unsigned _msPerBatch,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
)
{
s_workgroupSize = _localWorkSize;
s_initialGlobalWorkSize = _globalWorkSize;
s_msPerBatch = _msPerBatch;
s_allowCPU = _allowCPU;
s_extraRequiredGPUMem = _extraGPUMemory;
// 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;
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)
{
@ -254,7 +265,6 @@ void ethash_cl_miner::finish()
bool ethash_cl_miner::init(
uint8_t const* _dag,
uint64_t _dagSize,
unsigned _workgroupSize,
unsigned _platformId,
unsigned _deviceId
)
@ -299,14 +309,18 @@ bool ethash_cl_miner::init(
m_context = cl::Context(vector<cl::Device>(&device, &device + 1));
m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8
m_workgroupSize = ((_workgroupSize + 7) / 8) * 8;
// make sure that global work size is evenly divisible by the local workgroup size
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
// 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
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, "ACCESSES", ETHASH_ACCESSES);
addDefinition(code, "MAX_OUTPUTS", c_maxSearchResults);
@ -323,7 +337,7 @@ bool ethash_cl_miner::init(
ETHCL_LOG("Printing program log");
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());
return false;
@ -415,9 +429,8 @@ bool ethash_cl_miner::init(
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
{
struct pending_batch
@ -454,10 +467,9 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
unsigned buf = 0;
random_device 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
m_searchKernel.setArg(0, m_searchBuffer[buf]);
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);
// 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 });
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);
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)
break;
@ -497,19 +509,31 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
pending.pop();
}
/* chrono::high_resolution_clock::duration d = chrono::high_resolution_clock::now() - t;
if (d > chrono::milliseconds(_msPerBatch * 10 / 9))
// adjust global work size depending on last search time
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.";
m_batchSize = max<unsigned>(128, m_batchSize * 9 / 10);
cerr << "New batch size" << m_batchSize;
// cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast<chrono::milliseconds>(d).count() << " ms, >> " << _msPerBatch << " ms." << endl;
m_globalWorkSize = max<unsigned>(128, m_globalWorkSize + s_workgroupSize);
// 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.";
m_batchSize = m_batchSize * 10 / 9;
cerr << "New batch size" << m_batchSize;
}*/
// cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast<chrono::milliseconds>(d).count() << " ms, << " << _msPerBatch << " ms." << endl;
m_globalWorkSize = min<unsigned>(pow(2, m_deviceBits) - 1, m_globalWorkSize - s_workgroupSize);
// 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

16
libethash-cl/ethash_cl_miner.h

@ -45,6 +45,9 @@ public:
static void listDevices();
static bool configureGPU(
unsigned _platformId,
unsigned _localWorkSize,
unsigned _globalWorkSize,
unsigned _msPerBatch,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
@ -53,12 +56,11 @@ public:
bool init(
uint8_t const* _dag,
uint64_t _dagSize,
unsigned _workgroupSize = 64,
unsigned _platformId = 0,
unsigned _deviceId = 0
);
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 search_chunk(uint8_t const*_header, uint64_t _target, search_hook& _hook);
@ -76,10 +78,16 @@ private:
cl::Buffer m_header;
cl::Buffer m_hashBuffer[c_bufferCount];
cl::Buffer m_searchBuffer[c_bufferCount];
unsigned m_workgroupSize;
unsigned m_batchSize = c_searchBatchSize;
unsigned m_globalWorkSize;
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
static bool s_allowCPU;
/// 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
};
class Transaction;
struct ImportRoute
{
h256s deadBlocks;
h256s liveBlocks;
std::vector<Transaction> goodTranactions;
};
enum class ImportResult
@ -129,10 +132,10 @@ struct ImportRequirements
};
/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight.
class Signal
template<typename... Args> class Signal
{
public:
using Callback = std::function<void()>;
using Callback = std::function<void(Args...)>;
class HandlerAux
{
@ -141,7 +144,7 @@ public:
public:
~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); m_s = nullptr; }
void reset() { m_s = nullptr; }
void fire() { m_h(); }
void fire(Args&&... _args) { m_h(std::forward<Args>(_args)...); }
private:
HandlerAux(unsigned _i, Signal* _s, Callback const& _h): m_i(_i), m_s(_s), m_h(_h) {}
@ -165,13 +168,13 @@ public:
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:
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
{
@ -182,6 +185,7 @@ struct TransactionSkeleton
bytes data;
u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256;
u256 nonce = UndefinedU256;
};
void badBlock(bytesConstRef _header, std::string const& _err);

30
libethcore/Ethash.cpp

@ -54,6 +54,9 @@ namespace dev
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();
std::string Ethash::name()
@ -373,7 +376,7 @@ void Ethash::GPUMiner::workLoop()
this_thread::sleep_for(chrono::milliseconds(500));
}
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);
@ -409,6 +412,9 @@ void Ethash::GPUMiner::listDevices()
}
bool Ethash::GPUMiner::configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId,
unsigned _deviceId,
bool _allowCPU,
@ -418,7 +424,27 @@ bool Ethash::GPUMiner::configureGPU(
{
s_platformId = _platformId;
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

11
libethcore/Ethash.h

@ -88,7 +88,7 @@ public:
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo();
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()); }
protected:
void kickOff() override
@ -118,6 +118,9 @@ public:
static unsigned getNumDevices();
static void listDevices();
static bool configureGPU(
unsigned _localWorkSize,
unsigned _globalWorkSizeMultiplier,
unsigned _msPerBatch,
unsigned _platformId,
unsigned _deviceId,
bool _allowCPU,
@ -147,6 +150,12 @@ public:
#else
using GPUMiner = CPUMiner;
#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::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)
{
int field = 0;

4
libethcore/Transaction.h

@ -51,6 +51,9 @@ public:
/// Constructs a null transaction.
TransactionBase() {}
/// Constructs a transaction from a transaction skeleton & optional secret.
TransactionBase(TransactionSkeleton const& _ts, Secret const& _s = Secret());
/// 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); }
@ -69,7 +72,6 @@ public:
/// Constructs a transaction from the given RLP.
explicit TransactionBase(bytes const& _rlp, CheckTransaction _checkSig): TransactionBase(&_rlp, _checkSig) {}
/// 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; }
/// Checks inequality of transactions.

4
libethereum/Account.h

@ -152,8 +152,7 @@ public:
h256 codeHash() const { assert(!isFreshCode()); return m_codeHash; }
/// 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 const& _code) { assert(isFreshCode()); m_codeCache = _code; changed(); }
void setCode(bytes&& _code) { assert(isFreshCode()); m_codeCache = std::move(_code); changed(); }
/// @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(); }
@ -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;
Timer t;
for (unsigned d = 1; d < originalNumber; ++d)
for (unsigned d = 1; d <= originalNumber; ++d)
{
if (!(d % 1000))
{
@ -337,6 +337,7 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
h256s fresh;
h256s dead;
h256s badBlocks;
Transactions goodTransactions;
unsigned count = 0;
for (VerifiedBlock const& block: blocks)
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);
fresh += r.liveBlocks;
dead += r.deadBlocks;
goodTransactions += r.goodTranactions;
++count;
}
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());
}
}
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
@ -497,6 +499,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
BlockReceipts br;
u256 td;
Transactions goodTransactions;
#if ETH_CATCH
try
#endif
@ -510,6 +513,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
{
blb.blooms.push_back(s.receipt(i).bloom());
br.receipts.push_back(s.receipt(i));
goodTransactions.push_back(s.pending()[i]);
}
s.cleanup(true);
@ -750,7 +754,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
dead.push_back(h);
else
fresh.push_back(h);
return ImportRoute{dead, fresh};
return ImportRoute{dead, fresh, move(goodTransactions)};
}
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
{
// cdebug << "treeRoute" << _from << "..." << _to;
@ -867,33 +890,21 @@ template <class T> static unsigned getHashSize(unordered_map<h256, T> const& _ma
void BlockChain::updateStats() const
{
{
ReadGuard l(x_blocks);
m_lastStats.memBlocks = 0;
DEV_READ_GUARDED(x_blocks)
for (auto const& i: m_blocks)
m_lastStats.memBlocks += i.second.size() + 64;
}
{
ReadGuard l(x_details);
DEV_READ_GUARDED(x_details)
m_lastStats.memDetails = getHashSize(m_details);
}
{
ReadGuard l1(x_logBlooms);
ReadGuard l2(x_blocksBlooms);
DEV_READ_GUARDED(x_logBlooms)
DEV_READ_GUARDED(x_blocksBlooms)
m_lastStats.memLogBlooms = getHashSize(m_logBlooms) + getHashSize(m_blocksBlooms);
}
{
ReadGuard l(x_receipts);
DEV_READ_GUARDED(x_receipts)
m_lastStats.memReceipts = getHashSize(m_receipts);
}
{
ReadGuard l(x_blockHashes);
DEV_READ_GUARDED(x_blockHashes)
m_lastStats.memBlockHashes = getHashSize(m_blockHashes);
}
{
ReadGuard l(x_transactionAddresses);
DEV_READ_GUARDED(x_transactionAddresses)
m_lastStats.memTransactionAddresses = getHashSize(m_transactionAddresses);
}
}
void BlockChain::garbageCollect(bool _force)
@ -950,10 +961,8 @@ void BlockChain::garbageCollect(bool _force)
void BlockChain::checkConsistency()
{
{
WriteGuard l(x_details);
DEV_WRITE_GUARDED(x_details)
m_details.clear();
}
ldb::Iterator* it = m_blocksDB->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().size() == 32)
@ -965,15 +974,11 @@ void BlockChain::checkConsistency()
{
auto dp = details(p);
if (asserts(contains(dp.children, h)))
{
cnote << "Apparently the database is corrupt. Not much we can do at this stage...";
}
if (assertsEqual(dp.number, dh.number - 1))
{
cnote << "Apparently the database is corrupt. Not much we can do at this stage...";
}
}
}
delete it;
}
@ -1084,7 +1089,8 @@ bool BlockChain::isKnown(h256 const& _hash) const
if (d.empty())
return false;
}
return true;
// return true;
return details(_hash).number <= m_lastBlockNumber; // to allow rewind functionality.
}
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() 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.
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()); }
@ -212,6 +215,9 @@ public:
/// 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);
/// Alter the head of the chain to some prior block along it.
void rewind(unsigned _newHead);
/** @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
* 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_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):
m_host(_host)
{
@ -69,7 +80,7 @@ DownloadMan& BlockChainSync::downloadMan()
void BlockChainSync::abortSync()
{
downloadMan().resetToChain(h256s());
downloadMan().reset();
}
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)
_peer->m_requireTransactions = true;
RLPStream s;
if (_s == 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);
protected:
Handler m_bqRoomAvailable; ///< Triggered once block queue
Handler<> m_bqRoomAvailable; ///< Triggered once block queue
mutable RecursiveMutex x_sync;
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.
@ -316,5 +316,8 @@ private:
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
};
std::ostream& operator<<(std::ostream& _out, SyncStatus const& _sync);
}
}

4
libethereum/BlockDetails.h

@ -59,7 +59,7 @@ struct BlockLogBlooms
{
BlockLogBlooms() {}
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;
mutable unsigned size;
@ -69,7 +69,7 @@ struct BlocksBlooms
{
BlocksBlooms() {}
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;
mutable unsigned size;

4
libethereum/BlockQueue.cpp

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

8
libethereum/BlockQueue.h

@ -111,8 +111,8 @@ public:
/// Get some infomration on the given block's status regarding us.
QueueStatus blockStatus(h256 const& _h) const;
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<> 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> 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.
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
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_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.
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.

13
libethereum/Client.cpp

@ -604,19 +604,18 @@ void Client::onChainChanged(ImportRoute const& _ir)
for (auto const& t: m_bc.transactions(h))
{
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.
for (auto const& h: _ir.liveBlocks)
{
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;
m_tq.drop(th);
}
clog(ClientTrace) << "Safely dropping transaction " << t.sha3();
m_tq.dropGood(t);
}
if (auto h = m_host.lock())
@ -651,7 +650,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
for (auto const& t: m_postMine.pending())
{
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)
onTransactionQueueReady();
}

6
libethereum/Client.h

@ -217,6 +217,8 @@ public:
std::string const& sentinel() const { return m_sentinel; }
/// Set the extra data that goes into mined blocks.
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head.
void rewind(unsigned _n) { m_bc.rewind(_n); }
protected:
/// InterfaceStub methods
@ -310,8 +312,8 @@ private:
GenericFarm<ProofOfWork> m_farm; ///< Our mining farm.
Handler m_tqReady;
Handler m_bqReady;
Handler<> m_tqReady;
Handler<> m_bqReady;
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.

46
libethereum/ClientBase.cpp

@ -45,48 +45,21 @@ State ClientBase::asOf(BlockNumber _h) const
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();
Transaction t(_value, _gasPrice, _gas, _dest, _data, _nonce, _secret);
m_tq.import(t.rlp());
TransactionSkeleton ts(_t);
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());
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);
Transaction t(ts, _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())));
}
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())));
return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));
}
// TODO: remove try/catch, allow exceptions
@ -354,6 +327,11 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
return Transaction();
}
TransactionReceipt ClientBase::transactionReceipt(h256 const& _transactionHash) const
{
return bc().transactionReceipt(_transactionHash);
}
pair<h256, unsigned> ClientBase::transactionLocation(h256 const& _transactionHash) const
{
return bc().transactionLocation(_transactionHash);

12
libethereum/ClientBase.h

@ -75,14 +75,9 @@ public:
ClientBase() {}
virtual ~ClientBase() {}
/// Submits the given message-call transaction.
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce);
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) 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;
/// Submits the given transaction.
/// @returns the new transaction's hash.
virtual std::pair<h256, Address> submitTransaction(TransactionSkeleton const& _t, Secret const& _secret) override;
using Interface::submitTransaction;
/// Makes the given call. Nothing is recorded into the state.
@ -124,6 +119,7 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const override;
virtual Transaction transaction(h256 _transactionHash) 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 Transactions transactions(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::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)
{
WriteGuard l(m_man->x_subs);

25
libethereum/DownloadMan.h

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

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" };
#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):
HostCapability<EthereumPeer>(),
Worker ("ethsync"),
@ -54,6 +60,7 @@ EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQu
m_networkId (_networkId)
{
m_latestBlockSent = _ch.currentHash();
m_tq.onImport([this](ImportResult _ir, h256 const& _h, h512 const& _nodeId) { onTransactionImported(_ir, _h, _nodeId); });
}
EthereumHost::~EthereumHost()
@ -66,8 +73,9 @@ bool EthereumHost::ensureInitialised()
{
// First time - just initialise.
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();
return true;
}
@ -82,6 +90,7 @@ void EthereumHost::reset()
m_sync.reset();
m_latestBlockSent = h256();
Guard tl(x_transactions);
m_transactionsSent.clear();
}
@ -116,6 +125,8 @@ void EthereumHost::maintainTransactions()
// Send any new transactions.
unordered_map<std::shared_ptr<EthereumPeer>, std::vector<size_t>> peerTransactions;
auto ts = m_tq.topTransactions(c_maxSendTransactions);
{
Guard l(x_transactions);
for (size_t i = 0; i < ts.size(); ++i)
{
auto const& t = ts[i];
@ -126,6 +137,7 @@ void EthereumHost::maintainTransactions()
}
for (auto const& t: ts)
m_transactionsSent.insert(t.sha3());
}
foreachPeer([&](shared_ptr<EthereumPeer> _p)
{
bytes b;
@ -144,7 +156,7 @@ void EthereumHost::maintainTransactions()
RLPStream ts;
_p->prep(ts, TransactionsPacket, n).appendRaw(b, n);
_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;
return true;
@ -200,11 +212,15 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash)
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.
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));
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 (auto const& b: blocks)
{
@ -286,33 +302,12 @@ void EthereumHost::onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP c
{
if (_peer->isCriticalSyncing())
{
clog(NetAllDetail) << "Ignoring transaction from peer we are syncing with";
clog(EthereumHostTrace) << "Ignoring transaction from peer we are syncing with";
return;
}
unsigned itemCount = _r.itemCount();
clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)";
Guard l(_peer->x_knownTransactions);
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:;
}
}
clog(EthereumHostTrace) << "Transactions (" << dec << itemCount << "entries)";
m_tq.enqueue(_r, _peer->session()->id());
}
void EthereumHost::onPeerAborting()
@ -344,3 +339,35 @@ SyncStatus EthereumHost::status() const
return SyncStatus();
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 BlockChainSync;
struct EthereumHostTrace: public LogChannel { static const char* name(); static const int verbosity = 6; };
/**
* @brief The EthereumHost class
* @warning None of this is thread-safe. You have been warned.
@ -105,6 +107,7 @@ private:
void maintainTransactions();
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.
bool isInitialised() const { return (bool)m_latestBlockSent; }
@ -132,6 +135,7 @@ private:
bool m_newBlocks = false;
mutable Mutex x_sync;
mutable Mutex x_transactions;
DownloadMan m_man;
std::unique_ptr<BlockChainSync> m_sync;
};

9
libethereum/Executive.cpp

@ -153,6 +153,11 @@ u256 Executive::gasUsed() const
return m_t.gas() - m_gas;
}
u256 Executive::gasUsedNoRefunds() const
{
return m_t.gas() - m_gas + m_refunded;
}
void Executive::accrueSubState(SubState& _parentContext)
{
if (m_ext)
@ -391,8 +396,8 @@ void Executive::finalize()
// SSTORE refunds...
// must be done before the miner gets the fees.
if (m_ext)
m_gas += min((m_t.gas() - m_gas) / 2, m_ext->sub.refunds);
m_refunded = m_ext ? min((m_t.gas() - m_gas) / 2, m_ext->sub.refunds) : 0;
m_gas += m_refunded;
// 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());

4
libethereum/Executive.h

@ -110,6 +110,9 @@ public:
/// @returns total gas used in the transaction/operation.
/// @warning Only valid after finalise().
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.
/// @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.
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_refunded = 0; ///< The amount of gas refunded.
Transaction m_t; ///< The original transaction. Set by setup().
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;
/// 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.
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.
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)
{
@ -70,6 +78,7 @@ void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp)
// 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
// the rest of the calls up to the depth limit (c_depthLimit).
if (_depth == c_offloadPoint)
goOnOffloadedStack(_e, _onOp);
else
@ -82,7 +91,11 @@ bool ExtVM::call(CallParameters& _p)
Executive e(m_s, lastHashes, depth + 1);
if (!e.call(_p, gasPrice, origin))
{
#if __clang__ // Enabled for clang only as the problem affects OSX
go(depth, e, _p.onOp);
#else
e.go(_p.onOp);
#endif
e.accrueSubState(sub);
}
_p.gas = e.gas();
@ -104,4 +117,3 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc
io_gas = e.gas();
return e.newAddress();
}

29
libethereum/Interface.cpp

@ -20,6 +20,31 @@
*/
#include "Interface.h"
using namespace std;
using namespace dev;
using namespace eth;
#pragma GCC diagnostic ignored "-Wunused-variable"
namespace { char dummy; }
void Interface::submitTransaction(Secret const& _secret, u256 const& _value, Address const& _dest, bytes const& _data, u256 const& _gas, u256 const& _gasPrice, u256 const& _nonce)
{
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]
/// Submits the given message-call transaction.
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0;
/// Submits a new transaction.
/// @returns the transaction's hash.
virtual std::pair<h256, Address> submitTransaction(TransactionSkeleton const& _t, Secret const& _secret) = 0;
/// 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 = 10000, u256 _gasPrice = 10 * szabo) = 0;
/// Submits the given message-call transaction.
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);
/// Submits a new contract-creation transaction.
/// @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.
virtual void flushTransactions() = 0;
@ -135,6 +135,7 @@ public:
virtual bool isKnownTransaction(h256 const& _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 h256 hashFromNumber(BlockNumber _number) const = 0;
virtual BlockNumber numberFromHash(h256 _blockHash) const = 0;

34
libethereum/State.cpp

@ -38,6 +38,7 @@
#include "Executive.h"
#include "CachedAddressState.h"
#include "CanonBlockChain.h"
#include "TransactionQueue.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -444,7 +445,8 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor
#if ETH_TIMED_ENACTMENTS
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
return ret;
}
@ -512,18 +514,17 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
{
if (t.gasPrice() >= _gp.ask(*this))
{
// Timer t;
// Timer t;
if (lh.empty())
lh = _bc.lastHashes();
execute(lh, t);
ret.first.push_back(m_receipts.back());
++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
// cnote << "TX took:" << t.elapsed() * 1000;
}
else if (t.gasPrice() < _gp.ask(*this) * 9 / 10)
{
// less than 90% of our ask price for gas. drop.
cnote << t.sha3() << "Dropping El Cheapo transaction (<90% of ask price)";
clog(StateTrace) << t.sha3() << "Dropping El Cheapo transaction (<90% of ask price)";
_tq.drop(t.sha3());
}
}
@ -535,22 +536,13 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
if (req > got)
{
// too old
for (Transaction const& mt: m_transactions)
{
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)";
}
}
clog(StateTrace) << t.sha3() << "Dropping old transaction (nonce too low)";
_tq.drop(t.sha3());
}
else if (got > req + _tq.waiting(t.sender()))
{
// 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());
}
else
@ -561,7 +553,7 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
bigint const& got = *boost::get_error_info<errinfo_got>(e);
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());
}
else
@ -575,14 +567,14 @@ pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQu
catch (Exception const& _e)
{
// 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());
}
catch (std::exception const&)
{
// Something else went wrong - drop it.
_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)
@ -964,6 +956,8 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
m_currentBlock.stateRoot = m_state.root();
m_currentBlock.parentHash = m_previousBlock.hash();
m_currentBlock.extraData = _extraData;
if (m_currentBlock.extraData.size() > 32)
m_currentBlock.extraData.resize(32);
m_committedToMine = true;
}
@ -1218,7 +1212,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
uncommitToMine();
// OK - transaction looks valid - execute.
u256 startGasUsed = gasUsed();
u256 startGasUsed = e.gasUsed();
#if ETH_PARANOIA
ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp());

2
libethereum/State.h

@ -32,7 +32,6 @@
#include <libethcore/ProofOfWork.h>
#include <libethcore/Miner.h>
#include <libevm/ExtVMFace.h>
#include "TransactionQueue.h"
#include "Account.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
@ -67,6 +66,7 @@ using LogBloomRequirementError = boost::tuple<errinfo_required_LogBloom, errinfo
class BlockChain;
class State;
class TransactionQueue;
struct VerifiedBlockRef;
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.
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.
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)
@ -96,12 +99,12 @@ public:
{}
/// 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)
{}
/// 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)
{}

153
libethereum/TransactionQueue.cpp

@ -31,7 +31,28 @@ using namespace dev::eth;
const char* TransactionQueueChannel::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.
h256 h = sha3(_transactionRLP);
@ -49,14 +70,13 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb
{
t = Transaction(_transactionRLP, CheckTransaction::Everything);
UpgradeGuard ul(l);
ir = manageImport_WITH_LOCK(h, t, _cb);
ir = manageImport_WITH_LOCK(h, t);
}
catch (...)
{
return ImportResult::Malformed;
}
}
// cdebug << "import-END: Nonce of" << t.sender() << "now" << maxNonce(t.sender());
return ir;
}
@ -71,27 +91,24 @@ ImportResult TransactionQueue::check_WITH_LOCK(h256 const& _h, IfDropped _ik)
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.
h256 h = _transaction.sha3(WithSignature);
// cdebug << "import-BEGIN: Nonce of sender" << maxNonce(_transaction.sender());
ImportResult ret;
{
UpgradableGuard l(m_lock);
// TODO: keep old transactions around and check in State for nonce validity
auto ir = check_WITH_LOCK(h, _ik);
if (ir != ImportResult::Success)
return ir;
{
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;
}
@ -111,7 +128,7 @@ h256Hash TransactionQueue::knownTransactions() const
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
{
@ -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));
if (_cb)
m_callbacks[_h] = _cb;
clog(TransactionQueueTraceChannel) << "Queued vaguely legit-looking transaction" << _h;
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
{
// cdebug << "txQ::maxNonce" << _a;
ReadGuard l(m_lock);
return maxNonce_WITH_LOCK(_a);
}
@ -212,29 +226,7 @@ void TransactionQueue::insertCurrent_WITH_LOCK(std::pair<h256, Transaction> cons
m_currentByHash[_p.first] = handle;
// Move following transactions from future to current
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)
{
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());
}
}
makeCurrent_WITH_LOCK(t);
m_known.insert(_p.first);
}
@ -296,6 +288,44 @@ void TransactionQueue::setFuture(h256 const& _txHash)
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)
{
UpgradableGuard l(m_lock);
@ -305,9 +335,17 @@ void TransactionQueue::drop(h256 const& _txHash)
UpgradeGuard ul(l);
m_dropped.insert(_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()
@ -320,3 +358,44 @@ void TransactionQueue::clear()
m_future.clear();
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
#include <functional>
#include <condition_variable>
#include <thread>
#include <deque>
#include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
@ -49,15 +52,14 @@ enum class IfDropped { Ignore, Retry };
class TransactionQueue
{
public:
using ImportCallback = std::function<void(ImportResult)>;
/// @brief TransactionQueue
/// @param _limit Maximum number of pending transactions in the queue
/// @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) {}
ImportResult import(Transaction const& _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore);
ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore) { return import(&_tx, _cb, _ik); }
ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore);
TransactionQueue(unsigned _limit = 1024, unsigned _futureLimit = 1024);
~TransactionQueue();
void enqueue(RLP const& _data, h512 const& _nodeId);
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);
@ -66,9 +68,11 @@ public:
h256Hash knownTransactions() const;
u256 maxNonce(Address const& _a) const;
void setFuture(h256 const& _t);
void dropGood(Transaction const& _t);
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:
struct VerifiedTransaction
@ -77,11 +81,25 @@ private:
VerifiedTransaction(VerifiedTransaction&& _t): transaction(std::move(_t.transaction)) {}
VerifiedTransaction(VerifiedTransaction const&) = delete;
VerifiedTransaction operator=(VerifiedTransaction const&) = delete;
VerifiedTransaction& operator=(VerifiedTransaction const&) = delete;
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
{
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.
using PriorityQueue = std::multiset<VerifiedTransaction, PriorityCompare>;
ImportResult import(bytesConstRef _tx, IfDropped _ik = IfDropped::Ignore);
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 makeCurrent_WITH_LOCK(Transaction const& _t);
bool remove_WITH_LOCK(h256 const& _txHash);
u256 maxNonce_WITH_LOCK(Address const& _a) const;
void verifierBody();
mutable SharedMutex m_lock; ///< General lock.
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, 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_futureLimit; ///< Max 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)
{
verified.info = _bi;
verified.info = std::move(_bi);
}
VerifiedBlock(VerifiedBlock&& _other):

6
libevm/ExtVMFace.cpp

@ -21,22 +21,20 @@
#include "ExtVMFace.h"
using namespace std;
using namespace dev;
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),
caller(_caller),
origin(_origin),
value(_value),
gasPrice(_gasPrice),
data(_data),
code(_code),
code(std::move(_code)),
codeHash(_codeHash),
lastHashes(_lh),
previousBlock(_previousBlock),
currentBlock(_currentBlock),
depth(_depth)
{}

2
libevm/ExtVMFace.h

@ -161,7 +161,7 @@ public:
ExtVMFace() = default;
/// 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;

1
libjsengine/CMakeLists.txt

@ -19,7 +19,6 @@ file(GLOB HEADERS "*.h")
include(EthUtils)
eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" "JSRES")
message(STATUS "HERE!!! ${JSRES}")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
# 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.
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:
void onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e);
@ -211,7 +214,7 @@ protected:
private:
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.
void determinePublic();

5
libp2p/Session.cpp

@ -256,9 +256,8 @@ bool Session::checkPacket(bytesConstRef _msg)
void Session::send(bytes&& _msg)
{
clog(NetLeft) << RLP(bytesConstRef(&_msg).cropped(1));
bytesConstRef msg(&_msg);
clog(NetLeft) << RLP(msg.cropped(1));
if (!checkPacket(msg))
clog(NetWarn) << "INVALID PACKET CONSTRUCTED!";
@ -268,7 +267,7 @@ void Session::send(bytes&& _msg)
bool doWrite = false;
{
Guard l(x_writeQueue);
m_writeQueue.push_back(_msg);
m_writeQueue.push_back(std::move(_msg));
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);
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].setCode(code);
m_state.m_cache[address].setCode(std::move(code));
}
else
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();
}
void SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
h256 SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
{
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))
queueTransaction(_t);
return h256();
}
void FixedAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
h256 FixedAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
{
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))
queueTransaction(_t);
return h256();
}

6
libweb3jsonrpc/AccountHolder.h

@ -51,7 +51,7 @@ public:
virtual AddressHash realAccounts() const = 0;
// use m_web3's submitTransaction
// 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;
bool isRealAccount(Address const& _account) const { return realAccounts().count(_account) > 0; }
@ -85,7 +85,7 @@ public:
{}
AddressHash realAccounts() const override;
void authenticate(dev::eth::TransactionSkeleton const& _t) override;
h256 authenticate(dev::eth::TransactionSkeleton const& _t) override;
private:
std::function<std::string(Address)> m_getPassword;
@ -117,7 +117,7 @@ public:
// use m_web3's submitTransaction
// or use AccountHolder::queueTransaction(_t) to accept
void authenticate(dev::eth::TransactionSkeleton const& _t) override;
h256 authenticate(dev::eth::TransactionSkeleton const& _t) override;
private:
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;
}
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 res;
@ -269,6 +296,9 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json)
if (!_json["code"].empty())
ret.data = jsToBytes(_json["code"].asString());
if (!_json["nonce"].empty())
ret.nonce = jsToU256(_json["nonce"].asString());
return ret;
}

3
libweb3jsonrpc/JsonHelper.h

@ -50,12 +50,15 @@ using UncleHashes = h256s;
using TransactionHashes = h256s;
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(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(TransactionSkeleton const& _t);
Json::Value toJson(Transaction 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(LogEntry const& _e);
TransactionSkeleton toTransactionSkeleton(Json::Value const& _json);

27
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -242,21 +242,16 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
{
try
{
string ret;
TransactionSkeleton t = toTransactionSkeleton(_json);
if (!t.from)
t.from = m_ethAccounts->defaultTransactAccount();
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (t.gasPrice == UndefinedU256)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (t.gas == UndefinedU256)
t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
m_ethAccounts->authenticate(t);
return ret;
return toJS(m_ethAccounts->authenticate(t));
}
catch (...)
{
@ -268,13 +263,10 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json)
{
try
{
string ret;
TransactionSkeleton t = toTransactionSkeleton(_json);
if (!t.from)
t.from = m_ethAccounts->defaultTransactAccount();
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (t.gasPrice == UndefinedU256)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
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)
{
try

1
libweb3jsonrpc/WebThreeStubServerBase.h

@ -119,6 +119,7 @@ public:
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_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_getUncleByBlockNumberAndIndex(std::string const& _blockNumber, std::string const& _uncleIndex);
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_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_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_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);
@ -224,6 +225,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
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)
{
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_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_getTransactionReceipt(const std::string& param1) = 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_getCompilers() = 0;

1
libweb3jsonrpc/spec.json

@ -29,6 +29,7 @@
{ "name": "eth_getTransactionByHash", "params": [""], "order": [], "returns": {}},
{ "name": "eth_getTransactionByBlockHashAndIndex", "params": ["", ""], "order": [], "returns": {}},
{ "name": "eth_getTransactionByBlockNumberAndIndex", "params": ["", ""], "order": [], "returns": {}},
{ "name": "eth_getTransactionReceipt", "params": [""], "order": [], "returns": {}},
{ "name": "eth_getUncleByBlockHashAndIndex", "params": ["", ""], "order": [], "returns": {}},
{ "name": "eth_getUncleByBlockNumberAndIndex", "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(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)
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 newAddress = m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice, _ctrTransaction.gasAuto);
return newAddress;
return m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice, _ctrTransaction.gasAuto);
}
void ClientModel::callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)

2
mix/ClientModel.h

@ -252,7 +252,7 @@ private:
QVariantMap contractAddresses() const;
QVariantList gasCosts() const;
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 onNewTransaction();
void onStateReset();

8
mix/DebuggingStateWrapper.h

@ -69,7 +69,7 @@ class QSolState: public QObject
public:
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:
@ -92,7 +92,7 @@ class QCode: public QObject
Q_PROPERTY(QString documentId MEMBER m_document CONSTANT)
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; }
private:
@ -110,7 +110,7 @@ class QCallData: public QObject
Q_PROPERTY(QVariantList items MEMBER m_items CONSTANT)
public:
QCallData(QObject* _owner, QVariantList&& _items): QObject(_owner), m_items(_items) {}
QCallData(QObject* _owner, QVariantList&& _items): QObject(_owner), m_items(std::move(_items)) {}
private:
QVariantList m_items;
@ -126,7 +126,7 @@ class QDebugData: public QObject
public:
QDebugData() { }
void setStates(QVariantList&& _states) { m_states = _states; }
void setStates(QVariantList&& _states) { m_states = std::move(_states); }
private:
QVariantList m_states;

2
mix/HttpServer.h

@ -46,7 +46,7 @@ class HttpRequest: public QObject
private:
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;
}
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);
u256 n = m_state.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
TransactionSkeleton ts = _ts;
ts.nonce = m_state.transactionsFrom(toAddress(_secret));
eth::Transaction t(ts, _secret);
executeTransaction(t, m_state, false, _gasAuto, _secret);
}
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;
return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));
}
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;
}
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)
{
return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff);

9
mix/MixClient.h

@ -54,14 +54,12 @@ public:
ExecutionResult lastExecution() 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 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;
void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto);
Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, 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); }
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);
void setAddress(Address _us) override;
@ -78,6 +76,9 @@ public:
using Interface::blockInfo; // to remove warning about hiding virtual function
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:
/// ClientBase methods
using ClientBase::asOf;

8
neth/main.cpp

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

4
test/TestHelper.cpp

@ -199,10 +199,10 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
stateOptions.m_bHasCode = true;
}
if (code.size())
if (!code.empty())
{
_state.m_cache[address] = Account(balance, Account::ContractConception);
_state.m_cache[address].setCode(code);
_state.m_cache[address].setCode(std::move(code));
}
else
_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;
Secret const sec("test");
Secret const sec(dev::sha3("test"));
crypto::aes::AuthenticatedStream as(crypto::aes::Encrypt, sec, 0);
BOOST_CHECK(as.getMacInterval() == 0);
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/TransientDirectory.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/TransactionQueue.h>
#include <test/TestHelper.h>
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);
}
BOOST_AUTO_TEST_CASE(bcBlockGasLimitTest)
{
dev::test::executeTests("bcBlockGasLimitTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests);
}
BOOST_AUTO_TEST_CASE(bcWalletTest)
{
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);
}
BOOST_AUTO_TEST_CASE(stPreCompiledContractsTransaction)
{
dev::test::executeTests("stPreCompiledContractsTransaction", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);
}
BOOST_AUTO_TEST_CASE(stLogTests)
{
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
// interior is executed.
contract multiowned {
// TYPES
// struct for the status of a pending operation.
struct PendingState {
uint yetNeeded;
uint ownersDone;
uint index;
}
// EVENTS
// this contract only has five types of events: it can accept a confirmation, in which case
// we record owner and operation (hash) alongside it.
event Confirmation(address owner, bytes32 operation);
@ -63,14 +69,9 @@ contract multiowned {
event OwnerRemoved(address oldOwner);
// the last one is emitted if the required signatures change
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.
function multiowned() {
m_required = 1;
m_numOwners = 1;
m_owners[m_numOwners] = uint(msg.sender);
m_ownerIndex[uint(msg.sender)] = m_numOwners;
}
// MODIFIERS
// simple single-sig function modifier.
modifier onlyowner {
if (isOwner(msg.sender))
@ -80,9 +81,21 @@ contract multiowned {
// that later attempts can be realised as the same underlying operation and
// thus count as confirmations.
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
function revoke(bytes32 _operation) external {
uint ownerIndex = m_ownerIndex[uint(msg.sender)];
@ -96,7 +109,75 @@ contract multiowned {
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:
uint ownerIndex = m_ownerIndex[uint(msg.sender)];
// 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) {
uint free = 1;
while (free < m_numOwners)
@ -182,6 +228,7 @@ contract multiowned {
}
}
}
function clearPending() internal {
uint length = m_pendingIndex.length;
for (uint i = 0; i < length; ++i)
@ -189,46 +236,54 @@ contract multiowned {
delete m_pending[m_pendingIndex[i]];
delete m_pendingIndex;
}
function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external {
if (_newRequired > m_numOwners) return;
m_required = _newRequired;
clearPending();
RequirementChanged(_newRequired);
}
function isOwner(address _addr) returns (bool) {
return m_ownerIndex[uint(_addr)] > 0;
}
// FIELDS
// the number of owners that must confirm the same operation before it is run.
uint public m_required;
// pointer used to find a free slot in m_owners
uint public m_numOwners;
// list of owners
uint[256] public m_owners;
uint[256] m_owners;
uint constant c_maxOwners = 250;
// index on the list of owners to allow reverse lookup
mapping(uint => uint) public m_ownerIndex;
mapping(uint => uint) m_ownerIndex;
// the ongoing operations.
mapping(bytes32 => PendingState) public m_pending;
bytes32[] public m_pendingIndex;
mapping(bytes32 => PendingState) m_pending;
bytes32[] m_pendingIndex;
}
// 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
// uses is specified in the modifier.
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.
function daylimit() {
m_lastDay = 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;
}
// (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;
}
// INTERNAL METHODS
// 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.
function underLimit(uint _value) internal onlyowner returns (bool) {
@ -244,60 +299,76 @@ contract daylimit is multiowned {
}
return false;
}
// simple modifier for daily limit.
modifier limitedDaily(uint _value) {
if (underLimit(_value))
_
}
// determines today's index.
function today() private constant returns (uint) { return now / 1 days; }
uint public m_spentToday;
// FIELDS
uint public m_dailyLimit;
uint public m_lastDay;
uint m_spentToday;
uint m_lastDay;
}
// interface contract for multisig proxy contracts; see below for docs.
contract multisig {
// EVENTS
// logged events:
// Funds has arrived into the wallet (record how much).
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);
// 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);
// Confirmation still needed for a transaction.
event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data);
// FUNCTIONS
// TODO: document
function changeOwner(address _from, address _to) external;
function execute(address _to, uint _value, bytes _data) external returns (bytes32);
function confirm(bytes32 _h) returns (bool);
}
// usage:
// bytes32 h = Wallet(w).from(oneOwner).transact(to, value, data);
// Wallet(w).from(anotherOwner).confirm(h);
contract Wallet is multisig, multiowned, daylimit {
// TYPES
// Transaction structure to remember details of transaction lest it need be saved for a later call.
struct Transaction {
address to;
uint value;
bytes data;
}
/*
// logged events:
// Funds has arrived into the wallet (record how much).
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);
// 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);*/
// EVENTS
event Created(bytes32 indexed identifier);
// METHODS
// constructor - just pass on the owner arra to the multiowned.
event Created();
function Wallet() {
Created();
function Wallet(bytes32 identifier) {
Created(identifier);
}
// 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);
}
// gets called when no other function matches
function() {
// just being sent some cash?
if (msg.value > 0)
Deposit(msg.sender, msg.value);
}
// 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
// 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;
}
// determine our operation hash.
_r = sha3(msg.data);
_r = sha3(msg.data, block.number);
if (!confirm(_r) && m_txs[_r].to == 0) {
m_txs[_r].to = _to;
m_txs[_r].value = _value;
@ -319,6 +390,7 @@ contract Wallet is multisig, multiowned, daylimit {
ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
}
}
// 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.
function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
@ -329,20 +401,20 @@ contract Wallet is multisig, multiowned, daylimit {
return true;
}
}
// INTERNAL METHODS
function clearPending() internal {
uint length = m_pendingIndex.length;
for (uint i = 0; i < length; ++i)
delete m_txs[m_pendingIndex[i]];
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) {
// _to.call.value(_value)(_data);
// MultiTransact("out", msg.sender, _h, _value, _to);
// return true;
// }
// FIELDS
// pending transactions we have at present.
mapping (bytes32 => Transaction) public m_txs;
mapping (bytes32 => Transaction) m_txs;
}
)DELIMITER";
@ -443,7 +515,7 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer)
// 4 owners, set required to 3
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
// 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);
m_sender = Address(0x12);
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
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 p;

Loading…
Cancel
Save