Browse Source

Merge branch 'develop' of https://github.com/ethereum/cpp-ethereum into

mix_test

Conflicts:
	mix/qml/WebCodeEditor.qml
cl-refactor
arkpar 10 years ago
parent
commit
4fe38fa033
  1. 283
      abi/main.cpp
  2. 5
      alethzero/CMakeLists.txt
  3. 63
      alethzero/Connect.cpp
  4. 55
      alethzero/Connect.h
  5. 123
      alethzero/Connect.ui
  6. 3
      alethzero/Debugger.cpp
  7. 74
      alethzero/Main.ui
  8. 76
      alethzero/MainWin.cpp
  9. 3
      alethzero/MainWin.h
  10. 4
      alethzero/Transact.cpp
  11. 31
      eth/main.cpp
  12. 12
      libdevcore/CommonData.h
  13. 1
      libdevcore/FixedHash.h
  14. 16
      libethcore/Ethasher.cpp
  15. 1
      libethcore/Exceptions.h
  16. 69
      libethereum/BlockChain.cpp
  17. 47
      libethereum/BlockChain.h
  18. 2
      libethereum/Client.h
  19. 4
      libethereum/ClientBase.cpp
  20. 2
      libethereum/EthereumHost.cpp
  21. 78
      libethereum/Executive.cpp
  22. 41
      libethereum/Executive.h
  23. 6
      libethereum/Interface.h
  24. 87
      libethereum/State.cpp
  25. 8
      libethereum/State.h
  26. 10
      libethereum/TransactionQueue.cpp
  27. 11
      libethereum/TransactionQueue.h
  28. 7
      libp2p/Common.cpp
  29. 3
      libp2p/Common.h
  30. 173
      libp2p/Host.cpp
  31. 33
      libp2p/Host.h
  32. 108
      libp2p/Network.cpp
  33. 26
      libp2p/Network.h
  34. 27
      libp2p/NodeTable.cpp
  35. 2
      libp2p/NodeTable.h
  36. 1
      libp2p/Peer.h
  37. 8
      libp2p/Session.cpp
  38. 7
      libp2p/UDP.h
  39. 5
      libtestutils/CMakeLists.txt
  40. 2
      libtestutils/Common.cpp
  41. 8
      libtestutils/TransientDirectory.cpp
  42. 3
      libtestutils/TransientDirectory.h
  43. 16
      libwebthree/WebThree.cpp
  44. 37
      libwebthree/WebThree.h
  45. 5
      mix/MixClient.cpp
  46. 2
      mix/qml/CodeEditorView.qml
  47. 5
      mix/qml/ProjectModel.qml
  48. 2
      mix/qml/TransactionLog.qml
  49. 67
      mix/qml/WebCodeEditor.qml
  50. 15
      mix/qml/html/cm/errorannotation.js
  51. 79
      mix/qml/js/ProjectModel.js
  52. 386
      mix/test/qml/TestTransactionDebug.qml
  53. 30
      neth/main.cpp
  54. 57
      test/blockchain.cpp
  55. 3
      test/checkRandomStateTest.cpp
  56. 3
      test/createRandomStateTest.cpp
  57. 14
      test/peer.cpp
  58. 3
      test/solidityExecutionFramework.h
  59. 3
      test/state.cpp
  60. 10
      test/stateOriginal.cpp

283
abi/main.cpp

@ -43,8 +43,8 @@ void help()
<< " -h,--help Print this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl
<< "Input options:" << endl
<< " -p,--prefix Require all input formats to be prefixed e.g. 0x for hex, . for decimal, @ for binary." << endl
<< " -P,--no-prefix Require no input format to be prefixed." << endl
<< " -f,--format-prefix Require all input formats to be prefixed e.g. 0x for hex, . for decimal, @ for binary." << endl
<< " -F,--no-format-prefix Require no input format to be prefixed." << endl
<< " -t,--typing Require all arguments to be typed e.g. b32: (bytes32), u64: (uint64), b[]: (byte[]), i: (int256)." << endl
<< " -T,--no-typing Require no arguments to be typed." << endl
<< "Output options:" << endl
@ -53,8 +53,6 @@ void help()
<< " -x,--hex Display all data as hex." << endl
<< " -b,--binary Display all data as binary." << endl
<< " -p,--prefix Prefix by a base identifier." << endl
<< " -z,--no-zeroes Remove any leading zeroes from the data." << endl
<< " -n,--no-nulls Remove any trailing nulls from the data." << endl
;
exit(0);
}
@ -90,7 +88,9 @@ enum class Format
{
Binary,
Hex,
Decimal
Decimal,
Open,
Close
};
struct InvalidUserString: public Exception {};
@ -115,6 +115,12 @@ static const map<Base, string> s_bases =
{ Base::Fixed, "fixed" }
};
struct EncodingPrefs
{
Encoding e = Encoding::Auto;
bool prefix = true;
};
struct ABIType
{
Base base = Base::Unknown;
@ -204,39 +210,72 @@ struct ABIType
bool isBytes() const { return base == Base::Bytes && !size; }
string render(bytes const& _data) const
string render(bytes const& _data, EncodingPrefs _e) const
{
if (base == Base::Uint)
return toString(fromBigEndian<u256>(_data));
else if (base == Base::Int)
return toString((s256)fromBigEndian<u256>(_data));
if (base == Base::Uint || base == Base::Int)
{
if (_e.e == Encoding::Hex)
return (_e.prefix ? "0x" : "") + toHex(toCompactBigEndian(fromBigEndian<bigint>(bytesConstRef(&_data).cropped(32 - size / 8))));
else
{
bigint i = fromBigEndian<bigint>(bytesConstRef(&_data).cropped(32 - size / 8));
if (base == Base::Int && i > (bigint(1) << (size - 1)))
i -= (bigint(1) << size);
return toString(i);
}
}
else if (base == Base::Address)
return toString(Address(h256(_data)));
{
Address a = Address(h256(_data), Address::AlignRight);
return _e.e == Encoding::Binary ? asString(a.asBytes()) : ((_e.prefix ? "0x" : "") + toString(a));
}
else if (isBytes())
{
return _e.e == Encoding::Binary ? asString(_data) : ((_e.prefix ? "0x" : "") + toHex(_data));
}
else if (base == Base::Bytes)
{
bytesConstRef b(&_data);
b = b.cropped(0, size);
return _e.e == Encoding::Binary ? asString(b) : ((_e.prefix ? "0x" : "") + toHex(b));
}
else
throw InvalidFormat();
}
bytes unrender(bytes const& _data, Format _f) const
{
if (isBytes())
{
auto ret = _data;
while (ret.size() % 32 != 0)
ret.push_back(0);
return ret;
}
else
return toHex(_data);
return aligned(_data, _f, 32);
}
void noteHexInput(unsigned _nibbles) { if (base == Base::Unknown) { if (_nibbles == 40) base = Base::Address; else { base = Base::Bytes; size = _nibbles / 2; } } }
void noteBinaryInput() { if (base == Base::Unknown) { base = Base::Bytes; size = 32; } }
void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } }
};
bytes aligned(bytes const& _b, ABIType _t, Format _f, unsigned _length)
{
(void)_t;
bytes ret = _b;
while (ret.size() < _length)
if (_f == Format::Binary)
ret.push_back(0);
else
ret.insert(ret.begin(), 0);
while (ret.size() > _length)
if (_f == Format::Binary)
ret.pop_back();
else
ret.erase(ret.begin());
return ret;
}
bytes aligned(bytes const& _b, Format _f, unsigned _length) const
{
bytes ret = _b;
while (ret.size() < _length)
if (_f == Format::Binary)
ret.push_back(0);
else
ret.insert(ret.begin(), 0);
while (ret.size() > _length)
if (_f == Format::Binary)
ret.pop_back();
else
ret.erase(ret.begin());
return ret;
}
};
tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix, Tristate _typing)
{
@ -269,25 +308,36 @@ tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix
type.noteBinaryInput();
return make_tuple(asBytes(val.substr(1)), type, Format::Binary);
}
if (val == "[")
return make_tuple(bytes(), type, Format::Open);
if (val == "]")
return make_tuple(bytes(), type, Format::Close);
}
if (_prefix != Tristate::True)
{
if (_arg.find_first_not_of("0123456789") == string::npos)
if (val.find_first_not_of("0123456789") == string::npos)
{
type.noteDecimalInput();
return make_tuple(toCompactBigEndian(bigint(val)), type, Format::Decimal);
}
if (_arg.find_first_not_of("0123456789abcdefABCDEF") == string::npos)
if (val.find_first_not_of("0123456789abcdefABCDEF") == string::npos)
{
type.noteHexInput(val.size());
return make_tuple(fromHex(val), type, Format::Hex);
}
if (val == "[")
return make_tuple(bytes(), type, Format::Open);
if (val == "]")
return make_tuple(bytes(), type, Format::Close);
type.noteBinaryInput();
return make_tuple(asBytes(_arg), type, Format::Binary);
return make_tuple(asBytes(val), type, Format::Binary);
}
throw InvalidUserString();
}
struct ExpectedOpen: public Exception {};
struct ExpectedClose: public Exception {};
struct ABIMethod
{
string name;
@ -355,77 +405,107 @@ struct ABIMethod
bytes encode(vector<pair<bytes, Format>> const& _params) const
{
// ALL WRONG!!!!
// INARITIES SHOULD BE HEIRARCHICAL!
bytes ret = name.empty() ? bytes() : id().asBytes();
bytes suffix;
// int int[] int
// example: 42 [ 1 2 3 ] 69
// int[2][][3]
// example: [ [ [ 1 2 3 ] [ 4 5 6 ] ] [ ] ]
unsigned pi = 0;
vector<unsigned> inArity;
for (ABIType const& i: ins)
{
unsigned arity = 1;
for (auto j: i.dims)
if (j == -1)
{
ret += aligned(_params[pi].first, ABIType(), Format::Decimal, 32);
arity *= fromBigEndian<unsigned>(_params[pi].first);
pi++;
}
else
arity *= j;
if (i.isBytes())
for (unsigned i = 0; i < arity; ++i)
inArity.push_back(arity);
}
unsigned ii = 0;
for (ABIType const& i: ins)
for (ABIType const& a: ins)
{
for (unsigned j = 0; j < inArity[ii]; ++j)
{
if (i.base == Base::Bytes && !i.size)
auto put = [&]() {
if (a.isBytes())
ret += h256(u256(_params[pi].first.size())).asBytes();
suffix += a.unrender(_params[pi].first, _params[pi].second);
pi++;
};
function<void(vector<int>, unsigned)> putDim = [&](vector<int> addr, unsigned q) {
if (addr.size() == a.dims.size())
put();
else
{
ret += _params[pi].first;
while (ret.size() % 32 != 0)
ret.push_back(0);
if (_params[pi].second != Format::Open)
throw ExpectedOpen();
int l = a.dims[addr.size()];
if (l == -1)
{
// read ahead in params and discover the arity.
unsigned depth = 0;
l = 0;
for (unsigned pi2 = pi + 1; depth || _params[pi2].second != Format::Close;)
{
if (_params[pi2].second == Format::Open)
++depth;
if (_params[pi2].second == Format::Close)
--depth;
if (!depth)
++l;
if (++pi2 == _params.size())
throw ExpectedClose();
}
ret += h256(u256(l)).asBytes();
}
q *= l;
for (addr.push_back(0); addr.back() < l; ++addr.back())
putDim(addr, q);
if (_params[pi].second != Format::Close)
throw ExpectedClose();
}
else
ret += aligned(_params[pi].first, i, _params[pi].second, 32);
++pi;
}
++ii;
};
putDim(vector<int>(), 1);
}
return ret;
return ret + suffix;
}
string decode(bytes const& _data, int _index = -1)
string decode(bytes const& _data, int _index, EncodingPrefs _ep)
{
stringstream out;
if (_index == -1)
out << "[";
unsigned di = 0;
vector<ABIType> souts;
vector<unsigned> catDims;
for (ABIType a: outs)
for (ABIType const& a: outs)
{
unsigned q = 1;
for (auto& i: a.dims)
{
for (unsigned j = 0; j < q; ++j)
if (i == -1)
auto put = [&]() {
if (a.isBytes())
{
catDims.push_back(fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32)));
di += 32;
}
};
function<void(vector<int>, unsigned)> putDim = [&](vector<int> addr, unsigned q) {
if (addr.size() == a.dims.size())
put();
else
{
out << "[";
int l = a.dims[addr.size()];
if (l == -1)
{
catDims.push_back(fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32)));
l = fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32));
catDims.push_back(l);
di += 32;
}
q *= i;
}
if (a.isBytes())
souts.push_back(a);
q *= l;
for (addr.push_back(0); addr.back() < l; ++addr.back())
putDim(addr, q);
out << "]";
}
};
putDim(vector<int>(), 1);
}
for (ABIType const& a: souts)
unsigned d = 0;
for (ABIType const& a: outs)
{
auto put = [&]() {
out << a.render(bytesConstRef(&_data).cropped(di, 32).toBytes()) << ", ";
di += 32;
unsigned l = 32;
if (a.isBytes())
l = (catDims[d++] + 31 / 32) * 32;
out << a.render(bytesConstRef(&_data).cropped(di, l).toBytes(), _ep) << ", ";
di += l;
};
function<void(vector<int>)> putDim = [&](vector<int> addr) {
if (addr.size() == a.dims.size())
@ -433,9 +513,11 @@ struct ABIMethod
else
{
out << "[";
auto d = addr;
addr.push_back(0);
for (addr.back() = 0; addr.back() < a.dims[addr.size() - 1]; ++addr.back())
int l = a.dims[addr.size() - 1];
if (l == -1)
l = catDims[d++];
for (addr.back() = 0; addr.back() < l; ++addr.back())
{
if (addr.back())
out << ", ";
@ -543,10 +625,9 @@ int main(int argc, char** argv)
Mode mode = Mode::Encode;
string abiFile;
string method;
Tristate prefix = Tristate::Mu;
Tristate formatPrefix = Tristate::Mu;
Tristate typePrefix = Tristate::Mu;
bool clearZeroes = false;
bool clearNulls = false;
EncodingPrefs prefs;
bool verbose = false;
int outputIndex = -1;
vector<pair<bytes, Format>> params;
@ -566,25 +647,23 @@ int main(int argc, char** argv)
else if ((arg == "-i" || arg == "--index") && argc > i)
outputIndex = atoi(argv[++i]);
else if (arg == "-p" || arg == "--prefix")
prefix = Tristate::True;
else if (arg == "-P" || arg == "--no-prefix")
prefix = Tristate::False;
prefs.prefix = true;
else if (arg == "-f" || arg == "--format-prefix")
formatPrefix = Tristate::True;
else if (arg == "-F" || arg == "--no-format-prefix")
formatPrefix = Tristate::False;
else if (arg == "-t" || arg == "--typing")
typePrefix = Tristate::True;
else if (arg == "-T" || arg == "--no-typing")
typePrefix = Tristate::False;
else if (arg == "-z" || arg == "--no-zeroes")
clearZeroes = true;
else if (arg == "-n" || arg == "--no-nulls")
clearNulls = true;
else if (arg == "-v" || arg == "--verbose")
verbose = true;
else if (arg == "-x" || arg == "--hex")
encoding = Encoding::Hex;
prefs.e = Encoding::Hex;
else if (arg == "-d" || arg == "--decimal" || arg == "--dec")
encoding = Encoding::Decimal;
prefs.e = Encoding::Decimal;
else if (arg == "-b" || arg == "--binary" || arg == "--bin")
encoding = Encoding::Binary;
prefs.e = Encoding::Binary;
else if (arg == "-v" || arg == "--verbose")
version();
else if (arg == "-V" || arg == "--version")
@ -593,7 +672,7 @@ int main(int argc, char** argv)
method = arg;
else
{
auto u = fromUser(arg, prefix, typePrefix);
auto u = fromUser(arg, formatPrefix, typePrefix);
args.push_back(get<1>(u));
params.push_back(make_pair(get<0>(u), get<2>(u)));
}
@ -648,14 +727,8 @@ int main(int argc, char** argv)
string encoded;
for (int i = cin.get(); i != -1; i = cin.get())
encoded.push_back((char)i);
cout << m.decode(fromHex(encoded));
cout << m.decode(fromHex(encoded), outputIndex, prefs);
}
// TODO: read abi to determine output format.
(void)encoding;
(void)clearZeroes;
(void)clearNulls;
(void)outputIndex;
}
return 0;

5
alethzero/CMakeLists.txt

@ -19,6 +19,7 @@ find_package (Qt5WebEngine QUIET)
find_package (Qt5WebEngineWidgets QUIET)
qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Connect.h Connect.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui)
@ -32,8 +33,8 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Debugger.ui Transact.ui
ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui
WIN_RESOURCES alethzero.rc
)

