Browse Source

Merge pull request #1 from ethereum/develop

Update to current cpp-ethereum
cl-refactor
AronVanAmmers 11 years ago
parent
commit
7043b38d8e
  1. 14
      CMakeLists.txt
  2. 2
      alethzero/CMakeLists.txt
  3. 83
      alethzero/DownloadView.cpp
  4. 47
      alethzero/DownloadView.h
  5. 112
      alethzero/Main.ui
  6. 442
      alethzero/MainWin.cpp
  7. 89
      alethzero/MainWin.h
  8. 13
      alethzero/MiningView.cpp
  9. 11
      alethzero/MiningView.h
  10. 4
      eth/CMakeLists.txt
  11. 11
      eth/CommonJS.cpp
  12. 41
      eth/CommonJS.h
  13. 44
      eth/EthStubServer.cpp
  14. 14
      eth/EthStubServer.h
  15. 7
      eth/abstractethstubserver.h
  16. 12
      eth/eth.js
  17. 200
      eth/main.cpp
  18. 1
      exp/CMakeLists.txt
  19. 330
      exp/main.cpp
  20. 0
      libdevcore/All.h
  21. 4
      libdevcore/CMakeLists.txt
  22. 7
      libdevcore/Common.cpp
  23. 19
      libdevcore/Common.h
  24. 282
      libdevcore/CommonData.cpp
  25. 23
      libdevcore/CommonData.h
  26. 10
      libdevcore/CommonIO.cpp
  27. 22
      libdevcore/CommonIO.h
  28. 2
      libdevcore/Exceptions.h
  29. 4
      libdevcore/FixedHash.cpp
  30. 24
      libdevcore/FixedHash.h
  31. 4
      libdevcore/Guards.cpp
  32. 2
      libdevcore/Guards.h
  33. 16
      libdevcore/Log.cpp
  34. 18
      libdevcore/Log.h
  35. 42
      libdevcore/RLP.cpp
  36. 130
      libdevcore/RLP.h
  37. 22
      libdevcore/RangeMask.cpp
  38. 212
      libdevcore/RangeMask.h
  39. 63
      libdevcore/Worker.cpp
  40. 59
      libdevcore/Worker.h
  41. 12
      libdevcore/_libdevcore.cpp
  42. 12
      libdevcore/vector_ref.h
  43. 9
      libdevcrypto/All.h
  44. 56
      libdevcrypto/CMakeLists.txt
  45. 110
      libdevcrypto/Common.cpp
  46. 89
      libdevcrypto/Common.h
  47. 54
      libdevcrypto/CryptoHeaders.h
  48. 8
      libdevcrypto/FileSystem.cpp
  49. 2
      libdevcrypto/FileSystem.h
  50. 8
      libdevcrypto/MemoryDB.cpp
  51. 13
      libdevcrypto/MemoryDB.h
  52. 8
      libdevcrypto/OverlayDB.cpp
  53. 12
      libdevcrypto/OverlayDB.h
  54. 49
      libdevcrypto/SHA3.cpp
  55. 9
      libdevcrypto/SHA3.h
  56. 29
      libdevcrypto/TrieCommon.cpp
  57. 33
      libdevcrypto/TrieCommon.h
  58. 11
      libdevcrypto/TrieDB.cpp
  59. 30
      libdevcrypto/TrieDB.h
  60. 10
      libethcore/All.h
  61. 18
      libethcore/BlockInfo.cpp
  62. 13
      libethcore/BlockInfo.h
  63. 6
      libethcore/CMakeLists.txt
  64. 69
      libethcore/CommonEth.cpp
  65. 62
      libethcore/CommonEth.h
  66. 10
      libethcore/Dagger.cpp
  67. 18
      libethcore/Dagger.h
  68. 69
      libethcore/Exceptions.h
  69. 183
      libethcore/UPnP.cpp
  70. 6
      libethcore/_libethcore.cpp
  71. 104
      libethential/CommonData.cpp
  72. 15
      libethereum/AccountDiff.cpp
  73. 11
      libethereum/AccountDiff.h
  74. 3
      libethereum/AddressState.cpp
  75. 10
      libethereum/AddressState.h
  76. 2
      libethereum/All.h
  77. 133
      libethereum/BlockChain.cpp
  78. 24
      libethereum/BlockChain.h
  79. 7
      libethereum/BlockDetails.cpp
  80. 16
      libethereum/BlockDetails.h
  81. 67
      libethereum/BlockQueue.cpp
  82. 31
      libethereum/BlockQueue.h
  83. 3
      libethereum/CMakeLists.txt
  84. 323
      libethereum/Client.cpp
  85. 161
      libethereum/Client.h
  86. 42
      libethereum/CommonNet.cpp
  87. 94
      libethereum/CommonNet.h
  88. 5
      libethereum/Defaults.cpp
  89. 5
      libethereum/Defaults.h
  90. 75
      libethereum/DownloadMan.cpp
  91. 147
      libethereum/DownloadMan.h
  92. 697
      libethereum/EthereumHost.cpp
  93. 141
      libethereum/EthereumHost.h
  94. 334
      libethereum/EthereumPeer.cpp
  95. 96
      libethereum/EthereumPeer.h
  96. 628
      libethereum/EthereumSession.cpp
  97. 116
      libethereum/EthereumSession.h
  98. 14
      libethereum/Executive.cpp
  99. 5
      libethereum/Executive.h
  100. 13
      libethereum/ExtVM.h

14
CMakeLists.txt

@ -324,7 +324,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
include_directories(/usr/local/include)
endif()
add_subdirectory(libethential)
add_subdirectory(libdevcore)
add_subdirectory(libevmface)
add_subdirectory(liblll)
add_subdirectory(libserpent)
@ -337,12 +337,16 @@ add_subdirectory(lllc)
add_subdirectory(sc)
if (NOT LANGUAGES)
add_subdirectory(secp256k1)
add_subdirectory(libethnet)
add_subdirectory(libp2p)
add_subdirectory(libdevcrypto)
add_subdirectory(libwhisper)
add_subdirectory(libethcore)
add_subdirectory(libevm)
add_subdirectory(libwhisper)
add_subdirectory(libethereum)
add_subdirectory(libethereumx)
# add_subdirectory(libethereumx) # TODO remove
add_subdirectory(libwebthree)
add_subdirectory(test)
add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
@ -365,7 +369,7 @@ if (NOT LANGUAGES)
add_subdirectory(third)
if(QTQML)
#add_subdirectory(iethxi)
add_subdirectory(walleth)
#add_subdirectory(walleth) // resurect once we want to submit ourselves to QML.
endif()
endif()
endif()

2
alethzero/CMakeLists.txt

@ -52,7 +52,7 @@ else ()
endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface ethential)
target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore)
if (APPLE)
# First have qt5 install plugins and frameworks

83
alethzero/DownloadView.cpp

@ -0,0 +1,83 @@
/*
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 DownloadView.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "DownloadView.h"
#include <QtWidgets>
#include <QtCore>
#include <libethereum/DownloadMan.h>
#include "Grapher.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
DownloadView::DownloadView(QWidget* _p): QWidget(_p)
{
}
void DownloadView::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.fillRect(rect(), Qt::white);
if (!m_man || m_man->chain().empty() || !m_man->subCount())
return;
double ratio = (double)rect().width() / rect().height();
if (ratio < 1)
ratio = 1 / ratio;
double n = min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio));
// QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n));
QSizeF area(n, n);
QPointF pos(0, 0);
auto const& bg = m_man->blocksGot();
for (unsigned i = bg.all().first, ei = bg.all().second; i < ei; ++i)
{
int s = -2;
if (bg.contains(i))
s = -1;
else
{
unsigned h = 0;
m_man->foreachSub([&](DownloadSub const& sub)
{
if (sub.asked().contains(i))
s = h;
h++;
});
}
unsigned dh = 360 / m_man->subCount();
if (s == -2)
p.fillRect(QRectF(QPointF(pos) + QPointF(3 * area.width() / 8, 3 * area.height() / 8), area / 4), Qt::black);
else if (s == -1)
p.fillRect(QRectF(QPointF(pos) + QPointF(1 * area.width() / 8, 1 * area.height() / 8), area * 3 / 4), Qt::black);
else
p.fillRect(QRectF(QPointF(pos) + QPointF(1 * area.width() / 8, 1 * area.height() / 8), area * 3 / 4), QColor::fromHsv(s * dh, 64, 128));
pos.setX(pos.x() + n);
if (pos.x() >= rect().width() - n)
pos = QPoint(0, pos.y() + n);
}
}

47
libwhisper/Whisper.h → alethzero/DownloadView.h

@ -14,37 +14,40 @@
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 Whisper.h
/** @file DownloadView.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
namespace eth
{
/*
class NetPeer
#ifdef Q_MOC_RUN
#define BOOST_MPL_IF_HPP_INCLUDED
#endif
#include <list>
#include <QtWidgets/QWidget>
#ifndef Q_MOC_RUN
#include <libethereum/Client.h>
#endif
namespace dev { namespace eth {
struct MineInfo;
class DownloadMan;
}}
class DownloadView: public QWidget
{
Q_OBJECT
public:
NetPeer();
virtual ~NetPeer();
DownloadView(QWidget* _p = nullptr);
void setDownloadMan(dev::eth::DownloadMan const* _man) { m_man = _man; }
protected:
virtual void onIncoming(PeerId);
void send(PeerId);
};
*/
/**
*/
class Whisper//: public NetPeer
{
public:
/// Constructor.
Whisper();
virtual void paintEvent(QPaintEvent*);
/// Destructor.
virtual ~Whisper();
private:
dev::eth::DownloadMan const* m_man = nullptr;
};
}

112
alethzero/Main.ui

@ -130,8 +130,11 @@
<property name="title">
<string>&amp;Network</string>
</property>
<addaction name="go"/>
<addaction name="separator"/>
<addaction name="upnp"/>
<addaction name="usePast"/>
<addaction name="localNetworking"/>
<addaction name="net"/>
<addaction name="connect"/>
</widget>
@ -140,15 +143,12 @@
<string>T&amp;ools</string>
</property>
<addaction name="mine"/>
<addaction name="preview"/>
<addaction name="separator"/>
<addaction name="create"/>
<addaction name="importKey"/>
<addaction name="importKeyFile"/>
<addaction name="exportKey"/>
<addaction name="separator"/>
<addaction name="showAll"/>
<addaction name="showAllAccounts"/>
<addaction name="separator"/>
<addaction name="loadJS"/>
</widget>
<widget class="QMenu" name="menu_Help">
@ -161,7 +161,32 @@
<property name="title">
<string>Deb&amp;ug</string>
</property>
<widget class="QMenu" name="menuDump_Trace">
<addaction name="debugDumpState"/>
<addaction name="debugDumpStatePre"/>
<addaction name="separator"/>
<addaction name="paranoia"/>
<addaction name="killBlockchain"/>
<addaction name="inject"/>
<addaction name="forceMining"/>
<addaction name="turboMining"/>
<addaction name="enableOptimizer"/>
<addaction name="separator"/>
<addaction name="usePrivate"/>
</widget>
<widget class="QMenu" name="menu_View">
<property name="title">
<string>&amp;View</string>
</property>
<addaction name="showAll"/>
<addaction name="showAllAccounts"/>
<addaction name="separator"/>
<addaction name="preview"/>
</widget>
<widget class="QMenu" name="menuDebugger">
<property name="title">
<string>D&amp;ebugger</string>
</property>
<widget class="QMenu" name="menu_Dump_Trace">
<property name="title">
<string>&amp;Dump Trace</string>
</property>
@ -170,8 +195,7 @@
<addaction name="dumpTracePretty"/>
</widget>
<addaction name="debugCurrent"/>
<addaction name="debugDumpState"/>
<addaction name="debugDumpStatePre"/>
<addaction name="menu_Dump_Trace"/>
<addaction name="separator"/>
<addaction name="debugStep"/>
<addaction name="debugStepInto"/>
@ -179,20 +203,12 @@
<addaction name="debugStepBack"/>
<addaction name="debugStepBackInto"/>
<addaction name="debugStepBackOut"/>
<addaction name="menuDump_Trace"/>
<addaction name="separator"/>
<addaction name="paranoia"/>
<addaction name="killBlockchain"/>
<addaction name="inject"/>
<addaction name="forceMining"/>
<addaction name="turboMining"/>
<addaction name="enableOptimizer"/>
<addaction name="separator"/>
<addaction name="usePrivate"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_View"/>
<addaction name="menu_Network"/>
<addaction name="menu_Tools"/>
<addaction name="menuDebugger"/>
<addaction name="menu_Debug"/>
<addaction name="menu_Help"/>
</widget>
@ -506,8 +522,7 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="net"/>
<addaction name="connect"/>
<addaction name="go"/>
<addaction name="preview"/>
<addaction name="mine"/>
<addaction name="refresh"/>
@ -1432,6 +1447,39 @@ font-size: 14pt</string>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_12">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Blockchain Download</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_12">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="DownloadView" name="downloadView" native="true"/>
</item>
</layout>
</widget>
</widget>
<action name="quit">
<property name="text">
<string>&amp;Quit</string>
@ -1487,7 +1535,7 @@ font-size: 14pt</string>
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Preview</string>
<string>&amp;Preview Pending Transactions</string>
</property>
</action>
<action name="debugStep">
@ -1698,6 +1746,24 @@ font-size: 14pt</string>
<string>Reserved Debug 1</string>
</property>
</action>
<action name="localNetworking">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable Local Addresses</string>
</property>
</action>
<action name="importKeyFile">
<property name="text">
<string>Claim Ether Presale &amp;Wallet...</string>
</property>
</action>
<action name="go">
<property name="text">
<string>Go!</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
@ -1712,6 +1778,12 @@ font-size: 14pt</string>
<header>MiningView.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DownloadView</class>
<extends>QWidget</extends>
<header>DownloadView.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>destination</tabstop>

442
alethzero/MainWin.cpp

File diff suppressed because it is too large

89
alethzero/MainWin.h

@ -21,43 +21,47 @@
#pragma once
#ifdef Q_MOC_RUN
#define BOOST_MPL_IF_HPP_INCLUDED
#endif
#include <map>
#include <QtNetwork/QNetworkAccessManager>
#include <QtCore/QAbstractListModel>
#include <QtCore/QMutex>
#include <QtWidgets/QMainWindow>
#include <libethential/RLP.h>
#include <libdevcore/RLP.h>
#include <libethcore/CommonEth.h>
#include <libethereum/State.h>
#include <libqethereum/QEthereum.h>
#include <libwebthree/WebThree.h>
namespace Ui {
class Main;
}
namespace eth {
namespace dev { namespace eth {
class Client;
class State;
class MessageFilter;
}
}}
class QQuickView;
struct WorldState
{
uint64_t steps;
eth::Address cur;
eth::u256 curPC;
eth::Instruction inst;
eth::bigint newMemSize;
eth::u256 gas;
eth::h256 code;
eth::h256 callData;
eth::u256s stack;
eth::bytes memory;
eth::bigint gasCost;
std::map<eth::u256, eth::u256> storage;
dev::Address cur;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::h256 code;
dev::h256 callData;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<WorldState const*> levels;
};
@ -69,9 +73,11 @@ public:
explicit Main(QWidget *parent = 0);
~Main();
eth::Client* client() { return m_client.get(); }
dev::WebThreeDirect* web3() const { return m_webThree.get(); }
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
QList<eth::KeyPair> const& owned() const { return m_myKeys; }
QList<dev::KeyPair> const& owned() const { return m_myKeys; }
public slots:
void load(QString _file);
@ -141,23 +147,27 @@ private slots:
void on_usePrivate_triggered();
void on_enableOptimizer_triggered();
void on_turboMining_triggered();
void on_go_triggered();
void on_importKeyFile_triggered();
signals:
void poll();
private:
QString pretty(eth::Address _a) const;
QString prettyU256(eth::u256 _n) const;
dev::p2p::NetworkPreferences netPrefs() const;
QString pretty(dev::Address _a) const;
QString prettyU256(dev::u256 _n) const;
QString lookup(QString const& _n) const;
void populateDebugger(eth::bytesConstRef r);
void populateDebugger(dev::bytesConstRef r);
void initDebugger();
void updateDebugger();
void debugFinished();
QString render(eth::Address _a) const;
eth::Address fromString(QString const& _a) const;
std::string renderDiff(eth::StateDiff const& _d) const;
QString render(dev::Address _a) const;
dev::Address fromString(QString const& _a) const;
std::string renderDiff(dev::eth::StateDiff const& _d) const;
void alterDebugStateGroup(bool _enable) const;
@ -166,13 +176,15 @@ private:
void writeSettings();
bool isCreation() const;
eth::u256 fee() const;
eth::u256 total() const;
eth::u256 value() const;
eth::u256 gasPrice() const;
dev::u256 fee() const;
dev::u256 total() const;
dev::u256 value() const;
dev::u256 gasPrice() const;
unsigned installWatch(eth::MessageFilter const& _tf, std::function<void()> const& _f);
unsigned installWatch(eth::h256 _tf, std::function<void()> const& _f);
unsigned installWatch(dev::eth::MessageFilter const& _tf, std::function<void()> const& _f);
unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f);
void keysChanged();
void onNewPending();
void onNewBlock();
@ -200,7 +212,8 @@ private:
std::unique_ptr<Ui::Main> ui;
std::unique_ptr<eth::Client> m_client;
std::unique_ptr<dev::WebThreeDirect> m_webThree;
std::map<unsigned, std::function<void()>> m_handlers;
unsigned m_nameRegFilter = (unsigned)-1;
unsigned m_currenciesFilter = (unsigned)-1;
@ -208,23 +221,22 @@ private:
QByteArray m_peers;
QStringList m_servers;
QList<eth::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myKeys;
QString m_privateChain;
bool m_keysChanged = false;
eth::bytes m_data;
eth::Address m_nameReg;
dev::bytes m_data;
dev::Address m_nameReg;
unsigned m_backupGas;
eth::State m_executiveState;
std::unique_ptr<eth::Executive> m_currentExecution;
eth::h256 m_lastCode;
eth::h256 m_lastData;
dev::eth::State m_executiveState;
std::unique_ptr<dev::eth::Executive> m_currentExecution;
dev::h256 m_lastCode;
dev::h256 m_lastData;
std::vector<WorldState const*> m_lastLevels;
QMap<unsigned, unsigned> m_pcWarp;
QList<WorldState> m_history;
std::map<eth::u256, eth::bytes> m_codes; // and pcWarps
std::map<dev::u256, dev::bytes> m_codes; // and pcWarps
bool m_enableOptimizer = true;
QNetworkAccessManager m_webCtrl;
@ -235,4 +247,5 @@ private:
bool m_logChanged = true;
QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr;
};

13
alethzero/MiningView.cpp

@ -29,17 +29,18 @@
using namespace std;
using namespace lb;
// do *not* use eth since eth::uint conflicts with Qt's global unit definition
// using namespace eth;
// do *not* use eth since unsigned conflicts with Qt's global unit definition
// using namespace dev;
using namespace dev::eth;
// types
using eth::MineInfo;
using eth::MineProgress;
using dev::eth::MineInfo;
using dev::eth::MineProgress;
// functions
using eth::toString;
using eth::trimFront;
using dev::toString;
using dev::trimFront;
string id(float _y) { return toString(_y); }
string s(float _x){ return toString(round(_x * 1000) / 1000) + (!_x ? "s" : ""); }

11
alethzero/MiningView.h

@ -27,12 +27,13 @@
#include <list>
#include <QtWidgets/QWidget>
#ifndef Q_MOC_RUN
#include <libethereum/Client.h>
#endif
namespace eth
{
namespace dev { namespace eth {
struct MineInfo;
}
}}
class MiningView: public QWidget
{
@ -41,14 +42,14 @@ class MiningView: public QWidget
public:
MiningView(QWidget* _p = nullptr);
void appendStats(std::list<eth::MineInfo> const& _l, eth::MineProgress const& _p);
void appendStats(std::list<dev::eth::MineInfo> const& _l, dev::eth::MineProgress const& _p);
void resetStats();
protected:
virtual void paintEvent(QPaintEvent*);
private:
eth::MineProgress m_progress;
dev::eth::MineProgress m_progress;
unsigned m_duration = 300;
std::vector<float> m_values;
std::vector<float> m_bests;

4
eth/CMakeLists.txt

@ -4,13 +4,13 @@ aux_source_directory(. SRC_LIST)
include_directories(..)
link_directories(../libethcore)
link_directories(../libethereum)
link_directories(../libwebthree)
set(EXECUTABLE eth)
add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp)
if(MINIUPNPC_LS)

11
eth/CommonJS.cpp

@ -22,9 +22,10 @@
#include "CommonJS.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
bytes eth::jsToBytes(string const& _s)
bytes dev::eth::jsToBytes(string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
@ -37,7 +38,7 @@ bytes eth::jsToBytes(string const& _s)
return asBytes(_s);
}
string eth::jsPadded(string const& _s, unsigned _l, unsigned _r)
string dev::eth::jsPadded(string const& _s, unsigned _l, unsigned _r)
{
bytes b = jsToBytes(_s);
while (b.size() < _l)
@ -47,7 +48,7 @@ string eth::jsPadded(string const& _s, unsigned _l, unsigned _r)
return asString(b).substr(b.size() - max(_l, _r));
}
string eth::jsPadded(string const& _s, unsigned _l)
string dev::eth::jsPadded(string const& _s, unsigned _l)
{
if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == string::npos)
// Numeric: pad to right
@ -57,7 +58,7 @@ string eth::jsPadded(string const& _s, unsigned _l)
return jsPadded(_s, 0, _l);
}
string eth::jsUnpadded(string _s)
string dev::eth::jsUnpadded(string _s)
{
auto p = _s.find_last_not_of((char)0);
_s.resize(p == string::npos ? 0 : (p + 1));

41
eth/CommonJS.h

@ -23,66 +23,69 @@
#pragma once
#include <string>
#include <libethential/Common.h>
#include <libethential/CommonIO.h>
#include <libethential/CommonData.h>
#include <libethential/FixedHash.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/FixedHash.h>
#include <libethcore/CommonEth.h>
namespace dev
{
namespace eth
{
eth::bytes jsToBytes(std::string const& _s);
bytes jsToBytes(std::string const& _s);
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r);
std::string jsPadded(std::string const& _s, unsigned _l);
std::string jsUnpadded(std::string _s);
template <unsigned N> eth::FixedHash<N> jsToFixed(std::string const& _s)
template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return eth::FixedHash<N>(_s.substr(2));
return FixedHash<N>(_s.substr(2));
else if (_s.find_first_not_of("0123456789") == std::string::npos)
// Decimal
return (typename eth::FixedHash<N>::Arith)(_s);
return (typename FixedHash<N>::Arith)(_s);
else
// Binary
return eth::FixedHash<N>(asBytes(jsPadded(_s, N)));
return FixedHash<N>(asBytes(jsPadded(_s, N)));
}
template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> jsToInt(std::string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return eth::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(eth::fromHex(_s.substr(2)));
return fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(fromHex(_s.substr(2)));
else if (_s.find_first_not_of("0123456789") == std::string::npos)
// Decimal
return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s);
else
// Binary
return eth::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N)));
return fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N)));
}
inline eth::Address jsToAddress(std::string const& _s) { return jsToFixed<20>(_s); }
inline eth::Secret jsToSecret(std::string const& _s) { return jsToFixed<32>(_s); }
inline eth::u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); }
inline Address jsToAddress(std::string const& _s) { return jsToFixed<20>(_s); }
inline Secret jsToSecret(std::string const& _s) { return jsToFixed<32>(_s); }
inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); }
template <unsigned S> std::string toJS(eth::FixedHash<S> const& _h) { return "0x" + toHex(_h.ref()); }
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n) { return "0x" + eth::toHex(eth::toCompactBigEndian(_n)); }
template <unsigned S> std::string toJS(FixedHash<S> const& _h) { return "0x" + toHex(_h.ref()); }
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n) { return "0x" + toHex(toCompactBigEndian(_n)); }
inline std::string jsToBinary(std::string const& _s)
{
return eth::asString(jsToBytes(_s));
return asString(jsToBytes(_s));
}
inline std::string jsToDecimal(std::string const& _s)
{
return eth::toString(jsToU256(_s));
return toString(jsToU256(_s));
}
inline std::string jsToHex(std::string const& _s)
{
return "0x" + eth::toHex(asBytes(_s));
return "0x" + toHex(asBytes(_s));
}
}
}

44
eth/EthStubServer.cpp

