Browse Source

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

Conflicts:
	mix/ClientModel.cpp
cl-refactor
yann300 10 years ago
parent
commit
4482ca02cf
  1. 24
      CMakeLists.txt
  2. 7
      abi/CMakeLists.txt
  3. 6
      alethzero/DappLoader.cpp
  4. 74
      alethzero/Main.ui
  5. 12
      alethzero/MainWin.cpp
  6. 12
      cmake/EthExecutableHelper.cmake
  7. 7
      eth/CMakeLists.txt
  8. 7
      eth/main.cpp
  9. 6
      ethminer/CMakeLists.txt
  10. 3
      ethminer/main.cpp
  11. 138
      exp/main.cpp
  12. 14
      libdevcore/Common.cpp
  13. 16
      libdevcore/Common.h
  14. 20
      libdevcore/Guards.h
  15. 45
      libdevcore/Worker.cpp
  16. 14
      libdevcrypto/Common.cpp
  17. 13
      libdevcrypto/Common.h
  18. 4
      libdevcrypto/CryptoPP.cpp
  19. 34
      libethash-cl/ethash_cl_miner.cpp
  20. 7
      libethash-cl/ethash_cl_miner.h
  21. 2
      libethcore/CommonJS.cpp
  22. 8
      libethcore/CommonJS.h
  23. 6
      libethcore/Ethash.cpp
  24. 1
      libethcore/EthashAux.cpp
  25. 29
      libethereum/BlockChain.cpp
  26. 56
      libethereum/Client.cpp
  27. 2
      libethereum/CommonNet.h
  28. 51
      libethereum/EthereumHost.cpp
  29. 4
      libethereum/EthereumHost.h
  30. 48
      libethereum/EthereumPeer.cpp
  31. 2
      libethereum/EthereumPeer.h
  32. 2
      libethereum/Farm.h
  33. 104
      libevmasm/GasMeter.cpp
  34. 67
      libevmasm/GasMeter.h
  35. 28
      libp2p/Common.cpp
  36. 13
      libp2p/Common.h
  37. 120
      libp2p/Host.cpp
  38. 7
      libp2p/Host.h
  39. 2
      libp2p/Network.cpp
  40. 134
      libp2p/NodeTable.cpp
  41. 127
      libp2p/NodeTable.h
  42. 4
      libp2p/UDP.h
  43. 9
      libsolidity/ASTPrinter.cpp
  44. 8
      libsolidity/ASTPrinter.h
  45. 44
      libsolidity/ASTVisitor.h
  46. 110
      libsolidity/StructuralGasEstimator.cpp
  47. 62
      libsolidity/StructuralGasEstimator.h
  48. 4
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  49. 5
      libwebthree/WebThree.cpp
  50. 5
      libwebthree/WebThree.h
  51. 26
      mix/ClientModel.cpp
  52. 8
      mix/ClientModel.h
  53. 2
      mix/QBigInt.h
  54. 6
      mix/Web3Server.cpp
  55. 100
      mix/qml/DeploymentDialog.qml
  56. 4
      mix/qml/Ether.qml
  57. 177
      mix/qml/js/NetworkDeployment.js
  58. 2
      mix/qml/js/TransactionHelper.js
  59. 6
      rlp/CMakeLists.txt
  60. 6
      solc/CMakeLists.txt
  61. 18
      solc/CommandLineInterface.cpp
  62. 98
      test/GasMeter.cpp
  63. 10
      test/TestHelper.cpp
  64. 2
      test/TestHelper.h
  65. 4
      test/libdevcrypto/crypto.cpp
  66. 4060
      test/libethereum/BlockTestsFiller/bcWalletTestFiller.json
  67. 90
      test/libethereum/StateTestsFiller/stCallCreateCallCodeTestFiller.json
  68. 160
      test/libethereum/StateTestsFiller/stSolidityTestFiller.json
  69. 42
      test/libethereum/StateTestsFiller/stSpecialTestFiller.json
  70. 1289
      test/libethereum/StateTestsFiller/stWalletTestFiller.json
  71. 5
      test/libethereum/blockchain.cpp
  72. 13
      test/libethereum/state.cpp
  73. 38
      test/libp2p/net.cpp
  74. 8
      test/libp2p/peer.cpp

24
CMakeLists.txt

@ -389,23 +389,37 @@ endif()
if (WIN32)
# packaging stuff
include(InstallRequiredSystemLibraries)
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "ethereum")
set(CPACK_PACKAGE_NAME "Ethereum")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ethereum")
set(CPACK_PACKAGE_VENDOR "ethereum.org")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION "0.7")
set(CPACK_PACKAGE_VERSION "0.9")
set(CPACK_GENERATOR "NSIS")
# seems to be not working
# set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp")
# our stuff
set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications")
set(CPACK_COMPONENT_THIRD_GROUP "Applications")
set(CPACK_COMPONENT_MIX_GROUP "Applications")
set(CPACK_COMPONENTS_ALL alethzero third mix)
set(CPACK_COMPONENT_SOLC_GROUP "CLI")
set(CPACK_COMPONENT_ETH_GROUP "CLI")
set(CPACK_COMPONENT_ETHMINER_GROUP "CLI")
set(CPACK_COMPONENT_RLP_GROUP "CLI")
set(CPACK_COMPONENT_ABI_GROUP "CLI")
set(CPACK_COMPONENTS_ALL alethzero mix solc eth ethminer rlp abi)
# nsis specific stuff
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ethereum")
if (CMAKE_CL_64)
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION} (Win64)")
else ()
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
endif()
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} Ethereum")
set(CPACK_NSIS_HELP_LINK "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_CONTACT "ethereum.org")

7
abi/CMakeLists.txt

@ -12,5 +12,8 @@ add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum)
install( TARGETS ${EXECUTABLE} DESTINATION bin)
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

6
alethzero/DappLoader.cpp

@ -69,7 +69,11 @@ DappLocation DappLoader::resolveAppUri(QString const& _uri)
string32 name = ZeroString32;
QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
if (address != m_nameReg)
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
else
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("register(bytes32)", name)).output);
domainParts.append(parts[partIndex]);
if (!address)
{

74
alethzero/Main.ui

@ -256,6 +256,19 @@
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="1">
<widget class="QLineEdit" name="listenIP">
<property name="inputMask">
<string/>
</property>
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
@ -266,16 +279,6 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="port">
<property name="minimum">
@ -289,20 +292,21 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="listenIP">
<property name="inputMask">
<string/>
</property>
<item row="3" column="3">
<widget class="QLabel" name="label_2">
<property name="text">
<string/>
<string>Public IP</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLineEdit" name="forcePublicIP">
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="0" column="0">
<item row="0" column="3">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Ideal &amp;Peers</string>
@ -312,21 +316,7 @@
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="forcePublicIP">
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Public IP</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Client Name</string>
@ -336,13 +326,30 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="0" column="4">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="5">
<widget class="QLineEdit" name="enode">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -1751,7 +1758,6 @@ font-size: 14pt</string>
<tabstop>verbosity</tabstop>
<tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop>
<tabstop>idealPeers</tabstop>
<tabstop>listenIP</tabstop>
<tabstop>port</tabstop>
<tabstop>transactionQueue</tabstop>

12
alethzero/MainWin.cpp

@ -143,10 +143,6 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s));
};
#if !ETH_FATDB
delete ui->dockWidget_accounts;
#endif
#if ETH_DEBUG
m_servers.append("127.0.0.1:30300");
#endif
@ -203,6 +199,9 @@ Main::Main(QWidget *parent) :
// QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page);
readSettings();
#if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts);
#endif
installWatches();
startTimer(100);
@ -1372,6 +1371,8 @@ void Main::on_transactionQueue_currentItemChanged()
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
else
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
s << "<div>Gas Used: <b>" << receipt.gasUsed() << "</b></div>";
s << "<div>End State: <b>" << receipt.stateRoot().abridged() << "</b></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
@ -1565,6 +1566,8 @@ void Main::on_blocks_currentItemChanged()
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
else
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
s << "<div>Gas Used: <b>" << receipt.gasUsed() << "</b></div>";
s << "<div>End State: <b>" << receipt.stateRoot().abridged() << "</b></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
@ -1775,6 +1778,7 @@ void Main::on_net_triggered()
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
ui->enode->setText(QString::fromStdString(web3()->enode()));
}
else
{

12
cmake/EthExecutableHelper.cmake

@ -94,6 +94,7 @@ macro(eth_install_executable EXECUTABLE)
# This tool and next will inspect linked libraries in order to determine which dependencies are required
if (${CMAKE_CFG_INTDIR} STREQUAL ".")
# TODO: This should only happen for GUI application
set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTABLE}.app")
else ()
set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app")
@ -126,8 +127,15 @@ macro(eth_install_executable EXECUTABLE)
eth_copy_dlls(${EXECUTABLE} ${dll})
endforeach(dll)
install( TARGETS ${EXECUTABLE} RUNTIME
DESTINATION bin
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Debug"
DESTINATION .
CONFIGURATIONS Debug
COMPONENT ${EXECUTABLE}
)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Release"
DESTINATION .
CONFIGURATIONS Release
COMPONENT ${EXECUTABLE}
)

7
eth/CMakeLists.txt

@ -37,5 +37,8 @@ if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin )
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

7
eth/main.cpp

@ -317,8 +317,9 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u
innerMean += rate;
}
f.stop();
innerMean /= (_trials - 2);
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl;
cout << "inner mean: " << innerMean << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
@ -407,6 +408,7 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
int main(int argc, char** argv)
{
#if 0
cout << "\x1b[30mEthBlack\x1b[0m" << endl;
cout << "\x1b[90mEthCoal\x1b[0m" << endl;
cout << "\x1b[37mEthGray\x1b[0m" << endl;
@ -472,7 +474,7 @@ int main(int argc, char** argv)
cout << "\x1b[4;35mEthPurpleU\x1b[0m" << endl;
cout << "\x1b[4;36mEthCyanU\x1b[0m" << endl;
cout << "\x1b[4;37mEthWhiteU\x1b[0m" << endl;
#endif
// Init defaults
Defaults::get();
@ -1051,6 +1053,7 @@ int main(int argc, char** argv)
cout << "Transaction Signer: " << sigKey.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl;
if (bootstrap)
web3.addNode(p2p::NodeId(), Host::pocHost());

6
ethminer/CMakeLists.txt

@ -37,5 +37,9 @@ if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin )
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

3
ethminer/main.cpp

@ -188,8 +188,9 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u
innerMean += rate;
}
f.stop();
innerMean /= (_trials - 2);
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl;
cout << "inner mean: " << innerMean << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE

138
exp/main.cpp

@ -33,6 +33,7 @@
#endif
#include <functional>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
@ -43,6 +44,7 @@
#include <libdevcrypto/TrieDB.h>
#include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libdevcrypto/FileSystem.h>
#include <libethereum/All.h>
#include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h>
@ -58,8 +60,142 @@ using namespace dev::eth;
using namespace dev::p2p;
using namespace dev::shh;
namespace js = json_spirit;
namespace fs = boost::filesystem;
#if 0
#if 1
inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); }
class KeyManager: public Worker
{
public:
KeyManager() { readKeys(); }
~KeyManager() {}
Secret secret(h128 const& _uuid, function<std::string()> const& _pass)
{
auto rit = m_ready.find(_uuid);
if (rit != m_ready.end())
return rit->second;
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return Secret();
Secret ret(decrypt(it->second, _pass()));
if (ret)
m_ready[_uuid] = ret;
return ret;
}
h128 create(std::string const& _pass)
{
auto s = Secret::random();
h128 r(sha3(s));
m_ready[r] = s;
m_keys[r] = encrypt(s.asBytes(), _pass);
return r;
}
private:
void writeKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
(void)_keysPath;
}
void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
fs::path p(_keysPath);
js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path()))
{
cdebug << "Reading" << it->path();
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type)
{
js::mObject o = v.get_obj();
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
if (version == 2)
m_keys[fromUUID(o["id"].get_str())] = o["crypto"];
else
cwarn << "Cannot read key version" << version;
}
else
cwarn << "Invalid JSON in key file" << it->path().string();
}
}
static js::mValue encrypt(bytes const& _v, std::string const& _pass)
{
(void)_v;
(void)_pass;
return js::mValue();
}
static bytes decrypt(js::mValue const& _v, std::string const& _pass)
{
js::mObject o = _v.get_obj();
// derive key
bytes derivedKey;
if (o["kdf"].get_str() == "pbkdf2")
{
auto params = o["kdfparams"].get_obj();
if (params["prf"].get_str() != "hmac-sha256")
{
cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported.";
return bytes();
}
unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str());
derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int());
}
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
}
bytes cipherText = fromHex(o["ciphertext"].get_str());
// check MAC
h256 mac(o["mac"].get_str());
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
// decrypt
bytes ret;
if (o["cipher"].get_str() == "aes-128-cbc")
{
auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str());
decryptSymNoAuth(key, iv, &cipherText, ret);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes();
}
return ret;
}
mutable std::map<h128, Secret> m_ready;
std::map<h128, js::mValue> m_keys;
};
int main()
{
cdebug << toHex(pbkdf2("password", asBytes("salt"), 1, 20));
KeyManager keyman;
cdebug << "Secret key for 0498f19a-59db-4d54-ac95-33901b4f1870 is " << keyman.secret(fromUUID("0498f19a-59db-4d54-ac95-33901b4f1870"), [](){ return "foo"; });
}
#elif 0
int main()
{
DownloadMan man;

14
libdevcore/Common.cpp

@ -28,7 +28,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.9.14";
char const* Version = "0.9.15o";
void HasInvariants::checkInvariants() const
{
@ -36,9 +36,19 @@ void HasInvariants::checkInvariants() const
BOOST_THROW_EXCEPTION(FailedInvariant());
}
struct TimerChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
#ifdef _WIN32
const char* TimerChannel::name() { return EthRed " ! "; }
#else
const char* TimerChannel::name() { return EthRed ""; }
#endif
TimerHelper::~TimerHelper()
{
cdebug << "Timer" << id << t.elapsed() << "s";
auto e = m_t.elapsed();
if (!m_ms || e * 1000 > m_ms)
clog(TimerChannel) << m_id << e << "s";
}
}

16
libdevcore/Common.h