63
alethzero/Connect.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 Connect.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#include "Connect.h"
#include <libp2p/Host.h>
#include "ui_Connect.h"
Connect::Connect(QWidget *parent) :
QDialog(parent),
ui(new Ui::Connect)
{
ui->setupUi(this);
}
Connect::~Connect()
{
delete ui;
}
void Connect::setEnvironment(QStringList const& _nodes)
{
ui->host->addItems(_nodes);
}
void Connect::reset()
{
ui->nodeId->clear();
ui->required->setChecked(false);
}
QString Connect::host()
{
return ui->host->currentText();
}
QString Connect::nodeId()
{
return ui->nodeId->text();
}
bool Connect::required()
{
return ui->required->isChecked();
}

55
alethzero/Connect.h

@ -0,0 +1,55 @@
/*
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 Connect.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#pragma once
#include <QDialog>
#include <QList>
namespace Ui { class Connect; }
namespace dev { namespace p2p { class Host; } }
class Connect : public QDialog
{
Q_OBJECT
public:
explicit Connect(QWidget* _parent = 0);
~Connect();
/// Populate host chooser with default host entries.
void setEnvironment(QStringList const& _nodes);
/// Clear dialogue inputs.
void reset();
/// @returns the host string, as chosen or entered by the user. Assumed to be "hostOrIP:port" (:port is optional).
QString host();
/// @returns the identity of the node, as entered by the user. Assumed to be a 64-character hex string.
QString nodeId();
/// @returns true if Required is checked by the user, indicating that the host is a required Peer.
bool required();
private:
Ui::Connect* ui;
};

123
alethzero/Connect.ui

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Connect</class>
<widget class="QDialog" name="Connect">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>343</width>
<height>178</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>343</width>
<height>178</height>
</size>
</property>
<property name="windowTitle">
<string>Connect to Peer</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="1" column="0">
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="host">
<property name="minimumSize">
<size>
<width>311</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLineEdit" name="nodeId">
<property name="placeholderText">
<string>Node Id</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="required">
<property name="text">
<string>Required (Always Connect to this Peer)</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="formLabel">
<property name="text">
<string>Enter a peer to which a connection may be made:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Connect</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Connect</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

3
alethzero/Debugger.cpp

@ -67,7 +67,8 @@ void Debugger::populate(dev::eth::Executive& _executive, dev::eth::Transaction c
bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction)
{
try {
if (_executive.setup(_transaction))
_executive.initialize(_transaction);
if (_executive.execute())
return false;
}
catch (...)

74
alethzero/Main.ui

@ -118,7 +118,7 @@
<x>0</x>
<y>0</y>
<width>1617</width>
<height>24</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@ -134,8 +134,7 @@
<addaction name="go"/>
<addaction name="separator"/>
<addaction name="upnp"/>
<addaction name="usePast"/>
<addaction name="localNetworking"/>
<addaction name="dropPeers"/>
<addaction name="net"/>
<addaction name="connect"/>
</widget>
@ -284,7 +283,27 @@
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="2">
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Listen on</string>
</property>
<property name="buddy">
<cstring>port</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="port">
<property name="minimum">
<number>1024</number>
@ -297,8 +316,8 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="forceAddress">
<item row="3" column="1">
<widget class="QLineEdit" name="listenIP">
<property name="inputMask">
<string/>
</property>
@ -310,16 +329,6 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Listen on</string>
</property>
<property name="buddy">
<cstring>port</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
@ -330,20 +339,17 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
<item row="5" column="1">
<widget class="QLineEdit" name="forcePublicIP">
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Public IP</string>
</property>
</widget>
</item>
@ -357,6 +363,13 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -1443,12 +1456,12 @@ font-size: 14pt</string>
<string>Show &amp;Anonymous Accounts</string>
</property>
</action>
<action name="usePast">
<action name="dropPeers">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Use &amp;Past Peers</string>
<string>&amp;Drop Past Peers</string>
</property>
</action>
<action name="loadJS">
@ -1694,9 +1707,8 @@ font-size: 14pt</string>
<tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop>
<tabstop>idealPeers</tabstop>
<tabstop>forceAddress</tabstop>
<tabstop>listenIP</tabstop>
<tabstop>port</tabstop>
<tabstop>clientName</tabstop>
<tabstop>transactionQueue</tabstop>
<tabstop>pendingInfo</tabstop>
<tabstop>blockChainFilter</tabstop>

76
alethzero/MainWin.cpp

@ -28,6 +28,7 @@
//pragma GCC diagnostic ignored "-Werror=pedantic"
#include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog>
#include <QtWebEngine/QtWebEngine>
@ -141,7 +142,7 @@ Main::Main(QWidget *parent) :
#endif
#if ETH_DEBUG
m_servers.append("localhost:30300");
m_servers.append("127.0.0.1:30300");
#endif
m_servers.append(QString::fromStdString(Host::pocHost() + ":30303"));
@ -251,7 +252,30 @@ void Main::addNewId(QString _ids)
NetworkPreferences Main::netPrefs() const
{
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked());
auto listenIP = ui->listenIP->text().toStdString();
try
{
listenIP = bi::address::from_string(listenIP).to_string();
}
catch (...)
{
listenIP.clear();
}
auto publicIP = ui->forcePublicIP->text().toStdString();
try
{
publicIP = bi::address::from_string(publicIP).to_string();
}
catch (...)
{
publicIP.clear();
}
if (isPublicAddress(publicIP))
return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
else
return NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked());
}
void Main::onKeysChanged()
@ -675,9 +699,7 @@ void Main::writeSettings()
}
s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forceAddress->text());
s.setValue("usePast", ui->usePast->isChecked());
s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceAddress", ui->forcePublicIP->text());
s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("natSpec", ui->natSpec->isChecked());
@ -685,6 +707,7 @@ void Main::writeSettings()
s.setValue("showAllAccounts", ui->showAllAccounts->isChecked());
s.setValue("clientName", ui->clientName->text());
s.setValue("idealPeers", ui->idealPeers->value());
s.setValue("listenIP", ui->listenIP->text());
s.setValue("port", ui->port->value());
s.setValue("url", ui->urlEdit->text());
s.setValue("privateChain", m_privateChain);
@ -744,9 +767,8 @@ void Main::readSettings(bool _skipGeometry)
}
ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool());
ui->localNetworking->setChecked(s.value("localNetworking", true).toBool());
ui->forcePublicIP->setText(s.value("forceAddress", "").toString());
ui->dropPeers->setChecked(false);
ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool());
@ -757,6 +779,7 @@ void Main::readSettings(bool _skipGeometry)
if (ui->clientName->text().isEmpty())
ui->clientName->setText(QInputDialog::getText(nullptr, "Enter identity", "Enter a name that will identify you on the peer network"));
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->listenIP->setText(s.value("listenIP", "").toString());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString();
@ -1099,7 +1122,7 @@ void Main::refreshBlockChain()
blocks.insert(bc.numberHash(b));
}
else if (f.toLongLong() <= bc.number())
blocks.insert(bc.numberHash(u256(f.toLongLong())));
blocks.insert(bc.numberHash((unsigned)f.toLongLong()));
else if (f.size() == 40)
{
Address h(f.toStdString());
@ -1362,7 +1385,7 @@ void Main::on_transactionQueue_currentItemChanged()
if (!!receipt.bloom())
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
else
s << "<div>Log Bloom: <i>Uneventful</i></div>";
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
@ -1461,7 +1484,7 @@ void Main::on_blocks_currentItemChanged()
if (!!info.logBloom)
s << "<div>Log Bloom: " << info.logBloom << "</div>";
else
s << "<div>Log Bloom: <i>Uneventful</i></div>";
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
s << "<div>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>" << "</div>";
s << "<div>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>" << "</div>";
for (auto u: block[2])
@ -1743,11 +1766,8 @@ void Main::on_net_triggered()
if (ui->net->isChecked())
{
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
// TODO: p2p
// if (m_networkConfig.size()/* && ui->usePast->isChecked()*/)
// web3()->restoreNetwork(bytesConstRef((byte*)m_networkConfig.data(), m_networkConfig.size()));
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
}
@ -1765,13 +1785,25 @@ void Main::on_connect_triggered()
ui->net->setChecked(true);
on_net_triggered();
}
bool ok = false;
QString s = QInputDialog::getItem(this, "Connect to a Network Peer", "Enter a peer to which a connection may be made:", m_servers, m_servers.count() ? rand() % m_servers.count() : 0, true, &ok);
if (ok && s.contains(":"))
m_connect.setEnvironment(m_servers);
if (m_connect.exec() == QDialog::Accepted)
{
string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt();
web3()->connect(host, port);
bool required = m_connect.required();
string host(m_connect.host().toStdString());
NodeId nodeID;
try
{
nodeID = NodeId(fromHex(m_connect.nodeId().toStdString()));
}
catch (BadHexCharacter&) {}
m_connect.reset();
if (required)
web3()->requirePeer(nodeID, host);
else
web3()->addNode(nodeID, host);
}
}
@ -1882,7 +1914,7 @@ void Main::on_go_triggered()
ui->net->setChecked(true);
on_net_triggered();
}
web3()->connect(Host::pocHost());
web3()->addNode(p2p::NodeId(), Host::pocHost());
}
QString Main::prettyU256(dev::u256 _n) const

3
alethzero/MainWin.h

@ -40,6 +40,7 @@
#include "Context.h"
#include "Transact.h"
#include "NatspecHandler.h"
#include "Connect.h"
namespace Ui {
class Main;
@ -256,4 +257,6 @@ private:
std::unique_ptr<DappHost> m_dappHost;
DappLoader* m_dappLoader;
QWebEnginePage* m_webPage;
Connect m_connect;
};

4
alethzero/Transact.cpp

@ -316,7 +316,7 @@ void Transact::rejigData()
return;
}
else
gasNeeded = min<qint64>((qint64)ethereum()->gasLimitRemaining(), (qint64)((b - value()) / gasPrice()));
gasNeeded = (qint64)min<bigint>(ethereum()->gasLimitRemaining(), ((b - value()) / gasPrice()));
// Dry-run execution to determine gas requirement and any execution errors
Address to;
@ -326,7 +326,7 @@ void Transact::rejigData()
else
{
to = m_context->fromString(ui->destination->currentText());
er = ethereum()->call(s, value(), to, m_data, ethereum()->gasLimitRemaining(), gasPrice());
er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
}
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded);
htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec [%4 refunded later]</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo;

31
eth/main.cpp

@ -121,8 +121,9 @@ void help()
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl
#endif
<< " -K,--kill-blockchain First kill the blockchain." << endl
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " --listen-ip <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -l,--listen <ip> Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
<< " -u,--public-ip <ip> Force public ip to given (default: auto)." << 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
@ -131,7 +132,6 @@ void help()
<< " -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
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
@ -199,7 +199,9 @@ enum class NodeMode
int main(int argc, char** argv)
{
string listenIP;
unsigned short listenPort = 30303;
string publicIP;
string remoteHost;
unsigned short remotePort = 30303;
string dbPath;
@ -211,10 +213,8 @@ int main(int argc, char** argv)
#if ETH_JSONRPC
int jsonrpc = -1;
#endif
string publicIP;
bool bootstrap = false;
bool upnp = true;
bool useLocal = false;
bool forceMining = false;
bool killChain = false;
bool jit = false;
@ -250,7 +250,9 @@ int main(int argc, char** argv)
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
if (arg == "--listen-ip" && i + 1 < argc)
listenIP = argv[++i];
else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
listenPort = (short)atoi(argv[++i]);
else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
publicIP = argv[++i];
@ -271,8 +273,6 @@ int main(int argc, char** argv)
return -1;
}
}
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if (arg == "-K" || arg == "--kill-blockchain")
killChain = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
@ -421,7 +421,7 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3(
@ -449,9 +449,9 @@ int main(int argc, char** argv)
web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC
shared_ptr<WebThreeStubServer> jsonrpcServer;
@ -511,7 +511,7 @@ int main(int argc, char** argv)
string addr;
unsigned port;
iss >> addr >> port;
web3.connect(addr, (short)port);
web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
}
else if (cmd == "netstop")
{
@ -835,11 +835,8 @@ int main(int argc, char** argv)
Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();
try
{
e.setup(&r);
OnOpFunc oof;
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
@ -872,7 +869,9 @@ int main(int argc, char** argv)
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.initialize(t);
if (!e.execute())
e.go(oof);
e.finalize();
}
catch(Exception const& _e)

12
libdevcore/CommonData.h

@ -42,14 +42,15 @@ enum class WhenError
};
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte.
/// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte.
/// @example toHex("A\x69") == "4169"
template <class _T>
std::string toHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
unsigned ii = 0;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
@ -74,6 +75,13 @@ inline std::string asString(bytes const& _b)
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
}
/// Converts byte array ref 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(bytesConstRef _b)
{
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
}
/// Converts a string to a byte array containing the string's (byte) data.
inline bytes asBytes(std::string const& _b)
{

1
libdevcore/FixedHash.h

@ -141,6 +141,7 @@ public:
return ret;
}
/// @returns a random valued object.
static FixedHash random() { return random(s_fixedHashEngine); }
/// A generic std::hash compatible function object.

