Browse Source

Merge branch 'develop' into secp256k1a

cl-refactor
subtly 10 years ago
parent
commit
f484f43f18
  1. 2663
      eth/main.cpp
  2. 2
      libdevcore/Common.cpp
  3. 2
      libdevcore/Common.h
  4. 99
      libdevcore/CommonData.h
  5. 146
      libdevcore/RangeMask.h
  6. 95
      libethereum/BasicGasPricer.cpp
  7. 53
      libethereum/BasicGasPricer.h
  8. 62
      libethereum/BlockChain.cpp
  9. 7
      libethereum/BlockChain.h
  10. 8
      libethereum/BlockChainSync.cpp
  11. 1
      libethereum/BlockChainSync.h
  12. 2
      libethereum/BlockQueue.cpp
  13. 242
      libethereum/Client.cpp
  14. 27
      libethereum/Client.h
  15. 21
      libethereum/ClientBase.cpp
  16. 4
      libethereum/ClientBase.h
  17. 2
      libethereum/EthereumHost.cpp
  18. 1
      libethereum/EthereumHost.h
  19. 1
      libethereum/EthereumPeer.h
  20. 2
      libethereum/Executive.h
  21. 26
      libethereum/GasPricer.cpp
  22. 74
      libethereum/GasPricer.h
  23. 5
      libethereum/Interface.h
  24. 24
      libethereum/State.cpp
  25. 42
      libethereum/State.h
  26. 20
      libethereum/Transaction.h
  27. 8
      libethereum/TransactionQueue.cpp
  28. 51
      libethereum/Utility.cpp
  29. 2
      libethereum/Utility.h
  30. 1
      libp2p/Host.h
  31. 2
      libp2p/Session.cpp
  32. 1
      libp2p/Session.h
  33. 45
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  34. 8
      libweb3jsonrpc/WebThreeStubServerBase.h
  35. 16
      libweb3jsonrpc/abstractwebthreestubserver.h
  36. 8
      libweb3jsonrpc/spec.json
  37. 28
      libwhisper/BloomFilter.cpp
  38. 6
      libwhisper/BloomFilter.h
  39. 2
      libwhisper/Common.cpp
  40. 7
      libwhisper/Common.h
  41. 9
      libwhisper/Message.cpp
  42. 2
      libwhisper/Message.h
  43. 24
      libwhisper/WhisperHost.cpp
  44. 2
      libwhisper/WhisperHost.h
  45. 43
      libwhisper/WhisperPeer.cpp
  46. 4
      libwhisper/WhisperPeer.h
  47. 42
      mix/ClientModel.cpp
  48. 14
      mix/ClientModel.h
  49. 2
      mix/CodeModel.cpp
  50. 2
      mix/qml.qrc
  51. 244
      mix/qml/Block.qml
  52. 84
      mix/qml/BlockChain.qml
  53. 134
      mix/qml/KeyValuePanel.qml
  54. 2
      mix/qml/MainContent.qml
  55. 124
      mix/qml/ScenarioExecution.qml
  56. 9
      mix/qml/ScenarioLoader.qml
  57. 3
      mix/qml/StateListModel.qml
  58. 7
      mix/qml/TransactionDialog.qml
  59. 203
      mix/qml/Watchers.qml
  60. 5
      mix/res.qrc
  61. 148
      test/libdevcore/RangeMask.cpp
  62. 5
      test/libethereum/gaspricer.cpp
  63. 64
      test/libethereum/transactionqueue.cpp
  64. 24
      test/libweb3jsonrpc/webthreestubclient.h
  65. 8
      test/libwhisper/bloomFilter.cpp

2663
eth/main.cpp

File diff suppressed because it is too large

2
libdevcore/Common.cpp

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

2
libdevcore/Common.h

@ -64,6 +64,8 @@ using byte = uint8_t;
#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
#define DEV_IF_NO_ELSE(X) if(!(X)){}else
namespace dev namespace dev
{ {

99
libdevcore/CommonData.h

@ -50,8 +50,8 @@ enum class HexPrefix
/// Convert a series of bytes to the corresponding string of hex duplets. /// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of the first 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" /// @example toHex("A\x69") == "4169"
template <class _T> template <class T>
std::string toHex(_T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd) std::string toHex(T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd)
{ {
std::ostringstream ret; std::ostringstream ret;
unsigned ii = 0; unsigned ii = 0;
@ -99,27 +99,27 @@ bytes asNibbles(bytesConstRef const& _s);
/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection. /// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
/// The size of the collection object will be unchanged. If it is too small, it will not represent the /// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out. /// value properly, if too big then the additional elements will be zeroed out.
/// @a _Out will typically be either std::string or bytes. /// @a Out will typically be either std::string or bytes.
/// @a _T will typically by unsigned, u160, u256 or bigint. /// @a T will typically by unsigned, u160, u256 or bigint.
template <class _T, class _Out> template <class T, class Out>
inline void toBigEndian(_T _val, _Out& o_out) inline void toBigEndian(T _val, Out& o_out)
{ {
for (auto i = o_out.size(); i != 0; _val >>= 8, i--) for (auto i = o_out.size(); i != 0; _val >>= 8, i--)
{ {
_T v = _val & (_T)0xff; T v = _val & (T)0xff;
o_out[i - 1] = (typename _Out::value_type)(uint8_t)v; o_out[i - 1] = (typename Out::value_type)(uint8_t)v;
} }
} }
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value. /// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
/// @a _In will typically be either std::string or bytes. /// @a _In will typically be either std::string or bytes.
/// @a _T will typically by unsigned, u160, u256 or bigint. /// @a T will typically by unsigned, u160, u256 or bigint.
template <class _T, class _In> template <class T, class _In>
inline _T fromBigEndian(_In const& _bytes) inline T fromBigEndian(_In const& _bytes)
{ {
_T ret = (_T)0; T ret = (T)0;
for (auto i: _bytes) for (auto i: _bytes)
ret = (_T)((ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i); ret = (T)((ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i);
return ret; return ret;
} }
@ -131,11 +131,11 @@ inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); ret
/// Convenience function for toBigEndian. /// Convenience function for toBigEndian.
/// @returns a byte array just big enough to represent @a _val. /// @returns a byte array just big enough to represent @a _val.
template <class _T> template <class T>
inline bytes toCompactBigEndian(_T _val, unsigned _min = 0) inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
{ {
int i = 0; int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {} for (T v = _val; v; ++i, v >>= 8) {}
bytes ret(std::max<unsigned>(_min, i), 0); bytes ret(std::max<unsigned>(_min, i), 0);
toBigEndian(_val, ret); toBigEndian(_val, ret);
return ret; return ret;
@ -147,11 +147,11 @@ inline bytes toCompactBigEndian(byte _val, unsigned _min = 0)
/// Convenience function for toBigEndian. /// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val. /// @returns a string just big enough to represent @a _val.
template <class _T> template <class T>
inline std::string toCompactBigEndianString(_T _val, unsigned _min = 0) inline std::string toCompactBigEndianString(T _val, unsigned _min = 0)
{ {
int i = 0; int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {} for (T v = _val; v; ++i, v >>= 8) {}
std::string ret(std::max<unsigned>(_min, i), '\0'); std::string ret(std::max<unsigned>(_min, i), '\0');
toBigEndian(_val, ret); toBigEndian(_val, ret);
return ret; return ret;
@ -179,8 +179,8 @@ std::string escaped(std::string const& _s, bool _all = true);
/// Determines the length of the common prefix of the two collections given. /// Determines the length of the common prefix of the two collections given.
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning. /// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5 /// @example commonPrefix("Hello world!", "Hello, world!") == 5
template <class _T, class _U> template <class T, class _U>
unsigned commonPrefix(_T const& _t, _U const& _u) unsigned commonPrefix(T const& _t, _U const& _u)
{ {
unsigned s = std::min<unsigned>(_t.size(), _u.size()); unsigned s = std::min<unsigned>(_t.size(), _u.size());
for (unsigned i = 0;; ++i) for (unsigned i = 0;; ++i)
@ -196,8 +196,8 @@ std::string randomWord();
// General datatype convenience functions. // General datatype convenience functions.
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. /// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class _T> template <class T>
inline unsigned bytesRequired(_T _i) inline unsigned bytesRequired(T _i)
{ {
unsigned i = 0; unsigned i = 0;
for (; _i != 0; ++i, _i >>= 8) {} for (; _i != 0; ++i, _i >>= 8) {}
@ -206,39 +206,39 @@ inline unsigned bytesRequired(_T _i)
/// Trims a given number of elements from the front of a collection. /// Trims a given number of elements from the front of a collection.
/// Only works for POD element types. /// Only works for POD element types.
template <class _T> template <class T>
void trimFront(_T& _t, unsigned _elements) void trimFront(T& _t, unsigned _elements)
{ {
static_assert(std::is_pod<typename _T::value_type>::value, ""); static_assert(std::is_pod<typename T::value_type>::value, "");
memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0])); memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));
_t.resize(_t.size() - _elements); _t.resize(_t.size() - _elements);
} }
/// Pushes an element on to the front of a collection. /// Pushes an element on to the front of a collection.
/// Only works for POD element types. /// Only works for POD element types.
template <class _T, class _U> template <class T, class _U>
void pushFront(_T& _t, _U _e) void pushFront(T& _t, _U _e)
{ {
static_assert(std::is_pod<typename _T::value_type>::value, ""); static_assert(std::is_pod<typename T::value_type>::value, "");
_t.push_back(_e); _t.push_back(_e);
memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e)); memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e));
_t[0] = _e; _t[0] = _e;
} }
/// Concatenate two vectors of elements of POD types. /// Concatenate two vectors of elements of POD types.
template <class _T> template <class T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b) inline std::vector<T>& operator+=(std::vector<typename std::enable_if<std::is_pod<T>::value, T>::type>& _a, std::vector<T> const& _b)
{ {
auto s = _a.size(); auto s = _a.size();
_a.resize(_a.size() + _b.size()); _a.resize(_a.size() + _b.size());
memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(_T)); memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(T));
return _a; return _a;
} }
/// Concatenate two vectors of elements. /// Concatenate two vectors of elements.
template <class _T> template <class T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<!std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b) inline std::vector<T>& operator+=(std::vector<typename std::enable_if<!std::is_pod<T>::value, T>::type>& _a, std::vector<T> const& _b)
{ {
_a.reserve(_a.size() + _b.size()); _a.reserve(_a.size() + _b.size());
for (auto& i: _b) for (auto& i: _b)
@ -289,16 +289,16 @@ template <class T, class U> std::vector<T> operator+(std::vector<T> _a, U const&
} }
/// Concatenate two vectors of elements. /// Concatenate two vectors of elements.
template <class _T> template <class T>
inline std::vector<_T> operator+(std::vector<_T> const& _a, std::vector<_T> const& _b) inline std::vector<T> operator+(std::vector<T> const& _a, std::vector<T> const& _b)
{ {
std::vector<_T> ret(_a); std::vector<T> ret(_a);
return ret += _b; return ret += _b;
} }
/// Merge two sets of elements. /// Merge two sets of elements.
template <class _T> template <class T>
inline std::set<_T>& operator+=(std::set<_T>& _a, std::set<_T> const& _b) inline std::set<T>& operator+=(std::set<T>& _a, std::set<T> const& _b)
{ {
for (auto& i: _b) for (auto& i: _b)
_a.insert(i); _a.insert(i);
@ -306,13 +306,28 @@ inline std::set<_T>& operator+=(std::set<_T>& _a, std::set<_T> const& _b)
} }
/// Merge two sets of elements. /// Merge two sets of elements.
template <class _T> template <class T>
inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b) inline std::set<T> operator+(std::set<T> const& _a, std::set<T> const& _b)
{ {
std::set<_T> ret(_a); std::set<T> ret(_a);
return ret += _b; return ret += _b;
} }
template <class A, class B>
std::unordered_map<A, B>& operator+=(std::unordered_map<A, B>& _x, std::unordered_map<A, B> const& _y)
{
for (auto const& i: _y)
_x.insert(i);
return _x;
}
template <class A, class B>
std::unordered_map<A, B> operator+(std::unordered_map<A, B> const& _x, std::unordered_map<A, B> const& _y)
{
std::unordered_map<A, B> ret(_x);
return ret += _y;
}
/// Make normal string from fixed-length string. /// Make normal string from fixed-length string.
std::string toString(string32 const& _s); std::string toString(string32 const& _s);

146
libdevcore/RangeMask.h