@ -25,13 +25,15 @@
#include <libevmface/Instruction.h>
#include <liblll/Compiler.h>
#include <libethereum/Client.h>
#include <libwebthree/WebThree.h>
#include "CommonJS.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, Client& _client):
EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3):
AbstractEthStubServer(_conn),
m_client(_client)
m_web3(_web3)
{
}
@ -58,20 +60,25 @@ Json::Value EthStubServer::procedures()
return ret;
}
dev::eth::Client& EthStubServer::ethereum() const
{
return *m_web3.ethereum();
}
std::string EthStubServer::coinbase()
{
return toJS(m_client.address());
return toJS(ethereum().address());
}
std::string EthStubServer::balanceAt(std::string const& _a)
{
return toJS(m_client.balanceAt(jsToAddress(_a), 0));
return toJS(ethereum().balanceAt(jsToAddress(_a), 0));
}
Json::Value EthStubServer::check(Json::Value const& _as)
{
// TODO
// if (m_client.changed())
// if (ethereum().changed())
return _as;
/* else
{
@ -83,13 +90,13 @@ Json::Value EthStubServer::check(Json::Value const& _as)
std::string EthStubServer::create(const std::string& _bCode, const std::string& _sec, const std::string& _xEndowment, const std::string& _xGas, const std::string& _xGasPrice)
{
Address ret = m_client.transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice));
Address ret = ethereum().transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice));
return toJS(ret);
}
std::string EthStubServer::lll(const std::string& _s)
{
return "0x" + toHex(eth::compileLLL(_s));
return "0x" + toHex(dev::eth::compileLLL(_s));
}
std::string EthStubServer::gasPrice()
@ -99,17 +106,17 @@ std::string EthStubServer::gasPrice()
bool EthStubServer::isContractAt(const std::string& _a)
{
return m_client.codeAt(jsToAddress(_a), 0).size();
return ethereum().codeAt(jsToAddress(_a), 0).size();
}
bool EthStubServer::isListening()
{
return m_client.haveNetwork();
return m_web3.haveNetwork();
}
bool EthStubServer::isMining()
{
return m_client.isMining();
return ethereum().isMining();
}
std::string EthStubServer::key()
@ -129,23 +136,28 @@ Json::Value EthStubServer::keys()
int EthStubServer::peerCount()
{
return m_client.peerCount();
return m_web3.peerCount();
}
std::string EthStubServer::storageAt(const std::string& _a, const std::string& x)
{
return toJS(m_client.stateAt(jsToAddress(_a), jsToU256(x), 0));
return toJS(ethereum().stateAt(jsToAddress(_a), jsToU256(x), 0));
}
std::string EthStubServer::stateAt(const std::string& _a, const std::string& x, const std::string& s)
{
return toJS(ethereum().stateAt(jsToAddress(_a), jsToU256(x), std::atol(s.c_str())));
}
Json::Value EthStubServer::transact(const std::string& _aDest, const std::string& _bData, const std::string& _sec, const std::string& _xGas, const std::string& _xGasPrice, const std::string& _xValue)
{
m_client.transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice));
ethereum().transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice));
return Json::Value();
}
std::string EthStubServer::txCountAt(const std::string& _a)
{
return toJS(m_client.countAt(jsToAddress(_a), 0));
return toJS(ethereum().countAt(jsToAddress(_a), 0));
}
std::string EthStubServer::secretToAddress(const std::string& _a)
@ -166,7 +178,7 @@ Json::Value EthStubServer::block(const std::string& _hash)
Json::Value EthStubServer::blockJson(const std::string& _hash)
{
Json::Value res;
auto const& bc = m_client.blockChain();
auto const& bc = ethereum().blockChain();
auto b = _hash.length() ? bc.block(h256(_hash)) : bc.block();

14
eth/EthStubServer.h

@ -23,18 +23,18 @@
#include <iostream>
#include <jsonrpc/rpc.h>
#include <libdevcrypto/Common.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "abstractethstubserver.h"
#pragma GCC diagnostic pop
namespace eth { class Client; }
namespace eth { class KeyPair; }
namespace dev { class WebThreeDirect; namespace eth { class Client; } class KeyPair; }
class EthStubServer: public AbstractEthStubServer
{
public:
EthStubServer(jsonrpc::AbstractServerConnector* _conn, eth::Client& _client);
EthStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3);
virtual Json::Value procedures();
virtual std::string balanceAt(std::string const& _a);
@ -49,16 +49,18 @@ public:
virtual Json::Value keys();
virtual int peerCount();
virtual std::string storageAt(const std::string& a, const std::string& x);
virtual std::string stateAt(const std::string& a, const std::string& x, const std::string& s);
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue);
virtual std::string txCountAt(const std::string& a);
virtual std::string secretToAddress(const std::string& a);
virtual Json::Value lastBlock();
virtual std::string lll(const std::string& s);
virtual Json::Value block(const std::string&);
void setKeys(std::vector<eth::KeyPair> _keys) { m_keys = _keys; }
void setKeys(std::vector<dev::KeyPair> _keys) { m_keys = _keys; }
private:
eth::Client& m_client;
std::vector<eth::KeyPair> m_keys;
dev::eth::Client& ethereum() const;
dev::WebThreeDirect& m_web3;
std::vector<dev::KeyPair> m_keys;
Json::Value jsontypeToValue(int);
Json::Value blockJson(const std::string&);
};

7
eth/abstractethstubserver.h

@ -30,6 +30,7 @@ class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServ
this->bindAndAddMethod(new jsonrpc::Procedure("procedures", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::proceduresI);
this->bindAndAddMethod(new jsonrpc::Procedure("secretToAddress", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::secretToAddressI);
this->bindAndAddMethod(new jsonrpc::Procedure("storageAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::storageAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("stateAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING,"s",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::stateAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "aDest",jsonrpc::JSON_STRING,"bData",jsonrpc::JSON_STRING,"sec",jsonrpc::JSON_STRING,"xGas",jsonrpc::JSON_STRING,"xGasPrice",jsonrpc::JSON_STRING,"xValue",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::transactI);
this->bindAndAddMethod(new jsonrpc::Procedure("txCountAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::txCountAtI);
@ -120,6 +121,11 @@ class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServ
response = this->storageAt(request["a"].asString(), request["x"].asString());
}
inline virtual void stateAtI(const Json::Value& request, Json::Value& response)
{
response = this->stateAt(request["a"].asString(), request["x"].asString(), request["s"].asString());
}
inline virtual void transactI(const Json::Value& request, Json::Value& response)
{
response = this->transact(request["aDest"].asString(), request["bData"].asString(), request["sec"].asString(), request["xGas"].asString(), request["xGasPrice"].asString(), request["xValue"].asString());
@ -148,6 +154,7 @@ class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServ
virtual Json::Value procedures() = 0;
virtual std::string secretToAddress(const std::string& a) = 0;
virtual std::string storageAt(const std::string& a, const std::string& x) = 0;
virtual std::string stateAt(const std::string& a, const std::string& x, const std::string& b) = 0;
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue) = 0;
virtual std::string txCountAt(const std::string& a) = 0;

12
eth/eth.js

@ -25,6 +25,7 @@ var spec = [
{ "method": "peerCount", "params": null, "order": [], "returns" : 0 },
{ "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" },
{ "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" },
{ "method": "stateAt", "params": { "a": "", "x": "", "s": "" }, "order": ["a", "x", "s"], "returns" : "" },
{ "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" },
{ "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false },
{ "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" },
@ -70,9 +71,14 @@ window.eth = (function ethScope() {
var m = s.method;
var am = "get" + m.slice(0, 1).toUpperCase() + m.slice(1);
var getParams = function(a) {
var p = s.params ? {} : null
var p = s.params ? {} : null;
if (m == "stateAt")
if (a.length == 2)
a[2] = "0";
else
a[2] = String(a[2]);
for (j in s.order)
p[s.order[j]] = (s.order[j][0] === "b") ? a[j].unbin() : a[j]
p[s.order[j]] = (s.order[j][0] === "b") ? a[j].unbin() : a[j];
return p
};
if (m == "create" || m == "transact")
@ -101,7 +107,7 @@ window.eth = (function ethScope() {
for (var c in changed)
m_watching[changed[c]]()
var that = this;
setTimeout(function() { that.check() }, 5000)
setTimeout(function() { that.check() }, 12000)
}
ret.watch = function(a, fx, f) {

200
eth/main.cpp

@ -29,10 +29,11 @@
#if ETH_JSONRPC
#include <jsonrpc/connectors/httpserver.h>
#endif
#include <libethcore/FileSystem.h>
#include <libdevcrypto/FileSystem.h>
#include <libevmface/Instruction.h>
#include <libevm/VM.h>
#include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#if ETH_READLINE
#include <readline/readline.h>
#include <readline/history.h>
@ -42,9 +43,11 @@
#endif
#include "BuildInfo.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::p2p;
using namespace dev::eth;
using namespace boost::algorithm;
using eth::Instruction;
using dev::eth::Instruction;
#undef RETURN
@ -96,6 +99,7 @@ void help()
<< "Usage eth [OPTIONS] <remote-host>" << endl
<< "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
@ -109,7 +113,8 @@ void help()
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
@ -124,23 +129,14 @@ string credits(bool _interactive = false)
{
std::ostringstream cout;
cout
<< "Ethereum (++) " << eth::EthVersion << endl
<< "Ethereum (++) " << dev::Version << endl
<< " Code by Gav Wood, (c) 2013, 2014." << endl
<< " Based on a design by Vitalik Buterin." << endl << endl;
if (_interactive)
{
string vs = toString(eth::EthVersion);
vs = vs.substr(vs.find_first_of('.') + 1)[0];
int pocnumber = stoi(vs);
string m_servers;
if (pocnumber == 4)
m_servers = "54.72.31.55";
else
m_servers = "54.72.69.180";
cout << "Type 'netstart 30303' to start networking" << endl;
cout << "Type 'connect " << m_servers << " 30303' to connect" << endl;
cout << "Type 'connect " << Host::pocHost() << " 30303' to connect" << endl;
cout << "Type 'exit' to quit" << endl << endl;
}
return cout.str();
@ -148,13 +144,13 @@ string credits(bool _interactive = false)
void version()
{
cout << "eth version " << eth::EthVersion << endl;
cout << "Build: " << ETH_QUOTED(ETH_BUILD_PLATFORM) << "/" << ETH_QUOTED(ETH_BUILD_TYPE) << endl;
cout << "eth version " << dev::Version << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
Address c_config = Address("ccdeac59d35627b7de09332e819d5159e7bb7250");
string pretty(h160 _a, eth::State _st)
string pretty(h160 _a, dev::eth::State _st)
{
string ns;
h256 n;
@ -176,15 +172,17 @@ int main(int argc, char** argv)
string remoteHost;
unsigned short remotePort = 30303;
string dbPath;
eth::uint mining = ~(eth::uint)0;
unsigned mining = ~(unsigned)0;
NodeMode mode = NodeMode::Full;
unsigned peers = 5;
bool interactive = false;
#if ETH_JSONRPC
int jsonrpc = 8080;
int jsonrpc = -1;
#endif
string publicIP;
bool bootstrap = false;
bool upnp = true;
bool useLocal = false;
bool forceMining = false;
string clientName;
@ -230,10 +228,12 @@ int main(int argc, char** argv)
upnp = false;
else
{
cerr << "Invalid UPnP option: " << m << endl;
cerr << "Invalid -n/--upnp option: " << m << endl;
return -1;
}
}
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
@ -246,24 +246,26 @@ int main(int argc, char** argv)
{
string m = argv[++i];
if (isTrue(m))
mining = ~(eth::uint)0;
mining = ~(unsigned)0;
else if (isFalse(m))
mining = 0;
else if (int i = stoi(m))
mining = i;
else
{
cerr << "Unknown mining option: " << m << endl;
cerr << "Unknown -m/--mining option: " << m << endl;
return -1;
}
}
else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true;
else if (arg == "-f" || arg == "--force-mining")
forceMining = true;
else if (arg == "-i" || arg == "--interactive")
interactive = true;
#if ETH_JSONRPC
else if ((arg == "-j" || arg == "--json-rpc"))
jsonrpc = jsonrpc ? jsonrpc : 8080;
jsonrpc = jsonrpc == -1 ? 8080 : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]);
#endif
@ -295,22 +297,38 @@ int main(int argc, char** argv)
if (!clientName.empty())
clientName += "/";
Client c("Ethereum(++)/" + clientName + "v" + eth::EthVersion + "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath);
c.setForceMining(true);
cout << credits();
c.setForceMining(forceMining);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
dev::WebThreeDirect web3(
"Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM),
dbPath,
false,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs
);
web3.setIdealPeerCount(peers);
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
if (c)
{
c->setForceMining(forceMining);
c->setAddress(coinbase);
}
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
#if ETH_JSONRPC
auto_ptr<EthStubServer> jsonrpcServer;
if (jsonrpc > -1)
{
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c));
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening();
}
@ -348,34 +366,34 @@ int main(int argc, char** argv)
iss >> cmd;
if (cmd == "netstart")
{
eth::uint port;
iss >> port;
c.startNetwork((short)port);
iss >> netPrefs.listenPort;
web3.setNetworkPreferences(netPrefs);
web3.startNetwork();
}
else if (cmd == "connect")
{
string addr;
eth::uint port;
unsigned port;
iss >> addr >> port;
c.connect(addr, (short)port);
web3.connect(addr, (short)port);
}
else if (cmd == "netstop")
{
c.stopNetwork();
web3.stopNetwork();
}
else if (cmd == "minestart")
else if (c && cmd == "minestart")
{
c.startMining();
c->startMining();
}
else if (cmd == "minestop")
else if (c && cmd == "minestop")
{
c.stopMining();
c->stopMining();
}
else if (cmd == "mineforce")
else if (c && cmd == "mineforce")
{
string enable;
iss >> enable;
c.setForceMining(isTrue(enable));
c->setForceMining(isTrue(enable));
}
else if (cmd == "verbosity")
{
@ -394,7 +412,7 @@ int main(int argc, char** argv)
{
if (jsonrpc < 0)
jsonrpc = 8080;
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c));
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), web3));
jsonrpcServer->setKeys({us});
jsonrpcServer->StartListening();
}
@ -415,24 +433,24 @@ int main(int argc, char** argv)
{
cout << "Secret Key: " << toHex(us.secret().asArray()) << endl;
}
else if (cmd == "block")
else if (c && cmd == "block")
{
cout << "Current block: " << c.blockChain().details().number << endl;
cout << "Current block: " <<c->blockChain().details().number << endl;
}
else if (cmd == "peers")
{
for (auto it: c.peers())
for (auto it: web3.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl;
}
else if (cmd == "balance")
else if (c && cmd == "balance")
{
cout << "Current balance: " << formatBalance(c.balanceAt(us.address())) << " = " << c.balanceAt(us.address()) << " wei" << endl;
cout << "Current balance: " << formatBalance( c->balanceAt(us.address())) << " = " <<c->balanceAt(us.address()) << " wei" << endl;
}
else if (cmd == "transact")
else if (c && cmd == "transact")
{
auto const& bc = c.blockChain();
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
@ -449,7 +467,7 @@ int main(int argc, char** argv)
cnote << "Data:";
cnote << sdata;
bytes data = eth::parseData(sdata);
bytes data = dev::eth::parseData(sdata);
cnote << "Bytes:";
string sbd = asString(data);
bytes bbd = asBytes(sbd);
@ -477,35 +495,35 @@ int main(int argc, char** argv)
{
Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(hexAddr));
c.transact(secret, amount, dest, data, gas, gasPrice);
c->transact(secret, amount, dest, data, gas, gasPrice);
}
}
else
cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
else if (cmd == "listContracts")
else if (c && cmd == "listContracts")
{
auto acs = c.addresses();
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
if (c.codeAt(i, 0).size())
if ( c->codeAt(i, 0).size())
{
ss = toString(i) + " : " + toString(c.balanceAt(i)) + " [" + toString((unsigned)c.countAt(i)) + "]";
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
}
}
else if (cmd == "listAccounts")
else if (c && cmd == "listAccounts")
{
auto acs = c.addresses();
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
if (c.codeAt(i, 0).empty())
if ( c->codeAt(i, 0).empty())
{
ss = toString(i) + " : " + toString(c.balanceAt(i)) + " [" + toString((unsigned)c.countAt(i)) + "]";
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
}
}
else if (cmd == "send")
else if (c && cmd == "send")
{
if (iss.peek() != -1)
{
@ -521,21 +539,21 @@ int main(int argc, char** argv)
}
else
{
auto const& bc = c.blockChain();
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
u256 minGas = (u256)Client::txGas(0, 0);
Address dest = h160(fromHex(hexAddr));
c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice);
c->transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice);
}
}
else
cwarn << "Require parameters: send ADDRESS AMOUNT";
}
else if (cmd == "contract")
else if (c && cmd == "contract")
{
auto const& bc = c.blockChain();
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
@ -572,12 +590,12 @@ int main(int argc, char** argv)
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
c.transact(us.secret(), endowment, init, gas, gasPrice);
c->transact(us.secret(), endowment, init, gas, gasPrice);
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
}
else if (cmd == "dumptrace")
else if (c && cmd == "dumptrace")
{
unsigned block;
unsigned index;
@ -587,7 +605,7 @@ int main(int argc, char** argv)
ofstream f;
f.open(filename);
eth::State state = c.state(index + 1, c.blockChain().numberHash(block));
dev::eth::State state =c->state(index + 1,c->blockChain().numberHash(block));
if (index < state.pending().size())
{
Executive e(state);
@ -600,39 +618,39 @@ int main(int argc, char** argv)
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM)
{
eth::VM* vm = (VM*)vvm;
eth::ExtVM const* ext = (ExtVM const*)vextVM;
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
f << endl << " STACK" << endl;
for (auto i: vm->stack())
f << (h256)i << endl;
f << " MEMORY" << endl << eth::memDump(vm->memory());
f << " MEMORY" << endl << dev::memDump(vm->memory());
f << " STORAGE" << endl;
for (auto const& i: ext->state().storage(ext->myAddress))
f << showbase << hex << i.first << ": " << i.second << endl;
f << dec << ext->level << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
f << dec << ext->level << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
};
else if (format == "standard")
oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
{
eth::VM* vm = (VM*)vvm;
eth::ExtVM const* ext = (ExtVM const*)vextVM;
f << ext->myAddress << " " << hex << toHex(eth::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(eth::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(eth::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
else if (format == "standard+")
oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
{
eth::VM* vm = (VM*)vvm;
eth::ExtVM const* ext = (ExtVM const*)vextVM;
dev::eth::VM* vm = (VM*)vvm;
dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
for (auto const& i: ext->state().storage(ext->myAddress))
f << toHex(eth::toCompactBigEndian(i.first, 1)) << " " << toHex(eth::toCompactBigEndian(i.second, 1)) << endl;
f << ext->myAddress << " " << hex << toHex(eth::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(eth::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(eth::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
e.go(oof);
e.finalize(oof);
}
}
else if (cmd == "inspect")
else if (c && cmd == "inspect")
{
string rechex;
iss >> rechex;
@ -646,10 +664,10 @@ int main(int argc, char** argv)
try
{
auto storage = c.storageAt(h, 0);
auto storage =c->storageAt(h, 0);
for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble(c.codeAt(h, 0)) << endl;
s << endl << disassemble( c->codeAt(h, 0)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs;
@ -659,7 +677,7 @@ int main(int argc, char** argv)
cnote << "Saved" << rechex << "to" << outFile;
}
catch (eth::InvalidTrie)
catch (dev::eth::InvalidTrie)
{
cwarn << "Corrupted trie.";
}
@ -734,19 +752,21 @@ int main(int argc, char** argv)
jsonrpcServer->StopListening();
#endif
}
else
else if (c)
{
eth::uint n = c.blockChain().details().number;
unsigned n =c->blockChain().details().number;
if (mining)
c.startMining();
c->startMining();
while (true)
{
if (c.blockChain().details().number - n == mining)
c.stopMining();
if ( c->isMining() &&c->blockChain().details().number - n == mining)
c->stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
}
else
while (true)
this_thread::sleep_for(chrono::milliseconds(1000));
return 0;
}

1
exp/CMakeLists.txt

@ -9,6 +9,7 @@ set(EXECUTABLE exp)
add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} p2p)
target_link_libraries(${EXECUTABLE} gmp)
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS})
if(MINIUPNPC_LS)

330
exp/main.cpp

@ -19,277 +19,97 @@
* @date 2014
* Ethereum client.
*/
#if 0
#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <libethential/Log.h>
#include <libethential/Common.h>
#include <libethential/CommonData.h>
#include <libevm/VM.h>
#include "BuildInfo.h"
#include <functional>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h>
#include <libp2p/All.h>
#include <libdevcore/RangeMask.h>
#include <libethereum/DownloadMan.h>
#include <libwhisper/WhisperPeer.h>
using namespace std;
using namespace eth;
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
namespace sp = boost::spirit;
#if 0
class ASTSymbol: public string
{
public:
ASTSymbol() {}
};
enum class ASTType
{
Symbol,
IntegerLiteral,
StringLiteral,
Call,
Return,
Operator,
Compound
};
class ASTNode: public vector<ASTNode>
{
public:
ASTNode() {}
ASTNode(ASTSymbol const& _s): m_type(ASTType::Symbol), m_s(_s) {}
ASTNode(string const& _s): m_type(ASTType::StringLiteral), m_s(_s) {}
ASTNode(bigint const& _i): m_type(ASTType::IntegerLiteral), m_i(_i) {}
ASTNode(ASTType _t): m_type(_t) {}
ASTNode& operator=(ASTSymbol const& _s) { m_type = ASTType::Symbol; m_s = _s; return *this; }
ASTNode& operator=(string const& _s) { m_type = ASTType::StringLiteral; m_s = _s; return *this; }
ASTNode& operator=(bigint const& _i) { m_type = ASTType::IntegerLiteral; m_i = _i; return *this; }
ASTNode& operator=(ASTType const& _s) { m_type = _s; return *this; }
void debugOut(ostream& _out) const;
private:
ASTType m_type;
string m_s;
bigint m_i;
};
void parseTree(string const& _s, ASTNode& o_out)
{
using qi::standard::space;
using qi::standard::space_type;
typedef string::const_iterator it;
/* static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;*/
qi::rule<it, space_type, ASTNode()> element;
qi::rule<it, space_type, ASTNode()> call;
qi::rule<it, string()> str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"';
qi::rule<it, ASTSymbol()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
/* qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
qi::rule<it, bigint()> integer = intstr;
qi::rule<it, bigint()> multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether];
qi::rule<it, space_type, bigint()> quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1];
qi::rule<it, space_type, sp::utree()> atom = quantity[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, sp::utree::list_type()> seq = '{' > *element > '}';
qi::rule<it, space_type, sp::utree::list_type()> mload = '@' > element;
qi::rule<it, space_type, sp::utree::list_type()> sload = qi::lit("@@") > element;
qi::rule<it, space_type, sp::utree::list_type()> mstore = '[' > element > ']' > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> calldataload = qi::lit("$") > element;
qi::rule<it, space_type, sp::utree::list_type()> list = '(' > *element > ')';
qi::rule<it, space_type, sp::utree()> extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | seq[tagNode<5>()] | calldataload[tagNode<6>()];*/
qi::rule<it, space_type, ASTNode()> value = call[qi::_val = ASTType::Call] | str[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, ASTNode()> compound = '{' > *element > '}';
call = '(' > *value > ')'; //symbol > '(' > !(value > *(',' > value)) > ')';
element = compound[qi::_val = ASTType::Compound] | value[qi::_val = qi::_1];
auto ret = _s.cbegin();
qi::phrase_parse(ret, _s.cend(), element, space, qi::skip_flag::dont_postskip, o_out);
for (auto i = ret; i != _s.cend(); ++i)
if (!isspace(*i))
throw std::exception();
}
using namespace dev;
using namespace dev::eth;
using namespace dev::p2p;
using namespace dev::shh;
void ASTNode::debugOut(ostream& _out) const
int main()
{
switch (m_type)
{
case ASTType::StringLiteral:
_out << "\"" << m_s << "\"";
break;
case ASTType::Symbol:
_out << m_s;
break;
case ASTType::Compound:
{
unsigned n = 0;
_out << "{";
for (auto const& i: *this)
{
i.debugOut(_out);
_out << ";";
++n;
}
_out << "}";
break;
}
case ASTType::Call:
{
unsigned n = 0;
for (auto const& i: *this)
{
i.debugOut(_out);
if (n == 0)
_out << "(";
else if (n < size() - 1)
_out << ",";
if (n == size() - 1)
_out << ")";
++n;
}
break;
}
default:
_out << "nil";
}
}
int main(int, char**)
{
ASTNode out;
parseTree("{x}", out);
out.debugOut(cout);
cout << endl;
DownloadMan man;
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)}));
cnote << s0.nextFetch(2);
cnote << s1.nextFetch(2);
cnote << s2.nextFetch(2);
s0.noteBlock(u256(0));
s0.doneFetch();
cnote << s0.nextFetch(2);
s1.noteBlock(u256(2));
s1.noteBlock(u256(3));
s1.doneFetch();
cnote << s1.nextFetch(2);
s0.doneFetch();
cnote << s0.nextFetch(2);
/* RangeMask<unsigned> m(0, 100);
cnote << m;
m += UnsignedRange(3, 10);
cnote << m;
m += UnsignedRange(11, 16);
cnote << m;
m += UnsignedRange(10, 11);
cnote << m;
cnote << ~m;
cnote << (~m).lowest(10);
for (auto i: (~m).lowest(10))
cnote << i;*/
return 0;
}
#endif
void killBigints(sp::utree const& _this)
/*
int main(int argc, char** argv)
{
switch (_this.which())
{
case sp::utree_type::list_type: for (auto const& i: _this) killBigints(i); break;
case sp::utree_type::any_type: delete _this.get<bigint*>(); break;
default:;
}
}
g_logVerbosity = 20;
void debugOutAST(ostream& _out, sp::utree const& _this)
{
switch (_this.which())
{
case sp::utree_type::list_type:
switch (_this.tag())
{
case 0: { int n = 0; for (auto const& i: _this) { debugOutAST(_out, i); if (n++) _out << ", "; } break; }
case 1: _out << "@ "; debugOutAST(_out, _this.front()); break;
case 2: _out << "@@ "; debugOutAST(_out, _this.front()); break;
case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break;
case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break;
case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break;
case 6: _out << "$ "; debugOutAST(_out, _this.front()); break;
default:
{ _out << _this.tag() << ": "; int n = 0; for (auto const& i: _this) { debugOutAST(_out, i); if (n++) _out << ", "; } break; }
}
short listenPort = 30303;
string remoteHost;
short remotePort = 30303;
break;
case sp::utree_type::int_type: _out << _this.get<int>(); break;
case sp::utree_type::string_type: _out << "\"" << _this.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>() << "\""; break;
case sp::utree_type::symbol_type: _out << _this.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>(); break;
case sp::utree_type::any_type: _out << *_this.get<bigint*>(); break;
default: _out << "nil";
}
}
namespace eth {
namespace parseTreeLLL_ {
template<unsigned N>
struct tagNode
{
void operator()(sp::utree& n, qi::rule<string::const_iterator, qi::ascii::space_type, sp::utree()>::context_type& c) const
for (int i = 1; i < argc; ++i)
{
(boost::fusion::at_c<0>(c.attributes) = n).tag(N);
string arg = argv[i];
if (arg == "-l" && i + 1 < argc)
listenPort = (short)atoi(argv[++i]);
else if (arg == "-r" && i + 1 < argc)
remoteHost = argv[++i];
else if (arg == "-p" && i + 1 < argc)
remotePort = (short)atoi(argv[++i]);
else
remoteHost = argv[i];
}
};
}}
Host ph("Test", NetworkPreferences(listenPort, "", false, true));
ph.registerCapability(new WhisperHost());
auto wh = ph.cap<WhisperHost>();
void parseTree(string const& _s, sp::utree& o_out)
{
using qi::standard::space;
using qi::standard::space_type;
using eth::parseTreeLLL_::tagNode;
typedef sp::basic_string<std::string, sp::utree_type::symbol_type> symbol_type;
typedef string::const_iterator it;
ph.start();
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
#if 0
qi::rule<it, space_type, sp::utree()> element;
qi::rule<it, space_type, sp::utree()> statement;
qi::rule<it, string()> str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"';
qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))];
qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
qi::rule<it, bigint()> integer = intstr;
qi::rule<it, bigint()> multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether];
qi::rule<it, space_type, bigint()> quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1];
qi::rule<it, space_type, sp::utree()> atom = quantity[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, sp::utree::list_type()> compound = '{' > *statement > '}';
/* qi::rule<it, space_type, sp::utree::list_type()> mload = '@' > element;
qi::rule<it, space_type, sp::utree::list_type()> sload = qi::lit("@@") > element;
qi::rule<it, space_type, sp::utree::list_type()> mstore = '[' > element > ']' > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> calldataload = qi::lit("$") > element;*/
// qi::rule<it, space_type, sp::utree::list_type()> args = '(' > (element % ',') > ')';
if (!remoteHost.empty())
ph.connect(remoteHost, remotePort);
qi::rule<it, space_type, sp::utree::list_type()> expression;
qi::rule<it, space_type, sp::utree()> group = '(' >> expression[qi::_val = qi::_1] >> ')';
qi::rule<it, space_type, sp::utree()> factor = atom | group;
qi::rule<it, space_type, sp::utree()> mul = '*' >> factor;
qi::rule<it, space_type, sp::utree()> div = '/' >> factor;
qi::rule<it, space_type, sp::utree()> op = mul[tagNode<10>()] | div[tagNode<11>()];
qi::rule<it, space_type, sp::utree::list_type()> term = factor >> !op;
expression = term >> !(('+' >> term) | ('-' >> term));
/// Only interested in the packet if the lowest bit is 1
auto w = wh->installWatch(MessageFilter(std::vector<std::pair<bytes, bytes> >({{fromHex("0000000000000000000000000000000000000000000000000000000000000001"), fromHex("0000000000000000000000000000000000000000000000000000000000000001")}})));
// qi::rule<it, space_type, sp::utree()> extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | calldataload[tagNode<6>()];
statement = compound[tagNode<5>()] | (element > ';')[qi::_val = qi::_1];
element %= expression;// | extra;
#endif
qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
qi::rule<it, bigint()> integer = intstr;
qi::rule<it, sp::utree()> intnode = integer[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))];
qi::rule<it, space_type, sp::utree()> funcname = symbol;
qi::rule<it, space_type, sp::utree()> statement;
qi::rule<it, space_type, sp::utree::list_type()> call = funcname > '(' > funcname > ')';
statement = call | intnode | symbol;
auto ret = _s.cbegin();
qi::phrase_parse(ret, _s.cend(), statement, space, qi::skip_flag::dont_postskip, o_out);
for (auto i = ret; i != _s.cend(); ++i)
if (!isspace(*i))
throw std::exception();
}
#endif
int main(int, char**)
{
#if 0
sp::utree out;
parseTree("x(2)", out);
debugOutAST(cout, out);
killBigints(out);
cout << endl;
#endif
for (int i = 0; ; ++i)
{
wh->sendRaw(h256(u256(i * i)).asBytes(), h256(u256(i)).asBytes(), 1000);
for (auto i: wh->checkWatch(w))
cnote << "New message:" << (u256)h256(wh->message(i).payload);
}
return 0;
}
*/

0
libethential/All.h → libdevcore/All.h

4
libethential/CMakeLists.txt → libdevcore/CMakeLists.txt

@ -8,7 +8,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
set(EXECUTABLE ethential)
set(EXECUTABLE devcore)
# set(CMAKE_INSTALL_PREFIX ../lib)
if(ETH_STATIC)
@ -20,7 +20,7 @@ file(GLOB HEADERS "*.h")
include_directories(..)
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} devcore)
if("${TARGET_PLATFORM}" STREQUAL "w64")
include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)

7
libethential/Common.cpp → libdevcore/Common.cpp

@ -22,11 +22,12 @@
#include "Common.h"
using namespace std;
using namespace eth;
using namespace dev;
namespace eth
namespace dev
{
char const* EthVersion = "0.6.6";
char const* Version = "0.6.11";
}

19
libethential/Common.h → libdevcore/Common.h

@ -23,7 +23,7 @@
#pragma once
// way to many uint to size_t warnings in 32 bit build
// way to many unsigned to size_t warnings in 32 bit build
#ifdef _M_IX86
#pragma warning(disable:4244)
#endif
@ -43,13 +43,13 @@
using byte = uint8_t;
// Quote a given token stream to turn it into a string.
#define ETH_QUOTED_HELPER(s) #s
#define ETH_QUOTED(s) ETH_QUOTED_HELPER(s)
#define DEV_QUOTED_HELPER(s) #s
#define DEV_QUOTED(s) DEV_QUOTED_HELPER(s)
namespace eth
namespace dev
{
extern char const* EthVersion;
extern char const* Version;
// Binary data types.
using bytes = std::vector<byte>;
@ -62,8 +62,6 @@ using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backe
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using uint = uint64_t;
using sint = int64_t;
using u256s = std::vector<u256>;
using u160s = std::vector<u160>;
using u256Set = std::set<u256>;
@ -98,4 +96,11 @@ inline u256 s2u(s256 _u)
return (u256)(c_end + _u);
}
inline unsigned int toLog2(u256 _x)
{
unsigned ret;
for (ret = 0; _x >>= 1; ++ret) {}
return ret;
}
}

282
libdevcore/CommonData.cpp