16
libethcore/Ethasher.cpp

@ -119,9 +119,21 @@ bool Ethasher::verify(BlockInfo const& _header)
boundary.data());
#if ETH_DEBUG
// should be equivalent to:
auto result = eval(_header);
assert((result.mixHash == _header.mixHash && result.value <= boundary) == ret);
if ((result.value <= boundary && result.mixHash == _header.mixHash) != ret)
{
cwarn << "Assertion failure coming: evaluated result gives different outcome to ethash_quick_check_difficulty";
cwarn << "headerHash:" << _header.headerHash(WithoutNonce);
cwarn << "nonce:" << _header.nonce;
cwarn << "mixHash:" << _header.mixHash;
cwarn << "difficulty:" << _header.difficulty;
cwarn << "boundary:" << boundary;
cwarn << "result.value:" << result.value;
cwarn << "result.mixHash:" << result.mixHash;
}
assert((result.value <= boundary) == ret);
if (result.value <= boundary)
assert(result.mixHash == _header.mixHash);
#endif
return ret;

1
libethcore/Exceptions.h

@ -38,6 +38,7 @@ using errinfo_difficulty = boost::error_info<struct tag_difficulty, u256>;
using BadFieldError = boost::tuple<errinfo_field, errinfo_data>;
struct DatabaseAlreadyOpen: virtual dev::Exception {};
struct NotEnoughAvailableSpace: virtual dev::Exception {};
struct NotEnoughCash: virtual dev::Exception {};
struct GasPriceTooLow: virtual dev::Exception {};
struct BlockGasLimitReached: virtual dev::Exception {};

69
libethereum/BlockChain.cpp

@ -63,7 +63,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
return _out;
}
ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub)
ldb::Slice dev::eth::toSlice(h256 const& _h, unsigned _sub)
{
#if ALL_COMPILERS_ARE_CPP11_COMPLIANT
static thread_local h256 h = _h ^ sha3(h256(u256(_sub)));
@ -131,10 +131,19 @@ void BlockChain::open(std::string _path, bool _killExisting)
o.create_if_missing = true;
ldb::DB::Open(o, _path + "/blocks", &m_blocksDB);
ldb::DB::Open(o, _path + "/details", &m_extrasDB);
if (!m_blocksDB)
BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen());
if (!m_extrasDB)
BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen());
if (!m_blocksDB || !m_extrasDB)
{
if (boost::filesystem::space(_path + "/blocks").available < 1024)
{
cwarn << "Not enough available space found on hard drive. Please free some up and then re-run. Bailing.";
BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace());
}
else
{
cwarn << "Database already open. You appear to have another instance of ethereum running. Bailing.";
BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen());
}
}
if (!details(m_genesisHash))
{
@ -184,6 +193,19 @@ inline string toString(h256s const& _bs)
return out.str();
}
LastHashes BlockChain::lastHashes(unsigned _n) const
{
Guard l(x_lastLastHashes);
if (m_lastLastHashesNumber != _n || m_lastLastHashes.empty())
{
m_lastLastHashes.resize(256);
for (unsigned i = 0; i < 256; ++i)
m_lastLastHashes[i] = _n >= i ? numberHash(_n - i) : h256();
m_lastLastHashesNumber = _n;
}
return m_lastLastHashes;
}
h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{
_bq.tick(*this);
@ -412,6 +434,9 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
WriteGuard l(x_lastBlockHash);
m_lastBlockHash = newHash;
}
noteCanonChanged();
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret);
StructuredLogger::chainNewHead(
@ -428,7 +453,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
return ret;
}
h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, bool _post) const
h256s BlockChain::treeRoute(h256 const& _from, h256 const& _to, h256* o_common, bool _pre, bool _post) const
{
// cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged();
if (!_from || !_to)
@ -438,38 +463,40 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo
unsigned fn = details(_from).number;
unsigned tn = details(_to).number;
// cdebug << "treeRoute" << fn << "..." << tn;
h256 from = _from;
while (fn > tn)
{
if (_pre)
ret.push_back(_from);
_from = details(_from).parent;
ret.push_back(from);
from = details(from).parent;
fn--;
// cdebug << "from:" << fn << _from.abridged();
}
h256 to = _to;
while (fn < tn)
{
if (_post)
back.push_back(_to);
_to = details(_to).parent;
back.push_back(to);
to = details(to).parent;
tn--;
// cdebug << "to:" << tn << _to.abridged();
}
while (_from != _to)
while (from != to)
{
assert(_from);
assert(_to);
_from = details(_from).parent;
_to = details(_to).parent;
assert(from);
assert(to);
from = details(from).parent;
to = details(to).parent;
if (_pre)
ret.push_back(_from);
ret.push_back(from);
if (_post)
back.push_back(_to);
back.push_back(to);
fn--;
tn--;
// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged();
}
if (o_common)
*o_common = _from;
*o_common = from;
ret.reserve(ret.size() + back.size());
for (auto it = back.cbegin(); it != back.cend(); ++it)
ret.push_back(*it);
@ -677,7 +704,7 @@ vector<unsigned> BlockChain::withBlockBloom(LogBloom const& _b, unsigned _earlie
return ret;
}
h256Set BlockChain::allUnclesFrom(h256 _parent) const
h256Set BlockChain::allUnclesFrom(h256 const& _parent) const
{
// Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
h256Set ret;
@ -692,7 +719,7 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const
return ret;
}
bool BlockChain::isKnown(h256 _hash) const
bool BlockChain::isKnown(h256 const& _hash) const
{
if (_hash == m_genesisHash)
return true;
@ -706,7 +733,7 @@ bool BlockChain::isKnown(h256 _hash) const
return !!d.size();
}
bytes BlockChain::block(h256 _hash) const
bytes BlockChain::block(h256 const& _hash) const
{
if (_hash == m_genesisHash)
return m_genesisBlock;

47
libethereum/BlockChain.h

@ -30,9 +30,10 @@
#include <chrono>
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/Guards.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libdevcore/Guards.h>
#include <libevm/ExtVMFace.h>
#include "BlockDetails.h"
#include "Account.h"
#include "Transaction.h"
@ -61,7 +62,7 @@ struct BlockChainNote: public LogChannel { static const char* name() { return "=
// TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, Account> const& genesisState();
ldb::Slice toSlice(h256 _h, unsigned _sub = 0);
ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
using BlocksHash = std::map<h256, bytes>;
using TransactionHashes = h256s;
@ -105,37 +106,42 @@ public:
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;
bool isKnown(h256 const& _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockInfo info(h256 _hash) const { return BlockInfo(block(_hash)); }
BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash)); }
BlockInfo info() const { return BlockInfo(block()); }
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
bytes block(h256 _hash) const;
bytes block(h256 const& _hash) const;
bytes block() const { return block(currentHash()); }
/// 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, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details(h256 const& _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); }
/// Get the transactions' log blooms of a block (or the most recent mined if none given). Thread-safe.
BlockLogBlooms logBlooms(h256 _hash) const { return queryExtras<BlockLogBlooms, ExtraLogBlooms>(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); }
BlockLogBlooms logBlooms(h256 const& _hash) const { return queryExtras<BlockLogBlooms, ExtraLogBlooms>(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); }
BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); }
/// Get the transactions' receipts of a block (or the most recent mined if none given). Thread-safe.
BlockReceipts receipts(h256 _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts(h256 const& _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts() const { return receipts(currentHash()); }
/// Get a list of transaction hashes for a given block. Thread-safe.
TransactionHashes transactionHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); }
/// Get a list of uncle hashes for a given block. Thread-safe.
UncleHashes uncleHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[2]) ret.push_back(sha3(t.data())); return ret; }
UncleHashes uncleHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[2]) ret.push_back(sha3(t.data())); return ret; }
UncleHashes uncleHashes() const { return uncleHashes(currentHash()); }
h256 numberHash(u256 _index) const { if (!_index) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(_index), m_blockHashes, x_blockHashes, NullBlockHash).value; }
/// Get the hash for a given block's number.
h256 numberHash(unsigned _i) const { if (!_i) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(u256(_i)), m_blockHashes, x_blockHashes, NullBlockHash).value; }
/// Get the last N hashes for a given block. (N is determined by the LastHashes type.)
LastHashes lastHashes() const { return lastHashes(number()); }
LastHashes lastHashes(unsigned _i) const;
/** Get the block blooms for a number of blocks. Thread-safe.
* @returns the object pertaining to the blocks:
@ -158,15 +164,15 @@ public:
std::vector<unsigned> withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest, unsigned _topLevel, unsigned _index) const;
/// Get a transaction from its hash. Thread-safe.
bytes transaction(h256 _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); }
std::pair<h256, unsigned> transactionLocation(h256 _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return std::pair<h256, unsigned>(h256(), 0); return std::make_pair(ta.blockHash, ta.index); }
bytes transaction(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); }
std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return std::pair<h256, unsigned>(h256(), 0); return std::make_pair(ta.blockHash, ta.index); }
/// Get a block's transaction (RLP format) for the given block hash (or the most recent mined if none given) & index. Thread-safe.
bytes transaction(h256 _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); }
bytes transaction(h256 const& _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); }
bytes transaction(unsigned _i) const { return transaction(currentHash(), _i); }
/// Get a number for the given hash (or the most recent mined if none given). Thread-safe.
unsigned number(h256 _hash) const { return details(_hash).number; }
unsigned number(h256 const& _hash) const { return details(_hash).number; }
unsigned number() const { return number(currentHash()); }
/// Get a given block (RLP format). Thread-safe.
@ -178,7 +184,7 @@ public:
/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
/// togther with all their quoted uncles.
h256Set allUnclesFrom(h256 _parent) const;
h256Set allUnclesFrom(h256 const& _parent) const;
/** @returns the hash of all blocks between @a _from and @a _to, all blocks are ordered first by a number of
* blocks that are parent-to-child, then two sibling blocks, then a number of blocks that are child-to-parent.
@ -194,7 +200,7 @@ public:
* treeRoute(1b, 2a) == { 1b, 1a, 2a }; // *o_common == g
* @endcode
*/
h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
h256s treeRoute(h256 const& _from, h256 const& _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
struct Statistics
{
@ -219,7 +225,7 @@ 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
template<class T, unsigned N> T queryExtras(h256 const& _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n) const
{
{
ReadGuard l(_x);
@ -268,6 +274,11 @@ private:
void noteUsed(h256 const& _h, unsigned _extra = (unsigned)-1) const;
std::chrono::system_clock::time_point m_lastCollection;
void noteCanonChanged() const { Guard l(x_lastLastHashes); m_lastLastHashes.clear(); }
mutable Mutex x_lastLastHashes;
mutable LastHashes m_lastLastHashes;
mutable unsigned m_lastLastHashesNumber = (unsigned)-1;
void updateStats() const;
mutable Statistics m_lastStats;

2
libethereum/Client.h

@ -110,7 +110,7 @@ public:
private:
u256 m_weiPerRef;
u256 m_refsPerBlock;
u256 m_gasPerBlock = 1000000;
u256 m_gasPerBlock = 3141592;
std::array<u256, 9> m_octiles;
};

4
libethereum/ClientBase.cpp

@ -73,7 +73,7 @@ ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, byt
State temp = asOf(_blockNumber);
u256 n = temp.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted);
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
{
@ -92,7 +92,7 @@ ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _da
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted);
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
{

2
libethereum/EthereumHost.cpp

@ -178,7 +178,7 @@ void EthereumHost::maintainTransactions()
for (auto const& i: m_tq.transactions())
if (ep->m_requireTransactions || (!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)))
{
b += i.second;
b += i.second.rlp();
++n;
m_transactionsSent.insert(i.first);
}

78
libethereum/Executive.cpp

@ -35,7 +35,7 @@ using namespace dev::eth;
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
m_s(_s),
m_lastHashes(_s.getLastHashes(_bc, (unsigned)_s.info().number - 1)),
m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)),
m_depth(_level)
{}
@ -55,12 +55,33 @@ void Executive::accrueSubState(SubState& _parentContext)
_parentContext += m_ext->sub;
}
bool Executive::setup(bytesConstRef _rlp)
void Executive::initialize(Transaction const& _transaction)
{
// Entry point for a user-executed transaction.
m_t = _transaction;
// Avoid transactions that would take us beyond the block gas limit.
u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit)
{
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas();
m_excepted = TransactionException::BlockGasLimitReached;
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
}
// Check gas cost is enough.
m_gasRequired = Interface::txGas(m_t.data());
if (m_t.gas() < m_gasRequired)
{
clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << m_gasRequired << " Got" << m_t.gas();
m_excepted = TransactionException::OutOfGas;
BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)m_gasRequired, (bigint)m_t.gas()));
}
// Avoid invalid transactions.
u256 nonceReq;
try
{
m_t = Transaction(_rlp, CheckSignature::Sender);
nonceReq = m_s.transactionsFrom(m_t.sender());
}
catch (...)
{
@ -68,15 +89,6 @@ bool Executive::setup(bytesConstRef _rlp)
m_excepted = TransactionException::InvalidSignature;
throw;
}
return setup();
}
bool Executive::setup()
{
// Entry point for a user-executed transaction.
// Avoid invalid transactions.
auto nonceReq = m_s.transactionsFrom(m_t.sender());
if (m_t.nonce() != nonceReq)
{
clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce();
@ -84,46 +96,32 @@ bool Executive::setup()
BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce()));
}
// Check gas cost is enough.
auto gasRequired = Interface::txGas(m_t.data());
if (m_t.gas() < gasRequired)
{
clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasRequired << " Got" << m_t.gas();
m_excepted = TransactionException::OutOfGas;
BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)gasRequired, (bigint)m_t.gas()));
}
bigint gasCost = (bigint)m_t.gas() * m_t.gasPrice();
bigint totalCost = m_t.value() + gasCost;
// Avoid unaffordable transactions.
if (m_s.balance(m_t.sender()) < totalCost)
m_gasCost = (bigint)m_t.gas() * m_t.gasPrice();
m_totalCost = m_t.value() + m_gasCost;
if (m_s.balance(m_t.sender()) < m_totalCost)
{
clog(StateDetail) << "Not enough cash: Require >" << totalCost << " Got" << m_s.balance(m_t.sender());
clog(StateDetail) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender());
m_excepted = TransactionException::NotEnoughCash;
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(totalCost, (bigint)m_s.balance(m_t.sender())));
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender())));
}
}
u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit)
{
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas();
m_excepted = TransactionException::BlockGasLimitReached;
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
}
bool Executive::execute()
{
// Entry point for a user-executed transaction.
// Increment associated nonce for sender.
m_s.noteSending(m_t.sender());
// Pay...
clog(StateDetail) << "Paying" << formatBalance(u256(gasCost)) << "from sender for gas (" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
m_s.subBalance(m_t.sender(), gasCost);
clog(StateDetail) << "Paying" << formatBalance(u256(m_gasCost)) << "from sender for gas (" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
m_s.subBalance(m_t.sender(), m_gasCost);
if (m_t.isCreation())
return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasRequired, &m_t.data(), m_t.sender());
return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)m_gasRequired, &m_t.data(), m_t.sender());
else
return call(m_t.receiveAddress(), m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)gasRequired, m_t.sender());
return call(m_t.receiveAddress(), m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)m_gasRequired, m_t.sender());
}
bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress)