@ -24,6 +24,7 @@
#include <map> #include <map>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <iterator>
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
@ -35,6 +36,12 @@ class RLPStream;
using UnsignedRange = std::pair<unsigned, unsigned>; using UnsignedRange = std::pair<unsigned, unsigned>;
using UnsignedRanges = std::vector<UnsignedRange>; using UnsignedRanges = std::vector<UnsignedRange>;
/**
* Set of elements of a certain "ground range" representable by unions of ranges inside this
* ground range.
* Ranges are given as pairs (begin, end), denoting the interval [begin, end), i.e. end is excluded.
* Supports set-theoretic operators, size and iteration.
*/
template <class T> template <class T>
class RangeMask class RangeMask
{ {
@ -44,14 +51,19 @@ public:
using Range = std::pair<T, T>; using Range = std::pair<T, T>;
using Ranges = std::vector<Range>; using Ranges = std::vector<Range>;
/// Constructs an empty range mask with empty ground range.
RangeMask(): m_all(0, 0) {} RangeMask(): m_all(0, 0) {}
/// Constructs an empty range mask with ground range [_begin, _end).
RangeMask(T _begin, T _end): m_all(_begin, _end) {} RangeMask(T _begin, T _end): m_all(_begin, _end) {}
/// Constructs an empty range mask with ground range _c.
RangeMask(Range const& _c): m_all(_c) {} RangeMask(Range const& _c): m_all(_c) {}
/// @returns the union with the range mask _m, taking also the union of the ground ranges.
RangeMask unionedWith(RangeMask const& _m) const { return operator+(_m); } RangeMask unionedWith(RangeMask const& _m) const { return operator+(_m); }
RangeMask operator+(RangeMask const& _m) const { return RangeMask(*this) += _m; } RangeMask operator+(RangeMask const& _m) const { return RangeMask(*this) += _m; }
RangeMask lowest(T _items) const /// @returns a new range mask containing the smallest _items elements (not ranges).
RangeMask lowest(decltype(T{} - T{}) _items) const
{ {
RangeMask ret(m_all); RangeMask ret(m_all);
for (auto i = m_ranges.begin(); i != m_ranges.end() && _items; ++i) for (auto i = m_ranges.begin(); i != m_ranges.end() && _items; ++i)
@ -59,8 +71,10 @@ public:
return ret; return ret;
} }
/// @returns the complement of the range mask relative to the ground range.
RangeMask operator~() const { return inverted(); } RangeMask operator~() const { return inverted(); }
/// @returns a copy of this range mask representing the complement relative to the ground range.
RangeMask inverted() const RangeMask inverted() const
{ {
RangeMask ret(m_all); RangeMask ret(m_all);
@ -76,6 +90,8 @@ public:
return ret; return ret;
} }
/// Changes the range mask to its complement relative to the ground range and returns a
/// reference to itself.
RangeMask& invert() { return *this = inverted(); } RangeMask& invert() { return *this = inverted(); }
template <class S> RangeMask operator-(S const& _m) const { auto ret = *this; return ret -= _m; } template <class S> RangeMask operator-(S const& _m) const { auto ret = *this; return ret -= _m; }
@ -92,61 +108,13 @@ public:
return *this; return *this;
} }
RangeMask& operator+=(Range const& _m) { return unionWith(_m); } RangeMask& operator+=(Range const& _m) { return unionWith(_m); }
RangeMask& unionWith(Range const& _m) /// Modifies this range mask to also include the range _m, which has to be a subset of
{ /// the ground range.
for (auto i = _m.first; i < _m.second;) RangeMask& unionWith(Range const& _m);
{
assert(i >= m_all.first);
assert(i < m_all.second);
// for each number, we find the element equal or next lower. this, if any, must contain the value.
auto uit = m_ranges.upper_bound(i);
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit);
if (it == m_ranges.end() || it->second < i)
// lower range is too low to merge.
// if the next higher range is too high.
if (uit == m_ranges.end() || uit->first > _m.second)
{
// just create a new range
m_ranges[i] = _m.second;
break;
}
else
{
if (uit->first == i)
// move i to end of range
i = uit->second;
else
{
// merge with the next higher range
// move i to end of range
i = m_ranges[i] = uit->second;
i = uit->second;
m_ranges.erase(uit);
}
}
else if (it->second == i)
{
// if the next higher range is too high.
if (uit == m_ranges.end() || uit->first > _m.second)
{
// merge with the next lower range
m_ranges[it->first] = _m.second;
break;
}
else
{
// merge with both next lower & next higher.
i = m_ranges[it->first] = uit->second;
m_ranges.erase(uit);
}
}
else
i = it->second;
}
return *this;
}
/// Adds the single element _i to the range mask.
RangeMask& operator+=(T _m) { return unionWith(_m); } RangeMask& operator+=(T _m) { return unionWith(_m); }
/// Adds the single element _i to the range mask.
RangeMask& unionWith(T _i) RangeMask& unionWith(T _i)
{ {
return operator+=(Range(_i, _i + 1)); return operator+=(Range(_i, _i + 1));
@ -181,10 +149,12 @@ public:
m_all = std::make_pair(0, 0); m_all = std::make_pair(0, 0);
} }
/// @returns the ground range.
std::pair<T, T> const& all() const { return m_all; } std::pair<T, T> const& all() const { return m_all; }
/// Extends the ground range to include _i.
void extendAll(T _i) { m_all = std::make_pair(std::min(m_all.first, _i), std::max(m_all.second, _i + 1)); } void extendAll(T _i) { m_all = std::make_pair(std::min(m_all.first, _i), std::max(m_all.second, _i + 1)); }
class const_iterator class const_iterator: public std::iterator<std::forward_iterator_tag, T>
{ {
friend class RangeMask; friend class RangeMask;
@ -208,6 +178,8 @@ public:
const_iterator begin() const { return const_iterator(*this, false); } const_iterator begin() const { return const_iterator(*this, false); }
const_iterator end() const { return const_iterator(*this, true); } const_iterator end() const { return const_iterator(*this, true); }
/// @returns the smallest element in the range mask that is larger than _t or the end of the
/// base range if such an element does not exist.
T next(T _t) const T next(T _t) const
{ {
_t++; _t++;
@ -219,6 +191,7 @@ public:
return uit == m_ranges.end() ? m_all.second : uit->first; return uit == m_ranges.end() ? m_all.second : uit->first;
} }
/// @returns the number of elements (not ranges) in the range mask.
size_t size() const size_t size() const
{ {
size_t c = 0; size_t c = 0;
@ -228,7 +201,9 @@ public:
} }
private: private:
/// The ground range.
UnsignedRange m_all; UnsignedRange m_all;
/// Mapping begin -> end containing the ranges.
std::map<T, T> m_ranges; std::map<T, T> m_ranges;
}; };
@ -241,4 +216,65 @@ template <class T> inline std::ostream& operator<<(std::ostream& _out, RangeMask
return _out; return _out;
} }
template <class T>
RangeMask<T>& RangeMask<T>::unionWith(typename RangeMask<T>::Range const& _m)
{
for (auto i = _m.first; i < _m.second;)
{
assert(i >= m_all.first);
assert(i < m_all.second);
// For each number, we find the element equal or next lower. this, if any, must contain the value.
// First range that starts after i.
auto rangeAfter = m_ranges.upper_bound(i);
// Range before rangeAfter or "end" if the rangeAfter is the first ever...
auto it = rangeAfter == m_ranges.begin() ? m_ranges.end() : std::prev(rangeAfter);
if (it == m_ranges.end() || it->second < i)
{
// i is either before the first range or between two ranges (with some distance
// so that we cannot merge it onto "it").
// lower range is too low to merge.
// if the next higher range is too high.
if (rangeAfter == m_ranges.end() || rangeAfter->first > _m.second)
{
// just create a new range
m_ranges[i] = _m.second;
break;
}
else
{
if (rangeAfter->first == i)
// move i to end of range
i = rangeAfter->second;
else
{
// merge with the next higher range
// move i to end of range
i = m_ranges[i] = rangeAfter->second;
m_ranges.erase(rangeAfter);
}
}
}
else if (it->second == i)
{
// The range before i ends with i.
// if the next higher range is too high.
if (rangeAfter == m_ranges.end() || rangeAfter->first > _m.second)
{
// merge with the next lower range
m_ranges[it->first] = _m.second;
break;
}
else
{
// merge with both next lower & next higher.
i = m_ranges[it->first] = rangeAfter->second;
m_ranges.erase(rangeAfter);
}
}
else
i = it->second;
}
return *this;
}
} }

95
libethereum/BasicGasPricer.cpp