@ -0,0 +1,282 @@
/*
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 Common.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "CommonData.h"
#include <random>
#include "Exceptions.h"
using namespace std;
using namespace dev;
std::string dev::escaped(std::string const& _s, bool _all)
{
std::string ret;
ret.reserve(_s.size());
ret.push_back('"');
for (auto i: _s)
if (i == '"' && !_all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (i < ' ' || _all)
{
ret += "\\x";
ret.push_back("0123456789abcdef"[(uint8_t)i / 16]);
ret.push_back("0123456789abcdef"[(uint8_t)i % 16]);
}
else
ret.push_back(i);
ret.push_back('"');
return ret;
}
std::string dev::randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(std::uniform_int_distribution<int>(1, 5)(s_eng), ' ');
char const n[] = "qwertyuiop";//asdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
std::uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
int dev::fromHex(char _i)
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
throw BadHexCharacter();
}
bytes dev::fromHex(std::string const& _s)
{
unsigned s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s + 1) / 2);
if (_s.size() % 2)
try
{
ret.push_back(fromHex(_s[s++]));
}
catch (...){ ret.push_back(0); }
for (unsigned i = s; i < _s.size(); i += 2)
try
{
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
}
catch (...){ ret.push_back(0); }
return ret;
}
bytes dev::asNibbles(std::string const& _s)
{
std::vector<uint8_t> ret;
ret.reserve(_s.size() * 2);
for (auto i: _s)
{
ret.push_back(i / 16);
ret.push_back(i % 16);
}
return ret;
}
#if 0
/* Following code is copyright 2012-2014 Luke Dashjr
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details.
*/
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#include <cstring>
static const int8_t b58digits_map[] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
{
size_t binsz = *binszp;
const unsigned char *b58u = (void*)b58;
unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
unsigned zerocount = 0;
if (!b58sz)
b58sz = strlen(b58);
memset(outi, 0, outisz * sizeof(*outi));
// Leading zeros, just count
for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i)
++zerocount;
for ( ; i < b58sz; ++i)
{
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits_map[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
}
for (; j < outisz; ++j)
{
*(binu++) = (outi[j] >> 0x18) & 0xff;
*(binu++) = (outi[j] >> 0x10) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff;
*(binu++) = (outi[j] >> 0) & 0xff;
}
// Count canonical base58 byte count
binu = bin;
for (i = 0; i < binsz; ++i)
{
if (binu[i])
break;
--*binszp;
}
*binszp += zerocount;
return true;
}
static
bool my_dblsha256(void *hash, const void *data, size_t datasz)
{
uint8_t buf[0x20];
return b58_sha256_impl(buf, data, datasz) && b58_sha256_impl(hash, buf, sizeof(buf));
}
int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz)
{
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4)
return -4;
if (!my_dblsha256(buf, bin, binsz - 4))
return -2;
if (memcmp(&binc[binsz - 4], buf, 4))
return -1;
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
{} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1')
return -3;
return binc[0];
}
static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
const uint8_t *bin = data;
int carry;
size_t i, j, high, zcount = 0;
size_t size;
while (zcount < binsz && !bin[zcount])
++zcount;
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t buf[size];
memset(buf, 0, size);
for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
{
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
{
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
}
}
for (j = 0; j < size && !buf[j]; ++j);
if (*b58sz <= zcount + size - j)
{
*b58sz = zcount + size - j + 1;
return false;
}
if (zcount)
memset(b58, '1', zcount);
for (i = zcount; j < size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
return true;
}
#endif

23
libethential/CommonData.h → libdevcore/CommonData.h

@ -30,7 +30,7 @@
#include <string>
#include "Common.h"
namespace eth
namespace dev
{
// String conversion functions, mainly to/from hex/nibble/byte representations.
@ -55,6 +55,11 @@ int fromHex(char _i);
/// @example fromHex("41626261") == asBytes("Abba")
bytes fromHex(std::string const& _s);
#if 0
std::string toBase58(bytesConstRef _data);
bytes fromBase58(std::string const& _s);
#endif
/// Converts byte array to a string containing the same (binary) data. Unless
/// the byte array happens to contain ASCII data, this won't be printable.
inline std::string asString(bytes const& _b)
@ -79,7 +84,7 @@ bytes asNibbles(std::string const& _s);
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out.
/// @a _Out will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
/// @a _T will typically by unsigned, u160, u256 or bigint.
template <class _T, class _Out>
inline void toBigEndian(_T _val, _Out& o_out)
{
@ -89,7 +94,7 @@ inline void toBigEndian(_T _val, _Out& o_out)
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
/// @a _In will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
/// @a _T will typically by unsigned, u160, u256 or bigint.
template <class _T, class _In>
inline _T fromBigEndian(_In const& _bytes)
{
@ -140,10 +145,10 @@ std::string escaped(std::string const& _s, bool _all = true);
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5
template <class _T, class _U>
uint commonPrefix(_T const& _t, _U const& _u)
unsigned commonPrefix(_T const& _t, _U const& _u)
{
uint s = std::min<uint>(_t.size(), _u.size());
for (uint i = 0;; ++i)
unsigned s = std::min<unsigned>(_t.size(), _u.size());
for (unsigned i = 0;; ++i)
if (i == s || _t[i] != _u[i])
return i;
return s;
@ -157,9 +162,9 @@ std::string randomWord();
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class _T>
inline uint bytesRequired(_T _i)
inline unsigned bytesRequired(_T _i)
{
uint i = 0;
unsigned i = 0;
for (; _i != 0; ++i, _i >>= 8) {}
return i;
}
@ -167,7 +172,7 @@ inline uint bytesRequired(_T _i)
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
template <class _T>
void trimFront(_T& _t, uint _elements)
void trimFront(_T& _t, unsigned _elements)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));

10
libethential/CommonIO.cpp → libdevcore/CommonIO.cpp

@ -24,9 +24,9 @@
#include <fstream>
#include "Exceptions.h"
using namespace std;
using namespace eth;
using namespace dev;
string eth::memDump(bytes const& _b, unsigned _w, bool _html)
string dev::memDump(bytes const& _b, unsigned _w, bool _html)
{
stringstream ret;
if (_html)
@ -36,7 +36,7 @@ string eth::memDump(bytes const& _b, unsigned _w, bool _html)
ret << hex << setw(4) << setfill('0') << i << " ";
for (unsigned j = i; j < i + _w; ++j)
if (j < _b.size())
if (_b[j] >= 32 && _b[j] < 128)
if (_b[j] >= 32 && _b[j] < 127)
if ((char)_b[j] == '<' && _html)
ret << "&lt;";
else if ((char)_b[j] == '&' && _html)
@ -57,7 +57,7 @@ string eth::memDump(bytes const& _b, unsigned _w, bool _html)
return ret.str();
}
bytes eth::contents(std::string const& _file)
bytes dev::contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
if (!is)
@ -72,7 +72,7 @@ bytes eth::contents(std::string const& _file)
return ret;
}
void eth::writeFile(std::string const& _file, bytes const& _data)
void dev::writeFile(std::string const& _file, bytes const& _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}

22
libethential/CommonIO.h → libdevcore/CommonIO.h

@ -37,7 +37,7 @@
#include <iostream>
#include "Common.h"
namespace eth
namespace dev
{
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
@ -49,15 +49,6 @@ void writeFile(std::string const& _file, bytes const& _data);
/// Nicely renders the given bytes to a string, optionally as HTML.
std::string memDump(bytes const& _b, unsigned _w = 8, bool _html = false);
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
{
std::ostringstream o;
o << _t;
return o.str();
}
// Stream I/O functions.
// Provides templated stream I/O for all STL collections so they can be shifted on to any iostream-like interface.
@ -223,4 +214,15 @@ template <class T, class U> inline std::ostream& operator<<(std::ostream& _out,
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p) { if (_p) _out << "@" << (*_p); else _out << "nullptr"; return _out; }
// Functions that use streaming stuff.
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
{
std::ostringstream o;
o << _t;
return o.str();
}
}

2
libethential/Exceptions.h → libdevcore/Exceptions.h

@ -26,7 +26,7 @@
#include "CommonData.h"
#include "FixedHash.h"
namespace eth
namespace dev
{
class Exception: public std::exception

4
libethential/FixedHash.cpp → libdevcore/FixedHash.cpp

@ -23,6 +23,6 @@
#include "FixedHash.h"
using namespace std;
using namespace eth;
using namespace dev;
std::mt19937_64 eth::s_fixedHashEngine(time(0));
std::mt19937_64 dev::s_fixedHashEngine(time(0));

24
libethential/FixedHash.h → libdevcore/FixedHash.h

@ -28,7 +28,7 @@
#include <algorithm>
#include "CommonData.h"
namespace eth
namespace dev
{
extern std::mt19937_64 s_fixedHashEngine;
@ -65,13 +65,13 @@ public:
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
/// Explicitly construct, copying from a byte array.
explicit FixedHash(bytes const& _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<uint>(_b.size(), N)); }
explicit FixedHash(bytes const& _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); }
/// Explicitly construct, copying from a bytes in memory with given pointer.
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): FixedHash(_t == FromHex ? fromHex(_s) : eth::asBytes(_s)) {}
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex): FixedHash(_t == FromHex ? fromHex(_s) : dev::asBytes(_s)) {}
/// Convert to arithmetic type.
operator Arith() const { return fromBigEndian<Arith>(m_data); }
@ -127,7 +127,7 @@ public:
/// @returns a randomly-valued hash
template <class Engine>
static FixedHash random(Engine& _eng = s_fixedHashEngine)
static FixedHash random(Engine& _eng)
{
FixedHash ret;
for (auto& i: ret.m_data)
@ -135,6 +135,8 @@ public:
return ret;
}
static FixedHash random() { return random(s_fixedHashEngine); }
/// A generic std::hash compatible function object.
struct hash
{
@ -215,10 +217,20 @@ inline h160 left160(h256 const& _t)
return ret;
}
inline std::string toString(h256s const& _bs)
{
std::ostringstream out;
out << "[ ";
for (auto i: _bs)
out << i.abridged() << ", ";
out << "]";
return out.str();
}
}
namespace std
{
/// Forward std::hash<eth::h256> to eth::h256::hash.
template<> struct hash<eth::h256>: eth::h256::hash {};
/// Forward std::hash<dev::h256> to dev::h256::hash.
template<> struct hash<dev::h256>: dev::h256::hash {};
}

4
libethential/Guards.cpp → libdevcore/Guards.cpp

@ -21,9 +21,9 @@
#include "Guards.h"
using namespace std;
using namespace eth;
using namespace dev;
namespace eth
namespace dev
{
}

2
libethential/Guards.h → libdevcore/Guards.h

@ -24,7 +24,7 @@
#include <mutex>
#include <boost/thread.hpp>
namespace eth
namespace dev
{
using Mutex = std::mutex;

16
libethential/Log.cpp → libdevcore/Log.cpp

@ -23,22 +23,26 @@
#include <string>
#include <iostream>
#include "Guards.h"
using namespace std;
using namespace eth;
using namespace dev;
// Logging
int eth::g_logVerbosity = 5;
map<type_info const*, bool> eth::g_logOverride;
int dev::g_logVerbosity = 5;
map<type_info const*, bool> dev::g_logOverride;
ThreadLocalLogName eth::t_logThreadName("main");
ThreadLocalLogName dev::t_logThreadName("main");
// foward declare without all of Windows.h
#ifdef _WIN32
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
#endif
void eth::simpleDebugOut(std::string const& _s, char const*)
void dev::simpleDebugOut(std::string const& _s, char const*)
{
static Mutex s_lock;
Guard l(s_lock);
cout << _s << endl << flush;
// helpful to use OutputDebugString on windows
@ -50,5 +54,5 @@ void eth::simpleDebugOut(std::string const& _s, char const*)
#endif
}
std::function<void(std::string const&, char const*)> eth::g_logPost = simpleDebugOut;
std::function<void(std::string const&, char const*)> dev::g_logPost = simpleDebugOut;

18
libethential/Log.h → libdevcore/Log.h

@ -28,7 +28,7 @@
#include <boost/thread.hpp>
#include "vector_ref.h"
namespace eth
namespace dev
{
/// The null output stream. Used when logging is disabled.
@ -107,19 +107,19 @@ private:
// Simple cout-like stream objects for accessing common log channels.
// Dirties the global namespace, but oh so convenient...
#define cnote eth::LogOutputStream<eth::NoteChannel, true>()
#define cwarn eth::LogOutputStream<eth::WarnChannel, true>()
#define cnote dev::LogOutputStream<dev::NoteChannel, true>()
#define cwarn dev::LogOutputStream<dev::WarnChannel, true>()
// Null stream-like objects.
#define ndebug if (true) {} else eth::NullOutputStream()
#define nlog(X) if (true) {} else eth::NullOutputStream()
#define nslog(X) if (true) {} else eth::NullOutputStream()
#define ndebug if (true) {} else dev::NullOutputStream()
#define nlog(X) if (true) {} else dev::NullOutputStream()
#define nslog(X) if (true) {} else dev::NullOutputStream()
// Kill debugging log channel when we're in release mode.
#if NDEBUG
#define cdebug ndebug
#else
#define cdebug eth::LogOutputStream<eth::DebugChannel, true>()
#define cdebug dev::LogOutputStream<dev::DebugChannel, true>()
#endif
// Kill all logs when when NLOG is defined.
@ -127,8 +127,8 @@ private:
#define clog(X) nlog(X)
#define cslog(X) nslog(X)
#else
#define clog(X) eth::LogOutputStream<X, true>()
#define cslog(X) eth::LogOutputStream<X, false>()
#define clog(X) dev::LogOutputStream<X, true>()
#define cslog(X) dev::LogOutputStream<X, false>()
#endif
}

42
libethential/RLP.cpp → libdevcore/RLP.cpp

@ -21,10 +21,10 @@
#include "RLP.h"
using namespace std;
using namespace eth;
using namespace dev;
bytes eth::RLPNull = rlp("");
bytes eth::RLPEmptyList = rlpList();
bytes dev::RLPNull = rlp("");
bytes dev::RLPEmptyList = rlpList();
RLP::iterator& RLP::iterator::operator++()
{
@ -32,7 +32,7 @@ RLP::iterator& RLP::iterator::operator++()
{
m_lastItem.retarget(m_lastItem.next().data(), m_remaining);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize());
m_remaining -= std::min<uint>(m_remaining, m_lastItem.size());
m_remaining -= std::min<unsigned>(m_remaining, m_lastItem.size());
}
else
m_lastItem.retarget(m_lastItem.next().data(), 0);
@ -54,7 +54,7 @@ RLP::iterator::iterator(RLP const& _parent, bool _begin)
}
}
RLP RLP::operator[](uint _i) const
RLP RLP::operator[](unsigned _i) const
{
if (_i < m_lastIndex)
{
@ -81,7 +81,7 @@ RLPs RLP::toList() const
return ret;
}
eth::uint RLP::actualSize() const
unsigned RLP::actualSize() const
{
if (isNull())
return 0;
@ -118,11 +118,11 @@ bool RLP::isInt() const
return false;
}
eth::uint RLP::length() const
unsigned RLP::length() const
{
if (isNull())
return 0;
uint ret = 0;
unsigned ret = 0;
byte n = m_data[0];
if (n < c_rlpDataImmLenStart)
return 1;
@ -147,12 +147,12 @@ eth::uint RLP::length() const
return ret;
}
eth::uint RLP::items() const
unsigned RLP::items() const
{
if (isList())
{
bytesConstRef d = payload().cropped(0, length());
eth::uint i = 0;
unsigned i = 0;
for (; d.size(); ++i)
d = d.cropped(RLP(d).actualSize());
return i;
@ -160,16 +160,16 @@ eth::uint RLP::items() const
return 0;
}
RLPStream& RLPStream::appendRaw(bytesConstRef _s, uint _itemCount)
RLPStream& RLPStream::appendRaw(bytesConstRef _s, unsigned _itemCount)
{
uint os = m_out.size();
unsigned os = m_out.size();
m_out.resize(os + _s.size());
memcpy(m_out.data() + os, _s.data(), _s.size());
noteAppended(_itemCount);
return *this;
}
void RLPStream::noteAppended(uint _itemCount)
void RLPStream::noteAppended(unsigned _itemCount)
{
if (!_itemCount)
return;
@ -184,9 +184,9 @@ void RLPStream::noteAppended(uint _itemCount)
{
auto p = m_listStack.back().second;
m_listStack.pop_back();
uint s = m_out.size() - p; // list size
unsigned s = m_out.size() - p; // list size
auto brs = bytesRequired(s);
uint encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs);
unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs);
// cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")";
auto os = m_out.size();
m_out.resize(os + encodeSize);
@ -205,7 +205,7 @@ void RLPStream::noteAppended(uint _itemCount)
}
}
RLPStream& RLPStream::appendList(uint _items)
RLPStream& RLPStream::appendList(unsigned _items)
{
// cdebug << "appendList(" << _items << ")";
if (_items)
@ -227,7 +227,7 @@ RLPStream& RLPStream::appendList(bytesConstRef _rlp)
RLPStream& RLPStream::append(bytesConstRef _s, bool _compact)
{
uint s = _s.size();
unsigned s = _s.size();
byte const* d = _s.data();
if (_compact)
for (unsigned i = 0; i < _s.size() && !*d; ++i, --s, ++d) {}
@ -254,7 +254,7 @@ RLPStream& RLPStream::append(bigint _i)
m_out.push_back((byte)_i);
else
{
uint br = bytesRequired(_i);
unsigned br = bytesRequired(_i);
if (br < c_rlpDataImmLenCount)
m_out.push_back((byte)(br + c_rlpDataImmLenStart));
else
@ -269,21 +269,21 @@ RLPStream& RLPStream::append(bigint _i)
return *this;
}
void RLPStream::pushCount(uint _count, byte _base)
void RLPStream::pushCount(unsigned _count, byte _base)
{
auto br = bytesRequired(_count);
m_out.push_back((byte)(br + _base)); // max 8 bytes.
pushInt(_count, br);
}
std::ostream& eth::operator<<(std::ostream& _out, eth::RLP const& _d)
std::ostream& dev::operator<<(std::ostream& _out, RLP const& _d)
{
if (_d.isNull())
_out << "null";
else if (_d.isInt())
_out << std::showbase << std::hex << std::nouppercase << _d.toInt<bigint>(RLP::LaisezFaire) << dec;
else if (_d.isData())
_out << eth::escaped(_d.toString(), false);
_out << escaped(_d.toString(), false);
else if (_d.isList())
{
_out << "[";

130
libethential/RLP.h → libdevcore/RLP.h

@ -28,21 +28,21 @@
#include <exception>
#include <iostream>
#include <iomanip>
#include <libethential/vector_ref.h>
#include <libethential/Common.h>
#include <libethential/Exceptions.h>
#include <libethential/FixedHash.h>
#include <libdevcore/vector_ref.h>
#include <libdevcore/Common.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/FixedHash.h>
namespace eth
namespace dev
{
class RLP;
typedef std::vector<RLP> RLPs;
template <class _T> struct intTraits { static const uint maxSize = sizeof(_T); };
template <> struct intTraits<u160> { static const uint maxSize = 20; };
template <> struct intTraits<u256> { static const uint maxSize = 32; };
template <> struct intTraits<bigint> { static const uint maxSize = ~(uint)0; };
template <class _T> struct intTraits { static const unsigned maxSize = sizeof(_T); };
template <> struct intTraits<u160> { static const unsigned maxSize = 20; };
template <> struct intTraits<u256> { static const unsigned maxSize = 32; };
template <> struct intTraits<bigint> { static const unsigned maxSize = ~(unsigned)0; };
static const byte c_rlpMaxLengthBytes = 8;
static const byte c_rlpDataImmLenStart = 0x80;
@ -72,7 +72,7 @@ public:
explicit RLP(bytes const& _d): m_data(&_d) {}
/// Construct a node to read RLP data in the bytes given.
RLP(byte const* _b, uint _s): m_data(bytesConstRef(_b, _s)) {}
RLP(byte const* _b, unsigned _s): m_data(bytesConstRef(_b, _s)) {}
/// Construct a node to read RLP data in the string.
explicit RLP(std::string const& _s): m_data(bytesConstRef((byte const*)_s.data(), _s.size())) {}
@ -99,12 +99,12 @@ public:
bool isInt() const;
/// @returns the number of items in the list, or zero if it isn't a list.
uint itemCount() const { return isList() ? items() : 0; }
uint itemCountStrict() const { if (!isList()) throw BadCast(); return items(); }
unsigned itemCount() const { return isList() ? items() : 0; }
unsigned itemCountStrict() const { if (!isList()) throw BadCast(); return items(); }
/// @returns the number of bytes in the data, or zero if it isn't data.
uint size() const { return isData() ? length() : 0; }
uint sizeStrict() const { if (!isData()) throw BadCast(); return length(); }
unsigned size() const { return isData() ? length() : 0; }
unsigned sizeStrict() const { if (!isData()) throw BadCast(); return length(); }
/// Equality operators; does best-effort conversion and checks for equality.
bool operator==(char const* _s) const { return isData() && toString() == _s; }
@ -113,8 +113,8 @@ public:
bool operator!=(std::string const& _s) const { return isData() && toString() != _s; }
template <unsigned _N> bool operator==(FixedHash<_N> const& _h) const { return isData() && toHash<_N>() == _h; }
template <unsigned _N> bool operator!=(FixedHash<_N> const& _s) const { return isData() && toHash<_N>() != _s; }
bool operator==(uint const& _i) const { return isInt() && toInt<uint>() == _i; }
bool operator!=(uint const& _i) const { return isInt() && toInt<uint>() != _i; }
bool operator==(unsigned const& _i) const { return isInt() && toInt<unsigned>() == _i; }
bool operator!=(unsigned const& _i) const { return isInt() && toInt<unsigned>() != _i; }
bool operator==(u256 const& _i) const { return isInt() && toInt<u256>() == _i; }
bool operator!=(u256 const& _i) const { return isInt() && toInt<u256>() != _i; }
bool operator==(bigint const& _i) const { return isInt() && toInt<bigint>() == _i; }
@ -123,7 +123,7 @@ public:
/// Subscript operator.
/// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise.
/// @note if used to access items in ascending order, this is efficient.
RLP operator[](uint _i) const;
RLP operator[](unsigned _i) const;
typedef RLP element_type;
@ -146,7 +146,7 @@ public:
iterator() {}
iterator(RLP const& _parent, bool _begin);
uint m_remaining = 0;
unsigned m_remaining = 0;
bytesConstRef m_lastItem;
};
@ -160,7 +160,6 @@ public:
explicit operator std::string() const { return toString(); }
explicit operator RLPs() const { return toList(); }
explicit operator byte() const { return toInt<byte>(); }
explicit operator uint() const { return toInt<uint>(); }
explicit operator u256() const { return toInt<u256>(); }
explicit operator bigint() const { return toInt<bigint>(); }
template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); }
@ -178,10 +177,59 @@ public:
/// Converts to string. @throws BadCast if not a string.
std::string toStringStrict() const { if (!isData()) throw BadCast(); return payload().cropped(0, length()).toString(); }
template <class T> std::vector<T> toVector() const { std::vector<T> ret; if (isList()) { ret.reserve(itemCount()); for (auto const& i: *this) ret.push_back((T)i); } return ret; }
template <class T> std::set<T> toSet() const { std::set<T> ret; if (isList()) { for (auto const& i: *this) ret.insert((T)i); } return ret; }
template <class T, class U> std::pair<T, U> toPair() const { std::pair<T, U> ret; if (isList()) { ret.first = (T)((*this)[0]); ret.second = (U)((*this)[1]); } return ret; }
template <class T, size_t N> std::array<T, N> toArray() const { if (itemCount() != N || !isList()) throw BadCast(); std::array<T, N> ret; for (uint i = 0; i < N; ++i) ret[i] = (T)operator[](i); return ret; }
template <class T>
std::vector<T> toVector() const
{
std::vector<T> ret;
if (isList())
{
ret.reserve(itemCount());
for (auto const& i: *this)
{
ret.push_back((T)i);
}
}
return ret;
}
template <class T>
std::set<T> toSet() const
{
std::set<T> ret;
if (isList())
{
for (auto const& i: *this)
{
ret.insert((T)i);
}
}
return ret;
}
template <class T, class U>
std::pair<T, U> toPair() const
{
std::pair<T, U> ret;
if (isList())
{
ret.first = (T)(*this)[0];
ret.second = (U)(*this)[1];
}
return ret;
}
template <class T, size_t N>
std::array<T, N> toArray() const
{
if (itemCount() != N || !isList())
throw BadCast();
std::array<T, N> ret;
for (unsigned i = 0; i < N; ++i)
{
ret[i] = (T)operator[](i);
}
return ret;
}
/// Int conversion flags
enum
@ -194,7 +242,7 @@ public:
};
/// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string.
template <class _T = uint> _T toInt(int _flags = Strict) const
template <class _T = unsigned> _T toInt(int _flags = Strict) const
{
if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull())
if (_flags & ThrowOnFail)
@ -237,27 +285,27 @@ public:
/// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
uint actualSize() const;
unsigned actualSize() const;
private:
/// Single-byte data payload.
bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; }
/// @returns the bytes used to encode the length of the data. Valid for all types.
uint lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; }
unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; }
/// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data.
uint length() const;
unsigned length() const;
/// @returns the number of data items.
uint items() const;
unsigned items() const;
/// Our byte data.
bytesConstRef m_data;
/// The list-indexing cache.
mutable uint m_lastIndex = (uint)-1;
mutable uint m_lastEnd = 0;
mutable unsigned m_lastIndex = (unsigned)-1;
mutable unsigned m_lastEnd = 0;
mutable bytesConstRef m_lastItem;
};
@ -271,12 +319,12 @@ public:
RLPStream() {}
/// Initializes the RLPStream as a list of @a _listItems items.
explicit RLPStream(uint _listItems) { appendList(_listItems); }
explicit RLPStream(unsigned _listItems) { appendList(_listItems); }
~RLPStream() {}
/// Append given datum to the byte stream.
RLPStream& append(uint _s) { return append(bigint(_s)); }
RLPStream& append(unsigned _s) { return append(bigint(_s)); }
RLPStream& append(u160 _s) { return append(bigint(_s)); }
RLPStream& append(u256 _s) { return append(bigint(_s)); }
RLPStream& append(bigint _s);
@ -287,7 +335,7 @@ public:
template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); }
/// Appends an arbitrary RLP fragment - this *must* be a single item.
RLPStream& append(RLP const& _rlp, uint _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }
RLPStream& append(RLP const& _rlp, unsigned _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }
/// Appends a sequence of data to the stream as a list.
template <class _T> RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); }
@ -297,14 +345,14 @@ public:
template <class T, class U> RLPStream& append(std::pair<T, U> const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; }
/// Appends a list.
RLPStream& appendList(uint _items);
RLPStream& appendList(unsigned _items);
RLPStream& appendList(bytesConstRef _rlp);
RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); }
RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); }
/// Appends raw (pre-serialised) RLP data. Use with caution.
RLPStream& appendRaw(bytesConstRef _rlp, uint _itemCount = 1);
RLPStream& appendRaw(bytes const& _rlp, uint _itemCount = 1) { return appendRaw(&_rlp, _itemCount); }
RLPStream& appendRaw(bytesConstRef _rlp, unsigned _itemCount = 1);
RLPStream& appendRaw(bytes const& _rlp, unsigned _itemCount = 1) { return appendRaw(&_rlp, _itemCount); }
/// Shift operators for appending data items.
template <class T> RLPStream& operator<<(T _data) { return append(_data); }
@ -319,14 +367,14 @@ public:
void swapOut(bytes& _dest) { assert(m_listStack.empty()); swap(m_out, _dest); }
private:
void noteAppended(uint _itemCount = 1);
void noteAppended(unsigned _itemCount = 1);
/// Push the node-type byte (using @a _base) along with the item count @a _count.
/// @arg _count is number of characters for strings, data-bytes for ints, or items for lists.
void pushCount(uint _count, byte _offset);
void pushCount(unsigned _count, byte _offset);
/// Push an integer as a raw big-endian byte-stream.
template <class _T> void pushInt(_T _i, uint _br)
template <class _T> void pushInt(_T _i, unsigned _br)
{
m_out.resize(m_out.size() + _br);
byte* b = &m_out.back();
@ -337,7 +385,7 @@ private:
/// Our output byte stream.
bytes m_out;
std::vector<std::pair<uint, uint>> m_listStack;
std::vector<std::pair<unsigned, unsigned>> m_listStack;
};
template <class _T> void rlpListAux(RLPStream& _out, _T _t) { _out << _t; }
@ -362,6 +410,6 @@ extern bytes RLPNull;
extern bytes RLPEmptyList;
/// Human readable version of RLP.
std::ostream& operator<<(std::ostream& _out, eth::RLP const& _d);
std::ostream& operator<<(std::ostream& _out, dev::RLP const& _d);
}

22
libdevcore/RangeMask.cpp