@ -169,15 +169,17 @@ private:
#define DEV_INVARIANT_CHECK (void)0;
#endif
/// Simple scope-based timer helper.
class TimerHelper
{
public:
TimerHelper(char const* _id): id(_id) {}
TimerHelper(char const* _id, unsigned _msReportWhenGreater = 0): m_id(_id), m_ms(_msReportWhenGreater) {}
~TimerHelper();
private:
boost::timer t;
char const* id;
boost::timer m_t;
char const* m_id;
unsigned m_ms;
};
#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(#S, true); __eth_t.second; __eth_t.second = false)
@ -188,6 +190,14 @@ private:
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__)
#endif
#define DEV_TIMED_IF(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE_IF(S) ::dev::TimerHelper __eth_t(S, MS)
#if WIN32
#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__FUNCSIG__, MS)
#else
#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__PRETTY_FUNCTION__, MS)
#endif
enum class WithExisting: int
{
Trust = 0,

20
libdevcore/Guards.h

@ -81,9 +81,9 @@ using SpinGuard = std::lock_guard<SpinLock>;
* Mutex m;
* unsigned d;
* ...
* ETH_GUARDED(m) d = 1;
* ETH_(m) d = 1;
* ...
* ETH_GUARDED(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; }
* ETH_(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; }
* @endcode
*
* There are several variants of this basic mechanism for different Mutex types and Guards.
@ -95,7 +95,7 @@ using SpinGuard = std::lock_guard<SpinLock>;
* Mutex m;
* int d;
* ...
* ETH_GUARDED(m)
* ETH_(m)
* {
* for (auto d = 50; d > 25; --d)
* foo(d);
@ -107,19 +107,19 @@ using SpinGuard = std::lock_guard<SpinLock>;
* @endcode
*/
#define ETH_GUARDED(MUTEX) \
#define DEV_GUARDED(MUTEX) \
for (GenericGuardBool<Guard, Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_READ_GUARDED(MUTEX) \
#define DEV_READ_GUARDED(MUTEX) \
for (GenericGuardBool<ReadGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_WRITE_GUARDED(MUTEX) \
#define DEV_WRITE_GUARDED(MUTEX) \
for (GenericGuardBool<WriteGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_RECURSIVE_GUARDED(MUTEX) \
#define DEV_RECURSIVE_GUARDED(MUTEX) \
for (GenericGuardBool<RecursiveGuard, RecursiveMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_UNGUARDED(MUTEX) \
#define DEV_UNGUARDED(MUTEX) \
for (GenericUnguardBool<Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_READ_UNGUARDED(MUTEX) \
#define DEV_READ_UNGUARDED(MUTEX) \
for (GenericUnguardSharedBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_WRITE_UNGUARDED(MUTEX) \
#define DEV_WRITE_UNGUARDED(MUTEX) \
for (GenericUnguardBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
}

45
libdevcore/Worker.cpp

@ -29,7 +29,7 @@ using namespace dev;
void Worker::startWorking()
{
cnote << "startWorking for thread" << m_name;
// cnote << "startWorking for thread" << m_name;
Guard l(x_work);
if (m_work)
{
@ -42,65 +42,66 @@ void Worker::startWorking()
m_work.reset(new thread([&]()
{
setThreadName(m_name.c_str());
cnote << "Thread begins";
// cnote << "Thread begins";
while (m_state != WorkerState::Killing)
{
WorkerState ex = WorkerState::Starting;
bool ok = m_state.compare_exchange_strong(ex, WorkerState::Started);
cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; " << ok;
// cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; " << ok;
(void)ok;
startedWorking();
cnote << "Entering work loop...";
// cnote << "Entering work loop...";
workLoop();
cnote << "Finishing up worker thread...";
// cnote << "Finishing up worker thread...";
doneWorking();
// ex = WorkerState::Stopping;
// m_state.compare_exchange_strong(ex, WorkerState::Stopped);
ex = m_state.exchange(WorkerState::Stopped);
cnote << "State: Stopped: Thread was" << (unsigned)ex;
// cnote << "State: Stopped: Thread was" << (unsigned)ex;
if (ex == WorkerState::Killing || ex == WorkerState::Starting)
m_state.exchange(ex);
cnote << "Waiting until not Stopped...";
while (m_state == WorkerState::Stopped)
this_thread::sleep_for(chrono::milliseconds(20));
// cnote << "Waiting until not Stopped...";
DEV_TIMED_IF(Worker stopping, 100)
while (m_state == WorkerState::Stopped)
this_thread::sleep_for(chrono::milliseconds(20));
}
}));
cnote << "Spawning" << m_name;
// cnote << "Spawning" << m_name;
}
cnote << "Waiting until Started...";
while (m_state != WorkerState::Started)
this_thread::sleep_for(chrono::microseconds(20));
DEV_TIMED_IF(Start worker, 100)
while (m_state != WorkerState::Started)
this_thread::sleep_for(chrono::microseconds(20));
}
void Worker::stopWorking()
{
cnote << "stopWorking for thread" << m_name;
ETH_GUARDED(x_work)
DEV_GUARDED(x_work)
if (m_work)
{
cnote << "Stopping" << m_name;
WorkerState ex = WorkerState::Started;
m_state.compare_exchange_strong(ex, WorkerState::Stopping);
cnote << "Waiting until Stopped...";
while (m_state != WorkerState::Stopped)
this_thread::sleep_for(chrono::microseconds(20));
DEV_TIMED_IF(Stop worker, 100)
while (m_state != WorkerState::Stopped)
this_thread::sleep_for(chrono::microseconds(20));
}
}
void Worker::terminate()
{
// cnote << "stopWorking for thread" << m_name;
ETH_GUARDED(x_work)
DEV_GUARDED(x_work)
if (m_work)
{
cnote << "Terminating" << m_name;
m_state.exchange(WorkerState::Killing);
m_work->join();
DEV_TIMED_IF(Terminate worker, 100)
m_work->join();
m_work.reset();
}
}

14
libdevcrypto/Common.cpp

@ -112,13 +112,13 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
return decrypt(_k, _cipher, o_plain);
}
h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher)
{
h128 iv(Nonce::get());
return encryptSymNoAuth(_k, _plain, o_cipher, iv);
}
h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
{
o_cipher.resize(_plain.size());
@ -139,7 +139,7 @@ h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_ciph
}
}
bool dev::decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
bool dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
{
o_plaintext.resize(_cipher.size());
@ -175,6 +175,14 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
return s_secp256k1.verify(_p, _s, _hash.ref(), true);
}
bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen)
{
bytes ret(_dkLen);
PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
pbkdf.DeriveKey(ret.data(), ret.size(), 0, (byte*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _iterations);
return ret;
}
KeyPair KeyPair::create()
{
static boost::thread_specific_ptr<mt19937_64> s_eng;

13
libdevcrypto/Common.h

@ -103,13 +103,13 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher);
h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv);
h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv);
/// Decrypts payload with specified IV/ctr.
bool decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext);
/// Decrypts payload with specified IV/ctr using AES128-CTR.
bool decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext);
/// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash);
@ -120,6 +120,9 @@ Signature sign(Secret const& _k, h256 const& _hash);
/// Verify signature.
bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Derive key via PBKDF2.
bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32);
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).
@ -164,7 +167,7 @@ struct InvalidState: public dev::Exception {};
/// Key derivation
h256 kdf(Secret const& _priv, h256 const& _hash);
/**
* @brief Generator for nonce material
*/

4
libdevcrypto/CryptoPP.cpp

@ -79,7 +79,7 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher)
ctx.Final(mKey.data());
bytes cipherText;
encryptSymNoAuth(*(Secret*)eKey.data(), bytesConstRef(&io_cipher), cipherText, h128());
encryptSymNoAuth(h128(eKey), bytesConstRef(&io_cipher), cipherText, h128());
if (cipherText.empty())
return;
@ -139,7 +139,7 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text)
if (mac[i] != msgMac[i])
return false;
decryptSymNoAuth(*(Secret*)eKey.data(), iv, cipherNoIV, plain);
decryptSymNoAuth(h128(eKey), iv, cipherNoIV, plain);
io_text.resize(plain.size());
io_text.swap(plain);

34
libethash-cl/ethash_cl_miner.cpp

@ -88,6 +88,13 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic
return "{ \"platform\": \"" + platforms[platform_num].getInfo<CL_PLATFORM_NAME>() + "\", \"device\": \"" + device.getInfo<CL_DEVICE_NAME>() + "\", \"version\": \"" + device_version + "\" }";
}
unsigned ethash_cl_miner::get_num_platforms()
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
return platforms.size();
}
unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
{
std::vector<cl::Platform> platforms;
@ -117,14 +124,11 @@ void ethash_cl_miner::finish()
}
}
bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*)> _fillDAG, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
{
// store params
m_params = params;
// get all platforms
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
cout << "No OpenCL platforms found." << endl;
@ -137,10 +141,10 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
cout << "Using platform: " << platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str() << endl;
// get GPU device of the default platform
std::vector<cl::Device> devices;
// get GPU device of the default platform
std::vector<cl::Device> devices;
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
if (devices.empty())
{
cout << "No OpenCL devices found." << endl;
return false;
@ -171,7 +175,7 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
// patch source code
std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
add_definition(code, "GROUP_SIZE", m_workgroup_size);
add_definition(code, "DAG_SIZE", (unsigned)(params.full_size / ETHASH_MIX_BYTES));
add_definition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES));
add_definition(code, "ACCESSES", ETHASH_ACCESSES);
add_definition(code, "MAX_OUTPUTS", c_max_search_results);
//debugf("%s", code.c_str());
@ -194,18 +198,20 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
m_search_kernel = cl::Kernel(program, "ethash_search");
// create buffer for dag
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size);
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize);
// create buffer for header
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
// compute dag on CPU
{
m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag);
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size);
// void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize);
// memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap.
_fillDAG(dag_ptr);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
// _fillDAG(dag_ptr);
// m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
}
// create mining buffers

7
libethash-cl/ethash_cl_miner.h

@ -31,11 +31,11 @@ public:
public:
ethash_cl_miner();
bool init(ethash_params const& params, std::function<void(void*)> _fillDAG, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
static unsigned get_num_platforms();
static unsigned get_num_devices(unsigned _platformId = 0);
static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
void finish();
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
void search(uint8_t const* header, uint64_t target, search_hook& hook);
@ -43,7 +43,6 @@ public:
private:
enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 };
ethash_params m_params;
cl::Context m_context;
cl::CommandQueue m_queue;
cl::Kernel m_hash_kernel;

2
libethcore/CommonJS.cpp

@ -26,6 +26,8 @@
namespace dev
{
const u256 UndefinedU256 = ~(u256)0;
Address toAddress(std::string const& _sn)
{
if (_sn.size() == 40)

8
libethcore/CommonJS.h

@ -48,14 +48,18 @@ inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev:
/// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256.
std::string prettyU256(u256 _n, bool _abridged = true);
extern const u256 UndefinedU256;
}
// ethcore
namespace dev
{
namespace eth
{
struct TransactionSkeleton
{
bool creation = false;
@ -63,8 +67,8 @@ struct TransactionSkeleton
Address to;
u256 value;
bytes data;
u256 gas;
u256 gasPrice;
u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256;
};
/// Convert to a block number, a bit like jsToInt, except that it correctly recognises "pending" and "latest".

6
libethcore/Ethash.cpp

@ -309,10 +309,10 @@ void Ethash::GPUMiner::workLoop()
delete m_miner;
m_miner = new ethash_cl_miner;
auto p = EthashAux::params(m_minerSeed);
auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); };
unsigned device = instances() > 1 ? index() : s_deviceId;
m_miner->init(p, cb, 32, s_platformId, device);
EthashAux::FullType dag = EthashAux::full(m_minerSeed);
m_miner->init(dag->data.data(), dag->data.size(), 32, s_platformId, device);
}
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);

1
libethcore/EthashAux.cpp

@ -133,7 +133,6 @@ EthashAux::LightAllocation::~LightAllocation()
ethash_delete_light(light);
}
EthashAux::FullType EthashAux::full(BlockInfo const& _header, bytesRef _dest, bool _createIfMissing)
{
return full(_header.seedHash(), _dest, _createIfMissing);

29
libethereum/BlockChain.cpp

@ -474,7 +474,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
t.restart();
#endif
#if ETH_PARANOIA
#if ETH_PARANOIA || !ETH_TRUE
checkConsistency();
#endif
@ -486,29 +486,26 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// This is safe in practice since the caches don't get flushed nearly often enough to be
// done here.
details(bi.parentHash);
ETH_WRITE_GUARDED(x_details)
DEV_WRITE_GUARDED(x_details)
m_details[bi.parentHash].children.push_back(bi.hash());
#if ETH_TIMED_IMPORTS
#if ETH_TIMED_IMPORTS || !ETH_TRUE
collation = t.elapsed();
t.restart();
#endif
blocksBatch.Put(toSlice(bi.hash()), (ldb::Slice)ref(_block));
ETH_READ_GUARDED(x_details)
DEV_READ_GUARDED(x_details)
extrasBatch.Put(toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}).rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp()));
#if ETH_TIMED_IMPORTS
#if ETH_TIMED_IMPORTS || !ETH_TRUE
writing = t.elapsed();
t.restart();
#endif
#if ETH_PARANOIA
checkConsistency();
#endif
}
#if ETH_CATCH
catch (InvalidNonce const& _e)
@ -610,7 +607,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
}
clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route;
noteCanonChanged();
StructuredLogger::chainNewHead(
bi.headerHash(WithoutNonce).abridged(),
@ -627,12 +623,16 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
ETH_WRITE_GUARDED(x_lastBlockHash)
DEV_WRITE_GUARDED(x_lastBlockHash)
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
}
#if ETH_PARANOIA || !ETH_TRUE
checkConsistency();
#endif
#if ETH_TIMED_IMPORTS
checkBest = t.elapsed();
cnote << "Import took:" << total.elapsed();
@ -643,6 +643,9 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
cnote << "checkBest:" << checkBest;
#endif
if (!route.empty())
noteCanonChanged();
if (isKnown(bi.hash()) && !details(bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
@ -978,7 +981,7 @@ bool BlockChain::isKnown(h256 const& _hash) const
if (_hash == m_genesisHash)
return true;
ETH_READ_GUARDED(x_blocks)
DEV_READ_GUARDED(x_blocks)
if (!m_blocks.count(_hash))
{
string d;
@ -986,7 +989,7 @@ bool BlockChain::isKnown(h256 const& _hash) const
if (d.empty())
return false;
}
ETH_READ_GUARDED(x_details)
DEV_READ_GUARDED(x_details)
if (!m_details.count(_hash))
{
string d;

56
libethereum/Client.cpp

@ -244,13 +244,13 @@ void Client::startedWorking()
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
cdebug << "startedWorking()";
ETH_WRITE_GUARDED(x_preMine)
DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
ETH_READ_GUARDED(x_preMine)
DEV_READ_GUARDED(x_preMine)
{
ETH_WRITE_GUARDED(x_working)
DEV_WRITE_GUARDED(x_working)
m_working = m_preMine;
ETH_WRITE_GUARDED(x_postMine)
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_preMine;
}
}
@ -259,13 +259,13 @@ void Client::doneWorking()
{
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
ETH_WRITE_GUARDED(x_preMine)
DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
ETH_READ_GUARDED(x_preMine)
DEV_READ_GUARDED(x_preMine)
{
ETH_WRITE_GUARDED(x_working)
DEV_WRITE_GUARDED(x_working)
m_working = m_preMine;
ETH_WRITE_GUARDED(x_postMine)
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_preMine;
}
}
@ -309,7 +309,7 @@ void Client::killChain()
void Client::clearPending()
{
h256Set changeds;
ETH_WRITE_GUARDED(x_postMine)
DEV_WRITE_GUARDED(x_postMine)
{
if (!m_postMine.pending().size())
return;
@ -317,7 +317,7 @@ void Client::clearPending()
// appendFromNewPending(m_postMine.logBloom(i), changeds);
changeds.insert(PendingChangedFilter);
m_tq.clear();
ETH_READ_GUARDED(x_preMine)
DEV_READ_GUARDED(x_preMine)
m_postMine = m_preMine;
}
@ -434,7 +434,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
{
State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
ETH_READ_GUARDED(x_postMine)
DEV_READ_GUARDED(x_postMine)
temp = m_postMine;
temp.addBalance(_from, _value + _gasPrice * _gas);
Executive e(temp, LastHashes(), 0);
@ -461,13 +461,13 @@ ProofOfWork::WorkPackage Client::getWork()
bool Client::submitWork(ProofOfWork::Solution const& _solution)
{
bytes newBlock;
DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
if (!m_working.completeMine<ProofOfWork>(_solution))
return false;
ETH_READ_GUARDED(x_working)
DEV_READ_GUARDED(x_working)
{
DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
newBlock = m_working.blockData();
}
@ -499,17 +499,17 @@ void Client::syncTransactionQueue()
h256Set changeds;
TransactionReceipts newPendingReceipts;
DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.empty())
return;
ETH_READ_GUARDED(x_working)
DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
DEV_READ_GUARDED(x_working)
DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
ETH_READ_GUARDED(x_postMine)
DEV_READ_GUARDED(x_postMine)
for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
changeds.insert(PendingChangedFilter);
@ -561,7 +561,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
bool preChanged = false;
State newPreMine;
ETH_READ_GUARDED(x_preMine)
DEV_READ_GUARDED(x_preMine)
newPreMine = m_preMine;
// TODO: use m_postMine to avoid re-evaluating our own blocks.
@ -572,11 +572,11 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (isMining())
cnote << "New block on chain.";
ETH_WRITE_GUARDED(x_preMine)
DEV_WRITE_GUARDED(x_preMine)
m_preMine = newPreMine;
DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
m_working = newPreMine;
ETH_READ_GUARDED(x_postMine)
DEV_READ_GUARDED(x_postMine)
for (auto const& t: m_postMine.pending())
{
clog(ClientNote) << "Resubmitting post-mine transaction " << t;
@ -584,7 +584,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (ir != ImportResult::Success)
onTransactionQueueReady();
}
ETH_READ_GUARDED(x_working) DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
DEV_READ_GUARDED(x_working) DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
changeds.insert(PendingChangedFilter);
@ -609,11 +609,11 @@ void Client::onPostStateChanged()
cnote << "Post state changed: Restarting mining...";
if (isMining() || remoteActive())
{
DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc);
ETH_READ_GUARDED(x_working)
DEV_READ_GUARDED(x_working)
{
DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
m_miningInfo = m_postMine.info();
}
@ -694,7 +694,7 @@ void Client::checkWatchGarbage()
{
// watches garbage collection
vector<unsigned> toUninstall;
ETH_GUARDED(x_filtersWatches)
DEV_GUARDED(x_filtersWatches)
for (auto key: keysOf(m_watches))
if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20))
{
@ -733,7 +733,7 @@ eth::State Client::state(h256 _block) const
eth::State Client::state(unsigned _txi) const
{
ETH_READ_GUARDED(x_postMine)
DEV_READ_GUARDED(x_postMine)
return m_postMine.fromPending(_txi);
assert(false);
return State();

2
libethereum/CommonNet.h

@ -56,7 +56,7 @@ class EthereumPeer;
enum
{
StatusPacket = 0,
GetTransactionsPacket,
NewBlockHashesPacket,
TransactionsPacket,
GetBlockHashesPacket,
BlockHashesPacket,

51
libethereum/EthereumHost.cpp

@ -189,7 +189,7 @@ void EthereumHost::maintainTransactions()
for (auto const& i: ts)
{
bool unsent = !m_transactionsSent.count(i.first);
for (auto const& p: randomSelection(100, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }))
for (auto const& p: randomSelection(0, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }).second)
peerTransactions[p].push_back(i.first);
}
for (auto const& t: ts)
@ -218,28 +218,28 @@ void EthereumHost::maintainTransactions()
}
}
std::vector<std::shared_ptr<EthereumPeer>> EthereumHost::randomSelection(unsigned _percent, std::function<bool(EthereumPeer*)> const& _allow)
pair<vector<shared_ptr<EthereumPeer>>, vector<shared_ptr<EthereumPeer>>> EthereumHost::randomSelection(unsigned _percent, std::function<bool(EthereumPeer*)> const& _allow)
{
std::vector<std::shared_ptr<EthereumPeer>> candidates;
candidates.reserve(peerSessions().size());
pair<vector<shared_ptr<EthereumPeer>>, vector<shared_ptr<EthereumPeer>>> ret;
ret.second.reserve(peerSessions().size());
for (auto const& j: peerSessions())
{
auto pp = j.first->cap<EthereumPeer>();
if (_allow(pp.get()))
candidates.push_back(pp);
ret.second.push_back(pp);
}
std::vector<std::shared_ptr<EthereumPeer>> ret;
for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && candidates.size();)
ret.second.reserve((peerSessions().size() * _percent + 99) / 100);
for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && ret.second.size();)
{
unsigned n = rand() % candidates.size();
ret.push_back(std::move(candidates[n]));
candidates.erase(candidates.begin() + n);
unsigned n = rand() % ret.second.size();
ret.first.push_back(std::move(ret.second[n]));
ret.second.erase(ret.second.begin() + n);
}
return ret;
}
void EthereumHost::maintainBlocks(h256 _currentHash)
void EthereumHost::maintainBlocks(h256 const& _currentHash)
{
// Send any new blocks.
auto detailsFrom = m_chain.details(m_latestBlockSent);
@ -253,17 +253,28 @@ void EthereumHost::maintainBlocks(h256 _currentHash)
h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true));
for (auto const& p: randomSelection(100, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); }))
auto s = randomSelection(25, [&](EthereumPeer* p){ DEV_GUARDED(p->x_knownBlocks) return !p->m_knownBlocks.count(_currentHash); return false; });
for (shared_ptr<EthereumPeer> const& p: s.first)
for (auto const& b: blocks)
if (!p->m_knownBlocks.count(b))
{
RLPStream ts;
p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty);
{
RLPStream ts;
p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty);
Guard l(p->x_knownBlocks);
p->sealAndSend(ts);
p->m_knownBlocks.clear();
}
Guard l(p->x_knownBlocks);
p->sealAndSend(ts);
p->m_knownBlocks.clear();
}
for (shared_ptr<EthereumPeer> const& p: s.second)
{
RLPStream ts;
p->prep(ts, NewBlockHashesPacket, blocks.size());
for (auto const& b: blocks)
ts.append(b);
Guard l(p->x_knownBlocks);
p->sealAndSend(ts);
p->m_knownBlocks.clear();
}
}
m_latestBlockSent = _currentHash;
}