@ -0,0 +1,95 @@
/*
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 BasicGasPricer.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#include <boost/math/distributions/normal.hpp>
#include "BasicGasPricer.h"
#include "BlockChain.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
void BasicGasPricer::update(BlockChain const& _bc)
{
unsigned c = 0;
h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit;
map<u256, u256> dist;
u256 total = 0;
// make gasPrice versus gasUsed distribution for the last 1000 blocks
while (c < 1000 && p)
{
BlockInfo bi = _bc.info(p);
if (bi.transactionsRoot != EmptyTrie)
{
auto bb = _bc.block(p);
RLP r(bb);
BlockReceipts brs(_bc.receipts(bi.hash()));
size_t i = 0;
for (auto const& tr: r[1])
{
Transaction tx(tr.data(), CheckTransaction::None);
u256 gu = brs.receipts[i].gasUsed();
dist[tx.gasPrice()] += gu;
total += gu;
i++;
}
}
p = bi.parentHash;
++c;
}
// fill m_octiles with weighted gasPrices
if (total > 0)
{
m_octiles[0] = dist.begin()->first;
// calc mean
u256 mean = 0;
for (auto const& i: dist)
mean += i.first * i.second;
mean /= total;
// calc standard deviation
u256 sdSquared = 0;
for (auto const& i: dist)
sdSquared += i.second * (i.first - mean) * (i.first - mean);
sdSquared /= total;
if (sdSquared)
{
long double sd = sqrt(sdSquared.convert_to<long double>());
long double normalizedSd = sd / mean.convert_to<long double>();
// calc octiles normalized to gaussian distribution
boost::math::normal gauss(1.0, (normalizedSd > 0.01) ? normalizedSd : 0.01);
for (size_t i = 1; i < 8; i++)
m_octiles[i] = u256(mean.convert_to<long double>() * boost::math::quantile(gauss, i / 8.0));
m_octiles[8] = dist.rbegin()->first;
}
else
{
for (size_t i = 0; i < 9; i++)
m_octiles[i] = (i + 1) * mean / 5;
}
}
}

53
libethereum/BasicGasPricer.h

@ -0,0 +1,53 @@
/*
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 BasicGasPricer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <array>
#include "GasPricer.h"
namespace dev
{
namespace eth
{
class BasicGasPricer: public GasPricer
{
public:
explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {}
void setRefPrice(u256 _weiPerRef) { if ((bigint)m_refsPerBlock * _weiPerRef > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_weiPerRef = _weiPerRef; }
void setRefBlockFees(u256 _refsPerBlock) { if ((bigint)m_weiPerRef * _refsPerBlock > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_refsPerBlock = _refsPerBlock; }
u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); }
void update(BlockChain const& _bc) override;
private:
u256 m_weiPerRef;
u256 m_refsPerBlock;
u256 m_gasPerBlock = 3141592;
std::array<u256, 9> m_octiles;
};
}
}

62
libethereum/BlockChain.cpp

@ -127,7 +127,7 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif #endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::string _path, WithExisting _we, ProgressCallback const& _p) BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p)
{ {
// initialise deathrow. // initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize); m_cacheUsage.resize(c_collectionQueueSize);
@ -137,8 +137,7 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string _path, WithExisti
m_genesisBlock = _genesisBlock; m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); m_genesisHash = sha3(RLP(m_genesisBlock)[0].data());
open(_path, _we); if (open(_path, _we) != c_minorProtocolVersion)
if (_we == WithExisting::Verify)
rebuild(_path, _p); rebuild(_path, _p);
} }
@ -147,24 +146,41 @@ BlockChain::~BlockChain()
close(); close();
} }
void BlockChain::open(std::string const& _path, WithExisting _we) unsigned BlockChain::open(std::string const& _path, WithExisting _we)
{ {
std::string path = _path.empty() ? Defaults::get()->m_dbPath : _path; string path = _path.empty() ? Defaults::get()->m_dbPath : _path;
boost::filesystem::create_directories(path); string chainPath = path + "/" + toHex(m_genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(c_databaseVersion);
boost::filesystem::create_directories(extrasPath);
bytes status = contents(extrasPath + "/minor");
unsigned lastMinor = c_minorProtocolVersion;
DEV_IGNORE_EXCEPTIONS(lastMinor = (unsigned)RLP(status));
if (c_minorProtocolVersion != lastMinor)
{
cnote << "Killing extras database (DB minor version:" << lastMinor << " != our miner version: " << c_minorProtocolVersion << ").";
DEV_IGNORE_EXCEPTIONS(boost::filesystem::remove_all(extrasPath + "/details.old"));
boost::filesystem::rename(extrasPath + "/extras", extrasPath + "/extras.old");
boost::filesystem::remove_all(extrasPath + "/state");
writeFile(extrasPath + "/minor", rlp(c_minorProtocolVersion));
lastMinor = (unsigned)RLP(status);
}
if (_we == WithExisting::Kill) if (_we == WithExisting::Kill)
{ {
boost::filesystem::remove_all(path + "/blocks"); cnote << "Killing blockchain & extras database (WithExisting::Kill).";
boost::filesystem::remove_all(path + "/details"); boost::filesystem::remove_all(chainPath + "/blocks");
boost::filesystem::remove_all(extrasPath + "/extras");
} }
ldb::Options o; ldb::Options o;
o.create_if_missing = true; o.create_if_missing = true;
o.max_open_files = 256; o.max_open_files = 256;
ldb::DB::Open(o, path + "/blocks", &m_blocksDB); ldb::DB::Open(o, chainPath + "/blocks", &m_blocksDB);
ldb::DB::Open(o, path + "/details", &m_extrasDB); ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB);
if (!m_blocksDB || !m_extrasDB) if (!m_blocksDB || !m_extrasDB)
{ {
if (boost::filesystem::space(path + "/blocks").available < 1024) if (boost::filesystem::space(chainPath + "/blocks").available < 1024)
{ {
cwarn << "Not enough available space found on hard drive. Please free some up and then re-run. Bailing."; cwarn << "Not enough available space found on hard drive. Please free some up and then re-run. Bailing.";
BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace()); BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace());
@ -194,7 +210,8 @@ void BlockChain::open(std::string const& _path, WithExisting _we)
m_lastBlockHash = l.empty() ? m_genesisHash : *(h256*)l.data(); m_lastBlockHash = l.empty() ? m_genesisHash : *(h256*)l.data();
m_lastBlockNumber = number(m_lastBlockHash); m_lastBlockNumber = number(m_lastBlockHash);
cnote << "Opened blockchain DB. Latest: " << currentHash(); cnote << "Opened blockchain DB. Latest: " << currentHash() << (lastMinor == c_minorProtocolVersion ? "(rebuild not needed)" : "*** REBUILD NEEDED ***");
return lastMinor;
} }
void BlockChain::close() void BlockChain::close()
@ -208,11 +225,11 @@ void BlockChain::close()
m_blocks.clear(); m_blocks.clear();
} }
#define IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress, bool _prepPoW) void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress, bool _prepPoW)
{ {
std::string path = _path.empty() ? Defaults::get()->m_dbPath : _path; string path = _path.empty() ? Defaults::get()->m_dbPath : _path;
string chainPath = path + "/" + toHex(m_genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(c_databaseVersion);
#if ETH_PROFILING_GPERF #if ETH_PROFILING_GPERF
ProfilerStart("BlockChain_rebuild.log"); ProfilerStart("BlockChain_rebuild.log");
@ -220,16 +237,21 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
unsigned originalNumber = m_lastBlockNumber; unsigned originalNumber = m_lastBlockNumber;
///////////////////////////////
// TODO
// - KILL ALL STATE/CHAIN
// - REINSERT ALL BLOCKS
///////////////////////////////
// Keep extras DB around, but under a temp name // Keep extras DB around, but under a temp name
delete m_extrasDB; delete m_extrasDB;
m_extrasDB = nullptr; m_extrasDB = nullptr;
IGNORE_EXCEPTIONS(boost::filesystem::remove_all(path + "/details.old")); boost::filesystem::rename(path + "/details", path + "/extras.old");
boost::filesystem::rename(path + "/details", path + "/details.old");
ldb::DB* oldExtrasDB; ldb::DB* oldExtrasDB;
ldb::Options o; ldb::Options o;
o.create_if_missing = true; o.create_if_missing = true;
ldb::DB::Open(o, path + "/details.old", &oldExtrasDB); ldb::DB::Open(o, extrasPath + "/extras.old", &oldExtrasDB);
ldb::DB::Open(o, path + "/details", &m_extrasDB); ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB);
// Open a fresh state DB // Open a fresh state DB
State s(State::openDB(path, WithExisting::Kill), BaseState::CanonGenesis); State s(State::openDB(path, WithExisting::Kill), BaseState::CanonGenesis);
@ -289,7 +311,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
#endif #endif
delete oldExtrasDB; delete oldExtrasDB;
boost::filesystem::remove_all(path + "/details.old"); boost::filesystem::remove_all(path + "/extras.old");
} }
LastHashes BlockChain::lastHashes(unsigned _n) const LastHashes BlockChain::lastHashes(unsigned _n) const

7
libethereum/BlockChain.h

@ -94,7 +94,7 @@ using ProgressCallback = std::function<void(unsigned, unsigned)>;
class BlockChain class BlockChain
{ {
public: public:
BlockChain(bytes const& _genesisBlock, std::string _path, WithExisting _we, ProgressCallback const& _p = ProgressCallback()); BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback());
~BlockChain(); ~BlockChain();
/// Attempt a database re-open. /// Attempt a database re-open.
@ -178,6 +178,9 @@ public:
std::vector<unsigned> withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest) const; std::vector<unsigned> withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest) const;
std::vector<unsigned> withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest, unsigned _topLevel, unsigned _index) const; std::vector<unsigned> withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest, unsigned _topLevel, unsigned _index) const;
/// Returns true if transaction is known. Thread-safe
bool isKnownTransaction(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); return !!ta; }
/// Get a transaction from its hash. Thread-safe. /// Get a transaction from its hash. Thread-safe.
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); } 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); } 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); }
@ -261,7 +264,7 @@ public:
private: private:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
void open(std::string const& _path, WithExisting _we = WithExisting::Trust); unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust);
void close(); void close();
template<class T, unsigned N> T queryExtras(h256 const& _h, std::unordered_map<h256, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const template<class T, unsigned N> T queryExtras(h256 const& _h, std::unordered_map<h256, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const

8
libethereum/BlockChainSync.cpp

@ -791,10 +791,6 @@ bool PV60Sync::invariants() const
return false; return false;
if (m_state == SyncState::Hashes) if (m_state == SyncState::Hashes)
{ {
bool hashes = false;
host().foreachPeer([&](std::shared_ptr<EthereumPeer> _p) { if (_p->m_asking == Asking::Hashes) hashes = true; return !hashes; });
if (!hashes)
return false;
if (!m_syncingLatestHash) if (!m_syncingLatestHash)
return false; return false;
if (m_syncingNeededBlocks.empty() != (!m_syncingLastReceivedHash)) if (m_syncingNeededBlocks.empty() != (!m_syncingLastReceivedHash))
@ -802,10 +798,6 @@ bool PV60Sync::invariants() const
} }
if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks)
{ {
bool blocks = false;
host().foreachPeer([&](std::shared_ptr<EthereumPeer> _p) { if (_p->m_asking == Asking::Blocks) blocks = true; return !blocks; });
if (!blocks)
return false;
if (downloadMan().isComplete()) if (downloadMan().isComplete())
return false; return false;
} }

1
libethereum/BlockChainSync.h

@ -24,7 +24,6 @@
#include <mutex> #include <mutex>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/RangeMask.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libp2p/Common.h> #include <libp2p/Common.h>
#include "CommonNet.h" #include "CommonNet.h"

2
libethereum/BlockQueue.cpp

@ -184,7 +184,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS()
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs)
{ {
cdebug << std::this_thread::get_id(); clog(BlockQueueTraceChannel) << std::this_thread::get_id();
// Check if we already know this block. // Check if we already know this block.
h256 h = BlockInfo::headerHash(_block); h256 h = BlockInfo::headerHash(_block);

242
libethereum/Client.cpp

@ -24,7 +24,6 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/math/distributions/normal.hpp>
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
#include <jsonrpccpp/client.h> #include <jsonrpccpp/client.h>
#include <jsonrpccpp/client/connectors/httpclient.h> #include <jsonrpccpp/client/connectors/httpclient.h>
@ -38,53 +37,82 @@
#include "Defaults.h" #include "Defaults.h"
#include "Executive.h" #include "Executive.h"
#include "EthereumHost.h" #include "EthereumHost.h"
#include "Utility.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using namespace p2p; using namespace p2p;
VersionChecker::VersionChecker(string const& _dbPath): std::ostream& dev::eth::operator<<(std::ostream& _out, ActivityReport const& _r)
m_path(_dbPath.size() ? _dbPath : Defaults::dbPath())
{ {
bytes statusBytes = contents(m_path + "/status"); _out << "Since " << toString(_r.since) << " (" << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - _r.since).count();
RLP status(statusBytes); _out << "): " << _r.ticks << "ticks";
try return _out;
{
auto protocolVersion = (unsigned)status[0];
(void)protocolVersion;
auto minorProtocolVersion = (unsigned)status[1];
auto databaseVersion = (unsigned)status[2];
h256 ourGenesisHash = CanonBlockChain::genesis().hash();
auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : ourGenesisHash;
m_action =
databaseVersion != c_databaseVersion || genesisHash != ourGenesisHash ?
WithExisting::Kill
: minorProtocolVersion != eth::c_minorProtocolVersion ?
WithExisting::Verify
:
WithExisting::Trust;
}
catch (...)
{
m_action = WithExisting::Kill;
}
} }
void VersionChecker::setOk() #ifdef _WIN32
const char* ClientNote::name() { return EthTeal "^" EthBlue " i"; }
const char* ClientChat::name() { return EthTeal "^" EthWhite " o"; }
const char* ClientTrace::name() { return EthTeal "^" EthGray " O"; }
const char* ClientDetail::name() { return EthTeal "^" EthCoal " 0"; }
#else
const char* ClientNote::name() { return EthTeal "" EthBlue ""; }
const char* ClientChat::name() { return EthTeal "" EthWhite ""; }
const char* ClientTrace::name() { return EthTeal "" EthGray ""; }
const char* ClientDetail::name() { return EthTeal "" EthCoal ""; }
#endif
static const Addresses c_canaries =
{ {
if (m_action != WithExisting::Trust) Address("4bb7e8ae99b645c2b7860b8f3a2328aae28bd80a"), // gav
{ Address("1baf27b88c48dd02b744999cf3522766929d2b2a"), // vitalik
try Address("a8edb1ac2c86d3d9d78f96cd18001f60df29e52c"), // jeff
{ Address("60d11b58744784dc97f878f7e3749c0f1381a004") // christoph
boost::filesystem::create_directory(m_path); };
}
catch (...) VersionChecker::VersionChecker(string const& _dbPath)
{ {
cwarn << "Unhandled exception! Failed to create directory: " << m_path << "\n" << boost::current_exception_diagnostic_information(); upgradeDatabase(_dbPath);
} }
writeFile(m_path + "/status", rlpList(eth::c_protocolVersion, eth::c_minorProtocolVersion, c_databaseVersion, CanonBlockChain::genesis().hash()));
} Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Client(_extNet, make_shared<TrivialGasPricer>(), _dbPath, _forceAction, _networkId)
{
startWorking();
}
Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth", 0),
m_vc(_dbPath),
m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
m_gp(_gp),
m_stateDB(State::openDB(_dbPath, _forceAction)),
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30);
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc);
auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
m_host = host;
_extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
doWork();
startWorking();
}
Client::~Client()
{
stopWorking();
} }
ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) ImportResult Client::queueBlock(bytes const& _block, bool _isSafe)
@ -211,142 +239,6 @@ void Client::onBadBlock(Exception& _ex) const
#endif #endif
} }
void BasicGasPricer::update(BlockChain const& _bc)
{
unsigned c = 0;
h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit;
map<u256, u256> dist;
u256 total = 0;
// make gasPrice versus gasUsed distribution for the last 1000 blocks
while (c < 1000 && p)
{
BlockInfo bi = _bc.info(p);
if (bi.transactionsRoot != EmptyTrie)
{
auto bb = _bc.block(p);
RLP r(bb);
BlockReceipts brs(_bc.receipts(bi.hash()));
size_t i = 0;
for (auto const& tr: r[1])
{
Transaction tx(tr.data(), CheckTransaction::None);
u256 gu = brs.receipts[i].gasUsed();
dist[tx.gasPrice()] += gu;
total += gu;
i++;
}
}
p = bi.parentHash;
++c;
}
// fill m_octiles with weighted gasPrices
if (total > 0)
{
m_octiles[0] = dist.begin()->first;
// calc mean
u256 mean = 0;
for (auto const& i: dist)
mean += i.first * i.second;
mean /= total;
// calc standard deviation
u256 sdSquared = 0;
for (auto const& i: dist)
sdSquared += i.second * (i.first - mean) * (i.first - mean);
sdSquared /= total;
if (sdSquared)
{
long double sd = sqrt(sdSquared.convert_to<long double>());
long double normalizedSd = sd / mean.convert_to<long double>();
// calc octiles normalized to gaussian distribution
boost::math::normal gauss(1.0, (normalizedSd > 0.01) ? normalizedSd : 0.01);
for (size_t i = 1; i < 8; i++)
m_octiles[i] = u256(mean.convert_to<long double>() * boost::math::quantile(gauss, i / 8.0));
m_octiles[8] = dist.rbegin()->first;
}
else
{
for (size_t i = 0; i < 9; i++)
m_octiles[i] = (i + 1) * mean / 5;
}
}
}
std::ostream& dev::eth::operator<<(std::ostream& _out, ActivityReport const& _r)
{
_out << "Since " << toString(_r.since) << " (" << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - _r.since).count();
_out << "): " << _r.ticks << "ticks";
return _out;
}
#ifdef _WIN32
const char* ClientNote::name() { return EthTeal "^" EthBlue " i"; }
const char* ClientChat::name() { return EthTeal "^" EthWhite " o"; }
const char* ClientTrace::name() { return EthTeal "^" EthGray " O"; }
const char* ClientDetail::name() { return EthTeal "^" EthCoal " 0"; }
#else
const char* ClientNote::name() { return EthTeal "" EthBlue ""; }
const char* ClientChat::name() { return EthTeal "" EthWhite ""; }
const char* ClientTrace::name() { return EthTeal "" EthGray ""; }
const char* ClientDetail::name() { return EthTeal "" EthCoal ""; }
#endif
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Client(_extNet, make_shared<TrivialGasPricer>(), _dbPath, _forceAction, _networkId)
{
startWorking();
}
Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth", 0),
m_vc(_dbPath),
m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
m_gp(_gp),
m_stateDB(State::openDB(_dbPath, max(m_vc.action(), _forceAction))),
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30);
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc);
auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
m_host = host;
_extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
doWork();
startWorking();
}
Client::~Client()
{
stopWorking();
}
static const Addresses c_canaries =
{
Address("4bb7e8ae99b645c2b7860b8f3a2328aae28bd80a"), // gav
Address("1baf27b88c48dd02b744999cf3522766929d2b2a"), // vitalik
Address("a8edb1ac2c86d3d9d78f96cd18001f60df29e52c"), // jeff
Address("60d11b58744784dc97f878f7e3749c0f1381a004") // christoph
};
bool Client::isChainBad() const bool Client::isChainBad() const
{ {
unsigned numberBad = 0; unsigned numberBad = 0;

27
libethereum/Client.h

@ -64,33 +64,6 @@ class VersionChecker
{ {
public: public:
VersionChecker(std::string const& _dbPath); VersionChecker(std::string const& _dbPath);
void setOk();
WithExisting action() const { return m_action; }
private:
WithExisting m_action;
std::string m_path;
};
class BasicGasPricer: public GasPricer
{
public:
explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {}
void setRefPrice(u256 _weiPerRef) { if ((bigint)m_refsPerBlock * _weiPerRef > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_weiPerRef = _weiPerRef; }
void setRefBlockFees(u256 _refsPerBlock) { if ((bigint)m_weiPerRef * _refsPerBlock > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_refsPerBlock = _refsPerBlock; }
u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); }
void update(BlockChain const& _bc) override;
private:
u256 m_weiPerRef;
u256 m_refsPerBlock;
u256 m_gasPerBlock = 3141592;
std::array<u256, 9> m_octiles;
}; };
struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; };

21
libethereum/ClientBase.cpp

@ -480,3 +480,24 @@ int ClientBase::compareBlockHashes(h256 _h1, h256 _h2) const
} }
return -1; return -1;
} }
bool ClientBase::isKnown(h256 const& _hash) const
{
return _hash == PendingBlockHash ||
_hash == LatestBlockHash ||
_hash == EarliestBlockHash ||
bc().isKnown(_hash);
}
bool ClientBase::isKnown(BlockNumber _block) const
{
return _block == PendingBlock ||
_block == LatestBlock ||
bc().numberHash(_block) != h256();
}
bool ClientBase::isKnownTransaction(h256 const& _transactionHash) const
{
return bc().isKnownTransaction(_transactionHash);
}

4
libethereum/ClientBase.h

@ -149,6 +149,10 @@ public:
/// Get the coinbase address /// Get the coinbase address
virtual Address address() const override; virtual Address address() const override;
virtual bool isKnown(h256 const& _hash) const override;
virtual bool isKnown(BlockNumber _block) const override;
virtual bool isKnownTransaction(h256 const& _transactionHash) const override;
/// TODO: consider moving it to a separate interface /// TODO: consider moving it to a separate interface
virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); } virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); }

2
libethereum/EthereumHost.cpp

@ -286,7 +286,7 @@ void EthereumHost::onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP c
unsigned itemCount = _r.itemCount(); unsigned itemCount = _r.itemCount();
clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)"; clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)";
Guard l(_peer->x_knownTransactions); Guard l(_peer->x_knownTransactions);
for (unsigned i = 0; i < min<unsigned>(itemCount, 256); ++i) // process 256 transactions at most. TODO: much better solution. for (unsigned i = 0; i < min<unsigned>(itemCount, 32); ++i) // process 256 transactions at most. TODO: much better solution.
{ {
auto h = sha3(_r[i].data()); auto h = sha3(_r[i].data());
_peer->m_knownTransactions.insert(h); _peer->m_knownTransactions.insert(h);

1
libethereum/EthereumHost.h

@ -31,7 +31,6 @@
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libp2p/Common.h> #include <libp2p/Common.h>
#include "CommonNet.h" #include "CommonNet.h"

1
libethereum/EthereumPeer.h

@ -31,7 +31,6 @@
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/RangeMask.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libp2p/Capability.h> #include <libp2p/Capability.h>
#include "CommonNet.h" #include "CommonNet.h"

2
libethereum/Executive.h

@ -53,7 +53,7 @@ public:
std::string json(bool _styled = false) const; std::string json(bool _styled = false) const;
OnOpFunc onOp() { return [&](uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM) { (*this)(_steps, _inst, _newMemSize, _gasCost, _gas, _vm, _extVM); }; } OnOpFunc onOp() { return [=](uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM) { (*this)(_steps, _inst, _newMemSize, _gasCost, _gas, _vm, _extVM); }; }
private: private:
bool m_showMnemonics = false; bool m_showMnemonics = false;

26
libethereum/GasPricer.cpp

@ -0,0 +1,26 @@
/*
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 GasPricer.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#include "GasPricer.h"
using namespace std;
using namespace dev;
using namespace dev::eth;

74
libethereum/GasPricer.h

@ -0,0 +1,74 @@
/*
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 GasPricer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libethcore/Common.h>
namespace dev
{
namespace eth
{
class State;
class BlockChain;
enum class TransactionPriority
{
Lowest = 0,
Low = 2,
Medium = 4,
High = 6,
Highest = 8
};
class GasPricer
{
public:
GasPricer() = default;
virtual ~GasPricer() = default;
virtual u256 ask(State const&) const = 0;
virtual u256 bid(TransactionPriority _p = TransactionPriority::Medium) const = 0;
virtual void update(BlockChain const&) {}
};
class TrivialGasPricer: public GasPricer
{
public:
TrivialGasPricer() = default;
TrivialGasPricer(u256 const& _ask, u256 const& _bid): m_ask(_ask), m_bid(_bid) {}
void setAsk(u256 const& _ask) { m_ask = _ask; }
void setBid(u256 const& _bid) { m_bid = _bid; }
u256 ask() const { return m_ask; }
u256 ask(State const&) const override { return m_ask; }
u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return m_bid; }
private:
u256 m_ask = 10 * szabo;
u256 m_bid = 10 * szabo;
};
}
}

5
libethereum/Interface.h

@ -133,12 +133,15 @@ public:
// [BLOCK QUERY API] // [BLOCK QUERY API]
virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0;
virtual Transaction transaction(h256 _transactionHash) const = 0; virtual Transaction transaction(h256 _transactionHash) const = 0;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const = 0; virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const = 0;
virtual h256 hashFromNumber(BlockNumber _number) const = 0; virtual h256 hashFromNumber(BlockNumber _number) const = 0;
virtual BlockNumber numberFromHash(h256 _blockHash) const = 0; virtual BlockNumber numberFromHash(h256 _blockHash) const = 0;
virtual int compareBlockHashes(h256 _h1, h256 _h2) const = 0; virtual int compareBlockHashes(h256 _h1, h256 _h2) const = 0;
virtual bool isKnown(BlockNumber _block) const = 0;
virtual bool isKnown(h256 const& _hash) const = 0;
virtual BlockInfo blockInfo(h256 _hash) const = 0; virtual BlockInfo blockInfo(h256 _hash) const = 0;
virtual BlockDetails blockDetails(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
@ -151,7 +154,7 @@ public:
BlockInfo blockInfo(BlockNumber _block) const { return blockInfo(hashFromNumber(_block)); } BlockInfo blockInfo(BlockNumber _block) const { return blockInfo(hashFromNumber(_block)); }
BlockDetails blockDetails(BlockNumber _block) const { return blockDetails(hashFromNumber(_block)); } BlockDetails blockDetails(BlockNumber _block) const { return blockDetails(hashFromNumber(_block)); }
Transaction transaction(BlockNumber _block, unsigned _i) const { if (_block == PendingBlock) { auto p = pending(); return _i < p.size() ? p[_i] : Transaction(); } return transaction(hashFromNumber(_block)); } Transaction transaction(BlockNumber _block, unsigned _i) const { auto p = transactions(_block); return _i < p.size() ? p[_i] : Transaction(); }
unsigned transactionCount(BlockNumber _block) const { if (_block == PendingBlock) { auto p = pending(); return p.size(); } return transactionCount(hashFromNumber(_block)); } unsigned transactionCount(BlockNumber _block) const { if (_block == PendingBlock) { auto p = pending(); return p.size(); } return transactionCount(hashFromNumber(_block)); }
Transactions transactions(BlockNumber _block) const { if (_block == PendingBlock) return pending(); return transactions(hashFromNumber(_block)); } Transactions transactions(BlockNumber _block) const { if (_block == PendingBlock) return pending(); return transactions(hashFromNumber(_block)); }
TransactionHashes transactionHashes(BlockNumber _block) const { if (_block == PendingBlock) return pendingHashes(); return transactionHashes(hashFromNumber(_block)); } TransactionHashes transactionHashes(BlockNumber _block) const { if (_block == PendingBlock) return pendingHashes(); return transactionHashes(hashFromNumber(_block)); }

24
libethereum/State.cpp

@ -41,6 +41,7 @@
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
namespace fs = boost::filesystem;
#define ctrace clog(StateTrace) #define ctrace clog(StateTrace)
#define ETH_TIMED_ENACTMENTS 0 #define ETH_TIMED_ENACTMENTS 0
@ -52,23 +53,27 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; }
const char* StateTrace::name() { return EthViolet "" EthGray ""; } const char* StateTrace::name() { return EthViolet "" EthGray ""; }
const char* StateChat::name() { return EthViolet "" EthWhite ""; } const char* StateChat::name() { return EthViolet "" EthWhite ""; }
OverlayDB State::openDB(std::string _path, WithExisting _we) OverlayDB State::openDB(std::string const& _basePath, WithExisting _we)
{ {
if (_path.empty()) std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath;
_path = Defaults::get()->m_dbPath;
boost::filesystem::create_directory(_path);
if (_we == WithExisting::Kill) if (_we == WithExisting::Kill)
boost::filesystem::remove_all(_path + "/state"); {
cnote << "Killing state database (WithExisting::Kill).";
boost::filesystem::remove_all(path + "/state");
}
path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion);
boost::filesystem::create_directory(path);
ldb::Options o; ldb::Options o;
o.max_open_files = 256; o.max_open_files = 256;
o.create_if_missing = true; o.create_if_missing = true;
ldb::DB* db = nullptr; ldb::DB* db = nullptr;
ldb::DB::Open(o, _path + "/state", &db); ldb::DB::Open(o, path + "/state", &db);
if (!db) if (!db)
{ {
if (boost::filesystem::space(_path + "/state").available < 1024) 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."; cwarn << "Not enough available space found on hard drive. Please free some up and then re-run. Bailing.";
BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace()); BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace());
@ -603,7 +608,6 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
m_currentBlock.noteDirty(); m_currentBlock.noteDirty();
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
vector<bytes> receipts;
string ret; string ret;
unsigned i = 0; unsigned i = 0;
@ -613,10 +617,6 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
st.setShowMnemonics(); st.setShowMnemonics();
execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, st.onOp()); execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, st.onOp());
ret += (ret.empty() ? "[" : ",") + st.json(); ret += (ret.empty() ? "[" : ",") + st.json();
RLPStream receiptRLP;
m_receipts.back().streamRLP(receiptRLP);
receipts.push_back(receiptRLP.out());
++i; ++i;
} }
return ret.empty() ? "[]" : (ret + "]"); return ret.empty() ? "[]" : (ret + "]");

42
libethereum/State.h

@ -37,6 +37,7 @@
#include "Transaction.h" #include "Transaction.h"
#include "TransactionReceipt.h" #include "TransactionReceipt.h"
#include "AccountDiff.h" #include "AccountDiff.h"
#include "GasPricer.h"
namespace dev namespace dev
{ {
@ -80,45 +81,6 @@ enum class BaseState
CanonGenesis CanonGenesis
}; };
enum class TransactionPriority
{
Lowest = 0,
Low = 2,
Medium = 4,
High = 6,
Highest = 8
};
class GasPricer
{
public:
GasPricer() = default;
virtual ~GasPricer() = default;
virtual u256 ask(State const&) const = 0;
virtual u256 bid(TransactionPriority _p = TransactionPriority::Medium) const = 0;
virtual void update(BlockChain const&) {}
};
class TrivialGasPricer: public GasPricer
{
public:
TrivialGasPricer() = default;
TrivialGasPricer(u256 const& _ask, u256 const& _bid): m_ask(_ask), m_bid(_bid) {}
void setAsk(u256 const& _ask) { m_ask = _ask; }
void setBid(u256 const& _bid) { m_bid = _bid; }
u256 ask() const { return m_ask; }
u256 ask(State const&) const override { return m_ask; }
u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return m_bid; }
private:
u256 m_ask = 10 * szabo;
u256 m_bid = 10 * szabo;
};
enum class Permanence enum class Permanence
{ {
Reverted, Reverted,
@ -171,7 +133,7 @@ public:
Address address() const { return m_ourAddress; } Address address() const { return m_ourAddress; }
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary.
static OverlayDB openDB(std::string _path, WithExisting _we = WithExisting::Trust); static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust);
static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); }
OverlayDB const& db() const { return m_db; } OverlayDB const& db() const { return m_db; }
OverlayDB& db() { return m_db; } OverlayDB& db() { return m_db; }

20
libethereum/Transaction.h

@ -85,7 +85,25 @@ public:
/// Constructs a null transaction. /// Constructs a null transaction.
Transaction() {} Transaction() {}
using TransactionBase::TransactionBase; /// Constructs a signed message-call transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce, Secret const& _secret):
TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce, _secret)
{}
/// Constructs a signed contract-creation transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce, Secret const& _secret):
TransactionBase(_value, _gasPrice, _gas, _data, _nonce, _secret)
{}
/// Constructs an unsigned message-call transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce = 0):
TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce)
{}
/// Constructs an unsigned contract-creation transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = 0):
TransactionBase(_value, _gasPrice, _gas, _data, _nonce)
{}
/// Constructs a transaction from the given RLP. /// Constructs a transaction from the given RLP.
explicit Transaction(bytesConstRef _rlp, CheckTransaction _checkSig); explicit Transaction(bytesConstRef _rlp, CheckTransaction _checkSig);

8
libethereum/TransactionQueue.cpp

@ -98,11 +98,7 @@ ImportResult TransactionQueue::import(Transaction const& _transaction, ImportCal
std::unordered_map<h256, Transaction> TransactionQueue::transactions() const std::unordered_map<h256, Transaction> TransactionQueue::transactions() const
{ {
ReadGuard l(m_lock); ReadGuard l(m_lock);
auto ret = m_current; return m_current;
for (auto const& i: m_future)
if (i.second.nonce() < maxNonce_WITH_LOCK(i.second.sender()))
ret.insert(i);
return ret;
} }
ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction, ImportCallback const& _cb) ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transaction const& _transaction, ImportCallback const& _cb)
@ -113,6 +109,8 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
// If it doesn't work, the signature is bad. // If it doesn't work, the signature is bad.
// The transaction's nonce may yet be invalid (or, it could be "valid" but we may be missing a marginally older transaction). // The transaction's nonce may yet be invalid (or, it could be "valid" but we may be missing a marginally older transaction).
// Remove any prior transaction with the same nonce but a lower gas price.
// Bomb out if there's a prior transaction with higher gas price.
auto r = m_senders.equal_range(_transaction.from()); auto r = m_senders.equal_range(_transaction.from());
for (auto it = r.first; it != r.second; ++it) for (auto it = r.first; it != r.second; ++it)
if (m_current.count(it->second) && m_current[it->second].nonce() == _transaction.nonce()) if (m_current.count(it->second) && m_current[it->second].nonce() == _transaction.nonce())

51
libethereum/Utility.cpp

@ -22,11 +22,16 @@
#include "Utility.h" #include "Utility.h"
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <libethcore/Common.h> #include <boost/filesystem.hpp>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include <libdevcore/RLP.h>
#include <libdevcore/Log.h>
#include <libethcore/Common.h>
#include "Defaults.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
namespace fs = boost::filesystem;
bytes dev::eth::parseData(string const& _args) bytes dev::eth::parseData(string const& _args)
{ {
@ -84,3 +89,47 @@ bytes dev::eth::parseData(string const& _args)
return m_data; return m_data;
} }
void dev::eth::upgradeDatabase(std::string const& _basePath)
{
std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath;
if (fs::exists(path + "/state") && fs::exists(path + "/details") && fs::exists(path + "/blocks"))
{
// upgrade
cnote << "Upgrading database to new layout...";
bytes statusBytes = contents(path + "/status");
RLP status(statusBytes);
try
{
auto minorProtocolVersion = (unsigned)status[1];
auto databaseVersion = (unsigned)status[2];
auto genesisHash = (h256)status[3];
string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(databaseVersion);
// write status
if (!fs::exists(chainPath + "/blocks"))
{
boost::filesystem::create_directories(chainPath);
fs::rename(path + "/blocks", chainPath + "/blocks");
if (!fs::exists(extrasPath + "/extras"))
{
boost::filesystem::create_directories(extrasPath);
fs::rename(path + "/details", extrasPath + "/extras");
fs::rename(path + "/state", extrasPath + "/state");
writeFile(extrasPath + "/minor", rlp(minorProtocolVersion));
fs::remove_all(path + "/status");
}
}
}
catch (...)
{
cwarn << "Couldn't upgrade - bad status";
}
}
}

2
libethereum/Utility.h

@ -42,5 +42,7 @@ namespace eth
*/ */
bytes parseData(std::string const& _args); bytes parseData(std::string const& _args);
void upgradeDatabase(std::string const& _basePath);
} }
} }