41
libethereum/Executive.h

@ -41,10 +41,21 @@ struct VMTraceChannel: public LogChannel { static const char* name() { return "E
* @brief Message-call/contract-creation executor; useful for executing transactions.
*
* Two ways of using this class - either as a transaction executive or a CALL/CREATE executive.
* In the first use, after construction, begin with setup() and end with finalize(). Call go()
* after setup() only if it returns false.
*
* In the first use, after construction, begin with initialize(), then execute() and end with finalize(). Call go()
* after execute() only if it returns false.
*
* In the second use, after construction, begin with call() or create() and end with
* accrueSubState(). Call go() after call()/create() only if it returns false.
*
* Example:
* @code
* Executive e(state, blockchain, 0);
* e.initialize(transaction);
* if (!e.execute())
* e.go();
* e.finalize();
* @endcode
*/
class Executive
{
@ -59,17 +70,17 @@ public:
Executive(Executive const&) = delete;
void operator=(Executive) = delete;
/// Set up the executive for evaluating a transaction. You must call finalize() following this.
/// @returns true iff go() must be called (and thus a VM execution in required).
bool setup(bytesConstRef _transaction);
/// Set up the executive for evaluating a transaction. You must call finalize() following this.
/// @returns true iff go() must be called (and thus a VM execution in required).
bool setup(Transaction const& _transaction) { m_t = _transaction; return setup(); }
/// Finalise a transaction previously set up with setup().
/// @warning Only valid after setup(), and possibly go().
/// Initializes the executive for evaluating a transaction. You must call finalize() at some point following this.
void initialize(bytesConstRef _transaction) { initialize(Transaction(_transaction, CheckSignature::None)); }
void initialize(Transaction const& _transaction);
/// Finalise a transaction previously set up with initialize().
/// @warning Only valid after initialize() and execute(), and possibly go().
void finalize();
/// @returns the transaction from setup().
/// @warning Only valid after setup().
/// Begins execution of a transaction. You must call finalize() following this.
/// @returns true if the transaction is done, false if go() must be called.
bool execute();
/// @returns the transaction from initialize().
/// @warning Only valid after initialize().
Transaction const& t() const { return m_t; }
/// @returns the log entries created by this operation.
/// @warning Only valid after finalise().
@ -107,8 +118,6 @@ public:
ExecutionResult executionResult() const;
private:
bool setup();
State& m_s; ///< The state to which this operation/transaction is applied.
LastHashes m_lastHashes;
std::shared_ptr<ExtVM> m_ext; ///< The VM externality object for the VM execution or null if no VM is required.
@ -125,6 +134,10 @@ private:
Transaction m_t; ///< The original transaction. Set by setup().
LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize().
bigint m_gasRequired;
bigint m_gasCost;
bigint m_totalCost;
};
}

6
libethereum/Interface.h

@ -71,11 +71,13 @@ public:
virtual void flushTransactions() = 0;
/// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = 0) = 0;
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) = 0;
ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) { return call(_secret, _value, _dest, _data, _gas, _gasPrice, m_default); }
/// Does the given creation. Nothing is recorded into the state.
/// @returns the pair of the Address of the created contract together with its code.
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = 0) = 0;
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) = 0;
ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) { return create(_secret, _value, _data, _gas, _gasPrice, m_default); }
// [STATE-QUERY API]

87
libethereum/State.cpp

@ -60,7 +60,18 @@ OverlayDB State::openDB(std::string _path, bool _killExisting)
ldb::DB* db = nullptr;
ldb::DB::Open(o, _path + "/state", &db);
if (!db)
BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen());
{
if (boost::filesystem::space(_path + "/state").available < 1024)
{
cwarn << "Not enough available space found on hard drive. Please free some up and then re-run. Bailing.";
BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace());
}
else
{
cwarn << "Database already open. You appear to have another instance of ethereum running. Bailing.";
BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen());
}
}
cnote << "Opened state DB.";
return OverlayDB(db);
@ -388,8 +399,7 @@ bool State::cull(TransactionQueue& _tq) const
{
try
{
Transaction t(i.second, CheckSignature::Sender);
if (t.nonce() <= transactionsFrom(t.sender()))
if (i.second.nonce() <= transactionsFrom(i.second.sender()))
{
_tq.drop(i.first);
ret = true;
@ -411,7 +421,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
TransactionReceipts ret;
auto ts = _tq.transactions();
auto lh = getLastHashes(_bc, _bc.number());
LastHashes lh;
for (int goodTxs = 1; goodTxs;)
{
@ -421,12 +431,11 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
{
try
{
Transaction t(i.second, CheckSignature::Sender);
if (t.gasPrice() >= _gp.ask(*this))
if (i.second.gasPrice() >= _gp.ask(*this))
{
// don't have it yet! Execute it now.
uncommitToMine();
// boost::timer t;
if (lh.empty())
lh = _bc.lastHashes();
execute(lh, i.second);
ret.push_back(m_receipts.back());
_tq.noteGood(i);
@ -434,6 +443,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
// cnote << "TX took:" << t.elapsed() * 1000;
}
}
#if ETH_DEBUG
catch (InvalidNonce const& in)
{
bigint const* req = boost::get_error_info<errinfo_required>(in);
@ -449,13 +459,19 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
else
_tq.setFuture(i);
}
catch (BlockGasLimitReached const& e)
{
_tq.setFuture(i);
}
#endif
catch (Exception const& _e)
{
// Something else went wrong - drop it.
_tq.drop(i.first);
if (o_transactionQueueChanged)
*o_transactionQueueChanged = true;
cwarn << "Sync went wrong\n" << diagnostic_information(_e);
cnote << "Dropping invalid transaction:";
cnote << diagnostic_information(_e);
}
catch (std::exception const&)
{
@ -463,6 +479,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
_tq.drop(i.first);
if (o_transactionQueueChanged)
*o_transactionQueueChanged = true;
cnote << "Transaction caused low-level exception :(";
}
}
}
@ -498,7 +515,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number);
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
RLP rlp(_block);
// All ok with the block generally. Play back the transactions now...
@ -509,7 +526,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
k << i;
transactionsTrie.insert(&k.out(), tr.data());
execute(lh, tr.data());
execute(lh, Transaction(tr.data(), CheckSignature::Sender));
RLPStream receiptrlp;
m_receipts.back().streamRLP(receiptrlp);
@ -1040,56 +1057,34 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const
{
LastHashes ret;
ret.resize(256);
if (eth::c_protocolVersion > 49)
{
ret[0] = _bc.numberHash(_n);
for (unsigned i = 1; i < 256; ++i)
ret[i] = ret[i - 1] ? _bc.details(ret[i - 1]).parent : h256();
}
return ret;
}
ExecutionResult State::execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p)
{
return execute(getLastHashes(_bc, _bc.number()), &_rlp, _p);
}
ExecutionResult State::execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p)
ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p)
{
return execute(getLastHashes(_bc, _bc.number()), _rlp, _p);
}
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
ExecutionResult State::execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p)
{
#ifndef ETH_RELEASE
commit(); // get an updated hash
#endif
#if ETH_PARANOIA
paranoia("start of execution.", true);
State old(*this);
#if ETH_PARANOIA
auto h = rootHash();
#endif
// Create and initialize the executive. This will throw fairly cheaply and quickly if the
// transaction is bad in any way.
Executive e(*this, _lh, 0);
e.setup(_rlp);
e.initialize(_t);
u256 startGasUsed = gasUsed();
// Uncommitting is a non-trivial operation - only do it once we've verified as much of the
// transaction as possible.
uncommitToMine();
// OK - transaction looks valid - execute.
u256 startGasUsed = gasUsed();
#if ETH_PARANOIA
ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp());
#endif
if (!e.execute())
#if ETH_VMTRACE
e.go(e.simpleTrace());
e.go(e.simpleTrace());
#else
e.go();
e.go();
#endif
e.finalize();

8
libethereum/State.h

@ -188,15 +188,9 @@ public:
/// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const;
/// Returns the last few block hashes of the current chain.
LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const;
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
ExecutionResult execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p = Permanence::Committed);
ExecutionResult execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p = Permanence::Committed);
ExecutionResult execute(LastHashes const& _lh, bytes const& _rlp, Permanence _p = Permanence::Committed) { return execute(_lh, &_rlp, _p); }
ExecutionResult execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p = Permanence::Committed);
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed);
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }

10
libethereum/TransactionQueue.cpp

@ -46,7 +46,7 @@ bool TransactionQueue::import(bytesConstRef _transactionRLP)
UpgradeGuard ul(l);
// If valid, append to blocks.
m_current[h] = _transactionRLP.toBytes();
m_current[h] = t;
m_known.insert(h);
}
catch (Exception const& _e)
@ -63,20 +63,20 @@ bool TransactionQueue::import(bytesConstRef _transactionRLP)
return true;
}
void TransactionQueue::setFuture(std::pair<h256, bytes> const& _t)
void TransactionQueue::setFuture(std::pair<h256, Transaction> const& _t)
{
WriteGuard l(m_lock);
if (m_current.count(_t.first))
{
m_current.erase(_t.first);
m_unknown.insert(make_pair(Transaction(_t.second, CheckSignature::Sender).sender(), _t));
m_unknown.insert(make_pair(_t.second.sender(), _t));
}
}
void TransactionQueue::noteGood(std::pair<h256, bytes> const& _t)
void TransactionQueue::noteGood(std::pair<h256, Transaction> const& _t)
{
WriteGuard l(m_lock);
auto r = m_unknown.equal_range(Transaction(_t.second, CheckSignature::Sender).sender());
auto r = m_unknown.equal_range(_t.second.sender());
for (auto it = r.first; it != r.second; ++it)
m_current.insert(it->second);
m_unknown.erase(r.first, r.second);

11
libethereum/TransactionQueue.h

@ -25,6 +25,7 @@
#include <libdevcore/Common.h>
#include "libethcore/Common.h"
#include <libdevcore/Guards.h>
#include "Transaction.h"
namespace dev
{
@ -46,19 +47,19 @@ public:
void drop(h256 _txHash);
std::map<h256, bytes> transactions() const { ReadGuard l(m_lock); return m_current; }
std::map<h256, Transaction> transactions() const { ReadGuard l(m_lock); return m_current; }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); }
void setFuture(std::pair<h256, bytes> const& _t);
void noteGood(std::pair<h256, bytes> const& _t);
void setFuture(std::pair<h256, Transaction> const& _t);
void noteGood(std::pair<h256, Transaction> const& _t);
void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); }
private:
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets.
std::map<h256, bytes> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, bytes>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
std::map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
};
}

7
libp2p/Common.cpp

@ -25,10 +25,11 @@ using namespace dev;
using namespace dev::p2p;
const unsigned dev::p2p::c_protocolVersion = 3;
const unsigned dev::p2p::c_defaultIPPort = 30303;
bool p2p::isPublicAddress(std::string const& _addressToCheck)
{
return isPublicAddress(bi::address::from_string(_addressToCheck));
return _addressToCheck.empty() ? false : isPublicAddress(bi::address::from_string(_addressToCheck));
}
bool p2p::isPublicAddress(bi::address const& _addressToCheck)
@ -67,7 +68,7 @@ bool p2p::isPrivateAddress(bi::address const& _addressToCheck)
bool p2p::isPrivateAddress(std::string const& _addressToCheck)
{
return isPrivateAddress(bi::address::from_string(_addressToCheck));
return _addressToCheck.empty() ? false : isPrivateAddress(bi::address::from_string(_addressToCheck));
}
// Helper function to determine if an address is localhost
@ -86,7 +87,7 @@ bool p2p::isLocalHostAddress(bi::address const& _addressToCheck)
bool p2p::isLocalHostAddress(std::string const& _addressToCheck)
{
return isLocalHostAddress(bi::address::from_string(_addressToCheck));
return _addressToCheck.empty() ? false : isLocalHostAddress(bi::address::from_string(_addressToCheck));
}
std::string p2p::reasonOf(DisconnectReason _r)

3
libp2p/Common.h

@ -50,7 +50,8 @@ namespace p2p
/// Peer network protocol version.
extern const unsigned c_protocolVersion;
extern const unsigned c_defaultIPPort;
using NodeId = h512;
bool isPrivateAddress(bi::address const& _addressToCheck);

173
libp2p/Host.cpp