4
libethereum/EthereumHost.h

@ -80,7 +80,7 @@ public:
void noteNewBlocks() { m_newBlocks = true; }
private:
std::vector<std::shared_ptr<EthereumPeer>> randomSelection(unsigned _percent = 25, std::function<bool(EthereumPeer*)> const& _allow = [](EthereumPeer const*){ return true; });
std::pair<std::vector<std::shared_ptr<EthereumPeer>>, std::vector<std::shared_ptr<EthereumPeer>>> randomSelection(unsigned _percent = 25, std::function<bool(EthereumPeer*)> const& _allow = [](EthereumPeer const*){ return true; });
/// Session is tell us that we may need (re-)syncing with the peer.
void noteNeedsSyncing(EthereumPeer* _who);
@ -92,7 +92,7 @@ private:
void doWork();
void maintainTransactions();
void maintainBlocks(h256 _currentBlock);
void maintainBlocks(h256 const& _currentBlock);
/// Get a bunch of needed blocks.
/// Removes them from our list of needed blocks.

48
libethereum/EthereumPeer.cpp

@ -326,7 +326,6 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
transition(Asking::Nothing);
break;
}
case GetTransactionsPacket: break; // DEPRECATED.
case TransactionsPacket:
{
unsigned itemCount = _r.itemCount();
@ -560,8 +559,51 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
default:;
}
Guard l(x_knownBlocks);
m_knownBlocks.insert(h);
DEV_GUARDED(x_knownBlocks)
m_knownBlocks.insert(h);
}
break;
}
case NewBlockHashesPacket:
{
clog(NetMessageSummary) << "NewBlockHashes";
if (host()->isSyncing())
clog(NetMessageSummary) << "Ignoring since we're already downloading.";
else
{
unsigned knowns = 0;
unsigned unknowns = 0;
unsigned itemCount = _r.itemCount();
for (unsigned i = 0; i < itemCount; ++i)
{
addRating(1);
auto h = _r[i].toHash<h256>();
DEV_GUARDED(x_knownBlocks)
m_knownBlocks.insert(h);
auto status = host()->m_bq.blockStatus(h);
if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h))
knowns++;
else if (status == QueueStatus::Bad)
{
cwarn << "block hash bad!" << h << ". Bailing...";
return true;
}
else if (status == QueueStatus::Unknown)
{
unknowns++;
m_syncingNeededBlocks.push_back(h);
}
else
knowns++;
}
clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns";
if (unknowns > 0)
{
host()->m_man.resetToChain(m_syncingNeededBlocks);
host()->changeSyncer(this);
transition(Asking::Blocks);
}
return true;
}
break;
}

2
libethereum/EthereumPeer.h

@ -129,7 +129,7 @@ private:
/// This is built as we ask for hashes. Once no more hashes are given, we present this to the
/// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks.
h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer.
h256 m_syncingLastReceivedHash; ///< Hash more recently received from peer.
h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer.
h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync.

2
libethereum/Farm.h

@ -127,7 +127,7 @@ public:
*/
void resetMiningProgress()
{
ETH_READ_GUARDED(x_minerWork)
DEV_READ_GUARDED(x_minerWork)
for (auto const& i: m_miners)
i->resetHashCount();
resetTimer();

104
libevmasm/GasMeter.cpp

@ -0,0 +1,104 @@
/*
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 GasMeter.cpp
* @author Christian <c@ethdev.com>
* @date 2015
*/
#include "GasMeter.h"
#include <libevmcore/Params.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
GasMeter::GasConsumption& GasMeter::GasConsumption::operator+=(GasConsumption const& _other)
{
isInfinite = isInfinite || _other.isInfinite;
if (isInfinite)
return *this;
bigint v = bigint(value) + _other.value;
if (v > std::numeric_limits<u256>::max())
isInfinite = true;
else
value = u256(v);
return *this;
}
GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
{
switch (_item.type()) {
case Push:
case PushTag:
return runGas(Instruction::PUSH1);
case Tag:
return runGas(Instruction::JUMPDEST);
case Operation:
{
GasConsumption gas = runGas(_item.instruction());
switch (_item.instruction())
{
case Instruction::SSTORE:
// @todo logic can be improved
gas += c_sstoreSetGas;
break;
case Instruction::SLOAD:
gas += c_sloadGas;
break;
case Instruction::MSTORE:
case Instruction::MSTORE8:
case Instruction::MLOAD:
case Instruction::RETURN:
case Instruction::SHA3:
case Instruction::CALLDATACOPY:
case Instruction::CODECOPY:
case Instruction::EXTCODECOPY:
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
case Instruction::LOG3:
case Instruction::LOG4:
case Instruction::CALL:
case Instruction::CALLCODE:
case Instruction::CREATE:
case Instruction::EXP:
// @todo logic can be improved
gas = GasConsumption::infinite();
break;
default:
break;
}
return gas;
break;
}
default:
break;
}
return GasConsumption::infinite();
}
GasMeter::GasConsumption GasMeter::runGas(Instruction _instruction)
{
if (_instruction == Instruction::JUMPDEST)
return GasConsumption(1);
int tier = instructionInfo(_instruction).gasPriceTier;
return tier == InvalidTier ? GasConsumption::infinite() : c_tierStepGas[tier];
}

67
libevmasm/GasMeter.h

@ -0,0 +1,67 @@
/*
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 GasMeter.cpp
* @author Christian <c@ethdev.com>
* @date 2015
*/
#pragma once
#include <ostream>
#include <libevmasm/AssemblyItem.h>
namespace dev
{
namespace eth
{
/**
* Class that helps computing the maximum gas consumption for instructions.
*/
class GasMeter
{
public:
struct GasConsumption
{
GasConsumption(u256 _value = 0, bool _infinite = false): value(_value), isInfinite(_infinite) {}
static GasConsumption infinite() { return GasConsumption(0, true); }
GasConsumption& operator+=(GasConsumption const& _otherS);
std::ostream& operator<<(std::ostream& _str) const;
u256 value;
bool isInfinite;
};
/// Returns an upper bound on the gas consumed by the given instruction.
GasConsumption estimateMax(AssemblyItem const& _item);
private:
static GasConsumption runGas(Instruction _instruction);
};
inline std::ostream& operator<<(std::ostream& _str, GasMeter::GasConsumption const& _consumption)
{
if (_consumption.isInfinite)
return _str << "inf";
else
return _str << _consumption.value;
}
}
}

28
libp2p/Common.cpp

@ -24,8 +24,9 @@ using namespace std;
using namespace dev;
using namespace dev::p2p;
const unsigned dev::p2p::c_protocolVersion = 3;
const unsigned dev::p2p::c_protocolVersion = 4;
const unsigned dev::p2p::c_defaultIPPort = 30303;
static_assert(dev::p2p::c_protocolVersion == 4, "Replace v3 compatbility with v4 compatibility before updating network version.");
const dev::p2p::NodeIPEndpoint dev::p2p::UnspecifiedNodeIPEndpoint = NodeIPEndpoint(bi::address(), 0, 0);
const dev::p2p::Node dev::p2p::UnspecifiedNode = dev::p2p::Node(NodeId(), UnspecifiedNodeIPEndpoint);
@ -144,6 +145,31 @@ std::string p2p::reasonOf(DisconnectReason _r)
}
}
void NodeIPEndpoint::streamRLP(RLPStream& _s, RLPAppend _append) const
{
if (_append == StreamList)
_s.appendList(3);
if (address.is_v4())
_s << bytesConstRef(&address.to_v4().to_bytes()[0], 4);
else if (address.is_v6())
_s << bytesConstRef(&address.to_v6().to_bytes()[0], 16);
else
_s << bytes();
_s << udpPort << tcpPort;
}
void NodeIPEndpoint::interpretRLP(RLP const& _r)
{
if (_r[0].size() == 4)
address = bi::address_v4(*(bi::address_v4::bytes_type*)_r[0].toBytes().data());
else if (_r[0].size() == 16)
address = bi::address_v6(*(bi::address_v6::bytes_type*)_r[0].toBytes().data());
else
address = bi::address();
udpPort = _r[1].toInt<uint16_t>();
tcpPort = _r[2].toInt<uint16_t>();
}
namespace dev {
std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep)

13
libp2p/Common.h