1
libp2p/Host.h

@ -33,7 +33,6 @@
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libdevcrypto/ECDHE.h> #include <libdevcrypto/ECDHE.h>
#include "NodeTable.h" #include "NodeTable.h"

2
libp2p/Session.cpp

@ -382,7 +382,7 @@ void Session::doRead()
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
clog(NetWarn) << "Exception decoding frame header RLP:" << bytesConstRef(m_data.data(), h128::size).cropped(3); clog(NetWarn) << "Exception decoding frame header RLP:" << _e.what() << bytesConstRef(m_data.data(), h128::size).cropped(3);
drop(BadProtocol); drop(BadProtocol);
return; return;
} }

1
libp2p/Session.h

@ -31,7 +31,6 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/RangeMask.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include "RLPXFrameCoder.h" #include "RLPXFrameCoder.h"
#include "RLPXSocket.h" #include "RLPXSocket.h"

45
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -142,7 +142,7 @@ string WebThreeStubServerBase::eth_getStorageAt(string const& _address, string c
{ {
try try
{ {
return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_position), jsToBlockNumber(_blockNumber))); return toJS(toCompactBigEndian(client()->stateAt(jsToAddress(_address), jsToU256(_position), jsToBlockNumber(_blockNumber)), 1));
} }
catch (...) catch (...)
{ {
@ -162,11 +162,15 @@ string WebThreeStubServerBase::eth_getTransactionCount(string const& _address, s
} }
} }
string WebThreeStubServerBase::eth_getBlockTransactionCountByHash(string const& _blockHash) Json::Value WebThreeStubServerBase::eth_getBlockTransactionCountByHash(string const& _blockHash)
{ {
try try
{ {
return toJS(client()->transactionCount(jsToFixed<32>(_blockHash))); h256 blockHash = jsToFixed<32>(_blockHash);
if (!client()->isKnown(blockHash))
return Json::Value(Json::nullValue);
return toJS(client()->transactionCount(blockHash));
} }
catch (...) catch (...)
{ {
@ -174,10 +178,14 @@ string WebThreeStubServerBase::eth_getBlockTransactionCountByHash(string const&
} }
} }
string WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const& _blockNumber) Json::Value WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const& _blockNumber)
{ {
try try
{ {
BlockNumber blockNumber = jsToBlockNumber(_blockNumber);
if (!client()->isKnown(blockNumber))
return Json::Value(Json::nullValue);
return toJS(client()->transactionCount(jsToBlockNumber(_blockNumber))); return toJS(client()->transactionCount(jsToBlockNumber(_blockNumber)));
} }
catch (...) catch (...)
@ -186,11 +194,15 @@ string WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const
} }
} }
string WebThreeStubServerBase::eth_getUncleCountByBlockHash(string const& _blockHash) Json::Value WebThreeStubServerBase::eth_getUncleCountByBlockHash(string const& _blockHash)
{ {
try try
{ {
return toJS(client()->uncleCount(jsToFixed<32>(_blockHash))); h256 blockHash = jsToFixed<32>(_blockHash);
if (!client()->isKnown(blockHash))
return Json::Value(Json::nullValue);
return toJS(client()->uncleCount(blockHash));
} }
catch (...) catch (...)
{ {
@ -198,11 +210,15 @@ string WebThreeStubServerBase::eth_getUncleCountByBlockHash(string const& _block
} }
} }
string WebThreeStubServerBase::eth_getUncleCountByBlockNumber(string const& _blockNumber) Json::Value WebThreeStubServerBase::eth_getUncleCountByBlockNumber(string const& _blockNumber)
{ {
try try
{ {
return toJS(client()->uncleCount(jsToBlockNumber(_blockNumber))); BlockNumber blockNumber = jsToBlockNumber(_blockNumber);
if (!client()->isKnown(blockNumber))
return Json::Value(Json::nullValue);
return toJS(client()->uncleCount(blockNumber));
} }
catch (...) catch (...)
{ {
@ -330,7 +346,10 @@ Json::Value WebThreeStubServerBase::eth_getBlockByHash(string const& _blockHash,
{ {
try try
{ {
auto h = jsToFixed<32>(_blockHash); h256 h = jsToFixed<32>(_blockHash);
if (!client()->isKnown(h))
return Json::Value(Json::nullValue);
if (_includeTransactions) if (_includeTransactions)
return toJson(client()->blockInfo(h), client()->blockDetails(h), client()->uncleHashes(h), client()->transactions(h)); return toJson(client()->blockInfo(h), client()->blockDetails(h), client()->uncleHashes(h), client()->transactions(h));
else else
@ -346,7 +365,10 @@ Json::Value WebThreeStubServerBase::eth_getBlockByNumber(string const& _blockNum
{ {
try try
{ {
auto h = jsToBlockNumber(_blockNumber); BlockNumber h = jsToBlockNumber(_blockNumber);
if (!client()->isKnown(h))
return Json::Value(Json::nullValue);
if (_includeTransactions) if (_includeTransactions)
return toJson(client()->blockInfo(h), client()->blockDetails(h), client()->uncleHashes(h), client()->transactions(h)); return toJson(client()->blockInfo(h), client()->blockDetails(h), client()->uncleHashes(h), client()->transactions(h));
else else
@ -363,6 +385,9 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByHash(string const& _tran
try try
{ {
h256 h = jsToFixed<32>(_transactionHash); h256 h = jsToFixed<32>(_transactionHash);
if (!client()->isKnownTransaction(h))
return Json::Value(Json::nullValue);
auto l = client()->transactionLocation(h); auto l = client()->transactionLocation(h);
return toJson(client()->transaction(h), l, client()->numberFromHash(l.first)); return toJson(client()->transaction(h), l, client()->numberFromHash(l.first));
} }

8
libweb3jsonrpc/WebThreeStubServerBase.h

@ -106,10 +106,10 @@ public:
virtual std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber); virtual std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber);
virtual std::string eth_getStorageAt(std::string const& _address, std::string const& _position, std::string const& _blockNumber); virtual std::string eth_getStorageAt(std::string const& _address, std::string const& _position, std::string const& _blockNumber);
virtual std::string eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber); virtual std::string eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber);
virtual std::string eth_getBlockTransactionCountByHash(std::string const& _blockHash); virtual Json::Value eth_getBlockTransactionCountByHash(std::string const& _blockHash);
virtual std::string eth_getBlockTransactionCountByNumber(std::string const& _blockNumber); virtual Json::Value eth_getBlockTransactionCountByNumber(std::string const& _blockNumber);
virtual std::string eth_getUncleCountByBlockHash(std::string const& _blockHash); virtual Json::Value eth_getUncleCountByBlockHash(std::string const& _blockHash);
virtual std::string eth_getUncleCountByBlockNumber(std::string const& _blockNumber); virtual Json::Value eth_getUncleCountByBlockNumber(std::string const& _blockNumber);
virtual std::string eth_getCode(std::string const& _address, std::string const& _blockNumber); virtual std::string eth_getCode(std::string const& _address, std::string const& _blockNumber);
virtual std::string eth_sendTransaction(Json::Value const& _json); virtual std::string eth_sendTransaction(Json::Value const& _json);
virtual std::string eth_call(Json::Value const& _json, std::string const& _blockNumber); virtual std::string eth_call(Json::Value const& _json, std::string const& _blockNumber);

16
libweb3jsonrpc/abstractwebthreestubserver.h

@ -27,10 +27,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("eth_getBalance", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBalanceI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getBalance", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBalanceI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getStorageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getStorageAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getStorageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getStorageAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionCountI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionCountI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByHashI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByNumberI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockHashI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockNumberI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getCode", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getCodeI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getCode", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getCodeI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_sendTransaction", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_sendTransactionI); this->bindAndAddMethod(jsonrpc::Procedure("eth_sendTransaction", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_sendTransactionI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_callI); this->bindAndAddMethod(jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_callI);
@ -476,10 +476,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual std::string eth_getBalance(const std::string& param1, const std::string& param2) = 0; virtual std::string eth_getBalance(const std::string& param1, const std::string& param2) = 0;
virtual std::string eth_getStorageAt(const std::string& param1, const std::string& param2, const std::string& param3) = 0; virtual std::string eth_getStorageAt(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual std::string eth_getTransactionCount(const std::string& param1, const std::string& param2) = 0; virtual std::string eth_getTransactionCount(const std::string& param1, const std::string& param2) = 0;
virtual std::string eth_getBlockTransactionCountByHash(const std::string& param1) = 0; virtual Json::Value eth_getBlockTransactionCountByHash(const std::string& param1) = 0;
virtual std::string eth_getBlockTransactionCountByNumber(const std::string& param1) = 0; virtual Json::Value eth_getBlockTransactionCountByNumber(const std::string& param1) = 0;
virtual std::string eth_getUncleCountByBlockHash(const std::string& param1) = 0; virtual Json::Value eth_getUncleCountByBlockHash(const std::string& param1) = 0;
virtual std::string eth_getUncleCountByBlockNumber(const std::string& param1) = 0; virtual Json::Value eth_getUncleCountByBlockNumber(const std::string& param1) = 0;
virtual std::string eth_getCode(const std::string& param1, const std::string& param2) = 0; virtual std::string eth_getCode(const std::string& param1, const std::string& param2) = 0;
virtual std::string eth_sendTransaction(const Json::Value& param1) = 0; virtual std::string eth_sendTransaction(const Json::Value& param1) = 0;
virtual std::string eth_call(const Json::Value& param1, const std::string& param2) = 0; virtual std::string eth_call(const Json::Value& param1, const std::string& param2) = 0;

8
libweb3jsonrpc/spec.json

@ -16,10 +16,10 @@
{ "name": "eth_getBalance", "params": ["", ""], "order": [], "returns" : ""}, { "name": "eth_getBalance", "params": ["", ""], "order": [], "returns" : ""},
{ "name": "eth_getStorageAt", "params": ["", "", ""], "order": [], "returns": ""}, { "name": "eth_getStorageAt", "params": ["", "", ""], "order": [], "returns": ""},
{ "name": "eth_getTransactionCount", "params": ["", ""], "order": [], "returns" : ""}, { "name": "eth_getTransactionCount", "params": ["", ""], "order": [], "returns" : ""},
{ "name": "eth_getBlockTransactionCountByHash", "params": [""], "order": [], "returns" : ""}, { "name": "eth_getBlockTransactionCountByHash", "params": [""], "order": [], "returns" : {}},
{ "name": "eth_getBlockTransactionCountByNumber", "params": [""], "order": [], "returns" : ""}, { "name": "eth_getBlockTransactionCountByNumber", "params": [""], "order": [], "returns" : {}},
{ "name": "eth_getUncleCountByBlockHash", "params": [""], "order": [], "returns" : ""}, { "name": "eth_getUncleCountByBlockHash", "params": [""], "order": [], "returns" : {}},
{ "name": "eth_getUncleCountByBlockNumber", "params": [""], "order": [], "returns" : ""}, { "name": "eth_getUncleCountByBlockNumber", "params": [""], "order": [], "returns" : {}},
{ "name": "eth_getCode", "params": ["", ""], "order": [], "returns": ""}, { "name": "eth_getCode", "params": ["", ""], "order": [], "returns": ""},
{ "name": "eth_sendTransaction", "params": [{}], "order": [], "returns": ""}, { "name": "eth_sendTransaction", "params": [{}], "order": [], "returns": ""},
{ "name": "eth_call", "params": [{}, ""], "order": [], "returns": ""}, { "name": "eth_call", "params": [{}, ""], "order": [], "returns": ""},

28
libwhisper/BloomFilter.cpp

@ -1,28 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file BloomFilter.cpp
* @author Vladislav Gluhovsky <vlad@ethdev.com>
* @date June 2015
*/
#include "BloomFilter.h"
using namespace std;
using namespace dev;
using namespace dev::shh;

6
libwhisper/BloomFilter.h

@ -42,14 +42,12 @@ public:
void addRaw(FixedHash<N> const& _h); void addRaw(FixedHash<N> const& _h);
void removeRaw(FixedHash<N> const& _h); void removeRaw(FixedHash<N> const& _h);
bool containsRaw(FixedHash<N> const& _h) const { return this->contains(_h); } bool containsRaw(FixedHash<N> const& _h) const { return this->contains(_h); }
enum { BitsPerBloom = 3 };
private: private:
void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; } void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; }
static bool isBitSet(FixedHash<N> const& _h, unsigned _index); static bool isBitSet(FixedHash<N> const& _h, unsigned _index);
enum { CounterSize = 8 * TopicBloomFilterBase::size }; static const unsigned CounterSize = N * 8;
std::array<uint16_t, CounterSize> m_refCounter; std::array<uint16_t, CounterSize> m_refCounter;
}; };
@ -91,7 +89,7 @@ bool TopicBloomFilterBase<N>::isBitSet(FixedHash<N> const& _h, unsigned _index)
return (_h[iByte] & c_powerOfTwoBitMmask[iBit]) != 0; return (_h[iByte] & c_powerOfTwoBitMmask[iBit]) != 0;
} }
using TopicBloomFilter = TopicBloomFilterBase<c_topicBloomFilterSize>; using TopicBloomFilter = TopicBloomFilterBase<TopicBloomFilterSize>;
} }
} }

2
libwhisper/Common.cpp

@ -100,7 +100,7 @@ TopicBloomFilterHash TopicFilter::exportBloom() const
TopicBloomFilterHash ret; TopicBloomFilterHash ret;
for (TopicMask const& t: m_topicMasks) for (TopicMask const& t: m_topicMasks)
for (auto const& i: t) for (auto const& i: t)
ret |= i.first.template bloomPart<TopicBloomFilter::BitsPerBloom, c_topicBloomFilterSize>(); ret |= i.first.template bloomPart<BitsPerBloom, TopicBloomFilterSize>();
return ret; return ret;
} }

7
libwhisper/Common.h

@ -58,8 +58,9 @@ enum WhisperPacket
PacketCount PacketCount
}; };
static const int c_topicBloomFilterSize = 64; static const unsigned TopicBloomFilterSize = 64;
static const int c_whisperProtocolVersion = 3; static const unsigned BitsPerBloom = 3;
static const unsigned WhisperProtocolVersion = 3;
using AbridgedTopic = FixedHash<4>; using AbridgedTopic = FixedHash<4>;
using Topic = h256; using Topic = h256;
@ -67,7 +68,7 @@ using Topic = h256;
using AbridgedTopics = std::vector<AbridgedTopic>; using AbridgedTopics = std::vector<AbridgedTopic>;
using Topics = h256s; using Topics = h256s;
using TopicBloomFilterHash = FixedHash<c_topicBloomFilterSize>; using TopicBloomFilterHash = FixedHash<TopicBloomFilterSize>;
AbridgedTopic abridge(Topic const& _topic); AbridgedTopic abridge(Topic const& _topic);
AbridgedTopics abridge(Topics const& _topics); AbridgedTopics abridge(Topics const& _topics);