@ -0,0 +1,22 @@
/*
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 RangeMask.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "RangeMask.h"

212
libdevcore/RangeMask.h

@ -0,0 +1,212 @@
/*
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 EthereumHost.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <map>
#include <utility>
#include <vector>
#include <iostream>
namespace dev
{
class RLPStream;
using UnsignedRange = std::pair<unsigned, unsigned>;
using UnsignedRanges = std::vector<UnsignedRange>;
template <class T>
class RangeMask
{
template <class U> friend std::ostream& operator<<(std::ostream& _out, RangeMask<U> const& _r);
public:
using Range = std::pair<T, T>;
using Ranges = std::vector<Range>;
RangeMask() {}
RangeMask(T _begin, T _end): m_all(_begin, _end) {}
RangeMask(Range const& _c): m_all(_c) {}
RangeMask operator+(RangeMask const& _m) const { return RangeMask(*this) += _m; }
RangeMask lowest(T _items) const
{
RangeMask ret(m_all);
for (auto i = m_ranges.begin(); i != m_ranges.end() && _items; ++i)
_items -= (ret.m_ranges[i->first] = std::min(i->first + _items, i->second)) - i->first;
return ret;
}
RangeMask operator~() const
{
RangeMask ret(m_all);
T last = m_all.first;
for (auto i: m_ranges)
{
if (i.first != last)
ret.m_ranges[last] = i.first;
last = i.second;
}
if (last != m_all.second)
ret.m_ranges[last] = m_all.second;
return ret;
}
RangeMask& operator+=(RangeMask const& _m)
{
for (auto const& i: _m.m_ranges)
operator+=(i);
return *this;
}
RangeMask& operator+=(UnsignedRange const& _m)
{
for (auto i = _m.first; i < _m.second;)
{
// for each number, we find the element equal or next lower. this, if any, must contain the value.
auto uit = m_ranges.upper_bound(i);
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit);
if (it == m_ranges.end() || it->second < i)
// lower range is too low to merge.
// if the next higher range is too high.
if (uit == m_ranges.end() || uit->first > _m.second)
{
// just create a new range
m_ranges[i] = _m.second;
break;
}
else
{
if (uit->first == i)
// move i to end of range
i = uit->second;
else
{
// merge with the next higher range
// move i to end of range
i = m_ranges[i] = uit->second;
i = uit->second;
m_ranges.erase(uit);
}
}
else if (it->second == i)
{
// if the next higher range is too high.
if (uit == m_ranges.end() || uit->first > _m.second)
{
// merge with the next lower range
m_ranges[it->first] = _m.second;
break;
}
else
{
// merge with both next lower & next higher.
i = m_ranges[it->first] = uit->second;
m_ranges.erase(uit);
}
}
else
i = it->second;
}
return *this;
}
RangeMask& operator+=(T _i)
{
return operator+=(Range(_i, _i + 1));
}
bool contains(T _i) const
{
auto it = m_ranges.upper_bound(_i);
if (it == m_ranges.begin())
return false;
return (--it)->second > _i;
}
bool empty() const
{
return m_ranges.empty();
}
bool full() const
{
return m_ranges.size() == 1 && m_ranges.begin()->first == m_all.first && m_ranges.begin()->second == m_all.second;
}
void clear()
{
m_ranges.clear();
}
std::pair<T, T> const& all() const { return m_all; }
class const_iterator
{
friend class RangeMask;
public:
const_iterator() {}
T operator*() const { return m_value; }
const_iterator& operator++() { if (m_owner) m_value = m_owner->next(m_value); return *this; }
const_iterator operator++(int) { auto ret = *this; if (m_owner) m_value = m_owner->next(m_value); return ret; }
bool operator==(const_iterator const& _i) const { return m_owner == _i.m_owner && m_value == _i.m_value; }
bool operator!=(const_iterator const& _i) const { return !operator==(_i); }
bool operator<(const_iterator const& _i) const { return m_value < _i.m_value; }
private:
const_iterator(RangeMask const& _m, bool _end): m_owner(&_m), m_value(_m.m_ranges.empty() || _end ? _m.m_all.second : _m.m_ranges.begin()->first) {}
RangeMask const* m_owner = nullptr;
T m_value = 0;
};
const_iterator begin() const { return const_iterator(*this, false); }
const_iterator end() const { return const_iterator(*this, true); }
T next(T _t) const
{
_t++;
// find next item in range at least _t
auto uit = m_ranges.upper_bound(_t); // > _t
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit);
if (it != m_ranges.end() && it->first <= _t && it->second > _t)
return _t;
return uit == m_ranges.end() ? m_all.second : uit->first;
}
private:
UnsignedRange m_all;
std::map<T, T> m_ranges;
};
template <class T> inline std::ostream& operator<<(std::ostream& _out, RangeMask<T> const& _r)
{
_out << _r.m_all.first << "{ ";
for (auto const& i: _r.m_ranges)
_out << "[" << i.first << ", " << i.second << ") ";
_out << "}" << _r.m_all.second;
return _out;
}
}

63
libdevcore/Worker.cpp

@ -0,0 +1,63 @@
/*
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 Worker.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Worker.h"
#include <chrono>
#include <thread>
#include "Log.h"
using namespace std;
using namespace dev;
void Worker::startWorking()
{
cdebug << "startWorking for thread" << m_name;
Guard l(x_work);
if (m_work)
return;
cdebug << "Spawning" << m_name;
m_stop = false;
m_work.reset(new thread([&]()
{
setThreadName(m_name.c_str());
while (!m_stop)
{
this_thread::sleep_for(chrono::milliseconds(30));
doWork();
}
cdebug << "Finishing up worker thread";
doneWorking();
}));
}
void Worker::stopWorking()
{
cdebug << "stopWorking for thread" << m_name;
Guard l(x_work);
if (!m_work)
return;
cdebug << "Stopping" << m_name;
m_stop = true;
m_work->join();
m_work.reset();
cdebug << "Stopped" << m_name;
}

59
libdevcore/Worker.h

@ -0,0 +1,59 @@
/*
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 Worker.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <string>
#include <thread>
#include "Guards.h"
namespace dev
{
class Worker
{
protected:
Worker(std::string const& _name = "anon"): m_name(_name) {}
/// Move-constructor.
Worker(Worker&& _m) { std::swap(m_name, _m.m_name); }
/// Move-assignment.
Worker& operator=(Worker&& _m) { std::swap(m_name, _m.m_name); return *this; }
virtual ~Worker() { stopWorking(); }
void setName(std::string _n) { if (!isWorking()) m_name = _n; }
void startWorking();
void stopWorking();
bool isWorking() const { Guard l(x_work); return !!m_work; }
virtual void doWork() = 0;
virtual void doneWorking() {}
private:
mutable Mutex x_work; ///< Lock for the network existance.
std::unique_ptr<std::thread> m_work; ///< The network thread.
bool m_stop = false;
std::string m_name;
};
}

12
libdevcore/_libdevcore.cpp

@ -0,0 +1,12 @@
#ifdef _MSC_VER
#include "All.h"
#include "Common.cpp"
#include "CommonData.cpp"
#include "CommonIO.cpp"
#include "FixedHash.cpp"
#include "Guards.cpp"
#include "Log.cpp"
#include "RangeMask.cpp"
#include "RLP.cpp"
#include "Worker.cpp"
#endif

12
libethential/vector_ref.h → libdevcore/vector_ref.h

@ -5,12 +5,7 @@
#include <vector>
#include <string>
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
namespace eth
namespace dev
{
template <class _T>
@ -26,8 +21,9 @@ public:
vector_ref(std::string* _data): m_data((_T*)_data->data()), m_count(_data->size() / sizeof(_T)) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {}
vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {}
#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_
vector_ref(leveldb::Slice const& _s): m_data(_s.data()), m_count(_s.size() / sizeof(_T)) {}
#endif
explicit operator bool() const { return m_data && m_count; }
bool contentsEqual(std::vector<mutable_value_type> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); }
@ -56,7 +52,9 @@ public:
bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; }
bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); }
#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_
operator leveldb::Slice() const { return leveldb::Slice((char const*)m_data, m_count * sizeof(_T)); }
#endif
void reset() { m_data = nullptr; m_count = 0; }

9
libdevcrypto/All.h

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

56
libdevcrypto/CMakeLists.txt

@ -0,0 +1,56 @@
cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST)
set(EXECUTABLE devcrypto)
# set(CMAKE_INSTALL_PREFIX ../lib)
if(ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${SRC_LIST})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST})
endif()
file(GLOB HEADERS "*.h")
include_directories(..)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp)
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS})
if("${TARGET_PLATFORM}" STREQUAL "w64")
target_link_libraries(${EXECUTABLE} boost_system-mt-s)
target_link_libraries(${EXECUTABLE} boost_filesystem-mt-s)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} ws2_32)
target_link_libraries(${EXECUTABLE} mswsock)
target_link_libraries(${EXECUTABLE} shlwapi)
elseif (APPLE)
# Latest mavericks boost libraries only come with -mt
target_link_libraries(${EXECUTABLE} boost_system-mt)
target_link_libraries(${EXECUTABLE} boost_filesystem-mt)
target_link_libraries(${EXECUTABLE} boost_thread-mt)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
elseif (UNIX)
find_package(Boost 1.53 REQUIRED COMPONENTS filesystem)
target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY})
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARY})
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY})
target_link_libraries(${EXECUTABLE} ${Boost_DATE_TIME_LIBRARY})
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
else ()
target_link_libraries(${EXECUTABLE} boost_system)
target_link_libraries(${EXECUTABLE} boost_filesystem)
target_link_libraries(${EXECUTABLE} boost_thread)
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

110
libdevcrypto/Common.cpp

@ -0,0 +1,110 @@
/*
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 CommonEth.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Common.h"
#include <random>
#include <secp256k1/secp256k1.h>
#include "SHA3.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
//#define ETH_ADDRESS_DEBUG 1
Address dev::toAddress(Secret _private)
{
secp256k1_start();
byte pubkey[65];
int pubkeylen = 65;
int ok = secp256k1_ecdsa_seckey_verify(_private.data());
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
assert(pubkeylen == 65);
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl;
#endif
return ret;
}
KeyPair KeyPair::create()
{
secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
if (!ok)
return;
byte pubkey[65];
int pubkeylen = 65;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
if (!ok || pubkeylen != 65)
return;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return;
m_secret = m_secret;
memcpy(m_public.data(), &(pubkey[1]), 64);
m_address = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
}
KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{
return KeyPair(sha3(aesDecrypt(_seed, _password)));
}

89
libdevcrypto/Common.h

@ -0,0 +1,89 @@
/*
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 CommonEth.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Ethereum-specific data structures & algorithms.
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
/// A secret key: 32 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Secret = h256;
/// A public key: 64 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Public = h512;
/// An Ethereum address: 20 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Address = h160;
/// A vector of Ethereum addresses.
using Addresses = h160s;
/// Convert a private key into the public key equivalent.
/// @returns 0 if it's not a valid private key.
Address toAddress(h256 _private);
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).
class KeyPair
{
public:
/// Null constructor.
KeyPair() {}
/// Normal constructor - populates object from the given secret key.
KeyPair(Secret _k);
/// Create a new, randomly generated object.
static KeyPair create();
/// Create from an encrypted seed.
static KeyPair fromEncryptedSeed(bytesConstRef _seed, std::string const& _password);
/// Retrieve the secret key.
Secret const& secret() const { return m_secret; }
/// Retrieve the secret key.
Secret const& sec() const { return m_secret; }
/// Retrieve the public key.
Public const& pub() const { return m_public; }
/// Retrieve the associated address of the public key.
Address const& address() const { return m_address; }
bool operator==(KeyPair const& _c) const { return m_secret == _c.m_secret; }
bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; }
private:
Secret m_secret;
Public m_public;
Address m_address;
};
}

54
libethcore/UPnP.h → libdevcrypto/CryptoHeaders.h

@ -14,40 +14,28 @@
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 UPnP.h
* @authors:
* Gav Wood <i@gavwood.com>
/** @file CryptoHeaders.h
* @author Tim Hughes <tim@twistedfury.com>
* @date 2014
*/
#pragma once
#include <set>
#include <string>
#include <memory>
struct UPNPUrls;
struct IGDdatas;
namespace eth
{
class UPnP
{
public:
UPnP();
~UPnP();
std::string externalIP();
int addRedirect(char const* addr, int port);
void removeRedirect(int port);
bool isValid() const { return m_ok; }
std::set<int> m_reg;
bool m_ok;
std::shared_ptr<struct UPNPUrls> m_urls;
std::shared_ptr<struct IGDdatas> m_data;
};
}
// need to leave this one disabled
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma warning(push)
#pragma warning(disable:4100 4244)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#include <aes.h>
#include <pwdbased.h>
#include <modes.h>
#include <filters.h>
#include <secp256k1/secp256k1.h>
#pragma warning(pop)
#pragma GCC diagnostic pop

8
libethcore/FileSystem.cpp → libdevcrypto/FileSystem.cpp

@ -22,17 +22,17 @@
*/
#include "FileSystem.h"
#include <libethential/Common.h>
#include <libethential/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#ifdef _WIN32
#include <shlobj.h>
#endif
#include <boost/filesystem.hpp>
using namespace std;
using namespace eth;
using namespace dev;
std::string eth::getDataDir()
std::string dev::getDataDir()
{
#ifdef _WIN32
char path[1024] = "";

2
libethcore/FileSystem.h → libdevcrypto/FileSystem.h

@ -25,7 +25,7 @@
#include <string>
namespace eth
namespace dev
{
/// @returns the path for user data.

8
libethcore/MemoryDB.cpp → libdevcrypto/MemoryDB.cpp

@ -19,11 +19,14 @@
* @date 2014
*/
#include <libethential/Common.h>
#include <libdevcore/Common.h>
#include "MemoryDB.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
namespace dev
{
namespace eth
{
@ -113,3 +116,4 @@ set<h256> MemoryDB::keys() const
}
}
}

13
libethcore/MemoryDB.h → libdevcrypto/MemoryDB.h

@ -22,11 +22,13 @@
#pragma once
#include <map>
#include <libethential/Common.h>
#include <libethential/FixedHash.h>
#include <libethential/Log.h>
#include <libethential/RLP.h>
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
namespace dev
{
namespace eth
{
@ -54,7 +56,7 @@ public:
protected:
std::map<h256, std::string> m_over;
std::map<h256, uint> m_refCount;
std::map<h256, unsigned> m_refCount;
mutable bool m_enforceRefs = false;
};
@ -83,3 +85,4 @@ inline std::ostream& operator<<(std::ostream& _out, MemoryDB const& _m)
}
}
}

8
libethcore/OverlayDB.cpp → libdevcrypto/OverlayDB.cpp

@ -19,11 +19,14 @@
* @date 2014
*/
#include <libethential/Common.h>
#include <libdevcore/Common.h>
#include "OverlayDB.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
namespace dev
{
namespace eth
{
@ -97,3 +100,4 @@ void OverlayDB::kill(h256 _h)
}
}
}

12
libethcore/OverlayDB.h → libdevcrypto/OverlayDB.h

@ -21,12 +21,19 @@
#pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <memory>
#include <libethential/Common.h>
#include <libethential/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include "MemoryDB.h"
namespace ldb = leveldb;
namespace dev
{
namespace eth
{
@ -56,3 +63,4 @@ private:
};
}
}

49
libethcore/SHA3.cpp → libdevcrypto/SHA3.cpp

@ -23,11 +23,17 @@
#include "CryptoHeaders.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
h256 eth::EmptySHA3 = sha3(bytesConstRef());
namespace dev
{
namespace eth
{
std::string eth::sha3(std::string const& _input, bool _hex)
h256 EmptySHA3 = sha3(bytesConstRef());
std::string sha3(std::string const& _input, bool _hex)
{
if (!_hex)
{
@ -44,7 +50,7 @@ std::string eth::sha3(std::string const& _input, bool _hex)
return ret;
}
void eth::sha3(bytesConstRef _input, bytesRef _output)
void sha3(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
@ -52,17 +58,48 @@ void eth::sha3(bytesConstRef _input, bytesRef _output)
ctx.Final(_output.data());
}
bytes eth::sha3Bytes(bytesConstRef _input)
bytes sha3Bytes(bytesConstRef _input)
{
bytes ret(32);
sha3(_input, &ret);
return ret;
}
h256 eth::sha3(bytesConstRef _input)
h256 sha3(bytesConstRef _input)
{
h256 ret;
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}
bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt)
{
bytes pw = asBytes(_password);
if (!_salt.size())
_salt = &pw;
bytes target(64);
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256>().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds);
try
{
CryptoPP::AES::Decryption aesDecryption(target.data(), 16);
auto cipher = _ivCipher.cropped(16);
auto iv = _ivCipher.cropped(0, 16);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
std::string decrypted;
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted));
stfDecryptor.Put(cipher.data(), cipher.size());
stfDecryptor.MessageEnd();
return asBytes(decrypted);
}
catch (exception const& e)
{
cerr << e.what() << endl;
return bytes();
}
}
}
}

9
libethcore/SHA3.h → libdevcrypto/SHA3.h

@ -24,9 +24,11 @@
#pragma once
#include <string>
#include <libethential/FixedHash.h>
#include <libethential/vector_ref.h>
#include <libdevcore/FixedHash.h>
#include <libdevcore/vector_ref.h>
namespace dev
{
namespace eth
{
@ -58,4 +60,7 @@ inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input))
extern h256 EmptySHA3;
bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef());
}
}

29
libethcore/TrieCommon.cpp → libdevcrypto/TrieCommon.cpp

@ -21,6 +21,8 @@
#include "TrieCommon.h"
namespace dev
{
namespace eth
{
@ -42,8 +44,8 @@ namespace eth
std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf, int _begin, int _end)
{
uint begin = _begin;
uint end = _end < 0 ? _hexVector.size() + 1 + _end : _end;
unsigned begin = _begin;
unsigned end = _end < 0 ? _hexVector.size() + 1 + _end : _end;
bool odd = ((end - begin) % 2) != 0;
std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16);
@ -52,21 +54,21 @@ std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf, int _begin, int
ret[0] |= _hexVector[begin];
++begin;
}
for (uint i = begin; i < end; i += 2)
for (unsigned i = begin; i < end; i += 2)
ret += _hexVector[i] * 16 + _hexVector[i + 1];
return ret;
}
std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, uint _offset)
std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset)
{
uint begin = _beginNibble + _offset;
uint end = (_endNibble < 0 ? (_data.size() * 2 - _offset) + 1 + _endNibble : _endNibble) + _offset;
unsigned begin = _beginNibble + _offset;
unsigned end = (_endNibble < 0 ? (_data.size() * 2 - _offset) + 1 + _endNibble : _endNibble) + _offset;
bool odd = (end - begin) & 1;
std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16);
ret.reserve((end - begin) / 2 + 1);
uint d = odd ? 1 : 2;
unsigned d = odd ? 1 : 2;
for (auto i = begin; i < end; ++i, ++d)
{
byte n = nibble(_data, i);
@ -78,19 +80,19 @@ std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, i
return ret;
}
std::string hexPrefixEncode(bytesConstRef _d1, uint _o1, bytesConstRef _d2, uint _o2, bool _leaf)
std::string hexPrefixEncode(bytesConstRef _d1, unsigned _o1, bytesConstRef _d2, unsigned _o2, bool _leaf)
{
uint begin1 = _o1;
uint end1 = _d1.size() * 2;
uint begin2 = _o2;
uint end2 = _d2.size() * 2;
unsigned begin1 = _o1;
unsigned end1 = _d1.size() * 2;
unsigned begin2 = _o2;
unsigned end2 = _d2.size() * 2;
bool odd = (end1 - begin1 + end2 - begin2) & 1;
std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16);
ret.reserve((end1 - begin1 + end2 - begin2) / 2 + 1);
uint d = odd ? 1 : 2;
unsigned d = odd ? 1 : 2;
for (auto i = begin1; i < end1; ++i, ++d)
{
byte n = nibble(_d1, i);
@ -125,3 +127,4 @@ byte uniqueInUse(RLP const& _orig, byte except)
}
}
}

33
libethcore/TrieCommon.h → libdevcrypto/TrieCommon.h

@ -21,43 +21,45 @@
#pragma once
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
namespace dev
{
namespace eth
{
inline byte nibble(bytesConstRef _data, uint _i)
inline byte nibble(bytesConstRef _data, unsigned _i)
{
return (_i & 1) ? (_data[_i / 2] & 15) : (_data[_i / 2] >> 4);
}
inline uint sharedNibbles(bytesConstRef _a, uint _ab, uint _ae, bytesConstRef _b, uint _bb, uint _be)
inline unsigned sharedNibbles(bytesConstRef _a, unsigned _ab, unsigned _ae, bytesConstRef _b, unsigned _bb, unsigned _be)
{
uint ret = 0;
for (uint ai = _ab, bi = _bb; ai < _ae && bi < _be && nibble(_a, ai) == nibble(_b, bi); ++ai, ++bi, ++ret) {}
unsigned ret = 0;
for (unsigned ai = _ab, bi = _bb; ai < _ae && bi < _be && nibble(_a, ai) == nibble(_b, bi); ++ai, ++bi, ++ret) {}
return ret;
}
struct NibbleSlice
{
bytesConstRef data;
uint offset;
unsigned offset;
NibbleSlice(bytesConstRef _d = bytesConstRef(), uint _o = 0): data(_d), offset(_o) {}
byte operator[](uint _index) const { return nibble(data, offset + _index); }
uint size() const { return data.size() * 2 - offset; }
NibbleSlice mid(uint _index) const { return NibbleSlice(data, offset + _index); }
NibbleSlice(bytesConstRef _d = bytesConstRef(), unsigned _o = 0): data(_d), offset(_o) {}
byte operator[](unsigned _index) const { return nibble(data, offset + _index); }
unsigned size() const { return data.size() * 2 - offset; }
NibbleSlice mid(unsigned _index) const { return NibbleSlice(data, offset + _index); }
bool contains(NibbleSlice _k) const { return shared(_k) == _k.size(); }
uint shared(NibbleSlice _k) const { return sharedNibbles(data, offset, offset + size(), _k.data, _k.offset, _k.offset + _k.size()); }
unsigned shared(NibbleSlice _k) const { return sharedNibbles(data, offset, offset + size(), _k.data, _k.offset, _k.offset + _k.size()); }
bool operator==(NibbleSlice _k) const { return _k.size() == size() && shared(_k) == _k.size(); }
bool operator!=(NibbleSlice _s) const { return !operator==(_s); }
};
inline std::ostream& operator<<(std::ostream& _out, NibbleSlice const& _m)
{
for (uint i = 0; i < _m.size(); ++i)
for (unsigned i = 0; i < _m.size(); ++i)
_out << std::hex << (int)_m[i] << std::dec;
return _out;
}
@ -86,8 +88,8 @@ inline NibbleSlice keyOf(RLP const& _twoItem)
byte uniqueInUse(RLP const& _orig, byte except);
std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf = false, int _begin = 0, int _end = -1);
std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, uint _offset);
std::string hexPrefixEncode(bytesConstRef _d1, uint _o1, bytesConstRef _d2, uint _o2, bool _leaf);
std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset);
std::string hexPrefixEncode(bytesConstRef _d1, unsigned _o1, bytesConstRef _d2, unsigned _o2, bool _leaf);
inline std::string hexPrefixEncode(NibbleSlice _s, bool _leaf, int _begin = 0, int _end = -1)
{
@ -100,3 +102,4 @@ inline std::string hexPrefixEncode(NibbleSlice _s1, NibbleSlice _s2, bool _leaf)
}
}
}

11
libethcore/TrieDB.cpp → libdevcrypto/TrieDB.cpp

@ -19,17 +19,14 @@
* @date 2014
*/
#include <libethential/Common.h>
#include <libdevcore/Common.h>
#include "TrieDB.h"
using namespace std;
using namespace eth;
namespace eth
{
using namespace dev;
using namespace dev::eth;
#if !ETH_LANGUAGES
const h256 c_shaNull = sha3(rlp(""));
const h256 dev::eth::c_shaNull = sha3(rlp(""));
#endif
}

30
libethcore/TrieDB.h → libdevcrypto/TrieDB.h

@ -21,16 +21,23 @@
#pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <map>
#include <memory>
#include <libethential/Common.h>
#include <libethential/Log.h>
#include <libethcore/SHA3.h>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include "MemoryDB.h"
#include "OverlayDB.h"
#include "TrieCommon.h"
namespace ldb = leveldb;
namespace dev
{
namespace eth
{
@ -223,7 +230,7 @@ private:
// in: [K1 & K2, V] (DEL) : nibbles(K1) == _s, 0 < _s <= nibbles(K1 & K2)
// out: [K1, H] ; [K2, V] => H (INS) (being [K1, [K2, V]] if necessary)
bytes cleve(RLP const& _orig, uint _s);
bytes cleve(RLP const& _orig, unsigned _s);
// in: [K1, H] (DEL) ; H <= [K2, V] (DEL) (being [K1, [K2, V]] (DEL) if necessary)
// out: [K1 & K2, V]
@ -308,9 +315,12 @@ std::ostream& operator<<(std::ostream& _out, TrieDB<KeyType, DB> const& _db)
return _out;
}
}
}
// Template implementations...
namespace dev
{
namespace eth
{
@ -756,7 +766,7 @@ template <class DB> bytes GenericTrieDB<DB>::place(RLP const& _orig, NibbleSlice
return (RLPStream(2) << _orig[0] << _s).out();
auto s = RLPStream(17);
for (uint i = 0; i < 16; ++i)
for (unsigned i = 0; i < 16; ++i)
s << _orig[i];
s << _s;
return s.out();
@ -778,7 +788,7 @@ template <class DB> bytes GenericTrieDB<DB>::remove(RLP const& _orig)
if (_orig.itemCount() == 2)
return RLPNull;
RLPStream r(17);
for (uint i = 0; i < 16; ++i)
for (unsigned i = 0; i < 16; ++i)
r << _orig[i];
r << "";
return r.out();
@ -793,7 +803,7 @@ template <class DB> RLPStream& GenericTrieDB<DB>::streamNode(RLPStream& _s, byte
return _s;
}
template <class DB> bytes GenericTrieDB<DB>::cleve(RLP const& _orig, uint _s)
template <class DB> bytes GenericTrieDB<DB>::cleve(RLP const& _orig, unsigned _s)
{
#if ETH_PARANOIA
tdebug << "cleve " << _orig << _s;
@ -874,14 +884,14 @@ template <class DB> bytes GenericTrieDB<DB>::branch(RLP const& _orig)
if (k.size() == 0)
{
assert(isLeaf(_orig));
for (uint i = 0; i < 16; ++i)
for (unsigned i = 0; i < 16; ++i)
r << "";
r << _orig[1];
}
else
{
byte b = k[0];
for (uint i = 0; i < 16; ++i)
for (unsigned i = 0; i < 16; ++i)
if (i == b)
if (isLeaf(_orig) || k.size() > 1)
{
@ -899,3 +909,5 @@ template <class DB> bytes GenericTrieDB<DB>::branch(RLP const& _orig)
}
}
}

10
libethcore/All.h

@ -3,10 +3,6 @@
#include "BlockInfo.h"
#include "CommonEth.h"
#include "Dagger.h"
#include "FileSystem.h"
#include "MemoryDB.h"
#include "OverlayDB.h"
#include "SHA3.h"
#include "TrieCommon.h"
#include "TrieDB.h"
#include "UPnP.h"
#include "CryptoHeaders.h"
#include "Exceptions.h"

18
libethcore/BlockInfo.cpp

@ -21,16 +21,17 @@
#if !ETH_LANGUAGES
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libethcore/TrieDB.h>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include "Dagger.h"
#include "Exceptions.h"
#include "BlockInfo.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
u256 eth::c_genesisDifficulty = (u256)1 << 17;
u256 dev::eth::c_genesisDifficulty = (u256)1 << 17;
BlockInfo::BlockInfo(): timestamp(Invalid256)
{
@ -71,6 +72,8 @@ h256 BlockInfo::headerHash(bytesConstRef _block)
void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
{
hash = dev::eth::sha3(_header.data());
int field = 0;
try
{
@ -106,10 +109,9 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
void BlockInfo::populate(bytesConstRef _block, bool _checkNonce)
{
hash = eth::sha3(_block);
RLP root(_block);
RLP header = root[0];
if (!header.isList())
throw InvalidBlockFormat(0, header.data());
populateFromHeader(header, _checkNonce);
@ -171,7 +173,7 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
if (!parentHash)
return c_genesisDifficulty;
else
return timestamp >= _parent.timestamp + 9 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10));
return timestamp >= _parent.timestamp + 5 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10));
}
void BlockInfo::verifyParent(BlockInfo const& _parent) const

13
libethcore/BlockInfo.h

@ -21,10 +21,12 @@
#pragma once
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include "CommonEth.h"
namespace dev
{
namespace eth
{
@ -48,13 +50,13 @@ extern u256 c_genesisDifficulty;
* and calculateGasLimit() and the object serialised to RLP with fillStream. To determine the
* header hash without the nonce (for mining), the method headerHashWithoutNonce() is provided.
*
* The defualt constructor creates an empty object, which can be tested against with the boolean
* The default constructor creates an empty object, which can be tested against with the boolean
* conversion operator.
*/
struct BlockInfo
{
public:
h256 hash; ///< SHA3 hash of the entire block! Not serialised (the only member not contained in a block header).
h256 hash; ///< SHA3 hash of the block header! Not serialised (the only member not contained in a block header).
h256 parentHash;
h256 sha3Uncles;
Address coinbaseAddress;
@ -121,5 +123,4 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
}
}
}

6
libethcore/CMakeLists.txt

@ -15,12 +15,10 @@ file(GLOB HEADERS "*.h")
include_directories(..)
target_link_libraries(${EXECUTABLE} ethential)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp)
if(MINIUPNPC_LS)
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS})

69
libethcore/CommonEth.cpp

@ -22,15 +22,20 @@
#include "CommonEth.h"
#include <random>
#include <secp256k1/secp256k1.h>
#include <libethcore/SHA3.h>
#include <libdevcrypto/SHA3.h>
#include "Exceptions.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
//#define ETH_ADDRESS_DEBUG 1
namespace dev
{
namespace eth
{
const unsigned eth::c_protocolVersion = 28;
const unsigned eth::c_databaseVersion = 1;
const unsigned c_protocolVersion = 33;
const unsigned c_databaseVersion = 2;
static const vector<pair<u256, string>> g_units =
{
@ -55,12 +60,12 @@ static const vector<pair<u256, string>> g_units =
{u256(1), "wei"}
};
vector<pair<u256, string>> const& eth::units()
vector<pair<u256, string>> const& units()
{
return g_units;
}
std::string eth::formatBalance(u256 _b)
std::string formatBalance(u256 _b)
{
ostringstream ret;
if (_b > g_units[0].first * 10000)
@ -79,7 +84,7 @@ std::string eth::formatBalance(u256 _b)
return ret.str();
}
Address eth::toAddress(Secret _private)
Address toAddress(Secret _private)
{
secp256k1_start();
@ -95,7 +100,7 @@ Address eth::toAddress(Secret _private)
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
auto ret = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
@ -105,50 +110,4 @@ Address eth::toAddress(Secret _private)
return ret;
}
KeyPair KeyPair::create()
{
secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
if (!ok)
return;
byte pubkey[65];
int pubkeylen = 65;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
if (!ok || pubkeylen != 65)
return;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return;
m_secret = m_secret;
memcpy(m_public.data(), &(pubkey[1]), 64);
m_address = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
}
}}