@ -36,6 +36,7 @@
#include <libdevcrypto/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/RLP.h>
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
@ -162,10 +163,17 @@ using PeerSessionInfos = std::vector<PeerSessionInfo>;
*/
struct NodeIPEndpoint
{
enum RLPAppend
{
StreamList,
StreamInline
};
/// Setting true causes isAllowed to return true for all addresses. (Used by test fixtures)
static bool test_allowLocal;
NodeIPEndpoint(bi::address _addr, uint16_t _udp, uint16_t _tcp): address(_addr), udpPort(_udp), tcpPort(_tcp) {}
NodeIPEndpoint(RLP const& _r) { interpretRLP(_r); }
bi::address address;
uint16_t udpPort;
@ -177,11 +185,14 @@ struct NodeIPEndpoint
operator bool() const { return !address.is_unspecified() && udpPort > 0 && tcpPort > 0; }
bool isAllowed() const { return NodeIPEndpoint::test_allowLocal ? !address.is_unspecified() : isPublicAddress(address); }
void streamRLP(RLPStream& _s, RLPAppend _append = StreamList) const;
void interpretRLP(RLP const& _r);
};
struct Node
{
Node(Public _pubk, NodeIPEndpoint _ip, bool _required = false): id(_pubk), endpoint(_ip), required(_required) {}
Node(Public _pubk, NodeIPEndpoint const& _ip, bool _required = false): id(_pubk), endpoint(_ip), required(_required) {}
virtual NodeId const& address() const { return id; }
virtual Public const& publicKey() const { return id; }

120
libp2p/Host.cpp

@ -176,7 +176,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
{
// session maybe ingress or egress so m_peers and node table entries may not exist
shared_ptr<Peer> p;
ETH_RECURSIVE_GUARDED(x_sessions)
DEV_RECURSIVE_GUARDED(x_sessions)
{
if (m_peers.count(_id))
p = m_peers[_id];
@ -208,7 +208,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
// create session so disconnects are managed
auto ps = make_shared<Session>(this, _io, p, PeerSessionInfo({_id, clientVersion, _endpoint.address().to_string(), listenPort, chrono::steady_clock::duration(), _rlp[2].toSet<CapDesc>(), 0, map<string, string>()}));
if (protocolVersion != dev::p2p::c_protocolVersion)
if (protocolVersion < dev::p2p::c_protocolVersion - 1)
{
ps->disconnect(IncompatibleProtocol);
return;
@ -226,7 +226,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
return;
}
if (peerCount() > 9 * m_idealPeerCount)
if (!peerSlotsAvailable(Ingress))
{
ps->disconnect(TooManyPeers);
return;
@ -257,7 +257,7 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
if (Node n = m_nodeTable->node(_n))
{
shared_ptr<Peer> p;
ETH_RECURSIVE_GUARDED(x_sessions)
DEV_RECURSIVE_GUARDED(x_sessions)
{
if (m_peers.count(_n))
{
@ -271,7 +271,7 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
clog(NetNote) << "p2p.host.peers.events.peerAdded " << _n << p->endpoint;
}
}
if (peerCount() < m_idealPeerCount)
if (peerSlotsAvailable(Egress))
connect(p);
}
}
@ -412,8 +412,7 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
{
// create or update m_peers entry
shared_ptr<Peer> p;
ETH_RECURSIVE_GUARDED(x_sessions)
{
DEV_RECURSIVE_GUARDED(x_sessions)
if (m_peers.count(_n))
{
p = m_peers[_n];
@ -425,7 +424,6 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
p.reset(new Peer(node));
m_peers[_n] = p;
}
}
connect(p);
}
else if (m_nodeTable)
@ -438,6 +436,7 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
t->async_wait([this, _n](boost::system::error_code const& _ec)
{
if (!_ec && m_nodeTable)
// FIXME RACE CONDITION (use weak_ptr or mutex).
if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint);
});
@ -578,7 +577,11 @@ void Host::run(boost::system::error_code const&)
// is always live and to ensure reputation and fallback timers are properly
// updated. // disconnectLatePeers();
int openSlots = m_idealPeerCount - peerCount();
// todo: update peerSlotsAvailable()
unsigned pendingCount = 0;
DEV_GUARDED(x_pendingNodeConns)
pendingCount = m_pendingPeerConns.size();
int openSlots = m_idealPeerCount - peerCount() - pendingCount;
if (openSlots > 0)
{
list<shared_ptr<Peer>> toConnect;
@ -693,15 +696,16 @@ bytes Host::saveNetwork() const
int count = 0;
for (auto const& p: peers)
{
// Only save peers which have connected within 2 days, with properly-advertised port and public IP address
// todo: e2e ipv6 support
// todo: ipv6
if (!p.endpoint.address.is_v4())
continue;
if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && p.endpoint.tcpPort > 0 && p.id != id() && (p.required || p.endpoint.isAllowed()))
// Only save peers which have connected within 2 days, with properly-advertised port and public IP address
if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && !!p.endpoint && p.id != id() && (p.required || p.endpoint.isAllowed()))
{
network.appendList(10);
network << p.endpoint.address.to_v4().to_bytes() << p.endpoint.tcpPort << p.id << p.required
network.appendList(11);
p.endpoint.streamRLP(network, NodeIPEndpoint::StreamInline);
network << p.id << p.required
<< chrono::duration_cast<chrono::seconds>(p.m_lastConnected.time_since_epoch()).count()
<< chrono::duration_cast<chrono::seconds>(p.m_lastAttempted.time_since_epoch()).count()
<< p.m_failedAttempts << (unsigned)p.m_lastDisconnect << p.m_score << p.m_rating;
@ -715,12 +719,9 @@ bytes Host::saveNetwork() const
state.sort();
for (auto const& entry: state)
{
network.appendList(3);
if (entry.endpoint.address.is_v4())
network << entry.endpoint.address.to_v4().to_bytes();
else
network << entry.endpoint.address.to_v6().to_bytes();
network << entry.endpoint.tcpPort << entry.id;
network.appendList(4);
entry.endpoint.streamRLP(network, NodeIPEndpoint::StreamInline);
network << entry.id;
count++;
}
}
@ -736,6 +737,9 @@ bytes Host::saveNetwork() const
void Host::restoreNetwork(bytesConstRef _b)
{
if (!_b.size())
return;
// nodes can only be added if network is added
if (!isStarted())
BOOST_THROW_EXCEPTION(NetworkStartRequired());
@ -745,7 +749,8 @@ void Host::restoreNetwork(bytesConstRef _b)
RecursiveGuard l(x_sessions);
RLP r(_b);
if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion)
unsigned fileVersion = r[0].toInt<unsigned>();
if (r.itemCount() > 0 && r[0].isInt() && fileVersion >= dev::p2p::c_protocolVersion - 1)
{
// r[0] = version
// r[1] = key
@ -753,30 +758,57 @@ void Host::restoreNetwork(bytesConstRef _b)
for (auto i: r[2])
{
if (i[0].itemCount() != 4)
// todo: ipv6
if (i[0].itemCount() != 4 && i[0].size() != 4)
continue;
// todo: ipv6, bi::address_v6(i[0].toArray<byte, 16>()
Node n((NodeId)i[2], NodeIPEndpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<uint16_t>(), i[1].toInt<uint16_t>()));
if (i.itemCount() == 3 && n.endpoint.isAllowed())
m_nodeTable->addNode(n);
else if (i.itemCount() == 10)
if (i.itemCount() == 4 || i.itemCount() == 11)
{
n.required = i[3].toInt<bool>();
if (!n.endpoint.isAllowed() && !n.required)
continue;
shared_ptr<Peer> p = make_shared<Peer>(n);
p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>()));
p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
p->m_failedAttempts = i[6].toInt<unsigned>();
p->m_lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>();
p->m_score = (int)i[8].toInt<unsigned>();
p->m_rating = (int)i[9].toInt<unsigned>();
m_peers[p->id] = p;
if (p->required)
requirePeer(p->id, n.endpoint);
else
m_nodeTable->addNode(*p.get());
Node n((NodeId)i[3], NodeIPEndpoint(i));
if (i.itemCount() == 4 && n.endpoint.isAllowed())
m_nodeTable->addNode(n);
else if (i.itemCount() == 11)
{
n.required = i[4].toInt<bool>();
if (!n.endpoint.isAllowed() && !n.required)
continue;
shared_ptr<Peer> p = make_shared<Peer>(n);
p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[6].toInt<unsigned>()));
p->m_failedAttempts = i[7].toInt<unsigned>();
p->m_lastDisconnect = (DisconnectReason)i[8].toInt<unsigned>();
p->m_score = (int)i[9].toInt<unsigned>();
p->m_rating = (int)i[10].toInt<unsigned>();
m_peers[p->id] = p;
if (p->required)
requirePeer(p->id, n.endpoint);
else
m_nodeTable->addNode(*p.get(), NodeTable::NodeRelation::Known);
}
}
else if (i.itemCount() == 3 || i.itemCount() == 10)
{
Node n((NodeId)i[2], NodeIPEndpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<uint16_t>(), i[1].toInt<uint16_t>()));
if (i.itemCount() == 3 && n.endpoint.isAllowed())
m_nodeTable->addNode(n);
else if (i.itemCount() == 10)
{
n.required = i[3].toInt<bool>();
if (!n.endpoint.isAllowed() && !n.required)
continue;
shared_ptr<Peer> p = make_shared<Peer>(n);
p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>()));
p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
p->m_failedAttempts = i[6].toInt<unsigned>();
p->m_lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>();
p->m_score = (int)i[8].toInt<unsigned>();
p->m_rating = (int)i[9].toInt<unsigned>();
m_peers[p->id] = p;
if (p->required)
requirePeer(p->id, n.endpoint);
else
m_nodeTable->addNode(*p.get(), NodeTable::NodeRelation::Known);
}
}
}
}
@ -785,7 +817,7 @@ void Host::restoreNetwork(bytesConstRef _b)
KeyPair Host::networkAlias(bytesConstRef _b)
{
RLP r(_b);
if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion)
if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt<unsigned>() >= 3)
return move(KeyPair(move(Secret(r[1].toBytes()))));
else
return move(KeyPair::create());

7
libp2p/Host.h

@ -135,6 +135,8 @@ public:
// TODO: P2P this should be combined with peers into a HostStat object of some kind; coalesce data, as it's only used for status information.
Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; }
NetworkPreferences const& networkPreferences() const { return m_netPrefs; }
void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
/// Start network. @threadsafe
@ -162,6 +164,8 @@ protected:
void restoreNetwork(bytesConstRef _b);
private:
enum PeerSlotRatio { Egress = 2, Ingress = 9 };
bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; }
/// Determines and sets m_tcpPublic to publicly advertised address.
@ -169,6 +173,9 @@ private:
void connect(std::shared_ptr<Peer> const& _p);
/// Returns true if pending and connected peer count is less than maximum
bool peerSlotsAvailable(PeerSlotRatio _type) { Guard l(x_pendingNodeConns); return peerCount() + m_pendingPeerConns.size() < _type * m_idealPeerCount; }
/// Ping the peers to update the latency information and disconnect peers which have timed out.
void keepAlivePeers();

2
libp2p/Network.cpp

@ -226,7 +226,7 @@ bi::tcp::endpoint Network::resolveHost(string const& _addr)
boost::system::error_code ec;
// resolve returns an iterator (host can resolve to multiple addresses)
bi::tcp::resolver r(s_resolverIoService);
auto it = r.resolve({split[0], toString(port)}, ec);
auto it = r.resolve({bi::tcp::v4(), split[0], toString(port)}, ec);
if (ec)
clog(NetWarn) << "Error resolving host address..." << LogTag::Url << _addr << ":" << LogTag::Error << ec.message();
else

134
libp2p/NodeTable.cpp

@ -75,22 +75,20 @@ void NodeTable::processEvents()
m_nodeEventHandler->processEvents();
}
shared_ptr<NodeEntry> NodeTable::addNode(Public const& _pubk, NodeIPEndpoint const& _ep)
shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node, NodeRelation _relation)
{
auto node = Node(_pubk, _ep);
return addNode(node);
}
shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
{
// re-enable tcp checks when NAT hosts are handled by discover
// we handle when tcp endpoint is 0 below
if (_node.endpoint.address.to_string() == "0.0.0.0")
if (_relation == Known)
{
clog(NodeTableWarn) << "addNode Failed. Invalid UDP address" << LogTag::Url << "0.0.0.0" << "for" << _node.id;
return move(shared_ptr<NodeEntry>());
shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, _node.endpoint));
ret->pending = false;
m_nodes[_node.id] = ret;
noteActiveNode(_node.id, _node.endpoint);
return ret;
}
if (!_node.endpoint)
return move(shared_ptr<NodeEntry>());
// ping address to recover nodeid if nodeid is empty
if (!_node.id)
{
@ -99,9 +97,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
Guard l(x_pubkDiscoverPings);
m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now();
}
PingNode p(_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort);
p.sign(m_secret);
m_socketPointer->send(p);
ping(_node.endpoint);
return move(shared_ptr<NodeEntry>());
}
@ -114,9 +110,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, _node.endpoint));
m_nodes[_node.id] = ret;
clog(NodeTableConnect) << "addNode pending for" << _node.endpoint;
PingNode p(_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort);
p.sign(m_secret);
m_socketPointer->send(p);
ping(_node.endpoint);
return ret;
}
@ -144,8 +138,10 @@ list<NodeEntry> NodeTable::snapshot() const
list<NodeEntry> ret;
Guard l(x_state);
for (auto s: m_state)
for (auto n: s.nodes)
ret.push_back(*n.lock());
for (auto np: s.nodes)
if (auto n = np.lock())
if (!!n)
ret.push_back(*n);
return move(ret);
}
@ -286,14 +282,14 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
vector<shared_ptr<NodeEntry>> ret;
for (auto& nodes: found)
for (auto n: nodes.second)
if (n->endpoint.isAllowed())
if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed())
ret.push_back(n);
return move(ret);
}
void NodeTable::ping(bi::udp::endpoint _to) const
void NodeTable::ping(NodeIPEndpoint _to) const
{
PingNode p(_to, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort);
PingNode p(m_node.endpoint, _to);
p.sign(m_secret);
m_socketPointer->send(p);
}
@ -458,12 +454,17 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
m_pubkDiscoverPings.erase(_from.address());
}
if (!haveNode(nodeid))
addNode(nodeid, NodeIPEndpoint(_from.address(), _from.port(), _from.port()));
addNode(Node(nodeid, NodeIPEndpoint(_from.address(), _from.port(), _from.port())));
}
else
return; // unsolicited pong; don't note node as active
}
// update our endpoint address and UDP port
if ((!m_node.endpoint || !m_node.endpoint.isAllowed()) && isPublicAddress(in.destination.address))
m_node.endpoint.address = in.destination.address;
m_node.endpoint.udpPort = in.destination.udpPort;
clog(NodeTableConnect) << "PONG from " << nodeid << _from;
break;
}
@ -488,17 +489,22 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
}
Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes);
for (auto n: in.nodes)
addNode(n.node, NodeIPEndpoint(bi::address::from_string(n.ipAddress), n.udpPort, n.udpPort));
for (auto n: in.neighbours)
addNode(Node(n.node, n.endpoint));
break;
}
case FindNode::type:
{
FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes);
if (RLPXDatagramFace::secondsSinceEpoch() > in.ts)
{
clog(NodeTableTriviaSummary) << "Received expired FindNode from " << _from.address().to_string() << ":" << _from.port();
return;
}
vector<shared_ptr<NodeEntry>> nearest = nearestNodeEntries(in.target);
static unsigned const nlimit = (m_socketPointer->maxDatagramSize - 111) / 87;
static unsigned const nlimit = (m_socketPointer->maxDatagramSize - 109) / 90;
for (unsigned offset = 0; offset < nearest.size(); offset += nlimit)
{
Neighbours out(_from, nearest, offset, nlimit);
@ -513,17 +519,29 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
case PingNode::type:
{
PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes);
if (in.version != dev::p2p::c_protocolVersion)
if (in.version < dev::p2p::c_protocolVersion)
{
if (auto n = nodeEntry(nodeid))
dropNode(n);
return;
if (in.version == 3)
{
compat::Pong p(in.source);
p.echo = sha3(rlpBytes);
p.sign(m_secret);
m_socketPointer->send(p);
}
else
return;
}
// TODO: Feedback if _from.address() != in.ipAddress
addNode(nodeid, NodeIPEndpoint(_from.address(), _from.port(), in.tcpPort));
if (RLPXDatagramFace::secondsSinceEpoch() > in.ts)
{
clog(NodeTableTriviaSummary) << "Received expired PingNode from " << _from.address().to_string() << ":" << _from.port();
return;
}
Pong p(_from);
in.source.address = _from.address();
in.source.udpPort = _from.port();
addNode(Node(nodeid, in.source));
Pong p(in.source);
p.echo = sha3(rlpBytes);
p.sign(m_secret);
m_socketPointer->send(p);
@ -558,8 +576,8 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec)
bool evictionsRemain = false;
list<shared_ptr<NodeEntry>> drop;
{
Guard ln(x_nodes);
Guard le(x_evictions);
Guard ln(x_nodes);
for (auto& e: m_evictions)
if (chrono::steady_clock::now() - e.first.second > c_reqTimeout)
if (m_nodes.count(e.second))
@ -599,26 +617,44 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec)
void PingNode::streamRLP(RLPStream& _s) const
{
_s.appendList(4);
_s << dev::p2p::c_protocolVersion << ipAddress << tcpPort << ts;
_s << dev::p2p::c_protocolVersion;
source.streamRLP(_s);
destination.streamRLP(_s);
_s << ts;
}
void PingNode::interpretRLP(bytesConstRef _bytes)
{
RLP r(_bytes);
if (r.itemCountStrict() == 3)
if (r.itemCountStrict() == 4 && r[0].isInt() && r[0].toInt<unsigned>(RLP::Strict) == dev::p2p::c_protocolVersion)
{
version = 2;
ipAddress = r[0].toString();
tcpPort = r[1].toInt<unsigned>(RLP::Strict);
ts = r[2].toInt<unsigned>(RLP::Strict);
}
else if (r.itemCountStrict() == 4)
{
version = r[0].toInt<unsigned>(RLP::Strict);
ipAddress = r[1].toString();
tcpPort = r[2].toInt<unsigned>(RLP::Strict);
ts = r[3].toInt<unsigned>(RLP::Strict);
version = dev::p2p::c_protocolVersion;
source.interpretRLP(r[1]);
destination.interpretRLP(r[2]);
ts = r[3].toInt<uint32_t>(RLP::Strict);
}
else
BOOST_THROW_EXCEPTION(InvalidRLP());
version = r[0].toInt<unsigned>(RLP::Strict);
}
void Pong::streamRLP(RLPStream& _s) const
{
_s.appendList(3);
destination.streamRLP(_s);
_s << echo << ts;
}
void Pong::interpretRLP(bytesConstRef _bytes)
{
RLP r(_bytes);
destination.interpretRLP(r[0]);
echo = (h256)r[1];
ts = r[2].toInt<uint32_t>();
}
void compat::Pong::interpretRLP(bytesConstRef _bytes)
{
RLP r(_bytes);
echo = (h256)r[0];
ts = r[1].toInt<uint32_t>();
}

127
libp2p/NodeTable.h