9
libwhisper/Message.cpp

@ -181,3 +181,12 @@ void Envelope::proveWork(unsigned _ms)
} }
} }
} }
bool Envelope::matchesBloomFilter(TopicBloomFilterHash const& f) const
{
for (AbridgedTopic t: m_topic)
if (f.contains(t.template bloomPart<BitsPerBloom, TopicBloomFilterSize>()))
return true;
return false;
}

2
libwhisper/Message.h

@ -80,6 +80,8 @@ public:
unsigned workProved() const; unsigned workProved() const;
void proveWork(unsigned _ms); void proveWork(unsigned _ms);
bool matchesBloomFilter(TopicBloomFilterHash const& f) const;
private: private:
Envelope(unsigned _exp, unsigned _ttl, AbridgedTopics const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {} Envelope(unsigned _exp, unsigned _ttl, AbridgedTopics const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {}

24
libwhisper/WhisperHost.cpp

@ -51,6 +51,8 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p)
{ {
// this function processes messages originated both by local host (_p == null), and by remote peers (_p != null)
cnote << this << ": inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data()); cnote << this << ": inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data());
if (_m.expiry() <= (unsigned)time(0)) if (_m.expiry() <= (unsigned)time(0))
@ -66,21 +68,25 @@ void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p)
m_expiryQueue.insert(make_pair(_m.expiry(), h)); m_expiryQueue.insert(make_pair(_m.expiry(), h));
} }
DEV_GUARDED(m_filterLock) int rating = 1; // rating for local host is based upon: 1. installed watch; 2. proof of work
{
for (auto const& f: m_filters) if (_p) // incoming message from remote peer
if (f.second.filter.matches(_m)) DEV_GUARDED(m_filterLock)
for (auto& i: m_watches) for (auto const& f: m_filters)
if (i.second.id == f.first) if (f.second.filter.matches(_m))
i.second.changes.push_back(h); for (auto& i: m_watches)
} if (i.second.id == f.first)
{
i.second.changes.push_back(h);
rating += 10; // subject to review
}
// TODO p2p: capability-based rating // TODO p2p: capability-based rating
for (auto i: peerSessions()) for (auto i: peerSessions())
{ {
auto w = i.first->cap<WhisperPeer>().get(); auto w = i.first->cap<WhisperPeer>().get();
if (w == _p) if (w == _p)
w->addRating(1); w->addRating(rating);
else else
w->noteNewMessage(h, _m); w->noteNewMessage(h, _m);
} }

2
libwhisper/WhisperHost.h

@ -50,7 +50,7 @@ class WhisperHost: public HostCapability<WhisperPeer>, public Interface, public
public: public:
WhisperHost(); WhisperHost();
virtual ~WhisperHost(); virtual ~WhisperHost();
unsigned protocolVersion() const { return c_whisperProtocolVersion; } unsigned protocolVersion() const { return WhisperProtocolVersion; }
/// remove old messages /// remove old messages
void cleanup(); void cleanup();
std::map<h256, Envelope> all() const { dev::ReadGuard l(x_messages); return m_messages; } std::map<h256, Envelope> all() const { dev::ReadGuard l(x_messages); return m_messages; }

43
libwhisper/WhisperPeer.cpp