@ -66,10 +66,6 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, byte
m_alias(networkAlias(_restoreNetwork)),
m_lastPing(chrono::steady_clock::time_point::min())
{
for (auto address: m_ifAddresses)
if (address.is_v4())
clog(NetNote) << "IP Address: " << address << " = " << (isPrivateAddress(address) ? "[LOCAL]" : "[PEER]");
clog(NetNote) << "Id:" << id();
}
@ -287,67 +283,50 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
}
}
void Host::determinePublic(string const& _publicAddress, bool _upnp)
void Host::determinePublic()
{
m_peerAddresses.clear();
// no point continuing if there are no interface addresses or valid listen port
if (!m_ifAddresses.size() || m_listenPort < 1)
return;
// populate interfaces we'll listen on (eth listens on all interfaces); ignores local
for (auto addr: m_ifAddresses)
if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && !isLocalHostAddress(addr))
m_peerAddresses.insert(addr);
// if user supplied address is a public address then we use it
// if user supplied address is private, and localnetworking is enabled, we use it
bi::address reqPublicAddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress)));
bi::tcp::endpoint reqPublic(reqPublicAddr, m_listenPort);
bool isprivate = isPrivateAddress(reqPublicAddr);
bool ispublic = !isprivate && !isLocalHostAddress(reqPublicAddr);
if (!reqPublicAddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking)))
// set m_tcpPublic := listenIP (if public) > public > upnp > unspecified address.
auto ifAddresses = Network::getInterfaceAddresses();
auto laddr = m_netPrefs.listenIPAddress.empty() ? bi::address() : bi::address::from_string(m_netPrefs.listenIPAddress);
auto lset = !laddr.is_unspecified();
auto paddr = m_netPrefs.publicIPAddress.empty() ? bi::address() : bi::address::from_string(m_netPrefs.publicIPAddress);
auto pset = !paddr.is_unspecified();
bool listenIsPublic = lset && isPublicAddress(laddr);
bool publicIsHost = !lset && pset && ifAddresses.count(paddr);
bi::tcp::endpoint ep(bi::address(), m_netPrefs.listenPort);
if (m_netPrefs.traverseNAT && listenIsPublic)
{
if (!m_peerAddresses.count(reqPublicAddr))
m_peerAddresses.insert(reqPublicAddr);
m_tcpPublic = reqPublic;
return;
clog(NetNote) << "Listen address set to Public address:" << laddr << ". UPnP disabled.";
ep.address(laddr);
}
// if address wasn't provided, then use first public ipv4 address found
for (auto addr: m_peerAddresses)
if (addr.is_v4() && !isPrivateAddress(addr))
{
m_tcpPublic = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort);
return;
}
// or find address via upnp
if (_upnp)
else if (m_netPrefs.traverseNAT && publicIsHost)
{
clog(NetNote) << "Public address set to Host configured address:" << paddr << ". UPnP disabled.";
ep.address(paddr);
}
else if (m_netPrefs.traverseNAT)
{
bi::address upnpifaddr;
bi::tcp::endpoint upnpep = Network::traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr);
if (!upnpep.address().is_unspecified() && !upnpifaddr.is_unspecified())
bi::address natIFAddr;
ep = Network::traverseNAT(lset && ifAddresses.count(laddr) ? std::set<bi::address>({laddr}) : ifAddresses, m_netPrefs.listenPort, natIFAddr);
if (lset && natIFAddr != laddr)
// if listen address is set, Host will use it, even if upnp returns different
clog(NetWarn) << "Listen address" << laddr << "differs from local address" << natIFAddr << "returned by UPnP!";
if (pset && ep.address() != paddr)
{
if (!m_peerAddresses.count(upnpep.address()))
m_peerAddresses.insert(upnpep.address());
m_tcpPublic = upnpep;
return;
// if public address is set, Host will advertise it, even if upnp returns different
clog(NetWarn) << "Specified public address" << paddr << "differs from external address" << ep.address() << "returned by UPnP!";
ep.address(paddr);
}
}
else if (pset)
ep.address(paddr);
// or if no address provided, use private ipv4 address if local networking is enabled
if (reqPublicAddr.is_unspecified())
if (m_netPrefs.localNetworking)
for (auto addr: m_peerAddresses)
if (addr.is_v4() && isPrivateAddress(addr))
{
m_tcpPublic = bi::tcp::endpoint(addr, m_listenPort);
return;
}
// otherwise address is unspecified
m_tcpPublic = bi::tcp::endpoint(bi::address(), m_listenPort);
m_tcpPublic = ep;
}
void Host::runAcceptor()
@ -401,7 +380,7 @@ string Host::pocHost()
return "poc-" + strs[1] + ".ethdev.com";
}
void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPeerPort, unsigned short _udpNodePort)
void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpNodePort, unsigned short _tcpPeerPort)
{
// TODO: p2p clean this up (bring tested acceptor code over from network branch)
while (isWorking() && !m_run)
@ -417,24 +396,59 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short
cwarn << "Private port being recorded - setting to 0";
_tcpPeerPort = 0;
}
if (m_nodeTable)
m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(_addr, _udpNodePort), bi::tcp::endpoint(_addr, _tcpPeerPort))));
}
boost::system::error_code ec;
bi::address addr = bi::address::from_string(_addr, ec);
if (ec)
void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr, unsigned short _tcpPort)
{
auto naddr = _udpAddr;
auto paddr = _tcpAddr.is_unspecified() ? naddr : _tcpAddr;
auto udp = bi::udp::endpoint(naddr, _udpPort);
auto tcp = bi::tcp::endpoint(paddr, _tcpPort ? _tcpPort : _udpPort);
Node node(_n, NodeIPEndpoint(udp, tcp));
if (_n)
{
bi::tcp::resolver *r = new bi::tcp::resolver(m_ioService);
r->async_resolve({_addr, toString(_tcpPeerPort)}, [=](boost::system::error_code const& _ec, bi::tcp::resolver::iterator _epIt)
// add or replace peer
shared_ptr<Peer> p;
{
if (!_ec)
RecursiveGuard l(x_sessions);
if (m_peers.count(_n))
p = m_peers[_n];
else
{
bi::tcp::endpoint tcp = *_epIt;
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(tcp.address(), _udpNodePort), tcp)));
p.reset(new Peer());
p->id = _n;
p->required = true;
m_peers[_n] = p;
}
delete r;
p->endpoint.udp = node.endpoint.udp;
p->endpoint.tcp = node.endpoint.tcp;
}
connect(p);
}
else if (m_nodeTable)
{
shared_ptr<boost::asio::deadline_timer> t(new boost::asio::deadline_timer(m_ioService));
m_timers.push_back(t);
m_nodeTable->addNode(node);
t->expires_from_now(boost::posix_time::milliseconds(600));
t->async_wait([this, _n](boost::system::error_code const& _ec)
{
if (!_ec && m_nodeTable)
if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint.udp.address(), n.endpoint.udp.port(), n.endpoint.tcp.address(), n.endpoint.tcp.port());
});
}
else
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(addr, _udpNodePort), bi::tcp::endpoint(addr, _tcpPeerPort))));
}
void Host::relinquishPeer(NodeId const& _node)
{
Guard l(x_requiredPeers);
if (m_requiredPeers.count(_node))
m_requiredPeers.erase(_node);
}
void Host::connect(std::shared_ptr<Peer> const& _p)
@ -485,6 +499,9 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
Guard l(x_connecting);
m_connecting.push_back(handshake);
}
// preempt setting failedAttempts; this value is cleared upon success
_p->m_failedAttempts++;
handshake->start();
}
@ -541,6 +558,13 @@ void Host::run(boost::system::error_code const&)
Guard l(x_connecting);
m_connecting.remove_if([](std::weak_ptr<RLPXHandshake> h){ return h.lock(); });
}
{
Guard l(x_timers);
m_timers.remove_if([](std::shared_ptr<boost::asio::deadline_timer> t)
{
return t->expires_from_now().total_milliseconds() > 0;
});
}
for (auto p: m_sessions)
if (auto pp = p.second.lock())
@ -597,21 +621,21 @@ void Host::startedWorking()
h.second->onStarting();
// try to open acceptor (todo: ipv6)
m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort);
m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs);
// determine public IP, but only if we're able to listen for connections
// todo: GUI when listen is unavailable in UI
if (m_listenPort)
{
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
determinePublic();
if (m_listenPort > 0)
runAcceptor();
}
else
clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "Listen port is invalid or unavailable. Node Table using default port (30303).";
clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "TCP Listen port is invalid or unavailable.";
m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort() > 0 ? listenPort() : 30303));
m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort()));
m_nodeTable->setEventHandler(new HostNodeTableHandler(*this));
restoreNetwork(&m_restoreNetwork);
@ -720,6 +744,9 @@ void Host::restoreNetwork(bytesConstRef _b)
if (!isStarted())
BOOST_THROW_EXCEPTION(NetworkStartRequired());
if (m_dropPeers)
return;
RecursiveGuard l(x_sessions);
RLP r(_b);
if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion)

33
libp2p/Host.h

@ -70,9 +70,7 @@ private:
* @brief The Host class
* Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
*
* @todo cleanup startPeerSession
* @todo determinePublic: ipv6, udp
* @todo handle conflict if addNode/requireNode called and Node already exists w/conflicting tcp or udp port
* @todo per-session keepalive/ping instead of broadcast; set ping-timeout via median-latency
*/
class Host: public Worker
@ -105,8 +103,14 @@ public:
template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } }
/// Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity.
void addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort);
void addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort);
/// Create Peer and attempt keeping peer connected.
void requirePeer(NodeId const& _node, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr = bi::address(), unsigned short _tcpPort = 0);
/// Note peer as no longer being required.
void relinquishPeer(NodeId const& _node);
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
@ -117,10 +121,10 @@ public:
size_t peerCount() const;
/// Get the address we're listening on currently.
std::string listenAddress() const { return m_tcpPublic.address().to_string(); }
std::string listenAddress() const { return m_netPrefs.listenIPAddress.empty() ? "0.0.0.0" : m_netPrefs.listenIPAddress; }
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_tcpPublic.port(); }
unsigned short listenPort() const { return m_netPrefs.listenPort; }
/// Serialise the set of known peers.
bytes saveNetwork() const;
@ -128,7 +132,7 @@ public:
// TODO: P2P this should be combined with peers into a HostStat object of some kind; coalesce data, as it's only used for status information.
Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; }
void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
/// Start network. @threadsafe
void start();
@ -154,8 +158,8 @@ protected:
private:
bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; }
/// Populate m_peerAddresses with available public addresses.
void determinePublic(std::string const& _publicAddress, bool _upnp);
/// Determines and sets m_tcpPublic to publicly advertised address.
void determinePublic();
void connect(std::shared_ptr<Peer> const& _p);
@ -192,7 +196,7 @@ private:
NetworkPreferences m_netPrefs; ///< Network settings.
/// Interface addresses (private, public)
std::vector<bi::address> m_ifAddresses; ///< Interface addresses.
std::set<bi::address> m_ifAddresses; ///< Interface addresses.
int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized.
@ -211,6 +215,10 @@ private:
/// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer;
std::map<NodeId, std::shared_ptr<Peer>> m_peers;
/// Peers we try to connect regardless of p2p network.
std::set<NodeId> m_requiredPeers;
Mutex x_requiredPeers;
/// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run())
/// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
@ -222,12 +230,15 @@ private:
unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
std::set<bi::address> m_peerAddresses; ///< Public addresses that peers (can) know us by.
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support.
/// Deadline timers used for isolated network events. GC'd by run.
std::list<std::shared_ptr<boost::asio::deadline_timer>> m_timers;
Mutex x_timers;
std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
bool m_accepting = false;
bool m_dropPeers = false;
};
}

108
libp2p/Network.cpp

@ -27,6 +27,7 @@
#endif
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/Assertions.h>
@ -40,9 +41,9 @@ using namespace std;
using namespace dev;
using namespace dev::p2p;
std::vector<bi::address> Network::getInterfaceAddresses()
std::set<bi::address> Network::getInterfaceAddresses()
{
std::vector<bi::address> addresses;
std::set<bi::address> addresses;
#ifdef _WIN32
WSAData wsaData;
@ -72,7 +73,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
char *addrStr = inet_ntoa(addr);
bi::address address(bi::address::from_string(addrStr));
if (!isLocalHostAddress(address))
addresses.push_back(address.to_v4());
addresses.insert(address.to_v4());
}
WSACleanup();
@ -91,7 +92,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr));
if (!isLocalHostAddress(address))
addresses.push_back(address);
addresses.insert(address);
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
@ -101,7 +102,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
memcpy(&bytes[0], addr.s6_addr, 16);
boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id);
if (!isLocalHostAddress(address))
addresses.push_back(address);
addresses.insert(address);
}
}
@ -113,13 +114,39 @@ std::vector<bi::address> Network::getInterfaceAddresses()
return std::move(addresses);
}
int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort)
int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs)
{
int retport = -1;
for (unsigned i = 0; i < 2; ++i)
if (_netPrefs.listenIPAddress.empty())
for (unsigned i = 0; i < 2; ++i)
{
// try to connect w/listenPort, else attempt net-allocated port
bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _netPrefs.listenPort);
try
{
_acceptor.open(endpoint.protocol());
_acceptor.set_option(ba::socket_base::reuse_address(true));
_acceptor.bind(endpoint);
_acceptor.listen();
retport = _acceptor.local_endpoint().port();
break;
}
catch (...)
{
if (i)
{
// both attempts failed
cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information();
}
// first attempt failed
_acceptor.close();
continue;
}
}
else
{
// try to connect w/listenPort, else attempt net-allocated port
bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _listenPort);
bi::tcp::endpoint endpoint(bi::address::from_string(_netPrefs.listenIPAddress), _netPrefs.listenPort);
try
{
_acceptor.open(endpoint.protocol());
@ -127,25 +154,18 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort
_acceptor.bind(endpoint);
_acceptor.listen();
retport = _acceptor.local_endpoint().port();
break;
}
catch (...)
{
if (i)
{
// both attempts failed
cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information();
}
// first attempt failed
_acceptor.close();
continue;
clog(NetWarn) << "Couldn't start accepting connections on host. Failed to accept socket.\n" << boost::current_exception_diagnostic_information();
}
assert(retport == _netPrefs.listenPort);
return retport;
}
return retport;
}
bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr)
bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr)
{
asserts(_listenPort != 0);
@ -157,26 +177,26 @@ bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddres
// let m_upnp continue as null - we handle it properly.
catch (...) {}
bi::tcp::endpoint upnpep;
bi::tcp::endpoint upnpEP;
if (upnp && upnp->isValid())
{
bi::address paddr;
bi::address pAddr;
int extPort = 0;
for (auto const& addr: _ifAddresses)
if (addr.is_v4() && isPrivateAddress(addr) && (extPort = upnp->addRedirect(addr.to_string().c_str(), _listenPort)))
{
paddr = addr;
pAddr = addr;
break;
}
auto eip = upnp->externalIP();
bi::address eipaddr(bi::address::from_string(eip));
if (extPort && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr))
auto eIP = upnp->externalIP();
bi::address eIPAddr(bi::address::from_string(eIP));
if (extPort && eIP != string("0.0.0.0") && !isPrivateAddress(eIPAddr))
{
clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << extPort << ".";
clog(NetNote) << "External addr:" << eip;
o_upnpifaddr = paddr;
upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)extPort);
clog(NetNote) << "External addr:" << eIP;
o_upnpInterfaceAddr = pAddr;
upnpEP = bi::tcp::endpoint(eIPAddr, (unsigned short)extPort);
}
else
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place).";
@ -185,5 +205,33 @@ bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddres
delete upnp;
}
return upnpep;
return upnpEP;
}
bi::tcp::endpoint Network::resolveHost(string const& _addr)
{
static boost::asio::io_service s_resolverIoService;
vector<string> split;
boost::split(split, _addr, boost::is_any_of(":"));
unsigned port = split.size() > 1 ? stoi(split[1]) : dev::p2p::c_defaultIPPort;
bi::tcp::endpoint ep(bi::address(), port);
boost::system::error_code ec;
bi::address address = bi::address::from_string(split[0], ec);
if (!ec)
ep.address(address);
else
{
boost::system::error_code ec;
// resolve returns an iterator (host can resolve to multiple addresses)
bi::tcp::resolver r(s_resolverIoService);
auto it = r.resolve({split[0], toString(port)}, ec);
if (ec)
clog(NetWarn) << "Error resolving host address " << _addr << ":" << ec.message();
else
ep = *it;
}
return ep;
}