@ -100,23 +100,15 @@ inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)
* NodeTable accepts a port for UDP and will listen to the port on all available
* interfaces.
*
*
* [Integration]
* @todo TCP endpoints
* @todo GC uniform 1/32 entires at 112500ms interval
*
* [Optimization]
* @todo serialize evictions per-bucket
* @todo store evictions in map, unit-test eviction logic
* @todo store root node in table
* @todo encapsulate discover into NetworkAlgorithm (task)
* @todo Pong to include ip:port where ping was received
* @todo expiration and sha3(id) 'to' for messages which are replies (prevents replay)
* @todo cache Ping and FindSelf
*
* [Networking]
* @todo node-endpoint updates
* @todo TCP endpoints
* @todo eth/upnp/natpmp/stun/ice/etc for public-discovery
* @todo firewall
*
@ -131,14 +123,16 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this<NodeTable>
using TimePoint = std::chrono::steady_clock::time_point; ///< Steady time point.
using NodeIdTimePoint = std::pair<NodeId, TimePoint>;
using EvictionTimeout = std::pair<NodeIdTimePoint, NodeId>; ///< First NodeId (NodeIdTimePoint) may be evicted and replaced with second NodeId.
public:
enum NodeRelation { Unknown = 0, Known };
/// Constructor requiring host for I/O, credentials, and IP Address and port to listen on.
NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint);
~NodeTable();
/// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable.
static unsigned distance(NodeId const& _a, NodeId const& _b) { u512 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; }
static unsigned distance(NodeId const& _a, NodeId const& _b) { u256 d = sha3(_a) ^ sha3(_b); unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; }
/// Set event handler for NodeEntryAdded and NodeEntryDropped events.
void setEventHandler(NodeTableEventHandler* _handler) { m_nodeEventHandler.reset(_handler); }
@ -146,11 +140,8 @@ public:
/// Called by implementation which provided handler to process NodeEntryAdded/NodeEntryDropped events. Events are coalesced by type whereby old events are ignored.
void processEvents();
/// Add node. Node will be pinged and empty shared_ptr is returned if NodeId is uknown.
std::shared_ptr<NodeEntry> addNode(Public const& _pubk, NodeIPEndpoint const& _ep);
/// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen.
std::shared_ptr<NodeEntry> addNode(Node const& _node);
/// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen or NodeId is empty.
std::shared_ptr<NodeEntry> addNode(Node const& _node, NodeRelation _relation = NodeRelation::Unknown);
/// To be called when node table is empty. Runs node discovery with m_node.id as the target in order to populate node-table.
void discover();
@ -178,7 +169,7 @@ private:
/// Constants for Kademlia, derived from address space.
static unsigned const s_addressByteSize = sizeof(NodeId); ///< Size of address type in bytes.
static unsigned const s_addressByteSize = h256::size; ///< Size of address type in bytes.
static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia].
static unsigned const s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us).
static unsigned const s_maxSteps = boost::static_log2<s_bits>::value; ///< Max iterations of discovery. (discover)
@ -204,7 +195,7 @@ private:
};
/// Used to ping endpoint.
void ping(bi::udp::endpoint _to) const;
void ping(NodeIPEndpoint _to) const;
/// Used ping known node. Used by node table when refreshing buckets and as part of eviction process (see evict).
void ping(NodeEntry* _n) const;
@ -263,7 +254,7 @@ private:
mutable Mutex x_state; ///< LOCK x_state first if both x_nodes and x_state locks are required.
std::array<NodeBucket, s_bins> m_state; ///< State of p2p node network.
Mutex x_evictions; ///< LOCK x_nodes first if both x_nodes and x_evictions locks are required.
Mutex x_evictions; ///< LOCK x_evictions first if both x_nodes and x_evictions locks are required.
std::deque<EvictionTimeout> m_evictions; ///< Eviction timeouts.
Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required.
@ -299,30 +290,21 @@ struct InvalidRLP: public Exception {};
* a given bucket which is full, the least-responsive node is pinged.
* If the pinged node doesn't respond, then it is removed and the new
* node is inserted.
*
* RLP Encoded Items: 3
* Minimum Encoded Size: 18 bytes
* Maximum Encoded Size: bytes // todo after u128 addresses
*
* signature: Signature of message.
* ipAddress: Our IP address.
* port: Our port.
*
* @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint)
*
*/
struct PingNode: RLPXDatagram<PingNode>
{
PingNode(bi::udp::endpoint _ep): RLPXDatagram<PingNode>(_ep) {}
PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _ts = std::chrono::seconds(60)): RLPXDatagram<PingNode>(_ep), ipAddress(_src), tcpPort(_srcPort), ts(futureFromEpoch(_ts)) {}
/// Constructor used for sending PingNode.
PingNode(NodeIPEndpoint _src, NodeIPEndpoint _dest): RLPXDatagram<PingNode>(_dest), source(_src), destination(_dest), ts(futureFromEpoch(std::chrono::seconds(60))) {}
/// Constructor used to create empty PingNode for parsing inbound packets.
PingNode(bi::udp::endpoint _ep): RLPXDatagram<PingNode>(_ep), source(UnspecifiedNodeIPEndpoint), destination(UnspecifiedNodeIPEndpoint) {}
static const uint8_t type = 1;
unsigned version = 0;
std::string ipAddress;
// uint16_t udpPort;
uint16_t tcpPort;
unsigned ts;
NodeIPEndpoint source;
NodeIPEndpoint destination;
uint32_t ts = 0;
void streamRLP(RLPStream& _s) const override;
void interpretRLP(bytesConstRef _bytes) override;
@ -330,22 +312,20 @@ struct PingNode: RLPXDatagram<PingNode>
/**
* Pong packet: Sent in response to ping
*
* RLP Encoded Items: 2
* Minimum Encoded Size: 33 bytes
* Maximum Encoded Size: 33 bytes
*/
struct Pong: RLPXDatagram<Pong>
{
Pong(bi::udp::endpoint _ep): RLPXDatagram<Pong>(_ep), ts(futureFromEpoch(std::chrono::seconds(60))) {}
Pong(bi::udp::endpoint const& _ep): RLPXDatagram<Pong>(_ep), destination(UnspecifiedNodeIPEndpoint) {}
Pong(NodeIPEndpoint const& _dest): RLPXDatagram<Pong>((bi::udp::endpoint)_dest), destination(_dest), ts(futureFromEpoch(std::chrono::seconds(60))) {}
static const uint8_t type = 2;
NodeIPEndpoint destination;
h256 echo; ///< MCD of PingNode
unsigned ts;
uint32_t ts = 0;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << echo << ts; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); echo = (h256)r[0]; ts = r[1].toInt<unsigned>(); }
void streamRLP(RLPStream& _s) const;
void interpretRLP(bytesConstRef _bytes);
};
/**
@ -363,58 +343,63 @@ struct Pong: RLPXDatagram<Pong>
struct FindNode: RLPXDatagram<FindNode>
{
FindNode(bi::udp::endpoint _ep): RLPXDatagram<FindNode>(_ep) {}
FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _ts = std::chrono::seconds(60)): RLPXDatagram<FindNode>(_ep), target(_target), ts(futureFromEpoch(_ts)) {}
FindNode(bi::udp::endpoint _ep, NodeId _target): RLPXDatagram<FindNode>(_ep), target(_target), ts(futureFromEpoch(std::chrono::seconds(60))) {}
static const uint8_t type = 3;
h512 target;
unsigned ts;
uint32_t ts = 0;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << ts; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash<h512>(); ts = r[1].toInt<unsigned>(); }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash<h512>(); ts = r[1].toInt<uint32_t>(); }
};
/**
* Node Packet: Multiple node packets are sent in response to FindNode.
*
* RLP Encoded Items: 2 (first item is list)
* Minimum Encoded Size: 10 bytes
* Node Packet: One or more node packets are sent in response to FindNode.
*/
struct Neighbours: RLPXDatagram<Neighbours>
{
struct Node
struct Neighbour
{
Node() = default;
Node(RLP const& _r) { interpretRLP(_r); }
std::string ipAddress;
uint16_t udpPort;
// uint16_t tcpPort;
Neighbour(Node const& _node): endpoint(_node.endpoint), node(_node.id) {}
Neighbour(RLP const& _r): endpoint(_r) { node = h512(_r[3].toBytes()); }
NodeIPEndpoint endpoint;
NodeId node;
void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << udpPort << node; }
void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); udpPort = _r[1].toInt<uint16_t>(); node = h512(_r[2].toBytes()); }
void streamRLP(RLPStream& _s) const { _s.appendList(4); endpoint.streamRLP(_s, NodeIPEndpoint::StreamInline); _s << node; }
};
Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep), ts(futureFromEpoch(std::chrono::seconds(30))) {}
Neighbours(bi::udp::endpoint _to, std::vector<std::shared_ptr<NodeEntry>> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram<Neighbours>(_to), ts(futureFromEpoch(std::chrono::seconds(30)))
Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep), ts(secondsSinceEpoch()) {}
Neighbours(bi::udp::endpoint _to, std::vector<std::shared_ptr<NodeEntry>> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram<Neighbours>(_to), ts(futureFromEpoch(std::chrono::seconds(60)))
{
auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size();
for (auto i = _offset; i < limit; i++)
{
Node node;
node.ipAddress = _nearest[i]->endpoint.address.to_string();
node.udpPort = _nearest[i]->endpoint.udpPort;
node.node = _nearest[i]->publicKey();
nodes.push_back(node);
}
neighbours.push_back(Neighbour(*_nearest[i]));
}
static const uint8_t type = 4;
std::vector<Node> nodes;
unsigned ts = 1;
std::vector<Neighbour> neighbours;
uint32_t ts = 0;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << ts; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); ts = r[1].toInt<unsigned>(); }
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(neighbours.size()); for (auto& n: neighbours) n.streamRLP(_s); _s << ts; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) neighbours.push_back(Neighbour(n)); ts = r[1].toInt<uint32_t>(); }
};
namespace compat
{
/**
* Pong packet [compatability]: Sent in response to ping
*/
struct Pong: RLPXDatagram<Pong>
{
Pong(bi::udp::endpoint const& _ep): RLPXDatagram<Pong>(_ep) {}
Pong(NodeIPEndpoint const& _dest): RLPXDatagram<Pong>((bi::udp::endpoint)_dest), ts(futureFromEpoch(std::chrono::seconds(60))) {}
static const uint8_t type = 2;
h256 echo;
uint32_t ts = 0;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << echo << ts; }
void interpretRLP(bytesConstRef _bytes);
};
}
struct NodeTableWarn: public LogChannel { static const char* name(); static const int verbosity = 0; };
struct NodeTableNote: public LogChannel { static const char* name(); static const int verbosity = 1; };

4
libp2p/UDP.h

@ -61,8 +61,8 @@ protected:
*/
struct RLPXDatagramFace: public UDPDatagram
{
static uint64_t futureFromEpoch(std::chrono::milliseconds _ms) { return std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); }
static uint64_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); }
static uint32_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); }
static uint32_t secondsSinceEpoch() { return std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now()).time_since_epoch()).count(); }
static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp);
virtual uint8_t packetType() = 0;

9
libsolidity/ASTPrinter.cpp

@ -30,8 +30,11 @@ namespace dev
namespace solidity
{
ASTPrinter::ASTPrinter(ASTNode const& _ast, string const& _source):
m_indentation(0), m_source(_source), m_ast(&_ast)
ASTPrinter::ASTPrinter(
ASTNode const& _ast,
string const& _source,
StructuralGasEstimator::ASTGasConsumption const& _gasCosts
): m_indentation(0), m_source(_source), m_ast(&_ast), m_gasCosts(_gasCosts)
{
}
@ -503,6 +506,8 @@ void ASTPrinter::endVisit(Literal const&)
void ASTPrinter::printSourcePart(ASTNode const& _node)
{
if (m_gasCosts.count(&_node))
*m_ostream << getIndentation() << " Gas costs: " << m_gasCosts.at(&_node) << endl;
if (!m_source.empty())
{
SourceLocation const& location(_node.getLocation());

8
libsolidity/ASTPrinter.h

@ -24,6 +24,7 @@
#include <ostream>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/StructuralGasEstimator.h>
namespace dev
{
@ -38,7 +39,11 @@ class ASTPrinter: public ASTConstVisitor
public:
/// Create a printer for the given abstract syntax tree. If the source is specified,
/// the corresponding parts of the source are printed with each node.
ASTPrinter(ASTNode const& _ast, std::string const& _source = std::string());
ASTPrinter(
ASTNode const& _ast,
std::string const& _source = std::string(),
StructuralGasEstimator::ASTGasConsumption const& _gasCosts = {}
);
/// Output the string representation of the AST to _stream.
void print(std::ostream& _stream);
@ -128,6 +133,7 @@ private:
int m_indentation;
std::string m_source;
ASTNode const* m_ast;
StructuralGasEstimator::ASTGasConsumption m_gasCosts;
std::ostream* m_ostream;
};

44
libsolidity/ASTVisitor.h

@ -23,6 +23,8 @@
#pragma once
#include <string>
#include <functional>
#include <vector>
#include <libsolidity/AST.h>
namespace dev
@ -218,5 +220,47 @@ protected:
virtual void endVisitNode(ASTNode const&) { }
};
/**
* Utility class that visits the AST in depth-first order and calls a function on each node and each edge.
* Child nodes are only visited if the node callback of the parent returns true.
* The node callback of a parent is called before any edge or node callback involving the children.
* The edge callbacks of all children are called before the edge callback of the parent.
* This way, the node callback can be used as an initializing callback and the edge callbacks can be
* used to compute a "reduce" function.
*/
class ASTReduce: public ASTConstVisitor
{
public:
/**
* Constructs a new ASTReduce object with the given callback functions.
* @param _onNode called for each node, before its child edges and nodes, should return true to descend deeper
* @param _onEdge called for each edge with (parent, child)
*/
ASTReduce(
std::function<bool(ASTNode const&)> _onNode,
std::function<void(ASTNode const&, ASTNode const&)> _onEdge
): m_onNode(_onNode), m_onEdge(_onEdge)
{
}
protected:
bool visitNode(ASTNode const& _node) override
{
m_parents.push_back(&_node);
return m_onNode(_node);
}
void endVisitNode(ASTNode const& _node) override
{
m_parents.pop_back();
if (!m_parents.empty())
m_onEdge(*m_parents.back(), _node);
}
private:
std::vector<ASTNode const*> m_parents;
std::function<bool(ASTNode const&)> m_onNode;
std::function<void(ASTNode const&, ASTNode const&)> m_onEdge;
};
}
}

110
libsolidity/StructuralGasEstimator.cpp

@ -0,0 +1,110 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Gas consumption estimator working alongside the AST.
*/
#include "StructuralGasEstimator.h"
#include <map>
#include <functional>
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::solidity;
StructuralGasEstimator::ASTGasConsumptionSelfAccumulated StructuralGasEstimator::performEstimation(
AssemblyItems const& _items,
vector<ASTNode const*> const& _ast
)
{
solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, "");
map<SourceLocation, GasMeter::GasConsumption> particularCosts;
GasMeter meter;
for (auto const& item: _items)
particularCosts[item.getLocation()] += meter.estimateMax(item);
ASTGasConsumptionSelfAccumulated gasCosts;
auto onNode = [&](ASTNode const& _node)
{
gasCosts[&_node][0] = gasCosts[&_node][1] = particularCosts[_node.getLocation()];
return true;
};
auto onEdge = [&](ASTNode const& _parent, ASTNode const& _child)
{
gasCosts[&_parent][1] += gasCosts[&_child][1];
};
ASTReduce folder(onNode, onEdge);
for (ASTNode const* ast: _ast)
ast->accept(folder);
return gasCosts;
}
map<ASTNode const*, GasMeter::GasConsumption> StructuralGasEstimator::breakToStatementLevel(
ASTGasConsumptionSelfAccumulated const& _gasCosts,
vector<ASTNode const*> const& _roots
)
{
solAssert(std::count(_roots.begin(), _roots.end(), nullptr) == 0, "");
// first pass: statementDepth[node] is the distance from the deepend statement to node
// in direction of the tree root (or undefined if not possible)
map<ASTNode const*, int> statementDepth;
auto onNodeFirstPass = [&](ASTNode const& _node)
{
if (dynamic_cast<Statement const*>(&_node))
statementDepth[&_node] = 0;
return true;
};
auto onEdgeFirstPass = [&](ASTNode const& _parent, ASTNode const& _child)
{
if (statementDepth.count(&_child))
statementDepth[&_parent] = max(statementDepth[&_parent], statementDepth[&_child] + 1);
};
ASTReduce firstPass(onNodeFirstPass, onEdgeFirstPass);
for (ASTNode const* node: _roots)
node->accept(firstPass);
// we use the location of a node if
// - its statement depth is 0 or
// - its statement depth is undefined but the parent's statement depth is at least 1
map<ASTNode const*, GasMeter::GasConsumption> gasCosts;
auto onNodeSecondPass = [&](ASTNode const& _node)
{
return statementDepth.count(&_node);
};
auto onEdgeSecondPass = [&](ASTNode const& _parent, ASTNode const& _child)
{
bool useNode = false;
if (statementDepth.count(&_child))
useNode = statementDepth[&_child] == 0;
else
useNode = statementDepth.count(&_parent) && statementDepth.at(&_parent) > 0;
if (useNode)
gasCosts[&_child] = _gasCosts.at(&_child)[1];
};
ASTReduce secondPass(onNodeSecondPass, onEdgeSecondPass);
for (ASTNode const* node: _roots)
node->accept(secondPass);
// gasCosts should only contain non-overlapping locations
return gasCosts;
}