62
libethcore/CommonEth.h

@ -23,9 +23,12 @@
#pragma once
#include <libethential/Common.h>
#include <libethential/FixedHash.h>
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
#include <libdevcrypto/Common.h>
namespace dev
{
namespace eth
{
@ -35,21 +38,6 @@ extern const unsigned c_protocolVersion;
/// Current database version.
extern const unsigned c_databaseVersion;
/// A secret key: 32 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Secret = h256;
/// A public key: 64 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Public = h512;
/// An Ethereum address: 20 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Address = h160;
/// A vector of Ethereum addresses.
using Addresses = h160s;
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b);
@ -77,43 +65,5 @@ static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);
static const u256 wei = u256(1);
/// Convert a private key into the public key equivalent.
/// @returns 0 if it's not a valid private key.
Address toAddress(h256 _private);
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).
class KeyPair
{
public:
/// Null constructor.
KeyPair() {}
/// Normal constructor - populates object from the given secret key.
KeyPair(Secret _k);
/// Create a new, randomly generated object.
static KeyPair create();
/// Retrieve the secret key.
Secret const& secret() const { return m_secret; }
/// Retrieve the secret key.
Secret const& sec() const { return m_secret; }
/// Retrieve the public key.
Public const& pub() const { return m_public; }
/// Retrieve the associated address of the public key.
Address const& address() const { return m_address; }
bool operator==(KeyPair const& _c) const { return m_secret == _c.m_secret; }
bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; }
private:
Secret m_secret;
Public m_public;
Address m_address;
};
}
}

10
libethcore/Dagger.cpp

@ -27,17 +27,19 @@
#include <random>
#include <thread>
#include <libethcore/CryptoHeaders.h>
#include <libethential/Common.h>
#include <libdevcore/Common.h>
#include "Dagger.h"
using namespace std;
using namespace std::chrono;
namespace dev
{
namespace eth
{
#if FAKE_DAGGER
MineInfo Dagger::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout, bool _continue, bool _turbo)
MineInfo Dagger::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
{
MineInfo ret;
static std::mt19937_64 s_eng((time(0) + (unsigned)m_last));
@ -91,7 +93,7 @@ bool Dagger::verify(h256 const& _root, u256 const& _nonce, u256 const& _difficul
return eval(_root, _nonce) < bound(_difficulty);
}
bool Dagger::mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout, bool const& _continue)
bool Dagger::mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool const& _continue)
{
// restart search if root has changed
if (m_root != _root)
@ -185,5 +187,5 @@ h256 Dagger::eval(h256 const& _root, u256 const& _nonce)
#endif
}
}
#endif

18
libethcore/Dagger.h

@ -23,25 +23,22 @@
#pragma once
#include <libethcore/SHA3.h>
#include <libdevcrypto/SHA3.h>
#include "CommonEth.h"
#define FAKE_DAGGER 1
namespace eth
namespace dev
{
inline uint toLog2(u256 _d)
namespace eth
{
return (uint)log2((double)_d);
}
struct MineInfo
{
void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; }
double requirement = 0;
double best = 1e99;
uint hashes = 0;
unsigned hashes = 0;
bool completed = false;
};
@ -53,7 +50,7 @@ public:
static h256 eval(h256 const& _root, h256 const& _nonce) { h256 b[2] = { _root, _nonce }; return sha3(bytesConstRef((byte const*)&b[0], 64)); }
static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; }
MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout = 100, bool _continue = true, bool _turbo = false);
MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
h256 m_last;
};
@ -71,7 +68,7 @@ public:
static h256 eval(h256 const& _root, u256 const& _nonce);
static bool verify(h256 const& _root, u256 const& _nonce, u256 const& _difficulty);
bool mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout = 100, bool const& _continue = bool(true));
bool mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool const& _continue = bool(true));
private:
@ -84,5 +81,4 @@ private:
#endif
}
}

69
libethcore/Exceptions.h

@ -1,43 +1,46 @@
#pragma once
#include <libethential/Exceptions.h>
#include <libdevcore/Exceptions.h>
namespace dev
{
namespace eth
{
class DatabaseAlreadyOpen: public Exception {};
class DatabaseAlreadyOpen: public dev::Exception {};
class NotEnoughCash: public Exception {};
class NotEnoughCash: public dev::Exception {};
class GasPriceTooLow: public Exception {};
class BlockGasLimitReached: public Exception {};
class NoSuchContract: public Exception {};
class ContractAddressCollision: public Exception {};
class FeeTooSmall: public Exception {};
class TooMuchGasUsed: public Exception {};
class ExtraDataTooBig: public Exception {};
class InvalidSignature: public Exception {};
class InvalidTransactionFormat: public Exception { public: InvalidTransactionFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid transaction format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockFormat: public Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockHeaderFormat: public Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidUnclesHash: public Exception {};
class InvalidUncle: public Exception {};
class UncleTooOld: public Exception {};
class UncleInChain: public Exception {};
class DuplicateUncleNonce: public Exception {};
class InvalidStateRoot: public Exception {};
class InvalidTransactionsHash: public Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref()); } };
class InvalidTransaction: public Exception {};
class InvalidDifficulty: public Exception {};
class InvalidGasLimit: public Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual std::string description() const { return "Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")"; } };
class InvalidMinGasPrice: public Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual std::string description() const { return "Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")"; } };
class InvalidTransactionGasUsed: public Exception {};
class InvalidTransactionStateRoot: public Exception {};
class InvalidTimestamp: public Exception {};
class InvalidNonce: public Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual std::string description() const { return "Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")"; } };
class InvalidBlockNonce: public Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual std::string description() const { return "Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")"; } };
class InvalidParentHash: public Exception {};
class InvalidNumber: public Exception {};
class InvalidContractAddress: public Exception {};
class GasPriceTooLow: public dev::Exception {};
class BlockGasLimitReached: public dev::Exception {};
class NoSuchContract: public dev::Exception {};
class ContractAddressCollision: public dev::Exception {};
class FeeTooSmall: public dev::Exception {};
class TooMuchGasUsed: public dev::Exception {};
class ExtraDataTooBig: public dev::Exception {};
class InvalidSignature: public dev::Exception {};
class InvalidTransactionFormat: public dev::Exception { public: InvalidTransactionFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid transaction format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockFormat: public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockHeaderFormat: public dev::Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidUnclesHash: public dev::Exception {};
class InvalidUncle: public dev::Exception {};
class UncleTooOld: public dev::Exception {};
class UncleInChain: public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual std::string description() const { return "Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"; } };
class DuplicateUncleNonce: public dev::Exception {};
class InvalidStateRoot: public dev::Exception {};
class InvalidTransactionsHash: public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref()); } };
class InvalidTransaction: public dev::Exception {};
class InvalidDifficulty: public dev::Exception {};
class InvalidGasLimit: public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual std::string description() const { return "Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")"; } };
class InvalidMinGasPrice: public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual std::string description() const { return "Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")"; } };
class InvalidTransactionGasUsed: public dev::Exception {};
class InvalidTransactionStateRoot: public dev::Exception {};
class InvalidTimestamp: public dev::Exception {};
class InvalidNonce: public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual std::string description() const { return "Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")"; } };
class InvalidBlockNonce: public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual std::string description() const { return "Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")"; } };
class InvalidParentHash: public dev::Exception {};
class InvalidNumber: public dev::Exception {};
class InvalidContractAddress: public dev::Exception {};
}
}

183
libethcore/UPnP.cpp

@ -1,183 +0,0 @@
/*
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 UPnP.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "UPnP.h"
#include <stdio.h>
#include <string.h>
#if ETH_MINIUPNPC
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#endif
#include <libethential/Exceptions.h>
#include <libethential/Common.h>
#include <libethential/Log.h>
using namespace std;
using namespace eth;
UPnP::UPnP()
{
#if ETH_MINIUPNPC
m_urls.reset(new UPNPUrls);
m_data.reset(new IGDdatas);
m_ok = false;
struct UPNPDev* devlist;
struct UPNPDev* dev;
char* descXML;
int descXMLsize = 0;
int upnperror = 0;
memset(m_urls.get(), 0, sizeof(struct UPNPUrls));
memset(m_data.get(), 0, sizeof(struct IGDdatas));
devlist = upnpDiscover(2000, NULL/*multicast interface*/, NULL/*minissdpd socket path*/, 0/*sameport*/, 0/*ipv6*/, &upnperror);
if (devlist)
{
dev = devlist;
while (dev)
{
if (strstr (dev->st, "InternetGatewayDevice"))
break;
dev = dev->pNext;
}
if (!dev)
dev = devlist; /* defaulting to first device */
cnote << "UPnP device:" << dev->descURL << "[st:" << dev->st << "]";
#if MINIUPNPC_API_VERSION >= 9
descXML = (char*)miniwget(dev->descURL, &descXMLsize, 0);
#else
descXML = (char*)miniwget(dev->descURL, &descXMLsize);
#endif
if (descXML)
{
parserootdesc (descXML, descXMLsize, m_data.get());
free (descXML); descXML = 0;
#if MINIUPNPC_API_VERSION >= 9
GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL, 0);
#else
GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL);
#endif
m_ok = true;
}
freeUPNPDevlist(devlist);
}
else
#endif
{
cnote << "UPnP device not found.";
throw NoUPnPDevice();
}
}
UPnP::~UPnP()
{
auto r = m_reg;
for (auto i: r)
removeRedirect(i);
}
string UPnP::externalIP()
{
#if ETH_MINIUPNPC
char addr[16];
if (!UPNP_GetExternalIPAddress(m_urls->controlURL, m_data->first.servicetype, addr))
return addr;
else
#endif
return "0.0.0.0";
}
int UPnP::addRedirect(char const* _addr, int _port)
{
(void)_addr;
(void)_port;
#if ETH_MINIUPNPC
if (m_urls->controlURL[0] == '\0')
{
cwarn << "UPnP::addRedirect() called without proper initialisation?";
return -1;
}
// Try direct mapping first (port external, port internal).
char port_str[16];
sprintf(port_str, "%d", _port);
if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
return _port;
// Failed - now try (random external, port internal) and cycle up to 10 times.
for (uint i = 0; i < 10; ++i)
{
_port = rand() % 65535 - 1024 + 1024;
sprintf(port_str, "%d", _port);
if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, NULL, port_str, _addr, "ethereum", "TCP", NULL, NULL))
return _port;
}
// Failed. Try asking the router to give us a free external port.
if (UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, NULL, _addr, "ethereum", "TCP", NULL, NULL))
// Failed. Exit.
return 0;
// We got mapped, but we don't know which ports we got mapped to. Now to find...
unsigned num = 0;
UPNP_GetPortMappingNumberOfEntries(m_urls->controlURL, m_data->first.servicetype, &num);
for (unsigned i = 0; i < num; ++i)
{
char extPort[16];
char intClient[16];
char intPort[6];
char protocol[4];
char desc[80];
char enabled[4];
char rHost[64];
char duration[16];
UPNP_GetGenericPortMappingEntry(m_urls->controlURL, m_data->first.servicetype, toString(i).c_str(), extPort, intClient, intPort, protocol, desc, enabled, rHost, duration);
if (string("ethereum") == desc)
{
m_reg.insert(atoi(extPort));
return atoi(extPort);
}
}
cerr << "ERROR: Mapped port not found." << endl;
#endif
return 0;
}
void UPnP::removeRedirect(int _port)
{
(void)_port;
#if ETH_MINIUPNPC
char port_str[16];
// int t;
printf("TB : upnp_rem_redir (%d)\n", _port);
if (m_urls->controlURL[0] == '\0')
{
printf("TB : the init was not done !\n");
return;
}
sprintf(port_str, "%d", _port);
UPNP_DeletePortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, "TCP", NULL);
m_reg.erase(_port);
#endif
}

6
libethcore/_libethcore.cpp

@ -0,0 +1,6 @@
#ifdef _MSC_VER
#include "All.h"
#include "BlockInfo.cpp"
#include "CommonEth.cpp"
#include "Dagger.cpp"
#endif

104
libethential/CommonData.cpp