26
libp2p/Network.h

@ -39,12 +39,19 @@ namespace p2p
struct NetworkPreferences
{
NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), publicIP(i), upnp(u), localNetworking(l) {}
// Default Network Preferences
NetworkPreferences(unsigned short lp = 30303): listenPort(lp) {}
// Network Preferences with specific Listen IP
NetworkPreferences(std::string const& l, unsigned short lp = 30303, bool u = true): publicIPAddress(), listenIPAddress(l), listenPort(lp), traverseNAT(u) {}
// Network Preferences with intended Public IP
NetworkPreferences(std::string const& publicIP, std::string const& l = std::string(), unsigned short lp = 30303, bool u = true): publicIPAddress(publicIP), listenIPAddress(l), listenPort(lp), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); }
std::string publicIPAddress;
std::string listenIPAddress;
unsigned short listenPort = 30303;
std::string publicIP;
bool upnp = true;
bool localNetworking = false;
bool traverseNAT = true;
};
/**
@ -55,14 +62,17 @@ class Network
{
public:
/// @returns public and private interface addresses
static std::vector<bi::address> getInterfaceAddresses();
static std::set<bi::address> getInterfaceAddresses();
/// Try to bind and listen on _listenPort, else attempt net-allocated port.
static int tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort);
static int tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs);
/// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port.
static bi::tcp::endpoint traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr);
static bi::tcp::endpoint traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr);
/// Resolve "host:port" string as TCP endpoint. Returns unspecified endpoint on failure.
static bi::tcp::endpoint resolveHost(std::string const& _host);
};
}
}

27
libp2p/NodeTable.cpp

@ -101,6 +101,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp)));
m_nodes[_node.id] = ret;
ret->cullEndpoint();
clog(NodeTableConnect) << "addNode pending for" << m_node.endpoint.udp << m_node.endpoint.tcp;
PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port());
p.sign(m_secret);
m_socketPointer->send(p);
@ -450,6 +451,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
return; // unsolicited pong; don't note node as active
}
clog(NodeTableConnect) << "PONG from " << nodeid.abridged() << _from;
break;
}
@ -550,31 +552,16 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec)
clog(NodeTableEvent) << "refreshing buckets";
bool connected = m_socketPointer->isOpen();
bool refreshed = false;
if (connected)
{
Guard l(x_state);
for (auto& d: m_state)
if (chrono::steady_clock::now() - d.modified > c_bucketRefresh)
{
d.touch();
while (!d.nodes.empty())
{
auto n = d.nodes.front();
if (auto p = n.lock())
{
refreshed = true;
ping(p.get());
break;
}
d.nodes.pop_front();
}
}
NodeId randNodeId;
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0, h256::size));
crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size, h256::size));
discover(randNodeId);
}
unsigned nextRefresh = connected ? (refreshed ? 200 : c_bucketRefresh.count()*1000) : 10000;
auto runcb = [this](boost::system::error_code const& error) { doRefreshBuckets(error); };
m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh));
m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(c_bucketRefresh.count()));
m_bucketRefreshTimer.async_wait(runcb);
}

2
libp2p/NodeTable.h

@ -195,7 +195,7 @@ private:
/* todo: replace boost::posix_time; change constants to upper camelcase */
boost::posix_time::milliseconds const c_evictionCheckInterval = boost::posix_time::milliseconds(75); ///< Interval at which eviction timeouts are checked.
std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations).
std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
std::chrono::milliseconds const c_bucketRefresh = std::chrono::milliseconds(112500); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
struct NodeBucket
{

1
libp2p/Peer.h

@ -47,7 +47,6 @@ namespace p2p
* those peers. Modifying these properties via a storage backend alleviates
* Host of the responsibility. (&& remove save/restoreNetwork)
* @todo reimplement recording of historical session information on per-transport basis
* @todo rebuild nodetable when localNetworking is enabled/disabled
* @todo move attributes into protected
*/
class Peer: public Node

8
libp2p/Session.cpp

@ -216,12 +216,8 @@ bool Session::interpret(PacketType _t, RLP const& _r)
NodeId id = _r[i][2].toHash<NodeId>();
clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")";
// clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")" << isPrivateAddress(peerAddress) << this->id().abridged() << isPrivateAddress(endpoint().address()) << m_server->m_peers.count(id) << (m_server->m_peers.count(id) ? isPrivateAddress(m_server->m_peers.at(id)->address.address()) : -1);
// todo: draft spec: ignore if dist(us,item) - dist(us,them) > 1
// TODO: isPrivate
if (!m_server->m_netPrefs.localNetworking && isPrivateAddress(peerAddress))
if (!isPublicAddress(peerAddress))
goto CONTINUE; // Private address. Ignore.
if (!id)
@ -241,7 +237,7 @@ bool Session::interpret(PacketType _t, RLP const& _r)
// OK passed all our checks. Assume it's good.
addRating(1000);
m_server->addNode(id, ep.address().to_string(), ep.port(), ep.port());
m_server->addNode(id, ep.address(), ep.port(), ep.port());
clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")";
CONTINUE:;
LAMEPEER:;

7
libp2p/UDP.h

@ -203,7 +203,10 @@ void UDPSocket<Handler, MaxDatagramSize>::doRead()
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len)
{
if (_ec)
// ASIO Safety: It is possible that ASIO will call lambda w/o an error
// and after the socket has been disconnected. Checking m_closed
// guarantees that m_host will not be called after disconnect().
if (_ec || m_closed)
return disconnectWithError(_ec);
assert(_len);
@ -222,7 +225,7 @@ void UDPSocket<Handler, MaxDatagramSize>::doWrite()
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t)
{
if (_ec)
if (_ec || m_closed)
return disconnectWithError(_ec);
else
{

5
libtestutils/CMakeLists.txt

@ -18,6 +18,11 @@ set(EXECUTABLE testutils)
file(GLOB HEADERS "*.h")
if (NOT JSONRPC)
list(REMOVE_ITEM SRC_LIST "./FixedWebThreeServer.cpp")
list(REMOVE_ITEM HEADERS "./FixedWebThreeServer.h")
endif()
if (ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()

2
libtestutils/Common.cpp

@ -74,7 +74,7 @@ std::string dev::test::toTestFilePath(std::string const& _filename)
std::string dev::test::getRandomPath()
{
std::stringstream stream;
stream << getDataDir() << "/EthereumTests/" << randomNumber();
stream << getDataDir("EthereumTests") << "/" << randomNumber();
return stream.str();
}

8
libtestutils/TransientDirectory.cpp

@ -22,12 +22,16 @@
#include <boost/filesystem.hpp>
#include <libdevcore/Exceptions.h>
#include "TransientDirectory.h"
using namespace std;
using namespace dev;
using namespace dev::test;
TransientDirectory::TransientDirectory(std::string const& _path) : m_path(_path)
TransientDirectory::TransientDirectory():
TransientDirectory((boost::filesystem::temp_directory_path() / "eth_transient" / toString(FixedHash<4>::random())).string())
{}
TransientDirectory::TransientDirectory(std::string const& _path):
m_path(_path)
{
// we never ever want to delete a directory (including all its contents) that we did not create ourselves.
if (boost::filesystem::exists(m_path))

3
libtestutils/TransientDirectory.h

@ -37,7 +37,8 @@ namespace test
class TransientDirectory
{
public:
TransientDirectory(std::string const& _path = getRandomPath());
TransientDirectory();
TransientDirectory(std::string const& _path);
~TransientDirectory();
std::string const& path() const { return m_path; }

16
libwebthree/WebThree.cpp

@ -27,7 +27,6 @@
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libp2p/Host.h>
#include <libethereum/Defaults.h>
#include <libethereum/EthereumHost.h>
#include <libwhisper/WhisperHost.h>
@ -73,12 +72,12 @@ WebThreeDirect::~WebThreeDirect()
m_ethereum.reset();
}
void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n)
void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers)
{
auto had = haveNetwork();
if (had)
stopNetwork();
m_net.setNetworkPreferences(_n);
m_net.setNetworkPreferences(_n, _dropPeers);
if (had)
startNetwork();
}
@ -103,7 +102,14 @@ bytes WebThreeDirect::saveNetwork()
return m_net.saveNetwork();
}
void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port)
void WebThreeDirect::addNode(NodeId const& _node, bi::tcp::endpoint const& _host)
{
m_net.addNode(NodeId(), _seedHost, _port, _port);
m_net.addNode(_node, _host.address(), _host.port(), _host.port());
}
void WebThreeDirect::requirePeer(NodeId const& _node, bi::tcp::endpoint const& _host)
{
m_net.requirePeer(_node, _host.address(), _host.port());
}

37
libwebthree/WebThree.h

@ -63,9 +63,12 @@ public:
/// Same as peers().size(), but more efficient.
virtual size_t peerCount() const = 0;
/// Connect to a particular peer.
virtual void connect(std::string const& _seedHost, unsigned short _port) = 0;
/// Add node to connect to.
virtual void addNode(p2p::NodeId const& _node, bi::tcp::endpoint const& _hostEndpoint) = 0;
/// Require connection to peer.
virtual void requirePeer(p2p::NodeId const& _node, bi::tcp::endpoint const& _endpoint) = 0;
/// Save peers
virtual dev::bytes saveNetwork() = 0;
@ -74,7 +77,7 @@ public:
virtual bool haveNetwork() const = 0;
virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n) = 0;
virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) = 0;
virtual p2p::NodeId id() const = 0;
@ -137,22 +140,34 @@ public:
/// Same as peers().size(), but more efficient.
size_t peerCount() const override;
/// Connect to a particular peer.
void connect(std::string const& _seedHost, unsigned short _port = 30303) override;
/// Add node to connect to.
virtual void addNode(p2p::NodeId const& _node, bi::tcp::endpoint const& _hostEndpoint) override;
/// Add node to connect to.
void addNode(p2p::NodeId const& _node, std::string const& _hostString) { addNode(_node, p2p::Network::resolveHost(_hostString)); }
/// Add node to connect to.
void addNode(bi::tcp::endpoint const& _endpoint) { addNode(p2p::NodeId(), _endpoint); }
/// Add node to connect to.
void addNode(std::string const& _hostString) { addNode(p2p::NodeId(), _hostString); }
/// Require connection to peer.
void requirePeer(p2p::NodeId const& _node, bi::tcp::endpoint const& _endpoint) override;
/// Require connection to peer.
void requirePeer(p2p::NodeId const& _node, std::string const& _hostString) { requirePeer(_node, p2p::Network::resolveHost(_hostString)); }
/// Save peers
dev::bytes saveNetwork() override;
// /// Restore peers
// void restoreNetwork(bytesConstRef _saved) override;
/// Sets the ideal number of peers.
void setIdealPeerCount(size_t _n) override;
bool haveNetwork() const override { return m_net.isStarted(); }
void setNetworkPreferences(p2p::NetworkPreferences const& _n) override;
void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers = false) override;
p2p::NodeId id() const override { return m_net.id(); }

5
mix/MixClient.cpp