62
libsolidity/StructuralGasEstimator.h

@ -0,0 +1,62 @@
/*
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/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Gas consumption estimator working alongside the AST.
*/
#pragma once
#include <vector>
#include <map>
#include <array>
#include <libsolidity/ASTForward.h>
#include <libevmasm/GasMeter.h>
#include <libevmasm/Assembly.h>
namespace dev
{
namespace solidity
{
class StructuralGasEstimator
{
public:
using ASTGasConsumption = std::map<ASTNode const*, eth::GasMeter::GasConsumption>;
using ASTGasConsumptionSelfAccumulated =
std::map<ASTNode const*, std::array<eth::GasMeter::GasConsumption, 2>>;
/// Estimates the gas consumption for every assembly item in the given assembly and stores
/// it by source location.
/// @returns a mapping from each AST node to a pair of its particular and syntactically accumulated gas costs.
ASTGasConsumptionSelfAccumulated performEstimation(
eth::AssemblyItems const& _items,
std::vector<ASTNode const*> const& _ast
);
/// @returns a mapping from nodes with non-overlapping source locations to gas consumptions such that
/// the following source locations are part of the mapping:
/// 1. source locations of statements that do not contain other statements
/// 2. maximal source locations that do not overlap locations coming from the first rule
ASTGasConsumption breakToStatementLevel(
ASTGasConsumptionSelfAccumulated const& _gasCosts,
std::vector<ASTNode const*> const& _roots
);
};
}
}

4
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -502,9 +502,9 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
t.from = m_accounts->getDefaultTransactAccount();
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (!t.gasPrice)
if (t.gasPrice == UndefinedU256)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (!t.gas)
if (t.gas == UndefinedU256)
t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
if (m_accounts->isRealAccount(t.from))

5
libwebthree/WebThree.cpp

@ -72,6 +72,11 @@ WebThreeDirect::~WebThreeDirect()
m_ethereum.reset();
}
p2p::NetworkPreferences const& WebThreeDirect::networkPreferences() const
{
return m_net.networkPreferences();
}
void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers)
{
auto had = isNetworkStarted();

5
libwebthree/WebThree.h

@ -73,6 +73,7 @@ public:
virtual bool haveNetwork() const = 0;
virtual p2p::NetworkPreferences const& networkPreferences() const = 0;
virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) = 0;
virtual p2p::NodeId id() const = 0;
@ -88,6 +89,8 @@ public:
/// Is network working? there may not be any peers yet.
virtual bool isNetworkStarted() const = 0;
std::string enode() const { return "enode://" + toHex(id().ref()) + "@" + (networkPreferences().publicIPAddress.empty() ? "127.0.0.1" : networkPreferences().publicIPAddress) + ":" + toString(networkPreferences().listenPort); }
};
@ -164,6 +167,8 @@ public:
bool haveNetwork() const override { return m_net.haveNetwork(); }
p2p::NetworkPreferences const& networkPreferences() const override;
void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers = false) override;
p2p::NodeId id() const override { return m_net.id(); }

26
mix/ClientModel.cpp

@ -137,24 +137,29 @@ void ClientModel::mine()
QString ClientModel::newSecret()
{
KeyPair a = KeyPair::create();
return QString::fromStdString(toHex(a.secret().ref()));
return QString::fromStdString(dev::toHex(a.secret().ref()));
}
QString ClientModel::address(QString const& _secret)
{
return QString::fromStdString(toHex(KeyPair(Secret(_secret.toStdString())).address().ref()));
return QString::fromStdString(dev::toHex(KeyPair(Secret(_secret.toStdString())).address().ref()));
}
QString ClientModel::toHex(QString const& _int)
{
return QString::fromStdString(dev::toHex(dev::u256(_int.toStdString())));
}
QString ClientModel::encodeAbiString(QString _string)
{
ContractCallDataEncoder encoder;
return QString::fromStdString(toHex(encoder.encodeBytes(_string)));
return QString::fromStdString(dev::toHex(encoder.encodeBytes(_string)));
}
QString ClientModel::encodeStringParam(QString const& _param)
{
ContractCallDataEncoder encoder;
return QString::fromStdString(toHex(encoder.encodeStringParam(_param, 32)));
return QString::fromStdString(dev::toHex(encoder.encodeStringParam(_param, 32)));
}
QStringList ClientModel::encodeParams(QVariant const& _param, QString const& _contract, QString const& _function)
@ -179,7 +184,7 @@ QStringList ClientModel::encodeParams(QVariant const& _param, QString const& _co
QSolidityType const* type = var->type();
QVariant value = _param.toMap().value(var->name());
encoder.encode(value, type->type());
ret.push_back(QString::fromStdString(toHex(encoder.encodedData())));
ret.push_back(QString::fromStdString(dev::toHex(encoder.encodedData())));
}
return ret;
}
@ -192,11 +197,11 @@ QVariantMap ClientModel::contractAddresses() const
return res;
}
QVariantMap ClientModel::gasCosts() const
QVariantList ClientModel::gasCosts() const
{
QVariantMap res;
QVariantList res;
for (auto const& c: m_gasCosts)
res.insert(c.first, QVariant::fromValue(static_cast<int>(c.second)));
res.append(QVariant::fromValue(static_cast<int>(c)));
return res;
}
@ -302,6 +307,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
{
vector<Address> deployedContracts;
onStateReset();
m_gasCosts.clear();
for (TransactionSettings const& transaction: _sequence)
{
if (!transaction.isContractCall)
@ -371,7 +377,6 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
contractAddressesChanged();
}
gasCostsChanged();
m_gasCosts[transaction.contractId] = m_client->lastExecution().gasUsed;
}
else
{
@ -385,6 +390,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
}
callAddress(contractAddressIter->second, encoder.encodedData(), transaction);
}
m_gasCosts.append(m_client->lastExecution().gasUsed);
}
onNewTransaction();
}
@ -633,7 +639,7 @@ RecordLogEntry* ClientModel::lastBlock() const
strGas << blockInfo.gasUsed;
stringstream strNumber;
strNumber << blockInfo.number;
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()));
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()));
QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record;
}

8
mix/ClientModel.h

@ -149,7 +149,7 @@ public:
/// @returns deployed contracts addresses
Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged)
/// @returns deployed contracts gas costs
Q_PROPERTY(QVariantMap gasCosts READ gasCosts NOTIFY gasCostsChanged)
Q_PROPERTY(QVariantList gasCosts READ gasCosts NOTIFY gasCostsChanged)
// @returns the last block
Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT)
/// ethereum.js RPC request entry point
@ -164,6 +164,8 @@ public:
Q_INVOKABLE QStringList encodeParams(QVariant const& _param, QString const& _contract, QString const& _function);
/// Encode parameter
Q_INVOKABLE QString encodeStringParam(QString const& _param);
/// To Hex number
Q_INVOKABLE QString toHex(QString const& _int);
public slots:
/// Setup state, run transaction sequence, show debugger for the last transaction
@ -219,7 +221,7 @@ signals:
private:
RecordLogEntry* lastBlock() const;
QVariantMap contractAddresses() const;
QVariantMap gasCosts() const;
QVariantList gasCosts() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, std::map<Address, dev::eth::Account> const& _accounts, Secret const& _miner);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
@ -236,7 +238,7 @@ private:
std::unique_ptr<MixClient> m_client;
std::unique_ptr<RpcConnector> m_rpcConnector;
std::unique_ptr<Web3Server> m_web3Server;
std::map<QString, u256> m_gasCosts;
QList<u256> m_gasCosts;
std::map<QString, Address> m_contractAddresses;
std::map<Address, QString> m_contractNames;
std::map<QString, Address> m_stdContractAddresses;

2
mix/QBigInt.h

@ -79,7 +79,7 @@ public:
~QBigInt() {}
/// @returns the current used big integer.
BigIntVariant internalValue() { return m_internalValue; }
BigIntVariant internalValue() const { return m_internalValue; }
/// @returns a string representation of the big integer used. Invokable from QML.
Q_INVOKABLE QString value() const;
/// Set the value of the BigInteger used. Will use u256 type. Invokable from QML.

6
mix/Web3Server.cpp