@ -1,104 +0,0 @@
/*
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 Common.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "CommonData.h"
#include <random>
#include "Exceptions.h"
using namespace std;
using namespace eth;
std::string eth::escaped(std::string const& _s, bool _all)
{
std::string ret;
ret.reserve(_s.size());
ret.push_back('"');
for (auto i: _s)
if (i == '"' && !_all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (i < ' ' || _all)
{
ret += "\\x";
ret.push_back("0123456789abcdef"[(uint8_t)i / 16]);
ret.push_back("0123456789abcdef"[(uint8_t)i % 16]);
}
else
ret.push_back(i);
ret.push_back('"');
return ret;
}
std::string eth::randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(std::uniform_int_distribution<int>(1, 5)(s_eng), ' ');
char const n[] = "qwertyuiop";//asdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
std::uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
int eth::fromHex(char _i)
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
throw BadHexCharacter();
}
bytes eth::fromHex(std::string const& _s)
{
uint s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s + 1) / 2);
if (_s.size() % 2)
try
{
ret.push_back(fromHex(_s[s++]));
}
catch (...){ ret.push_back(0); }
for (uint i = s; i < _s.size(); i += 2)
try
{
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
}
catch (...){ ret.push_back(0); }
return ret;
}
bytes eth::asNibbles(std::string const& _s)
{
std::vector<uint8_t> ret;
ret.reserve(_s.size() * 2);
for (auto i: _s)
{
ret.push_back(i / 16);
ret.push_back(i % 16);
}
return ret;
}

15
libethereum/AccountDiff.cpp

@ -21,9 +21,10 @@
#include "AccountDiff.h"
#include <libethential/CommonIO.h>
#include <libdevcore/CommonIO.h>
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
AccountChange AccountDiff::changeType() const
{
@ -39,7 +40,9 @@ char const* AccountDiff::lead() const
return exist ? exist.from() ? "XXX" : "+++" : (bn && sc) ? "***" : bn ? " * " : sc ? "* *" : " ";
}
std::ostream& eth::operator<<(std::ostream& _out, AccountDiff const& _s)
namespace dev {
std::ostream& operator<<(std::ostream& _out, dev::eth::AccountDiff const& _s)
{
if (!_s.exist.to())
return _out;
@ -68,10 +71,14 @@ std::ostream& eth::operator<<(std::ostream& _out, AccountDiff const& _s)
return _out;
}
std::ostream& eth::operator<<(std::ostream& _out, StateDiff const& _s)
std::ostream& operator<<(std::ostream& _out, dev::eth::StateDiff const& _s)
{
_out << _s.accounts.size() << " accounts changed:" << endl;
dev::eth::AccountDiff d;
_out << d;
for (auto const& i: _s.accounts)
_out << i.second.lead() << " " << i.first << ": " << i.second << endl;
return _out;
}
}

11
libethereum/AccountDiff.h

@ -21,9 +21,11 @@
#pragma once
#include <libethential/Common.h>
#include <libdevcore/Common.h>
#include <libethcore/CommonEth.h>
namespace dev
{
namespace eth
{
@ -65,9 +67,10 @@ struct StateDiff
std::map<Address, AccountDiff> accounts;
};
std::ostream& operator<<(std::ostream& _out, StateDiff const& _s);
std::ostream& operator<<(std::ostream& _out, AccountDiff const& _s);
}
std::ostream& operator<<(std::ostream& _out, dev::eth::StateDiff const& _s);
std::ostream& operator<<(std::ostream& _out, dev::eth::AccountDiff const& _s);
}

3
libethereum/AddressState.cpp

@ -22,7 +22,8 @@
#include "AddressState.h"
#include <libethcore/CommonEth.h>
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
#pragma GCC diagnostic ignored "-Wunused-variable"
namespace { char dummy; };

10
libethereum/AddressState.h

@ -21,10 +21,12 @@
#pragma once
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libethcore/SHA3.h>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
namespace dev
{
namespace eth
{
@ -78,5 +80,5 @@ private:
};
}
}

2
libethereum/All.h

@ -8,7 +8,7 @@
#include "ExtVM.h"
#include "CommonNet.h"
#include "EthereumHost.h"
#include "EthereumSession.h"
#include "EthereumPeer.h"
#include "State.h"
#include "Transaction.h"
#include "TransactionQueue.h"

133
libethereum/BlockChain.cpp

@ -22,20 +22,21 @@
#include "BlockChain.h"
#include <boost/filesystem.hpp>
#include <libethential/Common.h>
#include <libethential/RLP.h>
#include <libethcore/FileSystem.h>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/Dagger.h>
#include <libethcore/BlockInfo.h>
#include "State.h"
#include "Defaults.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
#define ETH_CATCH 1
std::ostream& eth::operator<<(std::ostream& _out, BlockChain const& _bc)
std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
{
string cmp = toBigEndianString(_bc.currentHash());
auto it = _bc.m_extrasDB->NewIterator(_bc.m_readOptions);
@ -49,7 +50,7 @@ std::ostream& eth::operator<<(std::ostream& _out, BlockChain const& _bc)
return _out;
}
std::map<Address, AddressState> const& eth::genesisState()
std::map<Address, AddressState> const& dev::eth::genesisState()
{
static std::map<Address, AddressState> s_ret;
if (s_ret.empty())
@ -71,7 +72,7 @@ std::map<Address, AddressState> const& eth::genesisState()
BlockInfo* BlockChain::s_genesis = nullptr;
boost::shared_mutex BlockChain::x_genesis;
ldb::Slice eth::toSlice(h256 _h, unsigned _sub)
ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub)
{
#if ALL_COMPILERS_ARE_CPP11_COMPLIANT
static thread_local h256 h = _h ^ h256(u256(_sub));
@ -95,18 +96,32 @@ bytes BlockChain::createGenesisBlock()
MemoryDB db;
TrieDB<Address, MemoryDB> state(&db);
state.init();
eth::commit(genesisState(), db, state);
dev::eth::commit(genesisState(), db, state);
stateRoot = state.root();
}
block.appendList(13) << h256() << sha3EmptyList << h160();
block.append(stateRoot, false, true) << bytes() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (uint)0 << string() << sha3(bytes(1, 42));
block.append(stateRoot, false, true) << bytes() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42));
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
BlockChain::BlockChain(std::string _path, bool _killExisting)
{
// Initialise with the genesis as the last block on the longest chain.
m_genesisHash = BlockChain::genesis().hash;
m_genesisBlock = BlockChain::createGenesisBlock();
open(_path, _killExisting);
}
BlockChain::~BlockChain()
{
close();
}
void BlockChain::open(std::string _path, bool _killExisting)
{
if (_path.empty())
_path = Defaults::get()->m_dbPath;
@ -126,16 +141,12 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
if (!m_extrasDB)
throw DatabaseAlreadyOpen();
// Initialise with the genesis as the last block on the longest chain.
m_genesisHash = BlockChain::genesis().hash;
m_genesisBlock = BlockChain::createGenesisBlock();
if (!details(m_genesisHash))
{
// Insert details of genesis block.
m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {}, h256());
auto r = m_details[m_genesisHash].rlp();
m_extrasDB->Put(m_writeOptions, ldb::Slice((char const*)&m_genesisHash, 32), (ldb::Slice)eth::ref(r));
m_extrasDB->Put(m_writeOptions, ldb::Slice((char const*)&m_genesisHash, 32), (ldb::Slice)dev::ref(r));
}
checkConsistency();
@ -149,11 +160,16 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
cnote << "Opened blockchain DB. Latest: " << currentHash();
}
BlockChain::~BlockChain()
void BlockChain::close()
{
cnote << "Closing blockchain DB";
delete m_extrasDB;
delete m_db;
m_lastBlockHash = m_genesisHash;
m_details.clear();
m_blooms.clear();
m_traces.clear();
m_cache.clear();
}
template <class T, class V>
@ -165,8 +181,20 @@ bool contains(T const& _t, V const& _v)
return false;
}
inline string toString(h256s const& _bs)
{
ostringstream out;
out << "[ ";
for (auto i: _bs)
out << i.abridged() << ", ";
out << "]";
return out.str();
}
h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{
_bq.tick(*this);
vector<bytes> blocks;
_bq.drain(blocks);
@ -183,10 +211,16 @@ h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max
}
catch (UnknownParent)
{
cwarn << "Unknown parent of block!!!" << eth::sha3(block).abridged();
cwarn << "Unknown parent of block!!!" << BlockInfo::headerHash(block).abridged();
_bq.import(&block, *this);
}
catch (Exception const& _e)
{
cwarn << "Unexpected exception!" << _e.description();
_bq.import(&block, *this);
}
catch (...){}
catch (...)
{}
}
_bq.doneDrain();
return ret;
@ -223,24 +257,30 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
throw;
}
#endif
auto newHash = eth::sha3(_block);
auto newHash = BlockInfo::headerHash(_block);
// Check block doesn't already exist first!
if (details(newHash))
if (isKnown(newHash))
{
clog(BlockChainNote) << newHash << ": Not new.";
throw AlreadyHaveBlock();
}
// Work out its number as the parent's number + 1
auto pd = details(bi.parentHash);
if (!pd)
if (!isKnown(bi.parentHash))
{
clog(BlockChainNote) << newHash << ": Unknown parent " << bi.parentHash;
// We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on.
throw UnknownParent();
}
auto pd = details(bi.parentHash);
if (!pd)
{
cwarn << "Odd: details is returning false despite block known:" << RLP(pd.rlp());
cwarn << "Block:" << RLP(block(bi.parentHash));
}
// Check it's not crazy
if (bi.timestamp > (u256)time(0))
{
@ -277,7 +317,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
// All ok - insert into DB
{
WriteGuard l(x_details);
m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {}, b);
m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}, b);
m_details[bi.parentHash].children.push_back(newHash);
}
{
@ -289,10 +329,10 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
m_traces[newHash] = bt;
}
m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)eth::ref(m_details[newHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)eth::ref(m_details[bi.parentHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, 1), (ldb::Slice)eth::ref(m_blooms[newHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, 2), (ldb::Slice)eth::ref(m_traces[newHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)dev::ref(m_details[newHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, 1), (ldb::Slice)dev::ref(m_blooms[newHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, 2), (ldb::Slice)dev::ref(m_traces[newHash].rlp()));
m_db->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block));
#if ETH_PARANOIA
@ -320,20 +360,18 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
m_lastBlockHash = newHash;
}
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
clog(BlockChainNote) << " Imported and best. Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:";
for (auto r: ret)
clog(BlockChainNote) << r.abridged();
clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret);
}
else
{
clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << ", TD:" << td << ")";
clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")";
}
return ret;
}
h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, bool _post) const
{
cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged();
// cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged();
if (!_from || !_to)
{
return h256s();
@ -342,14 +380,14 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo
h256s back;
unsigned fn = details(_from).number;
unsigned tn = details(_to).number;
cdebug << "treeRoute" << fn << "..." << tn;
// cdebug << "treeRoute" << fn << "..." << tn;
while (fn > tn)
{
if (_pre)
ret.push_back(_from);
_from = details(_from).parent;
fn--;
cdebug << "from:" << fn << _from.abridged();
// cdebug << "from:" << fn << _from.abridged();
}
while (fn < tn)
{
@ -357,7 +395,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo
back.push_back(_to);
_to = details(_to).parent;
tn--;
cdebug << "to:" << tn << _to.abridged();
// cdebug << "to:" << tn << _to.abridged();
}
while (_from != _to)
{
@ -371,7 +409,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo
back.push_back(_to);
fn--;
tn--;
cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged();
// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged();
}
if (o_common)
*o_common = _from;
@ -408,13 +446,27 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const
h256 p = _parent;
for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent)
{
ret.insert(sha3(RLP(block(p))[0].data()));
ret.insert(p); // TODO: check: should this be details(p).parent?
for (auto i: RLP(block(p))[2])
ret.insert(sha3(i.data()));
}
return ret;
}
bool BlockChain::isKnown(h256 _hash) const
{
if (_hash == m_genesisHash)
return true;
{
ReadGuard l(x_cache);
if (m_cache.count(_hash))
return true;
}
string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
return !!d.size();
}
bytes BlockChain::block(h256 _hash) const
{
if (_hash == m_genesisHash)
@ -430,13 +482,16 @@ bytes BlockChain::block(h256 _hash) const
string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
if (!d.size())
{
cwarn << "Couldn't find requested block:" << _hash.abridged();
return bytes();
}
WriteGuard l(x_cache);
m_cache[_hash].resize(d.size());
memcpy(m_cache[_hash].data(), d.data(), d.size());
if (!d.size())
cwarn << "Couldn't find requested block:" << _hash.abridged();
return m_cache[_hash];
}

24
libethereum/BlockChain.h

@ -21,16 +21,23 @@
#pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <mutex>
#include <libethential/Log.h>
#include <libdevcore/Log.h>
#include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h>
#include <libethential/Guards.h>
#include <libdevcore/Guards.h>
#include "BlockDetails.h"
#include "AddressState.h"
#include "BlockQueue.h"
namespace ldb = leveldb;
namespace dev
{
namespace eth
{
@ -63,6 +70,8 @@ public:
BlockChain(std::string _path, bool _killExisting = false);
~BlockChain();
void reopen(std::string _path, bool _killExisting = false) { close(); open(_path, _killExisting); }
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.
/// To be called from main loop every 100ms or so.
void process();
@ -78,6 +87,9 @@ public:
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
h256s import(bytes const& _block, OverlayDB const& _stateDB);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); }
@ -95,8 +107,8 @@ public:
bytes block() const { return block(currentHash()); }
/// Get a number for the given hash (or the most recent mined if none given). Thread-safe.
uint number(h256 _hash) const { return details(_hash).number; }
uint number() const { return number(currentHash()); }
unsigned number(h256 _hash) const { return details(_hash).number; }
unsigned number() const { return number(currentHash()); }
/// Get a given block (RLP format). Thread-safe.
h256 currentHash() const { ReadGuard l(x_lastBlockHash); return m_lastBlockHash; }
@ -136,6 +148,9 @@ public:
h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
private:
void open(std::string _path, bool _killExisting = false);
void close();
template<class T, unsigned N> T queryExtras(h256 _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n) const
{
{
@ -195,3 +210,4 @@ private:
std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
}
}

7
libethereum/BlockDetails.cpp

@ -21,13 +21,14 @@
#include "BlockDetails.h"
#include <libethential/Common.h>
#include <libdevcore/Common.h>
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
BlockDetails::BlockDetails(RLP const& _r)
{
number = _r[0].toInt<uint>();
number = _r[0].toInt<unsigned>();
totalDifficulty = _r[1].toInt<u256>();
parent = _r[2].toHash<h256>();
children = _r[3].toVector<h256>();

16
libethereum/BlockDetails.h

@ -21,25 +21,32 @@
#pragma once
#include <libethential/Log.h>
#include <libethential/RLP.h>
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
#include "Manifest.h"
namespace ldb = leveldb;
namespace dev
{
namespace eth
{
struct BlockDetails
{
BlockDetails(): number(0), totalDifficulty(0) {}
BlockDetails(uint _n, u256 _tD, h256 _p, h256s _c, h256 _bloom): number(_n), totalDifficulty(_tD), parent(_p), children(_c), bloom(_bloom) {}
BlockDetails(unsigned _n, u256 _tD, h256 _p, h256s _c, h256 _bloom): number(_n), totalDifficulty(_tD), parent(_p), children(_c), bloom(_bloom) {}
BlockDetails(RLP const& _r);
bytes rlp() const;
bool isNull() const { return !totalDifficulty; }
explicit operator bool() const { return !isNull(); }
uint number; // TODO: remove?
unsigned number; // TODO: remove?
u256 totalDifficulty;
h256 parent;
h256s children;
@ -74,3 +81,4 @@ static const BlockBlooms NullBlockBlooms;
static const BlockTraces NullBlockTraces;
}
}

67
libethereum/BlockQueue.cpp

@ -21,23 +21,29 @@
#include "BlockQueue.h"
#include <libethential/Log.h>
#include <libdevcore/Log.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include "BlockChain.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
{
// Check if we already know this block.
h256 h = sha3(_block);
h256 h = BlockInfo::headerHash(_block);
cblockq << "Queuing block" << h.abridged() << "for import...";
UpgradableGuard l(m_lock);
if (m_readySet.count(h) || m_drainingSet.count(h) || m_futureSet.count(h))
if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h))
{
// Already know about this one.
cblockq << "Already known.";
return false;
}
// VERIFY: populates from the block and checks the block is internally coherent.
BlockInfo bi;
@ -56,29 +62,36 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
return false;
}
#endif
auto newHash = eth::sha3(_block);
// Check block doesn't already exist first!
if (_bc.details(newHash))
if (_bc.details(h))
{
cblockq << "Already known in chain.";
return false;
}
// Check it's not crazy
if (bi.timestamp > (u256)time(0))
return false;
UpgradeGuard ul(l);
// Check it's not in the future
if (bi.timestamp > (u256)time(0))
{
m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes()));
cblockq << "OK - queued for future.";
}
else
{
UpgradeGuard ul(l);
// We now know it.
if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.details(bi.parentHash))
if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
{
// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
m_future.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_futureSet.insert(h);
cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged();
m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_unknownSet.insert(h);
}
else
{
// If valid, append to blocks.
cblockq << "OK - ready for chain insertion.";
m_ready.push_back(_block.toBytes());
m_readySet.insert(h);
@ -89,21 +102,41 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
return true;
}
void BlockQueue::tick(BlockChain const& _bc)
{
unsigned t = time(0);
for (auto i = m_future.begin(); i != m_future.end() && i->first < time(0); ++i)
import(&(i->second), _bc);
WriteGuard l(m_lock);
m_future.erase(m_future.begin(), m_future.upper_bound(t));
}
void BlockQueue::drain(std::vector<bytes>& o_out)
{
WriteGuard l(m_lock);
if (m_drainingSet.empty())
{
swap(o_out, m_ready);
swap(m_drainingSet, m_readySet);
}
}
void BlockQueue::noteReadyWithoutWriteGuard(h256 _good)
{
list<h256> goodQueue(1, _good);
while (goodQueue.size())
{
auto r = m_future.equal_range(goodQueue.front());
auto r = m_unknown.equal_range(goodQueue.front());
goodQueue.pop_front();
for (auto it = r.first; it != r.second; ++it)
{
m_ready.push_back(it->second.second);
auto newReady = it->second.first;
m_futureSet.erase(newReady);
m_unknownSet.erase(newReady);
m_readySet.insert(newReady);
goodQueue.push_back(newReady);
}
m_future.erase(r.first, r.second);
m_unknown.erase(r.first, r.second);
}
}

31
libethereum/BlockQueue.h

@ -22,15 +22,21 @@
#pragma once
#include <boost/thread.hpp>
#include <libethential/Common.h>
#include "libethcore/CommonEth.h"
#include <libethential/Guards.h>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libethcore/CommonEth.h>
#include <libdevcore/Guards.h>
namespace dev
{
namespace eth
{
class BlockChain;
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; };
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
/**
* @brief A queue of blocks. Sits between network or other I/O and the BlockChain.
* Sorts them ready for blockchain insertion (with the BlockChain::sync() method).
@ -42,9 +48,12 @@ public:
/// Import a block into the queue.
bool import(bytesConstRef _tx, BlockChain const& _bc);
/// Notes that time has moved on and some blocks that used to be "in the future" may no be valid.
void tick(BlockChain const& _bc);
/// Grabs the blocks that are ready, giving them in the correct order for insertion into the chain.
/// Don't forget to call doneDrain() once you're done importing.
void drain(std::vector<bytes>& o_out) { WriteGuard l(m_lock); if (m_drainingSet.empty()) { swap(o_out, m_ready); swap(m_drainingSet, m_readySet); } }
void drain(std::vector<bytes>& o_out);
/// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them.
void doneDrain() { WriteGuard l(m_lock); m_drainingSet.clear(); }
@ -53,19 +62,23 @@ public:
void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); }
/// Get information on the items queued.
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_future.size()); }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
/// Clear everything.
void clear() { WriteGuard l(m_lock); m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
private:
void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_readySet; ///< All blocks ready for chain-import.
std::set<h256> m_drainingSet; ///< All blocks being imported.
std::vector<bytes> m_ready; ///< List of blocks, in correct order, ready for chain-import.
std::set<h256> m_futureSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::multimap<h256, std::pair<h256, bytes>> m_future; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
std::multimap<unsigned, bytes> m_future; ///< Set of blocks that are not yet valid.
};
}
}

3
libethereum/CMakeLists.txt

@ -19,6 +19,9 @@ include_directories(..)
target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} whisper)
target_link_libraries(${EXECUTABLE} p2p)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} secp256k1)
if(MINIUPNPC_LS)

323
libethereum/Client.cpp

@ -24,11 +24,14 @@
#include <chrono>
#include <thread>
#include <boost/filesystem.hpp>
#include <libethential/Log.h>
#include <libdevcore/Log.h>
#include <libp2p/Host.h>
#include "Defaults.h"
#include "EthereumHost.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
using namespace p2p;
VersionChecker::VersionChecker(string const& _dbPath):
m_path(_dbPath.size() ? _dbPath : Defaults::dbPath())
@ -50,76 +53,107 @@ void VersionChecker::setOk()
}
}
Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath, bool _forceClean):
m_clientVersion(_clientVersion),
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(_us, m_stateDB),
m_postMine(_us, m_stateDB)
m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB)
{
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
setMiningThreads();
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
work();
doWork();
startWorking();
}
Client::~Client()
{
if (m_work)
{
if (m_workState.load(std::memory_order_acquire) == Active)
m_workState.store(Deleting, std::memory_order_release);
while (m_workState.load(std::memory_order_acquire) != Deleted)
this_thread::sleep_for(chrono::milliseconds(10));
m_work->join();
m_work.reset(nullptr);
}
stopNetwork();
stopWorking();
}
void Client::ensureWorking()
void Client::setNetworkId(u256 _n)
{
static const char* c_threadName = "eth";
if (auto h = m_host.lock())
h->setNetworkId(_n);
}
if (!m_work)
m_work.reset(new thread([&]()
{
setThreadName(c_threadName);
m_workState.store(Active, std::memory_order_release);
while (m_workState.load(std::memory_order_acquire) != Deleting)
work();
m_workState.store(Deleted, std::memory_order_release);
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
WriteGuard l(x_stateDB);
m_preMine.sync(m_bc);
m_postMine = m_preMine;
}));
DownloadMan const* Client::downloadMan() const { if (auto h = m_host.lock()) return &(h->downloadMan()); return nullptr; }
bool Client::isSyncing() const { if (auto h = m_host.lock()) return h->isSyncing(); return false; }
void Client::doneWorking()
{
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
WriteGuard l(x_stateDB);
m_preMine.sync(m_bc);
m_postMine = m_preMine;
}
void Client::flushTransactions()
{
work();
doWork();
}
void Client::killChain()
{
bool wasMining = isMining();
if (wasMining)
stopMining();
stopWorking();
m_tq.clear();
m_bq.clear();
m_miners.clear();
m_preMine = State();
m_postMine = State();
{
WriteGuard l(x_stateDB);
m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), true);
}
m_bc.reopen(Defaults::dbPath(), true);
m_preMine = State(Address(), m_stateDB);
m_postMine = State(Address(), m_stateDB);
if (auto h = m_host.lock())
h->reset();
doWork();
setMiningThreads(0);
startWorking();
if (wasMining)
startMining();
}
void Client::clearPending()
{
WriteGuard l(x_stateDB);
if (!m_postMine.pending().size())
return;
h256Set changeds;
for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
appendFromNewPending(m_postMine.bloom(i), changeds);
changeds.insert(PendingChangedFilter);
m_postMine = m_preMine;
{
WriteGuard l(x_stateDB);
if (!m_postMine.pending().size())
return;
for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
appendFromNewPending(m_postMine.bloom(i), changeds);
changeds.insert(PendingChangedFilter);
m_postMine = m_preMine;
}
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
}
noteChanged(changeds);
}
@ -161,24 +195,6 @@ void Client::uninstallWatch(unsigned _i)
m_filters.erase(fit);
}
void Client::appendFromNewPending(h256 _bloom, h256Set& o_changed) const
{
lock_guard<mutex> l(m_filterLock);
for (pair<h256, InstalledFilter> const& i: m_filters)
if ((unsigned)i.second.filter.latest() > m_bc.number() && i.second.filter.matches(_bloom))
o_changed.insert(i.first);
}
void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const
{
auto d = m_bc.details(_block);
lock_guard<mutex> l(m_filterLock);
for (pair<h256, InstalledFilter> const& i: m_filters)
if ((unsigned)i.second.filter.latest() >= d.number && (unsigned)i.second.filter.earliest() <= d.number && i.second.filter.matches(d.bloom))
o_changed.insert(i.first);
}
void Client::noteChanged(h256Set const& _filters)
{
lock_guard<mutex> l(m_filterLock);
@ -190,107 +206,33 @@ void Client::noteChanged(h256Set const& _filters)
}
}
void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHost, unsigned short _port, NodeMode _mode, unsigned _peers, string const& _publicIP, bool _upnp, u256 _networkId)
{
static const char* c_threadName = "net";
{
UpgradableGuard l(x_net);
if (m_net.get())
return;
{
UpgradeGuard ul(l);
if (!m_workNet)
m_workNet.reset(new thread([&]()
{
setThreadName(c_threadName);
m_workNetState.store(Active, std::memory_order_release);
while (m_workNetState.load(std::memory_order_acquire) != Deleting)
workNet();
m_workNetState.store(Deleted, std::memory_order_release);
}));
try
{
m_net.reset(new EthereumHost(m_clientVersion, m_bc, _networkId, _listenPort, _mode, _publicIP, _upnp));
}
catch (std::exception const&)
{
// Probably already have the port open.
cwarn << "Could not initialize with specified/default port. Trying system-assigned port";
m_net.reset(new EthereumHost(m_clientVersion, m_bc, 0, _mode, _publicIP, _upnp));
}
}
m_net->setIdealPeerCount(_peers);
}
if (_seedHost.size())
connect(_seedHost, _port);
ensureWorking();
}
void Client::stopNetwork()
{
UpgradableGuard l(x_net);
if (m_workNet)
{
if (m_workNetState.load(std::memory_order_acquire) == Active)
m_workNetState.store(Deleting, std::memory_order_release);
while (m_workNetState.load(std::memory_order_acquire) != Deleted)
this_thread::sleep_for(chrono::milliseconds(10));
m_workNet->join();
}
if (m_net)
{
UpgradeGuard ul(l);
m_net.reset(nullptr);
m_workNet.reset(nullptr);
}
}
std::vector<PeerInfo> Client::peers()
{
ReadGuard l(x_net);
return m_net ? m_net->peers() : std::vector<PeerInfo>();
}
size_t Client::peerCount() const
{
ReadGuard l(x_net);
return m_net ? m_net->peerCount() : 0;
}
void Client::setIdealPeerCount(size_t _n) const
void Client::appendFromNewPending(h256 _bloom, h256Set& o_changed) const
{
ReadGuard l(x_net);
if (m_net)
return m_net->setIdealPeerCount(_n);
lock_guard<mutex> l(m_filterLock);
for (pair<h256, InstalledFilter> const& i: m_filters)
if ((unsigned)i.second.filter.latest() > m_bc.number() && i.second.filter.matches(_bloom))
o_changed.insert(i.first);
}
bytes Client::savePeers()
void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const
{
ReadGuard l(x_net);
if (m_net)
return m_net->savePeers();
return bytes();
}
auto d = m_bc.details(_block);
void Client::restorePeers(bytesConstRef _saved)
{
ReadGuard l(x_net);
if (m_net)
return m_net->restorePeers(_saved);
lock_guard<mutex> l(m_filterLock);
for (pair<h256, InstalledFilter> const& i: m_filters)
if ((unsigned)i.second.filter.latest() >= d.number && (unsigned)i.second.filter.earliest() <= d.number && i.second.filter.matches(d.bloom))
o_changed.insert(i.first);
}
void Client::connect(std::string const& _seedHost, unsigned short _port)
void Client::setForceMining(bool _enable)
{
ReadGuard l(x_net);
if (!m_net.get())
return;
m_net->connect(_seedHost, _port);
m_forceMining = _enable;
if (!m_host.lock())
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
}
}
void Client::setMiningThreads(unsigned _threads)
@ -318,6 +260,7 @@ MineProgress Client::miningProgress() const
std::list<MineInfo> Client::miningHistory()
{
std::list<MineInfo> ret;
ReadGuard l(x_miners);
if (m_miners.empty())
return ret;
@ -358,7 +301,7 @@ void Client::setupState(State& _s)
void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
ensureWorking();
startWorking();
Transaction t;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
@ -400,7 +343,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
ensureWorking();
startWorking();
Transaction t;
{
@ -420,60 +363,40 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
void Client::inject(bytesConstRef _rlp)
{
ensureWorking();
startWorking();
m_tq.attemptImport(_rlp);
}
void Client::workNet()
{
// Process network events.
// Synchronise block chain with network.
// Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks.
{
ReadGuard l(x_net);
if (m_net)
{
cwork << "NETWORK";
m_net->process(); // must be in guard for now since it uses the blockchain.
// returns h256Set as block hashes, once for each block that has come in/gone out.
cwork << "NET <==> TQ ; CHAIN ==> NET ==> BQ";
m_net->sync(m_tq, m_bq);
cwork << "TQ:" << m_tq.items() << "; BQ:" << m_bq.items();
}
}
this_thread::sleep_for(chrono::milliseconds(1));
}
void Client::work()
void Client::doWork()
{
// TODO: Use condition variable rather than polling.
cworkin << "WORK";
h256Set changeds;
ReadGuard l(x_miners);
for (auto& m: m_miners)
if (m.isComplete())
{
cwork << "CHAIN <== postSTATE";
h256s hs;
{
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
if (m.isComplete())
{
for (auto h: hs)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
//changeds.insert(PendingChangedFilter); // if we mined the new block, then we've probably reset the pending transactions.
cwork << "CHAIN <== postSTATE";
h256s hs;
{
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto h: hs)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
//changeds.insert(PendingChangedFilter); // if we mined the new block, then we've probably reset the pending transactions.
}
for (auto& m: m_miners)
m.noteStateChange();
}
for (auto& m: m_miners)
m.noteStateChange();
}
}
// Synchronise state to block chain.
// This should remove any transactions on our queue that are included within our state.
@ -502,7 +425,8 @@ void Client::work()
cwork << "preSTATE <== CHAIN";
if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address())
{
cnote << "New block on chain: Restarting mining operation.";
if (isMining())
cnote << "New block on chain: Restarting mining operation.";
m_postMine = m_preMine;
rsm = true;
changeds.insert(PendingChangedFilter);
@ -518,7 +442,8 @@ void Client::work()
appendFromNewPending(i, changeds);
changeds.insert(PendingChangedFilter);
cnote << "Additional transaction ready: Restarting mining operation.";
if (isMining())
cnote << "Additional transaction ready: Restarting mining operation.";
rsm = true;
}
}

161
libethereum/Client.h

@ -26,11 +26,13 @@
#include <list>
#include <atomic>
#include <boost/utility.hpp>
#include <libethential/Common.h>
#include <libethential/CommonIO.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libevm/FeeStructure.h>
#include <libethcore/Dagger.h>
#include <libethential/Guards.h>
#include <libp2p/Common.h>
#include "BlockChain.h"
#include "TransactionQueue.h"
#include "State.h"
@ -38,11 +40,15 @@
#include "PastMessage.h"
#include "MessageFilter.h"
#include "Miner.h"
#include "Interface.h"
namespace dev
{
namespace eth
{
class Client;
class DownloadMan;
enum ClientWorkState
{
@ -51,6 +57,12 @@ enum ClientWorkState
Deleted
};
enum class NodeMode
{
PeerServer,
Full
};
class VersionChecker
{
public:
@ -87,24 +99,24 @@ struct ClientWatch
};
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; };
#define cwatch eth::LogOutputStream<eth::WatchChannel, true>()
#define cwatch dev::LogOutputStream<dev::eth::WatchChannel, true>()
struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; };
struct WorkOutChannel: public LogChannel { static const char* name() { return "<W<"; } static const int verbosity = 16; };
struct WorkChannel: public LogChannel { static const char* name() { return "-W-"; } static const int verbosity = 16; };
#define cwork eth::LogOutputStream<eth::WorkChannel, true>()
#define cworkin eth::LogOutputStream<eth::WorkInChannel, true>()
#define cworkout eth::LogOutputStream<eth::WorkOutChannel, true>()
#define cwork dev::LogOutputStream<dev::eth::WorkChannel, true>()
#define cworkin dev::LogOutputStream<dev::eth::WorkInChannel, true>()
#define cworkout dev::LogOutputStream<dev::eth::WorkOutChannel, true>()
/**
* @brief Main API hub for interfacing with Ethereum.
*/
class Client: public MinerHost
class Client: public MinerHost, public Interface, Worker
{
friend class Miner;
public:
/// Constructor.
explicit Client(std::string const& _clientVersion, Address _us = Address(), std::string const& _dbPath = std::string(), bool _forceClean = false);
/// New-style Constructor.
explicit Client(p2p::Host* _host, std::string const& _dbPath = std::string(), bool _forceClean = false, u256 _networkId = 0);
/// Destructor.
~Client();
@ -129,14 +141,11 @@ public:
// [NEW API]
int getDefault() const { return m_default; }
void setDefault(int _block) { m_default = _block; }
u256 balanceAt(Address _a) const { return balanceAt(_a, m_default); }
u256 countAt(Address _a) const { return countAt(_a, m_default); }
u256 stateAt(Address _a, u256 _l) const { return stateAt(_a, _l, m_default); }
bytes codeAt(Address _a) const { return codeAt(_a, m_default); }
std::map<u256, u256> storageAt(Address _a) const { return storageAt(_a, m_default); }
using Interface::balanceAt;
using Interface::countAt;
using Interface::stateAt;
using Interface::codeAt;
using Interface::storageAt;
u256 balanceAt(Address _a, int _block) const;
u256 countAt(Address _a, int _block) const;
@ -155,62 +164,36 @@ public:
// [EXTRA API]:
/// @returns the length of the chain.
virtual unsigned number() const { return m_bc.number(); }
/// Get a map containing each of the pending transactions.
/// @TODO: Remove in favour of transactions().
Transactions pending() const { return m_postMine.pending(); }
/// Differences between transactions.
StateDiff diff(unsigned _txi) const { return diff(_txi, m_default); }
using Interface::diff;
StateDiff diff(unsigned _txi, h256 _block) const;
StateDiff diff(unsigned _txi, int _block) const;
/// Get a list of all active addresses.
std::vector<Address> addresses() const { return addresses(m_default); }
using Interface::addresses;
std::vector<Address> addresses(int _block) const;
/// Get the fee associated for a transaction with the given data.
static u256 txGas(uint _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; }
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); }
// [PRIVATE API - only relevant for base clients, not available in general]
eth::State state(unsigned _txi, h256 _block) const;
eth::State state(h256 _block) const;
eth::State state(unsigned _txi) const;
dev::eth::State state(unsigned _txi, h256 _block) const;
dev::eth::State state(h256 _block) const;
dev::eth::State state(unsigned _txi) const;
/// Get the object representing the current state of Ethereum.
eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; }
dev::eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; }
/// Get the object representing the current canonical blockchain.
BlockChain const& blockChain() const { return m_bc; }
// Misc stuff:
void setClientVersion(std::string const& _name) { m_clientVersion = _name; }
// Network stuff:
/// Get information on the current peer set.
std::vector<PeerInfo> peers();
/// Same as peers().size(), but more efficient.
size_t peerCount() const;
/// Same as peers().size(), but more efficient.
void setIdealPeerCount(size_t _n) const;
/// Start the network subsystem.
void startNetwork(unsigned short _listenPort = 30303, std::string const& _remoteHost = std::string(), unsigned short _remotePort = 30303, NodeMode _mode = NodeMode::Full, unsigned _peers = 5, std::string const& _publicIP = std::string(), bool _upnp = true, u256 _networkId = 0);
/// Connect to a particular peer.
void connect(std::string const& _seedHost, unsigned short _port = 30303);
/// Stop the network subsystem.
void stopNetwork();
/// Is the network subsystem up?
bool haveNetwork() { ReadGuard l(x_net); return !!m_net; }
/// Save peers
bytes savePeers();
/// Restore peers
void restorePeers(bytesConstRef _saved);
// Mining stuff:
/// Check block validity prior to mining.
@ -220,7 +203,7 @@ public:
/// Should we force mining to happen, even without transactions?
bool forceMining() const { return m_forceMining; }
/// Enable/disable forcing of mining to happen, even without transactions.
void setForceMining(bool _enable) { m_forceMining = _enable; }
void setForceMining(bool _enable);
/// Are we mining as fast as we can?
bool turboMining() const { return m_turboMining; }
/// Enable/disable fast mining.
@ -236,7 +219,7 @@ public:
unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
void startMining() { ensureWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
/// Stop mining.
/// NOT thread-safe
void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
@ -247,19 +230,22 @@ public:
/// Get and clear the mining history.
std::list<MineInfo> miningHistory();
// Debug stuff:
DownloadMan const* downloadMan() const;
bool isSyncing() const;
/// Sets the network id.
void setNetworkId(u256 _n);
/// Clears pending transactions. Just for debug use.
void clearPending();
/// Kills the blockchain. Just for debug use.
void killChain();
private:
/// Ensure the worker thread is running. Needed for blockchain maintenance & mining.
void ensureWorking();
/// Do some work. Handles blockchain maintenance and mining.
/// @param _justQueue If true will only processing the transaction queues.
void work();
virtual void doWork();
/// Do some work on the network.
void workNet();
virtual void doneWorking();
/// Overrides for being a mining host.
virtual void setupState(State& _s);
@ -284,24 +270,17 @@ private:
State asOf(int _h) const;
State asOf(unsigned _h) const;
std::string m_clientVersion; ///< Our end-application client's name/version.
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
BlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
// TODO: remove in favour of copying m_stateDB as required and thread-safing/copying State. Have a good think about what state objects there should be. Probably want 4 (pre, post, mining, user-visible).
mutable boost::shared_mutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::unique_ptr<std::thread> m_workNet; ///< The network thread.
std::atomic<ClientWorkState> m_workNetState;
mutable boost::shared_mutex x_net; ///< Lock for the network existance.
std::unique_ptr<EthereumHost> m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
std::unique_ptr<std::thread> m_work; ///< The work thread.
std::atomic<ClientWorkState> m_workState;
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector<Miner> m_miners;
mutable boost::shared_mutex x_miners;
@ -312,47 +291,7 @@ private:
mutable std::mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
int m_default = -1;
};
class Watch;
}
namespace std { void swap(eth::Watch& _a, eth::Watch& _b); }
namespace eth
{
class Watch: public boost::noncopyable
{
friend void std::swap(Watch& _a, Watch& _b);
public:
Watch() {}
Watch(Client& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {}
Watch(Client& _c, MessageFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {}
~Watch() { if (m_c) m_c->uninstallWatch(m_id); }
bool check() { return m_c ? m_c->checkWatch(m_id) : false; }
bool peek() { return m_c ? m_c->peekWatch(m_id) : false; }
PastMessages messages() const { return m_c->messages(m_id); }
private:
Client* m_c;
unsigned m_id;
};
}
namespace std
{
inline void swap(eth::Watch& _a, eth::Watch& _b)
{
swap(_a.m_c, _b.m_c);
swap(_a.m_id, _b.m_id);
}
}

42
libethereum/CommonNet.cpp

@ -21,42 +21,8 @@
#include "CommonNet.h"
using namespace std;
using namespace eth;
// Helper function to determine if an address falls within one of the reserved ranges
// For V4:
// Class A "10.*", Class B "172.[16->31].*", Class C "192.168.*"
// Not implemented yet for V6
bool eth::isPrivateAddress(bi::address _addressToCheck)
{
if (_addressToCheck.is_v4())
{
bi::address_v4 v4Address = _addressToCheck.to_v4();
bi::address_v4::bytes_type bytesToCheck = v4Address.to_bytes();
if (bytesToCheck[0] == 10 || bytesToCheck[0] == 127)
return true;
if (bytesToCheck[0] == 172 && (bytesToCheck[1] >= 16 && bytesToCheck[1] <= 31))
return true;
if (bytesToCheck[0] == 192 && bytesToCheck[1] == 168)
return true;
}
return false;
}
std::string eth::reasonOf(DisconnectReason _r)
{
switch (_r)
{
case DisconnectRequested: return "Disconnect was requested.";
case TCPError: return "Low-level TCP communication error.";
case BadProtocol: return "Data format error.";
case UselessPeer: return "Peer had no use for this node.";
case TooManyPeers: return "Peer had too many connections.";
case DuplicatePeer: return "Peer was already connected.";
case WrongGenesis: return "Disagreement over genesis block.";
case IncompatibleProtocol: return "Peer protocol versions are incompatible.";
case ClientQuit: return "Peer is exiting.";
default: return "Unknown reason.";
}
}
using namespace dev;
using namespace dev::eth;
#pragma GCC diagnostic ignored "-Wunused-variable"
namespace { char dummy; };

94
libethereum/CommonNet.h

@ -18,95 +18,57 @@
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Miscellanea required for the PeerServer/PeerSession classes.
* Miscellanea required for the PeerServer/Session classes.
*/
#pragma once
#include <string>
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <chrono>
#include <libethential/Common.h>
#include <libethential/Log.h>
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
namespace dev
{
namespace eth
{
bool isPrivateAddress(bi::address _addressToCheck);
static const eth::uint c_maxHashes = 32; ///< Maximum number of hashes BlockHashes will ever send.
static const eth::uint c_maxHashesAsk = 32; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const eth::uint c_maxBlocks = 16; ///< Maximum number of blocks Blocks will ever send.
static const eth::uint c_maxBlocksAsk = 16; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#if ETH_DEBUG
static const unsigned c_maxHashes = 64; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 64; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 32; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#else
static const unsigned c_maxHashes = 256; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#endif
class OverlayDB;
class BlockChain;
class TransactionQueue;
class EthereumHost;
class EthereumSession;
class EthereumPeer;
struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; };
struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; };
struct NetMessageSummary: public LogChannel { static const char* name() { return "-N-"; } static const int verbosity = 2; };
struct NetConnect: public LogChannel { static const char* name() { return "+N+"; } static const int verbosity = 4; };
struct NetMessageDetail: public LogChannel { static const char* name() { return "=N="; } static const int verbosity = 5; };
struct NetTriviaSummary: public LogChannel { static const char* name() { return "-N-"; } static const int verbosity = 10; };
struct NetTriviaDetail: public LogChannel { static const char* name() { return "=N="; } static const int verbosity = 11; };
struct NetAllDetail: public LogChannel { static const char* name() { return "=N="; } static const int verbosity = 13; };
struct NetRight: public LogChannel { static const char* name() { return ">N>"; } static const int verbosity = 14; };
struct NetLeft: public LogChannel { static const char* name() { return "<N<"; } static const int verbosity = 15; };
enum PacketType
enum EthereumPacket
{
HelloPacket = 0,
DisconnectPacket,
PingPacket,
PongPacket,
GetPeersPacket = 0x10,
PeersPacket,
TransactionsPacket,
BlocksPacket,
GetChainPacket,
NotInChainPacket,
StatusPacket = 0x10,
GetTransactionsPacket,
TransactionsPacket,
GetBlockHashesPacket,
BlockHashesPacket,
GetBlocksPacket,
BlocksPacket,
};
enum DisconnectReason
{
DisconnectRequested = 0,
TCPError,
BadProtocol,
UselessPeer,
TooManyPeers,
DuplicatePeer,
WrongGenesis,
IncompatibleProtocol,
ClientQuit
};
/// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);
struct PeerInfo
{
std::string clientVersion;
std::string host;
unsigned short port;
std::chrono::steady_clock::duration lastPing;
};
class UPnP;
enum class NodeMode
enum class Grabbing
{
Full,
PeerServer
State,
Hashes,
Chain,
ChainHelper,
Nothing
};
}
}

5
libethereum/Defaults.cpp

@ -21,9 +21,10 @@
#include "Defaults.h"
#include <libethcore/FileSystem.h>
#include <libdevcrypto/FileSystem.h>
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
Defaults* Defaults::s_this = nullptr;

5
libethereum/Defaults.h

@ -21,8 +21,10 @@
#pragma once
#include <libethential/Common.h>
#include <libdevcore/Common.h>
namespace dev
{
namespace eth
{
@ -45,3 +47,4 @@ private:
};
}
}

75
libethereum/DownloadMan.cpp