@ -91,19 +91,17 @@ void WhisperPeer::sendMessages()
if (m_advertiseTopicsOfInterest) if (m_advertiseTopicsOfInterest)
sendTopicsOfInterest(host()->bloom()); sendTopicsOfInterest(host()->bloom());
multimap<unsigned, h256> available;
DEV_GUARDED(x_unseen)
m_unseen.swap(available);
RLPStream amalg; RLPStream amalg;
unsigned msgCount = 0;
{ // send the highest rated messages first
Guard l(x_unseen); for (auto i = available.rbegin(); i != available.rend(); ++i)
msgCount = m_unseen.size(); host()->streamMessage(i->second, amalg);
while (m_unseen.size())
{ unsigned msgCount = available.size();
auto p = *m_unseen.begin();
m_unseen.erase(m_unseen.begin());
host()->streamMessage(p.second, amalg);
}
}
if (msgCount) if (msgCount)
{ {
RLPStream s; RLPStream s;
@ -114,8 +112,27 @@ void WhisperPeer::sendMessages()
void WhisperPeer::noteNewMessage(h256 _h, Envelope const& _m) void WhisperPeer::noteNewMessage(h256 _h, Envelope const& _m)
{ {
unsigned rate = ratingForPeer(_m);
Guard l(x_unseen); Guard l(x_unseen);
m_unseen.insert(make_pair(rating(_m), _h)); m_unseen.insert(make_pair(rate, _h));
}
unsigned WhisperPeer::ratingForPeer(Envelope const& e) const
{
// we try to estimate, how valuable this nessage will be for the remote peer,
// according to the following criteria:
// 1. bloom filter
// 2. proof of work
static const unsigned BloomFilterMatchReward = 256; // vlad todo: move to common.h
unsigned rating = 0;
DEV_GUARDED(x_bloom)
if (e.matchesBloomFilter(m_bloom))
rating += BloomFilterMatchReward;
rating += e.sha3().firstBitSet();
return rating;
} }
void WhisperPeer::sendTopicsOfInterest(TopicBloomFilterHash const& _bloom) void WhisperPeer::sendTopicsOfInterest(TopicBloomFilterHash const& _bloom)

4
libwhisper/WhisperPeer.h

@ -53,7 +53,7 @@ public:
virtual ~WhisperPeer(); virtual ~WhisperPeer();
WhisperHost* host() const; WhisperHost* host() const;
static std::string name() { return "shh"; } static std::string name() { return "shh"; }
static u256 version() { return c_whisperProtocolVersion; } static u256 version() { return WhisperProtocolVersion; }
static unsigned messageCount() { return PacketCount; } static unsigned messageCount() { return PacketCount; }
TopicBloomFilterHash bloom() const { dev::Guard g(x_bloom); return m_bloom; } TopicBloomFilterHash bloom() const { dev::Guard g(x_bloom); return m_bloom; }
void sendTopicsOfInterest(TopicBloomFilterHash const& _bloom); ///< sends our bloom filter to remote peer void sendTopicsOfInterest(TopicBloomFilterHash const& _bloom); ///< sends our bloom filter to remote peer
@ -62,7 +62,7 @@ public:
private: private:
virtual bool interpret(unsigned _id, RLP const&) override; virtual bool interpret(unsigned _id, RLP const&) override;
void sendMessages(); void sendMessages();
unsigned rating(Envelope const&) const { return 0; } // TODO unsigned ratingForPeer(Envelope const& e) const;
void noteNewMessage(h256 _h, Envelope const& _m); void noteNewMessage(h256 _h, Envelope const& _m);
void setBloom(TopicBloomFilterHash const& _b) { dev::Guard g(x_bloom); m_bloom = _b; } void setBloom(TopicBloomFilterHash const& _b) { dev::Guard g(x_bloom); m_bloom = _b; }

42
mix/ClientModel.cpp

@ -206,6 +206,21 @@ QVariantList ClientModel::gasCosts() const
return res; return res;
} }
void ClientModel::addAccount(QString const& _secret)
{
KeyPair key(Secret(_secret.toStdString()));
m_accountsSecret.push_back(key);
Address address = key.address();
m_accounts[address] = Account(u256(0), Account::NormalCreation);
m_ethAccounts->setAccounts(m_accountsSecret);
}
QString ClientModel::resolveAddress(QString const& _secret)
{
KeyPair key(Secret(_secret.toStdString()));
return "0x" + QString::fromStdString(key.address().hex());
}
void ClientModel::setupScenario(QVariantMap _scenario) void ClientModel::setupScenario(QVariantMap _scenario)
{ {
onStateReset(); onStateReset();
@ -336,6 +351,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence)
if (!transaction.isFunctionCall) if (!transaction.isFunctionCall)
{ {
callAddress(Address(address.toStdString()), bytes(), transaction); callAddress(Address(address.toStdString()), bytes(), transaction);
onNewTransaction(); onNewTransaction();
continue; continue;
} }
@ -674,7 +690,7 @@ RecordLogEntry* ClientModel::lastBlock() const
strGas << blockInfo.gasUsed; strGas << blockInfo.gasUsed;
stringstream strNumber; stringstream strNumber;
strNumber << blockInfo.number; strNumber << blockInfo.number;
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantList()); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList());
QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record; return record;
} }
@ -735,6 +751,7 @@ void ClientModel::onNewTransaction()
Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress; Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress;
auto contractAddressIter = m_contractNames.find(contractAddress); auto contractAddressIter = m_contractNames.find(contractAddress);
QVariantMap inputParameters; QVariantMap inputParameters;
QVariantMap returnParameters;
QVariantList logs; QVariantList logs;
if (contractAddressIter != m_contractNames.end()) if (contractAddressIter != m_contractNames.end())
{ {
@ -754,6 +771,11 @@ void ClientModel::onNewTransaction()
returned += "("; returned += "(";
returned += returnValues.join(", "); returned += returnValues.join(", ");
returned += ")"; returned += ")";
QStringList returnParams = encoder.decode(funcDef->returnParameters(), tr.result.output);
for (int k = 0; k < returnParams.length(); ++k)
returnParameters.insert(funcDef->returnParameters().at(k)->name(), returnParams.at(k));
bytes data = tr.inputParameters; bytes data = tr.inputParameters;
data.erase(data.begin(), data.begin() + 4); data.erase(data.begin(), data.begin() + 4);
QStringList parameters = encoder.decode(funcDef->parametersList(), data); QStringList parameters = encoder.decode(funcDef->parametersList(), data);
@ -837,9 +859,25 @@ void ClientModel::onNewTransaction()
} }
RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction,
gasUsed, sender, label, inputParameters, logs); gasUsed, sender, label, inputParameters, returnParameters, logs);
QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership);
emit newRecord(log); emit newRecord(log);
// retrieving all accounts balance
QVariantMap state;
QVariantMap accountBalances;
for (auto const& ctr : m_contractAddresses)
{
u256 wei = m_client->balanceAt(ctr.second, PendingBlock);
accountBalances.insert("0x" + QString::fromStdString(ctr.second.hex()), QEther(wei, QEther::Wei).format());
}
for (auto const& account : m_accounts)
{
u256 wei = m_client->balanceAt(account.first, PendingBlock);
accountBalances.insert("0x" + QString::fromStdString(account.first.hex()), QEther(wei, QEther::Wei).format());
}
state.insert("accounts", accountBalances);
emit newState(recordIndex, state);
} }
} }

14
mix/ClientModel.h

@ -32,6 +32,7 @@
#include <QVariableDeclaration.h> #include <QVariableDeclaration.h>
#include <libethereum/Account.h> #include <libethereum/Account.h>
#include "MachineStates.h" #include "MachineStates.h"
#include "QEther.h"
namespace dev namespace dev
{ {
@ -115,6 +116,8 @@ class RecordLogEntry: public QObject
Q_PROPERTY(QString label MEMBER m_label CONSTANT) Q_PROPERTY(QString label MEMBER m_label CONSTANT)
/// input parameters /// input parameters
Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT) Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT)
/// return parameters
Q_PROPERTY(QVariantMap returnParameters MEMBER m_returnParameters CONSTANT)
/// logs /// logs
Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT) Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT)
@ -128,9 +131,9 @@ public:
RecordLogEntry(): RecordLogEntry():
m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {} m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {}
RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed, RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed,
QString _sender, QString _label, QVariantMap _inputParameters, QVariantList _logs): QString _sender, QString _label, QVariantMap _inputParameters, QVariantMap _returnParameters, QVariantList _logs):
m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed), m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed),
m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_logs(_logs) {} m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_returnParameters(_returnParameters), m_logs(_logs) {}
private: private:
unsigned m_recordIndex; unsigned m_recordIndex;
@ -146,6 +149,7 @@ private:
QString m_sender; QString m_sender;
QString m_label; QString m_label;
QVariantMap m_inputParameters; QVariantMap m_inputParameters;
QVariantMap m_returnParameters;
QVariantList m_logs; QVariantList m_logs;
}; };
@ -183,6 +187,10 @@ public:
Q_INVOKABLE QString encodeStringParam(QString const& _param); Q_INVOKABLE QString encodeStringParam(QString const& _param);
/// To Hex number /// To Hex number
Q_INVOKABLE QString toHex(QString const& _int); Q_INVOKABLE QString toHex(QString const& _int);
/// Add new account to the model
Q_INVOKABLE void addAccount(QString const& _secret);
/// Return the address associated with the current secret
Q_INVOKABLE QString resolveAddress(QString const& _secret);
public slots: public slots:
/// Setup scenario, run transaction sequence, show debugger for the last transaction /// Setup scenario, run transaction sequence, show debugger for the last transaction
@ -236,6 +244,8 @@ signals:
void newRecord(RecordLogEntry* _r); void newRecord(RecordLogEntry* _r);
/// State (transaction log) cleared /// State (transaction log) cleared
void stateCleared(); void stateCleared();
/// new state has been processed
void newState(unsigned _record, QVariantMap _accounts);
private: private:
RecordLogEntry* lastBlock() const; RecordLogEntry* lastBlock() const;

2
mix/CodeModel.cpp

@ -543,7 +543,7 @@ void CodeModel::retrieveSubType(SolidityType& _wrapperType, dev::solidity::Type
SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
{ {
SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString()), std::vector<SolidityDeclaration>(), std::vector<QString>(), nullptr }; SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString(true)), std::vector<SolidityDeclaration>(), std::vector<QString>(), nullptr };
if (!_type) if (!_type)
return r; return r;
switch (_type->getCategory()) switch (_type->getCategory())

2
mix/qml.qrc

@ -69,5 +69,7 @@
<file>qml/ScenarioExecution.qml</file> <file>qml/ScenarioExecution.qml</file>
<file>qml/ScenarioLoader.qml</file> <file>qml/ScenarioLoader.qml</file>
<file>qml/ScenarioButton.qml</file> <file>qml/ScenarioButton.qml</file>
<file>qml/Watchers.qml</file>
<file>qml/KeyValuePanel.qml</file>
</qresource> </qresource>
</RCC> </RCC>

244
mix/qml/Block.qml