@ -70,6 +70,12 @@ class EmptyNetwork : public dev::WebThreeNetworkFace
return false;
}
p2p::NetworkPreferences const& networkPreferences() const override
{
static const p2p::NetworkPreferences c_ret;
return c_ret;
}
void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) override
{
(void)_n;

100
mix/qml/DeploymentDialog.qml

@ -17,6 +17,10 @@ Dialog {
width: 735
height: 400
visible: false
property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr.
property int ownedRegistrarSetSubRegistrarGas: 50000
property int ownedRegistrarSetContentHashGas: 50000
property int urlHintSuggestUrlGas: 70000
property alias applicationUrlEth: applicationUrlEth.text
property alias applicationUrlHttp: applicationUrlHttp.text
property alias localPackageUrl: localPackageUrl.text
@ -24,7 +28,7 @@ Dialog {
property string packageBase64
property string eth: registrarAddr.text
property string currentAccount
property string gasToUse: "0x188132" //gasToUseInput.text
property string gasPrice
property variant paramsModel: []
function close()
@ -43,7 +47,6 @@ Dialog {
id: 0
}];
console.log(packageHash);
TransactionHelper.rpcCall(requests, function(arg1, arg2)
{
modelAccounts.clear();
@ -70,16 +73,26 @@ Dialog {
{
var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei);
comboAccounts.balances.push(ether.format());
comboAccounts.weiBalances.push(balanceRet[k].result);
}
balance.text = comboAccounts.balances[0];
});
});
var gas = 0;
var gasCosts = clientModel.gasCosts;
for (var g in gasCosts)
gas += gasCosts[g];
gasToUse = gas;
if (clientModel.gasCosts.length === 0)
{
errorDialog.text = qsTr("Please run the state one time before deploying in order to calculate gas requirement.");
errorDialog.open();
}
else
{
NetworkDeploymentCode.gasPrice(function(price) {
gasPrice = price;
gasPriceInt.setValue(gasPrice);
ctrDeployCtrLabel.calculateContractDeployGas();
ctrRegisterLabel.calculateRegisterGas();
});
}
}
function stopForInputError(inError)
@ -114,6 +127,11 @@ Dialog {
poolLog.start();
}
BigIntValue
{
id: gasPriceInt
}
Timer
{
id: poolLog
@ -265,6 +283,10 @@ Dialog {
id: statesList
textRole: "title"
model: projectModel.stateListModel
onCurrentIndexChanged : {
ctrDeployCtrLabel.calculateContractDeployGas();
ctrRegisterLabel.calculateRegisterGas();
}
}
}
@ -278,7 +300,7 @@ Dialog {
{
Layout.preferredWidth: 350
id: registrarAddr
text: "c6d9d2cd449a754c494264e1809c50e34d64562b"
text: "ab69f864e49fc4294d18355c4bafb0b91b5e629b"
visible: false
}
@ -295,11 +317,15 @@ Dialog {
ComboBox {
id: comboAccounts
property var balances: []
property var weiBalances: []
onCurrentIndexChanged : {
if (modelAccounts.count > 0)
{
currentAccount = modelAccounts.get(currentIndex).id;
balance.text = balances[currentIndex];
balanceInt.setValue(weiBalances[currentIndex]);
ctrDeployCtrLabel.calculateContractDeployGas();
ctrRegisterLabel.calculateRegisterGas();
}
}
model: ListModel {
@ -314,19 +340,58 @@ Dialog {
anchors.leftMargin: 20
id: balance;
}
BigIntValue
{
id: balanceInt
}
}
}
DefaultLabel
{
text: qsTr("Amount of gas to use for each contract deployment: ")
text: qsTr("Amount of gas to use for contract deployment: ")
id: ctrDeployCtrLabel
function calculateContractDeployGas()
{
var ether = QEtherHelper.createBigInt(NetworkDeploymentCode.gasUsed());
var gasTotal = ether.multiply(gasPriceInt);
gasToUseInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent);
gasToUseDeployInput.update();
}
}
DefaultTextField
Ether {
id: gasToUseInput
displayUnitSelection: false
displayFormattedValue: true
Layout.preferredWidth: 350
}
DefaultLabel
{
text: "1000000"
text: qsTr("Amount of gas to use for dapp registration: ")
id: ctrRegisterLabel
function calculateRegisterGas()
{
if (!modalDeploymentDialog.visible)
return;
appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text).join('/');
NetworkDeploymentCode.checkPathCreationCost(function(pathCreationCost)
{
var ether = QEtherHelper.createBigInt(pathCreationCost);
var gasTotal = ether.multiply(gasPriceInt);
gasToUseDeployInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent);
gasToUseDeployInput.update();
});
}
}
Ether {
id: gasToUseDeployInput
displayUnitSelection: false
displayFormattedValue: true
Layout.preferredWidth: 350
id: gasToUseInput
}
DefaultLabel
@ -344,7 +409,7 @@ Dialog {
width: 200
id: applicationUrlEth
onTextChanged: {
appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(text).join('/');
ctrRegisterLabel.calculateRegisterGas();
}
}
@ -489,6 +554,15 @@ Dialog {
iconSource: "qrc:/qml/img/note.png"
}
BigIntValue
{
id: registerUrlHintGas
Component.onCompleted:
{
setValue(modalDeploymentDialog.urlHintSuggestUrlGas);
}
}
Action {
id: registerAction
enabled: rowRegister.isOkToRegister()

4
mix/qml/Ether.qml

@ -15,9 +15,11 @@ RowLayout {
property bool displayFormattedValue;
property bool edit;
property variant value;
property bool displayUnitSelection
onValueChanged: update()
Component.onCompleted: update()
function update()
{
if (value)
@ -45,13 +47,13 @@ RowLayout {
}
}
readOnly: !edit
visible: edit
id: etherValueEdit;
}
ComboBox
{
id: units
visible: displayUnitSelection;
onCurrentTextChanged:
{
if (value)

177
mix/qml/js/NetworkDeployment.js

@ -23,6 +23,7 @@
.import org.ethereum.qml.QSolidityType 1.0 as QSolidityType
Qt.include("TransactionHelper.js")
Qt.include("QEtherHelper.js")
var jsonRpcRequestId = 1;
@ -47,6 +48,7 @@ function startDeployProject(erasePrevious)
var ctrAddresses = {};
var state = retrieveState(projectModel.deployedState);
console.log(JSON.stringify(state));
if (!state)
{
var txt = qsTr("Unable to find state " + projectModel.deployedState);
@ -59,6 +61,47 @@ function startDeployProject(erasePrevious)
});
}
function checkPathCreationCost(callBack)
{
var dappUrl = formatAppUrl(deploymentDialog.applicationUrlEth);
checkEthPath(dappUrl, true, function(success, cause) {
if (!success)
{
switch (cause)
{
case "rootownedregistrar_notexist":
deploymentError(qsTr("Owned registrar does not exist under the global registrar. Please create one using DApp registration."));
break;
case "ownedregistrar_creationfailed":
deploymentError(qsTr("The creation of your new owned registrar fails. Please use DApp registration to create one."));
break;
case "ownedregistrar_notowner":
deploymentError(qsTr("You are not the owner of this registrar. You cannot register your Dapp here."));
break;
default:
break;
}
}
else
{
deploymentStepChanged(qsTr("Your Dapp can be registered here."));
callBack((dappUrl.length - 1) * (deploymentDialog.ownedRegistrarDeployGas + deploymentDialog.ownedRegistrarSetSubRegistrarGas) + deploymentDialog.ownedRegistrarSetContentHashGas);
}
});
}
function gasUsed()
{
var gas = 0;
var gasCosts = clientModel.gasCosts;
for (var g in gasCosts)
{
gas += gasCosts[g];
console.log(" gasCost " + gasCosts[g]);
}
return gas;
}
function retrieveState(state)
{
for (var k = 0; k < projectModel.stateListModel.count; k++)
@ -113,7 +156,8 @@ function executeTr(trIndex, state, ctrAddresses, callBack)
executeTrNextStep(trIndex, state, ctrAddresses, callBack);
else
{
var rpcParams = { "from": deploymentDialog.currentAccount, "gas": deploymentDialog.gasToUse };
var gasCost = clientModel.toHex(clientModel.gasCosts[trIndex]);
var rpcParams = { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost };
var params = replaceParamToken(func.parameters, tr.parameters, ctrAddresses);
var encodedParams = clientModel.encodeParams(params, tr.contractId, tr.functionId);
@ -157,6 +201,19 @@ function executeTrNextStep(trIndex, state, ctrAddresses, callBack)
callBack();
}
function gasPrice(callBack)
{
var requests = [{
jsonrpc: "2.0",
method: "eth_gasPrice",
params: [],
id: jsonRpcRequestId
}];
rpcCall(requests, function (httpCall, response){
callBack(JSON.parse(response)[0].result);
});
}
function finalizeDeployment(deploymentId, addresses) {
deploymentStepChanged(qsTr("Packaging application ..."));
var deploymentDir = projectPath + deploymentId + "/";
@ -185,8 +242,8 @@ function finalizeDeployment(deploymentId, addresses) {
}
//write deployment js
var deploymentJs =
"// Autogenerated by Mix\n" +
"contracts = {};\n";
"// Autogenerated by Mix\n" +
"contracts = {};\n";
for (var c in codeModel.contracts) {
var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]";
deploymentJs += contractAccessor + " = {\n" +
@ -209,19 +266,27 @@ function finalizeDeployment(deploymentId, addresses) {
applicationUrlEth = formatAppUrl(applicationUrlEth);
deploymentStepChanged(qsTr("Registering application on the Ethereum network ..."));
checkEthPath(applicationUrlEth, function () {
checkEthPath(applicationUrlEth, false, function (success) {
if (!success)
return;
deploymentComplete();
deployResourcesDialog.text = qsTr("Register Web Application to finalize deployment.");
deployResourcesDialog.open();
});
}
function checkEthPath(dappUrl, callBack)
function checkEthPath(dappUrl, checkOnly, callBack)
{
if (dappUrl.length === 1)
reserve(deploymentDialog.eth, function() {
registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar.
});
{
// convenient for dev purpose, should not be possible in normal env.
if (!checkOnly)
reserve(deploymentDialog.eth, function() {
registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar.
});
else
callBack(true);
}
else
{
// the first owned registrar must have been created to follow the path.
@ -231,7 +296,7 @@ function checkEthPath(dappUrl, callBack)
//subRegistrar()
jsonrpc: "2.0",
method: "eth_call",
params: [ { "gas": "0xffff", "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x5a3a05bd" + str }, "pending" ],
params: [ { "gas": "0xffff", "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0xe1fa8e84" + str }, "pending" ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
@ -242,35 +307,66 @@ function checkEthPath(dappUrl, callBack)
var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting.");
deploymentError(errorTxt);
console.log(errorTxt);
callBack(false, "rootownedregistrar_notexist");
}
else
{
dappUrl.splice(0, 1);
checkRegistration(dappUrl, addr, callBack);
checkRegistration(dappUrl, addr, callBack, checkOnly);
}
});
}
}
function checkRegistration(dappUrl, addr, callBack)
function isOwner(addr, callBack)
{
var requests = [];
requests.push({
//getOwner()
jsonrpc: "2.0",
method: "eth_call",
params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0xb387ef92" }, "pending" ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
var res = JSON.parse(response);
callBack(normalizeAddress(deploymentDialog.currentAccount) === normalizeAddress(res[0].result));
});
}
function checkRegistration(dappUrl, addr, callBack, checkOnly)
{
isOwner(addr, function(ret){
if (!ret)
{
var errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting");
deploymentError(errorTxt);
console.log(errorTxt);
callBack(false, "ownedregistrar_notowner");
}
else
continueRegistration(dappUrl, addr, callBack, checkOnly);
});
}
function continueRegistration(dappUrl, addr, callBack, checkOnly)
{
if (dappUrl.length === 1)
registerContentHash(addr, callBack); // We do not create the register for the last part, just registering the content hash.
{
if (!checkOnly)
registerContentHash(addr, callBack); // We do not create the register for the last part, just registering the content hash.
else
callBack(true);
}
else
{
var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr);
var txt = qsTr("Checking " + JSON.stringify(dappUrl));
deploymentStepChanged(txt);
console.log(txt);
var requests = [];
var registrar = {}
var str = clientModel.encodeStringParam(dappUrl[0]);
requests.push({
//getOwner()
jsonrpc: "2.0",
method: "eth_call",
params: [ { "gas" : 2000, "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x02571be3" }, "pending" ],
id: jsonRpcRequestId++
});
requests.push({
//register()
@ -282,37 +378,37 @@ function checkRegistration(dappUrl, addr, callBack)
rpcCall(requests, function (httpRequest, response) {
var res = JSON.parse(response);
var nextAddr = normalizeAddress(res[1].result);
var nextAddr = normalizeAddress(res[0].result);
var errorTxt;
if (res[1].result === "0x")
if (res[0].result === "0x")
{
errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting");
deploymentError(errorTxt);
console.log(errorTxt);
}
else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result))
{
errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting");
errorTxt = qsTr("Error when creating new owned registrar. Please use the registration Dapp. Aborting");
deploymentError(errorTxt);
console.log(errorTxt);
callBack(false, "ownedregistrar_creationfailed");
}
else if (nextAddr.replace(/0+/g, "") !== "")
{
dappUrl.splice(0, 1);
checkRegistration(dappUrl, nextAddr, callBack);
checkRegistration(dappUrl, nextAddr, callBack, checkOnly);
}
else
{
if (checkOnly)
{
callBack(true);
return;
}
var txt = qsTr("Registering sub domain " + dappUrl[0] + " ...");
console.log(txt);
deploymentStepChanged(txt);
//current registrar is owned => ownedregistrar creation and continue.
requests = [];
var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarDeployGas);
requests.push({
jsonrpc: "2.0",
method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317815561058990819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100a757806302571be3146100d957806321f8a721146100e35780632dff6941146100ed5780633b3b57de1461010d5780635a3a05bd1461013d5780635fd4b08a1461017057806389a69c0e1461017c578063b5c645bd146101b0578063be99a9801461022c578063c3d014d614610264578063d93e75731461029857005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000546102c89060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052557610585565b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b6000546102ce906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff9081169116146102e0576103af565b6000546102d49060043590602435903373ffffffffffffffffffffffffffffffffffffffff9081169116146103b4576103f1565b6000546102da90600435903373ffffffffffffffffffffffffffffffffffffffff9081169116146103f557610522565b60006000f35b60006000f35b60006000f35b60006000f35b600083815260026020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016831790558061034757827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a26103ae565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610432576104b2565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ],
params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "code": "0x600080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331781556105cd90819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100b257806321f8a721146100e45780632dff6941146100ee5780633b3b57de1461010e5780635a3a05bd1461013e5780635fd4b08a146101715780637dd564111461017d57806389a69c0e14610187578063b387ef92146101bb578063b5c645bd146101f4578063be99a98014610270578063c3d014d6146102a8578063d93e7573146102dc57005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000808052602081f35b60005461030c9060043590602435903373ffffffffffffffffffffffffffffffffffffffff908116911614610569576105c9565b60005473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b600054610312906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff90811691161461045457610523565b6000546103189060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052857610565565b60005461031e90600435903373ffffffffffffffffffffffffffffffffffffffff90811691161461032457610451565b60006000f35b60006000f35b60006000f35b60006000f35b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610361576103e1565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b600083815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001683179055806104bb57827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a2610522565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ],
id: jsonRpcRequestId++
});
@ -329,11 +425,12 @@ function checkRegistration(dappUrl, addr, callBack)
return;
}
var crLevel = clientModel.encodeStringParam(dappUrl[0]);
var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarSetSubRegistrarGas);
requests.push({
//setRegister()
jsonrpc: "2.0",
method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + deploymentDialog.pad(newCtrAddress) } ],
params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + deploymentDialog.pad(newCtrAddress) } ],
id: jsonRpcRequestId++
});
@ -382,16 +479,16 @@ function registerContentHash(registrar, callBack)
console.log(txt);
var requests = [];
var paramTitle = clientModel.encodeStringParam(projectModel.projectTitle);
var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarSetContentHashGas);
requests.push({
//setContent()
jsonrpc: "2.0",
method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.currentAccount, "gas": "0xfffff", "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageHash } ],
params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
callBack();
callBack(true);
});
}
@ -402,12 +499,12 @@ function registerToUrlHint()
urlHintAddress(function(urlHint){
var requests = [];
var paramUrlHttp = clientModel.encodeStringParam(deploymentDialog.applicationUrlHttp);
var gasCost = clientModel.toHex(deploymentDialog.urlHintSuggestUrlGas);
requests.push({
//urlHint => suggestUrl
jsonrpc: "2.0",
method: "eth_sendTransaction",
params: [ { "to": '0x' + urlHint, "from": deploymentDialog.currentAccount, "gas": "0xfffff", "data": "0x584e86ad" + deploymentDialog.packageHash + paramUrlHttp } ],
params: [ { "to": '0x' + urlHint, "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "data": "0x584e86ad" + deploymentDialog.packageHash + paramUrlHttp } ],
id: jsonRpcRequestId++
});
@ -425,7 +522,7 @@ function urlHintAddress(callBack)
//registrar: get UrlHint addr
jsonrpc: "2.0",
method: "eth_call",
params: [ { "to": '0x' + deploymentDialog.eth, "from": deploymentDialog.currentAccount, "gas": "0xfffff", "data": "0x3b3b57de" + urlHint }, "pending" ],
params: [ { "to": '0x' + deploymentDialog.eth, "from": deploymentDialog.currentAccount, "data": "0x3b3b57de" + urlHint }, "pending" ],
id: jsonRpcRequestId++
});
@ -446,6 +543,8 @@ function normalizeAddress(addr)
function formatAppUrl(url)
{
if (url.toLowerCase().lastIndexOf("/") === url.length - 1)
url = url.substring(0, url.length - 1);
if (url.toLowerCase().indexOf("eth://") === 0)
url = url.substring(6);
if (url.toLowerCase().indexOf(projectModel.projectTitle + ".") === 0)

2
mix/qml/js/TransactionHelper.js

@ -16,7 +16,7 @@ function defaultTransaction()
function rpcCall(requests, callBack)
{
var jsonRpcUrl = "http://localhost:8080";
var jsonRpcUrl = "http://localhost:8545";
var rpcRequest = JSON.stringify(requests);
console.log(rpcRequest);
var httpRequest = new XMLHttpRequest();

6
rlp/CMakeLists.txt

@ -12,5 +12,9 @@ add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} devcrypto)
install( TARGETS ${EXECUTABLE} DESTINATION bin)
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

6
solc/CMakeLists.txt

@ -17,7 +17,11 @@ target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_PROGRAM_OPTIONS_LIBRARIES})
target_link_libraries(${EXECUTABLE} solidity)
install( TARGETS ${EXECUTABLE} DESTINATION bin )
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()
add_library(soljson jsonCompiler.cpp ${HEADERS})
target_link_libraries(soljson solidity)

18
solc/CommandLineInterface.cpp

@ -42,6 +42,7 @@
#include <libsolidity/Exceptions.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libsolidity/StructuralGasEstimator.h>
using namespace std;
namespace po = boost::program_options;
@ -464,6 +465,17 @@ void CommandLineInterface::handleAst(string const& _argStr)
// do we need AST output?
if (m_args.count(_argStr))
{
StructuralGasEstimator gasEstimator;
vector<ASTNode const*> asts;
for (auto const& sourceCode: m_sourceCodes)
asts.push_back(&m_compiler->getAST(sourceCode.first));
map<ASTNode const*, eth::GasMeter::GasConsumption> gasCosts;
if (m_compiler->getRuntimeAssemblyItems())
gasCosts = gasEstimator.breakToStatementLevel(
gasEstimator.performEstimation(*m_compiler->getRuntimeAssemblyItems(), asts),
asts
);
auto choice = m_args[_argStr].as<OutputType>();
if (outputToStdout(choice))
{
@ -473,7 +485,11 @@ void CommandLineInterface::handleAst(string const& _argStr)
cout << endl << "======= " << sourceCode.first << " =======" << endl;
if (_argStr == g_argAstStr)
{
ASTPrinter printer(m_compiler->getAST(sourceCode.first), sourceCode.second);
ASTPrinter printer(
m_compiler->getAST(sourceCode.first),
sourceCode.second,
gasCosts
);
printer.print(cout);
}
else

98
test/GasMeter.cpp

@ -0,0 +1,98 @@
/*
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/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Unit tests for the gas estimator.
*/
#include <test/libsolidity/solidityExecutionFramework.h>
#include <libsolidity/AST.h>
#include <libsolidity/StructuralGasEstimator.h>
#include <libsolidity/SourceReferenceFormatter.h>
using namespace std;
using namespace dev::eth;
using namespace dev::solidity;
namespace dev
{
namespace solidity
{
namespace test
{
class GasMeterTestFramework: public ExecutionFramework
{
public:
GasMeterTestFramework() { }
void compile(string const& _sourceCode)
{
m_compiler.setSource(_sourceCode);
ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(), "Compiling contract failed");
StructuralGasEstimator estimator;
AssemblyItems const* items = m_compiler.getRuntimeAssemblyItems("");
ASTNode const& sourceUnit = m_compiler.getAST();
BOOST_REQUIRE(items != nullptr);
m_gasCosts = estimator.breakToStatementLevel(
estimator.performEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
{&sourceUnit}
);
}
protected:
dev::solidity::CompilerStack m_compiler;
map<ASTNode const*, eth::GasMeter::GasConsumption> m_gasCosts;
};
BOOST_FIXTURE_TEST_SUITE(GasMeterTests, GasMeterTestFramework)
BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs)
{
char const* sourceCode = R"(
contract test {
bytes x;
function f(uint a) returns (uint b) {
x.length = a;
for (; a < 200; ++a) {
x[a] = 9;
b = a * a;
}
return f(a - 1);
}
}
)";
compile(sourceCode);
for (auto first = m_gasCosts.cbegin(); first != m_gasCosts.cend(); ++first)
{
auto second = first;
for (++second; second != m_gasCosts.cend(); ++second)
if (first->first->getLocation().intersects(second->first->getLocation()))
{
BOOST_CHECK_MESSAGE(false, "Source locations should not overlap!");
SourceReferenceFormatter::printSourceLocation(cout, first->first->getLocation(), m_compiler.getScanner());
SourceReferenceFormatter::printSourceLocation(cout, second->first->getLocation(), m_compiler.getScanner());
}
}
}
BOOST_AUTO_TEST_SUITE_END()
}
}
}

10
test/TestHelper.cpp