@ -0,0 +1,75 @@
/*
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 DownloadMan.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "DownloadMan.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
DownloadSub::DownloadSub(DownloadMan& _man): m_man(&_man)
{
WriteGuard l(m_man->x_subs);
m_man->m_subs.insert(this);
}
DownloadSub::~DownloadSub()
{
if (m_man)
{
WriteGuard l(m_man->x_subs);
m_man->m_subs.erase(this);
}
}
h256Set DownloadSub::nextFetch(unsigned _n)
{
Guard l(m_fetch);
if (m_remaining.size())
return m_remaining;
m_asked.clear();
m_indices.clear();
m_remaining.clear();
if (!m_man || m_man->chain().empty())
return h256Set();
m_asked = (~(m_man->taken() + m_attempted)).lowest(_n);
if (m_asked.empty())
m_asked = (~(m_man->taken(true) + m_attempted)).lowest(_n);
m_attempted += m_asked;
for (auto i: m_asked)
{
auto x = m_man->m_chain[i];
m_remaining.insert(x);
m_indices[x] = i;
}
return m_remaining;
}
void DownloadSub::noteBlock(h256 _hash)
{
Guard l(m_fetch);
if (m_man && m_indices.count(_hash))
m_man->m_blocksGot += m_indices[_hash];
m_remaining.erase(_hash);
}

147
libethereum/DownloadMan.h

@ -0,0 +1,147 @@
/*
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 DownloadMan.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <map>
#include <vector>
#include <set>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
namespace eth
{
class DownloadMan;
class DownloadSub
{
friend class DownloadMan;
public:
DownloadSub(DownloadMan& _man);
~DownloadSub();
/// Finished last fetch - grab the next bunch of block hashes to download.
h256Set nextFetch(unsigned _n);
/// Note that we've received a particular block.
void noteBlock(h256 _hash);
/// Nothing doing here.
void doneFetch() { resetFetch(); }
RangeMask<unsigned> const& asked() const { return m_asked; }
RangeMask<unsigned> const& attemped() const { return m_attempted; }
private:
void resetFetch() // Called by DownloadMan when we need to reset the download.
{
Guard l(m_fetch);
m_remaining.clear();
m_indices.clear();
m_asked.clear();
m_attempted.clear();
}
DownloadMan* m_man = nullptr;
Mutex m_fetch;
h256Set m_remaining;
std::map<h256, unsigned> m_indices;
RangeMask<unsigned> m_asked;
RangeMask<unsigned> m_attempted;
};
class DownloadMan
{
friend class DownloadSub;
public:
~DownloadMan()
{
for (auto i: m_subs)
i->m_man = nullptr;
}
void resetToChain(h256s const& _chain)
{
{
ReadGuard l(x_subs);
for (auto i: m_subs)
i->resetFetch();
}
m_chain.clear();
m_chain.reserve(_chain.size());
for (auto i = _chain.rbegin(); i != _chain.rend(); ++i)
m_chain.push_back(*i);
m_blocksGot = RangeMask<unsigned>(0, m_chain.size());
}
void reset()
{
{
ReadGuard l(x_subs);
for (auto i: m_subs)
i->resetFetch();
}
m_chain.clear();
m_blocksGot.clear();
}
RangeMask<unsigned> taken(bool _desperate = false) const
{
auto ret = m_blocksGot;
if (!_desperate)
{
ReadGuard l(x_subs);
for (auto i: m_subs)
ret += i->m_asked;
}
return ret;
}
bool isComplete() const
{
return m_blocksGot.full();
}
h256s chain() const { return m_chain; }
void foreachSub(std::function<void(DownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); }
unsigned subCount() const { ReadGuard l(x_subs); return m_subs.size(); }
RangeMask<unsigned> blocksGot() const { return m_blocksGot; }
private:
h256s m_chain;
RangeMask<unsigned> m_blocksGot;
mutable SharedMutex x_subs;
std::set<DownloadSub*> m_subs;
};
}
}

697
libethereum/EthereumHost.cpp

@ -15,412 +15,155 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthereumHost.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* Eric Lombrozo <elombrozo@gmail.com>
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "EthereumHost.h"
#include <sys/types.h>
#ifdef _WIN32
// winsock is already included
// #include <winsock.h>
#else
#include <ifaddrs.h>
#endif
#include <set>
#include <chrono>
#include <thread>
#include <libethential/Common.h>
#include <libethcore/UPnP.h>
#include <libdevcore/Common.h>
#include <libp2p/Host.h>
#include <libp2p/Session.h>
#include <libethcore/Exceptions.h>
#include "BlockChain.h"
#include "TransactionQueue.h"
#include "BlockQueue.h"
#include "EthereumSession.h"
#include "EthereumPeer.h"
#include "DownloadMan.h"
using namespace std;
using namespace eth;
// Addresses we will skip during network interface discovery
// Use a vector as the list is small
// Why this and not names?
// Under MacOSX loopback (127.0.0.1) can be named lo0 and br0 are bridges (0.0.0.0)
static const set<bi::address> c_rejectAddresses = {
{bi::address_v4::from_string("127.0.0.1")},
{bi::address_v6::from_string("::1")},
{bi::address_v4::from_string("0.0.0.0")},
{bi::address_v6::from_string("::")}
};
EthereumHost::EthereumHost(std::string const& _clientVersion, BlockChain const& _ch, u256 _networkId, unsigned short _port, NodeMode _m, string const& _publicAddress, bool _upnp):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(_port),
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
{
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (_m == NodeMode::PeerServer ? "PeerServer" : "Full");
}
EthereumHost::EthereumHost(std::string const& _clientVersion, BlockChain const& _ch, u256 _networkId, NodeMode _m, string const& _publicAddress, bool _upnp):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(0),
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
using namespace dev;
using namespace dev::eth;
using namespace p2p;
EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
HostCapability<EthereumPeer>(),
Worker ("ethsync"),
m_chain (_ch),
m_tq (_tq),
m_bq (_bq),
m_networkId (_networkId)
{
m_listenPort = m_acceptor.local_endpoint().port();
// populate addresses.
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (m_mode == NodeMode::PeerServer ? "PeerServer" : "Full");
m_latestBlockSent = _ch.currentHash();
}
EthereumHost::EthereumHost(std::string const& _clientVersion, BlockChain const& _ch, u256 _networkId, NodeMode _m):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(0),
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
EthereumHost::~EthereumHost()
{
// populate addresses.
populateAddresses();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (m_mode == NodeMode::PeerServer ? "PeerServer" : "Full");
for (auto const& i: peers())
i->cap<EthereumPeer>()->giveUpOnFetch();
}
EthereumHost::~EthereumHost()
bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
{
disconnectPeers();
if (!m_latestBlockSent)
{
// First time - just initialise.
m_latestBlockSent = m_chain.currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged();
for (auto i: m_peers)
if (shared_ptr<EthereumSession> p = i.second.lock())
p->giveUpOnFetch();
for (auto const& i: _tq.transactions())
m_transactionsSent.insert(i.first);
return true;
}
return false;
}
void EthereumHost::registerPeer(std::shared_ptr<EthereumSession> _s)
void EthereumHost::noteHavePeerState(EthereumPeer* _who)
{
Guard l(x_peers);
m_peers[_s->m_id] = _s;
}
clog(NetAllDetail) << "Have peer state.";
void EthereumHost::disconnectPeers()
{
for (unsigned n = 0;; n = 0)
// if already downloading hash-chain, ignore.
if (m_grabbing != Grabbing::Nothing)
{
{
Guard l(x_peers);
for (auto i: m_peers)
if (auto p = i.second.lock())
{
p->disconnect(ClientQuit);
n++;
}
}
if (!n)
break;
m_ioService.poll();
this_thread::sleep_for(chrono::milliseconds(100));
clog(NetAllDetail) << "Already downloading chain. Just set to help out.";
_who->ensureGettingChain();
return;
}
delete m_upnp;
// otherwise check to see if we should be downloading...
_who->tryGrabbingHashChain();
}
unsigned EthereumHost::protocolVersion()
void EthereumHost::updateGrabbing(Grabbing _g)
{
return c_protocolVersion;
m_grabbing = _g;
if (_g == Grabbing::Nothing)
readyForSync();
else if (_g == Grabbing::Chain)
for (auto j: peers())
j->cap<EthereumPeer>()->ensureGettingChain();
}
void EthereumHost::seal(bytes& _b)
void EthereumHost::noteHaveChain(EthereumPeer* _from)
{
_b[0] = 0x22;
_b[1] = 0x40;
_b[2] = 0x08;
_b[3] = 0x91;
uint32_t len = (uint32_t)_b.size() - 8;
_b[4] = (len >> 24) & 0xff;
_b[5] = (len >> 16) & 0xff;
_b[6] = (len >> 8) & 0xff;
_b[7] = len & 0xff;
}
void EthereumHost::determinePublic(string const& _publicAddress, bool _upnp)
{
if (_upnp)
try
{
m_upnp = new UPnP;
}
catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly.
bi::tcp::resolver r(m_ioService);
if (m_upnp && m_upnp->isValid() && m_peerAddresses.size())
{
clog(NetNote) << "External addr: " << m_upnp->externalIP();
int p = m_upnp->addRedirect(m_peerAddresses[0].to_string().c_str(), m_listenPort);
if (p)
clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << ".";
else
{
// couldn't map
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place). Assuming " << m_listenPort << " is local & external port.";
p = m_listenPort;
}
auto eip = m_upnp->externalIP();
if (eip == string("0.0.0.0") && _publicAddress.empty())
m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p);
else
{
m_public = bi::tcp::endpoint(bi::address::from_string(_publicAddress.empty() ? eip : _publicAddress), (unsigned short)p);
m_addresses.push_back(m_public.address().to_v4());
}
}
else
{
// No UPnP - fallback on given public address or, if empty, the assumed peer address.
m_public = bi::tcp::endpoint(_publicAddress.size() ? bi::address::from_string(_publicAddress)
: m_peerAddresses.size() ? m_peerAddresses[0]
: bi::address(), m_listenPort);
m_addresses.push_back(m_public.address().to_v4());
}
}
void EthereumHost::populateAddresses()
{
#ifdef _WIN32
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
throw NoNetworking();
auto td = _from->m_totalDifficulty;
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
if (_from->m_neededBlocks.empty())
{
clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name.";
WSACleanup();
throw NoNetworking();
_from->setGrabbing(Grabbing::Nothing);
updateGrabbing(Grabbing::Nothing);
return;
}
struct hostent* phe = gethostbyname(ac);
if (phe == 0)
{
clog(NetWarn) << "Bad host lookup.";
WSACleanup();
throw NoNetworking();
}
clog(NetNote) << "Hash-chain COMPLETE:" << _from->m_totalDifficulty << "vs" << m_chain.details().totalDifficulty << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
for (int i = 0; phe->h_addr_list[i] != 0; ++i)
if (td < m_chain.details().totalDifficulty || (td == m_chain.details().totalDifficulty && m_chain.currentHash() == _from->m_latestHash))
{
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
char *addrStr = inet_ntoa(addr);
bi::address ad(bi::address::from_string(addrStr));
m_addresses.push_back(ad.to_v4());
bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
if (!isLocal)
m_peerAddresses.push_back(ad.to_v4());
clog(NetNote) << "Address: " << ac << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring.";
_from->setGrabbing(Grabbing::Nothing);
updateGrabbing(Grabbing::Nothing);
return;
}
WSACleanup();
#else
ifaddrs* ifaddr;
if (getifaddrs(&ifaddr) == -1)
throw NoNetworking();
clog(NetNote) << "Difficulty of hashchain HIGHER. Replacing fetch queue [latest now" << _from->m_latestHash.abridged() << ", was" << m_latestBlockSent.abridged() << "]";
bi::tcp::resolver r(m_ioService);
for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next)
{
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
char host[NI_MAXHOST];
if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
continue;
try
{
auto it = r.resolve({host, "30303"});
bi::tcp::endpoint ep = it->endpoint();
bi::address ad = ep.address();
m_addresses.push_back(ad.to_v4());
bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
if (!isLocal)
m_peerAddresses.push_back(ad.to_v4());
clog(NetNote) << "Address: " << host << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
}
catch (...)
{
clog(NetNote) << "Couldn't resolve: " << host;
}
}
}
freeifaddrs(ifaddr);
#endif
}
// Looks like it's the best yet for total difficulty. Set to download.
m_man.resetToChain(_from->m_neededBlocks);
m_latestBlockSent = _from->m_latestHash;
std::map<Public, bi::tcp::endpoint> EthereumHost::potentialPeers()
{
std::map<Public, bi::tcp::endpoint> ret;
if (!m_public.address().is_unspecified())
ret.insert(make_pair(m_key.pub(), m_public));
Guard l(x_peers);
for (auto i: m_peers)
if (auto j = i.second.lock())
{
auto ep = j->endpoint();
// Skip peers with a listen port of zero or are on a private network
bool peerOnNet = (j->m_listenPort != 0 && !isPrivateAddress(ep.address()));
if (peerOnNet && ep.port() && j->m_id)
ret.insert(make_pair(i.first, ep));
}
return ret;
_from->setGrabbing(Grabbing::Chain);
updateGrabbing(Grabbing::Chain);
}
void EthereumHost::ensureAccepting()
void EthereumHost::readyForSync()
{
if (m_accepting == false)
// start grabbing next hash chain if there is one.
for (auto j: peers())
{
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
m_accepting = true;
m_acceptor.async_accept(m_socket, [=](boost::system::error_code ec)
j->cap<EthereumPeer>()->tryGrabbingHashChain();
if (j->cap<EthereumPeer>()->m_grabbing == Grabbing::Hashes)
{
if (!ec)
try
{
try {
clog(NetConnect) << "Accepted connection from " << m_socket.remote_endpoint();
} catch (...){}
bi::address remoteAddress = m_socket.remote_endpoint().address();
// Port defaults to 0 - we let the hello tell us which port the peer listens to
auto p = std::make_shared<EthereumSession>(this, std::move(m_socket), m_networkId, remoteAddress);
p->start();
}
catch (std::exception const& _e)
{
clog(NetWarn) << "ERROR: " << _e.what();
}
m_accepting = false;
if (ec.value() != 1 && (m_mode == NodeMode::PeerServer || peerCount() < m_idealPeerCount * 2))
ensureAccepting();
});
m_grabbing = Grabbing::Hashes;
return;
}
}
clog(NetNote) << "No more peers to sync with.";
}
void EthereumHost::connect(std::string const& _addr, unsigned short _port) noexcept
void EthereumHost::noteDoneBlocks(EthereumPeer* _who)
{
try
if (m_man.isComplete())
{
connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port));
// Done our chain-get.
clog(NetNote) << "Chain download complete.";
updateGrabbing(Grabbing::Nothing);
m_man.reset();
}
catch (exception const& e)
if (_who->m_grabbing == Grabbing::Chain)
{
// Couldn't connect
clog(NetConnect) << "Bad host " << _addr << " (" << e.what() << ")";
// Done our chain-get.
clog(NetNote) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
// TODO: note that peer is BADBADBAD!
updateGrabbing(Grabbing::Nothing);
m_man.reset();
}
}
void EthereumHost::connect(bi::tcp::endpoint const& _ep)
{
clog(NetConnect) << "Attempting connection to " << _ep;
bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
s->async_connect(_ep, [=](boost::system::error_code const& ec)
{
if (ec)
{
clog(NetConnect) << "Connection refused to " << _ep << " (" << ec.message() << ")";
for (auto i = m_incomingPeers.begin(); i != m_incomingPeers.end(); ++i)
if (i->second.first == _ep && i->second.second < 3)
{
m_freePeers.push_back(i->first);
goto OK;
}
// for-else
clog(NetConnect) << "Giving up.";
OK:;
}
else
{
auto p = make_shared<EthereumSession>(this, std::move(*s), m_networkId, _ep.address(), _ep.port());
clog(NetConnect) << "Connected to " << _ep;
p->start();
}
delete s;
});
}
h256Set EthereumHost::neededBlocks()
{
Guard l(x_blocksNeeded);
h256Set ret;
if (m_blocksNeeded.size())
{
while (ret.size() < c_maxBlocksAsk && m_blocksNeeded.size())
{
ret.insert(m_blocksNeeded.back());
m_blocksOnWay.insert(m_blocksNeeded.back());
m_blocksNeeded.pop_back();
}
}
else
for (auto i = m_blocksOnWay.begin(); ret.size() < c_maxBlocksAsk && i != m_blocksOnWay.end(); ++i)
ret.insert(*i);
return ret;
}
bool EthereumHost::havePeer(Public _id) const
{
Guard l(x_peers);
// Remove dead peers from list.
for (auto i = m_peers.begin(); i != m_peers.end();)
if (i->second.lock().get())
++i;
else
i = m_peers.erase(i);
return !!m_peers.count(_id);
}
bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
{
if (m_latestBlockSent == h256())
{
// First time - just initialise.
m_latestBlockSent = m_chain->currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged();
for (auto const& i: _tq.transactions())
m_transactionsSent.insert(i.first);
m_lastPeersRequest = chrono::steady_clock::time_point::min();
return true;
}
return false;
}
bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data)
{
Guard l(x_blocksNeeded);
m_blocksOnWay.erase(_hash);
if (!m_chain->details(_hash))
if (!m_chain.details(_hash))
{
lock_guard<recursive_mutex> l(m_incomingLock);
m_incomingBlocks.push_back(_data.toBytes());
@ -429,67 +172,72 @@ bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data)
return false;
}
bool EthereumHost::sync(TransactionQueue& _tq, BlockQueue& _bq)
void EthereumHost::doWork()
{
bool netChange = ensureInitialised(_tq);
if (m_mode == NodeMode::Full)
{
auto h = m_chain->currentHash();
maintainTransactions(_tq, h);
maintainBlocks(_bq, h);
// Connect to additional peers
growPeers();
}
// platform for consensus of social contract.
// restricts your freedom but does so fairly. and that's the value proposition.
// guarantees that everyone else respect the rules of the system. (i.e. obeys laws).
prunePeers();
return netChange;
bool netChange = ensureInitialised(m_tq);
auto h = m_chain.currentHash();
maintainTransactions(m_tq, h);
maintainBlocks(m_bq, h);
// return netChange;
// TODO: Figure out what to do with netChange.
(void)netChange;
}
void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash)
{
bool resendAll = (_currentHash != m_latestBlockSent);
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
if (_tq.import(&*it))
{}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
else
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.
m_incomingTransactions.clear();
bool resendAll = (m_grabbing == Grabbing::Nothing && m_chain.isKnown(m_latestBlockSent) && _currentHash != m_latestBlockSent);
{
lock_guard<recursive_mutex> l(m_incomingLock);
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
if (_tq.import(&*it))
{}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
else
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.
m_incomingTransactions.clear();
}
// Send any new transactions.
Guard l(x_peers);
for (auto j: m_peers)
if (auto p = j.second.lock())
for (auto const& p: peers())
{
auto ep = p->cap<EthereumPeer>();
if (ep)
{
bytes b;
uint n = 0;
unsigned n = 0;
for (auto const& i: _tq.transactions())
if ((!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first)) || p->m_requireTransactions || resendAll)
if ((!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)) || ep->m_requireTransactions || resendAll)
{
b += i.second;
++n;
m_transactionsSent.insert(i.first);
}
ep->clearKnownTransactions();
if (n)
{
RLPStream ts;
EthereumSession::prep(ts);
EthereumPeer::prep(ts);
ts.appendList(n + 1) << TransactionsPacket;
ts.appendRaw(b, n).swapOut(b);
seal(b);
p->send(&b);
ep->send(&b);
}
p->m_knownTransactions.clear();
p->m_requireTransactions = false;
ep->m_requireTransactions = false;
}
}
}
void EthereumHost::reset()
{
m_grabbing = Grabbing::Nothing;
m_man.resetToChain(h256s());
m_incomingTransactions.clear();
m_incomingBlocks.clear();
m_latestBlockSent = h256();
m_transactionsSent.clear();
}
void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
@ -498,187 +246,44 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
{
lock_guard<recursive_mutex> l(m_incomingLock);
for (auto it = m_incomingBlocks.rbegin(); it != m_incomingBlocks.rend(); ++it)
if (_bq.import(&*it, *m_chain))
if (_bq.import(&*it, m_chain))
{}
else{} // TODO: don't forward it.
m_incomingBlocks.clear();
}
// Send any new blocks.
if (_currentHash != m_latestBlockSent)
// If we've finished our initial sync send any new blocks.
if (m_grabbing == Grabbing::Nothing && m_chain.isKnown(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
{
RLPStream ts;
EthereumSession::prep(ts);
EthereumPeer::prep(ts);
bytes bs;
unsigned c = 0;
for (auto h: m_chain->treeRoute(m_latestBlockSent, _currentHash, nullptr, false, true))
for (auto h: m_chain.treeRoute(m_latestBlockSent, _currentHash, nullptr, false, true))
{
bs += m_chain->block(h);
bs += m_chain.block(h);
++c;
}
clog(NetMessageSummary) << "Sending" << c << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
if (c > 1000)
{
cwarn << "Gaa this would be an awful lot of new blocks. Not bothering";
return;
}
ts.appendList(1 + c).append(BlocksPacket).appendRaw(bs, c);
bytes b;
ts.swapOut(b);
seal(b);
Guard l(x_peers);
for (auto j: m_peers)
if (auto p = j.second.lock())
{
if (!p->m_knownBlocks.count(_currentHash))
p->send(&b);
p->m_knownBlocks.clear();
}
}
m_latestBlockSent = _currentHash;
}
void EthereumHost::growPeers()
{
Guard l(x_peers);
while (m_peers.size() < m_idealPeerCount)
{
if (m_freePeers.empty())
for (auto j: peers())
{
if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
{
RLPStream s;
bytes b;
(EthereumSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b);
seal(b);
for (auto const& i: m_peers)
if (auto p = i.second.lock())
if (p->isOpen())
p->send(&b);
m_lastPeersRequest = chrono::steady_clock::now();
}
if (!m_accepting)
ensureAccepting();
break;
}
auto x = time(0) % m_freePeers.size();
m_incomingPeers[m_freePeers[x]].second++;
connect(m_incomingPeers[m_freePeers[x]].first);
m_freePeers.erase(m_freePeers.begin() + x);
}
}
void EthereumHost::noteHaveChain(std::shared_ptr<EthereumSession> const& _from)
{
auto td = _from->m_totalDifficulty;
if (_from->m_neededBlocks.empty())
return;
clog(NetNote) << "Hash-chain COMPLETE:" << log2((double)_from->m_totalDifficulty) << "vs" << log2((double)m_chain->details().totalDifficulty) << "," << log2((double)m_totalDifficultyOfNeeded) << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
if ((m_totalDifficultyOfNeeded && td < m_totalDifficultyOfNeeded) || td < m_chain->details().totalDifficulty)
{
clog(NetNote) << "Difficulty of hashchain LOWER. Ignoring.";
return;
}
clog(NetNote) << "Difficulty of hashchain HIGHER. Replacing fetch queue.";
// Looks like it's the best yet for total difficulty. Set to download.
{
Guard l(x_blocksNeeded);
m_blocksNeeded = _from->m_neededBlocks;
m_blocksOnWay.clear();
m_totalDifficultyOfNeeded = td;
}
{
Guard l(x_peers);
for (auto const& i: m_peers)
if (shared_ptr<EthereumSession> p = i.second.lock())
p->ensureGettingChain();
}
}
void EthereumHost::prunePeers()
{
Guard l(x_peers);
// We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
for (uint old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
while (m_peers.size() > m_idealPeerCount)
{
// look for worst peer to kick off
// first work out how many are old enough to kick off.
shared_ptr<EthereumSession> worst;
unsigned agedPeers = 0;
for (auto i: m_peers)
if (auto p = i.second.lock())
if ((m_mode != NodeMode::PeerServer || p->m_caps != 0x01) && chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // kill older ones
worst = p;
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
worst->disconnect(TooManyPeers);
}
// Remove dead peers from list.
for (auto i = m_peers.begin(); i != m_peers.end();)
if (i->second.lock().get())
++i;
else
i = m_peers.erase(i);
}
std::vector<PeerInfo> EthereumHost::peers(bool _updatePing) const
{
Guard l(x_peers);
if (_updatePing)
const_cast<EthereumHost*>(this)->pingAll();
this_thread::sleep_for(chrono::milliseconds(200));
std::vector<PeerInfo> ret;
for (auto& i: m_peers)
if (auto j = i.second.lock())
if (j->m_socket.is_open())
ret.push_back(j->m_info);
return ret;
}
void EthereumHost::pingAll()
{
Guard l(x_peers);
for (auto& i: m_peers)
if (auto j = i.second.lock())
j->ping();
}
bytes EthereumHost::savePeers() const
{
Guard l(x_peers);
RLPStream ret;
int n = 0;
for (auto& i: m_peers)
if (auto p = i.second.lock())
if (p->m_socket.is_open() && p->endpoint().port())
{
ret.appendList(3) << p->endpoint().address().to_v4().to_bytes() << p->endpoint().port() << p->m_id;
n++;
}
return RLPStream(n).appendRaw(ret.out(), n).out();
}
void EthereumHost::restorePeers(bytesConstRef _b)
{
for (auto i: RLP(_b))
{
auto k = (Public)i[2];
if (!m_incomingPeers.count(k))
{
m_incomingPeers.insert(make_pair(k, make_pair(bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>()), 0)));
m_freePeers.push_back(k);
auto p = j->cap<EthereumPeer>();
Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash))
p->send(&b);
p->m_knownBlocks.clear();
}
m_latestBlockSent = _currentHash;
}
}

141
libethereum/EthereumHost.h

@ -28,16 +28,23 @@
#include <memory>
#include <utility>
#include <thread>
#include <libethential/Guards.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
#include <libethcore/CommonEth.h>
#include <libp2p/Common.h>
#include "CommonNet.h"
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
#include "EthereumPeer.h"
#include "DownloadMan.h"
namespace eth
namespace dev
{
class RLPStream;
namespace eth
{
class TransactionQueue;
class BlockQueue;
@ -45,139 +52,79 @@ class BlockQueue;
* @brief The EthereumHost class
* @warning None of this is thread-safe. You have been warned.
*/
class EthereumHost
class EthereumHost: public p2p::HostCapability<EthereumPeer>, Worker
{
friend class EthereumSession;
friend class EthereumPeer;
public:
/// Start server, listening for connections on the given port.
EthereumHost(std::string const& _clientVersion, BlockChain const& _ch, u256 _networkId, unsigned short _port, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, listening for connections on a system-assigned port.
EthereumHost(std::string const& _clientVersion, BlockChain const& _ch, u256 _networkId, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, but don't listen.
EthereumHost(std::string const& _clientVersion, BlockChain const& _ch, u256 _networkId, NodeMode _m = NodeMode::Full);
EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId);
/// Will block on network process events.
~EthereumHost();
/// Closes all peers.
void disconnectPeers();
static unsigned protocolVersion();
u256 networkId() { return m_networkId; }
/// Connect to a peer explicitly.
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
void connect(bi::tcp::endpoint const& _ep);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
bool sync(TransactionQueue&, BlockQueue& _bc);
/// Conduct I/O, polling, syncing, whatever.
/// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway.
/// This won't touch alter the blockchain.
void process() { if (isInitialised()) m_ioService.poll(); }
/// @returns true iff we have the a peer of the given id.
bool havePeer(Public _id) const;
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
/// Set the mode of operation on the network.
void setMode(NodeMode _m) { m_mode = _m; }
virtual ~EthereumHost();
/// Get peer information.
std::vector<PeerInfo> peers(bool _updatePing = false) const;
unsigned protocolVersion() const { return c_protocolVersion; }
u256 networkId() const { return m_networkId; }
void setNetworkId(u256 _n) { m_networkId = _n; }
/// Get number of peers connected; equivalent to, but faster than, peers().size().
size_t peerCount() const { Guard l(x_peers); return m_peers.size(); }
void reset();
/// Ping the peers, to update the latency information.
void pingAll();
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_public.port(); }
/// Serialise the set of known peers.
bytes savePeers() const;
/// Deserialise the data and populate the set of known peers.
void restorePeers(bytesConstRef _b);
void registerPeer(std::shared_ptr<EthereumSession> _s);
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { return m_grabbing == Grabbing::Chain; }
private:
void noteHavePeerState(EthereumPeer* _who);
/// Session wants to pass us a block that we might not have.
/// @returns true if we didn't have it.
bool noteBlock(h256 _hash, bytesConstRef _data);
/// Session has finished getting the chain of hashes.
void noteHaveChain(std::shared_ptr<EthereumSession> const& _who);
/// Called when the session has provided us with a new peer we can connect to.
void noteNewPeers() {}
void noteHaveChain(EthereumPeer* _who);
/// Called when the peer can no longer provide us with any needed blocks.
void noteDoneBlocks(EthereumPeer* _who);
void seal(bytes& _b);
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting();
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
void doWork();
/// Called by peer to add incoming transactions.
void addIncomingTransaction(bytes const& _bytes) { std::lock_guard<std::recursive_mutex> l(m_incomingLock); m_incomingTransactions.push_back(_bytes); }
void growPeers();
void prunePeers();
void maintainTransactions(TransactionQueue& _tq, h256 _currentBlock);
void maintainBlocks(BlockQueue& _bq, h256 _currentBlock);
/// Get a bunch of needed blocks.
/// Removes them from our list of needed blocks.
/// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch.
h256Set neededBlocks();
h256Set neededBlocks(h256Set const& _exclude);
/// Check to see if the network peer-state initialisation has happened.
virtual bool isInitialised() const { return m_latestBlockSent; }
bool isInitialised() const { return m_latestBlockSent; }
/// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(TransactionQueue& _tq);
std::map<Public, bi::tcp::endpoint> potentialPeers();
virtual void onStarting() { startWorking(); }
virtual void onStopping() { stopWorking(); }
std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full;
void readyForSync();
void updateGrabbing(Grabbing _g);
unsigned short m_listenPort;
BlockChain const* m_chain = nullptr;
ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor;
bi::tcp::socket m_socket;
UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public;
KeyPair m_key;
BlockChain const& m_chain;
TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue& m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
u256 m_networkId;
mutable std::mutex x_peers;
mutable std::map<Public, std::weak_ptr<EthereumSession>> m_peers; // mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
Grabbing m_grabbing = Grabbing::Nothing; // TODO: needs to be thread-safe & switch to just having a peer id.
mutable std::recursive_mutex m_incomingLock;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers;
std::vector<Public> m_freePeers;
mutable std::mutex x_blocksNeeded;
u256 m_totalDifficultyOfNeeded;
h256s m_blocksNeeded; /// From latest to earliest.
h256Set m_blocksOnWay;
DownloadMan m_man;
h256 m_latestBlockSent;
std::set<h256> m_transactionsSent;
std::chrono::steady_clock::time_point m_lastPeersRequest;
unsigned m_idealPeerCount = 5;
std::vector<bi::address_v4> m_addresses;
std::vector<bi::address_v4> m_peerAddresses;
bool m_accepting = false;
h256Set m_transactionsSent;
};
}
}

334
libethereum/EthereumPeer.cpp