@ -22,6 +22,7 @@ ColumnLayout
property int blockIndex property int blockIndex
property variant scenario property variant scenario
property string labelColor: "#414141" property string labelColor: "#414141"
signal txSelected(var txIndex)
function calculateHeight() function calculateHeight()
{ {
@ -36,6 +37,14 @@ ColumnLayout
return trHeight return trHeight
} }
function editTx(txIndex)
{
transactionDialog.stateAccounts = scenario.accounts
transactionDialog.execute = false
transactionDialog.editMode = true
transactionDialog.open(txIndex, blockIndex, transactions.get(txIndex))
}
onOpenedTrChanged: onOpenedTrChanged:
{ {
Layout.preferredHeight = calculateHeight() Layout.preferredHeight = calculateHeight()
@ -156,11 +165,11 @@ ColumnLayout
Image { Image {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: -9 anchors.leftMargin: -4
anchors.topMargin: -9 anchors.topMargin: 0
id: saveStatusImage id: saveStatusImage
source: "qrc:/qml/img/recyclediscard@2x.png" source: "qrc:/qml/img/recyclediscard@2x.png"
width: statusWidth + 20 width: statusWidth + 10
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
} }
@ -194,185 +203,125 @@ ColumnLayout
Rectangle Rectangle
{ {
Layout.preferredWidth: blockWidth Layout.preferredWidth: blockWidth
Layout.preferredHeight: parent.height Layout.preferredHeight: trHeight
height: trHeight
color: "#DEDCDC" color: "#DEDCDC"
id: rowContentTr id: rowContentTr
anchors.top: parent.top anchors.top: parent.top
property bool selected: false
Connections
{
target: blockChainPanel
onTxSelected: {
if (root.blockIndex !== blockIndex || index !== txIndex)
rowContentTr.deselect()
}
}
function deselect()
{
rowContentTr.selected = false
rowContentTr.color = "#DEDCDC"
hash.color = labelColor
func.color = labelColor
}
MouseArea MouseArea
{ {
anchors.fill: parent anchors.fill: parent
onClicked: {
if (!rowContentTr.selected)
{
rowContentTr.selected = true
rowContentTr.color = "#4F4F4F"
hash.color = "#EAB920"
func.color = "#EAB920"
txSelected(index)
}
else
rowContentTr.deselect()
}
onDoubleClicked: onDoubleClicked:
{ {
transactionDialog.stateAccounts = scenario.accounts root.editTx(index)
transactionDialog.execute = false
transactionDialog.open(index, blockIndex, transactions.get(index))
} }
} }
ColumnLayout RowLayout
{ {
anchors.top: parent.top Layout.fillWidth: true
width: parent.width Layout.preferredHeight: trHeight - 10
spacing: 20 anchors.verticalCenter: parent.verticalCenter
RowLayout Rectangle
{ {
anchors.top: parent.top Layout.preferredWidth: fromWidth
Layout.fillWidth: true anchors.left: parent.left
Rectangle anchors.leftMargin: horizontalMargin
Text
{ {
Layout.preferredWidth: fromWidth id: hash
anchors.left: parent.left width: parent.width - 30
anchors.leftMargin: horizontalMargin elide: Text.ElideRight
Text anchors.verticalCenter: parent.verticalCenter
{ maximumLineCount: 1
id: hash color: labelColor
width: parent.width - 30 font.pointSize: dbgStyle.absoluteSize(1)
elide: Text.ElideRight font.bold: true
anchors.verticalCenter: parent.verticalCenter text: {
maximumLineCount: 1 if (index >= 0)
color: labelColor return clientModel.resolveAddress(transactions.get(index).sender)
font.pointSize: dbgStyle.absoluteSize(1)
font.bold: true
text: {
if (index >= 0)
return transactions.get(index).sender
else
return ""
}
}
}
Rectangle
{
Layout.preferredWidth: toWidth
Text
{
id: func
text: {
if (index >= 0)
parent.parent.userFrienldyToken(transactions.get(index).label)
else
return ""
}
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
color: labelColor
font.pointSize: dbgStyle.absoluteSize(1)
font.bold: true
maximumLineCount: 1
width: parent.width
}
}
function userFrienldyToken(value)
{
if (value && value.indexOf("<") === 0)
{
if (value.split("> ")[1] === " - ")
return value.split(" - ")[0].replace("<", "")
else else
return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; return ""
}
else
return value
}
Rectangle
{
Layout.preferredWidth: valueWidth
Text
{
id: returnValue
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
color: labelColor
font.bold: true
font.pointSize: dbgStyle.absoluteSize(1)
width: parent.width - 30
text: {
if (index >= 0 && transactions.get(index).returned)
return transactions.get(index).returned
else
return ""
}
} }
} }
}
Rectangle Rectangle
{
Layout.preferredWidth: toWidth
Text
{ {
Layout.preferredWidth: logsWidth id: func
Layout.preferredHeight: trHeight - 10 text: {
width: logsWidth if (index >= 0)
color: "transparent" parent.parent.userFrienldyToken(transactions.get(index).label)
Text else
{ return ""
id: logs
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 10
color: labelColor
font.bold: true
font.pointSize: dbgStyle.absoluteSize(1)
text: {
if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count)
return transactions.get(index).logs.count
else
return ""
}
}
MouseArea {
anchors.fill: parent
onClicked: {
rowTransaction.displayContent();
}
} }
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
color: labelColor
font.pointSize: dbgStyle.absoluteSize(1)
font.bold: true
maximumLineCount: 1
width: parent.width
} }
} }
RowLayout function userFrienldyToken(value)
{ {
id: rowDetailedContent if (value && value.indexOf("<") === 0)
visible: false
Layout.preferredHeight:{
if (index >= 0 && transactions.get(index).logs)
return 100 * transactions.get(index).logs.count
else
return 100
}
onVisibleChanged:
{ {
var lognb = transactions.get(index).logs.count if (value.split("> ")[1] === " - ")
if (visible) return value.split(" - ")[0].replace("<", "")
{
rowContentTr.Layout.preferredHeight = trHeight + 100 * lognb
openedTr += 100 * lognb
}
else else
{ return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()";
rowContentTr.Layout.preferredHeight = trHeight
openedTr -= 100 * lognb
}
} }
else
Text { return value
anchors.left: parent.left }
anchors.leftMargin: horizontalMargin
id: logsText
}
}
} }
} }
Rectangle Rectangle
{ {
width: debugActionWidth width: debugActionWidth
height: trHeight height: trHeight - 10
anchors.left: rowContentTr.right anchors.right: rowContentTr.right
anchors.topMargin: -6
anchors.top: rowContentTr.top anchors.top: rowContentTr.top
anchors.leftMargin: -50 anchors.rightMargin: 10
color: "transparent" color: "transparent"
Image { Image {
@ -380,7 +329,6 @@ ColumnLayout
source: "qrc:/qml/img/rightarrow@2x.png" source: "qrc:/qml/img/rightarrow@2x.png"
width: debugActionWidth width: debugActionWidth
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: transactions.get(index).recordIndex !== undefined visible: transactions.get(index).recordIndex !== undefined
} }

84
mix/qml/BlockChain.qml

@ -13,12 +13,18 @@ import "."
ColumnLayout { ColumnLayout {
id: blockChainPanel id: blockChainPanel
property alias trDialog: transactionDialog
property alias blockChainRepeater: blockChainRepeater
property variant model property variant model
property var states: ({})
spacing: 0 spacing: 0
property int previousWidth property int previousWidth
property variant debugTrRequested: [] property variant debugTrRequested: []
signal chainChanged signal chainChanged
signal chainReloaded signal chainReloaded
signal txSelected(var blockIndex, var txIndex)
signal rebuilding
signal accountAdded(string address, string amount)
Connections Connections
{ {
@ -40,20 +46,23 @@ ColumnLayout {
var minWidth = scenarioMinWidth - 20 // margin var minWidth = scenarioMinWidth - 20 // margin
if (width <= minWidth || previousWidth <= minWidth) if (width <= minWidth || previousWidth <= minWidth)
{ {
fromWidth = 100 fromWidth = 250
toWidth = 100 toWidth = 240
valueWidth = 200
} }
else else
{ {
var diff = (width - previousWidth) / 3; var diff = (width - previousWidth) / 3;
fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff fromWidth = fromWidth + diff < 250 ? 250 : fromWidth + diff
toWidth = toWidth + diff < 100 ? 100 : toWidth + diff toWidth = toWidth + diff < 240 ? 240 : toWidth + diff
valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff
} }
previousWidth = width previousWidth = width
} }
function getState(record)
{
return states[record]
}
function load(scenario) function load(scenario)
{ {
if (!scenario) if (!scenario)
@ -61,6 +70,7 @@ ColumnLayout {
if (model) if (model)
rebuild.startBlinking() rebuild.startBlinking()
model = scenario model = scenario
states = []
blockModel.clear() blockModel.clear()
for (var b in model.blocks) for (var b in model.blocks)
blockModel.append(model.blocks[b]) blockModel.append(model.blocks[b])
@ -68,10 +78,8 @@ ColumnLayout {
} }
property int statusWidth: 30 property int statusWidth: 30
property int fromWidth: 150 property int fromWidth: 250
property int toWidth: 100 property int toWidth: 240
property int valueWidth: 200
property int logsWidth: 40
property int debugActionWidth: 40 property int debugActionWidth: 40
property int horizontalMargin: 10 property int horizontalMargin: 10
property int cellSpacing: 10 property int cellSpacing: 10
@ -80,7 +88,7 @@ ColumnLayout {
{ {
id: header id: header
spacing: 0 spacing: 0
Layout.preferredHeight: 30 Layout.preferredHeight: 24
Rectangle Rectangle
{ {
Layout.preferredWidth: statusWidth Layout.preferredWidth: statusWidth
@ -91,12 +99,13 @@ ColumnLayout {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
source: "qrc:/qml/img/recycleicon@2x.png" source: "qrc:/qml/img/recycleicon@2x.png"
width: statusWidth + 20 width: statusWidth + 10
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
} }
} }
Rectangle Rectangle
{ {
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: fromWidth Layout.preferredWidth: fromWidth
Label Label
{ {
@ -109,21 +118,13 @@ ColumnLayout {
Label Label
{ {
text: "To" text: "To"
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: toWidth + cellSpacing Layout.preferredWidth: toWidth + cellSpacing
} }
Label Label
{
text: "Value"
Layout.preferredWidth: valueWidth + cellSpacing
}
Label
{
text: "Logs"
Layout.preferredWidth: logsWidth + cellSpacing
}
Label
{ {
text: "" text: ""
anchors.verticalCenter: parent.verticalCenter
Layout.preferredWidth: debugActionWidth Layout.preferredWidth: debugActionWidth
} }
} }
@ -162,8 +163,22 @@ ColumnLayout {
{ {
id: blockChainRepeater id: blockChainRepeater
model: blockModel model: blockModel
function editTx(blockIndex, txIndex)
{
itemAt(blockIndex).editTx(txIndex)
}
Block Block
{ {
Connections
{
target: block
onTxSelected: {
blockChainPanel.txSelected(index, txIndex)
}
}
id: block
scenario: blockChainPanel.model scenario: blockChainPanel.model
Layout.preferredWidth: blockChainScrollView.width Layout.preferredWidth: blockChainScrollView.width
Layout.preferredHeight: Layout.preferredHeight:
@ -248,6 +263,8 @@ ColumnLayout {
Rectangle Rectangle
{ {
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
Layout.preferredHeight: 70
color: "transparent"
RowLayout RowLayout
{ {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -270,7 +287,9 @@ ColumnLayout {
{ {
if (ensureNotFuturetime.running) if (ensureNotFuturetime.running)
return; return;
rebuilding()
stopBlinking() stopBlinking()
states = []
var retBlocks = []; var retBlocks = [];
var bAdded = 0; var bAdded = 0;
for (var j = 0; j < model.blocks.length; j++) for (var j = 0; j < model.blocks.length; j++)
@ -316,7 +335,7 @@ ColumnLayout {
blockModel.append(model.blocks[j]) blockModel.append(model.blocks[j])
ensureNotFuturetime.start() ensureNotFuturetime.start()
clientModel.setupScenario(model); clientModel.setupScenario(model);
} }
buttonShortcut: "" buttonShortcut: ""
sourceImg: "qrc:/qml/img/recycleicon@2x.png" sourceImg: "qrc:/qml/img/recycleicon@2x.png"
@ -346,6 +365,7 @@ ColumnLayout {
var item = TransactionHelper.defaultTransaction() var item = TransactionHelper.defaultTransaction()
transactionDialog.stateAccounts = model.accounts transactionDialog.stateAccounts = model.accounts
transactionDialog.execute = true transactionDialog.execute = true
transactionDialog.editMode = false
transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item)
} }
width: 100 width: 100
@ -397,7 +417,6 @@ ColumnLayout {
} }
else else
addNewBlock() addNewBlock()
} }
function addNewBlock() function addNewBlock()
@ -410,7 +429,7 @@ ColumnLayout {
height: 30 height: 30
buttonShortcut: "" buttonShortcut: ""
sourceImg: "qrc:/qml/img/addblock@2x.png" sourceImg: "qrc:/qml/img/newblock@2x.png"
} }
} }
@ -448,11 +467,13 @@ ColumnLayout {
tr.recordIndex = _r.recordIndex tr.recordIndex = _r.recordIndex
tr.logs = _r.logs tr.logs = _r.logs
tr.sender = _r.sender tr.sender = _r.sender
tr.returnParameters = _r.returnParameters
var trModel = blockModel.getTransaction(blockIndex, trIndex) var trModel = blockModel.getTransaction(blockIndex, trIndex)
trModel.returned = _r.returned trModel.returned = _r.returned
trModel.recordIndex = _r.recordIndex trModel.recordIndex = _r.recordIndex
trModel.logs = _r.logs trModel.logs = _r.logs
trModel.sender = _r.sender trModel.sender = _r.sender
trModel.returnParameters = _r.returnParameters
blockModel.setTransaction(blockIndex, trIndex, trModel) blockModel.setTransaction(blockIndex, trIndex, trModel)
return; return;
} }
@ -472,9 +493,15 @@ ColumnLayout {
itemTr.sender = _r.sender itemTr.sender = _r.sender
itemTr.recordIndex = _r.recordIndex itemTr.recordIndex = _r.recordIndex
itemTr.logs = _r.logs itemTr.logs = _r.logs
itemTr.returnParameters = _r.returnParameters
model.blocks[model.blocks.length - 1].transactions.push(itemTr) model.blocks[model.blocks.length - 1].transactions.push(itemTr)
blockModel.appendTransaction(itemTr) blockModel.appendTransaction(itemTr)
} }
onNewState: {
states[_record] = _accounts
}
onMiningComplete: onMiningComplete:
{ {
} }
@ -484,7 +511,12 @@ ColumnLayout {
id: newAccount id: newAccount
text: qsTr("New Account..") text: qsTr("New Account..")
onClicked: { onClicked: {
model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) var ac = projectModel.stateListModel.newAccount("O", QEther.Wei)
model.accounts.push(ac)
clientModel.addAccount(ac.secret);
for (var k in Object.keys(blockChainPanel.states))
blockChainPanel.states[k].accounts["0x" + ac.address] = "0 wei" // add the account in all the previous state (balance at O)
accountAdded(ac.address, "0")
} }
Layout.preferredWidth: 100 Layout.preferredWidth: 100
Layout.preferredHeight: 30 Layout.preferredHeight: 30

134
mix/qml/KeyValuePanel.qml

@ -0,0 +1,134 @@
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 Qt.labs.settings 1.0
import org.ethereum.qml.QEther 1.0
import "js/Debugger.js" as Debugger
import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "js/TransactionHelper.js" as TransactionHelper
import "js/QEtherHelper.js" as QEtherHelper
import "."
ColumnLayout {
id: root
property alias title: titleLabel.text
property variant _data
property string role
property alias model: modelKeyValue
function add(key, value)
{
modelKeyValue.append({ "key": key, "value": value })
}
function clear()
{
modelKeyValue.clear()
}
function init()
{
modelKeyValue.clear()
if (typeof(computeData) !== "undefined" && computeData instanceof Function)
computeData()
else
{
if (_data !== undefined && _data[role] !== undefined)
{
var keys = Object.keys(_data[role])
for (var k in keys)
{
modelKeyValue.append({ "key": keys[k] === "" ? "undefined" : keys[k], "value": _data[role][keys[k]] })
}
}
}
}
RowLayout
{
Layout.preferredHeight: 20
Layout.fillWidth: true
Label
{
id: titleLabel
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
color: "white"
}
}
RowLayout
{
Layout.fillWidth: true
Layout.preferredHeight: 100
ListModel
{
id: modelKeyValue
}
Rectangle
{
Layout.fillWidth: true
Layout.fillHeight: true
color: "white"
radius: 2
ScrollView
{
id: columnValues
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
anchors.fill: parent
clip: true
ColumnLayout
{
anchors.margins: 10
Repeater
{
id: repeaterKeyValue
model: modelKeyValue
RowLayout
{
Layout.fillWidth: true
Layout.preferredHeight: 30
spacing: 0
Rectangle
{
Layout.preferredWidth: columnValues.width / 2
Label
{
anchors.left: parent.left
anchors.leftMargin: 10
text: {
if (index >= 0 && repeaterKeyValue.model.get(index).key !== undefined)
return repeaterKeyValue.model.get(index).key
else
return ""
}
}
}
Rectangle
{
Layout.preferredWidth: columnValues.width / 2 - 10
Label
{
anchors.right: parent.right
anchors.rightMargin: 10
text: {
if (index >= 0 && repeaterKeyValue.model.get(index).value !== undefined)
return repeaterKeyValue.model.get(index).value
else
return ""
}
}
}
}
}
}
}
}
}
}

2
mix/qml/MainContent.qml

@ -31,7 +31,7 @@ Rectangle {
property alias codeEditor: codeEditor property alias codeEditor: codeEditor
property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally
property bool firstCompile: true property bool firstCompile: true
property int scenarioMinWidth: 590 property int scenarioMinWidth: 620
Connections { Connections {
target: codeModel target: codeModel

124
mix/qml/ScenarioExecution.qml

@ -8,6 +8,7 @@ import "js/Debugger.js" as Debugger
import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "." import "."
Rectangle { Rectangle {
color: "#ededed" color: "#ededed"
property alias bc: blockChain property alias bc: blockChain
@ -18,50 +19,109 @@ Rectangle {
onProjectLoaded: { onProjectLoaded: {
loader.init() loader.init()
} }
} }
Column ScrollView
{ {
anchors.margins: 10
anchors.fill: parent anchors.fill: parent
spacing: 10 onWidthChanged: {
ScenarioLoader columnExe.width = width - 40
{
height: 100
width: parent.width
id: loader
} }
Connections ColumnLayout
{ {
target: blockChain id: columnExe
onChainChanged: Layout.preferredWidth: parent.width
{ width: parent.width - 40
loader.needSaveOrReload() anchors.left: parent.left
} anchors.leftMargin: 15
} ColumnLayout
{
id: scenarioColumn
width: parent.width
spacing: 10
ScenarioLoader
{
anchors.horizontalCenter: parent.horizontalCenter
height: 100
Layout.preferredWidth: 400
width: 400
id: loader
}
Rectangle Connections
{ {
width: parent.parent.width target: blockChain
height: 1 onChainChanged:
color: "#cccccc" {
} loader.needSaveOrReload()
}
}
Connections Rectangle
{ {
target: loader Layout.preferredWidth: parent.width
onLoaded: height: 1
color: "#cccccc"
}
Connections
{
target: loader
onLoaded:
{
watchers.clear()
blockChain.load(scenario)
}
}
BlockChain
{
id: blockChain
width: parent.width
}
Connections
{
target: blockChain
property var currentSelectedBlock
property var currentSelectedTx
onTxSelected: {
currentSelectedBlock = blockIndex
currentSelectedTx = txIndex
updateWatchers(blockIndex, txIndex)
}
function updateWatchers(blockIndex, txIndex){
var tx = blockChain.model.blocks[blockIndex].transactions[txIndex]
var state = blockChain.getState(tx.recordIndex)
watchers.updateWidthTx(tx, state, blockIndex, txIndex)
}
onRebuilding: {
watchers.clear()
}
onAccountAdded: {
watchers.addAccount(address, "0 wei")
}
}
}
Watchers
{ {
blockChain.load(scenario) id: watchers
bc: blockChain
Layout.fillWidth: true
Layout.preferredHeight: 740
} }
}
BlockChain Rectangle
{ {
id: blockChain color: "transparent"
width: parent.width Layout.preferredHeight: 50
Layout.fillWidth: true
}
} }
} }
} }

9
mix/qml/ScenarioLoader.qml

@ -107,11 +107,13 @@ ColumnLayout
Rectangle Rectangle
{ {
id: editIconRect id: editIconRect
anchors.top: scenarioName.top
anchors.topMargin: 6
anchors.left: scenarioName.right anchors.left: scenarioName.right
anchors.leftMargin: 15 anchors.leftMargin: 20
Image { Image {
source: "qrc:/qml/img/edit.png" source: "qrc:/qml/img/edittransaction.png"
width: 10 width: 30
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -126,7 +128,6 @@ ColumnLayout
scenarioNameEdit.save() scenarioNameEdit.save()
else else
scenarioNameEdit.edit() scenarioNameEdit.edit()
} }
} }
} }

3
mix/qml/StateListModel.qml

@ -257,7 +257,8 @@ Item {
_secret = clientModel.newSecret(); _secret = clientModel.newSecret();
var address = clientModel.address(_secret); var address = clientModel.address(_secret);
var name = qsTr("Account") + "-" + address.substring(0, 4); var name = qsTr("Account") + "-" + address.substring(0, 4);
return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit), address: address }; var amount = QEtherHelper.createEther(_balance, _unit)
return { name: name, secret: _secret, balance: amount, address: address };
} }
function duplicateState(index) function duplicateState(index)

7
mix/qml/TransactionDialog.qml

@ -16,7 +16,8 @@ Dialog {
width: 580 width: 580
height: 500 height: 500
visible: false visible: false
title: qsTr("Edit Transaction") title: editMode ? qsTr("Edit Transaction") : qsTr("Add Transaction")
property bool editMode
property int transactionIndex property int transactionIndex
property int blockIndex property int blockIndex
property alias gas: gasValueEdit.gasValue; property alias gas: gasValueEdit.gasValue;
@ -390,7 +391,7 @@ Dialog {
objectName: "trTypeExecute" objectName: "trTypeExecute"
exclusiveGroup: rbbuttonList exclusiveGroup: rbbuttonList
height: 30 height: 30
text: qsTr("Execute Contract") text: qsTr("Transact with Contract")
} }
} }
} }
@ -687,7 +688,7 @@ Dialog {
} }
Button { Button {
text: qsTr("Update"); text: editMode ? qsTr("Update") : qsTr("Ok")
onClicked: { onClicked: {
var invalid = InputValidator.validate(paramsModel, paramValues); var invalid = InputValidator.validate(paramsModel, paramValues);
if (invalid.length === 0) if (invalid.length === 0)

203
mix/qml/Watchers.qml

@ -0,0 +1,203 @@
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 Qt.labs.settings 1.0
import org.ethereum.qml.QEther 1.0
import "js/Debugger.js" as Debugger
import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "js/TransactionHelper.js" as TransactionHelper
import "js/QEtherHelper.js" as QEtherHelper
import "."
Rectangle {
color: "#4F4F4F"
radius: 4
property variant tx
property variant currentState
property variant bc
property var blockIndex
property var txIndex
function clear()
{
from.text = ""
to.text = ""
value.text = ""
inputParams.clear()
returnParams.clear()
accounts.clear()
events.clear()
}
function addAccount(address, amount)
{
accounts.add(address, amount)
}
function updateWidthTx(_tx, _state, _blockIndex, _txIndex)
{
from.text = clientModel.resolveAddress(_tx.sender)
to.text = _tx.label
value.text = _tx.value.format()
tx = _tx
blockIndex = _blockIndex
txIndex = _txIndex
currentState = _state
inputParams.init()
if (_tx.isContractCreation)
{
returnParams.role = "creationAddr"
returnParams._data = {
creationAddr : {
}
}
returnParams._data.creationAddr[qsTr("contract address")] = _tx.returned
}
else
{
returnParams.role = "returnParameters"
returnParams._data = tx
}
returnParams.init()
accounts.init()
events.init()
}
Column {
anchors.fill: parent
spacing: 15
Rectangle
{
height: 15
width: parent.width - 30
color: "transparent"
Row
{
id: rowHeader
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: rowHeader.parent.top
anchors.topMargin: 6
spacing: 5
Label {
id: fromLabel
text: qsTr("from")
visible: from.text !== ""
color: "#EAB920"
}
Label {
id: from
color: "#EAB920"
elide: Text.ElideRight
maximumLineCount: 1
clip: true
width: 200
}
Label {
id: toLabel
text: qsTr("to")
visible: from.text !== ""
color: "#EAB920"
}
Label {
id: to
color: "#EAB920"
elide: Text.ElideRight
maximumLineCount: 1
clip: true
width: 100
}
Label {
id: value
color: "#EAB920"
font.italic: true
clip: true
}
}
Image {
anchors.right: rowHeader.parent.right
anchors.top: rowHeader.parent.top
anchors.topMargin: -3
source: "qrc:/qml/img/edittransaction2.png"
height: 30
fillMode: Image.PreserveAspectFit
visible: from.text !== ""
MouseArea
{
anchors.fill: parent
onClicked:
{
bc.blockChainRepeater.editTx(blockIndex, txIndex)
}
}
}
}
Rectangle {
height: 1
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
border.color: "#cccccc"
border.width: 1
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: inputParams
title: qsTr("INPUT PARAMETERS")
role: "parameters"
_data: tx
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: returnParams
title: qsTr("RETURN PARAMETERS")
role: "returnParameters"
_data: tx
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: accounts
title: qsTr("ACCOUNTS")
role: "accounts"
_data: currentState
}
KeyValuePanel
{
height: 150
width: parent.width - 30
anchors.horizontalCenter: parent.horizontalCenter
id: events
title: qsTr("EVENTS")
function computeData()
{
model.clear()
var ret = []
for (var k in tx.logs)
{
var param = ""
for (var p in tx.logs[k].param)
{
param += " " + tx.logs[k].param[p].value + " "
}
param = "(" + param + ")"
model.append({ "key": tx.logs[k].name, "value": param })
}
}
}
}
}

5
mix/res.qrc

@ -90,5 +90,10 @@
<file>qml/img/saveicon@2x.png</file> <file>qml/img/saveicon@2x.png</file>
<file>qml/img/sendtransactionicon.png</file> <file>qml/img/sendtransactionicon.png</file>
<file>qml/img/sendtransactionicon@2x.png</file> <file>qml/img/sendtransactionicon@2x.png</file>
<file>qml/img/edittransaction@2x.png</file>
<file>qml/img/newblock@2x.png</file>
<file>qml/img/edittransaction2@2x.png</file>
<file>qml/img/edittransaction.png</file>
<file>qml/img/edittransaction2.png</file>
</qresource> </qresource>
</RCC> </RCC>

148
test/libdevcore/RangeMask.cpp

@ -0,0 +1,148 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file RangeMask.cpp
* @author Christian <c@ethdev.com>
* @date 2015
*/
#include <libdevcore/RangeMask.h>
#include "../TestHelper.h"
using namespace std;
using namespace dev;
namespace dev
{
namespace test
{
BOOST_AUTO_TEST_SUITE(RangeMaskTest)
BOOST_AUTO_TEST_CASE(constructor)
{
using RM = RangeMask<unsigned>;
using Range = pair<unsigned, unsigned>;
for (RM r: {RM(), RM(1, 10), RM(Range(2, 10))})
{
BOOST_CHECK(r.empty());
BOOST_CHECK(!r.contains(0));
BOOST_CHECK(!r.contains(1));
BOOST_CHECK_EQUAL(0, r.size());
}
BOOST_CHECK(RM().full());
BOOST_CHECK(!RM(1, 10).full());
BOOST_CHECK(!RM(Range(2, 10)).full());
}
BOOST_AUTO_TEST_CASE(simple_unions)
{
using RM = RangeMask<unsigned>;
using Range = pair<unsigned, unsigned>;
RM m(Range(0, 2000));
m.unionWith(Range(1, 2));
BOOST_CHECK_EQUAL(m.size(), 1);
m.unionWith(Range(50, 250));
BOOST_CHECK_EQUAL(m.size(), 201);
m.unionWith(Range(10, 16));
BOOST_CHECK_EQUAL(m.size(), 207);
BOOST_CHECK(m.contains(1));
BOOST_CHECK(m.contains(11));
BOOST_CHECK(m.contains(51));
BOOST_CHECK(m.contains(200));
BOOST_CHECK(!m.contains(2));
BOOST_CHECK(!m.contains(7));
BOOST_CHECK(!m.contains(17));
BOOST_CHECK(!m.contains(258));
}
BOOST_AUTO_TEST_CASE(empty_union)
{
using RM = RangeMask<unsigned>;
using Range = pair<unsigned, unsigned>;
RM m(Range(0, 2000));
m.unionWith(Range(3, 6));
BOOST_CHECK_EQUAL(m.size(), 3);
m.unionWith(Range(50, 50));
BOOST_CHECK_EQUAL(m.size(), 3);
m.unionWith(Range(0, 0));
BOOST_CHECK_EQUAL(m.size(), 3);
m.unionWith(Range(1, 1));
BOOST_CHECK_EQUAL(m.size(), 3);
m.unionWith(Range(2, 2));
BOOST_CHECK_EQUAL(m.size(), 3);
m.unionWith(Range(3, 3));
BOOST_CHECK_EQUAL(m.size(), 3);
}
BOOST_AUTO_TEST_CASE(overlapping_unions)
{
using RM = RangeMask<unsigned>;
using Range = pair<unsigned, unsigned>;
RM m(Range(0, 2000));
m.unionWith(Range(10, 20));
BOOST_CHECK_EQUAL(10, m.size());
m.unionWith(Range(30, 40));
BOOST_CHECK_EQUAL(20, m.size());
m.unionWith(Range(15, 30));
BOOST_CHECK_EQUAL(40 - 10, m.size());
m.unionWith(Range(50, 60));
m.unionWith(Range(45, 55));
// [40, 45) still missing here
BOOST_CHECK_EQUAL(60 - 10 - 5, m.size());
m.unionWith(Range(15, 56));
BOOST_CHECK_EQUAL(60 - 10, m.size());
m.unionWith(Range(15, 65));
BOOST_CHECK_EQUAL(65 - 10, m.size());
m.unionWith(Range(5, 70));
BOOST_CHECK_EQUAL(70 - 5, m.size());
}
BOOST_AUTO_TEST_CASE(complement)
{
using RM = RangeMask<unsigned>;
using Range = pair<unsigned, unsigned>;
RM m(Range(0, 2000));
m.unionWith(7).unionWith(9);
m = ~m;
m.unionWith(7).unionWith(9);
m = ~m;
BOOST_CHECK(m.empty());
m += Range(0, 10);
m += Range(1000, 2000);
m.invert();
BOOST_CHECK_EQUAL(m.size(), 1000 - 10);
}
BOOST_AUTO_TEST_CASE(iterator)
{
using RM = RangeMask<unsigned>;
using Range = pair<unsigned, unsigned>;
RM m(Range(0, 2000));
m.unionWith(Range(7, 9));
m.unionWith(11);
m.unionWith(Range(200, 205));
vector<unsigned> elements;
copy(m.begin(), m.end(), back_inserter(elements));
BOOST_CHECK(elements == (vector<unsigned>{7, 8, 11, 200, 201, 202, 203, 204}));
}
BOOST_AUTO_TEST_SUITE_END()
}
}

5
test/libethereum/gaspricer.cpp

@ -20,10 +20,9 @@
*/ */
#include <libtestutils/BlockChainLoader.h> #include <libtestutils/BlockChainLoader.h>
#include <libethereum/State.h>
#include <libethereum/BlockChain.h> #include <libethereum/BlockChain.h>
#include <libethereum/Client.h> #include <libethereum/GasPricer.h>
#include <libdevcore/TransientDirectory.h> #include <libethereum/BasicGasPricer.h>
#include "../TestHelper.h" #include "../TestHelper.h"
using namespace std; using namespace std;

64
test/libethereum/transactionqueue.cpp

@ -0,0 +1,64 @@
/*
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 transactionqueue.cpp
* @author Christoph Jentzsch <cj@ethdev.com>
* @date 2015
* TransactionQueue test functions.
*/
#include <libethereum/TransactionQueue.h>
#include "../TestHelper.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
BOOST_AUTO_TEST_SUITE(TransactionQueue)
BOOST_AUTO_TEST_CASE(maxNonce)
{
dev::eth::TransactionQueue txq;
// from a94f5374fce5edbc8e2a8697c15331677e6ebf0b
const u256 gasCost = 10 * szabo;
const u256 gas = 25000;
Address dest = Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87");
Address to = Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
Secret sec = Secret("0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8");
Transaction tx0(0, gasCost, gas, dest, bytes(), 0, sec );
Transaction tx0_1(1, gasCost, gas, dest, bytes(), 0, sec );
Transaction tx1(0, gasCost, gas, dest, bytes(), 1, sec );
Transaction tx2(0, gasCost, gas, dest, bytes(), 2, sec );
Transaction tx9(0, gasCost, gas, dest, bytes(), 9, sec );
txq.import(tx0);
BOOST_CHECK(1 == txq.maxNonce(to));
txq.import(tx0);
BOOST_CHECK(1 == txq.maxNonce(to));
txq.import(tx0_1);
BOOST_CHECK(1 == txq.maxNonce(to));
txq.import(tx1);
BOOST_CHECK(2 == txq.maxNonce(to));
txq.import(tx9);
BOOST_CHECK(10 == txq.maxNonce(to));
txq.import(tx2);
BOOST_CHECK(10 == txq.maxNonce(to));
}
BOOST_AUTO_TEST_SUITE_END()

24
test/libweb3jsonrpc/webthreestubclient.h

@ -166,43 +166,43 @@ class WebThreeStubClient : public jsonrpc::Client
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
std::string eth_getBlockTransactionCountByHash(const std::string& param1) throw (jsonrpc::JsonRpcException) Json::Value eth_getBlockTransactionCountByHash(const std::string& param1) throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;
p.append(param1); p.append(param1);
Json::Value result = this->CallMethod("eth_getBlockTransactionCountByHash",p); Json::Value result = this->CallMethod("eth_getBlockTransactionCountByHash",p);
if (result.isString()) if (result.isObject())
return result.asString(); return result;
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
std::string eth_getBlockTransactionCountByNumber(const std::string& param1) throw (jsonrpc::JsonRpcException) Json::Value eth_getBlockTransactionCountByNumber(const std::string& param1) throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;
p.append(param1); p.append(param1);
Json::Value result = this->CallMethod("eth_getBlockTransactionCountByNumber",p); Json::Value result = this->CallMethod("eth_getBlockTransactionCountByNumber",p);
if (result.isString()) if (result.isObject())
return result.asString(); return result;
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
std::string eth_getUncleCountByBlockHash(const std::string& param1) throw (jsonrpc::JsonRpcException) Json::Value eth_getUncleCountByBlockHash(const std::string& param1) throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;
p.append(param1); p.append(param1);
Json::Value result = this->CallMethod("eth_getUncleCountByBlockHash",p); Json::Value result = this->CallMethod("eth_getUncleCountByBlockHash",p);
if (result.isString()) if (result.isObject())
return result.asString(); return result;
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
std::string eth_getUncleCountByBlockNumber(const std::string& param1) throw (jsonrpc::JsonRpcException) Json::Value eth_getUncleCountByBlockNumber(const std::string& param1) throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;
p.append(param1); p.append(param1);
Json::Value result = this->CallMethod("eth_getUncleCountByBlockNumber",p); Json::Value result = this->CallMethod("eth_getUncleCountByBlockNumber",p);
if (result.isString()) if (result.isObject())
return result.asString(); return result;
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }

8
test/libwhisper/bloomFilter.cpp

@ -28,7 +28,7 @@ using namespace dev;
using namespace dev::shh; using namespace dev::shh;
using TopicBloomFilterShort = TopicBloomFilterBase<4>; using TopicBloomFilterShort = TopicBloomFilterBase<4>;
using TopicBloomFilterTest = TopicBloomFilterBase<c_topicBloomFilterSize>; using TopicBloomFilterTest = TopicBloomFilterBase<TopicBloomFilterSize>;
void testAddNonExisting(TopicBloomFilterShort& _f, AbridgedTopic const& _h) void testAddNonExisting(TopicBloomFilterShort& _f, AbridgedTopic const& _h)
{ {
@ -61,7 +61,7 @@ void testRemoveExistingBloom(TopicBloomFilterShort& _f, AbridgedTopic const& _h)
double calculateExpected(TopicBloomFilterTest const& f, int n) double calculateExpected(TopicBloomFilterTest const& f, int n)
{ {
int const m = f.size * 8; // number of bits in the bloom int const m = f.size * 8; // number of bits in the bloom
int const k = f.BitsPerBloom; // number of hash functions (e.g. bits set to 1 in every bloom) int const k = BitsPerBloom; // number of hash functions (e.g. bits set to 1 in every bloom)
double singleBitSet = 1.0 / m; // probability of any bit being set after inserting a single bit double singleBitSet = 1.0 / m; // probability of any bit being set after inserting a single bit
double singleBitNotSet = (1.0 - singleBitSet); double singleBitNotSet = (1.0 - singleBitSet);
@ -256,7 +256,7 @@ void updateDistribution(FixedHash<DistributionTestSize> const& _h, array<unsigne
if (_h[i] & c_powerOfTwoBitMmask[j]) if (_h[i] & c_powerOfTwoBitMmask[j])
{ {
_distribution[i * 8 + j]++; _distribution[i * 8 + j]++;
if (++bits >= TopicBloomFilterTest::BitsPerBloom) if (++bits >= BitsPerBloom)
return; return;
} }
} }
@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE(distributionRate)
for (unsigned i = 0; i < 22000; ++i) for (unsigned i = 0; i < 22000; ++i)
{ {
x = sha3(x); x = sha3(x);
FixedHash<DistributionTestSize> h = x.template bloomPart<TopicBloomFilterTest::BitsPerBloom, DistributionTestSize>(); FixedHash<DistributionTestSize> h = x.template bloomPart<BitsPerBloom, DistributionTestSize>();
updateDistribution(h, distribution); updateDistribution(h, distribution);
} }

Loading…
Cancel
Save