@ -112,7 +112,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
State execState = _state;
Executive execution(execState, lastHashes, 0);
execution.setup(&rlp);
execution.initialize(&rlp);
execution.execute();
std::vector<MachineState> machineStates;
std::vector<unsigned> levels;
std::vector<MachineCode> codes;
@ -184,7 +185,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
// execute on a state
if (!_call)
{
_state.execute(lastHashes, rlp);
_state.execute(lastHashes, _t);
if (_t.isCreation() && _state.code(d.contractAddress).empty())
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
// collect watches

2
mix/qml/CodeEditorView.qml

@ -143,7 +143,7 @@ Item {
}
onProjectSaved: {
if (projectModel.appIsClosing)
if (projectModel.appIsClosing || projectModel.projectIsClosing)
return;
for (var i = 0; i < editorListModel.count; i++)
{

5
mix/qml/ProjectModel.qml

@ -35,6 +35,7 @@ Item {
readonly property string projectFileName: ".mix"
property bool appIsClosing: false
property bool projectIsClosing: false
property string projectPath: ""
property string projectTitle: ""
property string currentDocumentId: ""
@ -122,13 +123,17 @@ Item {
icon: StandardIcon.Question
property var callBack;
onYes: {
projectIsClosing = true;
projectModel.saveAll();
unsavedFiles = [];
ProjectModelCode.doCloseProject();
if (callBack)
callBack();
}
onRejected: {}
onNo: {
projectIsClosing = true;
unsavedFiles = [];
ProjectModelCode.doCloseProject();
if (callBack)
callBack();

2
mix/qml/TransactionLog.qml

@ -44,7 +44,7 @@ Item {
target: projectModel
onProjectSaved:
{
if (projectModel.appIsClosing)
if (projectModel.appIsClosing || projectModel.projectIsClosing)
return;
if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running)
projectModel.stateListModel.debugDefaultState();

67
mix/qml/WebCodeEditor.qml

@ -19,9 +19,9 @@ Item {
function setText(text, mode) {
currentText = text;
if(mode !== undefined)
if (mode !== undefined)
currentMode = mode;
if (initialized) {
if (initialized && editorBrowser) {
editorBrowser.runJavaScript("setTextBase64(\"" + Qt.btoa(text) + "\")");
editorBrowser.runJavaScript("setMode(\"" + currentMode + "\")");
}
@ -29,7 +29,8 @@ Item {
}
function setFocus() {
editorBrowser.forceActiveFocus();
if (editorBrowser)
editorBrowser.forceActiveFocus();
}
function getText() {
@ -37,19 +38,19 @@ Item {
}
function syncClipboard() {
if (Qt.platform.os == "osx") {
if (Qt.platform.os == "osx" && editorBrowser) {
var text = clipboard.text;
editorBrowser.runJavaScript("setClipboardBase64(\"" + Qt.btoa(text) + "\")");
}
}
function highlightExecution(location) {
if (initialized)
if (initialized && editorBrowser)
editorBrowser.runJavaScript("highlightExecution(" + location.start + "," + location.end + ")");
}
function showWarning(content) {
if (initialized)
if (initialized && editorBrowser)
editorBrowser.runJavaScript("showWarning('" + content + "')");
}
@ -58,12 +59,12 @@ Item {
}
function toggleBreakpoint() {
if (initialized)
if (initialized && editorBrowser)
editorBrowser.runJavaScript("toggleBreakpoint()");
}
function changeGeneration() {
if (initialized)
if (initialized && editorBrowser)
editorBrowser.runJavaScript("changeGeneration()", function(result) {});
}
@ -84,9 +85,15 @@ Item {
console.log("editor: " + sourceID + ":" + lineNumber + ":" + message);
}
Component.onDestruction:
{
codeModel.onCompilationComplete.disconnect(compilationComplete);
codeModel.onCompilationError.disconnect(compilationError);
}
onLoadingChanged:
{
if (!loading && !unloaded && editorBrowser) {
if (!loading && editorBrowser) {
initialized = true;
setText(currentText, currentMode);
runJavaScript("getTextChanged()", function(result) { });
@ -94,27 +101,31 @@ Item {
syncClipboard();
if (currentMode === "solidity")
{
codeModel.onCompilationComplete.connect(function(){
if (editorBrowser)
editorBrowser.runJavaScript("compilationComplete()", function(result) { });
});
codeModel.onCompilationError.connect(function(error){
if (editorBrowser)
{
var errorInfo = ErrorLocationFormater.extractErrorInfo(error, false);
if (errorInfo.line && errorInfo.column)
editorBrowser.runJavaScript("compilationError('" + errorInfo.line + "', '" + errorInfo.column + "', '" + errorInfo.errorDetail + "')", function(result) { });
else
editorBrowser.runJavaScript("compilationComplete()", function(result) { });
}
});
codeModel.onCompilationComplete.connect(compilationComplete);
codeModel.onCompilationError.connect(compilationError);
}
parent.changeGeneration();
loadComplete();
}
}
function compilationComplete()
{
if (editorBrowser)
editorBrowser.runJavaScript("compilationComplete()", function(result) { });
}
function compilationError(error)
{
if (!editorBrowser || !error)
return;
var errorInfo = ErrorLocationFormater.extractErrorInfo(error, false);
if (errorInfo.line && errorInfo.column)
editorBrowser.runJavaScript("compilationError('" + errorInfo.line + "', '" + errorInfo.column + "', '" + errorInfo.errorDetail + "')", function(result) { });
else
editorBrowser.runJavaScript("compilationComplete()", function(result) { });
}
Timer
{
id: pollTimer
@ -122,10 +133,10 @@ Item {
running: false
repeat: true
onTriggered: {
if (unloaded)
if (!editorBrowser)
return;
editorBrowser.runJavaScript("getTextChanged()", function(result) {
if (result === true) {
if (result === true && editorBrowser) {
editorBrowser.runJavaScript("getText()" , function(textValue) {
currentText = textValue;
editorTextChanged();
@ -133,7 +144,7 @@ Item {
}
});
editorBrowser.runJavaScript("getBreakpointsChanged()", function(result) {
if (result === true) {
if (result === true && editorBrowser) {
editorBrowser.runJavaScript("getBreakpoints()" , function(bp) {
if (currentBreakpoints !== bp) {
currentBreakpoints = bp;

15
mix/qml/html/cm/errorannotation.js

@ -23,12 +23,15 @@ ErrorAnnotation.prototype.init = function()
ErrorAnnotation.prototype.open = function()
{
var node = document.createElement("div");
node.id = "annotation"
node.innerHTML = this.content;
node.className = "CodeMirror-errorannotation-context";
this.lineWidget = this.editor.addLineWidget(this.errorMark.find().from.line, node, { coverGutter: false });
this.opened = true;
if (this.errorMark.find())
{
var node = document.createElement("div");
node.id = "annotation"
node.innerHTML = this.content;
node.className = "CodeMirror-errorannotation-context";
this.lineWidget = this.editor.addLineWidget(this.errorMark.find().from.line, node, { coverGutter: false });
this.opened = true;
}
}
ErrorAnnotation.prototype.close = function()

79
mix/qml/js/ProjectModel.js

@ -51,6 +51,7 @@ function closeProject(callBack) {
}
else
{
projectIsClosing = true;
doCloseProject();
if (callBack)
callBack();
@ -96,45 +97,45 @@ function saveProjectFile()
function loadProject(path) {
closeProject(function() {
console.log("Loading project at " + path);
var projectFile = path + projectFileName;
var json = fileIo.readFile(projectFile);
var projectData = JSON.parse(json);
if (projectData.deploymentDir)
projectModel.deploymentDir = projectData.deploymentDir
if (projectData.packageHash)
deploymentDialog.packageHash = projectData.packageHash
if (projectData.packageBase64)
deploymentDialog.packageBase64 = projectData.packageBase64
if (projectData.applicationUrlEth)
deploymentDialog.applicationUrlEth = projectData.applicationUrlEth
if (projectData.applicationUrlHttp)
deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp
if (!projectData.title) {
var parts = path.split("/");
projectData.title = parts[parts.length - 2];
}
deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : [];
projectTitle = projectData.title;
projectPath = path;
if (!projectData.files)
projectData.files = [];
for(var i = 0; i < projectData.files.length; i++) {
addFile(projectData.files[i]);
}
projectSettings.lastProjectPath = path;
projectLoading(projectData);
projectLoaded()
//TODO: move this to codemodel
var contractSources = {};
for (var d = 0; d < listModel.count; d++) {
var doc = listModel.get(d);
if (doc.isContract)
contractSources[doc.documentId] = fileIo.readFile(doc.path);
}
codeModel.reset(contractSources);
console.log("Loading project at " + path);
var projectFile = path + projectFileName;
var json = fileIo.readFile(projectFile);
var projectData = JSON.parse(json);
if (projectData.deploymentDir)
projectModel.deploymentDir = projectData.deploymentDir
if (projectData.packageHash)
deploymentDialog.packageHash = projectData.packageHash
if (projectData.packageBase64)
deploymentDialog.packageBase64 = projectData.packageBase64
if (projectData.applicationUrlEth)
deploymentDialog.applicationUrlEth = projectData.applicationUrlEth
if (projectData.applicationUrlHttp)
deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp
if (!projectData.title) {
var parts = path.split("/");
projectData.title = parts[parts.length - 2];
}
deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : [];
projectTitle = projectData.title;
projectPath = path;
if (!projectData.files)
projectData.files = [];
for(var i = 0; i < projectData.files.length; i++) {
addFile(projectData.files[i]);
}
projectSettings.lastProjectPath = path;
projectLoading(projectData);
projectLoaded()
//TODO: move this to codemodel
var contractSources = {};
for (var d = 0; d < listModel.count; d++) {
var doc = listModel.get(d);
if (doc.isContract)
contractSources[doc.documentId] = fileIo.readFile(doc.path);
}
codeModel.reset(contractSources);
});
}

386
mix/test/qml/TestTransactionDebug.qml

@ -1,386 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import QtQuick.PrivateWidgets 1.1
import Qt.labs.settings 1.0
import org.ethereum.qml.QEther 1.0
import org.ethereum.qml.CodeModel 1.0
import org.ethereum.qml.ClientModel 1.0
import org.ethereum.qml.FileIo 1.0
import org.ethereum.qml.Clipboard 1.0
ApplicationWindow {
id: mainApplication
signal loaded;
visible: true
width: 1200
height: 800
minimumWidth: 400
minimumHeight: 300
title: qsTr("Mix")
CodeModel {
id: codeModel
}
ClientModel {
id: clientModel
codeModel: codeModel
}
ProjectModel {
id: projectModel
}
FileIo {
id: fileIo
}
Clipboard {
id: clipboard
}
Connections {
target: mainApplication
onClosing:
{
mainApplication.close();
close.accepted = false;
}
}
Component.onCompleted: {
loaded();
}
function close() {
projectModel.appIsClosing = true;
if (projectModel.projectPath !== "")
projectModel.closeProject(function() { Qt.quit(); })
else
Qt.quit();
}
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem { action: createProjectAction }
MenuItem { action: openProjectAction }
MenuSeparator {}
MenuItem { action: saveAllFilesAction }
MenuItem { action: saveCurrentDocument }
MenuSeparator {}
MenuItem { action: addExistingFileAction }
MenuItem { action: addNewJsFileAction }
MenuItem { action: addNewHtmlFileAction }
MenuItem { action: addNewCssFileAction }
MenuSeparator {}
MenuItem { action: addNewContractAction }
MenuItem { action: closeProjectAction }
MenuSeparator {}
MenuItem { action: exitAppAction }
}
Menu {
title: qsTr("Deploy")
MenuItem { action: mineAction }
MenuSeparator {}
MenuItem { action: editStatesAction }
MenuSeparator {}
MenuItem { action: deployViaRpcAction }
MenuSeparator {}
MenuItem { action: toggleRunOnLoadAction }
}
Menu {
title: qsTr("Debug")
MenuItem { action: debugRunAction }
MenuSeparator {}
MenuItem { action: toggleAssemblyDebuggingAction }
}
Menu {
title: qsTr("Windows")
MenuItem { action: openNextDocumentAction }
MenuItem { action: openPrevDocumentAction }
MenuSeparator {}
MenuItem { action: toggleProjectNavigatorAction }
MenuItem { action: showHideRightPanelAction }
MenuItem { action: toggleTransactionLogAction }
MenuItem { action: toggleWebPreviewAction }
MenuItem { action: toggleWebPreviewOrientationAction }
//MenuItem { action: toggleCallsInLog }
}
}
MainContent {
id: mainContent;
anchors.fill: parent
}
ModalDialog {
objectName: "dialog"
id: dialog
}
AlertMessageDialog {
objectName: "alertMessageDialog"
id: messageDialog
}
Settings {
id: mainWindowSettings
property alias mainWidth: mainApplication.width
property alias mainHeight: mainApplication.height
property alias mainX: mainApplication.x
property alias mainY: mainApplication.y
}
Action {
id: exitAppAction
text: qsTr("Exit")
shortcut: "Ctrl+Q"
onTriggered:
{
mainApplication.close();
}
}
Action {
id: mineAction
text: qsTr("New Block")
shortcut: "Ctrl+M"
onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining
}
StateList {
id: stateList
}
Action {
id: editStatesAction
text: qsTr("Edit States")
shortcut: "Ctrl+Alt+E"
onTriggered: stateList.show();
}
Connections {
target: projectModel.stateListModel
function updateRunLabel()
{
debugRunAction.text = qsTr("Deploy") + " \"" + projectModel.stateListModel.defaultStateName() + "\"";
}
onDefaultStateChanged: updateRunLabel()
onStateListModelReady: updateRunLabel()
}
Action {
id: debugRunAction
text: qsTr("Deploy")
shortcut: "F5"
onTriggered: mainContent.startQuickDebugging()
enabled: codeModel.hasContract && !clientModel.running
}
Action {
id: toggleAssemblyDebuggingAction
text: qsTr("Show VM Code")
shortcut: "Ctrl+Alt+V"
onTriggered: mainContent.rightPane.assemblyMode = !mainContent.rightPane.assemblyMode;
checked: mainContent.rightPane.assemblyMode;
enabled: true
}
Action {
id: toggleWebPreviewAction
text: qsTr("Show Web View")
shortcut: "F2"
checkable: true
checked: mainContent.webViewVisible
onTriggered: mainContent.toggleWebPreview();
}
Action {
id: toggleTransactionLogAction
text: qsTr("Show States and Transactions")
shortcut: "Alt+1"
checkable: true
checked: mainContent.rightPane.transactionLog.visible
onTriggered: mainContent.rightPane.transactionLog.visible = !mainContent.rightPane.transactionLog.visible
}
Action {
id: toggleProjectNavigatorAction
text: qsTr("Show Project Navigator")
shortcut: "Alt+0"
checkable: true
checked: mainContent.projectViewVisible
onTriggered: mainContent.toggleProjectView();
}
Action {
id: toggleWebPreviewOrientationAction
text: qsTr("Horizontal Web View")
shortcut: ""
checkable: true
checked: mainContent.webViewHorizontal
onTriggered: mainContent.toggleWebPreviewOrientation();
}
Action {
id: toggleRunOnLoadAction
text: qsTr("Load State on Startup")
shortcut: ""
checkable: true
checked: mainContent.runOnProjectLoad
onTriggered: mainContent.runOnProjectLoad = !mainContent.runOnProjectLoad
}
Action {
id: showHideRightPanelAction
text: qsTr("Show Right View")
shortcut: "F7"
checkable: true
checked: mainContent.rightViewVisible
onTriggered: mainContent.toggleRightView();
}
Action {
id: createProjectAction
text: qsTr("&New Project")
shortcut: "Ctrl+N"
enabled: true;
onTriggered: projectModel.createProject();
}
Action {
id: openProjectAction
text: qsTr("&Open Project")
shortcut: "Ctrl+O"
enabled: true;
onTriggered: openProjectFileDialog.open()
}
FileDialog {
id: openProjectFileDialog
visible: false
title: qsTr("Open a Project")
selectFolder: true
onAccepted: {
var path = openProjectFileDialog.fileUrl.toString();
path += "/";
projectModel.loadProject(path);
}
}
Action {
id: addNewJsFileAction
text: qsTr("New JavaScript File")
shortcut: "Ctrl+Alt+J"
enabled: !projectModel.isEmpty
onTriggered: projectModel.newJsFile();
}
Action {
id: addNewHtmlFileAction
text: qsTr("New HTML File")
shortcut: "Ctrl+Alt+H"
enabled: !projectModel.isEmpty
onTriggered: projectModel.newHtmlFile();
}
Action {
id: addNewCssFileAction
text: qsTr("New CSS File")
shortcut: "Ctrl+Alt+S"
enabled: !projectModel.isEmpty
onTriggered: projectModel.newCssFile();
}
Action {
id: addNewContractAction
text: qsTr("New Contract")
shortcut: "Ctrl+Alt+C"
enabled: !projectModel.isEmpty
onTriggered: projectModel.newContract();
}
Action {
id: addExistingFileAction
text: qsTr("Add Existing File")
shortcut: "Ctrl+Alt+A"
enabled: !projectModel.isEmpty
onTriggered: addExistingFileDialog.open()
}
FileDialog {
id: addExistingFileDialog
visible: false
title: qsTr("Add a File")
selectFolder: false
onAccepted: {
var paths = addExistingFileDialog.fileUrls;
projectModel.addExistingFiles(paths);
}
}
Action {
id: saveAllFilesAction
text: qsTr("Save All")
shortcut: "Ctrl+Shift+A"
enabled: !projectModel.isEmpty
onTriggered: projectModel.saveAll();
}
Action {
id: saveCurrentDocument
text: qsTr("Save Current Document")
shortcut: "Ctrl+S"
enabled: !projectModel.isEmpty
onTriggered: projectModel.saveCurrentDocument();
}
Action {
id: closeProjectAction
text: qsTr("Close Project")
shortcut: "Ctrl+W"
enabled: !projectModel.isEmpty
onTriggered: projectModel.closeProject();
}
Action {
id: openNextDocumentAction
text: qsTr("Next Document")
shortcut: "Ctrl+Tab"
enabled: !projectModel.isEmpty
onTriggered: projectModel.openNextDocument();
}
Action {
id: openPrevDocumentAction
text: qsTr("Previous Document")
shortcut: "Ctrl+Shift+Tab"
enabled: !projectModel.isEmpty
onTriggered: projectModel.openPrevDocument();
}
Action {
id: toggleBreakpointAction
text: qsTr("Toggle Breakpoint")
shortcut: "F9"
enabled: mainContent.codeEditor.editingContract();
onTriggered: mainContent.toggleBreakpoint();
}
Action {
id: deployViaRpcAction
text: qsTr("Deploy to Network")
shortcut: "Ctrl+Shift+D"
enabled: !projectModel.isEmpty && codeModel.hasContract
onTriggered: projectModel.deployProject();
}
}

30
neth/main.cpp

@ -84,8 +84,9 @@ void help()
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif
<< " -K,--kill-blockchain First kill the blockchain." << endl
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " --listen-ip <ip> Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
<< " -l,--listen <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -m,--mining <on/off> Enable mining (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
@ -94,7 +95,6 @@ void help()
<< " -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
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
@ -321,7 +321,9 @@ enum class NodeMode
int main(int argc, char** argv)
{
string listenIP;
unsigned short listenPort = 30303;
string publicIP;
string remoteHost;
unsigned short remotePort = 30303;
string dbPath;
@ -332,10 +334,8 @@ int main(int argc, char** argv)
#if ETH_JSONRPC
int jsonrpc = 8080;
#endif
string publicIP;
bool bootstrap = false;
bool upnp = true;
bool useLocal = false;
bool forceMining = false;
bool killChain = false;
bool jit = false;
@ -371,7 +371,9 @@ int main(int argc, char** argv)
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
if (arg == "--listen-ip" && i + 1 < argc)
listenIP = argv[++i];
else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
listenPort = (short)atoi(argv[++i]);
else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
publicIP = argv[++i];
@ -392,8 +394,6 @@ int main(int argc, char** argv)
return -1;
}
}
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if (arg == "-K" || arg == "--kill-blockchain")
killChain = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
@ -535,6 +535,8 @@ int main(int argc, char** argv)
}
}
if (!clientName.empty())
clientName += "/";
@ -542,7 +544,7 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3(
@ -570,9 +572,9 @@ int main(int argc, char** argv)
web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
if (c && mining)
c->startMining();
@ -687,7 +689,9 @@ int main(int argc, char** argv)
{
unsigned port;
iss >> port;
web3.setNetworkPreferences(NetworkPreferences((short)port, publicIP, upnp));
if (port)
netPrefs.listenPort = port;
web3.setNetworkPreferences(netPrefs);
web3.startNetwork();
}
else if (cmd == "connect")
@ -695,7 +699,7 @@ int main(int argc, char** argv)
string addr;
unsigned port;
iss >> addr >> port;
web3.connect(addr, (short)port);
web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
}
else if (cmd == "netstop")
{

57
test/blockchain.cpp

@ -20,7 +20,9 @@
* block test functions.
*/
#include <boost/filesystem.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libtestutils/TransientDirectory.h>
#include <libethereum/CanonBlockChain.h>
#include "TestHelper.h"
@ -35,8 +37,8 @@ bytes createBlockRLPFromFields(mObject& _tObj);
void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj);
BlockInfo constructBlock(mObject& _o);
void updatePoW(BlockInfo& _bi);
void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi);
RLPStream createFullBlockFromHeader(const BlockInfo& _bi, const bytes& _txs = RLPEmptyList, const bytes& _uncles = RLPEmptyList);
void writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi);
RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList);
void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
{
@ -75,7 +77,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
o["genesisRLP"] = "0x" + toHex(rlpGenesisBlock.out());
// construct blockchain
BlockChain bc(rlpGenesisBlock.out(), string(), true);
TransientDirectory td;
BlockChain bc(rlpGenesisBlock.out(), td.path(), true);
if (_fillin)
{
@ -182,18 +185,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
Transactions txList;
for (auto const& txi: txs.transactions())
{
Transaction tx(txi.second, CheckSignature::Sender);
txList.push_back(tx);
txList.push_back(txi.second);
mObject txObject;
txObject["nonce"] = toString(tx.nonce());
txObject["data"] = "0x" + toHex(tx.data());
txObject["gasLimit"] = toString(tx.gas());
txObject["gasPrice"] = toString(tx.gasPrice());
txObject["r"] = "0x" + toString(tx.signature().r);
txObject["s"] = "0x" + toString(tx.signature().s);
txObject["v"] = to_string(tx.signature().v + 27);
txObject["to"] = tx.isCreation() ? "" : toString(tx.receiveAddress());
txObject["value"] = toString(tx.value());
txObject["nonce"] = toString(txi.second.nonce());
txObject["data"] = "0x" + toHex(txi.second.data());
txObject["gasLimit"] = toString(txi.second.gas());
txObject["gasPrice"] = toString(txi.second.gasPrice());
txObject["r"] = "0x" + toString(txi.second.signature().r);
txObject["s"] = "0x" + toString(txi.second.signature().s);
txObject["v"] = to_string(txi.second.signature().v + 27);
txObject["to"] = txi.second.isCreation() ? "" : toString(txi.second.receiveAddress());
txObject["value"] = toString(txi.second.value());
txArray.push_back(txObject);
}
@ -242,6 +244,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (sha3(RLP(state.blockData())[2].data()) != sha3(RLP(block2.out())[2].data()))
cnote << "uncle list mismatch\n" << RLP(state.blockData())[2].data() << "\n" << RLP(block2.out())[2].data();
try
{
state.sync(bc);
@ -293,7 +296,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BOOST_CHECK(blObj.count("uncleHeaders") == 0);
continue;
}
catch(...)
catch (...)
{
cnote << "state sync or block import did throw an exception\n";
BOOST_CHECK(blObj.count("blockHeader") == 0);
@ -389,7 +392,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match");
}
// check uncle list
@ -489,12 +491,12 @@ bytes createBlockRLPFromFields(mObject& _tObj)
return rlpStream.out();
}
void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj)
{
if (_blObj["blockHeader"].get_obj().size() != 14)
{
BlockInfo tmp = _current_BlockHeader;
BlockInfo tmp = _currentBlockHeader;
if (_blObj["blockHeader"].get_obj().count("parentHash"))
tmp.parentHash = h256(_blObj["blockHeader"].get_obj()["parentHash"].get_str());
@ -540,16 +542,16 @@ void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
// find new valid nonce
if (tmp != _current_BlockHeader)
if (tmp != _currentBlockHeader)
{
_current_BlockHeader = tmp;
_currentBlockHeader = tmp;
ProofOfWork pow;
std::pair<MineInfo, Ethash::Proof> ret;
while (!ProofOfWork::verify(_current_BlockHeader))
while (!ProofOfWork::verify(_currentBlockHeader))
{
ret = pow.mine(_current_BlockHeader, 1000, true, true);
Ethash::assignResult(ret.second, _current_BlockHeader);
ret = pow.mine(_currentBlockHeader, 1000, true, true);
Ethash::assignResult(ret.second, _currentBlockHeader);
}
}
}
@ -558,13 +560,12 @@ void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
// take the blockheader as is
const bytes c_blockRLP = createBlockRLPFromFields(_blObj["blockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP);
_current_BlockHeader.populateFromHeader(c_bRLP, IgnoreNonce);
_currentBlockHeader.populateFromHeader(c_bRLP, IgnoreNonce);
}
}
BlockInfo constructBlock(mObject& _o)
{
BlockInfo ret;
try
{
@ -601,7 +602,7 @@ void updatePoW(BlockInfo& _bi)
_bi.hash = _bi.headerHash(WithNonce);
}
void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi)
void writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi)
{
_o["parentHash"] = toString(_bi.parentHash);
_o["uncleHash"] = toString(_bi.sha3Uncles);
@ -621,7 +622,7 @@ void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi)
_o["hash"] = toString(_bi.hash);
}
RLPStream createFullBlockFromHeader(const BlockInfo& _bi,const bytes& _txs, const bytes& _uncles )
RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs, bytes const& _uncles)
{
RLPStream rlpStream;
_bi.streamRLP(rlpStream, WithNonce);
@ -633,8 +634,8 @@ RLPStream createFullBlockFromHeader(const BlockInfo& _bi,const bytes& _txs, cons
return ret;
}
} }// Namespace Close
} }// Namespace Close
BOOST_AUTO_TEST_SUITE(BlockChainTests)

3
test/checkRandomStateTest.cpp

@ -83,12 +83,11 @@ bool doStateTest(mValue& _v)
ImportTest importer(o, false);
eth::State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp();
bytes output;
try
{
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
}
catch (Exception const& _e)
{

3
test/createRandomStateTest.cpp

@ -183,12 +183,11 @@ void doStateTests(json_spirit::mValue& _v)
test::ImportTest importer(o, true);
eth::State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp();
bytes output;
try
{
output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx).output;
output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
}
catch (Exception const& _e)
{

14
test/peer.cpp

@ -35,8 +35,8 @@ BOOST_AUTO_TEST_CASE(host)
auto oldLogVerbosity = g_logVerbosity;
g_logVerbosity = 10;
NetworkPreferences host1prefs(30301, "127.0.0.1", false, true);
NetworkPreferences host2prefs(30302, "127.0.0.1", false, true);
NetworkPreferences host1prefs("127.0.0.1", 30301, false);
NetworkPreferences host2prefs("127.0.0.1", 30302, false);
Host host1("Test", host1prefs);
host1.start();
@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(host)
auto node2 = host2.id();
host2.start();
host1.addNode(node2, "127.0.0.1", host2prefs.listenPort, host2prefs.listenPort);
host1.addNode(node2, bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort);
this_thread::sleep_for(chrono::seconds(3));
@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(save_nodes)
std::list<Host*> hosts;
for (auto i:{0,1,2,3,4,5})
{
Host* h = new Host("Test", NetworkPreferences(30300 + i, "127.0.0.1", false, true));
Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 30300 + i, false));
h->setIdealPeerCount(10);
// starting host is required so listenport is available
h->start();
@ -73,11 +73,11 @@ BOOST_AUTO_TEST_CASE(save_nodes)
Host& host = *hosts.front();
for (auto const& h: hosts)
host.addNode(h->id(), "127.0.0.1", h->listenPort(), h->listenPort());
host.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort());
Host& host2 = *hosts.back();
for (auto const& h: hosts)
host2.addNode(h->id(), "127.0.0.1", h->listenPort(), h->listenPort());
host2.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort());
this_thread::sleep_for(chrono::milliseconds(2000));
bytes firstHostNetwork(host.saveNetwork());
@ -122,7 +122,7 @@ int peerTest(int argc, char** argv)
Host ph("Test", NetworkPreferences(listenPort));
if (!remoteHost.empty() && !remoteAlias)
ph.addNode(remoteAlias, remoteHost, remotePort, remotePort);
ph.addNode(remoteAlias, bi::address::from_string(remoteHost), remotePort, remotePort);
this_thread::sleep_for(chrono::milliseconds(200));

3
test/solidityExecutionFramework.h

@ -142,7 +142,8 @@ protected:
try
{
// this will throw since the transaction is invalid, but it should nevertheless store the transaction
executive.setup(&transactionRLP);
executive.initialize(&transactionRLP);
executive.execute();
}
catch (...) {}
if (_isCreation)

3
test/state.cpp

@ -57,13 +57,12 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
ImportTest importer(o, _fillin);
State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp();
bytes output;
try
{
Listener::ExecTimeGuard guard{i.first};
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
}
catch (Exception const& _e)
{

10
test/stateOriginal.cpp

@ -79,13 +79,9 @@ BOOST_AUTO_TEST_CASE(Complex)
cout << s;
// Inject a transaction to transfer funds from miner to me.
bytes tx;
{
Transaction t(1000, 10000, 10000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address());
tx = t.rlp();
}
s.execute(bc, tx);
Transaction t(1000, 10000, 10000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address());
s.execute(bc.lastHashes(), t);
cout << s;

Loading…
Cancel
Save