@ -715,11 +715,10 @@ Options::Options()
vmtrace = true;
else if (arg == "--filltests")
fillTests = true;
else if (arg.compare(0, 7, "--stats") == 0)
else if (arg == "--stats" && i + 1 < argc)
{
stats = true;
if (arg.size() > 7)
statsOutFile = arg.substr(8); // skip '=' char
statsOutFile = argv[i + 1];
}
else if (arg == "--performance")
performance = true;
@ -741,6 +740,11 @@ Options::Options()
inputLimits = true;
bigData = true;
}
else if (arg == "--singletest" && i + 1 < argc)
{
singleTest = true;
singleTestName = argv[i + 1];
}
}
}

2
test/TestHelper.h

@ -188,6 +188,8 @@ public:
/// Test selection
/// @{
bool singleTest = false;
std::string singleTestName;
bool performance = false;
bool quadratic = false;
bool memory = false;

4
test/libdevcrypto/crypto.cpp

@ -588,7 +588,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)
{
Secret encryptK(sha3("..."));
h128 encryptK(sha3("..."), h128::AlignLeft);
h256 egressMac(sha3("+++"));
// TESTING: send encrypt magic sequence
bytes magic {0x22,0x40,0x08,0x91};
@ -610,7 +610,7 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr)
{
Secret k(sha3("0xAAAA"));
h128 k(sha3("0xAAAA"), h128::AlignLeft);
string m = "AAAAAAAAAAAAAAAA";
bytesConstRef msg((byte*)m.data(), m.size());

4060
test/libethereum/BlockTestsFiller/bcWalletTestFiller.json

File diff suppressed because one or more lines are too long

90
test/libethereum/StateTestsFiller/stCallCreateCallCodeTestFiller.json

@ -618,6 +618,96 @@
}
},
"createNameRegistratorPreStore1NotEnoughGas": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "100000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{(MSTORE 0 0x6001600155601080600c6000396000f3006000355415600957005b6020356000 ) (MSTORE8 32 0x35) (MSTORE8 33 0x55) (CREATE 23 0 34) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "0x0129ef",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"createNameRegistratorPerTxs": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "0xb44e",
"to" : "",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : "0x6001600155601080600c6000396000f3006000355415600957005b60203560003555"
}
},
"createNameRegistratorPerTxsNotEnoughGas": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "0xb44d",
"to" : "",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : "0x6001600155601080600c6000396000f3006000355415600957005b60203560003555"
}
},
"createNameRegistratorendowmentTooHigh": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

160
test/libethereum/StateTestsFiller/stSolidityTestFiller.json

@ -1,4 +1,156 @@
{
"ContractInheritance" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000000000000",
"currentNumber" : "120",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"storage" : {
"0x" : "0x01"
}
}
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000",
"//" : "contract base ",
"//" : "{ ",
"//" : " function methodA() returns (uint32) ",
"//" : " { ",
"//" : " return 1; ",
"//" : " } ",
"//" : "} ",
"//" : " ",
"//" : "contract frombase is base ",
"//" : "{ ",
"//" : " function methodA() returns (uint32) ",
"//" : " { ",
"//" : " return 2; ",
"//" : " } ",
"//" : "} ",
"//" : " ",
"//" : "contract main ",
"//" : "{ ",
"//" : " bool returnValue; ",
"//" : " function run() returns (bool) ",
"//" : " { ",
"//" : " returnValue = testInheretance(); ",
"//" : " return returnValue; ",
"//" : " } ",
"//" : " ",
"//" : " function testInheretance() returns (bool res) ",
"//" : " { ",
"//" : " res = true; ",
"//" : " base contract1; ",
"//" : " if (contract1.methodA() != 1) ",
"//" : " return false; ",
"//" : " ",
"//" : " frombase contract2; ",
"//" : " if (contract2.methodA() != 2) ",
"//" : " return false; ",
"//" : " } ",
"//" : "} ",
"code" : "0x6000357c0100000000000000000000000000000000000000000000000000000000900480633e0bca3b1461003a578063c04062261461004c57005b610042610099565b8060005260206000f35b61005461005e565b8060005260206000f35b6000610068610099565b600060006101000a81548160ff02191690830217905550600060009054906101000a900460ff169050610096565b90565b60006000600060019250825060018273ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f16100fd57005b505060005163ffffffff1614156101135761011c565b60009250610194565b60028173ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f161017457005b505060005163ffffffff16141561018a57610193565b60009250610194565b5b50509056",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "50000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" :
{
"data" : "run()",
"data" : "0xc0406226",
"gasLimit" : "35000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"TestOverflow" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000000000000",
"currentNumber" : "120",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"storage" : {
"0x" : "0x01"
}
}
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000",
"//" : "contract main ",
"//" : "{ ",
"//" : " bool returnValue; ",
"//" : " function run() returns (bool) ",
"//" : " { ",
"//" : " returnValue = testOverflow(); ",
"//" : " return returnValue; ",
"//" : " } ",
"//" : " ",
"//" : " function testOverflow() returns (bool res) ",
"//" : " { ",
"//" : " res = true; ",
"//" : " uint256 a = 115792089237316195423570985008687907853269984665640564039457584007913129639935; ",
"//" : " if (a + 1 != 0) ",
"//" : " return false; ",
"//" : " ",
"//" : " uint32 b = 4294967295; ",
"//" : " if (b + 1 != 0) ",
"//" : " return false; ",
"//" : " ",
"//" : " uint64 c = 18446744073709551615; ",
"//" : " if (c + 1 != 0) ",
"//" : " return false; ",
"//" : " } ",
"//" : "} ",
"code" : "0x6000357c0100000000000000000000000000000000000000000000000000000000900480638040cac41461003a578063c04062261461004c57005b610042610099565b8060005260206000f35b61005461005e565b8060005260206000f35b6000610068610099565b600060006101000a81548160ff02191690830217905550600060009054906101000a900460ff169050610096565b90565b60006000600060006001935083507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff925060006001840114156100db576100e4565b6000935061013b565b63ffffffff915060006001830163ffffffff1614156101025761010b565b6000935061013b565b67ffffffffffffffff905060006001820167ffffffffffffffff1614156101315761013a565b6000935061013b565b5b5050509056",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "50000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" :
{
"data" : "run()",
"data" : "0xc0406226",
"gasLimit" : "35000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"TestStoreGasPrices" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
@ -125,10 +277,14 @@
"//" : " if (ripemd160('teststring') != 0xcd566972b5e50104011a92b59fa8e0b1234851ae) ",
"//" : " return false; ",
"//" : " ",
"//" : " //ecrecover ",
"//" : " if (ecrecover(0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c, ",
"//" : " 28, 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f, ",
"//" : " 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) ",
"//" : " != 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b) ",
"//" : " return false; ",
"//" : " } ",
"//" : "} ",
"code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c04062268114610039578063e0a9fd281461004b57005b61004161005d565b8060005260206000f35b61005361009d565b8060005260206000f35b600061006761009d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016919091179081905560ff16905090565b7f74657374737472696e67000000000000000000000000000000000000000000006000908152600190600a90207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d14156100f6576100fe565b5060006101eb565b60026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560325a03f161013c57005b506000517f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d111141561016c57610174565b5060006101eb565b60036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560325a03f16101b257005b506000517fcd566972b5e50104011a92b59fa8e0b1234851ae00000000000000000000000014156101e2576101ea565b5060006101eb565b5b9056",
"code" : "0x6000357c010000000000000000000000000000000000000000000000000000000090048063c04062261461003a578063e0a9fd281461004c57005b61004261005e565b8060005260206000f35b610054610099565b8060005260206000f35b6000610068610099565b600060006101000a81548160ff02191690830217905550600060009054906101000a900460ff169050610096565b90565b60006001905080507f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d60010260407f74657374737472696e67000000000000000000000000000000000000000000008152600a016040900360402014156100ff57610108565b600090506102ec565b7f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d11160010260026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a0160006000856161da5a03f161016b57005b50600051141561017a57610183565b600090506102ec565b73cd566972b5e50104011a92b59fa8e0b1234851ae6c010000000000000000000000000260036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a0160006000856161da5a03f16101e657005b506000516c010000000000000000000000000214156102045761020d565b600090506102ec565b73a94f5374fce5edbc8e2a8697c15331677e6ebf0b60016020600060007f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c6001028152602001601c81526020017f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f60010281526020017feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549600102815260200160006000856161da5a03f16102bd57005b5060005173ffffffffffffffffffffffffffffffffffffffff1614156102e2576102eb565b600090506102ec565b5b9056",
"nonce" : "0",
"storage" : {
}

42
test/libethereum/StateTestsFiller/stSpecialTestFiller.json

@ -1,5 +1,5 @@
{
"makeMoney" : {
"makeMoney" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
@ -8,7 +8,7 @@
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"expect" : {
"expect" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000"
},
@ -60,7 +60,7 @@
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"expect" : {
"expect" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000"
}
@ -84,5 +84,41 @@
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "501"
}
},
"gasPrice0" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"code" : "0x6001600101600055",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0xa033",
"gasPrice" : "0",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000"
}
}
}

1289
test/libethereum/StateTestsFiller/stWalletTestFiller.json

File diff suppressed because one or more lines are too long

5
test/libethereum/blockchain.cpp

@ -704,6 +704,11 @@ BOOST_AUTO_TEST_CASE(bcGasPricerTest)
dev::test::executeTests("bcGasPricerTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests);
}
BOOST_AUTO_TEST_CASE(bcWalletTest)
{
dev::test::executeTests("bcWalletTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests);
}
BOOST_AUTO_TEST_CASE(userDefinedFile)
{
dev::test::userDefinedTest("--singletest", dev::test::doBlockchainTests);

13
test/libethereum/state.cpp

@ -43,9 +43,14 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
{
for (auto& i: v.get_obj())
{
std::cout << " " << i.first << "\n";
mObject& o = i.second.get_obj();
if (test::Options::get().singleTest && test::Options::get().singleTestName != i.first)
{
o.clear();
continue;
}
std::cout << " " << i.first << std::endl;
BOOST_REQUIRE(o.count("env") > 0);
BOOST_REQUIRE(o.count("pre") > 0);
BOOST_REQUIRE(o.count("transaction") > 0);
@ -62,7 +67,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
}
catch (Exception const& _e)
{
cnote << "Exception:\n" << diagnostic_information(_e);
cnote << "Exception: " << diagnostic_information(_e);
theState.commit();
}
catch (std::exception const& _e)
@ -183,6 +188,10 @@ BOOST_AUTO_TEST_CASE(stMemoryTest)
dev::test::executeTests("stMemoryTest", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);
}
BOOST_AUTO_TEST_CASE(stWalletTest)
{
dev::test::executeTests("stWalletTest", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests);
}
BOOST_AUTO_TEST_CASE(stCreateTest)
{

38
test/libp2p/net.cpp

@ -82,7 +82,7 @@ struct TestNodeTable: public NodeTable
bi::address ourIp = bi::address::from_string("127.0.0.1");
for (auto& n: _testNodes)
{
ping(bi::udp::endpoint(ourIp, n.second));
ping(NodeIPEndpoint(ourIp, n.second, n.second));
this_thread::sleep_for(chrono::milliseconds(2));
}
}
@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(v2PingNodePacket)
PingNode p((bi::udp::endpoint()));
BOOST_REQUIRE_NO_THROW(p = PingNode::fromBytesConstRef(bi::udp::endpoint(), bytesConstRef(&s.out())));
BOOST_REQUIRE(p.version == 2);
BOOST_REQUIRE(p.version == 0);
}
BOOST_AUTO_TEST_CASE(neighboursPacketLength)
@ -235,8 +235,8 @@ BOOST_AUTO_TEST_CASE(neighboursPacketLength)
std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);
// hash(32), signature(65), overhead: packet(2), type(1), nodeList(2), ts(9),
static unsigned const nlimit = (1280 - 111) / 87;
// hash(32), signature(65), overhead: packetSz(3), type(1), nodeListSz(3), ts(5),
static unsigned const nlimit = (1280 - 109) / 90; // neighbour: 2 + 65 + 3 + 3 + 17
for (unsigned offset = 0; offset < testNodes.size(); offset += nlimit)
{
Neighbours out(to);
@ -244,11 +244,9 @@ BOOST_AUTO_TEST_CASE(neighboursPacketLength)
auto limit = nlimit ? std::min(testNodes.size(), (size_t)(offset + nlimit)) : testNodes.size();
for (auto i = offset; i < limit; i++)
{
Neighbours::Node node;
node.ipAddress = boost::asio::ip::address::from_string("200.200.200.200").to_string();
node.udpPort = testNodes[i].second;
node.node = testNodes[i].first.pub();
out.nodes.push_back(node);
Node n(testNodes[i].first.pub(), NodeIPEndpoint(boost::asio::ip::address::from_string("200.200.200.200"), testNodes[i].second, testNodes[i].second));
Neighbours::Neighbour neighbour(n);
out.neighbours.push_back(neighbour);
}
out.sign(k.sec());
@ -256,7 +254,7 @@ BOOST_AUTO_TEST_CASE(neighboursPacketLength)
}
}
BOOST_AUTO_TEST_CASE(test_neighbours_packet)
BOOST_AUTO_TEST_CASE(neighboursPacket)
{
KeyPair k = KeyPair::create();
std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
@ -265,11 +263,9 @@ BOOST_AUTO_TEST_CASE(test_neighbours_packet)
Neighbours out(to);
for (auto n: testNodes)
{
Neighbours::Node node;
node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string();
node.udpPort = n.second;
node.node = n.first.pub();
out.nodes.push_back(node);
Node node(n.first.pub(), NodeIPEndpoint(boost::asio::ip::address::from_string("200.200.200.200"), n.second, n.second));
Neighbours::Neighbour neighbour(node);
out.neighbours.push_back(neighbour);
}
out.sign(k.sec());
@ -277,9 +273,9 @@ BOOST_AUTO_TEST_CASE(test_neighbours_packet)
bytesConstRef rlpBytes(packet.cropped(h256::size + Signature::size + 1));
Neighbours in = Neighbours::fromBytesConstRef(to, rlpBytes);
int count = 0;
for (auto n: in.nodes)
for (auto n: in.neighbours)
{
BOOST_REQUIRE_EQUAL(testNodes[count].second, n.udpPort);
BOOST_REQUIRE_EQUAL(testNodes[count].second, n.endpoint.udpPort);
BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node);
BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node));
count++;
@ -293,12 +289,6 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbours)
// into the same list of nearest nodes.
}
BOOST_AUTO_TEST_CASE(test_windows_template)
{
bi::udp::endpoint ep;
PingNode p(ep);
}
BOOST_AUTO_TEST_CASE(kademlia)
{
// Not yet a 'real' test.
@ -332,7 +322,7 @@ BOOST_AUTO_TEST_CASE(kademlia)
}
BOOST_AUTO_TEST_CASE(test_udp_once)
BOOST_AUTO_TEST_CASE(udpOnce)
{
UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65}));
TestUDPSocket a; a.m_socket->connect(); a.start();

8
test/libp2p/peer.cpp

@ -51,6 +51,8 @@ BOOST_AUTO_TEST_CASE(host)
auto node2 = host2.id();
host2.start();
while (!host2.isStarted())
this_thread::sleep_for(chrono::milliseconds(20));
host1.addNode(node2, NodeIPEndpoint(bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort));
this_thread::sleep_for(chrono::seconds(3));
@ -72,7 +74,7 @@ BOOST_AUTO_TEST_CASE(networkConfig)
BOOST_REQUIRE(save.id() == restore.id());
}
BOOST_AUTO_TEST_CASE(save_nodes)
BOOST_AUTO_TEST_CASE(saveNodes)
{
std::list<Host*> hosts;
for (auto i:{0,1,2,3,4,5})
@ -111,8 +113,8 @@ BOOST_AUTO_TEST_CASE(save_nodes)
for (auto i: r[2])
{
BOOST_REQUIRE(i.itemCount() == 3 || i.itemCount() == 10);
BOOST_REQUIRE(i[0].itemCount() == 4 || i[0].itemCount() == 16);
BOOST_REQUIRE(i.itemCount() == 4 || i.itemCount() == 11);
BOOST_REQUIRE(i[0].size() == 4 || i[0].size() == 16);
}
}

Loading…
Cancel
Save