diff --git a/CMakeLists.txt b/CMakeLists.txt
index 667c2fb73..a2b31d174 100644
--- a/CMakeLists.txt
+++ b/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")
diff --git a/abi/CMakeLists.txt b/abi/CMakeLists.txt
index 82c7c4240..3cc6b2594 100644
--- a/abi/CMakeLists.txt
+++ b/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()
diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp
index 7c754f8f5..a91beb2f7 100644
--- a/alethzero/DappLoader.cpp
+++ b/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
(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
+ if (address != m_nameReg)
+ address = abiOut(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
+ else
+ address = abiOut(web3()->ethereum()->call(address, abiIn("register(bytes32)", name)).output);
+
domainParts.append(parts[partIndex]);
if (!address)
{
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index f28f5b5fc..736af8684 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -256,6 +256,19 @@
+ -
+
+
+
+
+
+
+
+
+ Automatic
+
+
+
-
@@ -266,16 +279,6 @@
- -
-
-
- 1
-
-
- 5
-
-
-
-
@@ -289,20 +292,21 @@
- -
-
-
-
-
+
-
+
-
+ Public IP
+
+
+ -
+
Automatic
- -
+
-
Ideal &Peers
@@ -312,21 +316,7 @@
- -
-
-
- Automatic
-
-
-
- -
-
-
- Public IP
-
-
-
- -
+
-
&Client Name
@@ -336,13 +326,30 @@
- -
+
-
+
+
+ 1
+
+
+ 5
+
+
+
+ -
Anonymous
+ -
+
+
+ true
+
+
+
@@ -1751,7 +1758,6 @@ font-size: 14pt
verbosity
tabWidget
urlEdit
- idealPeers
listenIP
port
transactionQueue
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index de5f149ce..62515f171 100644
--- a/alethzero/MainWin.cpp
+++ b/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);
@@ -1775,6 +1774,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
{
diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake
index be4f7ccd1..1d1cb887b 100644
--- a/cmake/EthExecutableHelper.cmake
+++ b/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}
)
diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt
index 962d55373..0e56eb9f5 100644
--- a/eth/CMakeLists.txt
+++ b/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()
diff --git a/eth/main.cpp b/eth/main.cpp
index 985e74e59..801ee1a0f 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -407,6 +407,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 +473,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 +1052,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());
diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt
index cd8919bb2..af38c0c84 100644
--- a/ethminer/CMakeLists.txt
+++ b/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()
diff --git a/exp/main.cpp b/exp/main.cpp
index 366c5b2ff..973679f3d 100644
--- a/exp/main.cpp
+++ b/exp/main.cpp
@@ -33,6 +33,7 @@
#endif
#include
#include
+#include
#include
#include
#include
@@ -43,6 +44,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -58,8 +60,94 @@ 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, std::string const& _pass)
+ {
+ auto it = m_keys.find(_uuid);
+ if (it == m_keys.end())
+ return Secret();
+ return Secret(decrypt(it->second, _pass));
+ }
+
+private:
+ 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);
+ 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;
+ }
+ }
+
+ static bytes decrypt(js::mValue const& _v, std::string const& _pass)
+ {
+ js::mObject o = _v.get_obj();
+ bytes pKey;
+ if (o["kdf"].get_str() == "pbkdf2")
+ {
+ auto params = o["kdfparams"].get_obj();
+ unsigned iterations = params["c"].get_int();
+ bytes salt = fromHex(params["salt"].get_str());
+ pKey = pbkdf2(_pass, salt, iterations).asBytes();
+ }
+ else
+ {
+ cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
+ return bytes();
+ }
+
+ // TODO check MAC
+ h256 mac(o["mac"].get_str());
+ (void)mac;
+
+ bytes cipherText = fromHex(o["ciphertext"].get_str());
+ bytes ret;
+ if (o["cipher"].get_str() == "aes-128-cbc")
+ {
+ auto params = o["cipherparams"].get_obj();
+ h128 key(sha3(h128(pKey, 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;
+ }
+
+ std::map m_keys;
+};
+
+int main()
+{
+ KeyManager keyman;
+ cdebug << "Secret key for 0498f19a-59db-4d54-ac95-33901b4f1870 is " << keyman.secret(fromUUID("0498f19a-59db-4d54-ac95-33901b4f1870"), "foo");
+}
+
+#elif 0
int main()
{
DownloadMan man;
diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp
index 72b5543a8..7b9d74155 100644
--- a/libdevcore/Common.cpp
+++ b/libdevcore/Common.cpp
@@ -28,7 +28,7 @@ using namespace dev;
namespace dev
{
-char const* Version = "0.9.14";
+char const* Version = "0.9.15";
void HasInvariants::checkInvariants() const
{
diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp
index ec6a9121b..48dd5c384 100644
--- a/libdevcrypto/Common.cpp
+++ b/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);
}
+h256 dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations)
+{
+ h256 ret;
+ PKCS5_PBKDF2_HMAC 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 s_eng;
diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h
index 3159f4e7e..50072c1bf 100644
--- a/libdevcrypto/Common.h
+++ b/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.
+h256 pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations);
+
/// 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
*/
diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp
index ff22b9b45..e89857502 100644
--- a/libdevcrypto/CryptoPP.cpp
+++ b/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);
diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp
index 111f92529..42098e09d 100644
--- a/libethash-cl/ethash_cl_miner.cpp
+++ b/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() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }";
}
+unsigned ethash_cl_miner::get_num_platforms()
+{
+ std::vector platforms;
+ cl::Platform::get(&platforms);
+ return platforms.size();
+}
+
unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
{
std::vector platforms;
@@ -117,14 +124,11 @@ void ethash_cl_miner::finish()
}
}
-bool ethash_cl_miner::init(ethash_params const& params, std::function _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 platforms;
- cl::Platform::get(&platforms);
+ std::vector 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().c_str() << endl;
- // get GPU device of the default platform
- std::vector devices;
+ // get GPU device of the default platform
+ std::vector 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 _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;
diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp
index e932fced4..011f0b9e0 100644
--- a/libethcore/Ethash.cpp
+++ b/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);
diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp
index ad7dfe53b..0b9af98ac 100644
--- a/libethcore/EthashAux.cpp
+++ b/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);
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index d92a3835f..c7c8a23ac 100644
--- a/libethereum/BlockChain.cpp
+++ b/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
@@ -489,7 +489,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
ETH_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
@@ -497,18 +497,15 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
blocksBatch.Put(toSlice(bi.hash()), (ldb::Slice)ref(_block));
ETH_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(),
@@ -633,6 +629,10 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
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.";
diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h
index 2083e9919..0b1469f19 100644
--- a/libethereum/CommonNet.h
+++ b/libethereum/CommonNet.h
@@ -56,7 +56,7 @@ class EthereumPeer;
enum
{
StatusPacket = 0,
- GetTransactionsPacket,
+ NewBlockHashesPacket,
TransactionsPacket,
GetBlockHashesPacket,
BlockHashesPacket,
diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp
index 340ae417f..34d5eb504 100644
--- a/libethereum/EthereumHost.cpp
+++ b/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> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow)
+pair>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow)
{
- std::vector> candidates;
- candidates.reserve(peerSessions().size());
+ pair>, vector>> ret;
+ ret.second.reserve(peerSessions().size());
for (auto const& j: peerSessions())
{
auto pp = j.first->cap();
if (_allow(pp.get()))
- candidates.push_back(pp);
+ ret.second.push_back(pp);
}
- std::vector> 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){ ETH_GUARDED(p->x_knownBlocks) return !p->m_knownBlocks.count(_currentHash); return false; });
+ for (shared_ptr 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 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;
}
diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h
index c2fffcd82..baa850b5c 100644
--- a/libethereum/EthereumHost.h
+++ b/libethereum/EthereumHost.h
@@ -80,7 +80,7 @@ public:
void noteNewBlocks() { m_newBlocks = true; }
private:
- std::vector> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; });
+ std::pair>, std::vector>> randomSelection(unsigned _percent = 25, std::function 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.
diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp
index 249831540..c550bd4f7 100644
--- a/libethereum/EthereumPeer.cpp
+++ b/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);
+ ETH_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();
+ ETH_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;
}
diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h
index a80d5dadd..75ebab02f 100644
--- a/libethereum/EthereumPeer.h
+++ b/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.
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 78c1102c1..17ae1a8f1 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -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(this, _io, p, PeerSessionInfo({_id, clientVersion, _endpoint.address().to_string(), listenPort, chrono::steady_clock::duration(), _rlp[2].toSet(), 0, map()}));
- if (protocolVersion != dev::p2p::c_protocolVersion)
+ if (protocolVersion < dev::p2p::c_protocolVersion)
{
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;
@@ -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);
}
}
@@ -413,7 +413,6 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
// create or update m_peers entry
shared_ptr p;
ETH_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;
+ ETH_GUARDED(x_pendingNodeConns)
+ pendingCount = m_pendingPeerConns.size();
+ int openSlots = m_idealPeerCount - peerCount() - pendingCount;
if (openSlots > 0)
{
list> toConnect;
@@ -759,7 +762,7 @@ void Host::restoreNetwork(bytesConstRef _b)
// todo: ipv6, bi::address_v6(i[0].toArray()
Node n((NodeId)i[2], NodeIPEndpoint(bi::address_v4(i[0].toArray()), i[1].toInt(), i[1].toInt()));
if (i.itemCount() == 3 && n.endpoint.isAllowed())
- m_nodeTable->addNode(n);
+ m_nodeTable->addNode(n, NodeTable::NodeRelation::Known);
else if (i.itemCount() == 10)
{
n.required = i[3].toInt();
@@ -776,7 +779,7 @@ void Host::restoreNetwork(bytesConstRef _b)
if (p->required)
requirePeer(p->id, n.endpoint);
else
- m_nodeTable->addNode(*p.get());
+ m_nodeTable->addNode(*p.get(), NodeTable::NodeRelation::Known);
}
}
}
diff --git a/libp2p/Host.h b/libp2p/Host.h
index 375481c38..41f4d1e72 100644
--- a/libp2p/Host.h
+++ b/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 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();
diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp
index de054a178..847e6a42d 100644
--- a/libp2p/Network.cpp
+++ b/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
diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp
index e324b8f86..42f1cad02 100644
--- a/libp2p/NodeTable.cpp
+++ b/libp2p/NodeTable.cpp
@@ -81,8 +81,17 @@ shared_ptr NodeTable::addNode(Public const& _pubk, NodeIPEndpoint con
return addNode(node);
}
-shared_ptr NodeTable::addNode(Node const& _node)
+shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relation)
{
+ if (_relation == Known)
+ {
+ shared_ptr ret(new NodeEntry(m_node, _node.id, _node.endpoint));
+ ret->pending = false;
+ m_nodes[_node.id] = ret;
+ noteActiveNode(_node.id, _node.endpoint);
+ return ret;
+ }
+
// 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")
diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h
index 07247462f..95028db2b 100644
--- a/libp2p/NodeTable.h
+++ b/libp2p/NodeTable.h
@@ -133,12 +133,14 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this
using EvictionTimeout = std::pair; ///< 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); }
@@ -149,8 +151,8 @@ public:
/// Add node. Node will be pinged and empty shared_ptr is returned if NodeId is uknown.
std::shared_ptr 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 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 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 +180,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::value; ///< Max iterations of discovery. (discover)
diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp
index a520190ee..606126e43 100644
--- a/libwebthree/WebThree.cpp
+++ b/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();
diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h
index 90a4aa3c2..ece83abb8 100644
--- a/libwebthree/WebThree.h
+++ b/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(); }
diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp
index 717757c70..fa5ec1c27 100644
--- a/mix/ClientModel.cpp
+++ b/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(c.second)));
+ res.append(QVariant::fromValue(static_cast(c)));
return res;
}
@@ -299,6 +304,7 @@ void ClientModel::executeSequence(vector const& _sequence,
{
vector deployedContracts;
onStateReset();
+ m_gasCosts.clear();
for (TransactionSettings const& transaction: _sequence)
{
ContractCallDataEncoder encoder;
@@ -345,7 +351,7 @@ void ClientModel::executeSequence(vector const& _sequence,
if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<") && value.toString().endsWith(">"))
{
QStringList nb = value.toString().remove("<").remove(">").split(" - ");
- value = QVariant(QString::fromStdString("0x" + toHex(deployedContracts.at(nb.back().toInt()).ref())));
+ value = QVariant(QString::fromStdString("0x" + dev::toHex(deployedContracts.at(nb.back().toInt()).ref())));
}
encoder.encode(value, type->type());
}
@@ -364,7 +370,6 @@ void ClientModel::executeSequence(vector const& _sequence,
contractAddressesChanged();
}
gasCostsChanged();
- m_gasCosts[transaction.contractId] = m_client->lastExecution().gasUsed;
}
else
{
@@ -378,6 +383,7 @@ void ClientModel::executeSequence(vector const& _sequence,
}
callContract(contractAddressIter->second, encoder.encodedData(), transaction);
}
+ m_gasCosts.append(m_client->lastExecution().gasUsed);
}
onNewTransaction();
}
@@ -615,7 +621,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;
}
diff --git a/mix/ClientModel.h b/mix/ClientModel.h
index 9b0529ae6..91b66c76c 100644
--- a/mix/ClientModel.h
+++ b/mix/ClientModel.h
@@ -147,7 +147,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
@@ -162,6 +162,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
@@ -217,7 +219,7 @@ signals:
private:
RecordLogEntry* lastBlock() const;
QVariantMap contractAddresses() const;
- QVariantMap gasCosts() const;
+ QVariantList gasCosts() const;
void executeSequence(std::vector const& _sequence, std::map const& _accounts, Secret const& _miner);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
@@ -233,7 +235,7 @@ private:
std::unique_ptr m_client;
std::unique_ptr m_rpcConnector;
std::unique_ptr m_web3Server;
- std::map m_gasCosts;
+ QList m_gasCosts;
std::map m_contractAddresses;
std::map m_contractNames;
std::map m_stdContractAddresses;
diff --git a/mix/QBigInt.h b/mix/QBigInt.h
index 0712ff984..b549a16db 100644
--- a/mix/QBigInt.h
+++ b/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.
diff --git a/mix/Web3Server.cpp b/mix/Web3Server.cpp
index 4acb262df..7edc73060 100644
--- a/mix/Web3Server.cpp
+++ b/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;
diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml
index f8eeb7a88..1fbde3ac9 100644
--- a/mix/qml/DeploymentDialog.qml
+++ b/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()
diff --git a/mix/qml/Ether.qml b/mix/qml/Ether.qml
index dd9022b81..7a059e04d 100644
--- a/mix/qml/Ether.qml
+++ b/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)
diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js
index 9bbed2415..8a833e144 100644
--- a/mix/qml/js/NetworkDeployment.js
+++ b/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)
diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js
index be057917c..b0a5caa9e 100644
--- a/mix/qml/js/TransactionHelper.js
+++ b/mix/qml/js/TransactionHelper.js
@@ -15,7 +15,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();
diff --git a/rlp/CMakeLists.txt b/rlp/CMakeLists.txt
index 0e2b5f57b..92d0c7978 100644
--- a/rlp/CMakeLists.txt
+++ b/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()
diff --git a/solc/CMakeLists.txt b/solc/CMakeLists.txt
index c8e74ed71..e60d3c8cf 100644
--- a/solc/CMakeLists.txt
+++ b/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)
diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp
index eecf6f80d..144a1a286 100644
--- a/test/TestHelper.cpp
+++ b/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];
+ }
}
}
diff --git a/test/TestHelper.h b/test/TestHelper.h
index 10e76aa96..02f509e4c 100644
--- a/test/TestHelper.h
+++ b/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;
diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp
index dbbc2dfa0..96826bdf9 100644
--- a/test/libdevcrypto/crypto.cpp
+++ b/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());
diff --git a/test/libethereum/StateTestsFiller/stSolidityTestFiller.json b/test/libethereum/StateTestsFiller/stSolidityTestFiller.json
index c74ced9de..a4243c8dd 100644
--- a/test/libethereum/StateTestsFiller/stSolidityTestFiller.json
+++ b/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" : {
}
diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp
index 900f3060f..9f676d437 100644
--- a/test/libethereum/state.cpp
+++ b/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)