@ -0,0 +1,334 @@
/*
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 EthereumPeer.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "EthereumPeer.h"
#include <chrono>
#include <libdevcore/Common.h>
#include <libethcore/Exceptions.h>
#include <libp2p/Session.h>
#include "BlockChain.h"
#include "EthereumHost.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace p2p;
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h):
Capability(_s, _h),
m_sub(host()->m_man)
{
setGrabbing(Grabbing::State);
sendStatus();
}
EthereumPeer::~EthereumPeer()
{
giveUpOnFetch();
}
EthereumHost* EthereumPeer::host() const
{
return static_cast<EthereumHost*>(Capability::hostCapability());
}
void EthereumPeer::sendStatus()
{
RLPStream s;
prep(s);
s.appendList(6) << StatusPacket
<< host()->protocolVersion()
<< host()->networkId()
<< host()->m_chain.details().totalDifficulty
<< host()->m_chain.currentHash()
<< host()->m_chain.genesisHash();
sealAndSend(s);
}
void EthereumPeer::startInitialSync()
{
// Grab transactions off them.
{
RLPStream s;
prep(s).appendList(1);
s << GetTransactionsPacket;
sealAndSend(s);
}
host()->noteHavePeerState(this);
}
void EthereumPeer::tryGrabbingHashChain()
{
// if already done this, then ignore.
if (m_grabbing != Grabbing::State)
{
clogS(NetAllDetail) << "Already synced with this peer.";
return;
}
h256 c = host()->m_chain.currentHash();
unsigned n = host()->m_chain.number();
u256 td = host()->m_chain.details().totalDifficulty;
clogS(NetAllDetail) << "Attempt chain-grab? Latest:" << c.abridged() << ", number:" << n << ", TD:" << td << " versus " << m_totalDifficulty;
if (td >= m_totalDifficulty)
{
clogS(NetAllDetail) << "No. Our chain is better.";
m_grabbing = Grabbing::Nothing;
return; // All good - we have the better chain.
}
// Our chain isn't better - grab theirs.
{
clogS(NetAllDetail) << "Yes. Their chain is better.";
host()->updateGrabbing(Grabbing::Hashes);
m_grabbing = Grabbing::Hashes;
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk;
m_neededBlocks = h256s(1, m_latestHash);
sealAndSend(s);
}
}
void EthereumPeer::giveUpOnFetch()
{
clogS(NetNote) << "GIVE UP FETCH";
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if (m_grabbing == Grabbing::Chain || m_grabbing == Grabbing::ChainHelper)
{
host()->noteDoneBlocks(this);
setGrabbing(Grabbing::Nothing);
}
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
m_sub.doneFetch();
}
bool EthereumPeer::interpret(RLP const& _r)
{
switch (_r[0].toInt<unsigned>())
{
case StatusPacket:
{
m_protocolVersion = _r[1].toInt<unsigned>();
m_networkId = _r[2].toInt<u256>();
m_totalDifficulty = _r[3].toInt<u256>();
m_latestHash = _r[4].toHash<h256>();
auto genesisHash = _r[5].toHash<h256>();
clogS(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash.abridged() << ", TD:" << m_totalDifficulty << "=" << m_latestHash.abridged();
if (genesisHash != host()->m_chain.genesisHash())
disable("Invalid genesis hash");
if (m_protocolVersion != host()->protocolVersion())
disable("Invalid protocol version.");
if (m_networkId != host()->networkId())
disable("Invalid network identifier.");
startInitialSync();
break;
}
case GetTransactionsPacket:
{
m_requireTransactions = true;
break;
}
case TransactionsPacket:
{
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << "entries)";
addRating(_r.itemCount() - 1);
lock_guard<recursive_mutex> l(host()->m_incomingLock);
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
host()->addIncomingTransaction(_r[i].data().toBytes());
lock_guard<mutex> l(x_knownTransactions);
m_knownTransactions.insert(sha3(_r[i].data()));
}
break;
}
case GetBlockHashesPacket:
{
h256 later = _r[1].toHash<h256>();
unsigned limit = _r[2].toInt<unsigned>();
clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")";
unsigned c = min<unsigned>(host()->m_chain.number(later), limit);
RLPStream s;
prep(s).appendList(1 + c).append(BlockHashesPacket);
h256 p = host()->m_chain.details(later).parent;
for (unsigned i = 0; i < c && p; ++i, p = host()->m_chain.details(p).parent)
s << p;
sealAndSend(s);
break;
}
case BlockHashesPacket:
{
clogS(NetMessageSummary) << "BlockHashes (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreHashes");
if (m_grabbing != Grabbing::Hashes)
{
cwarn << "Peer giving us hashes when we didn't ask for them.";
break;
}
if (_r.itemCount() == 1)
{
host()->noteHaveChain(this);
return true;
}
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = _r[i].toHash<h256>();
if (host()->m_chain.isKnown(h))
{
host()->noteHaveChain(this);
return true;
}
else
m_neededBlocks.push_back(h);
}
// run through - ask for more.
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_neededBlocks.back() << c_maxHashesAsk;
sealAndSend(s);
break;
}
case GetBlocksPacket:
{
clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << "entries)";
// return the requested blocks.
bytes rlp;
unsigned n = 0;
for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i)
{
auto b = host()->m_chain.block(_r[i].toHash<h256>());
if (b.size())
{
rlp += b;
++n;
}
}
RLPStream s;
sealAndSend(prep(s).appendList(n + 1).append(BlocksPacket).appendRaw(rlp, n));
break;
}
case BlocksPacket:
{
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreBlocks");
if (_r.itemCount() == 1)
{
// Couldn't get any from last batch - probably got to this peer's latest block - just give up.
if (m_grabbing == Grabbing::Chain || m_grabbing == Grabbing::ChainHelper)
giveUpOnFetch();
break;
}
unsigned used = 0;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = BlockInfo::headerHash(_r[i].data());
m_sub.noteBlock(h);
if (host()->noteBlock(h, _r[i].data()))
used++;
Guard l(x_knownBlocks);
m_knownBlocks.insert(h);
}
addRating(used);
unsigned knownParents = 0;
unsigned unknownParents = 0;
if (g_logVerbosity >= NetMessageSummary::verbosity)
{
unsigned ic = _r.itemCount();
for (unsigned i = 1; i < ic; ++i)
{
auto h = BlockInfo::headerHash(_r[i].data());
BlockInfo bi(_r[i].data());
Guard l(x_knownBlocks);
if (!host()->m_chain.details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash))
{
unknownParents++;
clogS(NetAllDetail) << "Unknown parent" << bi.parentHash.abridged() << "of block" << h.abridged();
}
else
{
knownParents++;
clogS(NetAllDetail) << "Known parent" << bi.parentHash.abridged() << "of block" << h.abridged();
}
}
}
clogS(NetMessageSummary) << dec << knownParents << "known parents," << unknownParents << "unknown," << used << "used.";
if (m_grabbing == Grabbing::Chain || m_grabbing == Grabbing::ChainHelper)
continueGettingChain();
break;
}
default:
return false;
}
return true;
}
void EthereumPeer::ensureGettingChain()
{
if (m_grabbing == Grabbing::ChainHelper)
return; // Already asked & waiting for some.
// Switch to ChainHelper otherwise, unless we're already the Chain grabber.
if (m_grabbing != Grabbing::Chain)
setGrabbing(Grabbing::ChainHelper);
continueGettingChain();
}
void EthereumPeer::continueGettingChain()
{
// If we're getting the hashes already, then we shouldn't be asking for the chain.
if (m_grabbing == Grabbing::Hashes)
return;
auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
if (blocks.size())
{
RLPStream s;
prep(s);
s.appendList(blocks.size() + 1) << GetBlocksPacket;
for (auto const& i: blocks)
s << i;
sealAndSend(s);
}
else
giveUpOnFetch();
}
void EthereumPeer::setGrabbing(Grabbing _g)
{
m_grabbing = _g;
session()->addNote("grab", _g == Grabbing::Nothing ? "nothing" : _g == Grabbing::State ? "state" : _g == Grabbing::Hashes ? "hashes" : _g == Grabbing::Chain ? "chain" : _g == Grabbing::ChainHelper ? "chainhelper" : "?");
}

96
libethereum/EthereumPeer.h

@ -0,0 +1,96 @@
/*
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 EthereumPeer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <mutex>
#include <array>
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcore/RangeMask.h>
#include <libethcore/CommonEth.h>
#include <libp2p/Capability.h>
#include "CommonNet.h"
#include "DownloadMan.h"
namespace dev
{
namespace eth
{
/**
* @brief The EthereumPeer class
* @todo Document fully.
*/
class EthereumPeer: public p2p::Capability
{
friend class EthereumHost;
public:
EthereumPeer(p2p::Session* _s, p2p::HostCapabilityFace* _h);
virtual ~EthereumPeer();
static std::string name() { return "eth"; }
EthereumHost* host() const;
private:
virtual bool interpret(RLP const& _r);
void sendStatus();
void startInitialSync();
void tryGrabbingHashChain();
/// Ensure that we are waiting for a bunch of blocks from our peer.
void ensureGettingChain();
/// Ensure that we are waiting for a bunch of blocks from our peer.
void continueGettingChain();
void giveUpOnFetch();
void clearKnownTransactions() { std::lock_guard<std::mutex> l(x_knownTransactions); m_knownTransactions.clear(); }
void setGrabbing(Grabbing _g);
unsigned m_protocolVersion;
u256 m_networkId;
Grabbing m_grabbing;
h256 m_latestHash; ///< Peer's latest block's hash.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
h256s m_neededBlocks; ///< The blocks that we should download from this peer.
bool m_requireTransactions;
Mutex x_knownBlocks;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
std::mutex x_knownTransactions;
DownloadSub m_sub;
};
}
}

628
libethereum/EthereumSession.cpp

@ -1,628 +0,0 @@
/*
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 EthereumSession.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "EthereumSession.h"
#include <chrono>
#include <libethential/Common.h>
#include <libethcore/Exceptions.h>
#include "BlockChain.h"
#include "EthereumHost.h"
using namespace std;
using namespace eth;
#define clogS(X) eth::LogOutputStream<X, true>(false) << "| " << std::setw(2) << m_socket.native_handle() << "] "
EthereumSession::EthereumSession(EthereumHost* _s, bi::tcp::socket _socket, u256 _rNId, bi::address _peerAddress, unsigned short _peerPort):
m_server(_s),
m_socket(std::move(_socket)),
m_reqNetworkId(_rNId),
m_listenPort(_peerPort),
m_rating(0)
{
m_disconnect = std::chrono::steady_clock::time_point::max();
m_connect = std::chrono::steady_clock::now();
m_info = PeerInfo({"?", _peerAddress.to_string(), m_listenPort, std::chrono::steady_clock::duration(0)});
}
EthereumSession::~EthereumSession()
{
giveUpOnFetch();
// Read-chain finished for one reason or another.
try
{
if (m_socket.is_open())
m_socket.close();
}
catch (...){}
}
string toString(h256s const& _bs)
{
ostringstream out;
out << "[ ";
for (auto i: _bs)
out << i.abridged() << ", ";
out << "]";
return out.str();
}
void EthereumSession::giveUpOnFetch()
{
clogS(NetNote) << "GIVE UP FETCH; can't get " << toString(m_askedBlocks);
if (m_askedBlocks.size())
{
Guard l (m_server->x_blocksNeeded);
m_server->m_blocksNeeded.reserve(m_server->m_blocksNeeded.size() + m_askedBlocks.size());
for (auto i: m_askedBlocks)
{
m_server->m_blocksOnWay.erase(i);
m_server->m_blocksNeeded.push_back(i);
}
m_askedBlocks.clear();
}
}
bi::tcp::endpoint EthereumSession::endpoint() const
{
if (m_socket.is_open())
try
{
return bi::tcp::endpoint(m_socket.remote_endpoint().address(), m_listenPort);
}
catch (...){}
return bi::tcp::endpoint();
}
bool EthereumSession::interpret(RLP const& _r)
{
clogS(NetRight) << _r;
switch (_r[0].toInt<unsigned>())
{
case HelloPacket:
{
m_protocolVersion = _r[1].toInt<uint>();
m_networkId = _r[2].toInt<u256>();
auto clientVersion = _r[3].toString();
m_caps = _r[4].toInt<uint>();
m_listenPort = _r[5].toInt<unsigned short>();
m_id = _r[6].toHash<h512>();
m_totalDifficulty = _r[7].toInt<u256>();
m_latestHash = _r[8].toHash<h256>();
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort;
if (m_server->havePeer(m_id))
{
// Already connected.
cwarn << "Already have peer id" << m_id.abridged();// << "at" << l->endpoint() << "rather than" << endpoint();
disconnect(DuplicatePeer);
return false;
}
if (m_protocolVersion != EthereumHost::protocolVersion() || m_networkId != m_server->networkId() || !m_id)
{
disconnect(IncompatibleProtocol);
return false;
}
try
{ m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), m_listenPort, std::chrono::steady_clock::duration()}); }
catch (...)
{
disconnect(BadProtocol);
return false;
}
m_server->registerPeer(shared_from_this());
startInitialSync();
// Grab trsansactions off them.
{
RLPStream s;
prep(s).appendList(1);
s << GetTransactionsPacket;
sealAndSend(s);
}
break;
}
case DisconnectPacket:
{
string reason = "Unspecified";
if (_r[1].isInt())
reason = reasonOf((DisconnectReason)_r[1].toInt<int>());
clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
if (m_socket.is_open())
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
else
clogS(NetNote) << "Remote closed.";
m_socket.close();
return false;
}
case PingPacket:
{
clogS(NetTriviaSummary) << "Ping";
RLPStream s;
sealAndSend(prep(s).appendList(1) << PongPacket);
break;
}
case PongPacket:
m_info.lastPing = std::chrono::steady_clock::now() - m_ping;
clogS(NetTriviaSummary) << "Latency: " << chrono::duration_cast<chrono::milliseconds>(m_info.lastPing).count() << " ms";
break;
case GetPeersPacket:
{
clogS(NetTriviaSummary) << "GetPeers";
auto peers = m_server->potentialPeers();
RLPStream s;
prep(s).appendList(peers.size() + 1);
s << PeersPacket;
for (auto i: peers)
{
clogS(NetTriviaDetail) << "Sending peer " << i.first.abridged() << i.second;
s.appendList(3) << bytesConstRef(i.second.address().to_v4().to_bytes().data(), 4) << i.second.port() << i.first;
}
sealAndSend(s);
break;
}
case PeersPacket:
clogS(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)";
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
bi::address_v4 peerAddress(_r[i][0].toHash<FixedHash<4>>().asArray());
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt<short>());
Public id = _r[i][2].toHash<Public>();
if (isPrivateAddress(peerAddress))
goto CONTINUE;
clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")";
// check that it's not us or one we already know:
if (id && (m_server->m_key.pub() == id || m_server->havePeer(id) || m_server->m_incomingPeers.count(id)))
goto CONTINUE;
// check that we're not already connected to addr:
if (!ep.port())
goto CONTINUE;
for (auto i: m_server->m_addresses)
if (ep.address() == i && ep.port() == m_server->listenPort())
goto CONTINUE;
for (auto i: m_server->m_incomingPeers)
if (i.second.first == ep)
goto CONTINUE;
m_server->m_incomingPeers[id] = make_pair(ep, 0);
m_server->m_freePeers.push_back(id);
m_server->noteNewPeers();
clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id << ")";
CONTINUE:;
}
break;
case TransactionsPacket:
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << " entries)";
m_rating += _r.itemCount() - 1;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
m_server->m_incomingTransactions.push_back(_r[i].data().toBytes());
m_knownTransactions.insert(sha3(_r[i].data()));
}
break;
case GetBlockHashesPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
h256 later = _r[1].toHash<h256>();
unsigned limit = _r[2].toInt<unsigned>();
clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries, " << later.abridged() << ")";
unsigned c = min<unsigned>(m_server->m_chain->number(later), limit);
RLPStream s;
prep(s).appendList(1 + c).append(BlockHashesPacket);
h256 p = m_server->m_chain->details(later).parent;
for (unsigned i = 0; i < c; ++i, p = m_server->m_chain->details(p).parent)
s << p;
sealAndSend(s);
break;
}
case BlockHashesPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "BlockHashes (" << dec << (_r.itemCount() - 1) << " entries)";
if (_r.itemCount() == 1)
{
m_server->noteHaveChain(shared_from_this());
return true;
}
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = _r[i].toHash<h256>();
if (m_server->m_chain->details(h))
{
m_server->noteHaveChain(shared_from_this());
return true;
}
else
m_neededBlocks.push_back(h);
}
// run through - ask for more.
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_neededBlocks.back() << c_maxHashesAsk;
sealAndSend(s);
break;
}
case GetBlocksPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << " entries)";
// TODO: return the requested blocks.
bytes rlp;
unsigned n = 0;
for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i)
{
auto b = m_server->m_chain->block(_r[i].toHash<h256>());
if (b.size())
{
rlp += b;
++n;
}
}
RLPStream s;
sealAndSend(prep(s).appendList(n + 1).append(BlocksPacket).appendRaw(rlp, n));
break;
}
case BlocksPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << " entries)";
if (_r.itemCount() == 1)
{
// Couldn't get any from last batch - probably got to this peer's latest block - just give up.
giveUpOnFetch();
break;
}
unsigned used = 0;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = sha3(_r[i].data());
if (m_server->noteBlock(h, _r[i].data()))
used++;
m_askedBlocks.erase(h);
m_knownBlocks.insert(h);
}
m_rating += used;
unsigned knownParents = 0;
unsigned unknownParents = 0;
if (g_logVerbosity >= NetMessageSummary::verbosity)
{
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = sha3(_r[i].data());
BlockInfo bi(_r[i].data());
if (!m_server->m_chain->details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash))
{
unknownParents++;
clogS(NetAllDetail) << "Unknown parent " << bi.parentHash << " of block " << h;
}
else
{
knownParents++;
clogS(NetAllDetail) << "Known parent " << bi.parentHash << " of block " << h;
}
}
}
clogS(NetMessageSummary) << dec << knownParents << " known parents, " << unknownParents << "unknown, " << used << "used.";
ensureGettingChain();
break;
}
case GetTransactionsPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
m_requireTransactions = true;
break;
}
default:
break;
}
return true;
}
void EthereumSession::ensureGettingChain()
{
if (!m_askedBlocks.size())
m_askedBlocks = m_server->neededBlocks();
if (m_askedBlocks.size())
{
RLPStream s;
prep(s);
s.appendList(m_askedBlocks.size() + 1) << GetBlocksPacket;
for (auto i: m_askedBlocks)
s << i;
sealAndSend(s);
}
else
clogS(NetMessageSummary) << "No blocks left to get.";
}
void EthereumSession::ping()
{
RLPStream s;
sealAndSend(prep(s).appendList(1) << PingPacket);
m_ping = std::chrono::steady_clock::now();
}
void EthereumSession::getPeers()
{
RLPStream s;
sealAndSend(prep(s).appendList(1) << GetPeersPacket);
}
RLPStream& EthereumSession::prep(RLPStream& _s)
{
return _s.appendRaw(bytes(8, 0));
}
void EthereumSession::sealAndSend(RLPStream& _s)
{
bytes b;
_s.swapOut(b);
m_server->seal(b);
sendDestroy(b);
}
bool EthereumSession::checkPacket(bytesConstRef _msg)
{
if (_msg.size() < 8)
return false;
if (!(_msg[0] == 0x22 && _msg[1] == 0x40 && _msg[2] == 0x08 && _msg[3] == 0x91))
return false;
uint32_t len = ((_msg[4] * 256 + _msg[5]) * 256 + _msg[6]) * 256 + _msg[7];
if (_msg.size() != len + 8)
return false;
RLP r(_msg.cropped(8));
if (r.actualSize() != len)
return false;
return true;
}
void EthereumSession::sendDestroy(bytes& _msg)
{
clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
if (!checkPacket(bytesConstRef(&_msg)))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
bytes buffer = bytes(std::move(_msg));
writeImpl(buffer);
}
void EthereumSession::send(bytesConstRef _msg)
{
clogS(NetLeft) << RLP(_msg.cropped(8));
if (!checkPacket(_msg))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
bytes buffer = bytes(_msg.toBytes());
writeImpl(buffer);
}
void EthereumSession::writeImpl(bytes& _buffer)
{
// cerr << (void*)this << " writeImpl" << endl;
if (!m_socket.is_open())
return;
lock_guard<recursive_mutex> l(m_writeLock);
m_writeQueue.push_back(_buffer);
if (m_writeQueue.size() == 1)
write();
}
void EthereumSession::write()
{
// cerr << (void*)this << " write" << endl;
lock_guard<recursive_mutex> l(m_writeLock);
if (m_writeQueue.empty())
return;
const bytes& bytes = m_writeQueue[0];
auto self(shared_from_this());
ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/)
{
// cerr << (void*)this << " write.callback" << endl;
// must check queue, as write callback can occur following dropped()
if (ec)
{
cwarn << "Error sending: " << ec.message();
dropped();
}
else
{
m_writeQueue.pop_front();
write();
}
});
}
void EthereumSession::dropped()
{
// cerr << (void*)this << " dropped" << endl;
if (m_socket.is_open())
try
{
clogS(NetConnect) << "Closing " << m_socket.remote_endpoint();
m_socket.close();
}
catch (...) {}
}
void EthereumSession::disconnect(int _reason)
{
clogS(NetConnect) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")";
if (m_socket.is_open())
{
if (m_disconnect == chrono::steady_clock::time_point::max())
{
RLPStream s;
prep(s);
s.appendList(2) << DisconnectPacket << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
else
dropped();
}
}
void EthereumSession::start()
{
RLPStream s;
prep(s);
s.appendList(9) << HelloPacket
<< (uint)EthereumHost::protocolVersion()
<< m_server->networkId()
<< m_server->m_clientVersion
<< (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0)
<< m_server->m_public.port()
<< m_server->m_key.pub()
<< m_server->m_chain->details().totalDifficulty
<< m_server->m_chain->currentHash();
sealAndSend(s);
ping();
getPeers();
doRead();
}
void EthereumSession::startInitialSync()
{
h256 c = m_server->m_chain->currentHash();
uint n = m_server->m_chain->number();
u256 td = max(m_server->m_chain->details().totalDifficulty, m_server->m_totalDifficultyOfNeeded);
clogS(NetAllDetail) << "Initial sync. Latest:" << c.abridged() << ", number:" << n << ", TD: max(" << m_server->m_chain->details().totalDifficulty << "," << m_server->m_totalDifficultyOfNeeded << ") versus " << m_totalDifficulty;
if (td > m_totalDifficulty)
return; // All good - we have the better chain.
// Our chain isn't better - grab theirs.
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk;
m_neededBlocks = h256s(1, m_latestHash);
sealAndSend(s);
}
void EthereumSession::doRead()
{
// ignore packets received while waiting to disconnect
if (chrono::steady_clock::now() - m_disconnect > chrono::seconds(0))
return;
auto self(shared_from_this());
m_socket.async_read_some(boost::asio::buffer(m_data), [this,self](boost::system::error_code ec, std::size_t length)
{
// If error is end of file, ignore
if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof)
{
// got here with length of 1241...
cwarn << "Error reading: " << ec.message();
dropped();
}
else if (ec && length == 0)
{
return;
}
else
{
try
{
m_incoming.resize(m_incoming.size() + length);
memcpy(m_incoming.data() + m_incoming.size() - length, m_data.data(), length);
while (m_incoming.size() > 8)
{
if (m_incoming[0] != 0x22 || m_incoming[1] != 0x40 || m_incoming[2] != 0x08 || m_incoming[3] != 0x91)
{
cwarn << "INVALID SYNCHRONISATION TOKEN; expected = 22400891; received = " << toHex(bytesConstRef(m_incoming.data(), 4));
disconnect(BadProtocol);
return;
}
else
{
uint32_t len = fromBigEndian<uint32_t>(bytesConstRef(m_incoming.data() + 4, 4));
uint32_t tlen = len + 8;
if (m_incoming.size() < tlen)
break;
// enough has come in.
auto data = bytesConstRef(m_incoming.data(), tlen);
if (!checkPacket(data))
{
cerr << "Received " << len << ": " << toHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
cwarn << "INVALID MESSAGE RECEIVED";
disconnect(BadProtocol);
return;
}
else
{
RLP r(data.cropped(8));
if (!interpret(r))
{
// error
dropped();
return;
}
}
memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen);
m_incoming.resize(m_incoming.size() - tlen);
}
}
doRead();
}
catch (Exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.description();
dropped();
}
catch (std::exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.what();
dropped();
}
}
});
}

116
libethereum/EthereumSession.h

@ -1,116 +0,0 @@
/*
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 EthereumSession.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <mutex>
#include <array>
#include <set>
#include <memory>
#include <utility>
#include <libethential/RLP.h>
#include <libethcore/CommonEth.h>
#include "CommonNet.h"
namespace eth
{
/**
* @brief The EthereumSession class
* @todo Document fully.
*/
class EthereumSession: public std::enable_shared_from_this<EthereumSession>
{
friend class EthereumHost;
public:
EthereumSession(EthereumHost* _server, bi::tcp::socket _socket, u256 _rNId, bi::address _peerAddress, unsigned short _peerPort = 0);
~EthereumSession();
void start();
void disconnect(int _reason);
void ping();
bool isOpen() const { return m_socket.is_open(); }
bi::tcp::endpoint endpoint() const; ///< for other peers to connect to.
private:
void startInitialSync();
void getPeers();
/// Ensure that we are waiting for a bunch of blocks from our peer.
void ensureGettingChain();
void giveUpOnFetch();
void dropped();
void doRead();
void doWrite(std::size_t length);
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytesConstRef _msg);
void writeImpl(bytes& _buffer);
void write();
EthereumHost* m_server;
std::recursive_mutex m_writeLock;
std::deque<bytes> m_writeQueue;
bi::tcp::socket m_socket;
std::array<byte, 65536> m_data;
PeerInfo m_info;
Public m_id;
bytes m_incoming;
uint m_protocolVersion;
u256 m_networkId;
u256 m_reqNetworkId;
unsigned short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers.
uint m_caps;
h256 m_latestHash; ///< Peer's latest block's hash.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
h256s m_neededBlocks; ///< The blocks that we should download from this peer.
h256Set m_askedBlocks; ///< The blocks for which we sent the last GetBlocks for but haven't received a corresponding Blocks.
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
uint m_rating;
bool m_requireTransactions;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand.
};
}

14
libethereum/Executive.cpp

@ -25,7 +25,8 @@
#include "State.h"
#include "ExtVM.h"
using namespace std;
using namespace eth;
using namespace dev;
using namespace dev::eth;
#define ETH_VMTRACE 1
@ -85,7 +86,7 @@ bool Executive::setup(bytesConstRef _rlp)
if (startGasUsed + m_t.gas > m_s.m_currentBlock.gasLimit)
{
clog(StateChat) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas;
// throw BlockGasLimitReached();
throw BlockGasLimitReached();
}
// Increment associated nonce for sender.
@ -130,11 +131,9 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// We can allow for the reverted state (i.e. that with which m_ext is constructed) to contain the m_newAddress, since
// we delete it explicitly if we decide we need to revert.
m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));
while (m_s.addressInUse(m_newAddress))
m_newAddress = (u160)m_newAddress + 1;
// Set up new account...
m_s.m_cache[m_newAddress] = AddressState(0, _endowment, h256(), h256());
m_s.m_cache[m_newAddress] = AddressState(0, m_s.balance(m_newAddress) + _endowment, h256(), h256());
// Execute _init.
m_vm = new VM(_gas);
@ -157,8 +156,8 @@ OnOpFunc Executive::simpleTrace()
o << " STORAGE" << endl;
for (auto const& i: ext.state().storage(ext.myAddress))
o << showbase << hex << i.first << ": " << i.second << endl;
eth::LogOutputStream<VMTraceChannel, false>(true) << o.str();
eth::LogOutputStream<VMTraceChannel, false>(false) << " | " << dec << ext.level << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]";
dev::LogOutputStream<VMTraceChannel, false>(true) << o.str();
dev::LogOutputStream<VMTraceChannel, false>(false) << " | " << dec << ext.level << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]";
};
}
@ -186,6 +185,7 @@ bool Executive::go(OnOpFunc const& _onOp)
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << _e.description();
m_endGas = m_vm->gas();
}
catch (Exception const& _e)
{

5
libethereum/Executive.h

@ -22,13 +22,15 @@
#pragma once
#include <functional>
#include <libethential/Log.h>
#include <libdevcore/Log.h>
#include <libevmface/Instruction.h>
#include <libethcore/CommonEth.h>
#include <libevm/ExtVMFace.h>
#include "Transaction.h"
#include "Manifest.h"
namespace dev
{
namespace eth
{
@ -78,3 +80,4 @@ private:
};
}
}

13
libethereum/ExtVM.h

@ -27,6 +27,8 @@
#include <libevm/ExtVMFace.h>
#include "State.h"
namespace dev
{
namespace eth
{
@ -49,6 +51,9 @@ public:
/// Write a value in storage.
void setStore(u256 _n, u256 _v) { m_s.setStorage(myAddress, _n, _v); if (m_ms) m_ms->altered.push_back(_n); }
/// Read address's code.
bytes const& codeAt(Address _a) { return m_s.code(_a); }
/// Create a new contract.
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, OnOpFunc const& _onOp = OnOpFunc())
{
@ -62,12 +67,12 @@ public:
return ret;
}
/// Create a new message call. Leave _myAddressOverride at he default to use the present address as caller.
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out, OnOpFunc const& _onOp = OnOpFunc(), Address _myAddressOverride = Address())
/// Create a new message call. Leave _myAddressOverride as the default to use the present address as caller.
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out, OnOpFunc const& _onOp = OnOpFunc(), Address _myAddressOverride = Address(), Address _codeAddressOverride = Address())
{
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.call(_receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, &posts, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, &posts, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
@ -119,5 +124,5 @@ private:
};
}
}

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

Loading…
Cancel
Save